diff -Nru a/CREDITS b/CREDITS --- a/CREDITS 2004-10-18 14:56:48 -07:00 +++ b/CREDITS 2004-10-18 14:56:48 -07:00 @@ -281,6 +281,11 @@ S: Greenbelt, Maryland 20771 S: USA +N: Adam Belay +E: ambx1@neo.rr.com +D: Linux Plug and Play Support +S: USA + N: Daniele Bellucci E: bellucda@tiscali.it D: Various Janitor work. @@ -513,6 +518,14 @@ S: Oxford S: United Kingdom +N: Luiz Fernando N. Capitulino +E: lcapitulino@terra.com.br +E: lcapitulino@prefeitura.sp.gov.br +W: http://www.telecentros.sp.gov.br +D: Little fixes and a lot of janitorial work +S: E-GOV Telecentros SP +S: Brazil + N: Remy Card E: Remy.Card@masi.ibp.fr E: Remy.Card@linux.org @@ -625,6 +638,14 @@ D: Assorted sched/mm titbits S: Oxfordshire, UK. +N: Kees Cook +E: kees@outflux.net +W: http://outflux.net/ +P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D +D: Minor updates to SCSI code for the Communications type +S: (ask for current address) +S: USA + N: Mark Corner E: mcorner@umich.edu W: http://www.eecs.umich.edu/~mcorner/ @@ -639,14 +660,6 @@ S: Santa Cruz, California S: USA -N: Kees Cook -E: kees@outflux.net -W: http://outflux.net/ -P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D -D: Minor updates to SCSI code for the Communications type -S: (ask for current address) -S: USA - N: Alan Cox W: http://www.linux.org.uk/diary/ D: Linux Networking (0.99.10->2.0.29) @@ -735,6 +748,12 @@ S: D-69231 Rauenberg S: Germany +N: Jean Delvare +E: khali@linux-fr.org +W: http://khali.linux-fr.org/ +D: Several hardware monitoring drivers +S: France + N: Peter Denison E: peterd@pnd-pc.demon.co.uk W: http://www.pnd-pc.demon.co.uk/promise/ @@ -754,7 +773,7 @@ D: HTB qdisc and random networking hacks N: Alex deVries -E: adevries@thepuffingroup.com +E: alex@onefishtwo.ca D: Various SGI parts, bits of HAL2 and Newport, PA-RISC Linux. S: 41.5 William Street S: Ottawa, Ontario @@ -905,6 +924,10 @@ S: S-114 79 Stockholm S: Sweden +N: David Engebretsen +E: engebret@us.ibm.com +D: Linux port to 64-bit PowerPC architecture + N: Michael Engel E: engel@unix-ag.org D: DECstation framebuffer drivers @@ -1049,6 +1072,12 @@ S: 80050-430 - Curitiba - Paraná S: Brazil +N: Kumar Gala +E: kumar.gala@freescale.com +D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support +S: Austin, Texas 78729 +S: USA + N: Nigel Gamble E: nigel@nrg.org D: Interrupt-driven printer driver @@ -1060,12 +1089,6 @@ N: Jeff Garzik E: jgarzik@pobox.com -N: Kumar Gala -E: kumar.gala@freescale.com -D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support -S: Austin, Texas 78729 -S: USA - N: Jacques Gelinas E: jacques@solucorp.qc.ca D: Author of the Umsdos file system @@ -1563,10 +1586,37 @@ D: Various Janitor work. S: United Kingdom +N: Martin Josfsson +E: gandalf@wlug.westbo.se +P: 1024D/F6B6D3B1 7610 7CED 5C34 4AA6 DBA2 8BE1 5A6D AF95 F6B6 D3B1 +D: netfilter: SAME target +D: netfilter: helper target +D: netfilter: various other hacks +S: Ronneby +S: Sweden + N: Ani Joshi E: ajoshi@shell.unixbox.com D: fbdev hacking +N: Jesper Juhl +E: juhl-lkml@dif.dk +D: Various small janitor fixes, cleanups etc. +S: Lemnosvej 1, 3.tv +S: 2300 Copenhagen S +S: Denmark + +N: Jozsef Kadlecsik +E: kadlec@blackhole.kfki.hu +P: 1024D/470DB964 4CB3 1A05 713E 9BF7 FAC5 5809 DD8C B7B1 470D B964 +D: netfilter: TCP window tracking code +D: netfilter: raw table +D: netfilter: iprange match +D: netfilter: new logging interfaces +D: netfilter: various other hacks +S: Tata +S: Hungary + N: Bernhard Kaindl E: bkaindl@netway.at E: edv@bartelt.via.at @@ -1818,11 +1868,6 @@ S: 370 01 Ceske Budejovice S: Czech Republic -N: Adam Belay -E: ambx1@neo.rr.com -D: Linux Plug and Play Support -S: USA - N: Bas Laarhoven E: sjml@xs4all.nl D: Loadable modules and ftape driver @@ -1954,12 +1999,6 @@ S: Niwot, Colorado 80503 S: USA -N: Pete Popov -E: pete_popov@yahoo.com -D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging -S: San Jose, CA 95134 -S: USA - N: Robert M. Love E: rml@tech9.net E: rml@novell.com @@ -2127,6 +2166,16 @@ S: (address available on request) S: USA +N: Patrick McHardy +E: kaber@trash.net +P: 1024D/12155E80 B128 7DE6 FF0A C2B2 48BE AB4C C9D4 964E 1215 5E80 +D: netfilter: endless number of bugfixes +D: netfilter: CLASSIFY target +D: netfilter: addrtype match +D: tc: HFSC scheduler +S: Freiburg +S: Germany + N: Mike McLagan E: mike.mclagan@linux.org W: http://www.invlogic.com/~mmclagan @@ -2214,14 +2263,13 @@ S: Netherlands N: David S. Miller -E: davem@redhat.com +E: davem@davemloft.net D: Sparc and blue box hacker D: Vger Linux mailing list co-maintainer D: Linux Emacs elf/qmagic support + other libc/gcc things D: Yee bore de yee bore! ;-) -S: 750 N. Shoreline Blvd. -S: Apt. #111 -S: Mountain View, California 94043 +S: 575 Harrison St. #103 +S: San Francisco, CA 94105 S: USA N: Rick Miller @@ -2570,6 +2618,7 @@ E: nico@cam.org D: StrongARM SA1100 support integrator & hacker D: Xscale PXA architecture +D: unified SMC 91C9x/91C11x ethernet driver (smc91x) S: Montreal, Quebec, Canada N: Ken Pizzini @@ -2582,6 +2631,12 @@ D: sonypi, meye drivers, mct_u232 usb serial hacks S: Paris, France +N: Pete Popov +E: pete_popov@yahoo.com +D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging +S: San Jose, CA 95134 +S: USA + N: Matt Porter E: mporter@kernel.crashing.org D: Motorola PowerPC PReP support @@ -2797,7 +2852,7 @@ N: Paul `Rusty' Russell E: rusty@rustcorp.com.au -W: http://www.samba.org/netfilter +W: http://ozlabs.org/~rusty D: Ruggedly handsome. D: netfilter, ipchains with Michael Neuling. S: 52 Moore St @@ -2821,7 +2876,6 @@ S: Wellington S: New Zealand - N: Sampo Saaristo E: sambo@cs.tut.fi D: Co-author of Multi-Protocol Over ATM (MPOA) @@ -2838,6 +2892,9 @@ S: 8006 Zuerich S: Switzerland +N: Manuel Estrada Sainz +D: Firmware loader (request_firmware) + N: Wayne Salamon E: wsalamon@tislabs.com E: wsalamon@nai.com @@ -3289,14 +3346,6 @@ S: 10200 Prague 10, Hostivar S: Czech Republic -N: James R. Van Zandt -E: jrv@vanzandt.mv.com -P: 1024/E298966D F0 37 4F FD E5 7E C5 E6 F1 A0 1E 22 6F 46 DA 0C -D: Author and maintainer of the Double Talk speech synthesizer driver -S: 27 Spencer Drive -S: Nashua, New Hampshire 03062 -S: USA - N: Heikki Vatiainen E: hessu@cs.tut.fi D: Co-author of Multi-Protocol Over ATM (MPOA), some LANE hacks @@ -3387,6 +3436,18 @@ S: Berkeley, CA 94720-1776 S: USA +N: Harald Welte +E: laforge@netfilter.org +P: 1024D/30F48BFF DBDE 6912 8831 9A53 879B 9190 5DA5 C655 30F4 8BFF +W: http://gnumonks.org/users/laforge +D: netfilter: new nat helper infrastructure +D: netfilter: ULOG, ECN, DSCP target +D: netfilter: TTL match +D: netfilter: IPv6 mangle table +D: netfilter: various other hacks +S: Berlin +S: Germany + N: Bill Wendling E: wendling@ganymede.isdn.uiuc.edu W: http://www.ncsa.uiuc.edu/~wendling/ @@ -3578,6 +3639,14 @@ S: Tokyo 153 S: Japan +N: James R. Van Zandt +E: jrv@vanzandt.mv.com +P: 1024/E298966D F0 37 4F FD E5 7E C5 E6 F1 A0 1E 22 6F 46 DA 0C +D: Author and maintainer of the Double Talk speech synthesizer driver +S: 27 Spencer Drive +S: Nashua, New Hampshire 03062 +S: USA + N: Orest Zborowski E: orestz@eskimo.com D: XFree86 and kernel development @@ -3619,13 +3688,6 @@ D: EISA/sysfs subsystem S: France -N: Luiz Fernando N. Capitulino -E: lcapitulino@terra.com.br -E: lcapitulino@prefeitura.sp.gov.br -W: http://www.telecentros.sp.gov.br -D: Little fixes and a lot of janitorial work -S: E-GOV Telecentros SP -S: Brazil # Don't add your name here, unless you really _are_ after Marc # alphabetically. Leonard used to be very proud of being the diff -Nru a/Documentation/CodingStyle b/Documentation/CodingStyle --- a/Documentation/CodingStyle 2004-10-18 14:56:28 -07:00 +++ b/Documentation/CodingStyle 2004-10-18 14:56:28 -07:00 @@ -356,10 +356,10 @@ Macros with multiple statements should be enclosed in a do - while block: -#define macrofun(a,b,c) \ +#define macrofun(a, b, c) \ do { \ if (a == 5) \ - do_this(b,c); \ + do_this(b, c); \ } while (0) Things to avoid when using macros: diff -Nru a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt --- a/Documentation/DMA-API.txt 2004-10-18 14:56:32 -07:00 +++ b/Documentation/DMA-API.txt 2004-10-18 14:56:32 -07:00 @@ -444,4 +444,83 @@ continuing on for size. Again, you *must* observe the cache line boundaries when doing this. +int +dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int + flags) + + +Declare region of memory to be handed out by dma_alloc_coherent when +it's asked for coherent memory for this device. + +bus_addr is the physical address to which the memory is currently +assigned in the bus responding region (this will be used by the +platform to perform the mapping) + +device_addr is the physical address the device needs to be programmed +with actually to address this memory (this will be handed out as the +dma_addr_t in dma_alloc_coherent()) + +size is the size of the area (must be multiples of PAGE_SIZE). + +flags can be or'd together and are + +DMA_MEMORY_MAP - request that the memory returned from +dma_alloc_coherent() be directly writeable. + +DMA_MEMORY_IO - request that the memory returned from +dma_alloc_coherent() be addressable using read/write/memcpy_toio etc. + +One or both of these flags must be present + +DMA_MEMORY_INCLUDES_CHILDREN - make the declared memory be allocated by +dma_alloc_coherent of any child devices of this one (for memory residing +on a bridge). + +DMA_MEMORY_EXCLUSIVE - only allocate memory from the declared regions. +Do not allow dma_alloc_coherent() to fall back to system memory when +it's out of memory in the declared region. + +The return value will be either DMA_MEMORY_MAP or DMA_MEMORY_IO and +must correspond to a passed in flag (i.e. no returning DMA_MEMORY_IO +if only DMA_MEMORY_MAP were passed in) for success or zero for +failure. + +Note, for DMA_MEMORY_IO returns, all subsequent memory returned by +dma_alloc_coherent() may no longer be accessed directly, but instead +must be accessed using the correct bus functions. If your driver +isn't prepared to handle this contingency, it should not specify +DMA_MEMORY_IO in the input flags. + +As a simplification for the platforms, only *one* such region of +memory may be declared per device. + +For reasons of efficiency, most platforms choose to track the declared +region only at the granularity of a page. For smaller allocations, +you should use the dma_pool() API. + +void +dma_release_declared_memory(struct device *dev) + +Remove the memory region previously declared from the system. This +API performs *no* in-use checking for this region and will return +unconditionally having removed all the required structures. It is the +drivers job to ensure that no parts of this memory region are +currently in use. + +void * +dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size) + +This is used to occupy specific regions of the declared space +(dma_alloc_coherent() will hand out the first free region it finds). + +device_addr is the *device* address of the region requested + +size is the size (and should be a page sized multiple). + +The return value will be either a pointer to the processor virtual +address of the memory, or an error (via PTR_ERR()) if any part of the +region is occupied. + diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile --- a/Documentation/DocBook/Makefile 2004-10-18 14:56:29 -07:00 +++ b/Documentation/DocBook/Makefile 2004-10-18 14:56:29 -07:00 @@ -185,9 +185,7 @@ $(patsubst %.sgml, %.9, $(DOCBOOKS)) \ $(C-procfs-example) -ifneq ($(wildcard $(patsubst %.html,%,$(HTML))),) -clean-rule := rm -rf $(wildcard $(patsubst %.html,%,$(HTML))) -endif +clean-dirs := $(patsubst %.sgml,%,$(DOCBOOKS)) #man put files in man subdir - traverse down subdir- := man/ diff -Nru a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl --- a/Documentation/DocBook/gadget.tmpl 2004-10-18 14:56:31 -07:00 +++ b/Documentation/DocBook/gadget.tmpl 2004-10-18 14:56:31 -07:00 @@ -2,8 +2,8 @@ USB Gadget API for Linux - 02 June 2003 - 02 June 2003 + 20 August 2004 + 20 August 2004 @@ -34,7 +34,7 @@ - 2003 + 2003-2004 David Brownell @@ -73,9 +73,13 @@ composite devices, and alternate interface settings. + USB "On-The-Go" (OTG) support, in conjunction + with updates to the Linux-USB host side. + Sharing data structures and API models with the - Linux-USB host side API. This looks forward to USB "On-The-Go" - (OTG) and similar more-symmetric frameworks. + Linux-USB host side API. This helps the OTG support, and + looks forward to more-symmetric frameworks (where the same + I/O model is used by both host and device side drivers). Minimalist, so it's easier to support new device controller hardware. I/O processing doesn't imply large @@ -153,6 +157,7 @@ the SA-11x0 or PXA-25x UDC (found within many PDAs), and a variety of other products. + @@ -162,10 +167,14 @@ The lower boundary of this driver implements hardware-neutral USB functions, using calls to the controller driver. Because such hardware varies widely in capabilities and restrictions, - the gadget driver is normally configured at compile time + and is used in embedded environments where space is at a premium, + the gadget driver is often configured at compile time to work with endpoints supported by one particular controller. Gadget drivers may be portable to several different controllers, using conditional compilation. + (Recent kernels substantially simplify the work involved in + supporting new hardware, by autoconfiguring + endpoints automatically for many bulk-oriented drivers.) Gadget driver responsibilities include: @@ -178,8 +187,9 @@ altsettings, including enabling and configuring endpoints handling life cycle events, such as managing - bindings - to hardware, and disconnection from the USB host. + bindings to hardware, + USB suspend/resume, remote wakeup, + and disconnection from the USB host. managing IN and OUT transfers on all currently enabled endpoints @@ -244,15 +254,38 @@ -Over time, reusable utilities should evolve to help make some -gadget driver tasks simpler. An example of particular interest +OTG-capable systems will also need to include a standard Linux-USB +host side stack, +with usbcore, +one or more Host Controller Drivers (HCDs), +USB Device Drivers to support +the OTG "Targeted Peripheral List", +and so forth. +There will also be an OTG Controller Driver, +which is visible to gadget and device driver developers only indirectly. +That helps the host and device side USB controllers implement the +two new OTG protocols (HNP and SRP). +Roles switch (host to peripheral, or vice versa) using HNP +during USB suspend processing, and SRP can be viewed as a +more battery-friendly kind of device wakeup protocol. + + +Over time, reusable utilities are evolving to help make some +gadget driver tasks simpler. +For example, building configuration descriptors from vectors of +descriptors for the configurations interfaces and endpoints is +now automated, and many drivers now use autoconfiguration to +choose hardware endpoints and initialize their descriptors. + +A potential example of particular interest is code implementing standard USB-IF protocols for HID, networking, storage, or audio classes. Some developers are interested in KDB or KGDB hooks, to let target hardware be remotely debugged. Most such USB protocol code doesn't need to be hardware-specific, any more than network protocols like X11, HTTP, or NFS are. -Such interface drivers might be combined, to support composite devices. +Such gadget-side interface drivers should eventually be combined, +to implement composite devices. @@ -284,7 +317,7 @@ However, docproc does not understand all the C constructs that are used, so some relevant information is likely omitted from what you are reading. -One example of such information is several per-request flags. +One example of such information is endpoint autoconfiguration. You'll have to read the header file, and use example source code (such as that for "Gadget Zero"), to fully understand the API. @@ -292,7 +325,7 @@ The part of the API implementing some basic driver capabilities is specific to the version of the Linux kernel that's in use. -The 2.5 kernel includes a driver model +The 2.6 kernel includes a driver model framework that has no analogue on earlier kernels; so those parts of the gadget API are not fully portable. (They are implemented on 2.4 kernels, but in a different way.) @@ -308,17 +341,21 @@ that would be added using hardware-specific APIs. -This API expects drivers to use conditional compilation to handle -endpoint capabilities of different hardware. -Those tend to have arbitrary restrictions, relating to +This API allows drivers to use conditional compilation to handle +endpoint capabilities of different hardware, but doesn't require that. +Hardware tends to have arbitrary restrictions, relating to transfer types, addressing, packet sizes, buffering, and availability. As a rule, such differences only matter for "endpoint zero" logic that handles device configuration and management. -The API only supports limited run-time +The API supports limited run-time detection of capabilities, through naming conventions for endpoints. -Although a gadget driver could scan the endpoints available to it and -choose to map those capabilities onto driver functionality in some way, -few drivers will want to reconfigure themselves at run-time. +Many drivers will be able to at least partially autoconfigure +themselves. +In particular, driver init sections will often have endpoint +autoconfiguration logic that scans the hardware's list of endpoints +to find ones matching the driver requirements +(relying on those conventions), to eliminate some of the most +common reasons for conditional compilation. Like the Linux-USB host side API, this API exposes @@ -355,10 +392,14 @@ At this point the device is logically in the USB ch9 initial state ("attached"), drawing no power and not usable (since it does not yet support enumeration). +Any host should not see the device, since it's not +activated the data line pullup used by the host to +detect a device, even if VBUS power is available. Register a gadget driver that implements some higher level -device function. That will then bind() to a usb_gadget. +device function. That will then bind() to a usb_gadget, which +activates the data line pullup sometime after detecting VBUS. The hardware driver can now start enumerating. @@ -373,6 +414,8 @@ functionality being implemented. That can involve alternate settings or configurations, unless the hardware prevents such operation. +For OTG devices, each configuration descriptor includes +an OTG descriptor. The gadget driver handles the last step of enumeration, @@ -381,13 +424,18 @@ with all interfaces in their default settings. That involves using a list of the hardware's endpoints, enabling each endpoint according to its descriptor. +It may also involve using usb_gadget_vbus_draw +to let more power be drawn from VBUS, as allowed by that configuration. +For OTG devices, setting a configuration may also involve reporting +HNP capabilities through a user interface. Do real work and perform data transfers, possibly involving changes to interface settings or switching to new configurations, until the device is disconnect()ed from the host. Queue any number of transfer requests to each endpoint. -The drivers then go back to step 3 (above). +It may be suspended and resumed several times before being disconnected. +On disconnect, the drivers go back to step 3 (above). When the gadget driver module is being unloaded, @@ -399,7 +447,9 @@ Drivers will normally be arranged so that just loading the gadget driver module (or statically linking it into a Linux kernel) -allows the peripheral device to be enumerated. +allows the peripheral device to be enumerated, but some drivers +will defer enumeration until some higher level component (like +a user mode daemon) enables it. Note that at this lowest level there are no policies about how ep0 configuration logic is implemented, except that it should obey USB specifications. @@ -410,6 +460,18 @@ be built by integrating reusable components. +Note that the lifecycle above can be slightly different +for OTG devices. +Other than providing an additional OTG descriptor in each +configuration, only the HNP-related differences are particularly +visible to driver code. +They involve reporting requirements during the SET_CONFIGURATION +request, and the option to invoke HNP during some suspend callbacks. +Also, SRP changes the semantics of +usb_gadget_wakeup +slightly. + + USB 2.0 Chapter 9 Types and Constants @@ -418,9 +480,9 @@ rely on common USB structures and constants defined in the <linux/usb_ch9.h> -header file, which is standard in Linux 2.5 kernels. +header file, which is standard in Linux 2.6 kernels. These are the same types and constants used by host -side drivers. +side drivers (and usbcore). !Iinclude/linux/usb_ch9.h @@ -451,26 +513,38 @@ The core API is sufficient for writing a USB Gadget Driver, but some optional utilities are provided to simplify common tasks. +These utilities include endpoint autoconfiguration. !Edrivers/usb/gadget/usbstring.c !Edrivers/usb/gadget/config.c + Peripheral Controller Drivers -The first hardware supporting this API is the NetChip 2280 +The first hardware supporting this API was the NetChip 2280 controller, which supports USB 2.0 high speed and is based on PCI. This is the net2280 driver module. -The driver supports Linux kernel versions 2.4 and 2.5; +The driver supports Linux kernel versions 2.4 and 2.6; contact NetChip Technologies for development boards and product information. -For users of Intel's PXA 2xx series processors, -a pxa2xx_udc driver is available. +Other hardware working in the "gadget" framework includes: +Intel's PXA 25x and IXP42x series processors +(pxa2xx_udc), +Toshiba TC86c001 "Goku-S" (goku_udc), +Renesas SH7705/7727 (sh_udc), +MediaQ 11xx (mq11xx_udc), +Hynix HMS30C7202 (h7202_udc), +National 9303/4 (n9604_udc), +Texas Instruments OMAP (omap_udc), +Sharp LH7A40x (lh7a40x_udc), +and more. +Most of those are full speed controllers. At this writing, there are people at work on drivers in @@ -526,6 +600,15 @@ to avoid creating problems.) +Support for Microsoft's RNDIS +protocol has been contributed by Pengutronix and Auerswald GmbH. +This is like CDC Ethernet, but it runs on more slightly USB hardware +(but less than the CDC subset). +However, its main claim to fame is being able to connect directly to +recent versions of Windows, using drivers that Microsoft bundles +and supports, making it much simpler to network with Windows. + + There is also support for user mode gadget drivers, using gadgetfs. This provides a User Mode API that presents @@ -535,6 +618,10 @@ develop and debug user mode drivers, so that once a robust controller driver is available many applications for it won't require new kernel mode software. +Linux 2.6 Async I/O (AIO) +support is available, so that user mode software +can stream data with only slightly more overhead +than a kernel driver. There's a USB Mass Storage class driver, which provides @@ -548,6 +635,16 @@ to access the data from the backing store. +There's a "serial line" driver, useful for TTY style +operation over USB. +The latest version of that driver supports CDC ACM style +operation, like a USB modem, and so on most hardware it can +interoperate easily with MS-Windows. +One interesting use of that driver is in boot firmware (like a BIOS), +which can sometimes use that model with very small systems without +real serial lines. + + Support for other kinds of gadget is expected to be developed and contributed over time, as this driver framework evolves. @@ -555,6 +652,96 @@ +USB On-The-GO (OTG) + +USB OTG support on Linux 2.6 was initially developed +by Texas Instruments for +OMAP 16xx and 17xx +series processors. +Other OTG systems should work in similar ways, but the +hardware level details could be very different. + + +Systems need specialized hardware support to implement OTG, +notably including a special Mini-AB jack +and associated transciever to support Dual-Role +operation: +they can act either as a host, using the standard +Linux-USB host side driver stack, +or as a peripheral, using this "gadget" framework. +To do that, the system software relies on small additions +to those programming interfaces, +and on a new internal component (here called an "OTG Controller") +affecting which driver stack connects to the OTG port. +In each role, the system can re-use the existing pool of +hardware-neutral drivers, layered on top of the controller +driver interfaces (usb_bus or +usb_gadget). +Such drivers need at most minor changes, and most of the calls +added to support OTG can also benefit non-OTG products. + + + + Gadget drivers test the is_otg + flag, and use it to determine whether or not to include + an OTG descriptor in each of their configurations. + + Gadget drivers may need changes to support the + two new OTG protocols, exposed in new gadget attributes + such as b_hnp_enable flag. + HNP support should be reported through a user interface + (two LEDs could suffice), and is triggered in some cases + when the host suspends the peripheral. + SRP support can be user-initiated just like remote wakeup, + probably by pressing the same button. + + On the host side, USB device drivers need + to be taught to trigger HNP at appropriate moments, using + usb_suspend_device(). + That also conserves battery power, which is useful even + for non-OTG configurations. + + Also on the host side, a driver must support the + OTG "Targeted Peripheral List". That's just a whitelist, + used to reject peripherals not supported with a given + Linux OTG host. + This whitelist is product-specific; + each product must modify otg_whitelist.h + to match its interoperability specification. + + + Non-OTG Linux hosts, like PCs and workstations, + normally have some solution for adding drivers, so that + peripherals that aren't recognized can eventually be supported. + That approach is unreasonable for consumer products that may + never have their firmware upgraded, and where it's usually + unrealistic to expect traditional PC/workstation/server kinds + of support model to work. + For example, it's often impractical to change device firmware + once the product has been distributed, so driver bugs can't + normally be fixed if they're found after shipment. + + + + +Additional changes are needed below those hardware-neutral +usb_bus and usb_gadget +driver interfaces; those aren't discussed here in any detail. +Those affect the hardware-specific code for each USB Host or Peripheral +controller, and how the HCD initializes (since OTG can be active only +on a single port). +They also involve what may be called an OTG Controller +Driver, managing the OTG transceiver and the OTG state +machine logic as well as much of the root hub behavior for the +OTG port. +The OTG controller driver needs to activate and deactivate USB +controllers depending on the relevant device role. +Some related changes were needed inside usbcore, so that it +can identify OTG-capable devices and respond appropriately +to HNP or SRP protocols. + + + Slave NPU + * | + * | + * P2P + * | + * + * Bus 1 | + * <--+------+---------+---------+------+--> + * | | | | | + * | | | | | + * ... Dev PMC Media Eth0 Eth1 ... + * + * The master controlls all but Eth1, which is controlled by the + * slave. What this measn is that the both the master and the slave + * have to scan the bus, but only one of them can enumerate the bus. + * In addition, after the bus is scaned, each kernel must remove + * the device(s) it does not control from the PCI dev list otherwise + * a driver on each NPU will try to manage it and we will have horrible + * conflicts. Oh..and the slave NPU needs to see the master NPU + * for Intel's drivers to work properly. Closed source drivers... + * + * The way we deal with this is fairly simple but ugly: + * + * 1) Let master scan and enumerate the bus completely. + * 2) Master deletes Eth1 from device list. + * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave) + * from device list. + * 4) Find HW designers and LART them. + * + * The boards also do not do normal PCI IRQ routing, or any sort of + * sensical swizzling, so we just need to check where on the bus a + * device sits and figure out to which CPLD pin the interrupt is routed. + * See ixdp2[48]00.c files. + * + *************************************************************************/ +void ixdp2x00_slave_pci_postinit(void) +{ + struct pci_dev *dev; + + /* + * Remove PMC device is there is one + */ + if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN))) + pci_remove_bus_device(dev); + + dev = pci_find_slot(0, IXDP2X00_21555_DEVFN); + pci_remove_bus_device(dev); +} + +/************************************************************************** + * IXDP2x00 Machine Setup + *************************************************************************/ +static struct flash_platform_data ixdp2x00_platform_data = { + .map_name = "cfi_probe", + .width = 1, +}; + +static struct ixp2000_flash_data ixdp2x00_flash_data = { + .platform_data = &ixdp2x00_platform_data, + .nr_banks = 1 +}; + +static struct resource ixdp2x00_flash_resource = { + .start = 0xc4000000, + .end = 0xc4000000 + 0x00ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ixdp2x00_flash = { + .name = "IXP2000-Flash", + .id = 0, + .dev = { + .platform_data = &ixdp2x00_flash_data, + }, + .num_resources = 1, + .resource = &ixdp2x00_flash_resource, +}; + +static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = { + .sda_pin = IXDP2X00_GPIO_SDA, + .scl_pin = IXDP2X00_GPIO_SCL, +}; + +static struct platform_device ixdp2x00_i2c_controller = { + .name = "IXP2000-I2C", + .id = 0, + .dev = { + .platform_data = &ixdp2x00_i2c_gpio_pins, + }, + .num_resources = 0 +}; + +static struct platform_device *ixdp2x00_devices[] __initdata = { + &ixdp2x00_flash, + &ixdp2x00_i2c_controller +}; + +void __init ixdp2x00_init_machine(void) +{ + gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1); + gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT); + + platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices)); +} + diff -Nru a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-ixp2000/ixdp2x01.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,381 @@ +/* + * arch/arm/mach-ixp2000/ixdp2x01.c + * + * Code common to Intel IXDP2401 and IXDP2801 platforms + * + * Original Author: Andrzej Mialwoski + * Maintainer: Deepak Saxena + * + * Copyright (C) 2002-2003 Intel Corp. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/************************************************************************* + * IXDP2x01 IRQ Handling + *************************************************************************/ +static void ixdp2x01_irq_mask(unsigned int irq) +{ + *IXDP2X01_INT_MASK_SET_REG = IXP2000_BOARD_IRQ_MASK(irq); +} + +static void ixdp2x01_irq_unmask(unsigned int irq) +{ + *IXDP2X01_INT_MASK_CLR_REG = IXP2000_BOARD_IRQ_MASK(irq); +} + +static u32 valid_irq_mask; + +static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + u32 ex_interrupt; + int i; + + desc->chip->mask(irq); + + ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask; + + if (!ex_interrupt) { + printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n"); + return; + } + + for (i = 0; i < IXP2000_BOARD_IRQS; i++) { + if (ex_interrupt & (1 << i)) { + struct irqdesc *cpld_desc; + int cpld_irq = IXP2000_BOARD_IRQ(0) + i; + cpld_desc = irq_desc + cpld_irq; + cpld_desc->handle(cpld_irq, cpld_desc, regs); + } + } + + desc->chip->unmask(irq); +} + +static struct irqchip ixdp2x01_irq_chip = { + .mask = ixdp2x01_irq_mask, + .ack = ixdp2x01_irq_mask, + .unmask = ixdp2x01_irq_unmask +}; + +/* + * We only do anything if we are the master NPU on the board. + * The slave NPU only has the ethernet chip going directly to + * the PCIB interrupt input. + */ +void __init ixdp2x01_init_irq(void) +{ + int irq = 0; + + /* initialize chip specific interrupts */ + ixp2000_init_irq(); + + if (machine_is_ixdp2401()) + valid_irq_mask = IXDP2401_VALID_IRQ_MASK; + else + valid_irq_mask = IXDP2801_VALID_IRQ_MASK; + + /* Mask all interrupts from CPLD, disable simulation */ + *IXDP2X01_INT_MASK_SET_REG = 0xffffffff; + *IXDP2X01_INT_SIM_REG = 0; + + for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { + if (irq & valid_irq_mask) { + set_irq_chip(irq, &ixdp2x01_irq_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); + } else { + set_irq_flags(irq, 0); + } + } + + /* Hook into PCI interrupts */ + set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler); +} + + +/************************************************************************* + * IXDP2x01 memory map and serial ports + *************************************************************************/ +static struct map_desc ixdp2x01_io_desc __initdata = { + .virtual = IXDP2X01_VIRT_CPLD_BASE, + .physical = IXDP2X01_PHYS_CPLD_BASE, + .length = IXDP2X01_CPLD_REGION_SIZE, + .type = MT_DEVICE +}; + +static struct uart_port ixdp2x01_serial_ports[2] = { + { + .membase = (char *)(IXDP2X01_UART1_VIRT_BASE), + .mapbase = (unsigned long)IXDP2X01_UART1_PHYS_BASE, + .irq = IRQ_IXDP2X01_UART1, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM32, + .regshift = 2, + .uartclk = IXDP2X01_UART_CLK, + .line = 1, + .type = PORT_16550A, + .fifosize = 16 + }, { + .membase = (char *)(IXDP2X01_UART2_VIRT_BASE), + .mapbase = (unsigned long)IXDP2X01_UART2_PHYS_BASE, + .irq = IRQ_IXDP2X01_UART2, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM32, + .regshift = 2, + .uartclk = IXDP2X01_UART_CLK, + .line = 2, + .type = PORT_16550A, + .fifosize = 16 + }, +}; + +static void __init ixdp2x01_map_io(void) +{ + ixp2000_map_io(); + + iotable_init(&ixdp2x01_io_desc, 1); + + early_serial_setup(&ixdp2x01_serial_ports[0]); + early_serial_setup(&ixdp2x01_serial_ports[1]); +} + + +/************************************************************************* + * IXDP2x01 timer tick configuration + *************************************************************************/ +static unsigned int ixdp2x01_clock; + +static int __init ixdp2x01_clock_setup(char *str) +{ + ixdp2x01_clock = simple_strtoul(str, NULL, 10); + + return 1; +} + +__setup("ixdp2x01_clock=", ixdp2x01_clock_setup); + +static void __init ixdp2x01_init_time(void) +{ + if (!ixdp2x01_clock) + ixdp2x01_clock = 50000000; + + ixp2000_init_time(ixdp2x01_clock); +} + +/************************************************************************* + * IXDP2x01 PCI + *************************************************************************/ +void __init ixdp2x01_pci_preinit(void) +{ + ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000); + ixp2000_pci_preinit(); +} + +#define DEVPIN(dev, pin) ((pin) | ((dev) << 3)) + +static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + u8 bus = dev->bus->number; + u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin); + struct pci_bus *tmp_bus = dev->bus; + + /* Primary bus, no interrupts here */ + if (bus == 0) { + return -1; + } + + /* Lookup first leaf in bus tree */ + while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) { + tmp_bus = tmp_bus->parent; + } + + /* Select between known bridges */ + switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) { + /* Device is located after first MB bridge */ + case 0x0008: + if (tmp_bus == dev->bus) { + /* Device is located directy after first MB bridge */ + switch (devpin) { + case DEVPIN(1, 1): /* Onboard 82546 ch 0 */ + if (machine_is_ixdp2401()) + return IRQ_IXDP2401_INTA_82546; + return -1; + case DEVPIN(1, 2): /* Onboard 82546 ch 1 */ + if (machine_is_ixdp2401()) + return IRQ_IXDP2401_INTB_82546; + return -1; + case DEVPIN(0, 1): /* PMC INTA# */ + return IRQ_IXDP2X01_SPCI_PMC_INTA; + case DEVPIN(0, 2): /* PMC INTB# */ + return IRQ_IXDP2X01_SPCI_PMC_INTB; + case DEVPIN(0, 3): /* PMC INTC# */ + return IRQ_IXDP2X01_SPCI_PMC_INTC; + case DEVPIN(0, 4): /* PMC INTD# */ + return IRQ_IXDP2X01_SPCI_PMC_INTD; + } + } + break; + case 0x0010: + if (tmp_bus == dev->bus) { + /* Device is located directy after second MB bridge */ + /* Secondary bus of second bridge */ + switch (devpin) { + case DEVPIN(0, 1): /* DB#0 */ + return IRQ_IXDP2X01_SPCI_DB_0; + case DEVPIN(1, 1): /* DB#1 */ + return IRQ_IXDP2X01_SPCI_DB_1; + } + } else { + /* Device is located indirectly after second MB bridge */ + /* Not supported now */ + } + break; + } + + return -1; +} + + +static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys) +{ + sys->mem_offset = 0xe0000000; + + if (machine_is_ixdp2801()) + sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16); + + return ixp2000_pci_setup(nr, sys); +} + +struct hw_pci ixdp2x01_pci __initdata = { + .nr_controllers = 1, + .setup = ixdp2x01_pci_setup, + .preinit = ixdp2x01_pci_preinit, + .scan = ixp2000_pci_scan_bus, + .map_irq = ixdp2x01_pci_map_irq, +}; + +int __init ixdp2x01_pci_init(void) +{ + + pci_common_init(&ixdp2x01_pci); + return 0; +} + +subsys_initcall(ixdp2x01_pci_init); + +/************************************************************************* + * IXDP2x01 Machine Intialization + *************************************************************************/ +static struct flash_platform_data ixdp2x01_flash_platform_data = { + .map_name = "cfi_probe", + .width = 1, +}; + +static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) +{ + *IXDP2X01_CPLD_FLASH_REG = + ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN); + return (ofs & IXDP2X01_FLASH_WINDOW_MASK); +} + +static struct ixp2000_flash_data ixdp2x01_flash_data = { + .platform_data = &ixdp2x01_flash_platform_data, + .bank_setup = ixdp2x01_flash_bank_setup +}; + +static struct resource ixdp2x01_flash_resource = { + .start = 0xc4000000, + .end = 0xc4000000 + 0x01ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ixdp2x01_flash = { + .name = "IXP2000-Flash", + .id = 0, + .dev = { + .platform_data = &ixdp2x01_flash_data, + }, + .num_resources = 1, + .resource = &ixdp2x01_flash_resource, +}; + +static struct platform_device *ixdp2x01_devices[] __initdata = { + &ixdp2x01_flash +}; + +static void __init ixdp2x01_init_machine(void) +{ + *IXDP2X01_CPLD_FLASH_REG = + (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN); + + ixdp2x01_flash_data.nr_banks = + ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1); + + platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices)); +} + + +#ifdef CONFIG_ARCH_IXDP2401 +MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE) + BOOT_PARAMS(0x00000100) + MAPIO(ixdp2x01_map_io) + INITIRQ(ixdp2x01_init_irq) + INITTIME(ixdp2x01_init_time) + INIT_MACHINE(ixdp2x01_init_machine) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_IXDP2801 +MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE) + BOOT_PARAMS(0x00000100) + MAPIO(ixdp2x01_map_io) + INITIRQ(ixdp2x01_init_irq) + INITTIME(ixdp2x01_init_time) + INIT_MACHINE(ixdp2x01_init_machine) +MACHINE_END +#endif + + diff -Nru a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-ixp2000/pci.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,233 @@ +/* + * arch/arm/mach-ixp2000/pci.c + * + * PCI routines for IXDP2400/IXDP2800 boards + * + * Original Author: Naeem Afzal + * Maintained by: Deepak Saxena + * + * Copyright 2002 Intel Corp. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +static int pci_master_aborts = 0; + +static int clear_master_aborts(void); + +static u32 * +ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where) +{ + u32 *paddress; + + if (PCI_SLOT(devfn) > 7) + return 0; + + /* Must be dword aligned */ + where &= ~3; + + /* + * For top bus, generate type 0, else type 1 + */ + if (!bus_nr) { + /* only bits[23:16] are used for IDSEL */ + paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE + | (1 << (PCI_SLOT(devfn) + 16)) + | (PCI_FUNC(devfn) << 8) | where); + } else { + paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE + | (bus_nr << 16) + | (PCI_SLOT(devfn) << 11) + | (PCI_FUNC(devfn) << 8) | where); + } + + return paddress; +} + +/* + * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes. + * 0 and 3 are not valid indexes... + */ +static u32 bytemask[] = { + /*0*/ 0, + /*1*/ 0xff, + /*2*/ 0xffff, + /*3*/ 0, + /*4*/ 0xffffffff, +}; + + +int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + u32 n; + u32 *addr; + + n = where % 4; + + addr = ixp2000_pci_config_addr(bus->number, devfn, where); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + pci_master_aborts = 0; + *value = (*addr >> (8*n)) & bytemask[size]; + if (pci_master_aborts) { + pci_master_aborts = 0; + *value = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + +/* + * We don't do error checks by callling clear_master_aborts() b/c the + * assumption is that the caller did a read first to make sure a device + * exists. + */ +int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + u32 mask; + u32 *addr; + u32 temp; + + mask = ~(bytemask[size] << ((where % 0x4) * 8)); + addr = ixp2000_pci_config_addr(bus->number, devfn, where); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + temp = (u32) (value) << ((where % 0x4) * 8); + *addr = (*addr & mask) | temp; + + clear_master_aborts(); + + return PCIBIOS_SUCCESSFUL; +} + + +static struct pci_ops ixp2000_pci_ops = { + .read = ixp2000_pci_read_config, + .write = ixp2000_pci_write_config +}; + +struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata) +{ + return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata); +} + + +int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + + volatile u32 temp; + + pci_master_aborts = 1; + + cli(); + temp = *(IXP2000_PCI_CONTROL); + if (temp & ((1 << 8) | (1 << 5))) { + *(IXP2000_PCI_CONTROL) = temp; + } + + temp = *(IXP2000_PCI_CMDSTAT); + if (temp & (1 << 29)) { + while (temp & (1 << 29)) { + *(IXP2000_PCI_CMDSTAT) = temp; + temp = *(IXP2000_PCI_CMDSTAT); + } + } + sti(); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + +int +clear_master_aborts(void) +{ + volatile u32 temp; + + cli(); + temp = *(IXP2000_PCI_CONTROL); + if (temp & ((1 << 8) | (1 << 5))) { + *(IXP2000_PCI_CONTROL) = temp; + } + + temp = *(IXP2000_PCI_CMDSTAT); + if (temp & (1 << 29)) { + while (temp & (1 << 29)) { + *(IXP2000_PCI_CMDSTAT) = temp; + temp = *(IXP2000_PCI_CMDSTAT); + } + } + sti(); + + return 0; +} + +void __init +ixp2000_pci_preinit(void) +{ + hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, + "PCI config cycle to non-existent device"); +} + + +/* + * IXP2000 systems often have large resource requirements, so we just + * use our own resource space. + */ +static struct resource ixp2000_pci_mem_space = { + .start = 0x00000000, + .end = 0xffffffff, + .flags = IORESOURCE_MEM, + .name = "PCI Mem Space" +}; + +static struct resource ixp2000_pci_io_space = { + .start = 0x00000000, + .end = 0xffffffff, + .flags = IORESOURCE_IO, + .name = "PCI I/O Space" +}; + +int ixp2000_pci_setup(int nr, struct pci_sys_data *sys) +{ + if (nr >= 1) + return 0; + + sys->resource[0] = &ixp2000_pci_io_space; + sys->resource[1] = &ixp2000_pci_mem_space; + sys->resource[2] = NULL; + + return 1; +} + diff -Nru a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c --- a/arch/arm/mach-ixp4xx/common.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mach-ixp4xx/common.c 2004-10-18 14:56:32 -07:00 @@ -207,7 +207,7 @@ static unsigned volatile last_jiffy_time; -#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC) +#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) /* IRQs are disabled before entering here from do_gettimeofday() */ static unsigned long ixp4xx_gettimeoffset(void) diff -Nru a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c 2004-10-18 14:55:54 -07:00 @@ -45,7 +45,6 @@ .resource = smc91x_resources, }; -#if 0 static struct resource lh7a40x_usbclient_resources[] = { [0] = { .start = USB_PHYS, @@ -53,8 +52,8 @@ .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_USB, - .end = IRQ_USB, + .start = IRQ_USBINTR, + .end = IRQ_USBINTR, .flags = IORESOURCE_IRQ, }, }; @@ -62,7 +61,7 @@ static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL; static struct platform_device lh7a40x_usbclient_device = { - .name = "lh7a40x-udc", + .name = "lh7a40x_udc", .id = 0, .dev = { .dma_mask = &lh7a40x_usbclient_dma_mask, @@ -71,7 +70,6 @@ .num_resources = ARRAY_SIZE (lh7a40x_usbclient_resources), .resource = lh7a40x_usbclient_resources, }; -#endif #if defined (CONFIG_ARCH_LH7A404) @@ -105,8 +103,7 @@ static struct platform_device *lpd7a40x_devs[] __initdata = { &smc91x_device, -/* &lh7a40x_usbclient_device, */ - + &lh7a40x_usbclient_device, #if defined (CONFIG_ARCH_LH7A404) &lh7a404_usbhost_device, #endif diff -Nru a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c --- a/arch/arm/mach-lh7a40x/time.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mach-lh7a40x/time.c 2004-10-18 14:56:32 -07:00 @@ -22,12 +22,12 @@ #include #if HZ < 100 -# define TIMER_CONTROL TIMER_CONTROL1 -# define TIMER_LOAD TIMER_LOAD1 +# define TIMER_CONTROL TIMER_CONTROL2 +# define TIMER_LOAD TIMER_LOAD2 # define TIMER_CONSTANT (508469/HZ) # define TIMER_MODE (TIMER_C_ENABLE | TIMER_C_PERIODIC | TIMER_C_508KHZ) -# define TIMER_EOI TIMER_EOI1 -# define TIMER_IRQ IRQ_T1UI +# define TIMER_EOI TIMER_EOI2 +# define TIMER_IRQ IRQ_T2UI #else # define TIMER_CONTROL TIMER_CONTROL3 # define TIMER_LOAD TIMER_LOAD3 diff -Nru a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile --- a/arch/arm/mach-omap/Makefile 2004-10-18 14:56:13 -07:00 +++ b/arch/arm/mach-omap/Makefile 2004-10-18 14:56:13 -07:00 @@ -3,25 +3,29 @@ # # Common support -obj-y := common.o irq.o dma.o clocks.o mux.o bus.o gpio.o time.o +obj-y := common.o time.o irq.o dma.o clocks.o mux.o gpio.o mcbsp.o obj-m := obj-n := obj- := led-y := leds.o # Specific board support +obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o +obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o -# OCPI interconnect support for 1610 and 5912 +# OCPI interconnect support for 1710, 1610 and 5912 +obj-$(CONFIG_ARCH_OMAP1710) += ocpi.o obj-$(CONFIG_ARCH_OMAP1610) += ocpi.o obj-$(CONFIG_ARCH_OMAP5912) += ocpi.o # LEDs support +led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o -led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-perseus2.o +led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o obj-$(CONFIG_LEDS) += $(led-y) # Power Management diff -Nru a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c --- a/arch/arm/mach-omap/board-generic.c 2004-10-18 14:56:33 -07:00 +++ b/arch/arm/mach-omap/board-generic.c 2004-10-18 14:56:33 -07:00 @@ -25,9 +25,13 @@ #include #include #include +#include +#include #include "common.h" +extern void __init omap_init_time(void); + static void __init omap_generic_init_irq(void) { omap_init_irq(); @@ -36,17 +40,49 @@ /* * Muxes the serial ports on */ +#ifdef CONFIG_ARCH_OMAP1510 static void __init omap_early_serial_init(void) { +#ifdef CONFIG_OMAP_LL_DEBUG_UART1 omap_cfg_reg(UART1_TX); omap_cfg_reg(UART1_RTS); +#endif +#ifdef CONFIG_OMAP_LL_DEBUG_UART2 omap_cfg_reg(UART2_TX); omap_cfg_reg(UART2_RTS); +#endif +#ifdef CONFIG_OMAP_LL_DEBUG_UART1 omap_cfg_reg(UART3_TX); omap_cfg_reg(UART3_RX); +#endif } +#endif + +/* assume no Mini-AB port */ + +#ifdef CONFIG_ARCH_OMAP1510 +static struct omap_usb_config generic1510_usb_config __initdata = { + .register_host = 1, + .register_dev = 1, + .hmc_mode = 16, + .pins[0] = 3, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP1610 +static struct omap_usb_config generic1610_usb_config __initdata = { + .register_host = 1, + .register_dev = 1, + .hmc_mode = 16, + .pins[0] = 6, +}; +#endif + +static struct omap_board_config_kernel generic_config[] = { + { OMAP_TAG_USB, NULL }, +}; static void __init omap_generic_init(void) { @@ -55,9 +91,19 @@ * You have to mux them off in device drivers later on * if not needed. */ +#ifdef CONFIG_ARCH_OMAP1510 if (cpu_is_omap1510()) { omap_early_serial_init(); + generic_config[0].data = &generic1510_usb_config; + } +#endif +#ifdef CONFIG_ARCH_OMAP1610 + if (!cpu_is_omap1510()) { + generic_config[0].data = &generic1610_usb_config; } +#endif + omap_board_config = generic_config; + omap_board_config_size = ARRAY_SIZE(generic_config); } static void __init omap_generic_map_io(void) @@ -65,18 +111,12 @@ omap_map_io(); } -static void __init omap_generic_init_time(void) -{ - omap_init_time(); -} - -MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610/1710") +MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710") MAINTAINER("Tony Lindgren ") BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) BOOT_PARAMS(0x10000100) MAPIO(omap_generic_map_io) INITIRQ(omap_generic_init_irq) INIT_MACHINE(omap_generic_init) - INITTIME(omap_generic_init_time) + INITTIME(omap_init_time) MACHINE_END - diff -Nru a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap/board-h2.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/board-h2.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,115 @@ +/* + * linux/arch/arm/mach-omap/board-h2.c + * + * Board specific inits for OMAP-1610 H2 + * + * Copyright (C) 2001 RidgeRun, Inc. + * Author: Greg Lonnon + * + * Copyright (C) 2002 MontaVista Software, Inc. + * + * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 + * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen + * + * H2 specific changes and cleanup + * Copyright (C) 2004 Nokia Corporation by Imre Deak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "common.h" + +extern void __init omap_init_time(void); + +static struct map_desc h2_io_desc[] __initdata = { +{ OMAP1610_ETHR_BASE, OMAP1610_ETHR_START, OMAP1610_ETHR_SIZE,MT_DEVICE }, +{ OMAP1610_NOR_FLASH_BASE, OMAP1610_NOR_FLASH_START, OMAP1610_NOR_FLASH_SIZE, + MT_DEVICE }, +}; + +static struct resource h2_smc91x_resources[] = { + [0] = { + .start = OMAP1610_ETHR_START, /* Physical */ + .end = OMAP1610_ETHR_START + SZ_4K, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0, /* Really GPIO 0 */ + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device h2_smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(h2_smc91x_resources), + .resource = h2_smc91x_resources, +}; + +static struct platform_device *h2_devices[] __initdata = { + &h2_smc91x_device, +}; + +void h2_init_irq(void) +{ + omap_init_irq(); +} + +static struct omap_usb_config h2_usb_config __initdata = { + /* usb1 has a Mini-AB port and external isp1301 transceiver */ + .otg = 2, + +#ifdef CONFIG_USB_GADGET_OMAP + .hmc_mode = 19, // 0:host(off) 1:dev|otg 2:disabled + // .hmc_mode = 21, // 0:host(off) 1:dev(loopback) 2:host(loopback) +#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */ + .hmc_mode = 20, // 1:dev|otg(off) 1:host 2:disabled +#endif + + .pins[1] = 3, +}; + +static struct omap_board_config_kernel h2_config[] = { + { OMAP_TAG_USB, &h2_usb_config }, +}; + +static void __init h2_init(void) +{ + platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); + omap_board_config = h2_config; + omap_board_config_size = ARRAY_SIZE(h2_config); +} + +static void __init h2_map_io(void) +{ + omap_map_io(); + iotable_init(h2_io_desc, ARRAY_SIZE(h2_io_desc)); +} + +MACHINE_START(OMAP_H2, "TI-H2") + MAINTAINER("Imre Deak ") + BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) + BOOT_PARAMS(0x10000100) + MAPIO(h2_map_io) + INITIRQ(h2_init_irq) + INIT_MACHINE(h2_init) + INITTIME(omap_init_time) +MACHINE_END diff -Nru a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap/board-h3.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/board-h3.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,90 @@ +/* + * linux/arch/arm/mach-omap/board-h3.c + * + * This file contains OMAP1710 H3 specific code. + * + * Copyright (C) 2004 Texas Instruments, Inc. + * Copyright (C) 2002 MontaVista Software, Inc. + * Copyright (C) 2001 RidgeRun, Inc. + * Author: RidgeRun, Inc. + * Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +extern void __init omap_init_time(void); + +void h3_init_irq(void) +{ + omap_init_irq(); +} + +static struct resource smc91x_resources[] = { + [0] = { + .start = OMAP1710_ETHR_START, /* Physical */ + .end = OMAP1710_ETHR_START + OMAP1710_ETHR_SIZE, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *devices[] __initdata = { + &smc91x_device, +}; + +static void __init h3_init(void) +{ + (void) platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static struct map_desc h3_io_desc[] __initdata = { +{ OMAP1710_ETHR_BASE, OMAP1710_ETHR_START, OMAP1710_ETHR_SIZE, MT_DEVICE }, +{ OMAP_NOR_FLASH_BASE, OMAP_NOR_FLASH_START, OMAP_NOR_FLASH_SIZE, MT_DEVICE }, +}; + +static void __init h3_map_io(void) +{ + omap_map_io(); + iotable_init(h3_io_desc, ARRAY_SIZE(h3_io_desc)); +} + +MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board") + MAINTAINER("Texas Instruments, Inc.") + BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) + BOOT_PARAMS(0x10000100) + MAPIO(h3_map_io) + INITIRQ(h3_init_irq) + INIT_MACHINE(h3_init) + INITTIME(omap_init_time) +MACHINE_END diff -Nru a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c --- a/arch/arm/mach-omap/board-innovator.c 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mach-omap/board-innovator.c 2004-10-18 14:55:54 -07:00 @@ -29,9 +29,12 @@ #include #include #include +#include #include "common.h" +extern void __init omap_init_time(void); + #ifdef CONFIG_ARCH_OMAP1510 extern int omap_gpio_init(void); @@ -49,8 +52,8 @@ .flags = IORESOURCE_MEM, }, [1] = { - .start = INT_ETHER, - .end = INT_ETHER, + .start = OMAP1510_INT_ETHER, + .end = OMAP1510_INT_ETHER, .flags = IORESOURCE_IRQ, }, }; @@ -108,11 +111,43 @@ #ifdef CONFIG_ARCH_OMAP1510 if (cpu_is_omap1510()) { omap_gpio_init(); - fpga_init_irq(); + omap1510_fpga_init_irq(); } #endif } +#ifdef CONFIG_ARCH_OMAP1510 +static struct omap_usb_config innovator1510_usb_config __initdata = { + /* has usb host and device, but no Mini-AB port */ + .register_host = 1, + .register_dev = 1, + /* Assume bad Innovator wiring; Use internal host only with custom cable */ + .hmc_mode = 16, + .pins[0] = 2, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP1610 +static struct omap_usb_config h2_usb_config __initdata = { + /* usb1 has a Mini-AB port and external isp1301 transceiver */ + .otg = 2, + +#ifdef CONFIG_USB_GADGET_OMAP + .hmc_mode = 19, // 0:host(off) 1:dev|otg 2:disabled + // .hmc_mode = 21, // 0:host(off) 1:dev(loopback) 2:host(loopback) +#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */ + .hmc_mode = 20, // 1:dev|otg(off) 1:host 2:disabled +#endif + + .pins[1] = 3, +}; +#endif + +static struct omap_board_config_kernel innovator_config[] = { + { OMAP_TAG_USB, NULL }, +}; + static void __init innovator_init(void) { #ifdef CONFIG_ARCH_OMAP1510 @@ -121,10 +156,21 @@ } #endif #ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { + if (!cpu_is_omap1510()) { platform_add_devices(innovator1610_devices, ARRAY_SIZE(innovator1610_devices)); } #endif + +#ifdef CONFIG_ARCH_OMAP1510 + if (cpu_is_omap1510()) + innovator_config[0].data = &innovator1510_usb_config; +#endif +#ifdef CONFIG_ARCH_OMAP1610 + if (cpu_is_omap1610()) + innovator_config[0].data = &h2_usb_config; +#endif + omap_board_config = innovator_config; + omap_board_config_size = ARRAY_SIZE(innovator_config); } static void __init innovator_map_io(void) @@ -144,7 +190,7 @@ } #endif #ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { + if (!cpu_is_omap1510()) { iotable_init(innovator1610_io_desc, ARRAY_SIZE(innovator1610_io_desc)); } #endif @@ -156,6 +202,6 @@ BOOT_PARAMS(0x10000100) MAPIO(innovator_map_io) INITIRQ(innovator_init_irq) - INITTIME(omap_init_time) INIT_MACHINE(innovator_init) + INITTIME(omap_init_time) MACHINE_END diff -Nru a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c --- a/arch/arm/mach-omap/board-osk.c 2004-10-18 14:56:50 -07:00 +++ b/arch/arm/mach-omap/board-osk.c 2004-10-18 14:56:50 -07:00 @@ -41,6 +41,8 @@ #include "common.h" +extern void __init omap_init_time(void); + static struct map_desc osk5912_io_desc[] __initdata = { { OMAP_OSK_ETHR_BASE, OMAP_OSK_ETHR_START, OMAP_OSK_ETHR_SIZE,MT_DEVICE }, { OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE, @@ -94,6 +96,6 @@ BOOT_PARAMS(0x10000100) MAPIO(osk_map_io) INITIRQ(osk_init_irq) - INITTIME(omap_init_time) INIT_MACHINE(osk_init) + INITTIME(omap_init_time) MACHINE_END diff -Nru a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c --- a/arch/arm/mach-omap/board-perseus2.c 2004-10-18 14:56:49 -07:00 +++ b/arch/arm/mach-omap/board-perseus2.c 2004-10-18 14:56:49 -07:00 @@ -23,9 +23,12 @@ #include #include #include +#include #include "common.h" +extern void __init omap_init_time(void); + void omap_perseus2_init_irq(void) { omap_init_irq(); @@ -33,14 +36,14 @@ static struct resource smc91x_resources[] = { [0] = { - .start = OMAP730_FPGA_ETHR_START, /* Physical */ - .end = OMAP730_FPGA_ETHR_START + SZ_4K, + .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ + .end = H2P2_DBG_FPGA_ETHR_START + SZ_4K, .flags = IORESOURCE_MEM, }, [1] = { - .start = 0, + .start = INT_730_MPU_EXT_NIRQ, .end = 0, - .flags = INT_ETHER, + .flags = IORESOURCE_IRQ, }, }; @@ -62,7 +65,7 @@ /* Only FPGA needs to be mapped here. All others are done with ioremap */ static struct map_desc omap_perseus2_io_desc[] __initdata = { - {OMAP730_FPGA_BASE, OMAP730_FPGA_START, OMAP730_FPGA_SIZE, + {H2P2_DBG_FPGA_BASE, H2P2_DBG_FPGA_START, H2P2_DBG_FPGA_SIZE, MT_DEVICE}, }; @@ -111,6 +114,6 @@ BOOT_PARAMS(0x10000100) MAPIO(omap_perseus2_map_io) INITIRQ(omap_perseus2_init_irq) - INITTIME(omap_init_time) INIT_MACHINE(omap_perseus2_init) + INITTIME(omap_init_time) MACHINE_END diff -Nru a/arch/arm/mach-omap/bus.c b/arch/arm/mach-omap/bus.c --- a/arch/arm/mach-omap/bus.c 2004-10-18 14:57:18 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,246 +0,0 @@ -/* - * linux/arch/arm/mach-omap/bus.c - * - * Virtual bus for OMAP. Allows better power management, such as managing - * shared clocks, and mapping of bus addresses to Local Bus addresses. - * - * See drivers/usb/host/ohci-omap.c or drivers/video/omap/omapfb.c for - * examples on how to register drivers to this bus. - * - * Copyright (C) 2003 - 2004 Nokia Corporation - * Written by Tony Lindgren - * Portions of code based on sa1111.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -static int omap_bus_match(struct device *_dev, struct device_driver *_drv); -static int omap_bus_suspend(struct device *dev, u32 state); -static int omap_bus_resume(struct device *dev); - -/* - * OMAP bus definitions - * - * NOTE: Most devices should use TIPB. LBUS does automatic address mapping - * to Local Bus addresses, and should only be used for Local Bus devices. - * We may add new buses later on for power management reasons. Basically - * we want to be able to turn off any bus if it's not used by device - * drivers. - */ -static struct device omap_bus_devices[OMAP_NR_BUSES] = { - { - .bus_id = OMAP_BUS_NAME_TIPB - }, { - .bus_id = OMAP_BUS_NAME_LBUS - }, -}; - -static struct bus_type omap_bus_types[OMAP_NR_BUSES] = { - { - .name = OMAP_BUS_NAME_TIPB, - .match = omap_bus_match, - .suspend = omap_bus_suspend, - .resume = omap_bus_resume, - }, { - .name = OMAP_BUS_NAME_LBUS, /* Local bus on 1510 */ - .match = omap_bus_match, - .suspend = omap_bus_suspend, - .resume = omap_bus_resume, - }, -}; - -static int omap_bus_match(struct device *dev, struct device_driver *drv) -{ - struct omap_dev *omapdev = OMAP_DEV(dev); - struct omap_driver *omapdrv = OMAP_DRV(drv); - - return omapdev->devid == omapdrv->devid; -} - -static int omap_bus_suspend(struct device *dev, u32 state) -{ - struct omap_dev *omapdev = OMAP_DEV(dev); - struct omap_driver *omapdrv = OMAP_DRV(dev->driver); - int ret = 0; - - if (omapdrv && omapdrv->suspend) - ret = omapdrv->suspend(omapdev, state); - return ret; -} - -static int omap_bus_resume(struct device *dev) -{ - struct omap_dev *omapdev = OMAP_DEV(dev); - struct omap_driver *omapdrv = OMAP_DRV(dev->driver); - int ret = 0; - - if (omapdrv && omapdrv->resume) - ret = omapdrv->resume(omapdev); - return ret; -} - -static int omap_device_probe(struct device *dev) -{ - struct omap_dev *omapdev = OMAP_DEV(dev); - struct omap_driver *omapdrv = OMAP_DRV(dev->driver); - int ret = -ENODEV; - - if (omapdrv && omapdrv->probe) - ret = omapdrv->probe(omapdev); - - return ret; -} - -static int omap_device_remove(struct device *dev) -{ - struct omap_dev *omapdev = OMAP_DEV(dev); - struct omap_driver *omapdrv = OMAP_DRV(dev->driver); - int ret = 0; - - if (omapdrv && omapdrv->remove) - ret = omapdrv->remove(omapdev); - return ret; -} - -int omap_device_register(struct omap_dev *odev) -{ - if (!odev) - return -EINVAL; - - if (odev->busid < 0 || odev->busid >= OMAP_NR_BUSES) { - printk(KERN_ERR "%s: busid invalid: %s: bus: %i\n", - __FUNCTION__, odev->name, odev->busid); - return -EINVAL; - } - - odev->dev.parent = &omap_bus_devices[odev->busid]; - odev->dev.bus = &omap_bus_types[odev->busid]; - - /* This is needed for USB OHCI to work */ - if (odev->dma_mask) - odev->dev.dma_mask = odev->dma_mask; - - if (odev->coherent_dma_mask) - odev->dev.coherent_dma_mask = odev->coherent_dma_mask; - - snprintf(odev->dev.bus_id, BUS_ID_SIZE, "%s%u", - odev->name, odev->devid); - - printk("Registering OMAP device '%s'. Parent at %s\n", - odev->dev.bus_id, odev->dev.parent->bus_id); - - return device_register(&odev->dev); -} - -void omap_device_unregister(struct omap_dev *odev) -{ - if (odev) - device_unregister(&odev->dev); -} - -int omap_driver_register(struct omap_driver *driver) -{ - int ret; - - if (driver->busid < 0 || driver->busid >= OMAP_NR_BUSES) { - printk(KERN_ERR "%s: busid invalid: bus: %i device: %i\n", - __FUNCTION__, driver->busid, driver->devid); - return -EINVAL; - } - - driver->drv.probe = omap_device_probe; - driver->drv.remove = omap_device_remove; - driver->drv.bus = &omap_bus_types[driver->busid]; - - /* - * driver_register calls bus_add_driver - */ - ret = driver_register(&driver->drv); - - return ret; -} - -void omap_driver_unregister(struct omap_driver *driver) -{ - driver_unregister(&driver->drv); -} - -static int __init omap_bus_init(void) -{ - int i, ret; - - /* Initialize all OMAP virtual buses */ - for (i = 0; i < OMAP_NR_BUSES; i++) { - ret = device_register(&omap_bus_devices[i]); - if (ret != 0) { - printk(KERN_ERR "Unable to register bus device %s\n", - omap_bus_devices[i].bus_id); - continue; - } - ret = bus_register(&omap_bus_types[i]); - if (ret != 0) { - printk(KERN_ERR "Unable to register bus %s\n", - omap_bus_types[i].name); - device_unregister(&omap_bus_devices[i]); - } - } - printk("OMAP virtual buses initialized\n"); - - return ret; -} - -static void __exit omap_bus_exit(void) -{ - int i; - - /* Unregister all OMAP virtual buses */ - for (i = 0; i < OMAP_NR_BUSES; i++) { - bus_unregister(&omap_bus_types[i]); - device_unregister(&omap_bus_devices[i]); - } -} - -postcore_initcall(omap_bus_init); -module_exit(omap_bus_exit); - -MODULE_DESCRIPTION("Virtual bus for OMAP"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(omap_bus_types); -EXPORT_SYMBOL(omap_driver_register); -EXPORT_SYMBOL(omap_driver_unregister); -EXPORT_SYMBOL(omap_device_register); -EXPORT_SYMBOL(omap_device_unregister); - diff -Nru a/arch/arm/mach-omap/clocks.c b/arch/arm/mach-omap/clocks.c --- a/arch/arm/mach-omap/clocks.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mach-omap/clocks.c 2004-10-18 14:56:32 -07:00 @@ -36,6 +36,8 @@ #include #include +extern void start_mputimer1(unsigned long load_val); + /* Input clock in MHz */ static unsigned int source_clock = 12; @@ -239,7 +241,7 @@ int ck_debug = 0; #define CK_MAX_PLL_FREQ OMAP_CK_MAX_RATE -static __u8 ck_valid_table[CK_MAX_PLL_FREQ / 8 + 1]; +static __u32 ck_valid_table[CK_MAX_PLL_FREQ / 32 + 1]; static __u8 ck_lookup_table[CK_MAX_PLL_FREQ]; int @@ -615,11 +617,11 @@ int __init init_ck(void) { - const struct omap_clock_info *info; + const struct omap_clock_config *info; int crystal_type = 0; /* Default 12 MHz */ __ck_make_lookup_table(); - info = omap_get_per_info(OMAP_TAG_CLOCK, struct omap_clock_info); + info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); if (info != NULL) { if (!cpu_is_omap1510()) crystal_type = info->system_clock_type; @@ -645,7 +647,8 @@ #elif defined(CONFIG_OMAP_ARM_182MHZ) && defined(CONFIG_ARCH_OMAP730) omap_writew(0x250E, ARM_CKCTL); omap_writew(0x2710, DPLL_CTL); -#elif defined(CONFIG_OMAP_ARM_192MHZ) && (defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)) +#elif defined(CONFIG_OMAP_ARM_192MHZ) && (defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \ + || defined(CONFIG_ARCH_OMAP1710)) omap_writew(0x150f, ARM_CKCTL); if (crystal_type == 2) { source_clock = 13; /* MHz */ diff -Nru a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c --- a/arch/arm/mach-omap/common.c 2004-10-18 14:57:04 -07:00 +++ b/arch/arm/mach-omap/common.c 2004-10-18 14:57:04 -07:00 @@ -104,7 +104,7 @@ }; #endif -#ifdef CONFIG_ARCH_OMAP1610 +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) static struct map_desc omap1610_io_desc[] __initdata = { { OMAP1610_DSP_BASE, OMAP1610_DSP_START, OMAP1610_DSP_SIZE, MT_DEVICE }, { OMAP1610_DSPREG_BASE, OMAP1610_DSPREG_START, OMAP1610_DSPREG_SIZE, MT_DEVICE }, @@ -147,8 +147,8 @@ iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); } #endif -#ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap1710()) { iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc)); } #endif @@ -181,13 +181,18 @@ extern int omap_bootloader_tag_len; extern u8 omap_bootloader_tag[]; -const void *__omap_get_per_info(u16 tag, size_t len) +struct omap_board_config_kernel *omap_board_config; +int omap_board_config_size = 0; + +const void *__omap_get_config(u16 tag, size_t len) { - struct omap_board_info_entry *info = NULL; + struct omap_board_config_entry *info = NULL; + struct omap_board_config_kernel *kinfo = NULL; + int i; #ifdef CONFIG_OMAP_BOOT_TAG if (omap_bootloader_tag_len > 4) - info = (struct omap_board_info_entry *) omap_bootloader_tag; + info = (struct omap_board_config_entry *) omap_bootloader_tag; while (info != NULL) { u8 *next; @@ -198,26 +203,38 @@ if (next >= omap_bootloader_tag + omap_bootloader_tag_len) info = NULL; else - info = (struct omap_board_info_entry *) next; + info = (struct omap_board_config_entry *) next; } -#endif - if (info == NULL) - return NULL; - if (info->len != len) { - printk(KERN_ERR "OMAP per_info: Length mismatch with tag %x (want %d, got %d)\n", - tag, len, info->len); - return NULL; + if (info != NULL) { + /* Check the length as a lame attempt to check for + * binary inconsistancy. */ + if (info->len != len) { + printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n", + tag, len, info->len); + return NULL; + } + return info->data; + } +#endif + /* Try to find the config from the board-specific structures + * in the kernel. */ + for (i = 0; i < omap_board_config_size; i++) { + if (omap_board_config[i].tag == tag) { + kinfo = &omap_board_config[i]; + break; + } } - - return info->data; + if (kinfo == NULL) + return NULL; + return kinfo->data; } -EXPORT_SYMBOL(__omap_get_per_info); +EXPORT_SYMBOL(__omap_get_config); static int __init omap_add_serial_console(void) { - const struct omap_uart_info *info; + const struct omap_uart_config *info; - info = omap_get_per_info(OMAP_TAG_UART, struct omap_uart_info); + info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); if (info != NULL && info->console_uart) { static char speed[11], *opt = NULL; diff -Nru a/arch/arm/mach-omap/common.h b/arch/arm/mach-omap/common.h --- a/arch/arm/mach-omap/common.h 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mach-omap/common.h 2004-10-18 14:56:32 -07:00 @@ -28,7 +28,6 @@ #define __ARCH_ARM_MACH_OMAP_COMMON_H extern void omap_map_io(void); -extern void omap_init_time(void); #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */ diff -Nru a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c --- a/arch/arm/mach-omap/dma.c 2004-10-18 14:57:04 -07:00 +++ b/arch/arm/mach-omap/dma.c 2004-10-18 14:57:04 -07:00 @@ -118,7 +118,7 @@ u16 w; #ifdef CONFIG_DEBUG_KERNEL - if (omap_dma_in_1510_mode) { + if (omap_dma_in_1510_mode()) { printk(KERN_ERR "OMAP DMA constant fill not available in 1510 mode."); BUG(); return; @@ -141,7 +141,7 @@ u16 w; #ifdef CONFIG_DEBUG_KERNEL - if (omap_dma_in_1510_mode) { + if (omap_dma_in_1510_mode()) { printk(KERN_ERR "OMAP DMA transparent copy not available in 1510 mode."); BUG(); } @@ -266,46 +266,78 @@ omap_writew(w, OMAP_DMA_CSDP(lch)); } +static inline void init_intr(int lch) +{ + u16 w; + + /* Read CSR to make sure it's cleared. */ + w = omap_readw(OMAP_DMA_CSR(lch)); + /* Enable some nice interrupts. */ + omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch)); + dma_chan[lch].flags |= OMAP_DMA_ACTIVE; +} + +static inline void enable_lnk(int lch) +{ + u16 w; + + /* Clear the STOP_LNK bits */ + w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); + w &= ~(1 << 14); + omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); + + /* And set the ENABLE_LNK bits */ + if (dma_chan[lch].next_lch != -1) + omap_writew(dma_chan[lch].next_lch | (1 << 15), + OMAP_DMA_CLNK_CTRL(lch)); +} + +static inline void disable_lnk(int lch) +{ + u16 w; + + /* Disable interrupts */ + omap_writew(0, OMAP_DMA_CICR(lch)); + + /* Set the STOP_LNK bit */ + w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); + w |= (1 << 14); + w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); + + dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; +} + void omap_start_dma(int lch) { u16 w; - if (!omap_dma_in_1510_mode()) { - int next_lch; + if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { + int next_lch, cur_lch; + char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; + + dma_chan_link_map[lch] = 1; + /* Set the link register of the first channel */ + enable_lnk(lch); + + memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map)); + cur_lch = dma_chan[lch].next_lch; + do { + next_lch = dma_chan[cur_lch].next_lch; - next_lch = dma_chan[lch].next_lch; + /* The loop case: we've been here already */ + if (dma_chan_link_map[cur_lch]) + break; + /* Mark the current channel */ + dma_chan_link_map[cur_lch] = 1; - /* Enable the queue, if needed so. */ - if (next_lch != -1) { - /* Clear the STOP_LNK bits */ - w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); - w &= ~(1 << 14); - omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); - w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch)); - w &= ~(1 << 14); - omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch)); - - /* And set the ENABLE_LNK bits */ - omap_writew(next_lch | (1 << 15), - OMAP_DMA_CLNK_CTRL(lch)); - /* The loop case */ - if (dma_chan[next_lch].next_lch == lch) - omap_writew(lch | (1 << 15), - OMAP_DMA_CLNK_CTRL(next_lch)); - - /* Read CSR to make sure it's cleared. */ - w = omap_readw(OMAP_DMA_CSR(next_lch)); - /* Enable some nice interrupts. */ - omap_writew(dma_chan[next_lch].enabled_irqs, - OMAP_DMA_CICR(next_lch)); - dma_chan[next_lch].flags |= OMAP_DMA_ACTIVE; - } + enable_lnk(cur_lch); + init_intr(cur_lch); + + cur_lch = next_lch; + } while (next_lch != -1); } - /* Read CSR to make sure it's cleared. */ - w = omap_readw(OMAP_DMA_CSR(lch)); - /* Enable some nice interrupts. */ - omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch)); + init_intr(lch); w = omap_readw(OMAP_DMA_CCR(lch)); w |= OMAP_DMA_CCR_EN; @@ -316,37 +348,34 @@ void omap_stop_dma(int lch) { u16 w; - int next_lch; - /* Disable all interrupts on the channel */ - omap_writew(0, OMAP_DMA_CICR(lch)); + if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { + int next_lch, cur_lch = lch; + char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; + + memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map)); + do { + /* The loop case: we've been here already */ + if (dma_chan_link_map[cur_lch]) + break; + /* Mark the current channel */ + dma_chan_link_map[cur_lch] = 1; + + disable_lnk(cur_lch); + + next_lch = dma_chan[cur_lch].next_lch; + cur_lch = next_lch; + } while (next_lch != -1); - if (omap_dma_in_1510_mode()) { - w = omap_readw(OMAP_DMA_CCR(lch)); - w &= ~OMAP_DMA_CCR_EN; - omap_writew(w, OMAP_DMA_CCR(lch)); - dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; return; } + /* Disable all interrupts on the channel */ + omap_writew(0, OMAP_DMA_CICR(lch)); - next_lch = dma_chan[lch].next_lch; - - /* - * According to thw HW spec, enabling the STOP_LNK bit - * resets the CCR_EN bit at the same time. - */ - w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); - w |= (1 << 14); - w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); + w = omap_readw(OMAP_DMA_CCR(lch)); + w &= ~OMAP_DMA_CCR_EN; + omap_writew(w, OMAP_DMA_CCR(lch)); dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; - - if (next_lch != -1) { - omap_writew(0, OMAP_DMA_CICR(next_lch)); - w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch)); - w |= (1 << 14); - w = omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch)); - dma_chan[next_lch].flags &= ~OMAP_DMA_ACTIVE; - } } void omap_enable_dma_irq(int lch, u16 bits) @@ -445,7 +474,7 @@ chan->data = data; chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; - if (cpu_is_omap1610() || cpu_is_omap5912()) { + if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) { /* If the sync device is set, configure it dynamically. */ if (dev_id != 0) { set_gdma_dev(free_ch + 1, dev_id); @@ -533,7 +562,6 @@ } dma_chan[lch_head].next_lch = -1; - dma_chan[lch_queue].next_lch = -1; } @@ -713,7 +741,7 @@ printk(KERN_INFO "DMA support for OMAP1510 initialized\n"); dma_chan_count = 9; enable_1510_mode = 1; - } else if (cpu_is_omap1610() || cpu_is_omap5912()) { + } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) { printk(KERN_INFO "OMAP DMA hardware version %d\n", omap_readw(OMAP_DMA_HW_ID)); printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n", @@ -771,6 +799,8 @@ EXPORT_SYMBOL(omap_free_dma); EXPORT_SYMBOL(omap_start_dma); EXPORT_SYMBOL(omap_stop_dma); +EXPORT_SYMBOL(omap_enable_dma_irq); +EXPORT_SYMBOL(omap_disable_dma_irq); EXPORT_SYMBOL(omap_set_dma_transfer_params); EXPORT_SYMBOL(omap_set_dma_constant_fill); diff -Nru a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap/fpga.c --- a/arch/arm/mach-omap/fpga.c 2004-10-18 14:56:20 -07:00 +++ b/arch/arm/mach-omap/fpga.c 2004-10-18 14:56:20 -07:00 @@ -31,19 +31,9 @@ #include #include -unsigned char fpga_read(int reg) -{ - return __raw_readb(reg); -} - -void fpga_write(unsigned char val, int reg) -{ - __raw_writeb(val, reg); -} - static void fpga_mask_irq(unsigned int irq) { - irq -= IH_FPGA_BASE; + irq -= OMAP1510_IH_FPGA_BASE; if (irq < 8) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) @@ -76,7 +66,7 @@ static void fpga_unmask_irq(unsigned int irq) { - irq -= IH_FPGA_BASE; + irq -= OMAP1510_IH_FPGA_BASE; if (irq < 8) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)), @@ -114,8 +104,8 @@ break; } - for (fpga_irq = IH_FPGA_BASE; - (fpga_irq < (IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; + for (fpga_irq = OMAP1510_IH_FPGA_BASE; + (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; fpga_irq++, stat >>= 1) { if (stat & 1) { d = irq_desc + fpga_irq; @@ -162,7 +152,7 @@ * interrupts at the interrupt controller via disable_irq/enable_irq * could pose a problem. */ -void fpga_init_irq(void) +void omap1510_fpga_init_irq(void) { int i; @@ -170,9 +160,9 @@ __raw_writeb(0, OMAP1510_FPGA_IMR_HI); __raw_writeb(0, INNOVATOR_FPGA_IMR2); - for (i = IH_FPGA_BASE; i < (IH_FPGA_BASE + NR_FPGA_IRQS); i++) { + for (i = OMAP1510_IH_FPGA_BASE; i < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS); i++) { - if (i == INT_FPGA_TS) { + if (i == OMAP1510_INT_FPGA_TS) { /* * The touchscreen interrupt is level-sensitive, so * we'll use the regular mask_ack routine for it. @@ -201,9 +191,7 @@ omap_request_gpio(13); omap_set_gpio_direction(13, 1); omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE); - set_irq_chained_handler(INT_FPGA, innovator_fpga_IRQ_demux); + set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux); } -EXPORT_SYMBOL(fpga_init_irq); -EXPORT_SYMBOL(fpga_read); -EXPORT_SYMBOL(fpga_write); +EXPORT_SYMBOL(omap1510_fpga_init_irq); diff -Nru a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c --- a/arch/arm/mach-omap/gpio.c 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mach-omap/gpio.c 2004-10-18 14:56:29 -07:00 @@ -94,7 +94,7 @@ #define METHOD_GPIO_1610 2 #define METHOD_GPIO_730 3 -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) static struct gpio_bank gpio_bank_1610[5] = { { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO}, { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 }, @@ -113,7 +113,7 @@ #ifdef CONFIG_ARCH_OMAP730 static struct gpio_bank gpio_bank_730[7] = { - { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, + { OMAP_MPUIO_BASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, { OMAP730_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 }, { OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 }, { OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 }, @@ -135,8 +135,8 @@ return &gpio_bank[1]; } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if (cpu_is_omap1610() || cpu_is_omap5912()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) + if (cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1 + (gpio >> 4)]; @@ -172,8 +172,8 @@ if (cpu_is_omap1510() && gpio < 16) return 0; #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if ((cpu_is_omap1610() || cpu_is_omap5912()) && gpio < 64) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) + if ((cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) && gpio < 64) return 0; #endif #ifdef CONFIG_ARCH_OMAP730 @@ -554,7 +554,7 @@ if (bank->method == METHOD_GPIO_1510) isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1; #endif @@ -588,7 +588,7 @@ if (bank->method == METHOD_GPIO_1510) __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1510_GPIO_INT_STATUS); #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1610_GPIO_IRQSTATUS1); #endif @@ -629,7 +629,7 @@ unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_gpio_bank(gpio); - _set_gpio_irqenable(bank, gpio, 0); + _set_gpio_irqenable(bank, get_gpio_index(gpio), 0); } static void mpuio_unmask_irq(unsigned int irq) @@ -637,7 +637,7 @@ unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_gpio_bank(gpio); - _set_gpio_irqenable(bank, gpio, 1); + _set_gpio_irqenable(bank, get_gpio_index(gpio), 1); } static struct irqchip gpio_irq_chip = { @@ -668,8 +668,8 @@ gpio_bank = gpio_bank_1510; } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if (cpu_is_omap1610() || cpu_is_omap5912()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) + if (cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) { int rev; gpio_bank_count = 5; @@ -702,7 +702,7 @@ __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) { __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1); __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); @@ -731,7 +731,7 @@ /* Enable system clock for GPIO module. * The CAM_CLK_CTRL *is* really the right place. */ - if (cpu_is_omap1610()) + if (cpu_is_omap1610() || cpu_is_omap1710()) omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL); return 0; diff -Nru a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap/irq.c --- a/arch/arm/mach-omap/irq.c 2004-10-18 14:56:13 -07:00 +++ b/arch/arm/mach-omap/irq.c 2004-10-18 14:56:13 -07:00 @@ -140,7 +140,9 @@ }; #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \ + || defined(CONFIG_ARCH_OMAP1710) + static struct omap_irq_bank omap1610_irq_banks[] = { { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfffff7ff }, @@ -171,8 +173,9 @@ irq_bank_count = ARRAY_SIZE(omap1510_irq_banks); } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if (cpu_is_omap1610() || cpu_is_omap5912()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \ + || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) { irq_banks = omap1610_irq_banks; irq_bank_count = ARRAY_SIZE(omap1610_irq_banks); } @@ -190,6 +193,11 @@ irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET); irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET); + /* Enable interrupts in global mask */ + if (cpu_is_omap730()) { + irq_bank_writel(0x0, 0, IRQ_GMR_REG_OFFSET); + } + /* Install the interrupt handlers for each bank */ for (i = 0; i < irq_bank_count; i++) { for (j = i * 32; j < (i + 1) * 32; j++) { @@ -205,5 +213,9 @@ } /* Unmask level 2 handler */ - omap_unmask_irq(INT_IH2_IRQ); + if (cpu_is_omap730()) { + omap_unmask_irq(INT_730_IH2_IRQ); + } else { + omap_unmask_irq(INT_IH2_IRQ); + } } diff -Nru a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap/leds-h2p2-debug.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/leds-h2p2-debug.c 2004-10-18 14:56:49 -07:00 @@ -0,0 +1,104 @@ +/* + * linux/arch/arm/mach-omap/leds-h2p2-debug.c + * + * Copyright 2003 by Texas Instruments Incorporated + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "leds.h" + +void h2p2_dbg_leds_event(led_event_t evt) +{ + unsigned long flags; + static unsigned long hw_led_state = 0; + + local_irq_save(flags); + + switch (evt) { + case led_start: + hw_led_state |= H2P2_DBG_FPGA_LED_STARTSTOP; + break; + + case led_stop: + hw_led_state &= ~H2P2_DBG_FPGA_LED_STARTSTOP; + break; + + case led_claim: + hw_led_state |= H2P2_DBG_FPGA_LED_CLAIMRELEASE; + break; + + case led_release: + hw_led_state &= ~H2P2_DBG_FPGA_LED_CLAIMRELEASE; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + /* + * Toggle Timer LED + */ + if (hw_led_state & H2P2_DBG_FPGA_LED_TIMER) + hw_led_state &= ~H2P2_DBG_FPGA_LED_TIMER; + else + hw_led_state |= H2P2_DBG_FPGA_LED_TIMER; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + hw_led_state |= H2P2_DBG_FPGA_LED_IDLE; + break; + + case led_idle_end: + hw_led_state &= ~H2P2_DBG_FPGA_LED_IDLE; + break; +#endif + + case led_halted: + if (hw_led_state & H2P2_DBG_FPGA_LED_HALTED) + hw_led_state &= ~H2P2_DBG_FPGA_LED_HALTED; + else + hw_led_state |= H2P2_DBG_FPGA_LED_HALTED; + break; + + case led_green_on: + break; + + case led_green_off: + break; + + case led_amber_on: + break; + + case led_amber_off: + break; + + case led_red_on: + break; + + case led_red_off: + break; + + default: + break; + } + + + /* + * Actually burn the LEDs + */ + __raw_writew(~hw_led_state & 0xffff, H2P2_DBG_FPGA_LEDS); + + local_irq_restore(flags); +} diff -Nru a/arch/arm/mach-omap/leds-perseus2.c b/arch/arm/mach-omap/leds-perseus2.c --- a/arch/arm/mach-omap/leds-perseus2.c 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,102 +0,0 @@ -/* - * linux/arch/arm/mach-omap/leds-perseus2.c - * - * Copyright 2003 by Texas Instruments Incorporated - * - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "leds.h" - -void perseus2_leds_event(led_event_t evt) -{ - unsigned long flags; - static unsigned long hw_led_state = 0; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state |= OMAP730_FPGA_LED_STARTSTOP; - break; - - case led_stop: - hw_led_state &= ~OMAP730_FPGA_LED_STARTSTOP; - break; - - case led_claim: - hw_led_state |= OMAP730_FPGA_LED_CLAIMRELEASE; - break; - - case led_release: - hw_led_state &= ~OMAP730_FPGA_LED_CLAIMRELEASE; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - /* - * Toggle Timer LED - */ - if (hw_led_state & OMAP730_FPGA_LED_TIMER) - hw_led_state &= ~OMAP730_FPGA_LED_TIMER; - else - hw_led_state |= OMAP730_FPGA_LED_TIMER; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - hw_led_state |= OMAP730_FPGA_LED_IDLE; - break; - - case led_idle_end: - hw_led_state &= ~OMAP730_FPGA_LED_IDLE; - break; -#endif - - case led_halted: - if (hw_led_state & OMAP730_FPGA_LED_HALTED) - hw_led_state &= ~OMAP730_FPGA_LED_HALTED; - else - hw_led_state |= OMAP730_FPGA_LED_HALTED; - break; - - case led_green_on: - break; - - case led_green_off: - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - break; - - case led_red_off: - break; - - default: - break; - } - - - /* - * Actually burn the LEDs - */ - __raw_writew(~hw_led_state & 0xffff, OMAP730_FPGA_LEDS); - - local_irq_restore(flags); -} diff -Nru a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap/leds.c --- a/arch/arm/mach-omap/leds.c 2004-10-18 14:56:50 -07:00 +++ b/arch/arm/mach-omap/leds.c 2004-10-18 14:56:50 -07:00 @@ -3,6 +3,7 @@ * * OMAP LEDs dispatcher */ +#include #include #include @@ -11,17 +12,17 @@ #include "leds.h" static int __init -omap1510_leds_init(void) +omap_leds_init(void) { if (machine_is_omap_innovator()) leds_event = innovator_leds_event; - else if (machine_is_omap_perseus2()) { - leds_event = perseus2_leds_event; + else if (machine_is_omap_h2() || machine_is_omap_perseus2()) { + leds_event = h2p2_dbg_leds_event; } leds_event(led_start); return 0; } -__initcall(omap1510_leds_init); +__initcall(omap_leds_init); diff -Nru a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap/leds.h --- a/arch/arm/mach-omap/leds.h 2004-10-18 14:57:05 -07:00 +++ b/arch/arm/mach-omap/leds.h 2004-10-18 14:57:05 -07:00 @@ -1,2 +1,2 @@ extern void innovator_leds_event(led_event_t evt); -extern void perseus2_leds_event(led_event_t evt); +extern void h2p2_dbg_leds_event(led_event_t evt); diff -Nru a/arch/arm/mach-omap/mcbsp.c b/arch/arm/mach-omap/mcbsp.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/mcbsp.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,669 @@ +/* + * linux/arch/arm/omap/mcbsp.c + * + * Copyright (C) 2004 Nokia Corporation + * Author: Samuel Ortiz + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Multichannel mode not supported. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_MCBSP_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) do { } while (0) +#endif + +struct omap_mcbsp { + u32 io_base; + u8 id; + u8 free; + omap_mcbsp_word_length rx_word_length; + omap_mcbsp_word_length tx_word_length; + + /* IRQ based TX/RX */ + int rx_irq; + int tx_irq; + + /* DMA stuff */ + u8 dma_rx_sync; + short dma_rx_lch; + u8 dma_tx_sync; + short dma_tx_lch; + + /* Completion queues */ + struct completion tx_irq_completion; + struct completion rx_irq_completion; + struct completion tx_dma_completion; + struct completion rx_dma_completion; + + spinlock_t lock; +}; + +static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT]; + + +static void omap_mcbsp_dump_reg(u8 id) +{ + DBG("**** MCBSP%d regs ****\n", mcbsp[id].id); + DBG("DRR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2)); + DBG("DRR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1)); + DBG("DXR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2)); + DBG("DXR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1)); + DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2)); + DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1)); + DBG("RCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2)); + DBG("RCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1)); + DBG("XCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2)); + DBG("XCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1)); + DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2)); + DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1)); + DBG("PCR0: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0)); + DBG("***********************\n"); +} + + +static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id); + + DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2)); + + complete(&mcbsp_tx->tx_irq_completion); + return IRQ_HANDLED; +} + +static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id); + + DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2)); + + complete(&mcbsp_rx->rx_irq_completion); + return IRQ_HANDLED; +} + + +static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data); + + DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2)); + + /* We can free the channels */ + omap_free_dma(mcbsp_dma_tx->dma_tx_lch); + mcbsp_dma_tx->dma_tx_lch = -1; + + complete(&mcbsp_dma_tx->tx_dma_completion); +} + +static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data); + + DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2)); + + /* We can free the channels */ + omap_free_dma(mcbsp_dma_rx->dma_rx_lch); + mcbsp_dma_rx->dma_rx_lch = -1; + + complete(&mcbsp_dma_rx->rx_dma_completion); +} + + +/* + * omap_mcbsp_config simply write a config to the + * appropriate McBSP. + * You either call this function or set the McBSP registers + * by yourself before calling omap_mcbsp_start(). + */ + +void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config) +{ + u32 io_base = mcbsp[id].io_base; + + DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id+1, io_base); + + /* We write the given config */ + OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2); + OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1); + OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2); + OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1); + OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2); + OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1); + OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2); + OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1); + OMAP_MCBSP_WRITE(io_base, SRGR2, config->mcr2); + OMAP_MCBSP_WRITE(io_base, SRGR1, config->mcr1); + OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0); +} + + + +static int omap_mcbsp_check(unsigned int id) +{ + if (cpu_is_omap730()) { + if (id > OMAP_MAX_MCBSP_COUNT - 1) { + printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); + return -1; + } + return 0; + } + + if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { + if (id > OMAP_MAX_MCBSP_COUNT) { + printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); + return -1; + } + return 0; + } + + return -1; +} + +#define DSP_RSTCT2 0xe1008014 + +static void omap_mcbsp_dsp_request(void) +{ + if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { + omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)), + ARM_RSTCT1); + omap_writew((omap_readw(ARM_CKCTL) | 1 << EN_DSPCK), + ARM_CKCTL); + omap_writew((omap_readw(ARM_IDLECT2) | (1 << EN_APICK)), + ARM_IDLECT2); + + /* enable 12MHz clock to mcbsp 1 & 3 */ + __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK), + DSP_IDLECT2); + __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1, + DSP_RSTCT2); + } +} + +static void omap_mcbsp_dsp_free(void) +{ + /* Useless for now */ +} + + +int omap_mcbsp_request(unsigned int id) +{ + int err; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + /* + * On 1510, 1610 and 1710, McBSP1 and McBSP3 + * are DSP public peripherals. + */ + if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) + omap_mcbsp_dsp_request(); + + spin_lock(&mcbsp[id].lock); + if (!mcbsp[id].free) { + printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1); + spin_unlock(&mcbsp[id].lock); + return -1; + } + + mcbsp[id].free = 0; + spin_unlock(&mcbsp[id].lock); + + /* We need to get IRQs here */ + err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", + mcbsp[id].tx_irq, mcbsp[id].id); + return err; + } + + init_completion(&(mcbsp[id].tx_irq_completion)); + + + err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", + mcbsp[id].rx_irq, mcbsp[id].id); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + return err; + } + + init_completion(&(mcbsp[id].rx_irq_completion)); + return 0; + +} + +void omap_mcbsp_free(unsigned int id) +{ + if (omap_mcbsp_check(id) < 0) + return; + + if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) + omap_mcbsp_dsp_free(); + + spin_lock(&mcbsp[id].lock); + if (mcbsp[id].free) { + printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1); + spin_unlock(&mcbsp[id].lock); + return; + } + + mcbsp[id].free = 1; + spin_unlock(&mcbsp[id].lock); + + /* Free IRQs */ + free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); +} + +/* + * Here we start the McBSP, by enabling the sample + * generator, both transmitter and receivers, + * and the frame sync. + */ +void omap_mcbsp_start(unsigned int id) +{ + u32 io_base; + u16 w; + + if (omap_mcbsp_check(id) < 0) + return; + + io_base = mcbsp[id].io_base; + + mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7); + mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7); + + /* Start the sample generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); + + /* Enable transmitter and receiver */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); + + w = OMAP_MCBSP_READ(io_base, SPCR1); + OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); + + udelay(100); + + /* Start frame sync */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); + + /* Dump McBSP Regs */ + omap_mcbsp_dump_reg(id); + +} + +void omap_mcbsp_stop(unsigned int id) +{ + u32 io_base; + u16 w; + + if (omap_mcbsp_check(id) < 0) + return; + + io_base = mcbsp[id].io_base; + + /* Reset transmitter */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1)); + + /* Reset receiver */ + w = OMAP_MCBSP_READ(io_base, SPCR1); + OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1)); + + /* Reset the sample rate generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); +} + + +/* + * IRQ based word transmission. + */ +void omap_mcbsp_xmit_word(unsigned int id, u32 word) +{ + u32 io_base; + omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length; + + if (omap_mcbsp_check(id) < 0) + return; + + io_base = mcbsp[id].io_base; + + wait_for_completion(&(mcbsp[id].tx_irq_completion)); + + if (word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); +} + +u32 omap_mcbsp_recv_word(unsigned int id) +{ + u32 io_base; + u16 word_lsb, word_msb = 0; + omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + io_base = mcbsp[id].io_base; + + wait_for_completion(&(mcbsp[id].rx_irq_completion)); + + if (word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + return (word_lsb | (word_msb << 16)); +} + + +/* + * Simple DMA based buffer rx/tx routines. + * Nothing fancy, just a single buffer tx/rx through DMA. + * The DMA resources are released once the transfer is done. + * For anything fancier, you should use your own customized DMA + * routines and callbacks. + */ +int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) +{ + int dma_tx_ch; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback, + &mcbsp[id], + &dma_tx_ch)) { + printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1); + return -EAGAIN; + } + mcbsp[id].dma_tx_lch = dma_tx_ch; + + DBG("TX DMA on channel %d\n", dma_tx_ch); + + init_completion(&(mcbsp[id].tx_dma_completion)); + + omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, + OMAP_DMA_DATA_TYPE_S16, + length >> 1, 1, + OMAP_DMA_SYNC_ELEMENT); + + omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1); + + omap_set_dma_src_params(mcbsp[id].dma_tx_lch, + OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + buffer); + + omap_start_dma(mcbsp[id].dma_tx_lch); + wait_for_completion(&(mcbsp[id].tx_dma_completion)); + return 0; +} + + +int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) +{ + int dma_rx_ch; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback, + &mcbsp[id], + &dma_rx_ch)) { + printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1); + return -EAGAIN; + } + mcbsp[id].dma_rx_lch = dma_rx_ch; + + DBG("RX DMA on channel %d\n", dma_rx_ch); + + init_completion(&(mcbsp[id].rx_dma_completion)); + + omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, + OMAP_DMA_DATA_TYPE_S16, + length >> 1, 1, + OMAP_DMA_SYNC_ELEMENT); + + omap_set_dma_src_params(mcbsp[id].dma_rx_lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1); + + omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, + OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + buffer); + + omap_start_dma(mcbsp[id].dma_rx_lch); + wait_for_completion(&(mcbsp[id].rx_dma_completion)); + return 0; +} + + +/* + * SPI wrapper. + * Since SPI setup is much simpler than the generic McBSP one, + * this wrapper just need an omap_mcbsp_spi_cfg structure as an input. + * Once this is done, you can call omap_mcbsp_start(). + */ +void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg) +{ + struct omap_mcbsp_reg_cfg mcbsp_cfg; + + if (omap_mcbsp_check(id) < 0) + return; + + memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg)); + + /* SPI has only one frame */ + mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0)); + mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0)); + + /* Clock stop mode */ + if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY) + mcbsp_cfg.spcr1 |= (1 << 12); + else + mcbsp_cfg.spcr1 |= (3 << 11); + + /* Set clock parities */ + if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING) + mcbsp_cfg.pcr0 |= CLKRP; + else + mcbsp_cfg.pcr0 &= ~CLKRP; + + if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING) + mcbsp_cfg.pcr0 &= ~CLKXP; + else + mcbsp_cfg.pcr0 |= CLKXP; + + /* Set SCLKME to 0 and CLKSM to 1 */ + mcbsp_cfg.pcr0 &= ~SCLKME; + mcbsp_cfg.srgr2 |= CLKSM; + + /* Set FSXP */ + if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH) + mcbsp_cfg.pcr0 &= ~FSXP; + else + mcbsp_cfg.pcr0 |= FSXP; + + if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) { + mcbsp_cfg.pcr0 |= CLKXM; + mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1); + mcbsp_cfg.pcr0 |= FSXM; + mcbsp_cfg.srgr2 &= ~FSGM; + mcbsp_cfg.xcr2 |= XDATDLY(1); + mcbsp_cfg.rcr2 |= RDATDLY(1); + } + else { + mcbsp_cfg.pcr0 &= ~CLKXM; + mcbsp_cfg.srgr1 |= CLKGDV(1); + mcbsp_cfg.pcr0 &= ~FSXM; + mcbsp_cfg.xcr2 &= ~XDATDLY(3); + mcbsp_cfg.rcr2 &= ~RDATDLY(3); + } + + mcbsp_cfg.xcr2 &= ~XPHASE; + mcbsp_cfg.rcr2 &= ~RPHASE; + + omap_mcbsp_config(id, &mcbsp_cfg); +} + + +/* + * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. + * 730 has only 2 McBSP, and both of them are MPU peripherals. + */ +struct omap_mcbsp_info { + u32 virt_base; + u8 dma_rx_sync, dma_tx_sync; + u16 rx_irq, tx_irq; +}; + +#ifdef CONFIG_ARCH_OMAP730 +static const struct omap_mcbsp_info mcbsp_730[] = { + [0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP_DMA_MCBSP1_TX, + .rx_irq = INT_730_McBSP1RX, + .tx_irq = INT_730_McBSP1TX }, + [1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP3_RX, + .dma_tx_sync = OMAP_DMA_MCBSP3_TX, + .rx_irq = INT_730_McBSP2RX, + .tx_irq = INT_730_McBSP2TX }, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP1510 +static const struct omap_mcbsp_info mcbsp_1510[] = { + [0] = { .virt_base = OMAP1510_MCBSP1_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP_DMA_MCBSP1_TX, + .rx_irq = INT_McBSP1RX, + .tx_irq = INT_McBSP1TX }, + [1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP_DMA_MCBSP2_TX, + .rx_irq = INT_1510_SPI_RX, + .tx_irq = INT_1510_SPI_TX }, + [2] = { .virt_base = OMAP1510_MCBSP3_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP3_RX, + .dma_tx_sync = OMAP_DMA_MCBSP3_TX, + .rx_irq = INT_McBSP3RX, + .tx_irq = INT_McBSP3TX }, +}; +#endif + +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) +static const struct omap_mcbsp_info mcbsp_1610[] = { + [0] = { .virt_base = OMAP1610_MCBSP1_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP_DMA_MCBSP1_TX, + .rx_irq = INT_McBSP1RX, + .tx_irq = INT_McBSP1TX }, + [1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP_DMA_MCBSP2_TX, + .rx_irq = INT_1610_McBSP2_RX, + .tx_irq = INT_1610_McBSP2_TX }, + [2] = { .virt_base = OMAP1610_MCBSP3_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP3_RX, + .dma_tx_sync = OMAP_DMA_MCBSP3_TX, + .rx_irq = INT_McBSP3RX, + .tx_irq = INT_McBSP3TX }, +}; +#endif + +static int __init omap_mcbsp_init(void) +{ + int mcbsp_count = 0, i; + static const struct omap_mcbsp_info *mcbsp_info; + + printk("Initializing OMAP McBSP system\n"); +#ifdef CONFIG_ARCH_OMAP730 + if (cpu_is_omap730()) { + mcbsp_info = mcbsp_730; + mcbsp_count = ARRAY_SIZE(mcbsp_730); + } +#endif +#ifdef CONFIG_ARCH_OMAP1510 + if (cpu_is_omap1510()) { + mcbsp_info = mcbsp_1510; + mcbsp_count = ARRAY_SIZE(mcbsp_1510); + } +#endif +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap1710()) { + mcbsp_info = mcbsp_1610; + mcbsp_count = ARRAY_SIZE(mcbsp_1610); + } +#endif + for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) { + if (i >= mcbsp_count) { + mcbsp[i].io_base = 0; + mcbsp[i].free = 0; + continue; + } + mcbsp[i].id = i + 1; + mcbsp[i].free = 1; + mcbsp[i].dma_tx_lch = -1; + mcbsp[i].dma_rx_lch = -1; + + mcbsp[i].io_base = mcbsp_info[i].virt_base; + mcbsp[i].tx_irq = mcbsp_info[i].tx_irq; + mcbsp[i].rx_irq = mcbsp_info[i].rx_irq; + mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync; + mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync; + spin_lock_init(&mcbsp[i].lock); + } + + return 0; +} + + +arch_initcall(omap_mcbsp_init); + +EXPORT_SYMBOL(omap_mcbsp_config); +EXPORT_SYMBOL(omap_mcbsp_request); +EXPORT_SYMBOL(omap_mcbsp_free); +EXPORT_SYMBOL(omap_mcbsp_start); +EXPORT_SYMBOL(omap_mcbsp_stop); +EXPORT_SYMBOL(omap_mcbsp_xmit_word); +EXPORT_SYMBOL(omap_mcbsp_recv_word); +EXPORT_SYMBOL(omap_mcbsp_xmit_buffer); +EXPORT_SYMBOL(omap_mcbsp_recv_buffer); +EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); diff -Nru a/arch/arm/mach-omap/ocpi.c b/arch/arm/mach-omap/ocpi.c --- a/arch/arm/mach-omap/ocpi.c 2004-10-18 14:57:04 -07:00 +++ b/arch/arm/mach-omap/ocpi.c 2004-10-18 14:57:04 -07:00 @@ -59,8 +59,8 @@ /* Make sure there's clock for OCPI */ -#ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap1710()) { val = omap_readl(OMAP1610_ARM_IDLECT3); val |= EN_OCPI_CK; val &= ~IDLOCPI_ARM; diff -Nru a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/usb.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,541 @@ +/* + * arch/arm/mach-omap/usb.c -- platform level USB initialization + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* These routines should handle the standard chip-specific modes + * for usb0/1/2 ports, covering basic mux and transceiver setup. + * Call omap_usb_init() once, from INIT_MACHINE(). + * + * Some board-*.c files will need to set up additional mux options, + * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup. + */ + +/* TESTED ON: + * - 1611B H2 (with usb1 mini-AB) + * - 1510 Innovator with built-in transceiver (custom cable feeding 5V VBUS) + * - 1710 custom development board using alternate pin group + */ + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP_OTG + +static struct otg_transceiver *xceiv; + +/** + * otg_get_transceiver - find the (single) OTG transceiver driver + * + * Returns the transceiver driver, after getting a refcount to it; or + * null if there is no such transceiver. The caller is responsible for + * releasing that count. + */ +struct otg_transceiver *otg_get_transceiver(void) +{ + if (xceiv) + get_device(xceiv->dev); + return xceiv; +} +EXPORT_SYMBOL(otg_get_transceiver); + +int otg_set_transceiver(struct otg_transceiver *x) +{ + if (xceiv && x) + return -EBUSY; + xceiv = x; + return 0; +} +EXPORT_SYMBOL(otg_set_transceiver); + +#endif + +/*-------------------------------------------------------------------------*/ + +static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device) +{ + u32 syscon1 = 0; + + if (nwires == 0) { + USB_TRANSCEIVER_CTRL_REG &= ~(1 << 3); + return 0; + } + + /* + * VP and VM are needed for all active usb0 configurations. + * USB0_VP and USB0_VM are always set on 1510, there's no muxing + * available for them. + */ + if (nwires >= 2 && !cpu_is_omap1510()) { + omap_cfg_reg(AA9_USB0_VP); + omap_cfg_reg(R9_USB0_VM); + } + + /* internal transceiver */ + if (nwires == 2) { + if (cpu_is_omap1510()) { + /* This works for OHCI on 1510-Innovator, nothing to mux */ + return 0; + } + +#if 0 + /* NOTE: host OR device mode for now, no OTG */ + USB_TRANSCEIVER_CTRL_REG &= ~(3 << 4); + if (is_device) { + omap_cfg_reg(W4_USB_PUEN); + omap_cfg_reg(R18_1510_USB_GPIO0); + // omap_cfg_reg(USB0_VBUS); + // omap_cfg_reg(USB0_PUEN); + // USB_TRANSCEIVER_CTRL_REG.CONF_USB0_PORT_R = 7 + // when USB0_PUEN is needed + } else /* host mode needs D+ and D- pulldowns */ + USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1); + return 3 << 16; +#else + /* FIXME: 1610 needs to return the right value here */ + printk(KERN_ERR "usb0 internal transceiver, nyet\n"); + return 0; +#endif + } + + /* alternate pin config, external transceiver */ + omap_cfg_reg(V6_USB0_TXD); + omap_cfg_reg(W9_USB0_TXEN); + omap_cfg_reg(W5_USB0_SE0); + +#ifdef CONFIG_ARCH_OMAP_USB_SPEED + /* FIXME: there's good chance that pin V9 is used for MMC2 port cmddir */ + omap_cfg_reg(V9_USB0_SPEED); + // omap_cfg_reg(V9_USB0_SUSP); +#endif + + if (nwires != 3) + omap_cfg_reg(Y5_USB0_RCV); + + switch (nwires) { + case 3: + syscon1 = 2; + break; + case 4: + syscon1 = 1; + break; + case 6: + syscon1 = 3; + /* REVISIT: Is CONF_USB2_UNI_R only needed when nwires = 6? */ + USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; + break; + default: + printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", + 0, nwires); + } + return syscon1 << 16; +} + +static u32 __init omap_usb1_init(unsigned nwires) +{ + u32 syscon1 = 0; + + if (nwires != 6) + USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R; + if (nwires == 0) + return 0; + + /* external transceiver */ + omap_cfg_reg(USB1_TXD); + omap_cfg_reg(USB1_TXEN); + if (cpu_is_omap1510()) { + omap_cfg_reg(USB1_SEO); + omap_cfg_reg(USB1_SPEED); + // SUSP + } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) { + omap_cfg_reg(W13_1610_USB1_SE0); + omap_cfg_reg(R13_1610_USB1_SPEED); + // SUSP + } else { + pr_debug("usb unrecognized\n"); + } + if (nwires != 3) + omap_cfg_reg(USB1_RCV); + + switch (nwires) { + case 3: + syscon1 = 2; + break; + case 4: + syscon1 = 1; + break; + case 6: + syscon1 = 3; + omap_cfg_reg(USB1_VP); + omap_cfg_reg(USB1_VM); + USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R; + break; + default: + printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", + 1, nwires); + } + return syscon1 << 20; +} + +static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup) +{ + u32 syscon1 = 0; + + if (alt_pingroup) + return 0; + if (nwires != 6) + USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; + if (nwires == 0) + return 0; + + /* external transceiver */ + if (cpu_is_omap1510()) { + omap_cfg_reg(USB2_TXD); + omap_cfg_reg(USB2_TXEN); + omap_cfg_reg(USB2_SEO); + if (nwires != 3) + omap_cfg_reg(USB2_RCV); + } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) { + omap_cfg_reg(V6_USB2_TXD); + omap_cfg_reg(W9_USB2_TXEN); + omap_cfg_reg(W5_USB2_SE0); + if (nwires != 3) + omap_cfg_reg(Y5_USB2_RCV); + } else { + pr_debug("usb unrecognized\n"); + } + // omap_cfg_reg(USB2_SUSP); + // FIXME omap_cfg_reg(USB2_SPEED); + + switch (nwires) { + case 3: + syscon1 = 2; + break; + case 4: + syscon1 = 1; + break; + case 6: + syscon1 = 3; + if (cpu_is_omap1510()) { + omap_cfg_reg(USB2_VP); + omap_cfg_reg(USB2_VM); + } else { + omap_cfg_reg(AA9_USB2_VP); + omap_cfg_reg(R9_USB2_VM); + } + USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; + break; + default: + printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", + 2, nwires); + } + return syscon1 << 24; +} + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_USB_GADGET_OMAP) || \ + defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) || \ + (defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)) +static void usb_release(struct device *dev) +{ + /* normally not freed */ +} +#endif + +#ifdef CONFIG_USB_GADGET_OMAP + +static struct resource udc_resources[] = { + /* order is significant! */ + { /* registers */ + .start = IO_ADDRESS(UDC_BASE), + .end = IO_ADDRESS(UDC_BASE + 0xff), + .flags = IORESOURCE_MEM, + }, { /* general IRQ */ + .start = IH2_BASE + 20, + .flags = IORESOURCE_IRQ, + }, { /* PIO IRQ */ + .start = IH2_BASE + 30, + .flags = IORESOURCE_IRQ, + }, { /* SOF IRQ */ + .start = IH2_BASE + 29, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 udc_dmamask = ~(u32)0; + +static struct platform_device udc_device = { + .name = "omap_udc", + .id = -1, + .dev = { + .release = usb_release, + .dma_mask = &udc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(udc_resources), + .resource = udc_resources, +}; + +#endif + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + +/* The dmamask must be set for OHCI to work */ +static u64 ohci_dmamask = ~(u32)0; + +static struct resource ohci_resources[] = { + { + .start = IO_ADDRESS(OMAP_OHCI_BASE), + .end = IO_ADDRESS(OMAP_OHCI_BASE + 4096), + .flags = IORESOURCE_MEM, + }, + { + .start = INT_USB_HHC_1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ohci_device = { + .name = "ohci", + .id = -1, + .dev = { + .release = usb_release, + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0x0fffffff, + }, + .num_resources = ARRAY_SIZE(ohci_resources), + .resource = ohci_resources, +}; + +#endif + +#if defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG) + +static struct resource otg_resources[] = { + /* order is significant! */ + { + .start = IO_ADDRESS(OTG_BASE), + .end = IO_ADDRESS(OTG_BASE + 0xff), + .flags = IORESOURCE_MEM, + }, { + .start = IH2_BASE + 8, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device otg_device = { + .name = "omap_otg", + .id = -1, + .dev = { + .release = usb_release, + }, + .num_resources = ARRAY_SIZE(otg_resources), + .resource = otg_resources, +}; + +#endif + +/*-------------------------------------------------------------------------*/ + +// FIXME correct answer depends on hmc_mode, +// as does any nonzero value for config->otg port number +#define is_usb0_device(config) 0 + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP_OTG + +void __init +omap_otg_init(struct omap_usb_config *config) +{ + u32 syscon = OTG_SYSCON_1_REG & 0xffff; + int status; + int alt_pingroup = 0; + + /* NOTE: no bus or clock setup (yet?) */ + + syscon = OTG_SYSCON_1_REG & 0xffff; + if (!(syscon & OTG_RESET_DONE)) + pr_debug("USB resets not complete?\n"); + + // OTG_IRQ_EN_REG = 0; + + /* pin muxing and transceiver pinouts */ + if (config->pins[0] > 2) /* alt pingroup 2 */ + alt_pingroup = 1; + syscon |= omap_usb0_init(config->pins[0], is_usb0_device(config)); + syscon |= omap_usb1_init(config->pins[1]); + syscon |= omap_usb2_init(config->pins[2], alt_pingroup); + pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon); + OTG_SYSCON_1_REG = syscon; + + syscon = config->hmc_mode; + syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */; + if (config->otg || config->register_host) + syscon |= UHOST_EN; +#ifdef CONFIG_USB_OTG + if (config->otg) + syscon |= OTG_EN; +#endif + pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon); + OTG_SYSCON_2_REG = syscon; + + printk("USB: hmc %d", config->hmc_mode); + if (alt_pingroup) + printk(", usb2 alt %d wires", config->pins[2]); + else if (config->pins[0]) + printk(", usb0 %d wires%s", config->pins[2], + is_usb0_device(config) ? " (dev)" : ""); + if (config->pins[1]) + printk(", usb1 %d wires", config->pins[1]); + if (!alt_pingroup && config->pins[2]) + printk(", usb2 %d wires", config->pins[2]); + if (config->otg) + printk(", Mini-AB on usb%d", config->otg - 1); + printk("\n"); + + /* don't clock unused USB controllers */ + syscon = OTG_SYSCON_1_REG; + syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN; + +#ifdef CONFIG_USB_GADGET_OMAP + if (config->otg || config->register_dev) { + syscon &= ~DEV_IDLE_EN; + udc_device.dev.platform_data = config; + status = platform_device_register(&udc_device); + if (status) + pr_debug("can't register UDC device, %d\n", status); + } +#endif + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + if (config->otg || config->register_host) { + syscon &= ~HST_IDLE_EN; + ohci_device.dev.platform_data = config; + status = platform_device_register(&ohci_device); + if (status) + pr_debug("can't register OHCI device, %d\n", status); + } +#endif + +#ifdef CONFIG_USB_OTG + if (config->otg) { + syscon &= ~OTG_IDLE_EN; + if (cpu_is_omap730()) + otg_resources[1].start = INT_730_USB_OTG; + status = platform_device_register(&otg_device); + // ... + } +#endif + pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon); + OTG_SYSCON_1_REG = syscon; + + status = 0; +} + +#else +static inline void omap_otg_init(struct omap_usb_config *config) {} +#endif + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP1510 + +static void __init omap_1510_usb_init(struct omap_usb_config *config) +{ + int status; + unsigned int val; + + omap_usb0_init(config->pins[0], is_usb0_device(config)); + omap_usb1_init(config->pins[1]); + omap_usb2_init(config->pins[2], 0); + + val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1); + val |= (config->hmc_mode << 1); + omap_writel(val, MOD_CONF_CTRL_0); + + // FIXME this has a UDC controller too + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + if (config->otg || config->register_host) { + ohci_device.dev.platform_data = config; + status = platform_device_register(&ohci_device); + if (status) + pr_debug("can't register OHCI device, %d\n", status); + } + // FIXME completely untested ... +#endif + +} + +#else +static inline void omap_1510_usb_init(struct omap_usb_config *config) {} +#endif + +/*-------------------------------------------------------------------------*/ + +static struct omap_usb_config platform_data; + +static int __init +omap_usb_init(void) +{ + const struct omap_usb_config *config; + + config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config); + if (config == NULL) { + printk(KERN_ERR "USB: No board-specific platform config found\n"); + return -ENODEV; + } + platform_data = *config; + + if (cpu_is_omap730() + || cpu_is_omap1610() + || cpu_is_omap1710() + || cpu_is_omap5912()) + omap_otg_init(&platform_data); + else if (cpu_is_omap1510()) + omap_1510_usb_init(&platform_data); + else { + printk(KERN_ERR "USB: No init for your chip yet\n"); + return -ENODEV; + } + return 0; +} + +subsys_initcall(omap_usb_init); diff -Nru a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig --- a/arch/arm/mach-pxa/Kconfig 2004-10-18 14:56:20 -07:00 +++ b/arch/arm/mach-pxa/Kconfig 2004-10-18 14:56:20 -07:00 @@ -12,7 +12,7 @@ config MACH_MAINSTONE bool "Intel HCDDBBVA0 Development Platform" select PXA27x - #select IWMMXT + select IWMMXT config ARCH_PXA_IDP bool "Accelent Xscale IDP" @@ -31,5 +31,10 @@ bool help Select code specific to PXA27x variants + +config IWMMXT + bool + help + Enable support for iWMMXt endif diff -Nru a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c --- a/arch/arm/mach-pxa/dma.c 2004-10-18 14:57:05 -07:00 +++ b/arch/arm/mach-pxa/dma.c 2004-10-18 14:57:05 -07:00 @@ -23,6 +23,7 @@ #include #include +#include static struct dma_channel { char *name; diff -Nru a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c --- a/arch/arm/mach-pxa/generic.c 2004-10-18 14:56:27 -07:00 +++ b/arch/arm/mach-pxa/generic.c 2004-10-18 14:56:27 -07:00 @@ -30,8 +30,10 @@ #include #include +#include #include #include +#include #include "generic.h" @@ -127,6 +129,12 @@ .num_resources = ARRAY_SIZE(pxamci_resources), .resource = pxamci_resources, }; + +void __init pxa_set_mci_info(struct pxamci_platform_data *info) +{ + pxamci_device.dev.platform_data = info; +} +EXPORT_SYMBOL(pxa_set_mci_info); static struct pxa2xx_udc_mach_info pxa_udc_info; diff -Nru a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c --- a/arch/arm/mach-pxa/idp.c 2004-10-18 14:55:46 -07:00 +++ b/arch/arm/mach-pxa/idp.c 2004-10-18 14:55:46 -07:00 @@ -27,6 +27,7 @@ #include #include +#include #include #include "generic.h" @@ -100,7 +101,7 @@ pxa_map_io(); iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc)); - set_irq_type(IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE); + set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE); // serial ports 2 & 3 pxa_gpio_mode(GPIO42_BTRXD_MD); diff -Nru a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c --- a/arch/arm/mach-pxa/irq.c 2004-10-18 14:57:03 -07:00 +++ b/arch/arm/mach-pxa/irq.c 2004-10-18 14:57:03 -07:00 @@ -20,39 +20,64 @@ #include #include #include +#include #include "generic.h" /* - * This is for IRQs known as PXA_IRQ([8...31]). + * This is for peripheral IRQs internal to the PXA chip. */ -static void pxa_mask_irq(unsigned int irq) +static void pxa_mask_low_irq(unsigned int irq) { ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); } -static void pxa_unmask_irq(unsigned int irq) +static void pxa_unmask_low_irq(unsigned int irq) { ICMR |= (1 << (irq + PXA_IRQ_SKIP)); } -static struct irqchip pxa_internal_chip = { - .ack = pxa_mask_irq, - .mask = pxa_mask_irq, - .unmask = pxa_unmask_irq, +static struct irqchip pxa_internal_chip_low = { + .ack = pxa_mask_low_irq, + .mask = pxa_mask_low_irq, + .unmask = pxa_unmask_low_irq, }; +#if PXA_INTERNAL_IRQS > 32 + +/* + * This is for the second set of internal IRQs as found on the PXA27x. + */ + +static void pxa_mask_high_irq(unsigned int irq) +{ + ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); +} + +static void pxa_unmask_high_irq(unsigned int irq) +{ + ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); +} + +static struct irqchip pxa_internal_chip_high = { + .ack = pxa_mask_high_irq, + .mask = pxa_mask_high_irq, + .unmask = pxa_unmask_high_irq, +}; + +#endif + /* * PXA GPIO edge detection for IRQs: * IRQs are generated on Falling-Edge, Rising-Edge, or both. * Use this instead of directly setting GRER/GFER. */ -static long GPIO_IRQ_rising_edge[3]; -static long GPIO_IRQ_falling_edge[3]; -static long GPIO_IRQ_mask[3]; +static long GPIO_IRQ_rising_edge[4]; +static long GPIO_IRQ_falling_edge[4]; +static long GPIO_IRQ_mask[4]; static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) { @@ -106,13 +131,13 @@ static struct irqchip pxa_low_gpio_chip = { .ack = pxa_ack_low_gpio, - .mask = pxa_mask_irq, - .unmask = pxa_unmask_irq, + .mask = pxa_mask_low_irq, + .unmask = pxa_unmask_low_irq, .type = pxa_gpio_irq_type, }; /* - * Demux handler for GPIO 2-80 edge detect interrupts + * Demux handler for GPIO>=2 edge detect interrupts */ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, @@ -169,6 +194,23 @@ } while (mask); loop = 1; } + +#if PXA_LAST_GPIO >= 96 + mask = GEDR3; + if (mask) { + GEDR3 = mask; + irq = IRQ_GPIO(96); + desc = irq_desc + irq; + do { + if (mask & 1) + desc->handle(irq, desc, regs); + irq++; + desc++; + mask >>= 1; + } while (mask); + loop = 1; + } +#endif } while (loop); } @@ -214,12 +256,25 @@ ICLR = 0; /* clear all GPIO edge detects */ - GFER0 = GFER1 = GFER2 = 0; - GRER0 = GRER1 = GRER2 = 0; + GFER0 = 0; + GFER1 = 0; + GFER2 = 0; + GRER0 = 0; + GRER1 = 0; + GRER2 = 0; GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; +#ifdef CONFIG_PXA27x + /* And similarly for the extra regs on the PXA27x */ + ICMR2 = 0; + ICLR2 = 0; + GFER3 = 0; + GRER3 = 0; + GEDR3 = GEDR3; +#endif + /* only unmasked interrupts kick us out of idle */ ICCR = 1; @@ -227,10 +282,18 @@ GPIO_IRQ_mask[0] = 3; for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { - set_irq_chip(irq, &pxa_internal_chip); + set_irq_chip(irq, &pxa_internal_chip_low); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); + } + +#if PXA_INTERNAL_IRQS > 32 + for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { + set_irq_chip(irq, &pxa_internal_chip_high); set_irq_handler(irq, do_level_IRQ); set_irq_flags(irq, IRQF_VALID); } +#endif for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { set_irq_chip(irq, &pxa_low_gpio_chip); @@ -238,13 +301,13 @@ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) { + for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { set_irq_chip(irq, &pxa_muxed_gpio_chip); set_irq_handler(irq, do_edge_IRQ); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - /* Install handler for GPIO 2-80 edge detect interrupts */ - set_irq_chip(IRQ_GPIO_2_80, &pxa_internal_chip); - set_irq_chained_handler(IRQ_GPIO_2_80, pxa_gpio_demux_handler); + /* Install handler for GPIO>=2 edge detect interrupts */ + set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); + set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); } diff -Nru a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c --- a/arch/arm/mach-pxa/leds-lubbock.c 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mach-pxa/leds-lubbock.c 2004-10-18 14:55:54 -07:00 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "leds.h" diff -Nru a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c --- a/arch/arm/mach-pxa/leds-mainstone.c 2004-10-18 14:55:53 -07:00 +++ b/arch/arm/mach-pxa/leds-mainstone.c 2004-10-18 14:55:53 -07:00 @@ -17,6 +17,7 @@ #include #include +#include #include #include "leds.h" diff -Nru a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c --- a/arch/arm/mach-pxa/lubbock.c 2004-10-18 14:56:28 -07:00 +++ b/arch/arm/mach-pxa/lubbock.c 2004-10-18 14:56:28 -07:00 @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff -Nru a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c --- a/arch/arm/mach-pxa/mainstone.c 2004-10-18 14:57:04 -07:00 +++ b/arch/arm/mach-pxa/mainstone.c 2004-10-18 14:57:04 -07:00 @@ -31,6 +31,7 @@ #include #include +#include #include #include diff -Nru a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c --- a/arch/arm/mach-pxa/pm.c 2004-10-18 14:56:33 -07:00 +++ b/arch/arm/mach-pxa/pm.c 2004-10-18 14:56:33 -07:00 @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include /* @@ -45,7 +47,7 @@ */ enum { SLEEP_SAVE_START = 0, - SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, + SLEEP_SAVE_OIER, SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, @@ -68,17 +70,18 @@ { unsigned long sleep_save[SLEEP_SAVE_SIZE]; unsigned long checksum = 0; - unsigned long delta; + struct timespec delta, rtc; int i; if (state != PM_SUSPEND_MEM) return -EINVAL; /* preserve current time */ - delta = xtime.tv_sec - RCNR; + rtc.tv_sec = RCNR; + rtc.tv_nsec = 0; + save_time_delta(&delta, &rtc); /* save vital registers */ - SAVE(OSCR); SAVE(OSMR0); SAVE(OSMR1); SAVE(OSMR2); @@ -149,9 +152,11 @@ RESTORE(OSMR1); RESTORE(OSMR2); RESTORE(OSMR3); - RESTORE(OSCR); RESTORE(OIER); + /* OSMR0 is the system timer: make sure OSCR is sufficiently behind */ + OSCR = OSMR0 - LATCH; + RESTORE(CKEN); ICLR = 0; @@ -159,7 +164,8 @@ RESTORE(ICMR); /* restore current time */ - xtime.tv_sec = RCNR + delta; + rtc.tv_sec = RCNR; + restore_time_delta(&delta, &rtc); #ifdef DEBUG printk(KERN_DEBUG "*** made it back from resume\n"); diff -Nru a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c --- a/arch/arm/mach-pxa/pxa25x.c 2004-10-18 14:57:19 -07:00 +++ b/arch/arm/mach-pxa/pxa25x.c 2004-10-18 14:57:19 -07:00 @@ -22,6 +22,7 @@ #include #include +#include #include "generic.h" diff -Nru a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c --- a/arch/arm/mach-pxa/pxa27x.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mach-pxa/pxa27x.c 2004-10-18 14:56:32 -07:00 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff -Nru a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S --- a/arch/arm/mach-pxa/sleep.S 2004-10-18 14:57:03 -07:00 +++ b/arch/arm/mach-pxa/sleep.S 2004-10-18 14:57:03 -07:00 @@ -16,6 +16,8 @@ #include #include +#include + .text /* @@ -64,6 +66,37 @@ @ prepare pointer to physical address 0 (virtual mapping in generic.c) mov r2, #UNCACHED_PHYS_0 + @ Intel PXA255 Specification Update notes problems + @ about suspending with PXBus operating above 133MHz + @ (see Errata 31, GPIO output signals, ... unpredictable in sleep + @ + @ We keep the change-down close to the actual suspend on SDRAM + @ as possible to eliminate messing about with the refresh clock + @ as the system will restore with the original speed settings + @ + @ Ben Dooks, 13-Sep-2004 + + ldr r6, =CCCR + ldr r8, [r6] @ keep original value for resume + + @ ensure x1 for run and turbo mode with memory clock + bic r7, r8, #CCCR_M_MASK | CCCR_N_MASK + orr r7, r7, #(1<<5) | (2<<7) + + @ check that the memory frequency is within limits + and r14, r7, #CCCR_L_MASK + teq r14, #1 + bicne r7, r7, #CCCR_L_MASK + orrne r7, r7, #1 @@ 99.53MHz + + @ get ready for the change + @ note, since we are making turbo=run, do not remove the turbo + @ as this may cause non-turbo mode on resume + mrc p14, 0, r0, c6, c0, 0 + bic r0, r0, #2 @ clear change bit + mcr p14, 0, r0, c6, c0, 0 + orr r0, r0, #2 @ initiate change bit + @ align execution to a cache line b 1f @@ -74,6 +107,13 @@ @ All needed values are now in registers. @ These last instructions should be in cache + @ initiate the frequency change... + str r7, [r6] + mcr p14, 0, r0, c6, c0, 0 + + @ restore the original cpu speed value for resume + str r8, [r6] + @ put SDRAM into self-refresh str r5, [r4] @@ -83,8 +123,7 @@ @ enter sleep mode mcr p14, 0, r1, c7, c0, 0 -20: nop - b 20b @ loop waiting for sleep +20: b 20b @ loop waiting for sleep /* * cpu_pxa_resume() diff -Nru a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c --- a/arch/arm/mach-pxa/time.c 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mach-pxa/time.c 2004-10-18 14:56:29 -07:00 @@ -27,6 +27,7 @@ #include #include #include +#include static inline unsigned long pxa_get_rtc_time(void) diff -Nru a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig --- a/arch/arm/mach-s3c2410/Kconfig 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mach-s3c2410/Kconfig 2004-10-18 14:56:29 -07:00 @@ -1,9 +1,10 @@ if ARCH_S3C2410 -menu "S3C2410 Implementations" +menu "S3C24XX Implementations" config ARCH_BAST bool "Simtec Electronics BAST (EB2410ITX)" + select CPU_S3C2410 help Say Y here if you are using the Simtec Electronics EB2410ITX development board (also known as BAST) @@ -12,18 +13,22 @@ config ARCH_H1940 bool "IPAQ H1940" + select CPU_S3C2410 help Say Y here if you are using the HP IPAQ H1940 + . config ARCH_SMDK2410 bool "SMDK2410/A9M2410" + select CPU_S3C2410 help Say Y here if you are using the SMDK2410 or the derived module A9M2410 config MACH_VR1000 bool "Thorcom VR1000" + select CPU_S3C2410 help Say Y here if you are using the Thorcom VR1000 board. @@ -31,5 +36,40 @@ of Thorcom. Any queries, please contact Thorcom first. endmenu + +config CPU_S3C2410 + bool + depends on ARCH_S3C2410 + help + Support for S3C2410 and S3C2410A family from the S3C24XX line + of Samsung Mobile CPUs. + +config CPU_S3C2440 + bool + depends on ARCH_S3C2410 + help + Support for S3C2440 Samsung Mobile CPU based systems. + +comment "S3C2410 Setup" + +config S3C2410_DMA + bool "S3C2410 DMA support" + depends on ARCH_S3C2410 + help + S3C2410 DMA support. This is needed for drivers like sound which + use the S3C2410's DMA system to move data to and from the + peripheral blocks. + +config S3C2410_DMA_DEBUG + bool "S3C2410 DMA support debug" + depends on ARCH_S3C2410 && S3C2410_DMA + help + Enable debugging output for the DMA code. This option sends info + to the kernel log, at priority KERN_DEBUG. + + Note, it is easy to create and fill the log buffer in a small + amount of time, as well as using an significant percantage of + the CPU time doing so. + endif diff -Nru a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile --- a/arch/arm/mach-s3c2410/Makefile 2004-10-18 14:56:17 -07:00 +++ b/arch/arm/mach-s3c2410/Makefile 2004-10-18 14:56:17 -07:00 @@ -1,19 +1,28 @@ + # # Makefile for the linux kernel. # # Object file lists. -obj-y := s3c2410.o irq.o time.o gpio.o +obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o obj-m := obj-n := obj- := -obj-$(CONFIG_ARCH_BAST) += mach-bast.o -obj-$(CONFIG_MACH_H1940) += mach-h1940.o -obj-$(CONFIG_ARCH_H1940) += mach-h1940.o -obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o -obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o +# S3C2410 support files + +obj-$(CONFIG_CPU_S3C2410) += s3c2410.o +obj-$(CONFIG_S3C2410_DMA) += dma.o + +# S3C2440 support + +obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o + +# machine specific support + +obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o +obj-$(CONFIG_ARCH_H1940) += mach-h1940.o +obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o +obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o -#obj-$(CONFIG_PCI) +=$(pci-y) -#obj-$(CONFIG_LEDS) +=$(leds-y) diff -Nru a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/clock.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,310 @@ +/* linux/arch/arm/mach-s3c2410/clock.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * S3C2410 Clock control support + * + * Based on, and code from linux/arch/arm/mach-versatile/clock.c + ** + ** Copyright (C) 2004 ARM Limited. + ** Written by Deep Blue Solutions Limited. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "clock.h" + + +static LIST_HEAD(clocks); +static DECLARE_MUTEX(clocks_sem); + + +/* old functions */ + +void s3c2410_clk_enable(unsigned int clocks, unsigned int enable) +{ + unsigned long clkcon; + unsigned long flags; + + local_irq_save(flags); + + clkcon = __raw_readl(S3C2410_CLKCON); + clkcon &= ~clocks; + + if (enable) + clkcon |= clocks; + + __raw_writel(clkcon, S3C2410_CLKCON); + + local_irq_restore(flags); +} + + +/* Clock API calls */ + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p; + struct clk *clk = ERR_PTR(-ENOENT); + + down(&clocks_sem); + list_for_each_entry(p, &clocks, list) { + if (strcmp(id, p->name) == 0 && + try_module_get(p->owner)) { + clk = p; + break; + } + } + up(&clocks_sem); + + return clk; +} + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} + +int clk_enable(struct clk *clk) +{ + if (clk->ctrlbit != 0) + s3c2410_clk_enable(clk->ctrlbit, 1); + + return 0; +} + +void clk_disable(struct clk *clk) +{ + s3c2410_clk_enable(clk->ctrlbit, 0); +} + + +int clk_use(struct clk *clk) +{ + atomic_inc(&clk->used); + return 0; +} + + +void clk_unuse(struct clk *clk) +{ + atomic_dec(&clk->used); +} + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk->parent != NULL) + return clk->parent->rate; + + return clk->rate; +} + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return rate; +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return -EINVAL; +} + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} + +EXPORT_SYMBOL(clk_get); +EXPORT_SYMBOL(clk_put); +EXPORT_SYMBOL(clk_enable); +EXPORT_SYMBOL(clk_disable); +EXPORT_SYMBOL(clk_use); +EXPORT_SYMBOL(clk_unuse); +EXPORT_SYMBOL(clk_get_rate); +EXPORT_SYMBOL(clk_round_rate); +EXPORT_SYMBOL(clk_set_rate); +EXPORT_SYMBOL(clk_get_parent); + +/* base clocks */ + +static struct clk clk_f = { + .name = "fclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0 +}; + +static struct clk clk_h = { + .name = "hclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0 +}; + +static struct clk clk_p = { + .name = "pclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0 +}; + +/* clock definitions */ + +static struct clk init_clocks[] = { + { .name = "nand", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_NAND + }, + { .name = "lcd", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_LCDC + }, + { .name = "usb-host", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_USBH + }, + { .name = "usb-device", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_USBD + }, + { .name = "timers", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_PWMT + }, + { .name = "sdi", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_SDI + }, + { .name = "uart0", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_UART0 + }, + { .name = "uart1", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_UART1 + }, + { .name = "uart2", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_UART2 + }, + { .name = "gpio", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_GPIO + }, + { .name = "rtc", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_RTC + }, + { .name = "adc", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_ADC + }, + { .name = "i2c", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_IIC + }, + { .name = "iis", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_IIS + }, + { .name = "spi", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_SPI + }, + { .name = "watchdog", + .parent = &clk_p, + .ctrlbit = 0 + } +}; + +/* initialise the clock system */ + +int s3c2410_register_clock(struct clk *clk) +{ + clk->owner = THIS_MODULE; + atomic_set(&clk->used, 0); + + /* add to the list of available clocks */ + + down(&clocks_sem); + list_add(&clk->list, &clocks); + up(&clocks_sem); + + return 0; +} + +/* initalise all the clocks */ + +static int __init s3c2410_init_clocks(void) +{ + struct clk *clkp = init_clocks; + int ptr; + int ret; + + printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n"); + + /* initialise the main system clocks */ + + clk_h.rate = s3c2410_hclk; + clk_p.rate = s3c2410_pclk; + clk_f.rate = s3c2410_fclk; + + /* set the enabled clocks to a minimal (known) state */ + __raw_writel(S3C2410_CLKCON_PWMT | S3C2410_CLKCON_UART0 | S3C2410_CLKCON_UART1 | S3C2410_CLKCON_UART2 | S3C2410_CLKCON_GPIO | S3C2410_CLKCON_RTC, S3C2410_CLKCON); + + /* register our clocks */ + + if (s3c2410_register_clock(&clk_f) < 0) + printk(KERN_ERR "failed to register cpu fclk\n"); + + if (s3c2410_register_clock(&clk_h) < 0) + printk(KERN_ERR "failed to register cpu hclk\n"); + + if (s3c2410_register_clock(&clk_p) < 0) + printk(KERN_ERR "failed to register cpu pclk\n"); + + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { + ret = s3c2410_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + return 0; +} + +arch_initcall(s3c2410_init_clocks); + diff -Nru a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/clock.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,20 @@ +/* + * linux/arch/arm/mach-s3c2410/clock.h + * + * Copyright (c) 2004 Simtec Electronics + * Written by Ben Dooks, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +struct clk { + struct list_head list; + struct module *owner; + struct clk *parent; + const char *name; + atomic_t used; + unsigned long rate; + unsigned long ctrlbit; +}; diff -Nru a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/cpu.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,152 @@ +/* linux/arch/arm/mach-s3c2410/cpu.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * S3C24XX CPU Support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "cpu.h" +#include "s3c2410.h" +#include "s3c2440.h" + +struct cpu_table { + unsigned long idcode; + unsigned long idmask; + void (*map_io)(struct map_desc *mach_desc, int size); + int (*init)(void); + const char *name; +}; + +/* table of supported CPUs */ + +static const char name_s3c2410[] = "S3C2410"; +static const char name_s3c2440[] = "S3C2440"; +static const char name_s3c2410a[] = "S3C2410A"; +static const char name_s3c2440a[] = "S3C2440A"; + +static struct cpu_table cpu_ids[] __initdata = { + { + .idcode = 0x32410000, + .idmask = 0xffffffff, + .map_io = s3c2410_map_io, + .init = s3c2410_init, + .name = name_s3c2410 + }, + { + .idcode = 0x3241002, + .idmask = 0xffffffff, + .map_io = s3c2410_map_io, + .init = s3c2410_init, + .name = name_s3c2410a + }, + { + .idcode = 0x32440000, + .idmask = 0xffffffff, + .map_io = s3c2440_map_io, + .init = s3c2440_init, + .name = name_s3c2440 + }, + { + .idcode = 0x32440001, + .idmask = 0xffffffff, + .map_io = s3c2440_map_io, + .init = s3c2440_init, + .name = name_s3c2440a + } +}; + +/* minimal IO mapping */ + +static struct map_desc s3c_iodesc[] __initdata = { + IODESC_ENT(GPIO), + IODESC_ENT(IRQ), + IODESC_ENT(MEMCTRL), + IODESC_ENT(UART) +}; + + +static struct cpu_table * +s3c_lookup_cpu(unsigned long idcode) +{ + struct cpu_table *tab; + int count; + + tab = cpu_ids; + for (count = 0; count < ARRAY_SIZE(cpu_ids); count++) { + if ((idcode & tab->idmask) == tab->idcode) + return tab; + } + + return NULL; +} + +static struct cpu_table *cpu; + +void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) +{ + unsigned long idcode; + + /* initialise the io descriptors we need for initialisation */ + iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); + + idcode = __raw_readl(S3C2410_GSTATUS1); + cpu = s3c_lookup_cpu(idcode); + + if (cpu == NULL) { + printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); + panic("Unknown S3C24XX CPU"); + } + + if (cpu->map_io == NULL || cpu->init == NULL) { + printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); + panic("Unsupported S3C24XX CPU"); + } + + printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); + + (cpu->map_io)(mach_desc, size); +} + +static int __init s3c_arch_init(void) +{ + // do the correct init for cpu + + if (cpu == NULL) + panic("s3c_arch_init: NULL cpu\n"); + + return (cpu->init)(); +} + +arch_initcall(s3c_arch_init); diff -Nru a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/cpu.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,41 @@ +/* arch/arm/mach-s3c2410/cpu.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for S3C24XX CPU support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 24-Aug-2004 BJD Start of generic S3C24XX support +*/ + +#define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE } + +#ifndef MHZ +#define MHZ (1000*1000) +#endif + +#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000) + +#ifdef CONFIG_CPU_S3C2410 +extern int s3c2410_init(void); +extern void s3c2410_map_io(struct map_desc *mach_desc, int size); +#else +#define s3c2410_map_io NULL +#define s3c2410_init NULL +#endif + +#ifdef CONFIG_CPU_S3C2440 +extern int s3c2440_init(void); +extern void s3c2440_map_io(struct map_desc *mach_desc, int size); +#else +#define s3c2440_map_io NULL +#define s3c2440_init NULL +#endif + +extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); + diff -Nru a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/devs.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,442 @@ +/* linux/arch/arm/mach-s3c2410/devs.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Base S3C2410 platform device definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 29-Aug-2004 BJD Added timers 0 through 3 + * 29-Aug-2004 BJD Changed index of devices we only have one of to -1 + * 21-Aug-2004 BJD Added IRQ_TICK to RTC resources + * 18-Aug-2004 BJD Created initial version +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "devs.h" + +/* USB Host Controller */ + +static struct resource s3c_usb_resource[] = { + [0] = { + .start = S3C2410_PA_USBHOST, + .end = S3C2410_PA_USBHOST + S3C2410_SZ_USBHOST, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_USBH, + .end = IRQ_USBH, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 s3c_device_usb_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_usb = { + .name = "s3c2410-ohci", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_resource), + .resource = s3c_usb_resource, + .dev = { + .dma_mask = &s3c_device_usb_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_usb); + +/* LCD Controller */ + +static struct resource s3c_lcd_resource[] = { + [0] = { + .start = S3C2410_PA_LCD, + .end = S3C2410_PA_LCD + S3C2410_SZ_LCD, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LCD, + .end = IRQ_LCD, + .flags = IORESOURCE_IRQ, + } + +}; + +static u64 s3c_device_lcd_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_lcd = { + .name = "s3c2410-lcd", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_lcd_resource), + .resource = s3c_lcd_resource, + .dev = { + .dma_mask = &s3c_device_lcd_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_lcd); + +/* NAND Controller */ + +static struct resource s3c_nand_resource[] = { + [0] = { + .start = S3C2410_PA_NAND, + .end = S3C2410_PA_NAND + S3C2410_SZ_NAND, + .flags = IORESOURCE_MEM, + } +}; + +struct platform_device s3c_device_nand = { + .name = "s3c2410-nand", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_nand_resource), + .resource = s3c_nand_resource, +}; + +EXPORT_SYMBOL(s3c_device_nand); + +/* USB Device (Gadget)*/ + +static struct resource s3c_usbgadget_resource[] = { + [0] = { + .start = S3C2410_PA_USBDEV, + .end = S3C2410_PA_USBDEV + S3C2410_SZ_USBDEV, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_USBD, + .end = IRQ_USBD, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_usbgadget = { + .name = "s3c2410-usbgadget", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usbgadget_resource), + .resource = s3c_usbgadget_resource, +}; + +EXPORT_SYMBOL(s3c_device_usbgadget); + +/* Watchdog */ + +static struct resource s3c_wdt_resource[] = { + [0] = { + .start = S3C2410_PA_WATCHDOG, + .end = S3C2410_PA_WATCHDOG + S3C2410_SZ_WATCHDOG, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_WDT, + .end = IRQ_WDT, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_wdt = { + .name = "s3c2410-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_wdt_resource), + .resource = s3c_wdt_resource, +}; + +EXPORT_SYMBOL(s3c_device_wdt); + +/* I2C */ + +static struct resource s3c_i2c_resource[] = { + [0] = { + .start = S3C2410_PA_IIC, + .end = S3C2410_PA_IIC + S3C2410_SZ_IIC, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IIC, + .end = IRQ_IIC, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_i2c = { + .name = "s3c2410-i2c", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_i2c_resource), + .resource = s3c_i2c_resource, +}; + +EXPORT_SYMBOL(s3c_device_i2c); + +/* IIS */ + +static struct resource s3c_iis_resource[] = { + [0] = { + .start = S3C2410_PA_IIS, + .end = S3C2410_PA_IIS + S3C2410_SZ_IIS, + .flags = IORESOURCE_MEM, + } +}; + +static u64 s3c_device_iis_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_iis = { + .name = "s3c2410-iis", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_iis_resource), + .resource = s3c_iis_resource, + .dev = { + .dma_mask = &s3c_device_iis_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_iis); + +/* RTC */ + +static struct resource s3c_rtc_resource[] = { + [0] = { + .start = S3C2410_PA_RTC, + .end = S3C2410_PA_RTC + 0xff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_RTC, + .end = IRQ_RTC, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = IRQ_TICK, + .end = IRQ_TICK, + .flags = IORESOURCE_IRQ + } +}; + +struct platform_device s3c_device_rtc = { + .name = "s3c2410-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_rtc_resource), + .resource = s3c_rtc_resource, +}; + +EXPORT_SYMBOL(s3c_device_rtc); + +/* ADC */ + +static struct resource s3c_adc_resource[] = { + [0] = { + .start = S3C2410_PA_ADC, + .end = S3C2410_PA_ADC + S3C2410_SZ_ADC, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TC, + .end = IRQ_ADC, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_adc = { + .name = "s3c2410-adc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_adc_resource), + .resource = s3c_adc_resource, +}; + +/* SDI */ + +static struct resource s3c_sdi_resource[] = { + [0] = { + .start = S3C2410_PA_SDI, + .end = S3C2410_PA_SDI + S3C2410_SZ_SDI, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SDI, + .end = IRQ_SDI, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_sdi = { + .name = "s3c2410-sdi", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_sdi_resource), + .resource = s3c_sdi_resource, +}; + +EXPORT_SYMBOL(s3c_device_sdi); + +/* SPI (0) */ + +static struct resource s3c_spi0_resource[] = { + [0] = { + .start = S3C2410_PA_SPI, + .end = S3C2410_PA_SPI + 0x1f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SPI0, + .end = IRQ_SPI0, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_spi0 = { + .name = "s3c2410-spi", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_spi0_resource), + .resource = s3c_spi0_resource, +}; + +EXPORT_SYMBOL(s3c_device_spi0); + +/* SPI (1) */ + +static struct resource s3c_spi1_resource[] = { + [0] = { + .start = S3C2410_PA_SPI + 0x20, + .end = S3C2410_PA_SPI + 0x20 + 0x1f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SPI1, + .end = IRQ_SPI1, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_spi1 = { + .name = "s3c2410-spi", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_spi1_resource), + .resource = s3c_spi1_resource, +}; + +EXPORT_SYMBOL(s3c_device_spi1); + +/* pwm timer blocks */ + +static struct resource s3c_timer0_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x0C, + .end = S3C2410_PA_TIMER + 0x0C + 0xB, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER0, + .end = IRQ_TIMER0, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer0 = { + .name = "s3c2410-timer", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_timer0_resource), + .resource = s3c_timer0_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer0); + +/* timer 1 */ + +static struct resource s3c_timer1_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x18, + .end = S3C2410_PA_TIMER + 0x23, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER1, + .end = IRQ_TIMER1, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer1 = { + .name = "s3c2410-timer", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_timer1_resource), + .resource = s3c_timer1_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer1); + +/* timer 2 */ + +static struct resource s3c_timer2_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x24, + .end = S3C2410_PA_TIMER + 0x2F, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER2, + .end = IRQ_TIMER2, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer2 = { + .name = "s3c2410-timer", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_timer2_resource), + .resource = s3c_timer2_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer2); + +/* timer 3 */ + +static struct resource s3c_timer3_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x30, + .end = S3C2410_PA_TIMER + 0x3B, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER3, + .end = IRQ_TIMER3, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer3 = { + .name = "s3c2410-timer", + .id = 3, + .num_resources = ARRAY_SIZE(s3c_timer3_resource), + .resource = s3c_timer3_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer3); diff -Nru a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/devs.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,36 @@ +/* arch/arm/mach-s3c2410/devs.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2410 standard platform devices + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 18-Aug-2004 BJD Created initial version + * 27-Aug-2004 BJD Added timers 0 through 3 +*/ + +extern struct platform_device s3c_device_usb; +extern struct platform_device s3c_device_lcd; +extern struct platform_device s3c_device_wdt; +extern struct platform_device s3c_device_i2c; +extern struct platform_device s3c_device_iis; +extern struct platform_device s3c_device_rtc; +extern struct platform_device s3c_device_adc; +extern struct platform_device s3c_device_sdi; + +extern struct platform_device s3c_device_spi0; +extern struct platform_device s3c_device_spi1; + +extern struct platform_device s3c_device_nand; + +extern struct platform_device s3c_device_timer0; +extern struct platform_device s3c_device_timer1; +extern struct platform_device s3c_device_timer2; +extern struct platform_device s3c_device_timer3; + +extern struct platform_device s3c_device_usbgadget; diff -Nru a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/dma.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,1085 @@ +/* linux/arch/arm/mach-bast/dma.c + * + * (c) 2003,2004 Simtec Electronics + * Ben Dooks + * + * S3C2410 DMA core + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 08-Aug-2004 BJD Apply rmk's suggestions + * 21-Jul-2004 BJD Ported to linux 2.6 + * 12-Jul-2004 BJD Finished re-write and change of API + * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems + * 23-May-2003 BJD Created file + * 19-Aug-2003 BJD Cleanup, header fix, added URL + * + * This file is based on the Sangwook Lee/Samsung patches, re-written due + * to various ommisions from the code (such as flexible dma configuration) + * for use with the BAST system board. + * + * The re-write is pretty much complete, and should be good enough for any + * possible DMA function + */ + +#include + +#ifdef CONFIG_S3C2410_DMA_DEBUG +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* io map for dma */ +static void *dma_base; + +/* dma channel state information */ +s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS]; + +/* debugging functions */ + +#define BUF_MAGIC (0xcafebabe) + +#define dmawarn(fmt...) printk(KERN_DEBUG fmt) + +#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) + +#if 1 +#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) +#else +static inline void +dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val) +{ + pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); + writel(val, dma_regaddr(chan, reg)); +} + +#endif + +#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) + +/* captured register state for debug */ + +struct s3c2410_dma_regstate { + unsigned long dcsrc; + unsigned long disrc; + unsigned long dstat; + unsigned long dcon; + unsigned long dmsktrig; +}; + +#ifdef CONFIG_S3C2410_DMA_DEBUG + +/* dmadbg_showregs + * + * simple debug routine to print the current state of the dma registers +*/ + +static void +dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs) +{ + regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC); + regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC); + regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT); + regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON); + regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); +} + +static void +dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan, + struct s3c2410_dma_regstate *regs) +{ + printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", + chan->number, fname, line, + regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, + regs->dcon); +} + +static void +dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan) +{ + struct s3c2410_dma_regstate state; + + dmadbg_capture(chan, &state); + + printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", + chan->number, fname, line, chan->load_state, + chan->curr, chan->next, chan->end); + + dmadbg_showregs(fname, line, chan, &state); +} + +#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan)) +#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan)) +#else +#define dbg_showregs(chan) do { } while(0) +#define dbg_showchan(chan) do { } while(0) +#endif /* CONFIG_S3C2410_DMA_DEBUG */ + +#define check_channel(chan) \ + do { if ((chan) >= S3C2410_DMA_CHANNELS) { \ + printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \ + return -EINVAL; \ + } } while(0) + + +/* s3c2410_dma_stats_timeout + * + * Update DMA stats from timeout info +*/ + +static void +s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *stats, int val) +{ + if (stats == NULL) + return; + + if (val > stats->timeout_longest) + stats->timeout_longest = val; + if (val < stats->timeout_shortest) + stats->timeout_shortest = val; + + stats->timeout_avg += val; +} + +/* s3c2410_dma_waitforload + * + * wait for the DMA engine to load a buffer, and update the state accordingly +*/ + +static int +s3c2410_dma_waitforload(s3c2410_dma_chan_t *chan, int line) +{ + int timeout = chan->load_timeout; + int took; + + if (chan->load_state != S3C2410_DMALOAD_1LOADED) { + printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); + return 0; + } + + if (chan->stats != NULL) + chan->stats->loads++; + + while (--timeout > 0) { + if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { + took = chan->load_timeout - timeout; + + s3c2410_dma_stats_timeout(chan->stats, took); + + switch (chan->load_state) { + case S3C2410_DMALOAD_1LOADED: + chan->load_state = S3C2410_DMALOAD_1RUNNING; + break; + + default: + printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); + } + + return 1; + } + } + + if (chan->stats != NULL) { + chan->stats->timeout_failed++; + } + + return 0; +} + + + +/* s3c2410_dma_loadbuffer + * + * load a buffer, and update the channel state +*/ + +static inline int +s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan, + s3c2410_dma_buf_t *buf) +{ + unsigned long reload; + + pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", + buf, (unsigned long)buf->data, buf->size); + + if (buf == NULL) { + dmawarn("buffer is NULL\n"); + return -EINVAL; + } + + /* check the state of the channel before we do anything */ + + if (chan->load_state == S3C2410_DMALOAD_1LOADED) { + dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); + } + + if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { + dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); + } + + /* it would seem sensible if we are the last buffer to not bother + * with the auto-reload bit, so that the DMA engine will not try + * and load another transfer after this one has finished... + */ + if (chan->load_state == S3C2410_DMALOAD_NONE) { + pr_debug("load_state is none, checking for noreload (next=%p)\n", + buf->next); + reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; + } else { + pr_debug("load_state is %d => autoreload\n", chan->load_state); + reload = S3C2410_DCON_AUTORELOAD; + } + + writel(buf->data, chan->addr_reg); + + dma_wrreg(chan, S3C2410_DMA_DCON, + chan->dcon | reload | (buf->size/chan->xfer_unit)); + + chan->next = buf->next; + + /* update the state of the channel */ + + switch (chan->load_state) { + case S3C2410_DMALOAD_NONE: + chan->load_state = S3C2410_DMALOAD_1LOADED; + break; + + case S3C2410_DMALOAD_1RUNNING: + chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; + break; + + default: + dmawarn("dmaload: unknown state %d in loadbuffer\n", + chan->load_state); + break; + } + + return 0; +} + +/* s3c2410_dma_call_op + * + * small routine to call the op routine with the given op if it has been + * registered +*/ + +static void +s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op) +{ + if (chan->op_fn != NULL) { + (chan->op_fn)(chan, op); + } +} + +/* s3c2410_dma_buffdone + * + * small wrapper to check if callback routine needs to be called, and + * if so, call it +*/ + +static inline void +s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf, + s3c2410_dma_buffresult_t result) +{ + pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", + chan->callback_fn, buf, buf->id, buf->size, result); + + if (chan->callback_fn != NULL) { + (chan->callback_fn)(chan, buf->id, buf->size, result); + } +} + +/* s3c2410_dma_start + * + * start a dma channel going +*/ + +static int s3c2410_dma_start(s3c2410_dma_chan_t *chan) +{ + unsigned long tmp; + unsigned long flags; + + pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); + + local_irq_save(flags); + + if (chan->state == S3C2410_DMA_RUNNING) { + pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); + local_irq_restore(flags); + return 0; + } + + chan->state = S3C2410_DMA_RUNNING; + + /* check wether there is anything to load, and if not, see + * if we can find anything to load + */ + + if (chan->load_state == S3C2410_DMALOAD_NONE) { + if (chan->next == NULL) { + printk(KERN_ERR "dma%d: channel has nothing loaded\n", + chan->number); + chan->state = S3C2410_DMA_IDLE; + local_irq_restore(flags); + return -EINVAL; + } + + s3c2410_dma_loadbuffer(chan, chan->next); + } + + dbg_showchan(chan); + + /* enable the channel */ + + if (!chan->irq_enabled) { + enable_irq(chan->irq); + chan->irq_enabled = 1; + } + + /* start the channel going */ + + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + tmp &= ~S3C2410_DMASKTRIG_STOP; + tmp |= S3C2410_DMASKTRIG_ON; + dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + + pr_debug("wrote %08lx to DMASKTRIG\n", tmp); + +#if 0 + /* the dma buffer loads should take care of clearing the AUTO + * reloading feature */ + tmp = dma_rdreg(chan, S3C2410_DMA_DCON); + tmp &= ~S3C2410_DCON_NORELOAD; + dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + + s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); + + dbg_showchan(chan); + + local_irq_restore(flags); + return 0; +} + +/* s3c2410_dma_canload + * + * work out if we can queue another buffer into the DMA engine +*/ + +static int +s3c2410_dma_canload(s3c2410_dma_chan_t *chan) +{ + if (chan->load_state == S3C2410_DMALOAD_NONE || + chan->load_state == S3C2410_DMALOAD_1RUNNING) + return 1; + + return 0; +} + + +/* s3c2410_dma_enqueue + * + * queue an given buffer for dma transfer. + * + * id the device driver's id information for this buffer + * data the physical address of the buffer data + * size the size of the buffer in bytes + * + * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART + * is checked, and if set, the channel is started. If this flag isn't set, + * then an error will be returned. + * + * It is possible to queue more than one DMA buffer onto a channel at + * once, and the code will deal with the re-loading of the next buffer + * when necessary. +*/ + +int s3c2410_dma_enqueue(unsigned int channel, void *id, + dma_addr_t data, int size) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + s3c2410_dma_buf_t *buf; + unsigned long flags; + + check_channel(channel); + + pr_debug("%s: id=%p, data=%08x, size=%d\n", + __FUNCTION__, id, (unsigned int)data, size); + + buf = (s3c2410_dma_buf_t *)kmalloc(sizeof(*buf), GFP_ATOMIC); + if (buf == NULL) { + pr_debug("%s: out of memory (%d alloc)\n", + __FUNCTION__, sizeof(*buf)); + return -ENOMEM; + } + + pr_debug("%s: new buffer %p\n", __FUNCTION__, buf); + + //dbg_showchan(chan); + + buf->next = NULL; + buf->data = buf->ptr = data; + buf->size = size; + buf->id = id; + buf->magic = BUF_MAGIC; + + local_irq_save(flags); + + if (chan->curr == NULL) { + /* we've got nothing loaded... */ + pr_debug("%s: buffer %p queued onto empty channel\n", + __FUNCTION__, buf); + + chan->curr = buf; + chan->end = buf; + chan->next = NULL; + } else { + pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", + chan->number, __FUNCTION__, buf); + + if (chan->end == NULL) + pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", + chan->number, __FUNCTION__, chan); + + chan->end->next = buf; + chan->end = buf; + } + + /* if necessary, update the next buffer field */ + if (chan->next == NULL) + chan->next = buf; + + /* check to see if we can load a buffer */ + if (chan->state == S3C2410_DMA_RUNNING) { + if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + printk(KERN_ERR "dma%d: loadbuffer:" + "timeout loading buffer\n", + chan->number); + dbg_showchan(chan); + local_irq_restore(flags); + return -EINVAL; + } + } + + while (s3c2410_dma_canload(chan) && chan->next != NULL) { + s3c2410_dma_loadbuffer(chan, chan->next); + } + } else if (chan->state == S3C2410_DMA_IDLE) { + if (chan->flags & S3C2410_DMAF_AUTOSTART) { + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START); + } else { + printk(KERN_DEBUG "dma%d: cannot load onto stopped channel'n", chan->number); + local_irq_restore(flags); + return -EINVAL; + } + } + + local_irq_restore(flags); + return 0; +} + +static inline void +s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf) +{ + int magicok = (buf->magic == BUF_MAGIC); + + buf->magic = -1; + + if (magicok) { + kfree(buf); + } else { + printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); + } +} + +/* s3c2410_dma_lastxfer + * + * called when the system is out of buffers, to ensure that the channel + * is prepared for shutdown. +*/ + +static inline void +s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan) +{ + pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", + chan->number, chan->load_state); + + switch (chan->load_state) { + case S3C2410_DMALOAD_NONE: + break; + + case S3C2410_DMALOAD_1LOADED: + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + /* flag error? */ + printk(KERN_ERR "dma%d: timeout waiting for load\n", + chan->number); + return; + } + break; + + default: + pr_debug("dma%d: lastxfer: unhandled load_state %d with no next", + chan->number, chan->load_state); + return; + + } + + /* hopefully this'll shut the damned thing up after the transfer... */ + dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); +} + + +#define dmadbg2(x...) + +static irqreturn_t +s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs) +{ + s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw; + s3c2410_dma_buf_t *buf; + + buf = chan->curr; + + dbg_showchan(chan); + + /* modify the channel state */ + + switch (chan->load_state) { + case S3C2410_DMALOAD_1RUNNING: + /* TODO - if we are running only one buffer, we probably + * want to reload here, and then worry about the buffer + * callback */ + + chan->load_state = S3C2410_DMALOAD_NONE; + break; + + case S3C2410_DMALOAD_1LOADED: + /* iirc, we should go back to NONE loaded here, we + * had a buffer, and it was never verified as being + * loaded. + */ + + chan->load_state = S3C2410_DMALOAD_NONE; + break; + + case S3C2410_DMALOAD_1LOADED_1RUNNING: + /* we'll worry about checking to see if another buffer is + * ready after we've called back the owner. This should + * ensure we do not wait around too long for the DMA + * engine to start the next transfer + */ + + chan->load_state = S3C2410_DMALOAD_1LOADED; + break; + + case S3C2410_DMALOAD_NONE: + printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", + chan->number); + break; + + default: + printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", + chan->number, chan->load_state); + break; + } + + if (buf != NULL) { + /* update the chain to make sure that if we load any more + * buffers when we call the callback function, things should + * work properly */ + + chan->curr = buf->next; + buf->next = NULL; + + if (buf->magic != BUF_MAGIC) { + printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", + chan->number, __FUNCTION__, buf); + return IRQ_HANDLED; + } + + s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); + + /* free resouces */ + s3c2410_dma_freebuf(buf); + } else { + } + + if (chan->next != NULL) { + unsigned long flags; + + switch (chan->load_state) { + case S3C2410_DMALOAD_1RUNNING: + /* don't need to do anything for this state */ + break; + + case S3C2410_DMALOAD_NONE: + /* can load buffer immediately */ + break; + + case S3C2410_DMALOAD_1LOADED: + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + /* flag error? */ + printk(KERN_ERR "dma%d: timeout waiting for load\n", + chan->number); + return IRQ_HANDLED; + } + + break; + + default: + printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", + chan->number, chan->load_state); + return IRQ_HANDLED; + } + + local_irq_save(flags); + s3c2410_dma_loadbuffer(chan, chan->next); + local_irq_restore(flags); + } else { + s3c2410_dma_lastxfer(chan); + + /* see if we can stop this channel.. */ + if (chan->load_state == S3C2410_DMALOAD_NONE) { + pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", + chan->number, jiffies); + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); + } + } + + return IRQ_HANDLED; +} + + + +/* s3c2410_request_dma + * + * get control of an dma channel +*/ + +int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client, + void *dev) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + unsigned long flags; + int err; + + pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", + channel, client->name, dev); + + check_channel(channel); + + local_irq_save(flags); + + dbg_showchan(chan); + + if (chan->in_use) { + if (client != chan->client) { + printk(KERN_ERR "dma%d: already in use\n", channel); + local_irq_restore(flags); + return -EBUSY; + } else { + printk(KERN_ERR "dma%d: client already has channel\n", channel); + } + } + + chan->client = client; + chan->in_use = 1; + + if (!chan->irq_claimed) { + pr_debug("dma%d: %s : requesting irq %d\n", + channel, __FUNCTION__, chan->irq); + + err = request_irq(chan->irq, s3c2410_dma_irq, SA_INTERRUPT, + client->name, (void *)chan); + + if (err) { + chan->in_use = 0; + local_irq_restore(flags); + + printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", + client->name, chan->irq, chan->number); + return err; + } + + chan->irq_claimed = 1; + chan->irq_enabled = 1; + } + + local_irq_restore(flags); + + /* need to setup */ + + pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan); + + return 0; +} + +/* s3c2410_dma_free + * + * release the given channel back to the system, will stop and flush + * any outstanding transfers, and ensure the channel is ready for the + * next claimant. + * + * Note, although a warning is currently printed if the freeing client + * info is not the same as the registrant's client info, the free is still + * allowed to go through. +*/ + +int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + unsigned long flags; + + check_channel(channel); + + local_irq_save(flags); + + + if (chan->client != client) { + printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", + channel, chan->client, client); + } + + /* sort out stopping and freeing the channel */ + + if (chan->state != S3C2410_DMA_IDLE) { + pr_debug("%s: need to stop dma channel %p\n", + __FUNCTION__, chan); + + /* possibly flush the channel */ + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); + } + + chan->client = NULL; + chan->in_use = 0; + + local_irq_restore(flags); + + return 0; +} + +static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan) +{ + unsigned long tmp; + unsigned long flags; + + pr_debug("%s:\n", __FUNCTION__); + + dbg_showchan(chan); + + local_irq_save(flags); + + s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP); + + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + tmp |= S3C2410_DMASKTRIG_STOP; + dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + +#if 0 + /* should also clear interrupts, according to WinCE BSP */ + tmp = dma_rdreg(chan, S3C2410_DMA_DCON); + tmp |= S3C2410_DCON_NORELOAD; + dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + + chan->state = S3C2410_DMA_IDLE; + chan->load_state = S3C2410_DMALOAD_NONE; + + local_irq_restore(flags); + + return 0; +} + +/* s3c2410_dma_flush + * + * stop the channel, and remove all current and pending transfers +*/ + +static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan) +{ + s3c2410_dma_buf_t *buf, *next; + unsigned long flags; + + pr_debug("%s:\n", __FUNCTION__); + + local_irq_save(flags); + + if (chan->state != S3C2410_DMA_IDLE) { + pr_debug("%s: stopping channel...\n", __FUNCTION__ ); + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); + } + + buf = chan->curr; + if (buf == NULL) + buf = chan->next; + + chan->curr = chan->next = chan->end = NULL; + + if (buf != NULL) { + for ( ; buf != NULL; buf = next) { + next = buf->next; + + pr_debug("%s: free buffer %p, next %p\n", + __FUNCTION__, buf, buf->next); + + s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); + s3c2410_dma_freebuf(buf); + } + } + + local_irq_restore(flags); + + return 0; +} + + +int +s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + switch (op) { + case S3C2410_DMAOP_START: + return s3c2410_dma_start(chan); + + case S3C2410_DMAOP_STOP: + return s3c2410_dma_dostop(chan); + + case S3C2410_DMAOP_PAUSE: + return -ENOENT; + + case S3C2410_DMAOP_RESUME: + return -ENOENT; + + case S3C2410_DMAOP_FLUSH: + return s3c2410_dma_flush(chan); + + case S3C2410_DMAOP_TIMEOUT: + return 0; + + } + + return -ENOENT; /* unknown, don't bother */ +} + + +/* DMA configuration for each channel + * + * DISRCC -> source of the DMA (AHB,APB) + * DISRC -> source address of the DMA + * DIDSTC -> destination of the DMA (AHB,APD) + * DIDST -> destination address of the DMA +*/ + +/* s3c2410_dma_config + * + * xfersize: size of unit in bytes (1,2,4) + * dcon: base value of the DCONx register +*/ + +int s3c2410_dma_config(dmach_t channel, + int xferunit, + int dcon) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", + __FUNCTION__, channel, xferunit, dcon); + + check_channel(channel); + + switch (xferunit) { + case 1: + dcon |= S3C2410_DCON_BYTE; + break; + + case 2: + dcon |= S3C2410_DCON_HALFWORD; + break; + + case 4: + dcon |= S3C2410_DCON_WORD; + break; + + default: + pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit); + return -EINVAL; + } + + dcon |= S3C2410_DCON_HWTRIG; + dcon |= S3C2410_DCON_INTREQ; + + pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon); + + chan->dcon = dcon; + chan->xfer_unit = xferunit; + + return 0; +} + + +int s3c2410_dma_setflags(dmach_t channel, unsigned int flags) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags); + + chan->flags = flags; + + return 0; +} + +/* do we need to protect the settings of the fields from + * irq? +*/ + +int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn); + + chan->op_fn = rtn; + + return 0; +} + +int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn); + + chan->callback_fn = rtn; + + return 0; +} + +/* s3c2410_dma_devconfig + * + * configure the dma source/destination hardware type and address + * + * source: S3C2410_DMASRC_HW: source is hardware + * S3C2410_DMASRC_MEM: source is memory + * + * hwcfg: the value for xxxSTCn register, + * bit 0: 0=increment pointer, 1=leave pointer + * bit 1: 0=soucre is AHB, 1=soucre is APB + * + * devaddr: physical address of the source +*/ + +int s3c2410_dma_devconfig(int channel, + s3c2410_dmasrc_t source, + int hwcfg, + unsigned long devaddr) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n", + __FUNCTION__, (int)source, hwcfg, devaddr); + + chan->source = source; + chan->dev_addr = devaddr; + + switch (source) { + case S3C2410_DMASRC_HW: + /* source is hardware */ + pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", + __FUNCTION__, devaddr, hwcfg); + dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); + dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr); + dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); + + chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); + return 0; + + case S3C2410_DMASRC_MEM: + /* source is memory */ + pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n", + __FUNCTION__, devaddr, hwcfg); + dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); + dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr); + dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); + + chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); + return 0; + } + + printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source); + return -EINVAL; +} + +/* initialisation code */ + +static int __init s3c2410_init_dma(void) +{ + int channel; + s3c2410_dma_chan_t *cp; + + printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n"); + + dma_base = ioremap(S3C2410_PA_DMA, 0x200); + if (dma_base == NULL) { + printk(KERN_ERR "dma failed to remap register block\n"); + return -ENOMEM; + } + + for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) { + cp = &s3c2410_chans[channel]; + + memset(cp, 0, sizeof(s3c2410_dma_chan_t)); + + /* dma channel irqs are in order.. */ + cp->number = channel; + cp->irq = channel + IRQ_DMA0; + cp->regs = (unsigned long)dma_base + (channel*0x40); + + /* point current stats somewhere */ + cp->stats = &cp->stats_store; + cp->stats_store.timeout_shortest = LONG_MAX; + + /* basic channel configuration */ + + cp->load_timeout = 1<<18; + + printk("DMA channel %d at %08lx, irq %d\n", + cp->number, cp->regs, cp->irq); + } + + return 0; +} + +__initcall(s3c2410_init_dma); diff -Nru a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c --- a/arch/arm/mach-s3c2410/gpio.c 2004-10-18 14:56:49 -07:00 +++ b/arch/arm/mach-s3c2410/gpio.c 2004-10-18 14:56:49 -07:00 @@ -19,6 +19,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * Changelog + * 13-Sep-2004 BJD Implemented change of MISCCR + * 14-Sep-2004 BJD Added getpin call + * 14-Sep-2004 BJD Fixed bug in setpin() call + * 30-Sep-2004 BJD Fixed cfgpin() mask bug + * 01-Oct-2004 BJD Added getcfg() to get pin configuration + * 01-Oct-2004 BJD Fixed mask bug in pullup() call + * 01-Oct-2004 BJD Added getirq() to turn pin into irqno + * 04-Oct-2004 BJD Added irq filter controls for GPIO */ @@ -36,23 +45,20 @@ void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) { unsigned long base = S3C2410_GPIO_BASE(pin); - unsigned long shift = 1; - unsigned long mask = 3; + unsigned long mask; unsigned long con; unsigned long flags; if (pin < S3C2410_GPIO_BANKB) { - shift = 0; - mask = 1; + mask = 1 << S3C2410_GPIO_OFFSET(pin); + } else { + mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; } - mask <<= S3C2410_GPIO_OFFSET(pin); - local_irq_save(flags); - con = __raw_readl(base + 0x00); - - con &= mask << shift; + con = __raw_readl(base + 0x00); + con &= ~mask; con |= function; __raw_writel(con, base + 0x00); @@ -60,6 +66,20 @@ local_irq_restore(flags); } +unsigned int s3c2410_gpio_getcfg(unsigned int pin) +{ + unsigned long base = S3C2410_GPIO_BASE(pin); + unsigned long mask; + + if (pin < S3C2410_GPIO_BANKB) { + mask = 1 << S3C2410_GPIO_OFFSET(pin); + } else { + mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; + } + + return __raw_readl(base) & mask; +} + void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) { unsigned long base = S3C2410_GPIO_BASE(pin); @@ -73,7 +93,7 @@ local_irq_save(flags); up = __raw_readl(base + 0x08); - up &= 1 << offs; + up &= ~(1L << offs); up |= to << offs; __raw_writel(up, base + 0x08); @@ -90,9 +110,85 @@ local_irq_save(flags); dat = __raw_readl(base + 0x04); - dat &= 1 << offs; + dat &= ~(1 << offs); dat |= to << offs; __raw_writel(dat, base + 0x04); local_irq_restore(flags); +} + +unsigned int s3c2410_gpio_getpin(unsigned int pin) +{ + unsigned long base = S3C2410_GPIO_BASE(pin); + unsigned long offs = S3C2410_GPIO_OFFSET(pin); + + return __raw_readl(base + 0x04) & (1<< offs); +} + +unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) +{ + unsigned long flags; + unsigned long misccr; + + local_irq_save(flags); + misccr = __raw_readl(S3C2410_MISCCR); + misccr &= ~clear; + misccr ^= change; + __raw_writel(misccr, S3C2410_MISCCR); + local_irq_restore(flags); + + return misccr; +} + +int s3c2410_gpio_getirq(unsigned int pin) +{ + if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23) + return -1; /* not valid interrupts */ + + if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) + return -1; /* not valid pin */ + + if (pin < S3C2410_GPF4) + return (pin - S3C2410_GPF0) + IRQ_EINT0; + + if (pin < S3C2410_GPG0) + return (pin - S3C2410_GPF4) + IRQ_EINT4; + + return (pin - S3C2410_GPG0) + IRQ_EINT8; +} + +int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, + unsigned int config) +{ + unsigned long reg = S3C2410_EINFLT0; + unsigned long flags; + unsigned long val; + + if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15) + return -1; + + config &= 0xff; + + pin -= S3C2410_GPG8_EINT16; + reg += pin & ~3; + + local_irq_save(flags); + + /* update filter width and clock source */ + + val = __raw_readl(reg); + val &= ~(0xff << ((pin & 3) * 8)); + val |= config << ((pin & 3) * 8); + __raw_writel(val, reg); + + /* update filter enable */ + + val = __raw_readl(S3C2410_EXTINT2); + val &= ~(1 << ((pin * 4) + 3)); + val |= on << ((pin * 4) + 3); + __raw_writel(val, S3C2410_EXTINT2); + + local_irq_restore(flags); + + return 0; } diff -Nru a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c --- a/arch/arm/mach-s3c2410/irq.c 2004-10-18 14:56:28 -07:00 +++ b/arch/arm/mach-s3c2410/irq.c 2004-10-18 14:56:28 -07:00 @@ -1,7 +1,7 @@ /* linux/arch/arm/mach-s3c2410/irq.c * - * Copyright (c) 2003 Simtec Electronics - * Ben Dooks + * Copyright (c) 2003,2004 Simtec Electronics + * Ben Dooks * * 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 @@ -17,7 +17,23 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - */ + * Changelog: + * + * 22-Jul-2004 Ben Dooks + * Fixed compile warnings + * + * 22-Jul-2004 Roc Wu + * Fixed s3c_extirq_type + * + * 21-Jul-2004 Arnaud Patard (Rtp) + * Addition of ADC/TC demux + * + * 04-Oct-2004 Klaus Fetscher + * Fix for set_irq_type() on low EINT numbers + * + * 05-Oct-2004 Ben Dooks + * Tidy up KF's patch and sort out new release +*/ #include @@ -34,11 +50,8 @@ #include #include -#include +#include -#if 0 -#include -#endif #define irqdbf(x...) #define irqdbf2(x...) @@ -177,12 +190,84 @@ s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); } -/* todo - put type handler in here */ - static int s3c_irqext_type(unsigned int irq, unsigned int type) { - irqdbf("s3c_irqext_type: called for irq %d, type %d\n", irq, type); + unsigned long extint_reg; + unsigned long gpcon_reg; + unsigned long gpcon_offset, extint_offset; + unsigned long newvalue = 0, value; + + if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) + { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C2410_EXTINT0; + gpcon_offset = (irq - IRQ_EINT0) * 2; + extint_offset = (irq - IRQ_EINT0) * 4; + } + else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) + { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C2410_EXTINT0; + gpcon_offset = (irq - (EXTINT_OFF)) * 2; + extint_offset = (irq - (EXTINT_OFF)) * 4; + } + else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) + { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C2410_EXTINT1; + gpcon_offset = (irq - IRQ_EINT8) * 2; + extint_offset = (irq - IRQ_EINT8) * 4; + } + else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) + { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C2410_EXTINT2; + gpcon_offset = (irq - IRQ_EINT8) * 2; + extint_offset = (irq - IRQ_EINT16) * 4; + } else + return -1; + + /* Set the GPIO to external interrupt mode */ + value = __raw_readl(gpcon_reg); + value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); + __raw_writel(value, gpcon_reg); + + /* Set the external interrupt to pointed trigger type */ + switch (type) + { + case IRQT_NOEDGE: + printk(KERN_WARNING "No edge setting!\n"); + break; + + case IRQT_RISING: + newvalue = S3C2410_EXTINT_RISEEDGE; + break; + + case IRQT_FALLING: + newvalue = S3C2410_EXTINT_FALLEDGE; + break; + + case IRQT_BOTHEDGE: + newvalue = S3C2410_EXTINT_BOTHEDGE; + break; + + case IRQT_LOW: + newvalue = S3C2410_EXTINT_LOWLEV; + break; + + case IRQT_HIGH: + newvalue = S3C2410_EXTINT_HILEV; + break; + + default: + printk(KERN_ERR "No such irq type %d", type); + return -1; + } + + value = __raw_readl(extint_reg); + value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); + __raw_writel(value, extint_reg); return 0; } @@ -194,6 +279,13 @@ .type = s3c_irqext_type }; +static struct irqchip s3c_irq_eint0t4 = { + .ack = s3c_irq_ack, + .mask = s3c_irq_mask, + .unmask = s3c_irq_unmask, + .type = s3c_irqext_type +}; + /* mask values for the parent registers for each of the interrupt types */ #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) @@ -368,37 +460,37 @@ .ack = s3c_irq_adc_ack, }; -#if 0 -/* LCD (todo) */ - -static void -s3c_irq_lcd_mask(unsigned int irqno) +/* irq demux for adc */ +static void s3c_irq_demux_adc(unsigned int irq, + struct irqdesc *desc, + struct pt_regs *regs) { + unsigned int subsrc, submsk; + unsigned int offset = 9; + struct irqdesc *mydesc; -} - -static void -s3c_irq_lcd_unmask(unsigned int irqno) -{ + /* read the current pending interrupts, and the mask + * for what it is available */ -} + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); -static void -s3c_irq_lcd_ack(unsigned int irqno) -{ + subsrc &= ~submsk; + subsrc >>= offset; + subsrc &= 3; + if (subsrc != 0) { + if (subsrc & 1) { + mydesc = irq_desc + IRQ_TC; + mydesc->handle( IRQ_TC, mydesc, regs); + } + if (subsrc & 2) { + mydesc = irq_desc + IRQ_ADC; + mydesc->handle(IRQ_ADC, mydesc, regs); + } + } } -static struct irqchip s3c_irq_lcd = { - .mask = s3c_irq_lcd_mask, - .unmask = s3c_irq_lcd_unmask, - .ack = s3c_irq_lcd_ack, -}; -#endif - -/* irq demux */ - - static void s3c_irq_demux_uart(unsigned int start, struct pt_regs *regs) { @@ -466,11 +558,15 @@ s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); } - +/* s3c2410_init_irq + * + * Initialise S3C2410 IRQ system +*/ void __init s3c2410_init_irq(void) { unsigned long pend; + unsigned long last; int irqno; int i; @@ -478,48 +574,51 @@ /* first, clear all interrupts pending... */ + last = 0; for (i = 0; i < 4; i++) { pend = __raw_readl(S3C2410_EINTPEND); - if (pend == 0) + + if (pend == 0 || pend == last) break; + __raw_writel(pend, S3C2410_EINTPEND); printk("irq: clearing pending ext status %08x\n", (int)pend); + last = pend; } + last = 0; for (i = 0; i < 4; i++) { pend = __raw_readl(S3C2410_INTPND); - if (pend == 0) + + if (pend == 0 || pend == last) break; + __raw_writel(pend, S3C2410_SRCPND); __raw_writel(pend, S3C2410_INTPND); printk("irq: clearing pending status %08x\n", (int)pend); + last = pend; } + last = 0; for (i = 0; i < 4; i++) { pend = __raw_readl(S3C2410_SUBSRCPND); - if (pend == 0) + if (pend == 0 || pend == last) break; printk("irq: clearing subpending status %08x\n", (int)pend); __raw_writel(pend, S3C2410_SUBSRCPND); + last = pend; } /* register the main interrupts */ irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); - for (irqno = IRQ_EINT0; irqno < IRQ_ADCPARENT; irqno++) { + for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { /* set all the s3c2410 internal irqs */ switch (irqno) { - - case IRQ_EINT4t7: - case IRQ_EINT8t23: - /* these are already dealt with, so should never - * appear */ - break; - /* deal with the special IRQs (cascaded) */ case IRQ_UART0: @@ -549,11 +648,17 @@ set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); - //set_irq_chained_handler(IRQ_LCD, s3c_irq_demux_); - //set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_); + set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); /* external interrupts */ + + for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { + irqdbf("registering irq %d (ext int)\n", irqno); + set_irq_chip(irqno, &s3c_irq_eint0t4); + set_irq_handler(irqno, do_edge_IRQ); + set_irq_flags(irqno, IRQF_VALID); + } for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { irqdbf("registering irq %d (extended s3c irq)\n", irqno); diff -Nru a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c --- a/arch/arm/mach-s3c2410/mach-bast.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mach-s3c2410/mach-bast.c 2004-10-18 14:56:32 -07:00 @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s3c2410/mach-bast.c * - * Copyright (c) 2003 Simtec Electronics + * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks * * http://www.simtec.co.uk/products/EB2410ITX/ @@ -10,6 +10,9 @@ * published by the Free Software Foundation. * * Modifications: + * 14-Sep-2004 BJD USB power control + * 20-Aug-2004 BJD Added s3c2410_board struct + * 18-Aug-2004 BJD Added platform devices from default set * 16-May-2003 BJD Created initial version * 16-Aug-2003 BJD Fixed header files and copyright, added URL * 05-Sep-2003 BJD Moved to v2.6 kernel @@ -23,6 +26,7 @@ #include #include #include +#include #include #include @@ -39,6 +43,9 @@ #include #include "s3c2410.h" +#include "devs.h" +#include "cpu.h" +#include "usb-simtec.h" /* macros for virtual address mods for the io space entries */ #define VA_C5(item) ((item) + BAST_VAM_CS5) @@ -154,6 +161,7 @@ [1] = { .hwport = 1, .flags = 0, + .clock = &bast_serial_clock, .ucon = UCON, .ulcon = ULCON, @@ -170,19 +178,51 @@ } }; +/* NOR Flash on BAST board */ + +static struct resource bast_nor_resource[] = { + [0] = { + .start = S3C2410_CS1 + 0x4000000, + .end = S3C2410_CS1 + 0x4000000 + (32*1024*1024) - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device bast_device_nor = { + .name = "bast-nor", + .id = -1, + .num_resources = ARRAY_SIZE(bast_nor_resource), + .resource = bast_nor_resource, +}; + +/* Standard BAST devices */ + +static struct platform_device *bast_devices[] __initdata = { + &s3c_device_usb, + &s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, + &s3c_device_rtc, + &bast_device_nor +}; + +static struct s3c2410_board bast_board __initdata = { + .devices = bast_devices, + .devices_count = ARRAY_SIZE(bast_devices) +}; void __init bast_map_io(void) { - s3c2410_map_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); - s3c2410_uartcfgs = bast_uartcfgs; + s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); + s3c2410_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs)); + s3c2410_set_board(&bast_board); + usb_simtec_init(); } void __init bast_init_irq(void) { - //llprintk("bast_init_irq:\n"); - s3c2410_init_irq(); - } void __init bast_init_time(void) diff -Nru a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c --- a/arch/arm/mach-s3c2410/mach-h1940.c 2004-10-18 14:56:49 -07:00 +++ b/arch/arm/mach-s3c2410/mach-h1940.c 2004-10-18 14:56:49 -07:00 @@ -1,6 +1,6 @@ -/* linux/arch/arm/mach-s3c2410/mach-ipaq.c +/* linux/arch/arm/mach-s3c2410/mach-h1940.c * - * Copyright (c) 2003 Simtec Electronics + * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks * * http://www.handhelds.org/projects/h1940.html @@ -16,6 +16,8 @@ * 06-Jan-2003 BJD Updates for * 18-Jan-2003 BJD Added serial port configuration * 17-Feb-2003 BJD Copied to mach-ipaq.c + * 21-Aug-2004 BJD Added struct s3c2410_board + * 04-Sep-2004 BJD Changed uart init, renamed ipaq_ -> h1940_ */ #include @@ -39,8 +41,10 @@ #include #include "s3c2410.h" +#include "devs.h" +#include "cpu.h" -static struct map_desc ipaq_iodesc[] __initdata = { +static struct map_desc h1940_iodesc[] __initdata = { /* nothing here yet */ }; @@ -48,7 +52,7 @@ #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB #define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE -static struct s3c2410_uartcfg ipaq_uartcfgs[] = { +static struct s3c2410_uartcfg h1940_uartcfgs[] = { [0] = { .hwport = 0, .flags = 0, @@ -77,21 +81,35 @@ }; -void __init ipaq_map_io(void) + + +static struct platform_device *h1940_devices[] __initdata = { + &s3c_device_usb, + &s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, +}; + +static struct s3c2410_board h1940_board __initdata = { + .devices = h1940_devices, + .devices_count = ARRAY_SIZE(h1940_devices) +}; + +void __init h1940_map_io(void) { - s3c2410_map_io(ipaq_iodesc, ARRAY_SIZE(ipaq_iodesc)); - s3c2410_uartcfgs = ipaq_uartcfgs; + s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc)); + s3c2410_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs)); + s3c2410_set_board(&h1940_board); } -void __init ipaq_init_irq(void) +void __init h1940_init_irq(void) { - //llprintk("ipaq_init_irq:\n"); - s3c2410_init_irq(); } -void __init ipaq_init_time(void) +void __init h1940_init_time(void) { s3c2410_init_time(); } @@ -100,7 +118,7 @@ MAINTAINER("Ben Dooks ") BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) - MAPIO(ipaq_map_io) - INITIRQ(ipaq_init_irq) - INITTIME(ipaq_init_time) + MAPIO(h1940_map_io) + INITIRQ(h1940_init_irq) + INITTIME(h1940_init_time) MACHINE_END diff -Nru a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c --- a/arch/arm/mach-s3c2410/mach-smdk2410.c 2004-10-18 14:56:31 -07:00 +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c 2004-10-18 14:56:31 -07:00 @@ -47,7 +47,8 @@ #include #include "s3c2410.h" - +#include "devs.h" +#include "cpu.h" static struct map_desc smdk2410_iodesc[] __initdata = { /* nothing here yet */ @@ -87,11 +88,24 @@ } }; +static struct platform_device *smdk2410_devices[] __initdata = { + &s3c_device_usb, + &s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, +}; + +static struct s3c2410_board smdk2410_board __initdata = { + .devices = smdk2410_devices, + .devices_count = ARRAY_SIZE(smdk2410_devices) +}; void __init smdk2410_map_io(void) { - s3c2410_map_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); - s3c2410_uartcfgs = smdk2410_uartcfgs; + s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); + s3c2410_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); + s3c2410_set_board(&smdk2410_board); } void __init smdk2410_init_irq(void) @@ -113,3 +127,5 @@ INITIRQ(smdk2410_init_irq) INITTIME(smdk2410_init_time) MACHINE_END + + diff -Nru a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c --- a/arch/arm/mach-s3c2410/mach-vr1000.c 2004-10-18 14:56:49 -07:00 +++ b/arch/arm/mach-s3c2410/mach-vr1000.c 2004-10-18 14:56:49 -07:00 @@ -11,13 +11,10 @@ * published by the Free Software Foundation. * * Modifications: + * 14-Sep-2004 BJD USB Power control + * 04-Sep-2004 BJD Added new uart init, and io init + * 21-Aug-2004 BJD Added struct s3c2410_board * 06-Aug-2004 BJD Fixed call to time initialisation - * 12-Jul-2004 BJD Renamed machine - * 16-May-2003 BJD Created initial version - * 16-Aug-2003 BJD Fixed header files and copyright, added URL - * 05-Sep-2003 BJD Moved to v2.6 kernel - * 06-Jan-2003 BJD Updates for - * 18-Jan-2003 BJD Added serial port configuration * 05-Apr-2004 BJD Copied to make mach-vr1000.c */ @@ -44,6 +41,9 @@ #include #include "s3c2410.h" +#include "devs.h" +#include "cpu.h" +#include "usb-simtec.h" /* macros for virtual address mods for the io space entries */ #define VA_C5(item) ((item) + BAST_VAM_CS5) @@ -143,19 +143,31 @@ } }; +static struct platform_device *vr1000_devices[] __initdata = { + &s3c_device_usb, + &s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, +}; + +static struct s3c2410_board vr1000_board __initdata = { + .devices = vr1000_devices, + .devices_count = ARRAY_SIZE(vr1000_devices) +}; + void __init vr1000_map_io(void) { - s3c2410_map_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc)); - s3c2410_uartcfgs = vr1000_uartcfgs; + s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc)); + s3c2410_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs)); + s3c2410_set_board(&vr1000_board); + usb_simtec_init(); } void __init vr1000_init_irq(void) { - //llprintk("vr1000init_irq:\n"); - s3c2410_init_irq(); - } void __init vr1000_init_time(void) diff -Nru a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c --- a/arch/arm/mach-s3c2410/s3c2410.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mach-s3c2410/s3c2410.c 2004-10-18 14:56:32 -07:00 @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s3c2410/s3c2410.c * - * Copyright (c) 2003 Simtec Electronics + * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks * * http://www.simtec.co.uk/products/EB2410ITX/ @@ -13,7 +13,8 @@ * 16-May-2003 BJD Created initial version * 16-Aug-2003 BJD Fixed header files and copyright, added URL * 05-Sep-2003 BJD Moved to kernel v2.6 - * 18-Jan-2003 BJD Added serial port configuration + * 18-Jan-2004 BJD Added serial port configuration + * 21-Aug-2004 BJD Added new struct s3c2410_board handler */ #include @@ -35,6 +36,9 @@ #include #include +#include "s3c2410.h" +#include "cpu.h" + int s3c2410_clock_tick_rate = 12*1000*1000; /* current timers at 12MHz */ /* serial port setup */ @@ -47,33 +51,14 @@ unsigned long s3c2410_hclk; unsigned long s3c2410_pclk; -#ifndef MHZ -#define MHZ (1000*1000) -#endif - -#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000) - -#define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE } - static struct map_desc s3c2410_iodesc[] __initdata = { - IODESC_ENT(IRQ), - IODESC_ENT(MEMCTRL), - IODESC_ENT(USBHOST), - IODESC_ENT(DMA), - IODESC_ENT(CLKPWR), - IODESC_ENT(LCD), - IODESC_ENT(NAND), - IODESC_ENT(UART), - IODESC_ENT(TIMER), - IODESC_ENT(USBDEV), - IODESC_ENT(WATCHDOG), - IODESC_ENT(IIC), - IODESC_ENT(IIS), - IODESC_ENT(GPIO), - IODESC_ENT(RTC), - IODESC_ENT(ADC), - IODESC_ENT(SPI), - IODESC_ENT(SDI) + IODESC_ENT(USBHOST), + IODESC_ENT(CLKPWR), + IODESC_ENT(LCD), + IODESC_ENT(UART), + IODESC_ENT(TIMER), + IODESC_ENT(ADC), + IODESC_ENT(WATCHDOG) }; static struct resource s3c_uart0_resource[] = { @@ -146,14 +131,16 @@ &s3c_uart2 }; -void __init s3c2410_map_io(struct map_desc *mach_desc, int size) +void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size) { unsigned long tmp; /* register our io-tables */ iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc)); - iotable_init(mach_desc, size); + iotable_init(mach_desc, mach_size); + + printk("machine_initted %p,%d\n", mach_desc, mach_size); /* now we've got our machine bits initialised, work out what * clocks we've got */ @@ -175,16 +162,41 @@ print_mhz(s3c2410_pclk)); } +static struct s3c2410_board *board; + +void s3c2410_set_board(struct s3c2410_board *b) +{ + board = b; +} -static int __init s3c2410_init(void) +void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + s3c2410_uartcfgs = cfg; +} + +int __init s3c2410_init(void) { int ret; printk("S3C2410: Initialising architecture\n"); ret = platform_add_devices(uart_devices, ARRAY_SIZE(uart_devices)); + if (ret) + return ret; + + if (board != NULL) { + if (board->devices != NULL) { + ret = platform_add_devices(board->devices, + board->devices_count); + + if (ret) { + printk(KERN_ERR "s3c2410: failed to add board devices (%d)\n", ret); + } + } + + /* not adding board devices may not be fatal */ + ret = 0; + } return ret; } - -arch_initcall(s3c2410_init); diff -Nru a/arch/arm/mach-s3c2410/s3c2410.h b/arch/arm/mach-s3c2410/s3c2410.h --- a/arch/arm/mach-s3c2410/s3c2410.h 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mach-s3c2410/s3c2410.h 2004-10-18 14:56:29 -07:00 @@ -1,4 +1,19 @@ - +/* arch/arm/mach-s3c2410/s3c2410.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2410 machine directory + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 18-Aug-2004 BJD Created initial version + * 20-Aug-2004 BJD Added s3c2410_board struct + * 04-Sep-2004 BJD Added s3c2410_init_uarts() call +*/ extern void s3c2410_map_io(struct map_desc *, int count); @@ -6,3 +21,18 @@ extern void s3c2410_init_time(void); +/* the board structure is used at first initialsation time + * to get info such as the devices to register for this + * board. This is done because platfrom_add_devices() cannot + * be called from the map_io entry. + * +*/ + +struct s3c2410_board { + struct platform_device **devices; + unsigned int devices_count; +}; + +extern void s3c2410_set_board(struct s3c2410_board *board); + +extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); diff -Nru a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2410/s3c2440-dsc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/s3c2440-dsc.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,57 @@ +/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Samsung S3C2440 Drive Strength Control support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 29-Aug-2004 BJD Start of drive-strength control +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "s3c2440.h" +#include "cpu.h" + +int s3c2440_set_dsc(unsigned int pin, unsigned int value) +{ + unsigned long base; + unsigned long val; + unsigned long flags; + unsigned long mask; + + base = (pin & S3C2440_SELECT_DSC1) ? S3C2440_DSC1 : S3C2440_DSC0; + mask = 3 << S3C2440_DSC_GETSHIFT(pin); + + local_irq_save(flags); + + val = __raw_readl(base); + val &= ~mask; + val |= value & mask; + __raw_writel(val, base); + + local_irq_restore(flags); + return 0; +} diff -Nru a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/s3c2440.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,192 @@ +/* linux/arch/arm/mach-s3c2410/s3c2440.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Samsung S3C2440 Mobile CPU support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 24-Aug-2004 BJD Start of s3c2440 support +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "s3c2440.h" +#include "cpu.h" + +int s3c2440_clock_tick_rate = 12*1000*1000; /* current timers at 12MHz */ + +/* clock info */ + +unsigned long s3c2440_baseclk = 12*1000*1000; /* assume base is 12MHz */ +unsigned long s3c2440_hdiv; + +unsigned long s3c2440_fclk; +unsigned long s3c2440_hclk; +unsigned long s3c2440_pclk; + +static struct map_desc s3c2440_iodesc[] __initdata = { + IODESC_ENT(USBHOST), + IODESC_ENT(CLKPWR), + IODESC_ENT(LCD), + IODESC_ENT(TIMER), + IODESC_ENT(ADC), +}; + +static struct resource s3c_uart0_resource[] = { + [0] = { + .start = S3C2410_PA_UART0, + .end = S3C2410_PA_UART0 + 0x3fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_S3CUART_RX0, + .end = IRQ_S3CUART_ERR0, + .flags = IORESOURCE_IRQ, + } + +}; + +static struct resource s3c_uart1_resource[] = { + [0] = { + .start = S3C2410_PA_UART1, + .end = S3C2410_PA_UART1 + 0x3fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_S3CUART_RX1, + .end = IRQ_S3CUART_ERR1, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource s3c_uart2_resource[] = { + [0] = { + .start = S3C2410_PA_UART2, + .end = S3C2410_PA_UART2 + 0x3fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_S3CUART_RX2, + .end = IRQ_S3CUART_ERR2, + .flags = IORESOURCE_IRQ, + } +}; + +/* our uart devices */ + +static struct platform_device s3c_uart0 = { + .name = "s3c2440-uart", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_uart0_resource), + .resource = s3c_uart0_resource, +}; + + +static struct platform_device s3c_uart1 = { + .name = "s3c2440-uart", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_uart1_resource), + .resource = s3c_uart1_resource, +}; + +static struct platform_device s3c_uart2 = { + .name = "s3c2440-uart", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_uart2_resource), + .resource = s3c_uart2_resource, +}; + +static struct platform_device *uart_devices[] __initdata = { + &s3c_uart0, + &s3c_uart1, + &s3c_uart2 +}; + +void __init s3c2440_map_io(struct map_desc *mach_desc, int size) +{ + unsigned long tmp; + unsigned long camdiv; + + /* register our io-tables */ + + iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc)); + iotable_init(mach_desc, size); + + /* now we've got our machine bits initialised, work out what + * clocks we've got */ + + s3c2440_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), + s3c2440_baseclk); + + tmp = __raw_readl(S3C2410_CLKDIVN); + camdiv = __raw_readl(S3C2440_CAMDIVN); + + /* work out clock scalings */ + + switch (tmp & S3C2440_CLKDIVN_HDIVN_MASK) { + case S3C2440_CLKDIVN_HDIVN_1: + s3c2440_hdiv = 1; + break; + + case S3C2440_CLKDIVN_HDIVN_2: + s3c2440_hdiv = 1; + break; + + case S3C2440_CLKDIVN_HDIVN_4_8: + s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4; + break; + + case S3C2440_CLKDIVN_HDIVN_3_6: + s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 6 : 3; + break; + } + + s3c2440_hclk = s3c2440_fclk / s3c2440_hdiv; + s3c2440_pclk = s3c2440_hclk / ((tmp & S3C2440_CLKDIVN_PDIVN) ? 2 : 1); + + /* print brieft summary of clocks, etc */ + + printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", + print_mhz(s3c2440_fclk), print_mhz(s3c2440_hclk), + print_mhz(s3c2440_pclk)); +} + + + +int __init s3c2440_init(void) +{ + int ret; + + printk("S3C2440: Initialising architecture\n"); + + ret = platform_add_devices(uart_devices, ARRAY_SIZE(uart_devices)); + if (ret) + return ret; + + // todo: board specific inits? + + return ret; +} + diff -Nru a/arch/arm/mach-s3c2410/s3c2440.h b/arch/arm/mach-s3c2410/s3c2440.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/s3c2440.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,18 @@ +/* arch/arm/mach-s3c2410/s3c2440.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2440 cpu support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 24-Aug-2004 BJD Start of S3C2440 CPU support +*/ + +extern void s3c2440_init_irq(void); + +extern void s3c2440_init_time(void); diff -Nru a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c --- a/arch/arm/mach-s3c2410/time.c 2004-10-18 14:56:28 -07:00 +++ b/arch/arm/mach-s3c2410/time.c 2004-10-18 14:56:28 -07:00 @@ -31,14 +31,12 @@ #include #include #include +#include #include static unsigned long timer_startval; static unsigned long timer_ticks_usec; -#ifdef CONFIG_S3C2410_RTC -extern void s3c2410_rtc_check(); -#endif /* with an 12MHz clock, we get 12 ticks per-usec */ @@ -49,14 +47,29 @@ * will have been disabled by do_gettimeoffset() * IRQs are disabled before entering here from do_gettimeofday() */ + +#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0)) + static unsigned long s3c2410_gettimeoffset (void) { unsigned long tdone; unsigned long usec; + unsigned long irqpend; /* work out how many ticks have gone since last timer interrupt */ tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); + + /* check to see if there is an interrupt pending */ + + irqpend = __raw_readl(S3C2410_SRCPND); + if (irqpend & SRCPND_TIMER4) { + /* re-read the timer, and try and fix up for the missed + * interrupt */ + + tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); + tdone += 1<<16; + } /* currently, tcnt is in 12MHz units, but this may change * for non-bast machines... diff -Nru a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/usb-simtec.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,123 @@ +/* linux/arch/arm/mach-s3c2410/usb-simtec.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * Simtec BAST and Thorcom VR1000 USB port support functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 14-Sep-2004 BJD Created +*/ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "devs.h" +#include "usb-simtec.h" + +/* control power and monitor over-current events on various Simtec + * designed boards. +*/ + +static void +usb_simtec_powercontrol(int port, int to) +{ + pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to); + + if (port == 1) { + s3c2410_gpio_setpin(S3C2410_GPB4, to ? 0:1); + pr_debug("GPBDAT now %08x\n", __raw_readl(S3C2410_GPBDAT)); + } +} + +static irqreturn_t +usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs) +{ + struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw; + + if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) { + pr_debug("usb_simtec: over-current irq (oc detected)\n"); + s3c2410_report_oc(info, 3); + } else { + pr_debug("usb_simtec: over-current irq (oc cleared)\n"); + } + + return IRQ_HANDLED; +} + +static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on) +{ + int ret; + + if (on) { + pr_debug("claiming usb overccurent\n"); + ret = request_irq(IRQ_USBOC, usb_simtec_ocirq, SA_INTERRUPT, + "usb-oc", info); + if (ret != 0) { + printk(KERN_ERR "failed to request usb oc irq\n"); + } + + set_irq_type(IRQ_USBOC, IRQT_BOTHEDGE); + } else { + free_irq(IRQ_USBOC, NULL); + } +} + +static struct s3c2410_hcd_info usb_simtec_info = { + .port[0] = { + .flags = S3C_HCDFLG_USED + }, + .port[1] = { + .flags = S3C_HCDFLG_USED + }, + + .power_control = usb_simtec_powercontrol, + .enable_oc = usb_simtec_enableoc, +}; + + +int usb_simtec_init(void) +{ + printk("USB Power Control, (c) 2004 Simtec Electronics\n"); + s3c_device_usb.dev.platform_data = &usb_simtec_info; + + s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP); + s3c2410_gpio_setpin(S3C2410_GPB4, 1); + + pr_debug("GPB: CON=%08x, DAT=%08x\n", + __raw_readl(S3C2410_GPBCON), __raw_readl(S3C2410_GPBDAT)); + + if (0) { + s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, + S3C2410_MISCCR_USBDEV); + } + + return 0; +} diff -Nru a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-s3c2410/usb-simtec.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,19 @@ +/* linux/arch/arm/mach-s3c2410/usb-simtec.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * Simtec BAST and Thorcom VR1000 USB port support functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 20-Aug-2004 BJD Created +*/ + +extern int usb_simtec_init(void); + diff -Nru a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c --- a/arch/arm/mach-sa1100/cpu-sa1100.c 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mach-sa1100/cpu-sa1100.c 2004-10-18 14:55:54 -07:00 @@ -230,9 +230,7 @@ } static struct cpufreq_driver sa1100_driver = { - .flags = CPUFREQ_STICKY | - CPUFREQ_PANIC_OUTOFSYNC | - CPUFREQ_PANIC_RESUME_OUTOFSYNC, + .flags = CPUFREQ_STICKY, .verify = sa11x0_verify_speed, .target = sa1100_target, .get = sa11x0_getspeed, diff -Nru a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c --- a/arch/arm/mach-sa1100/cpu-sa1110.c 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mach-sa1100/cpu-sa1110.c 2004-10-18 14:55:54 -07:00 @@ -329,9 +329,7 @@ } static struct cpufreq_driver sa1110_driver = { - .flags = CPUFREQ_STICKY | - CPUFREQ_PANIC_OUTOFSYNC | - CPUFREQ_PANIC_RESUME_OUTOFSYNC, + .flags = CPUFREQ_STICKY, .verify = sa11x0_verify_speed, .target = sa1110_target, .get = sa11x0_getspeed, diff -Nru a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c --- a/arch/arm/mach-sa1100/pm.c 2004-10-18 14:56:19 -07:00 +++ b/arch/arm/mach-sa1100/pm.c 2004-10-18 14:56:19 -07:00 @@ -30,6 +30,7 @@ #include #include #include +#include extern void sa1100_cpu_suspend(void); extern void sa1100_cpu_resume(void); @@ -44,7 +45,7 @@ */ enum { SLEEP_SAVE_SP = 0, - SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, + SLEEP_SAVE_OIER, SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR, @@ -58,18 +59,19 @@ static int sa11x0_pm_enter(u32 state) { - unsigned long sleep_save[SLEEP_SAVE_SIZE]; - unsigned long delta, gpio; + unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE]; + struct timespec delta, rtc; if (state != PM_SUSPEND_MEM) return -EINVAL; /* preserve current time */ - delta = xtime.tv_sec - RCNR; + rtc.tv_sec = RCNR; + rtc.tv_nsec = 0; + save_time_delta(&delta, &rtc); gpio = GPLR; /* save vital registers */ - SAVE(OSCR); SAVE(OSMR0); SAVE(OSMR1); SAVE(OSMR2); @@ -131,11 +133,14 @@ RESTORE(OSMR1); RESTORE(OSMR2); RESTORE(OSMR3); - RESTORE(OSCR); RESTORE(OIER); + /* OSMR0 is the system timer: make sure OSCR is sufficiently behind */ + OSCR = OSMR0 - LATCH; + /* restore current time */ - xtime.tv_sec = RCNR + delta; + rtc.tv_sec = RCNR; + restore_time_delta(&delta, &rtc); return 0; } diff -Nru a/arch/arm/mach-versatile/clock.c b/arch/arm/mach-versatile/clock.c --- a/arch/arm/mach-versatile/clock.c 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mach-versatile/clock.c 2004-10-18 14:55:54 -07:00 @@ -87,8 +87,8 @@ if (clk->setvco) { struct icst525_vco vco; - vco = icst525_khz_to_vco(clk->params, rate); - clk->rate = icst525_khz(clk->params, vco); + vco = icst525_khz_to_vco(clk->params, rate / 1000); + clk->rate = icst525_khz(clk->params, vco) * 1000; printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", clk->name, vco.s, vco.r, vco.v); diff -Nru a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c --- a/arch/arm/mach-versatile/core.c 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mach-versatile/core.c 2004-10-18 14:56:29 -07:00 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include @@ -325,6 +327,213 @@ }; #endif +/* + * CLCD support. + */ +#define SYS_CLCD_MODE_MASK (3 << 0) +#define SYS_CLCD_MODE_5551 (0 << 0) +#define SYS_CLCD_MODE_565 (1 << 0) +#define SYS_CLCD_MODE_888 (2 << 0) +#define SYS_CLCD_MODE_LT (3 << 0) +#define SYS_CLCD_NLCDIOON (1 << 2) +#define SYS_CLCD_VDDPOSSWITCH (1 << 3) +#define SYS_CLCD_PWR3V5SWITCH (1 << 4) +#define SYS_CLCD_ID_MASK (0x1f << 8) +#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) +#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8) +#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) +#define SYS_CLCD_ID_VGA (0x1f << 8) + +static struct clcd_panel vga = { + .mode = { + .name = "VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +static struct clcd_panel sanyo_3_8_in = { + .mode = { + .name = "Sanyo QVGA", + .refresh = 116, + .xres = 320, + .yres = 240, + .pixclock = 100000, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 5, + .lower_margin = 5, + .hsync_len = 6, + .vsync_len = 6, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +static struct clcd_panel epson_2_2_in = { + .mode = { + .name = "Epson QCIF", + .refresh = 390, + .xres = 176, + .yres = 220, + .pixclock = 62500, + .left_margin = 3, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 0, + .hsync_len = 3, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +/* + * Detect which LCD panel is connected, and return the appropriate + * clcd_panel structure. Note: we do not have any information on + * the required timings for the 8.4in panel, so we presently assume + * VGA timings. + */ +static struct clcd_panel *versatile_clcd_panel(void) +{ + unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; + struct clcd_panel *panel = &vga; + u32 val; + + val = readl(sys_clcd) & SYS_CLCD_ID_MASK; + if (val == SYS_CLCD_ID_SANYO_3_8) + panel = &sanyo_3_8_in; + else if (val == SYS_CLCD_ID_EPSON_2_2) + panel = &epson_2_2_in; + else if (val == SYS_CLCD_ID_VGA) + panel = &vga; + else { + printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", + val); + } + + return &vga; +} + +/* + * Disable all display connectors on the interface module. + */ +static void versatile_clcd_disable(struct clcd_fb *fb) +{ + unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; + u32 val; + + val = readl(sys_clcd); + val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; + writel(val, sys_clcd); +} + +/* + * Enable the relevant connector on the interface module. + */ +static void versatile_clcd_enable(struct clcd_fb *fb) +{ + unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; + u32 val; + + val = readl(sys_clcd); + val &= ~SYS_CLCD_MODE_MASK; + + switch (fb->fb.var.green.length) { + case 5: +#if 0 + /* + * For some undocumented reason, we need to select 565 mode + * even when using 555 with VGA. Maybe this is only true + * for the VGA output and needs to be done for LCD panels? + * I can't get an explaination from the people who should + * know. + */ + val |= SYS_CLCD_MODE_5551; + break; +#endif + case 6: + val |= SYS_CLCD_MODE_565; + break; + case 8: + val |= SYS_CLCD_MODE_888; + break; + } + + /* + * Set the MUX + */ + writel(val, sys_clcd); + + /* + * And now enable the PSUs + */ + val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; + writel(val, sys_clcd); +} + +static unsigned long framesize = SZ_1M; + +static int versatile_clcd_setup(struct clcd_fb *fb) +{ + dma_addr_t dma; + + fb->panel = versatile_clcd_panel(); + + fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, + &dma, GFP_KERNEL); + if (!fb->fb.screen_base) { + printk(KERN_ERR "CLCD: unable to map framebuffer\n"); + return -ENOMEM; + } + + fb->fb.fix.smem_start = dma; + fb->fb.fix.smem_len = framesize; + + return 0; +} + +static void versatile_clcd_remove(struct clcd_fb *fb) +{ + dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, + fb->fb.screen_base, fb->fb.fix.smem_start); +} + +static struct clcd_board clcd_plat_data = { + .name = "Versatile PB", + .check = clcdfb_check, + .decode = clcdfb_decode, + .disable = versatile_clcd_disable, + .enable = versatile_clcd_enable, + .setup = versatile_clcd_setup, + .remove = versatile_clcd_remove, +}; + #define AMBA_DEVICE(name,busid,base,plat) \ static struct amba_device name##_device = { \ .dev = { \ @@ -417,7 +626,7 @@ /* DevChip Primecells */ AMBA_DEVICE(smc, "dev:00", SMC, NULL); AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL); -AMBA_DEVICE(clcd, "dev:20", CLCD, NULL); +AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data); AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); diff -Nru a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig --- a/arch/arm/mm/Kconfig 2004-10-18 14:56:28 -07:00 +++ b/arch/arm/mm/Kconfig 2004-10-18 14:56:28 -07:00 @@ -43,7 +43,7 @@ # ARM720T config CPU_ARM720T bool "Support ARM720T processor" if !ARCH_CLPS711X && !ARCH_L7200 && !ARCH_CDB89712 && ARCH_INTEGRATOR - default y if ARCH_CLPS711X || ARCH_L7200 || ARCH_CDB89712 + default y if ARCH_CLPS711X || ARCH_L7200 || ARCH_CDB89712 || ARCH_H720X select CPU_32v4 select CPU_ABRT_LV4T select CPU_CACHE_V4 @@ -59,7 +59,7 @@ # ARM920T config CPU_ARM920T bool "Support ARM920T processor" if !ARCH_S3C2410 - depends on ARCH_INTEGRATOR || ARCH_S3C2410 + depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX default y if ARCH_S3C2410 select CPU_32v4 select CPU_ABRT_EV4T @@ -220,7 +220,7 @@ # XScale config CPU_XSCALE bool - depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX + depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000 default y select CPU_32v5 select CPU_ABRT_EV5T diff -Nru a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile --- a/arch/arm/mm/Makefile 2004-10-18 14:57:18 -07:00 +++ b/arch/arm/mm/Makefile 2004-10-18 14:57:18 -07:00 @@ -3,7 +3,8 @@ # obj-y := consistent.o extable.o fault-armv.o \ - fault.o init.o ioremap.o mmap.o mm-armv.o + fault.o flush.o init.o ioremap.o mmap.o \ + mm-armv.o obj-$(CONFIG_MODULES) += proc-syms.o diff -Nru a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S --- a/arch/arm/mm/abort-ev5tj.S 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mm/abort-ev5tj.S 2004-10-18 14:56:32 -07:00 @@ -23,7 +23,6 @@ mrc p15, 0, r0, c6, c0, 0 @ get FAR bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #PSR_J_BIT @ Java? - orrne r1, r1, #1 << 11 @ always assume write movne pc, lr tst r3, #PSR_T_BIT @ Thumb? ldrneh r3, [r2] @ read aborted thumb instruction diff -Nru a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S --- a/arch/arm/mm/cache-v3.S 2004-10-18 14:56:49 -07:00 +++ b/arch/arm/mm/cache-v3.S 2004-10-18 14:56:49 -07:00 @@ -57,6 +57,19 @@ * - end - virtual end address */ ENTRY(v3_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v3_coherent_user_range) mov pc, lr /* @@ -116,6 +129,7 @@ .long v3_flush_user_cache_all .long v3_flush_user_cache_range .long v3_coherent_kern_range + .long v3_coherent_user_range .long v3_flush_kern_dcache_page .long v3_dma_inv_range .long v3_dma_clean_range diff -Nru a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S --- a/arch/arm/mm/cache-v4.S 2004-10-18 14:56:28 -07:00 +++ b/arch/arm/mm/cache-v4.S 2004-10-18 14:56:28 -07:00 @@ -59,6 +59,19 @@ * - end - virtual end address */ ENTRY(v4_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v4_coherent_user_range) mov pc, lr /* @@ -118,6 +131,7 @@ .long v4_flush_user_cache_all .long v4_flush_user_cache_range .long v4_coherent_kern_range + .long v4_coherent_user_range .long v4_flush_kern_dcache_page .long v4_dma_inv_range .long v4_dma_clean_range diff -Nru a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S --- a/arch/arm/mm/cache-v4wb.S 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mm/cache-v4wb.S 2004-10-18 14:56:32 -07:00 @@ -121,6 +121,19 @@ * - end - virtual end address */ ENTRY(v4wb_coherent_kern_range) + /* fall through */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v4wb_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry @@ -195,6 +208,7 @@ .long v4wb_flush_user_cache_all .long v4wb_flush_user_cache_range .long v4wb_coherent_kern_range + .long v4wb_coherent_user_range .long v4wb_flush_kern_dcache_page .long v4wb_dma_inv_range .long v4wb_dma_clean_range diff -Nru a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S --- a/arch/arm/mm/cache-v4wt.S 2004-10-18 14:56:17 -07:00 +++ b/arch/arm/mm/cache-v4wt.S 2004-10-18 14:56:17 -07:00 @@ -97,6 +97,19 @@ * - end - virtual end address */ ENTRY(v4wt_coherent_kern_range) + /* FALLTRHOUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v4wt_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry add r0, r0, #CACHE_DLINESIZE @@ -167,6 +180,7 @@ .long v4wt_flush_user_cache_all .long v4wt_flush_user_cache_range .long v4wt_coherent_kern_range + .long v4wt_coherent_user_range .long v4wt_flush_kern_dcache_page .long v4wt_dma_inv_range .long v4wt_dma_clean_range diff -Nru a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S --- a/arch/arm/mm/cache-v6.S 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mm/cache-v6.S 2004-10-18 14:55:54 -07:00 @@ -75,6 +75,22 @@ * - the Icache does not read data from the write buffer */ ENTRY(v6_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * v6_coherent_user_range(start,end) + * + * Ensure that the I and D caches are coherent within specified + * region. This is typically used when code has been written to + * a memory region, and will be executed. + * + * - start - virtual start address of region + * - end - virtual end address of region + * + * It is assumed that: + * - the Icache does not read data from the write buffer + */ +ENTRY(v6_coherent_user_range) bic r0, r0, #CACHE_LINE_SIZE - 1 1: #ifdef HARVARD_CACHE @@ -203,6 +219,7 @@ .long v6_flush_user_cache_all .long v6_flush_user_cache_range .long v6_coherent_kern_range + .long v6_coherent_user_range .long v6_flush_kern_dcache_page .long v6_dma_inv_range .long v6_dma_clean_range diff -Nru a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c --- a/arch/arm/mm/consistent.c 2004-10-18 14:56:49 -07:00 +++ b/arch/arm/mm/consistent.c 2004-10-18 14:56:49 -07:00 @@ -138,7 +138,7 @@ struct page *page; struct vm_region *c; unsigned long order; - u64 mask = 0x00ffffff, limit; /* ISA default */ + u64 mask = ISA_DMA_THRESHOLD, limit; if (!consistent_pte) { printk(KERN_ERR "%s: not initialised\n", __func__); @@ -148,19 +148,34 @@ if (dev) { mask = dev->coherent_dma_mask; + + /* + * Sanity check the DMA mask - it must be non-zero, and + * must be able to be satisfied by a DMA allocation. + */ if (mask == 0) { dev_warn(dev, "coherent DMA mask is unset\n"); - return NULL; + goto no_page; + } + + if ((~mask) & ISA_DMA_THRESHOLD) { + dev_warn(dev, "coherent DMA mask %#llx is smaller " + "than system GFP_DMA mask %#llx\n", + mask, (unsigned long long)ISA_DMA_THRESHOLD); + goto no_page; } } + /* + * Sanity check the allocation size. + */ size = PAGE_ALIGN(size); limit = (mask + 1) & ~mask; - if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) { - printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n", - size, mask); - *handle = ~0; - return NULL; + if ((limit && size >= limit) || + size >= (CONSISTENT_END - CONSISTENT_BASE)) { + printk(KERN_WARNING "coherent allocation too big " + "(requested %#x mask %#llx)\n", size, mask); + goto no_page; } order = get_order(size); @@ -221,6 +236,7 @@ if (page) __free_pages(page, order); no_page: + *handle = ~0; return NULL; } diff -Nru a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c --- a/arch/arm/mm/copypage-v6.c 2004-10-18 14:56:28 -07:00 +++ b/arch/arm/mm/copypage-v6.c 2004-10-18 14:56:28 -07:00 @@ -32,13 +32,45 @@ #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) /* + * Copy the user page. No aliasing to deal with so we can just + * attack the kernel's existing mapping of these pages. + */ +void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr) +{ + copy_page(kto, kfrom); +} + +/* + * Clear the user page. No aliasing to deal with so we can just + * attack the kernel's existing mapping of this page. + */ +void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr) +{ + clear_page(kaddr); +} + +/* * Copy the page, taking account of the cache colour. */ -void v6_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) +void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr) { unsigned int offset = DCACHE_COLOUR(vaddr); unsigned long from, to; + /* + * Discard data in the kernel mapping for the new page. + * FIXME: needs this MCRR to be supported. + */ + __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" + : + : "r" (kto), + "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES) + : "cc"); + + /* + * Now copy the page using the same cache colour as the + * pages ultimate destination. + */ spin_lock(&v6_lock); set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot)); @@ -55,11 +87,30 @@ spin_unlock(&v6_lock); } -void v6_clear_user_page(void *kaddr, unsigned long vaddr) +/* + * Clear the user page. We need to deal with the aliasing issues, + * so remap the kernel page into the same cache colour as the user + * page. + */ +void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) { unsigned int offset = DCACHE_COLOUR(vaddr); unsigned long to = to_address + (offset << PAGE_SHIFT); + /* + * Discard data in the kernel mapping for the new page + * FIXME: needs this MCRR to be supported. + */ + __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" + : + : "r" (kaddr), + "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES) + : "cc"); + + /* + * Now clear the page using the same cache colour as + * the pages ultimate destination. + */ spin_lock(&v6_lock); set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot)); @@ -70,26 +121,31 @@ } struct cpu_user_fns v6_user_fns __initdata = { - .cpu_clear_user_page = v6_clear_user_page, - .cpu_copy_user_page = v6_copy_user_page, + .cpu_clear_user_page = v6_clear_user_page_nonaliasing, + .cpu_copy_user_page = v6_copy_user_page_nonaliasing, }; static int __init v6_userpage_init(void) { - pgd_t *pgd; - pmd_t *pmd; - - pgd = pgd_offset_k(from_address); - pmd = pmd_alloc(&init_mm, pgd, from_address); - if (!pmd) - BUG(); - from_pte = pte_alloc_kernel(&init_mm, pmd, from_address); - if (!from_pte) - BUG(); - - to_pte = pte_alloc_kernel(&init_mm, pmd, to_address); - if (!to_pte) - BUG(); + if (cache_is_vipt_aliasing()) { + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset_k(from_address); + pmd = pmd_alloc(&init_mm, pgd, from_address); + if (!pmd) + BUG(); + from_pte = pte_alloc_kernel(&init_mm, pmd, from_address); + if (!from_pte) + BUG(); + + to_pte = pte_alloc_kernel(&init_mm, pmd, to_address); + if (!to_pte) + BUG(); + + cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; + cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; + } return 0; } diff -Nru a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c --- a/arch/arm/mm/fault-armv.c 2004-10-18 14:56:19 -07:00 +++ b/arch/arm/mm/fault-armv.c 2004-10-18 14:56:19 -07:00 @@ -76,59 +76,12 @@ return 0; } -static void __flush_dcache_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - struct mm_struct *mm = current->active_mm; - struct vm_area_struct *mpnt = NULL; - struct prio_tree_iter iter; - unsigned long offset; - pgoff_t pgoff; - - __cpuc_flush_dcache_page(page_address(page)); - - if (!mapping) - return; - - /* - * With a VIVT cache, we need to also write back - * and invalidate any user data. - */ - pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); - - flush_dcache_mmap_lock(mapping); - while ((mpnt = vma_prio_tree_next(mpnt, &mapping->i_mmap, - &iter, pgoff, pgoff)) != NULL) { - /* - * If this VMA is not in our MM, we can ignore it. - */ - if (mpnt->vm_mm != mm) - continue; - if (!(mpnt->vm_flags & VM_MAYSHARE)) - continue; - offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; - flush_cache_page(mpnt, mpnt->vm_start + offset); - } - flush_dcache_mmap_unlock(mapping); -} - -void flush_dcache_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - - if (mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); - else - __flush_dcache_page(page); -} -EXPORT_SYMBOL(flush_dcache_page); - static void make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty) { struct address_space *mapping = page_mapping(page); struct mm_struct *mm = vma->vm_mm; - struct vm_area_struct *mpnt = NULL; + struct vm_area_struct *mpnt; struct prio_tree_iter iter; unsigned long offset; pgoff_t pgoff; @@ -145,8 +98,7 @@ * cache coherency. */ flush_dcache_mmap_lock(mapping); - while ((mpnt = vma_prio_tree_next(mpnt, &mapping->i_mmap, - &iter, pgoff, pgoff)) != NULL) { + vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { /* * If this VMA is not in our MM, we can ignore it. * Note that we intentionally mask out the VMA @@ -190,10 +142,21 @@ if (page_mapping(page)) { int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); - if (dirty) + if (dirty) { + /* + * This is our first userspace mapping of this page. + * Ensure that the physical page is coherent with + * the kernel mapping. + * + * FIXME: only need to do this on VIVT and aliasing + * VIPT cache architectures. We can do that + * by choosing whether to set this bit... + */ __cpuc_flush_dcache_page(page_address(page)); + } - make_coherent(vma, addr, page, dirty); + if (cache_is_vivt()) + make_coherent(vma, addr, page, dirty); } } diff -Nru a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mm/flush.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,94 @@ +/* + * linux/arch/arm/mm/flush.c + * + * Copyright (C) 1995-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include + +static void __flush_dcache_page(struct address_space *mapping, struct page *page) +{ + struct mm_struct *mm = current->active_mm; + struct vm_area_struct *mpnt; + struct prio_tree_iter iter; + pgoff_t pgoff; + + /* + * Writeback any data associated with the kernel mapping of this + * page. This ensures that data in the physical page is mutually + * coherent with the kernels mapping. + */ + __cpuc_flush_dcache_page(page_address(page)); + + /* + * If there's no mapping pointer here, then this page isn't + * visible to userspace yet, so there are no cache lines + * associated with any other aliases. + */ + if (!mapping) + return; + + /* + * There are possible user space mappings of this page: + * - VIVT cache: we need to also write back and invalidate all user + * data in the current VM view associated with this page. + * - aliasing VIPT: we only need to find one mapping of this page. + */ + pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); + + flush_dcache_mmap_lock(mapping); + vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { + unsigned long offset; + + /* + * If this VMA is not in our MM, we can ignore it. + */ + if (mpnt->vm_mm != mm) + continue; + if (!(mpnt->vm_flags & VM_MAYSHARE)) + continue; + offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; + flush_cache_page(mpnt, mpnt->vm_start + offset); + if (cache_is_vipt()) + break; + } + flush_dcache_mmap_unlock(mapping); +} + +/* + * Ensure cache coherency between kernel mapping and userspace mapping + * of this page. + * + * We have three cases to consider: + * - VIPT non-aliasing cache: fully coherent so nothing required. + * - VIVT: fully aliasing, so we need to handle every alias in our + * current VM view. + * - VIPT aliasing: need to handle one alias in our current VM view. + * + * If we need to handle aliasing: + * If the page only exists in the page cache and there are no user + * space mappings, we can be lazy and remember that we may have dirty + * kernel cache lines for later. Otherwise, we assume we have + * aliasing mappings. + */ +void flush_dcache_page(struct page *page) +{ + struct address_space *mapping = page_mapping(page); + + if (cache_is_vipt_nonaliasing()) + return; + + if (mapping && !mapping_mapped(mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else + __flush_dcache_page(mapping, page); +} +EXPORT_SYMBOL(flush_dcache_page); diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c --- a/arch/arm/mm/init.c 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mm/init.c 2004-10-18 14:55:54 -07:00 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -344,7 +345,7 @@ * Initialise the bootmem allocator for all nodes. This is called * early during the architecture specific initialisation. */ -void __init bootmem_init(struct meminfo *mi) +static void __init bootmem_init(struct meminfo *mi) { struct node_info node_info[MAX_NUMNODES], *np = node_info; unsigned int bootmap_pages, bootmap_pfn, map_pg; @@ -412,9 +413,7 @@ } #endif - if (map_pg != bootmap_pfn + bootmap_pages) - BUG(); - + BUG_ON(map_pg != bootmap_pfn + bootmap_pages); } /* @@ -426,6 +425,8 @@ void *zero_page; int node; + bootmem_init(mi); + memcpy(&meminfo, mi, sizeof(meminfo)); /* @@ -495,7 +496,7 @@ */ arch_adjust_zones(node, zone_size, zhole_size); - free_area_init_node(node, pgdat, NULL, zone_size, + free_area_init_node(node, pgdat, zone_size, bdata->node_boot_start >> PAGE_SHIFT, zhole_size); } @@ -590,7 +591,7 @@ * anywhere without overcommit, so turn * it on by default. */ - sysctl_overcommit_memory = 1; + sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; } } diff -Nru a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S --- a/arch/arm/mm/proc-arm1020.S 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mm/proc-arm1020.S 2004-10-18 14:55:54 -07:00 @@ -196,6 +196,19 @@ * - end - virtual end address */ ENTRY(arm1020_coherent_kern_range) + /* FALLTRHOUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1020_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 mcr p15, 0, ip, c7, c10, 4 @@ -317,6 +330,7 @@ .long arm1020_flush_user_cache_all .long arm1020_flush_user_cache_range .long arm1020_coherent_kern_range + .long arm1020_coherent_user_range .long arm1020_flush_kern_dcache_page .long arm1020_dma_inv_range .long arm1020_dma_clean_range diff -Nru a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S --- a/arch/arm/mm/proc-arm1020e.S 2004-10-18 14:56:33 -07:00 +++ b/arch/arm/mm/proc-arm1020e.S 2004-10-18 14:56:33 -07:00 @@ -193,6 +193,18 @@ * - end - virtual end address */ ENTRY(arm1020e_coherent_kern_range) + /* FALLTHROUGH */ +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1020e_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 1: @@ -304,6 +316,7 @@ .long arm1020e_flush_user_cache_all .long arm1020e_flush_user_cache_range .long arm1020e_coherent_kern_range + .long arm1020e_coherent_user_range .long arm1020e_flush_kern_dcache_page .long arm1020e_dma_inv_range .long arm1020e_dma_clean_range @@ -495,7 +508,7 @@ b __arm1020e_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB + .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP .long cpu_arm1020e_name .long arm1020e_processor_functions .long v4wbi_tlb_fns diff -Nru a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S --- a/arch/arm/mm/proc-arm1022.S 2004-10-18 14:57:04 -07:00 +++ b/arch/arm/mm/proc-arm1022.S 2004-10-18 14:57:04 -07:00 @@ -180,6 +180,19 @@ * - end - virtual end address */ ENTRY(arm1022_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1022_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 1: @@ -291,6 +304,7 @@ .long arm1022_flush_user_cache_all .long arm1022_flush_user_cache_range .long arm1022_coherent_kern_range + .long arm1022_coherent_user_range .long arm1022_flush_kern_dcache_page .long arm1022_dma_inv_range .long arm1022_dma_clean_range @@ -475,7 +489,7 @@ b __arm1022_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB + .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP .long cpu_arm1022_name .long arm1022_processor_functions .long v4wbi_tlb_fns diff -Nru a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S --- a/arch/arm/mm/proc-arm1026.S 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mm/proc-arm1026.S 2004-10-18 14:56:29 -07:00 @@ -175,6 +175,18 @@ * - end - virtual end address */ ENTRY(arm1026_coherent_kern_range) + /* FALLTHROUGH */ +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1026_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 1: @@ -286,6 +298,7 @@ .long arm1026_flush_user_cache_all .long arm1026_flush_user_cache_range .long arm1026_coherent_kern_range + .long arm1026_coherent_user_range .long arm1026_flush_kern_dcache_page .long arm1026_dma_inv_range .long arm1026_dma_clean_range @@ -471,7 +484,7 @@ b __arm1026_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA .long cpu_arm1026_name .long arm1026_processor_functions .long v4wbi_tlb_fns diff -Nru a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S --- a/arch/arm/mm/proc-arm920.S 2004-10-18 14:55:54 -07:00 +++ b/arch/arm/mm/proc-arm920.S 2004-10-18 14:55:54 -07:00 @@ -182,6 +182,19 @@ * - end - virtual end address */ ENTRY(arm920_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm920_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -277,6 +290,7 @@ .long arm920_flush_user_cache_all .long arm920_flush_user_cache_range .long arm920_coherent_kern_range + .long arm920_coherent_user_range .long arm920_flush_kern_dcache_page .long arm920_dma_inv_range .long arm920_dma_clean_range diff -Nru a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S --- a/arch/arm/mm/proc-arm922.S 2004-10-18 14:57:03 -07:00 +++ b/arch/arm/mm/proc-arm922.S 2004-10-18 14:57:03 -07:00 @@ -184,6 +184,19 @@ * - end - virtual end address */ ENTRY(arm922_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm922_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -279,6 +292,7 @@ .long arm922_flush_user_cache_all .long arm922_flush_user_cache_range .long arm922_coherent_kern_range + .long arm922_coherent_user_range .long arm922_flush_kern_dcache_page .long arm922_dma_inv_range .long arm922_dma_clean_range diff -Nru a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S --- a/arch/arm/mm/proc-arm925.S 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mm/proc-arm925.S 2004-10-18 14:56:29 -07:00 @@ -225,6 +225,19 @@ * - end - virtual end address */ ENTRY(arm925_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm925_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -329,6 +342,7 @@ .long arm925_flush_user_cache_all .long arm925_flush_user_cache_range .long arm925_coherent_kern_range + .long arm925_coherent_user_range .long arm925_flush_kern_dcache_page .long arm925_dma_inv_range .long arm925_dma_clean_range diff -Nru a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S --- a/arch/arm/mm/proc-arm926.S 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/mm/proc-arm926.S 2004-10-18 14:56:32 -07:00 @@ -185,6 +185,19 @@ * - end - virtual end address */ ENTRY(arm926_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm926_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -289,6 +302,7 @@ .long arm926_flush_user_cache_all .long arm926_flush_user_cache_range .long arm926_coherent_kern_range + .long arm926_coherent_user_range .long arm926_flush_kern_dcache_page .long arm926_dma_inv_range .long arm926_dma_clean_range @@ -473,7 +487,7 @@ b __arm926_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | HWCAP_JAVA + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA .long cpu_arm926_name .long arm926_processor_functions .long v4wbi_tlb_fns diff -Nru a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c --- a/arch/arm/mm/proc-syms.c 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/mm/proc-syms.c 2004-10-18 14:56:29 -07:00 @@ -22,10 +22,10 @@ #endif #ifndef MULTI_CACHE -EXPORT_SYMBOL_NOVERS(__cpuc_flush_kern_all); -EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_all); -EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_range); -EXPORT_SYMBOL_NOVERS(__cpuc_coherent_kern_range); +EXPORT_SYMBOL(__cpuc_flush_kern_all); +EXPORT_SYMBOL(__cpuc_flush_user_all); +EXPORT_SYMBOL(__cpuc_flush_user_range); +EXPORT_SYMBOL(__cpuc_coherent_kern_range); #else EXPORT_SYMBOL(cpu_cache); #endif diff -Nru a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S --- a/arch/arm/mm/proc-v6.S 2004-10-18 14:55:53 -07:00 +++ b/arch/arm/mm/proc-v6.S 2004-10-18 14:55:53 -07:00 @@ -189,12 +189,10 @@ * - cache type register is implemented */ __v6_setup: - mrc p15, 0, r10, c0, c0, 1 @ read cache type register - tst r10, #1 << 24 @ Harvard cache? mov r10, #0 - mcrne p15, 0, r10, c7, c14, 0 @ clean+invalidate D cache - mcrne p15, 0, r10, c7, c5, 0 @ invalidate I cache - mcreq p15, 0, r10, c7, c15, 0 @ clean+invalidate cache + mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D cache + mcr p15, 0, r10, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r10, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, r10, c7, c10, 4 @ drain write buffer mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r10, c2, c0, 2 @ TTB control register @@ -258,7 +256,7 @@ b __v6_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_FAST_MULT | HWCAP_VFP + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA .long cpu_v6_name .long v6_processor_functions .long v6wbi_tlb_fns diff -Nru a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S --- a/arch/arm/mm/proc-xscale.S 2004-10-18 14:56:50 -07:00 +++ b/arch/arm/mm/proc-xscale.S 2004-10-18 14:56:50 -07:00 @@ -241,6 +241,22 @@ * it also trashes the mini I-cache used by JTAG debuggers. */ ENTRY(xscale_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + * + * Note: single I-cache line invalidation isn't used here since + * it also trashes the mini I-cache used by JTAG debuggers. + */ +ENTRY(xscale_coherent_user_range) bic r0, r0, #CACHELINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHELINESIZE @@ -341,6 +357,7 @@ .long xscale_flush_user_cache_all .long xscale_flush_user_cache_range .long xscale_coherent_kern_range + .long xscale_coherent_user_range .long xscale_flush_kern_dcache_page .long xscale_dma_inv_range .long xscale_dma_clean_range @@ -585,7 +602,12 @@ mcr p15, 0, r4, c2, c0, 0 @ load page table pointer mov r0, #0x1f @ Domains 0, 1 = client mcr p15, 0, r0, c3, c0, 0 @ load domain access register - mov r0, #1 @ Allow access to CP0 and CP13 +#ifdef CONFIG_IWMMXT + mov r0, #0 @ initially disallow access to CP0/CP1 +#else + mov r0, #1 @ Allow access to CP0 +#endif + orr r0, r0, #1 << 6 @ cp6 for IOP3xx and Bulverde orr r0, r0, #1 << 13 @ Its undefined whether this mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes mrc p15, 0, r0, c1, c0, 0 @ get control register @@ -632,10 +654,15 @@ .asciz "XScale-80200" .size cpu_80200_name, . - cpu_80200_name - .type cpu_80321_name, #object -cpu_80321_name: - .asciz "XScale-IOP80321" - .size cpu_80321_name, . - cpu_80321_name + .type cpu_8032x_name, #object +cpu_8032x_name: + .asciz "XScale-IOP8032x Family" + .size cpu_8032x_name, . - cpu_8032x_name + + .type cpu_8033x_name, #object +cpu_8033x_name: + .asciz "XScale-IOP8033x Family" + .size cpu_8033x_name, . - cpu_8033x_name .type cpu_pxa250_name, #object cpu_pxa250_name: @@ -652,6 +679,16 @@ .asciz "XScale-IXP42x Family" .size cpu_ixp42x_name, . - cpu_ixp42x_name + .type cpu_ixp2400_name, #object +cpu_ixp2400_name: + .asciz "XScale-IXP2400" + .size cpu_ixp2400_name, . - cpu_ixp2400_name + + .type cpu_ixp2800_name, #object +cpu_ixp2800_name: + .asciz "XScale-IXP2800" + .size cpu_ixp2800_name, . - cpu_ixp2800_name + .type cpu_pxa255_name, #object cpu_pxa255_name: .asciz "XScale-PXA255" @@ -682,21 +719,37 @@ .long xscale_cache_fns .size __80200_proc_info, . - __80200_proc_info - .type __80321_proc_info,#object -__80321_proc_info: + .type __8032x_proc_info,#object +__8032x_proc_info: .long 0x69052420 - .long 0xfffff7e0 + .long 0xfffff5e0 @ mask should accomodate IOP80219 also + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_8032x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __8032x_proc_info, . - __8032x_proc_info + + .type __8033x_proc_info,#object +__8033x_proc_info: + .long 0x69054090 + .long 0xffffffb0 .long 0x00000c0e b __xscale_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP - .long cpu_80321_name + .long cpu_8033x_name .long xscale_processor_functions .long v4wbi_tlb_fns .long xscale_mc_user_fns .long xscale_cache_fns - .size __80321_proc_info, . - __80321_proc_info + .size __8033x_proc_info, . - __8033x_proc_info .type __pxa250_proc_info,#object __pxa250_proc_info: @@ -729,6 +782,38 @@ .long xscale_mc_user_fns .long xscale_cache_fns .size __pxa210_proc_info, . - __pxa210_proc_info + + .type __ixp2400_proc_info, #object +__ixp2400_proc_info: + .long 0x69054190 + .long 0xfffffff0 + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2400_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp2400_proc_info, . - __ixp2400_proc_info + + .type __ixp2800_proc_info, #object +__ixp2800_proc_info: + .long 0x690541a0 + .long 0xfffffff0 + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2800_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp2800_proc_info, . - __ixp2800_proc_info .type __ixp42x_proc_info, #object __ixp42x_proc_info: diff -Nru a/arch/arm/nwfpe/fpa11_cpdt.c b/arch/arm/nwfpe/fpa11_cpdt.c --- a/arch/arm/nwfpe/fpa11_cpdt.c 2004-10-18 14:57:04 -07:00 +++ b/arch/arm/nwfpe/fpa11_cpdt.c 2004-10-18 14:57:04 -07:00 @@ -42,8 +42,13 @@ unsigned int *p; p = (unsigned int *) &fpa11->fpreg[Fn].fDouble; fpa11->fType[Fn] = typeDouble; +#ifdef __ARMEB__ + get_user(p[0], &pMem[0]); /* sign & exponent */ + get_user(p[1], &pMem[1]); +#else get_user(p[0], &pMem[1]); get_user(p[1], &pMem[0]); /* sign & exponent */ +#endif } #ifdef CONFIG_FPE_NWFPE_XP @@ -140,8 +145,13 @@ val.f = fpa11->fpreg[Fn].fDouble; } +#ifdef __ARMEB__ + put_user(val.i[0], &pMem[0]); /* msw */ + put_user(val.i[1], &pMem[1]); /* lsw */ +#else put_user(val.i[1], &pMem[0]); /* msw */ put_user(val.i[0], &pMem[1]); /* lsw */ +#endif } #ifdef CONFIG_FPE_NWFPE_XP diff -Nru a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c --- a/arch/arm/oprofile/op_model_xscale.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm/oprofile/op_model_xscale.c 2004-10-18 14:56:32 -07:00 @@ -7,7 +7,7 @@ * @remark Copyright 2004 Dave Jiang * @remark Copyright 2004 Intel Corporation * @remark Copyright 2004 Zwane Mwaikambo - * @remark Copyright 2004 Oprofile Authors + * @remark Copyright 2004 OProfile Authors * * @remark Read the file COPYING * @@ -30,6 +30,7 @@ #define PMN_RESET 0x002 /* Reset event counters */ #define CCNT_RESET 0x004 /* Reset clock counter */ #define PMU_RESET (CCNT_RESET | PMN_RESET) +#define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */ /* TODO do runtime detection */ #ifdef CONFIG_ARCH_IOP310 @@ -125,12 +126,15 @@ static void write_pmnc(u32 val) { - /* upper 4bits and 7, 11 are write-as-0 */ - val &= 0xffff77f; - if (pmu->id == PMU_XSC1) + if (pmu->id == PMU_XSC1) { + /* upper 4bits and 7, 11 are write-as-0 */ + val &= 0xffff77f; __asm__ __volatile__ ("mcr p14, 0, %0, c0, c0, 0" : : "r" (val)); - else + } else { + /* bits 4-23 are write-as-0, 24-31 are write ignored */ + val &= 0xf; __asm__ __volatile__ ("mcr p14, 0, %0, c0, c1, 0" : : "r" (val)); + } } static u32 read_pmnc(void) @@ -139,8 +143,11 @@ if (pmu->id == PMU_XSC1) __asm__ __volatile__ ("mrc p14, 0, %0, c0, c0, 0" : "=r" (val)); - else + else { __asm__ __volatile__ ("mrc p14, 0, %0, c0, c1, 0" : "=r" (val)); + /* bits 1-2 and 4-23 are read-unpredictable */ + val &= 0xff000009; + } return val; } @@ -249,7 +256,7 @@ int i; for (i = CCNT; i < MAX_COUNTERS; i++) { - if (counter_config[i].event) + if (counter_config[i].enabled) continue; counter_config[i].event = EVT_UNUSED; @@ -336,7 +343,7 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) { - unsigned long eip = instruction_pointer(regs); + unsigned long pc = profile_pc(regs); int i, is_kernel = !user_mode(regs); u32 pmnc; @@ -350,7 +357,7 @@ continue; write_counter(i, -(u32)results[i].reset_counter); - oprofile_add_sample(eip, is_kernel, i, smp_processor_id()); + oprofile_add_sample(pc, is_kernel, i, smp_processor_id()); results[i].ovf--; } @@ -386,8 +393,10 @@ if (pmu->id == PMU_XSC1) pmnc |= pmu->int_enable; - else + else { __asm__ __volatile__ ("mcr p14, 0, %0, c4, c1, 0" : : "r" (pmu->int_enable)); + pmnc &= ~PMU_CNT64; + } pmnc |= PMU_ENABLE; write_pmnc(pmnc); diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types --- a/arch/arm/tools/mach-types 2004-10-18 14:56:29 -07:00 +++ b/arch/arm/tools/mach-types 2004-10-18 14:56:29 -07:00 @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Fri Jul 2 11:58:36 2004 +# Last update: Thu Sep 30 15:23:21 2004 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -519,7 +519,7 @@ omap_h3 MACH_OMAP_H3 OMAP_H3 509 omap_h4 MACH_OMAP_H4 OMAP_H4 510 n10 MACH_N10 N10 511 -montajade MACH_MONTAJADE MONTAJADE 512 +montejade MACH_MONTAJADE MONTAJADE 512 sg560 MACH_SG560 SG560 513 dp1000 MACH_DP1000 DP1000 514 omap_osk MACH_OMAP_OSK OMAP_OSK 515 @@ -559,3 +559,59 @@ switchgrass MACH_SWITCHGRASS SWITCHGRASS 549 ens_cmu MACH_ENS_CMU ENS_CMU 550 mm6_sdb MACH_MM6_SDB MM6_SDB 551 +saturn MACH_SATURN SATURN 552 +argonplusevb MACH_ARGONPLUSEVB ARGONPLUSEVB 553 +scma11evb MACH_SCMA11EVB SCMA11EVB 554 +smdk2800 MACH_SMDK2800 SMDK2800 555 +mtwilson MACH_MTWILSON MTWILSON 556 +ziti MACH_ZITI ZITI 557 +grandfather MACH_GRANDFATHER GRANDFATHER 558 +tengine MACH_TENGINE TENGINE 559 +s3c2460 MACH_S3C2460 S3C2460 560 +pdm MACH_PDM PDM 561 +h4700 MACH_H4700 H4700 562 +h6300 MACH_H6300 H6300 563 +rz1700 MACH_RZ1700 RZ1700 564 +a716 MACH_A716 A716 565 +estk2440a MACH_ESTK2440A ESTK2440A 566 +atwixp425 MACH_ATWIXP425 ATWIXP425 567 +csb336 MACH_CSB336 CSB336 568 +rirm2 MACH_RIRM2 RIRM2 569 +cx23518 MACH_CX23518 CX23518 570 +cx2351x MACH_CX2351X CX2351X 571 +computime MACH_COMPUTIME COMPUTIME 572 +izarus MACH_IZARUS IZARUS 573 +pxa_rts MACH_RTS RTS 574 +se5100 MACH_SE5100 SE5100 575 +s3c2510 MACH_S3C2510 S3C2510 576 +csb437tl MACH_CSB437TL CSB437TL 577 +slauson MACH_SLAUSON SLAUSON 578 +pearlriver MACH_PEARLRIVER PEARLRIVER 579 +tdc_p210 MACH_TDC_P210 TDC_P210 580 +sg580 MACH_SG580 SG580 581 +wrsbcarm7 MACH_WRSBCARM7 WRSBCARM7 582 +ipd MACH_IPD IPD 583 +pxa_dnp2110 MACH_PXA_DNP2110 PXA_DNP2110 584 +xaeniax MACH_XAENIAX XAENIAX 585 +somn4250 MACH_SOMN4250 SOMN4250 586 +pleb2 MACH_PLEB2 PLEB2 587 +cwl MACH_CWL CWL 588 +gd MACH_GD GD 589 +chaffee MACH_CHAFFEE CHAFFEE 590 +rms101 MACH_RMS101 RMS101 591 +rx3715 MACH_RX3715 RX3715 592 +swift MACH_SWIFT SWIFT 593 +roverp7 MACH_ROVERP7 ROVERP7 594 +pr818s MACH_PR818S PR818S 595 +trxpro MACH_TRXPRO TRXPRO 596 +nslu2 MACH_NSLU2 NSLU2 597 +e400 MACH_E400 E400 598 +trab MACH_TRAB TRAB 599 +cmc_pu2 MACH_CMC_PU2 CMC_PU2 600 +fulcrum MACH_FULCRUM FULCRUM 601 +netgate42x MACH_NETGATE42X NETGATE42X 602 +str710 MACH_STR710 STR710 603 +ixdpg425 MACH_IXDPG425 IXDPG425 604 +tomtomgo MACH_TOMTOMGO TOMTOMGO 605 +versatile_ab MACH_VERSATILE_AB VERSATILE_AB 606 +edb9307 MACH_EDB9307 EDB9307 607 diff -Nru a/arch/arm26/Kconfig b/arch/arm26/Kconfig --- a/arch/arm26/Kconfig 2004-10-18 14:56:33 -07:00 +++ b/arch/arm26/Kconfig 2004-10-18 14:56:33 -07:00 @@ -62,7 +62,7 @@ bool "Archimedes" help Say Y to support the Acorn Archimedes. - + The Acorn Archimedes was an personal computer based on an 8MHz ARM2 processor, released in 1987. It supported up to 16MB of RAM in later models and floppy, harddisc, ethernet etc. @@ -71,7 +71,7 @@ bool "A5000" help Say Y here to to support the Acorn A5000. - + Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. Note that on some A5000s the floppy is @@ -214,118 +214,7 @@ source "drivers/usb/Kconfig" -menu "Kernel hacking" - -# RMK wants arm kernels compiled with frame pointers so hardwire this to y. -# If you know what you are doing and are willing to live without stack -# traces, you can get a slightly smaller kernel by setting this option to -# n, but then RMK will have to kill you ;). -config FRAME_POINTER - bool - default y - help - If you say N here, the resulting kernel will be slightly smaller and - faster. However, when a problem occurs with the kernel, the - information that is reported is severely limited. Most people - should say Y here. - -config DEBUG_USER - bool "Verbose user fault messages" - help - When a user program crashes due to an exception, the kernel can - print a brief message explaining what the problem was. This is - sometimes helpful for debugging but serves no purpose on a - production system. Most people should say N here. - -config DEBUG_INFO - bool "Include GDB debugging information in kernel binary" - help - Say Y here to include source-level debugging information in the - `vmlinux' binary image. This is handy if you want to use gdb or - addr2line to debug the kernel. It has no impact on the in-memory - footprint of the running kernel but it can increase the amount of - time and disk space needed for compilation of the kernel. If in - doubt say N. - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_WAITQ - bool "Wait queue debugging" - depends on DEBUG_KERNEL - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" - depends on DEBUG_KERNEL - help - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -config DEBUG_ERRORS - bool "Verbose kernel error messages" - depends on DEBUG_KERNEL - help - This option controls verbose debugging information which can be - printed when the kernel detects an internal error. This debugging - information is useful to kernel hackers when tracking down problems, - but mostly meaningless to other people. It's safe to say Y unless - you are concerned with the code size or don't want to see these - messages. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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. - -# These options are only for real kernel hackers who want to get their hands dirty. -config DEBUG_LL - bool "Kernel low-level debugging functions" - depends on DEBUG_KERNEL - help - Say Y here to include definitions of printascii, printchar, printhex - in the kernel. This is helpful if you are debugging code that - executes before the console is initialized. - -endmenu +source "arch/arm26/Kconfig.debug" source "security/Kconfig" diff -Nru a/arch/arm26/Kconfig.debug b/arch/arm26/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm26/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,60 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +# RMK wants arm kernels compiled with frame pointers so hardwire this to y. +# If you know what you are doing and are willing to live without stack +# traces, you can get a slightly smaller kernel by setting this option to +# n, but then RMK will have to kill you ;). +config FRAME_POINTER + bool + default y + help + If you say N here, the resulting kernel will be slightly smaller and + faster. However, when a problem occurs with the kernel, the + information that is reported is severely limited. Most people + should say Y here. + +config DEBUG_USER + bool "Verbose user fault messages" + help + When a user program crashes due to an exception, the kernel can + print a brief message explaining what the problem was. This is + sometimes helpful for debugging but serves no purpose on a + production system. Most people should say N here. + +config DEBUG_WAITQ + bool "Wait queue debugging" + depends on DEBUG_KERNEL + +config DEBUG_ERRORS + bool "Verbose kernel error messages" + depends on DEBUG_KERNEL + help + This option controls verbose debugging information which can be + printed when the kernel detects an internal error. This debugging + information is useful to kernel hackers when tracking down problems, + but mostly meaningless to other people. It's safe to say Y unless + you are concerned with the code size or don't want to see these + messages. + +config DEBUG_INFO + bool "Include GDB debugging information in kernel binary" + help + Say Y here to include source-level debugging information in the + `vmlinux' binary image. This is handy if you want to use gdb or + addr2line to debug the kernel. It has no impact on the in-memory + footprint of the running kernel but it can increase the amount of + time and disk space needed for compilation of the kernel. If in + doubt say N. + +# These options are only for real kernel hackers who want to get their hands dirty. +config DEBUG_LL + bool "Kernel low-level debugging functions" + depends on DEBUG_KERNEL + help + Say Y here to include definitions of printascii, printchar, printhex + in the kernel. This is helpful if you are debugging code that + executes before the console is initialized. + +endmenu diff -Nru a/arch/arm26/Makefile b/arch/arm26/Makefile --- a/arch/arm26/Makefile 2004-10-18 14:56:29 -07:00 +++ b/arch/arm26/Makefile 2004-10-18 14:56:29 -07:00 @@ -8,8 +8,7 @@ # Copyright (C) 1995-2001 by Russell King LDFLAGS_vmlinux :=-p -X -LDFLAGS_BLOB :=--format binary -AFLAGS_vmlinux.lds.o = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) +CPPFLAGS_vmlinux.lds = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) OBJCOPYFLAGS :=-O binary -R .note -R .comment -S GZFLAGS :=-9 @@ -28,7 +27,6 @@ AFLAGS +=-mapcs-26 -mcpu=arm3 -mno-fpu -msoft-float -Wa,-mno-fpu head-y := arch/arm26/machine/head.o arch/arm26/kernel/init_task.o -LDFLAGS_BLOB += --oformat elf32-littlearm ifeq ($(CONFIG_XIP_KERNEL),y) TEXTADDR := 0x03880000 diff -Nru a/arch/arm26/boot/Makefile b/arch/arm26/boot/Makefile --- a/arch/arm26/boot/Makefile 2004-10-18 14:57:05 -07:00 +++ b/arch/arm26/boot/Makefile 2004-10-18 14:57:05 -07:00 @@ -67,12 +67,12 @@ install: $(obj)/Image $(CONFIG_SHELL) $(obj)/install.sh \ - $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) \ + $(KERNELRELEASE) \ $(obj)/Image System.map "$(INSTALL_PATH)" zinstall: $(obj)/zImage $(CONFIG_SHELL) $(obj)/install.sh \ - $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) \ + $(KERNELRELEASE) \ $(obj)/zImage System.map "$(INSTALL_PATH)" subdir- := compressed diff -Nru a/arch/arm26/kernel/Makefile b/arch/arm26/kernel/Makefile --- a/arch/arm26/kernel/Makefile 2004-10-18 14:56:29 -07:00 +++ b/arch/arm26/kernel/Makefile 2004-10-18 14:56:29 -07:00 @@ -14,5 +14,5 @@ obj-$(CONFIG_FIQ) += fiq.o obj-$(CONFIG_MODULES) += armksyms.o -extra-y := init_task.o vmlinux.lds.s +extra-y := init_task.o vmlinux.lds diff -Nru a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c --- a/arch/arm26/kernel/armksyms.c 2004-10-18 14:56:28 -07:00 +++ b/arch/arm26/kernel/armksyms.c 2004-10-18 14:56:28 -07:00 @@ -95,7 +95,7 @@ EXPORT_SYMBOL(kd_mksound); #endif -EXPORT_SYMBOL_NOVERS(__do_softirq); +EXPORT_SYMBOL(__do_softirq); /* platform dependent support */ EXPORT_SYMBOL(dump_thread); @@ -125,71 +125,71 @@ /* io */ #ifndef __raw_readsb -EXPORT_SYMBOL_NOVERS(__raw_readsb); +EXPORT_SYMBOL(__raw_readsb); #endif #ifndef __raw_readsw -EXPORT_SYMBOL_NOVERS(__raw_readsw); +EXPORT_SYMBOL(__raw_readsw); #endif #ifndef __raw_readsl -EXPORT_SYMBOL_NOVERS(__raw_readsl); +EXPORT_SYMBOL(__raw_readsl); #endif #ifndef __raw_writesb -EXPORT_SYMBOL_NOVERS(__raw_writesb); +EXPORT_SYMBOL(__raw_writesb); #endif #ifndef __raw_writesw -EXPORT_SYMBOL_NOVERS(__raw_writesw); +EXPORT_SYMBOL(__raw_writesw); #endif #ifndef __raw_writesl -EXPORT_SYMBOL_NOVERS(__raw_writesl); +EXPORT_SYMBOL(__raw_writesl); #endif /* string / mem functions */ -EXPORT_SYMBOL_NOVERS(strcpy); -EXPORT_SYMBOL_NOVERS(strncpy); -EXPORT_SYMBOL_NOVERS(strcat); -EXPORT_SYMBOL_NOVERS(strncat); -EXPORT_SYMBOL_NOVERS(strcmp); -EXPORT_SYMBOL_NOVERS(strncmp); -EXPORT_SYMBOL_NOVERS(strchr); -EXPORT_SYMBOL_NOVERS(strlen); -EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(__memzero); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(__memzero); /* user mem (segment) */ EXPORT_SYMBOL(uaccess_kernel); EXPORT_SYMBOL(uaccess_user); -EXPORT_SYMBOL_NOVERS(__get_user_1); -EXPORT_SYMBOL_NOVERS(__get_user_2); -EXPORT_SYMBOL_NOVERS(__get_user_4); -EXPORT_SYMBOL_NOVERS(__get_user_8); - -EXPORT_SYMBOL_NOVERS(__put_user_1); -EXPORT_SYMBOL_NOVERS(__put_user_2); -EXPORT_SYMBOL_NOVERS(__put_user_4); -EXPORT_SYMBOL_NOVERS(__put_user_8); +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); +EXPORT_SYMBOL(__get_user_8); + +EXPORT_SYMBOL(__put_user_1); +EXPORT_SYMBOL(__put_user_2); +EXPORT_SYMBOL(__put_user_4); +EXPORT_SYMBOL(__put_user_8); /* gcc lib functions */ -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__divsi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(__modsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__ucmpdi2); -EXPORT_SYMBOL_NOVERS(__udivdi3); -EXPORT_SYMBOL_NOVERS(__umoddi3); -EXPORT_SYMBOL_NOVERS(__udivmoddi4); -EXPORT_SYMBOL_NOVERS(__udivsi3); -EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__udivdi3); +EXPORT_SYMBOL(__umoddi3); +EXPORT_SYMBOL(__udivmoddi4); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umodsi3); /* bitops */ EXPORT_SYMBOL(_set_bit_le); @@ -214,10 +214,10 @@ EXPORT_SYMBOL(sys_wait4); /* semaphores */ -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); -EXPORT_SYMBOL_NOVERS(__down_trylock_failed); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_interruptible_failed); +EXPORT_SYMBOL(__down_trylock_failed); +EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(get_wchan); diff -Nru a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c --- a/arch/arm26/kernel/irq.c 2004-10-18 14:57:03 -07:00 +++ b/arch/arm26/kernel/irq.c 2004-10-18 14:57:03 -07:00 @@ -187,6 +187,7 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) { unsigned int status; + int ret; spin_unlock(&irq_controller_lock); if (!(action->flags & SA_INTERRUPT)) @@ -194,8 +195,9 @@ status = 0; do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); diff -Nru a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c --- a/arch/arm26/kernel/ptrace.c 2004-10-18 14:56:32 -07:00 +++ b/arch/arm26/kernel/ptrace.c 2004-10-18 14:56:32 -07:00 @@ -729,11 +729,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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c --- a/arch/arm26/kernel/signal.c 2004-10-18 14:56:27 -07:00 +++ b/arch/arm26/kernel/signal.c 2004-10-18 14:56:27 -07:00 @@ -465,9 +465,7 @@ return; } - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, tsk); + force_sigsegv(sig, tsk); } /* diff -Nru a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c --- a/arch/arm26/kernel/sys_arm.c 2004-10-18 14:56:33 -07:00 +++ b/arch/arm26/kernel/sys_arm.c 2004-10-18 14:56:33 -07:00 @@ -256,7 +256,7 @@ if (!newsp) newsp = regs->ARM_sp; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL); + return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); } asmlinkage int sys_vfork(struct pt_regs *regs) diff -Nru a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c --- a/arch/arm26/kernel/time.c 2004-10-18 14:56:48 -07:00 +++ b/arch/arm26/kernel/time.c 2004-10-18 14:56:48 -07:00 @@ -67,28 +67,6 @@ */ unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; -/* - * Handle kernel profile stuff... - */ -static inline void do_profile(struct pt_regs *regs) -{ - if (!user_mode(regs) && - prof_buffer && - current->pid) { - unsigned long pc = instruction_pointer(regs); - extern int _stext; - - pc -= (unsigned long)&_stext; - - pc >>= prof_shift; - - if (pc >= prof_len) - pc = prof_len - 1; - - prof_buffer[pc] += 1; - } -} - static unsigned long next_rtc_update; /* @@ -189,7 +167,7 @@ { do_timer(regs); do_set_rtc(); //FIME - EVERY timer IRQ? - do_profile(regs); + profile_tick(CPU_PROFILING, regs); return IRQ_HANDLED; //FIXME - is this right? } diff -Nru a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in --- a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in 2004-10-18 14:56:50 -07:00 +++ b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in 2004-10-18 14:56:50 -07:00 @@ -34,9 +34,6 @@ __early_begin = .; *(__early_param) __early_end = .; - __start___param = .; - *(__param) - __stop___param = .; __initcall_start = .; *(.initcall1.init) *(.initcall2.init) diff -Nru a/arch/arm26/kernel/vmlinux-arm26.lds.in b/arch/arm26/kernel/vmlinux-arm26.lds.in --- a/arch/arm26/kernel/vmlinux-arm26.lds.in 2004-10-18 14:55:55 -07:00 +++ b/arch/arm26/kernel/vmlinux-arm26.lds.in 2004-10-18 14:55:55 -07:00 @@ -35,9 +35,6 @@ __early_begin = .; *(__early_param) __early_end = .; - __start___param = .; - *(__param) - __stop___param = .; __initcall_start = .; *(.initcall1.init) *(.initcall2.init) diff -Nru a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c --- a/arch/arm26/mm/init.c 2004-10-18 14:57:04 -07:00 +++ b/arch/arm26/mm/init.c 2004-10-18 14:57:04 -07:00 @@ -305,8 +305,8 @@ (bdata->node_boot_start >> PAGE_SHIFT); if (!zone_size[0]) BUG(); - - free_area_init_node(0, pgdat, 0, zone_size, + pgdat->node_mem_map = NULL; + free_area_init_node(0, pgdat, zone_size, bdata->node_boot_start >> PAGE_SHIFT, zhole_size); mem_map = NODE_DATA(0)->node_mem_map; @@ -376,7 +376,7 @@ * Turn on overcommit on tiny machines */ if (PAGE_SIZE >= 16384 && num_physpages <= 128) { - sysctl_overcommit_memory = 1; + sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; printk("Turning on overcommit\n"); } } diff -Nru a/arch/cris/Kconfig b/arch/cris/Kconfig --- a/arch/cris/Kconfig 2004-10-18 14:57:03 -07:00 +++ b/arch/cris/Kconfig 2004-10-18 14:57:03 -07:00 @@ -20,8 +20,11 @@ config RWSEM_XCHGADD_ALGORITHM bool -source "init/Kconfig" +config CRIS + bool + default y +source "init/Kconfig" menu "General setup" @@ -51,7 +54,7 @@ bool "Enable ETRAX fast timer API" help This options enables the API to a fast timer implementation using - timer1 to get sub jiffie resolution timers (primarily one-shot + timer1 to get sub jiffie resolution timers (primarily one-shot timers). This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled. @@ -69,7 +72,6 @@ endmenu - menu "Hardware setup" choice @@ -96,7 +98,7 @@ config ETRAX_ARCH_V10 bool default y if ETRAX100LX || ETRAX100LX_V2 - default n if !(ETRAX100LX || ETRAX100LX_V2) + default n if !(ETRAX100LX || ETRAX100LX_V2) config ETRAX_DRAM_SIZE int "DRAM size (dec, in MB)" @@ -165,54 +167,10 @@ source "drivers/usb/Kconfig" - -menu "Kernel hacking" - -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -config PROFILE - bool "Kernel profiling support" - -config PROFILE_SHIFT - int "Profile shift count" - depends on PROFILE - default "2" - -config ETRAX_KGDB - bool "Use kernel GDB debugger" - ---help--- - The CRIS version of gdb can be used to remotely debug a running - Linux kernel via the serial debug port. Provided you have gdb-cris - installed, run gdb-cris vmlinux, then type - - (gdb) set remotebaud 115200 <- kgdb uses 115200 as default - (gdb) target remote /dev/ttyS0 <- maybe you use another port - - This should connect you to your booted kernel (or boot it now if you - didn't before). The kernel halts when it boots, waiting for gdb if - this option is turned on! - - -config DEBUG_INFO - bool "Compile the kernel with debug info" - help - If you say Y here the resulting kernel image will include - 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 FRAME_POINTER - bool "Compile the kernel with frame pointers" - 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. - -endmenu +source "arch/cris/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/cris/Kconfig.debug b/arch/cris/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/cris/Kconfig.debug 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,28 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +config PROFILE + bool "Kernel profiling support" + +config PROFILE_SHIFT + int "Profile shift count" + depends on PROFILE + default "2" + +config ETRAX_KGDB + bool "Use kernel GDB debugger" + ---help--- + The CRIS version of gdb can be used to remotely debug a running + Linux kernel via the serial debug port. Provided you have gdb-cris + installed, run gdb-cris vmlinux, then type + + (gdb) set remotebaud 115200 <- kgdb uses 115200 as default + (gdb) target remote /dev/ttyS0 <- maybe you use another port + + This should connect you to your booted kernel (or boot it now if you + didn't before). The kernel halts when it boots, waiting for gdb if + this option is turned on! + +endmenu diff -Nru a/arch/cris/Makefile b/arch/cris/Makefile --- a/arch/cris/Makefile 2004-10-18 14:56:29 -07:00 +++ b/arch/cris/Makefile 2004-10-18 14:56:29 -07:00 @@ -24,12 +24,10 @@ endif LD = $(CROSS_COMPILE)ld -mcrislinux -LDFLAGS_BLOB := --format binary --oformat elf32-cris \ - -T arch/cris/$(SARCH)/output_arch.ld OBJCOPYFLAGS := -O binary -R .note -R .comment -S -AFLAGS_vmlinux.lds.o = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) +CPPFLAGS_vmlinux.lds = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) AFLAGS += -mlinux CFLAGS := $(CFLAGS) -mlinux -march=$(arch-y) -pipe @@ -39,7 +37,7 @@ CFLAGS += -fno-omit-frame-pointer endif -HEAD := arch/$(ARCH)/$(SARCH)/kernel/head.o +head-y := arch/$(ARCH)/$(SARCH)/kernel/head.o LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) diff -Nru a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c --- a/arch/cris/arch-v10/kernel/debugport.c 2004-10-18 14:55:54 -07:00 +++ b/arch/cris/arch-v10/kernel/debugport.c 2004-10-18 14:55:54 -07:00 @@ -259,7 +259,7 @@ void __init init_etrax_debug(void) { -#if CONFIG_ETRAX_DEBUG_PORT_NULL +#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL return; #endif diff -Nru a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c --- a/arch/cris/arch-v10/kernel/process.c 2004-10-18 14:56:33 -07:00 +++ b/arch/cris/arch-v10/kernel/process.c 2004-10-18 14:56:33 -07:00 @@ -180,7 +180,7 @@ { if (!newusp) newusp = rdusp(); - return do_fork(flags & ~CLONE_IDLETASK, newusp, regs, 0, parent_tid, child_tid); + return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); } /* vfork is a system call in i386 because of register-pressure - maybe diff -Nru a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c --- a/arch/cris/arch-v10/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 +++ b/arch/cris/arch-v10/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 @@ -85,17 +85,8 @@ goto out_tsk; } - ret = -ESRCH; - - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - - if (child->parent != current) + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; switch (request) { diff -Nru a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c --- a/arch/cris/arch-v10/kernel/signal.c 2004-10-18 14:55:54 -07:00 +++ b/arch/cris/arch-v10/kernel/signal.c 2004-10-18 14:55:54 -07:00 @@ -409,9 +409,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -475,9 +473,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* diff -Nru a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c --- a/arch/cris/arch-v10/mm/init.c 2004-10-18 14:56:17 -07:00 +++ b/arch/cris/arch-v10/mm/init.c 2004-10-18 14:56:17 -07:00 @@ -183,7 +183,7 @@ * mem_map page array. */ - free_area_init_node(0, &contig_page_data, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); + free_area_init_node(0, &contig_page_data, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); mem_map = contig_page_data.node_mem_map; } diff -Nru a/arch/cris/arch-v10/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S --- a/arch/cris/arch-v10/vmlinux.lds.S 2004-10-18 14:56:29 -07:00 +++ b/arch/cris/arch-v10/vmlinux.lds.S 2004-10-18 14:56:29 -07:00 @@ -64,9 +64,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; .initcall.init : { __initcall_start = .; *(.initcall1.init); diff -Nru a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile --- a/arch/cris/kernel/Makefile 2004-10-18 14:56:33 -07:00 +++ b/arch/cris/kernel/Makefile 2004-10-18 14:56:33 -07:00 @@ -3,7 +3,7 @@ # Makefile for the linux kernel. # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds obj-y := process.o traps.o irq.o ptrace.o setup.o \ time.o sys_cris.o semaphore.o diff -Nru a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c --- a/arch/cris/kernel/crisksyms.c 2004-10-18 14:56:49 -07:00 +++ b/arch/cris/kernel/crisksyms.c 2004-10-18 14:56:49 -07:00 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -91,8 +90,8 @@ #undef memset extern void * memset(void *, int, __kernel_size_t); extern void * memcpy(void *, const void *, __kernel_size_t); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); #ifdef CONFIG_ETRAX_FAST_TIMER /* Fast timer functions */ diff -Nru a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c --- a/arch/cris/kernel/irq.c 2004-10-18 14:57:04 -07:00 +++ b/arch/cris/kernel/irq.c 2004-10-18 14:57:04 -07:00 @@ -125,7 +125,7 @@ { struct irqaction *action; int do_random, cpu; - int retval = 0; + int ret, retval = 0; cpu = smp_processor_id(); irq_enter(); @@ -137,8 +137,10 @@ local_irq_enable(); do_random = 0; do { - do_random |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + do_random |= action->flags; + retval |= ret; action = action->next; } while (action); diff -Nru a/arch/h8300/Kconfig b/arch/h8300/Kconfig --- a/arch/h8300/Kconfig 2004-10-18 14:56:49 -07:00 +++ b/arch/h8300/Kconfig 2004-10-18 14:56:49 -07:00 @@ -176,86 +176,15 @@ source "drivers/i2c/Kconfig" source "drivers/usb/Kconfig" - + endmenu source "fs/Kconfig" -menu "Kernel hacking" - -config FULLDEBUG - bool "Full Symbolic/Source Debugging support" - help - Enable debugging symbols on kernel build. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - help - Enables console device to interprent special characters as - commands to dump state information. - -config HIGHPROFILE - bool "Use fast second timer for profiling" - help - Use a fast secondary clock to produce profiling information. - -config NO_KERNEL_MSG - bool "Suppress Kernel BUG Messages" - help - Do not output any debug BUG messages within the kernel. - -config GDB_MAGICPRINT - bool "Message Output for GDB MagicPrint service" - depends on (H8300H_SIM || H8S_SIM) - help - kernel messages output useing MagicPrint service from GDB - -config SYSCALL_PRINT - bool "SystemCall trace print" - help - outout history of systemcall - -config GDB_DEBUG - bool "Use gdb stub" - depends on (!H8300H_SIM && !H8S_SIM) - help - gdb stub exception support - -config CONFIG_SH_STANDARD_BIOS - bool "Use gdb protocol serial console" - depends on (!H8300H_SIM && !H8S_SIM) - help - serial console output using GDB protocol. - Require eCos/RedBoot - -config DEFAULT_CMDLINE - bool "Use buildin commandline" - default n - help - buildin kernel commandline enabled. - -config KERNEL_COMMAND - string "Buildin commmand string" - depends on DEFAULT_CMDLINE - help - buildin kernel commandline strings. - -config BLKDEV_RESERVE - bool "BLKDEV Reserved Memory" - default n - help - Reserved BLKDEV area. - -config CONFIG_BLKDEV_RESERVE_ADDRESS - hex 'start address' - depends on BLKDEV_RESERVE - help - BLKDEV start address. -endmenu +source "arch/h8300/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/h8300/Kconfig.debug b/arch/h8300/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/h8300/Kconfig.debug 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,68 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debugging symbols on kernel build. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + help + Use a fast secondary clock to produce profiling information. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config GDB_MAGICPRINT + bool "Message Output for GDB MagicPrint service" + depends on (H8300H_SIM || H8S_SIM) + help + kernel messages output useing MagicPrint service from GDB + +config SYSCALL_PRINT + bool "SystemCall trace print" + help + outout history of systemcall + +config GDB_DEBUG + bool "Use gdb stub" + depends on (!H8300H_SIM && !H8S_SIM) + help + gdb stub exception support + +config CONFIG_SH_STANDARD_BIOS + bool "Use gdb protocol serial console" + depends on (!H8300H_SIM && !H8S_SIM) + help + serial console output using GDB protocol. + Require eCos/RedBoot + +config DEFAULT_CMDLINE + bool "Use buildin commandline" + default n + help + buildin kernel commandline enabled. + +config KERNEL_COMMAND + string "Buildin commmand string" + depends on DEFAULT_CMDLINE + help + buildin kernel commandline strings. + +config BLKDEV_RESERVE + bool "BLKDEV Reserved Memory" + default n + help + Reserved BLKDEV area. + +config CONFIG_BLKDEV_RESERVE_ADDRESS + hex 'start address' + depends on BLKDEV_RESERVE + help + BLKDEV start address. + +endmenu diff -Nru a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile --- a/arch/h8300/kernel/Makefile 2004-10-18 14:56:33 -07:00 +++ b/arch/h8300/kernel/Makefile 2004-10-18 14:56:33 -07:00 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds obj-y := process.o traps.o ptrace.o ints.o \ sys_h8300.o time.o semaphore.o signal.o \ diff -Nru a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c --- a/arch/h8300/kernel/asm-offsets.c 2004-10-18 14:55:54 -07:00 +++ b/arch/h8300/kernel/asm-offsets.c 2004-10-18 14:55:54 -07:00 @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #include #define DEFINE(sym, val) \ diff -Nru a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c --- a/arch/h8300/kernel/h8300_ksyms.c 2004-10-18 14:57:03 -07:00 +++ b/arch/h8300/kernel/h8300_ksyms.c 2004-10-18 14:57:03 -07:00 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -50,13 +49,13 @@ explicitly (the C compiler generates them). Fortunately, their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ -//EXPORT_SYMBOL_NOVERS(__ashrdi3); -//EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memmove); +//EXPORT_SYMBOL(__ashrdi3); +//EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(get_wchan); @@ -85,29 +84,29 @@ extern void __umodsi3(void); /* gcc lib functions */ -EXPORT_SYMBOL_NOVERS(__gcc_bcmp); -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__cmpdi2); -EXPORT_SYMBOL_NOVERS(__divdi3); -EXPORT_SYMBOL_NOVERS(__divsi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(__moddi3); -EXPORT_SYMBOL_NOVERS(__modsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__mulsi3); -EXPORT_SYMBOL_NOVERS(__negdi2); -EXPORT_SYMBOL_NOVERS(__ucmpdi2); -EXPORT_SYMBOL_NOVERS(__udivdi3); -EXPORT_SYMBOL_NOVERS(__udivmoddi4); -EXPORT_SYMBOL_NOVERS(__udivsi3); -EXPORT_SYMBOL_NOVERS(__umoddi3); -EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL(__gcc_bcmp); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__cmpdi2); +EXPORT_SYMBOL(__divdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__moddi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulsi3); +EXPORT_SYMBOL(__negdi2); +EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__udivdi3); +EXPORT_SYMBOL(__udivmoddi4); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umoddi3); +EXPORT_SYMBOL(__umodsi3); #ifdef MAGIC_ROM_PTR -EXPORT_SYMBOL_NOVERS(is_in_rom); +EXPORT_SYMBOL(is_in_rom); #endif -EXPORT_SYMBOL_NOVERS(h8300_reserved_gpio); -EXPORT_SYMBOL_NOVERS(h8300_free_gpio); -EXPORT_SYMBOL_NOVERS(h8300_set_gpio_dir); +EXPORT_SYMBOL(h8300_reserved_gpio); +EXPORT_SYMBOL(h8300_free_gpio); +EXPORT_SYMBOL(h8300_set_gpio_dir); diff -Nru a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c --- a/arch/h8300/kernel/ints.c 2004-10-18 14:56:27 -07:00 +++ b/arch/h8300/kernel/ints.c 2004-10-18 14:56:27 -07:00 @@ -22,13 +22,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include /* diff -Nru a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c --- a/arch/h8300/kernel/process.c 2004-10-18 14:55:53 -07:00 +++ b/arch/h8300/kernel/process.c 2004-10-18 14:55:53 -07:00 @@ -189,7 +189,7 @@ newsp = regs->er2; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL); + return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); } diff -Nru a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c --- a/arch/h8300/kernel/ptrace.c 2004-10-18 14:56:28 -07:00 +++ b/arch/h8300/kernel/ptrace.c 2004-10-18 14:56:28 -07:00 @@ -89,13 +89,6 @@ ret = ptrace_attach(child); goto out_tsk; } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; @@ -114,7 +107,7 @@ /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { - unsigned long tmp; + unsigned long tmp = 0; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) { ret = -EIO; @@ -270,10 +263,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; - 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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c --- a/arch/h8300/kernel/signal.c 2004-10-18 14:56:32 -07:00 +++ b/arch/h8300/kernel/signal.c 2004-10-18 14:56:32 -07:00 @@ -391,9 +391,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, @@ -443,9 +441,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static inline void diff -Nru a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c --- a/arch/h8300/kernel/time.c 2004-10-18 14:56:28 -07:00 +++ b/arch/h8300/kernel/time.c 2004-10-18 14:56:28 -07:00 @@ -36,24 +36,6 @@ EXPORT_SYMBOL(jiffies_64); -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -64,10 +46,7 @@ platform_timer_eoi(); do_timer(regs); - - if (!user_mode(regs)) - do_profile(regs->pc); - + profile_tick(CPU_PROFILING, regs); } void time_init(void) diff -Nru a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S --- a/arch/h8300/kernel/vmlinux.lds.S 2004-10-18 14:56:33 -07:00 +++ b/arch/h8300/kernel/vmlinux.lds.S 2004-10-18 14:56:33 -07:00 @@ -150,9 +150,6 @@ *(.init.setup) . = ALIGN(0x4) ; ___setup_end = .; - ___start___param = .; - *(__param) - ___stop___param = .; ___initcall_start = .; *(.initcall1.init) *(.initcall2.init) diff -Nru a/arch/h8300/lib/checksum.c b/arch/h8300/lib/checksum.c --- a/arch/h8300/lib/checksum.c 2004-10-18 14:55:54 -07:00 +++ b/arch/h8300/lib/checksum.c 2004-10-18 14:55:54 -07:00 @@ -32,6 +32,7 @@ of the assembly has to go. */ #include +#include static inline unsigned short from32to16(unsigned long x) { diff -Nru a/arch/h8300/platform/h8300h/generic/timer.c b/arch/h8300/platform/h8300h/generic/timer.c --- a/arch/h8300/platform/h8300h/generic/timer.c 2004-10-18 14:56:28 -07:00 +++ b/arch/h8300/platform/h8300h/generic/timer.c 2004-10-18 14:56:28 -07:00 @@ -32,7 +32,7 @@ #define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */ -int platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) +void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) { /* setup 8bit timer ch2 */ ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2); /* set interval */ @@ -69,7 +69,7 @@ #define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8 /* Timer input freq. */ -int platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) +void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) { *(unsigned short *)GRA= H8300_TIMER_FREQ / HZ; /* set interval */ *(unsigned short *)TCNT=0; /* clear counter */ diff -Nru a/arch/h8300/platform/h8s/ints.c b/arch/h8300/platform/h8s/ints.c --- a/arch/h8300/platform/h8s/ints.c 2004-10-18 14:56:28 -07:00 +++ b/arch/h8300/platform/h8s/ints.c 2004-10-18 14:56:28 -07:00 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig 2004-10-18 14:56:12 -07:00 +++ b/arch/i386/Kconfig 2004-10-18 14:56:12 -07:00 @@ -29,8 +29,11 @@ bool default y -source "init/Kconfig" +config GENERIC_IOMAP + bool + default y +source "init/Kconfig" menu "Processor type and features" @@ -55,20 +58,20 @@ config X86_VOYAGER bool "Voyager (NCR)" help - Voyager is a MCA based 32 way capable SMP architecture proprietary - to NCR Corp. Machine classes 345x/35xx/4100/51xx are voyager based. - + Voyager is an MCA-based 32-way capable SMP architecture proprietary + to NCR Corp. Machine classes 345x/35xx/4100/51xx are Voyager-based. + *** WARNING *** - + If you do not specifically know you have a Voyager based machine, - say N here otherwise the kernel you build will not be bootable. + say N here, otherwise the kernel you build will not be bootable. config X86_NUMAQ bool "NUMAQ (IBM/Sequent)" select DISCONTIGMEM select NUMA help - This option is used for getting Linux to run on a (IBM/Sequent) NUMA + This option is used for getting Linux to run on a (IBM/Sequent) NUMA multiquad box. This changes the way that processors are bootstrapped, and uses Clustered Logical APIC addressing mode instead of Flat Logical. You will need a new lynxer.elf file to flash your firmware with - send @@ -115,8 +118,8 @@ depends on SMP help Support for Unisys ES7000 systems. Say 'Y' here if this kernel is - supposed to run on an IA32-based Unisys ES7000 system. - Only choose this option if you have such a system, otherwise you + supposed to run on an IA32-based Unisys ES7000 system. + Only choose this option if you have such a system, otherwise you should say N here. endchoice @@ -322,7 +325,7 @@ endchoice config X86_GENERIC - bool "Generic x86 support" + bool "Generic x86 support" help Instead of just including optimizations for the selected x86 variant (e.g. PII, Crusoe or Athlon), include some more @@ -1027,7 +1030,6 @@ endmenu - menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" config X86_VISWS_APIC @@ -1105,7 +1107,7 @@ config PCI_MMCONFIG bool - depends on PCI && (PCI_GOMMCONFIG || PCI_GOANY) + depends on PCI && (PCI_GOMMCONFIG || (PCI_GOANY && ACPI)) select ACPI_BOOT default y @@ -1158,7 +1160,7 @@ tristate "NatSemi SCx200 support" depends on !X86_VOYAGER help - This provides basic support for the National Semiconductor SCx200 + This provides basic support for the National Semiconductor SCx200 processor. Right now this is just a driver for the GPIO pins. If you don't know what to do here, say N. @@ -1172,7 +1174,6 @@ endmenu - menu "Executable file formats" source "fs/Kconfig.binfmt" @@ -1185,130 +1186,7 @@ source "arch/i386/oprofile/Kconfig" - -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config EARLY_PRINTK - bool "Early printk" if EMBEDDED - default y - help - Write kernel log output directly into the VGA buffer or to a serial - port. - - This is useful for kernel debugging when your machine crashes very - early before the console code is initialized. For normal operation - it is not recommended because it looks ugly and doesn't cooperate - with klogd/syslogd or the X server. You should normally N here, - unless you want to debug such a crash. - -config DEBUG_STACKOVERFLOW - bool "Check for stack overflows" - depends on DEBUG_KERNEL - -config DEBUG_STACK_USAGE - bool "Stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_PAGEALLOC - bool "Page alloc debugging" - depends on DEBUG_KERNEL - help - Unmap pages from the kernel linear mapping after free_pages(). - This results in a large slowdown, but helps to find certain types - of memory corruptions. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - help - This options enables addition error checking for high memory systems. - Disable for production systems. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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" - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - 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 4KSTACKS - bool "Use 4Kb for kernel stacks instead of 8Kb" - help - If you say Y here the kernel will use a 4Kb stacksize for the - kernel stack attached to each process/thread. This facilitates - running more threads on a system and also reduces the pressure - on the VM subsystem for higher order allocations. This option - will also use IRQ stacks to compensate for the reduced stackspace. - -config X86_FIND_SMP_CONFIG - bool - depends on X86_LOCAL_APIC || X86_VOYAGER - default y - -config X86_MPPARSE - bool - depends on X86_LOCAL_APIC && !X86_VISWS - default y - -endmenu +source "arch/i386/Kconfig.debug" source "security/Kconfig" diff -Nru a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/i386/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,80 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config EARLY_PRINTK + bool "Early printk" if EMBEDDED + default y + help + Write kernel log output directly into the VGA buffer or to a serial + port. + + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. For normal operation + it is not recommended because it looks ugly and doesn't cooperate + with klogd/syslogd or the X server. You should normally N here, + unless you want to debug such a crash. + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL + +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". + +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config DEBUG_PAGEALLOC + bool "Page alloc debugging" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a large slowdown, but helps to find certain types + of memory corruptions. + +config 4KSTACKS + bool "Use 4Kb for kernel stacks instead of 8Kb" + help + If you say Y here the kernel will use a 4Kb stacksize for the + kernel stack attached to each process/thread. This facilitates + running more threads on a system and also reduces the pressure + on the VM subsystem for higher order allocations. This option + will also use IRQ stacks to compensate for the reduced stackspace. + +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on DEBUG_KERNEL && PROC_FS + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. + +config X86_FIND_SMP_CONFIG + bool + depends on X86_LOCAL_APIC || X86_VOYAGER + default y + +config X86_MPPARSE + bool + depends on X86_LOCAL_APIC && !X86_VISWS + default y + +endmenu diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile --- a/arch/i386/Makefile 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/Makefile 2004-10-18 14:56:28 -07:00 @@ -18,48 +18,47 @@ LDFLAGS := -m elf_i386 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := -CHECK := $(CHECK) -D__i386__=1 +CHECKFLAGS += -D__i386__ 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 += $(call cc-option,-mpreferred-stack-boundary=2) +align := $(subst -functions=0,,$(call cc-option,-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_M586MMX) += $(call cc-option,-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_MPENTIUMM) += $(call check_gcc,-march=pentium3,-march=i686) -cflags-$(CONFIG_MPENTIUM4) += $(call check_gcc,-march=pentium4,-march=i686) +cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,-march=pentium2,-march=i686) +cflags-$(CONFIG_MPENTIUMIII) += $(call cc-option,-march=pentium3,-march=i686) +cflags-$(CONFIG_MPENTIUMM) += $(call cc-option,-march=pentium3,-march=i686) +cflags-$(CONFIG_MPENTIUM4) += $(call cc-option,-march=pentium4,-march=i686) cflags-$(CONFIG_MK6) += -march=k6 # 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_MK7) += $(call cc-option,-march=athlon,-march=i686 $(align)-functions=4) +cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,$(call cc-option,-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) +cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) +cflags-$(CONFIG_MWINCHIP2) += $(call cc-option,-march=winchip2,-march=i586) +cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586) +cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 +cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) # 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)) +GCC_VERSION := $(call cc-version) cflags-$(CONFIG_REGPARM) += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;) # Disable unit-at-a-time mode, it makes gcc use a lot more stack # due to the lack of sharing of stacklots. -CFLAGS += $(call check_gcc,-fno-unit-at-a-time,) +CFLAGS += $(call cc-option,-fno-unit-at-a-time) CFLAGS += $(cflags-y) diff -Nru a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile --- a/arch/i386/boot/Makefile 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/boot/Makefile 2004-10-18 14:56:28 -07:00 @@ -29,9 +29,9 @@ zImage bzImage subdir- := compressed -host-progs := tools/build +hostprogs-y := tools/build -HOSTCFLAGS_build.o := -Iinclude +HOSTCFLAGS_build.o := $(LINUXINCLUDE) # --------------------------------------------------------------------------- diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S --- a/arch/i386/boot/setup.S 2004-10-18 14:56:32 -07:00 +++ b/arch/i386/boot/setup.S 2004-10-18 14:56:32 -07:00 @@ -156,7 +156,7 @@ # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long (MAXMEM-1) & 0x7fffffff +ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd diff -Nru a/arch/i386/boot/video.S b/arch/i386/boot/video.S --- a/arch/i386/boot/video.S 2004-10-18 14:57:19 -07:00 +++ b/arch/i386/boot/video.S 2004-10-18 14:57:19 -07:00 @@ -232,6 +232,41 @@ xorl %eax, %eax movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE) + +# switching the DAC to 8-bit is for <= 8 bpp only + movw %fs:(PARAM_LFB_DEPTH), %ax + cmpw $8, %ax + jg dac_done + +# get DAC switching capability + xorl %eax, %eax + movb 10(%di), %al + testb $1, %al + jz dac_set + +# attempt to switch DAC to 8-bit + movw $0x4f08, %ax + movw $0x0800, %bx + int $0x10 + cmpw $0x004f, %ax + jne dac_set + movb %bh, dac_size # store actual DAC size + +dac_set: +# set color size to DAC size + movb dac_size, %al + movb %al, %fs:(PARAM_LFB_COLORS+0) + movb %al, %fs:(PARAM_LFB_COLORS+2) + movb %al, %fs:(PARAM_LFB_COLORS+4) + movb %al, %fs:(PARAM_LFB_COLORS+6) + +# set color offsets to 0 + movb $0, %fs:(PARAM_LFB_COLORS+1) + movb $0, %fs:(PARAM_LFB_COLORS+3) + movb $0, %fs:(PARAM_LFB_COLORS+5) + movb $0, %fs:(PARAM_LFB_COLORS+7) + +dac_done: # get protected mode interface informations movw $0x4f0a, %ax xorw %bx, %bx @@ -1929,6 +1964,7 @@ do_restore: .byte 0 # Screen contents altered during mode change svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes graphic_mode: .byte 0 # Graphic mode with a linear frame buffer +dac_size: .byte 6 # DAC bit depth # Status messages keymsg: .ascii "Press to see video modes available, " diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile 2004-10-18 14:56:17 -07:00 +++ b/arch/i386/kernel/Makefile 2004-10-18 14:56:17 -07:00 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds 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 \ @@ -25,6 +25,7 @@ obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o +obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o @@ -41,11 +42,14 @@ # Note: kbuild does not track this dependency due to usage of .incbin $(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) +targets += vsyscall.lds # The DSO images are built using a special linker script. quiet_cmd_syscall = SYSCALL $@ cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ -Wl,-T,$(filter-out FORCE,$^) -o $@ + +export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH) vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) diff -Nru a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c --- a/arch/i386/kernel/acpi/boot.c 2004-10-18 14:56:50 -07:00 +++ b/arch/i386/kernel/acpi/boot.c 2004-10-18 14:56:50 -07:00 @@ -71,6 +71,7 @@ int acpi_lapic; int acpi_ioapic; int acpi_strict; +EXPORT_SYMBOL(acpi_strict); acpi_interrupt_flags acpi_sci_flags __initdata; int acpi_sci_override_gsi __initdata; @@ -84,6 +85,11 @@ #warning ACPI uses CMPXCHG, i486 and later hardware #endif +#define MAX_MADT_ENTRIES 256 +u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = + { [0 ... MAX_MADT_ENTRIES-1] = 0xff }; +EXPORT_SYMBOL(x86_acpiid_to_apicid); + /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ @@ -225,6 +231,8 @@ if (processor->flags.enabled == 0) return 0; + x86_acpiid_to_apicid[processor->acpi_id] = processor->id; + mp_register_lapic ( processor->id, /* APIC ID */ processor->flags.enabled); /* Enabled? */ @@ -822,9 +830,15 @@ */ error = acpi_blacklisted(); if (error) { - printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); - disable_acpi(); - return error; + extern int acpi_force; + + if (acpi_force) { + printk(KERN_WARNING PREFIX "acpi=force override\n"); + } else { + printk(KERN_WARNING PREFIX "Disabling ACPI support\n"); + disable_acpi(); + return error; + } } /* diff -Nru a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c --- a/arch/i386/kernel/acpi/sleep.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/kernel/acpi/sleep.c 2004-10-18 14:56:29 -07:00 @@ -77,10 +77,7 @@ printk(KERN_ERR "ACPI: Wakeup code way too big, S3 disabled.\n"); return; } -#ifdef CONFIG_X86_PAE - printk(KERN_ERR "ACPI: S3 and PAE do not like each other for now, S3 disabled.\n"); - return; -#endif + acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); if (!acpi_wakeup_address) printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c --- a/arch/i386/kernel/apic.c 2004-10-18 14:57:05 -07:00 +++ b/arch/i386/kernel/apic.c 2004-10-18 14:57:05 -07:00 @@ -39,6 +39,12 @@ #include "io_ports.h" +/* + * Debug level + */ +int apic_verbosity; + + static void apic_pm_activate(void); void __init apic_intr_init(void) @@ -85,7 +91,7 @@ unsigned int lvr, version; lvr = apic_read(APIC_LVR); version = GET_APIC_VERSION(lvr); - if (version >= 0x14) + if (!APIC_INTEGRATED(version) || version >= 0x14) return 0xff; else return 0xf; @@ -173,7 +179,8 @@ * PIC mode, enable APIC mode in the IMCR, i.e. * connect BSP's local APIC to INT and NMI lines. */ - printk("leaving PIC mode, enabling APIC mode.\n"); + apic_printk(APIC_VERBOSE, "leaving PIC mode, " + "enabling APIC mode.\n"); outb(0x70, 0x22); outb(0x01, 0x23); } @@ -189,7 +196,8 @@ * interrupts, including IPIs, won't work beyond * this point! The only exception are INIT IPIs. */ - printk("disabling APIC mode, entering PIC mode.\n"); + apic_printk(APIC_VERBOSE, "disabling APIC mode, " + "entering PIC mode.\n"); outb(0x70, 0x22); outb(0x00, 0x23); } @@ -230,10 +238,10 @@ * The version register is read-only in a real APIC. */ reg0 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg0); apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); reg1 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg1); /* * The two version reads above should print the same @@ -257,7 +265,7 @@ * The ID register is read/write in a real APIC. */ reg0 = apic_read(APIC_ID); - Dprintk("Getting ID: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); /* * The next two are just to see if we have sane values. @@ -265,9 +273,9 @@ * compatibility mode, but most boxes are anymore. */ reg0 = apic_read(APIC_LVT0); - Dprintk("Getting LVT0: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting LVT0: %x\n", reg0); reg1 = apic_read(APIC_LVT1); - Dprintk("Getting LVT1: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting LVT1: %x\n", reg1); return 1; } @@ -279,7 +287,7 @@ */ apic_wait_icr_idle(); - Dprintk("Synchronizing Arb IDs.\n"); + apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n"); apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT); } @@ -335,7 +343,7 @@ void __init setup_local_APIC (void) { - unsigned long value, ver, maxlvt; + unsigned long oldvalue, value, ver, maxlvt; /* Pound the ESR really hard over the head with a big hammer - mbligh */ if (esr_disable) { @@ -427,10 +435,12 @@ value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; if (!smp_processor_id() && (pic_mode || !value)) { value = APIC_DM_EXTINT; - printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", + smp_processor_id()); } else { value = APIC_DM_EXTINT | APIC_LVT_MASKED; - printk("masked ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", + smp_processor_id()); } apic_write_around(APIC_LVT0, value); @@ -449,8 +459,7 @@ maxlvt = get_maxlvt(); if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); - value = apic_read(APIC_ESR); - printk("ESR value before enabling vector: %08lx\n", value); + oldvalue = apic_read(APIC_ESR); value = ERROR_APIC_VECTOR; // enables sending errors apic_write_around(APIC_LVTERR, value); @@ -460,7 +469,10 @@ if (maxlvt > 3) apic_write(APIC_ESR, 0); value = apic_read(APIC_ESR); - printk("ESR value after enabling vector: %08lx\n", value); + if (value != oldvalue) + apic_printk(APIC_VERBOSE, "ESR value before enabling " + "vector: 0x%08lx after: 0x%08lx\n", + oldvalue, value); } else { if (esr_disable) /* @@ -635,6 +647,21 @@ } __setup("lapic", lapic_enable); +static int __init apic_set_verbosity(char *str) +{ + if (strcmp("debug", str) == 0) + apic_verbosity = APIC_DEBUG; + else if (strcmp("verbose", str) == 0) + apic_verbosity = APIC_VERBOSE; + else + printk(KERN_WARNING "APIC Verbosity level %s not recognised" + " use apic=verbose or apic=debug", str); + + return 0; +} + +__setup("apic=", apic_set_verbosity); + static int __init detect_init_APIC (void) { u32 h, l, features; @@ -665,13 +692,20 @@ if (!cpu_has_apic) { /* + * Over-ride BIOS and try to enable LAPIC + * only if "lapic" specified + */ + if (enable_local_apic != 1) + goto no_apic; + /* * Some BIOSes disable the local APIC in the * APIC_BASE MSR. This can only be done in * software for Intel P6 and AMD K7 (Model > 1). */ rdmsr(MSR_IA32_APICBASE, l, h); if (!(l & MSR_IA32_APICBASE_ENABLE)) { - printk("Local APIC disabled by BIOS -- reenabling.\n"); + apic_printk(APIC_VERBOSE, "Local APIC disabled " + "by BIOS -- reenabling.\n"); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); @@ -698,7 +732,7 @@ if (nmi_watchdog != NMI_NONE) nmi_watchdog = NMI_LOCAL_APIC; - printk("Found and enabled local APIC!\n"); + apic_printk(APIC_VERBOSE, "Found and enabled local APIC!\n"); apic_pm_activate(); @@ -725,7 +759,8 @@ apic_phys = mp_lapic_addr; set_fixmap_nocache(FIX_APIC_BASE, apic_phys); - Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); + apic_printk(APIC_DEBUG, "mapped APIC to %08lx (%08lx)\n", APIC_BASE, + apic_phys); /* * Fetch the APIC ID of the BSP in case we have a @@ -755,7 +790,8 @@ ioapic_phys = __pa(ioapic_phys); } set_fixmap_nocache(idx, ioapic_phys); - Dprintk("mapped IOAPIC to %08lx (%08lx)\n", + apic_printk(APIC_DEBUG, "mapped IOAPIC to " + "%08lx (%08lx)\n", __fix_to_virt(idx), ioapic_phys); idx++; } @@ -894,7 +930,7 @@ int i; const int LOOPS = HZ/10; - printk("calibrating APIC timer ...\n"); + apic_printk(APIC_VERBOSE, "calibrating APIC timer ...\n"); /* * Put whatever arbitrary (but long enough) timeout @@ -939,11 +975,13 @@ result = (tt1-tt2)*APIC_DIVISOR/LOOPS; if (cpu_has_tsc) - printk("..... CPU clock speed is %ld.%04ld MHz.\n", + apic_printk(APIC_VERBOSE, "..... CPU clock speed is " + "%ld.%04ld MHz.\n", ((long)(t2-t1)/LOOPS)/(1000000/HZ), ((long)(t2-t1)/LOOPS)%(1000000/HZ)); - printk("..... host bus clock speed is %ld.%04ld MHz.\n", + apic_printk(APIC_VERBOSE, "..... host bus clock speed is " + "%ld.%04ld MHz.\n", result/(1000000/HZ), result%(1000000/HZ)); @@ -954,7 +992,7 @@ void __init setup_boot_APIC_clock(void) { - printk("Using local APIC timer interrupts.\n"); + apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"); using_apic_timer = 1; local_irq_disable(); @@ -1039,8 +1077,7 @@ { int cpu = smp_processor_id(); - x86_do_profile(regs); - + profile_tick(CPU_PROFILING, regs); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got @@ -1159,7 +1196,7 @@ 6: Received illegal vector 7: Illegal register address */ - printk (KERN_INFO "APIC error on CPU%d: %02lx(%02lx)\n", + printk (KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n", smp_processor_id(), v , v1); irq_exit(); } diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c --- a/arch/i386/kernel/apm.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/apm.c 2004-10-18 14:55:54 -07:00 @@ -601,8 +601,8 @@ cpus = apm_save_cpus(); cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; local_save_flags(flags); APM_DO_CLI; @@ -610,7 +610,7 @@ apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); APM_DO_RESTORE_SEGS; local_irq_restore(flags); - cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); @@ -644,8 +644,8 @@ cpus = apm_save_cpus(); cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; local_save_flags(flags); APM_DO_CLI; @@ -653,7 +653,7 @@ error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); APM_DO_RESTORE_SEGS; local_irq_restore(flags); - cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40; + __get_cpu_var(cpu_gdt_table)[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); return error; @@ -2271,10 +2271,12 @@ } if ((num_online_cpus() > 1) && !power_off && !smp) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); + apm_info.disabled = 1; return -ENODEV; } if (PM_IS_ACTIVE()) { printk(KERN_NOTICE "apm: overridden by ACPI.\n"); + apm_info.disabled = 1; return -ENODEV; } pm_active = 1; @@ -2292,35 +2294,35 @@ apm_bios_entry.segment = APM_CS; for (i = 0; i < NR_CPUS; i++) { - set_base(cpu_gdt_table[i][APM_CS >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_CS >> 3], __va((unsigned long)apm_info.bios.cseg << 4)); - set_base(cpu_gdt_table[i][APM_CS_16 >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], __va((unsigned long)apm_info.bios.cseg_16 << 4)); - set_base(cpu_gdt_table[i][APM_DS >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); #ifndef APM_RELAX_SEGMENTS if (apm_info.bios.version == 0x100) { #endif /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 - 1); /* For some unknown machine. */ - _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ - _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], 64 * 1024 - 1); #ifndef APM_RELAX_SEGMENTS } else { - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], (apm_info.bios.cseg_len - 1) & 0xffff); - _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], (apm_info.bios.cseg_16_len - 1) & 0xffff); - _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], (apm_info.bios.dseg_len - 1) & 0xffff); /* workaround for broken BIOSes */ if (apm_info.bios.cseg_len <= apm_info.bios.offset) - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 -1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 -1); if (apm_info.bios.dseg_len <= 0x40) { /* 0x40 * 4kB == 64kB */ /* for the BIOS that assumes granularity = 1 */ - cpu_gdt_table[i][APM_DS >> 3].b |= 0x800000; + per_cpu(cpu_gdt_table, i)[APM_DS >> 3].b |= 0x800000; printk(KERN_NOTICE "apm: we set the granularity of dseg.\n"); } } @@ -2360,8 +2362,15 @@ { int error; - if (set_pm_idle) + if (set_pm_idle) { pm_idle = original_pm_idle; + /* + * We are about to unload the current idle thread pm callback + * (pm_idle), Wait for all processors to update cached/local + * copies of pm_idle before proceeding. + */ + synchronize_kernel(); + } if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0) && (apm_info.connection_version > 0x0100)) { error = apm_engage_power_management(APM_DEVICE_ALL, 0); diff -Nru a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c --- a/arch/i386/kernel/asm-offsets.c 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/kernel/asm-offsets.c 2004-10-18 14:56:28 -07:00 @@ -62,4 +62,5 @@ sizeof(struct tss_struct)); DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(VSYSCALL_BASE, __fix_to_virt(FIX_VSYSCALL)); } diff -Nru a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c --- a/arch/i386/kernel/cpu/centaur.c 2004-10-18 14:56:33 -07:00 +++ b/arch/i386/kernel/cpu/centaur.c 2004-10-18 14:56:33 -07:00 @@ -286,23 +286,20 @@ c->x86_capability[5] = cpuid_edx(0xC0000001); } - switch (c->x86_model) { - case 6 ... 8: /* Cyrix III family */ - rdmsr (MSR_VIA_FCR, lo, hi); - lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ - wrmsr (MSR_VIA_FCR, lo, hi); - - set_bit(X86_FEATURE_CX8, c->x86_capability); - set_bit(X86_FEATURE_3DNOW, c->x86_capability); + /* Cyrix III family needs CX8 & PGE explicity enabled. */ + if (c->x86_model >=6 && c->x86_model <= 9) { + rdmsr (MSR_VIA_FCR, lo, hi); + lo |= (1<<1 | 1<<7); + wrmsr (MSR_VIA_FCR, lo, hi); + set_bit(X86_FEATURE_CX8, c->x86_capability); + } - /* fall through */ + /* Before Nehemiah, the C3's had 3dNOW! */ + if (c->x86_model >=6 && c->x86_model <9) + set_bit(X86_FEATURE_3DNOW, c->x86_capability); - case 9: /* Nehemiah */ - default: - get_model_name(c); - display_cacheinfo(c); - break; - } + get_model_name(c); + display_cacheinfo(c); } static void __init init_centaur(struct cpuinfo_x86 *c) diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c --- a/arch/i386/kernel/cpu/common.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/cpu/common.c 2004-10-18 14:55:54 -07:00 @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include @@ -11,6 +13,9 @@ #include "cpu.h" +DEFINE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]); +EXPORT_PER_CPU_SYMBOL(cpu_gdt_table); + static int cachesize_override __initdata = -1; static int disable_x86_fxsr __initdata = 0; static int disable_x86_serial_nr __initdata = 1; @@ -501,7 +506,7 @@ void __init cpu_init (void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct * t = &per_cpu(init_tss, cpu); struct thread_struct *thread = ¤t->thread; if (test_and_set_bit(cpu, &cpu_initialized)) { @@ -523,15 +528,17 @@ * Initialize the per-CPU GDT with the boot GDT, * and set up the GDT descriptor: */ - if (cpu) { - memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE); - cpu_gdt_descr[cpu].size = GDT_SIZE - 1; - cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu]; - } + memcpy(&per_cpu(cpu_gdt_table, cpu), cpu_gdt_table, + GDT_SIZE); + cpu_gdt_descr[cpu].size = GDT_SIZE - 1; + cpu_gdt_descr[cpu].address = + (unsigned long)&per_cpu(cpu_gdt_table, cpu); + /* * Set up the per-thread TLS descriptor cache: */ - memcpy(thread->tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8); + memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu), + GDT_ENTRY_TLS_ENTRIES * 8); __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu])); __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); @@ -552,13 +559,11 @@ load_esp0(t, thread); set_tss_desc(cpu,t); - cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); 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; /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); diff -Nru a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig --- a/arch/i386/kernel/cpu/cpufreq/Kconfig 2004-10-18 14:56:17 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/Kconfig 2004-10-18 14:56:17 -07:00 @@ -88,6 +88,11 @@ If in doubt, say N. +config X86_POWERNOW_K7_ACPI + bool + depends on ((X86_POWERNOW_K7 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K7 = "y" && ACPI_PROCESSOR = "y")) + default y + config X86_POWERNOW_K8 tristate "AMD Opteron/Athlon64 PowerNow!" depends on CPU_FREQ && EXPERIMENTAL @@ -97,6 +102,11 @@ For details, take a look at . If in doubt, say N. + +config X86_POWERNOW_K8_ACPI + bool + depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y")) + default y config X86_GX_SUSPMOD tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" diff -Nru a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c --- a/arch/i386/kernel/cpu/cpufreq/acpi.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c 2004-10-18 14:55:54 -07:00 @@ -108,13 +108,27 @@ u32 value = 0; int i = 0; struct cpufreq_freqs cpufreq_freqs; + cpumask_t saved_mask; + int retval; ACPI_FUNCTION_TRACE("acpi_processor_set_performance"); + /* + * TBD: Use something other than set_cpus_allowed. + * As set_cpus_allowed is a bit racy, + * with any other set_cpus_allowed for this process. + */ + saved_mask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (smp_processor_id() != cpu) { + return_VALUE(-EAGAIN); + } + if (state == data->acpi_data.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at target state (P%d)\n", state)); - return_VALUE(0); + retval = 0; + goto migrate_end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n", @@ -144,7 +158,8 @@ if (ret) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid port width 0x%04x\n", bit_width)); - return_VALUE(ret); + retval = ret; + goto migrate_end; } /* @@ -166,7 +181,8 @@ if (ret) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid port width 0x%04x\n", bit_width)); - return_VALUE(ret); + retval = ret; + goto migrate_end; } if (value == (u32) data->acpi_data.states[state].status) break; @@ -183,7 +199,8 @@ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Transition failed\n")); - return_VALUE(-ENODEV); + retval = -ENODEV; + goto migrate_end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -192,7 +209,10 @@ data->acpi_data.state = state; - return_VALUE(0); + retval = 0; +migrate_end: + set_cpus_allowed(current, saved_mask); + return_VALUE(retval); } @@ -266,6 +286,69 @@ } + +/* + * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities + * of this driver + * @perf: processor-specific acpi_io_data struct + * @cpu: CPU being initialized + * + * To avoid issues with legacy OSes, some BIOSes require to be informed of + * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC + * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in + * driver/acpi/processor.c + */ +static void +acpi_processor_cpu_init_pdc_est( + struct acpi_processor_performance *perf, + unsigned int cpu, + struct acpi_object_list *obj_list + ) +{ + union acpi_object *obj; + u32 *buf; + struct cpuinfo_x86 *c = cpu_data + cpu; + ACPI_FUNCTION_TRACE("acpi_processor_cpu_init_pdc_est"); + + if (!cpu_has(c, X86_FEATURE_EST)) + return_VOID; + + /* Initialize pdc. It will be used later. */ + if (!obj_list) + return_VOID; + + if (!(obj_list->count && obj_list->pointer)) + return_VOID; + + obj = obj_list->pointer; + if ((obj->buffer.length == 12) && obj->buffer.pointer) { + buf = (u32 *)obj->buffer.pointer; + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; + perf->pdc = obj_list; + } + return_VOID; +} + + +/* CPU specific PDC initialization */ +static void +acpi_processor_cpu_init_pdc( + struct acpi_processor_performance *perf, + unsigned int cpu, + struct acpi_object_list *obj_list + ) +{ + struct cpuinfo_x86 *c = cpu_data + cpu; + ACPI_FUNCTION_TRACE("acpi_processor_cpu_init_pdc"); + perf->pdc = NULL; + if (cpu_has(c, X86_FEATURE_EST)) + acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list); + return_VOID; +} + + static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -275,7 +358,14 @@ struct cpufreq_acpi_io *data; unsigned int result = 0; + union acpi_object arg0 = {ACPI_TYPE_BUFFER}; + u32 arg0_buf[3]; + struct acpi_object_list arg_list = {1, &arg0}; + ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init"); + /* setup arg_list for _PDC settings */ + arg0.buffer.length = 12; + arg0.buffer.pointer = (u8 *) arg0_buf; data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) @@ -284,7 +374,10 @@ acpi_io_data[cpu] = data; + acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list); result = acpi_processor_register_performance(&data->acpi_data, cpu); + data->acpi_data.pdc = NULL; + if (result) goto err_free; diff -Nru a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c 2004-10-18 14:56:31 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c 2004-10-18 14:56:31 -07:00 @@ -297,6 +297,7 @@ case PCI_DEVICE_ID_CYRIX_5520: case PCI_DEVICE_ID_CYRIX_5510: suscfg = gx_params->pci_suscfg | SUSMOD; + break; default: local_irq_restore(flags); dprintk("fatal: try to set unknown chipset.\n"); diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c 2004-10-18 14:55:54 -07:00 @@ -5,14 +5,19 @@ * Licensed under the terms of the GNU GPL License version 2. * Based upon datasheets & sample CPUs kindly provided by VIA. * - * VIA have currently 2 different versions of Longhaul. + * VIA have currently 3 different versions of Longhaul. * Version 1 (Longhaul) uses the BCR2 MSR at 0x1147. - * It is present only in Samuel 1, Samuel 2 and Ezra. - * Version 2 (Powersaver) uses the POWERSAVER MSR at 0x110a. - * It is present in Ezra-T, Nehemiah and above. - * In addition to scaling multiplier, it can also scale voltage. - * There is provision for scaling FSB too, but this doesn't work - * too well in practice. + * It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0. + * Version 2 of longhaul is the same as v1, but adds voltage scaling. + * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C) + * voltage scaling support has currently been disabled in this driver + * until we have code that gets it right. + * Version 3 of longhaul got renamed to Powersaver and redesigned + * to use the POWERSAVER MSR at 0x110a. + * It is present in Ezra-T (C5M), Nehemiah (C5X) and above. + * It's pretty much the same feature wise to longhaul v2, though + * there is provision for scaling FSB too, but this doesn't work + * too well in practice so we don't even try to use this. * * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* */ @@ -33,6 +38,17 @@ #define PFX "longhaul: " +#define TYPE_LONGHAUL_V1 1 +#define TYPE_LONGHAUL_V2 2 +#define TYPE_POWERSAVER 3 + +#define CPU_SAMUEL 1 +#define CPU_SAMUEL2 2 +#define CPU_EZRA 3 +#define CPU_EZRA_T 4 +#define CPU_NEHEMIAH 5 + +static int cpu_model; static unsigned int numscales=16, numvscales; static unsigned int fsb; static int minvid, maxvid; @@ -68,9 +84,23 @@ static unsigned int highest_speed, lowest_speed; /* kHz */ static int longhaul_version; static struct cpufreq_frequency_table *longhaul_table; +static char speedbuffer[8]; +static char *print_speed(int speed) +{ + if (speed > 1000) { + if (speed%1000 == 0) + sprintf (speedbuffer, "%dGHz", speed/1000); + else + sprintf (speedbuffer, "%d.%dGHz", speed/1000, (speed%1000)/100); + } else + sprintf (speedbuffer, "%dMHz", speed); -static unsigned int calc_speed(int mult, int fsb) + return speedbuffer; +} + + +static unsigned int calc_speed(int mult) { int khz; khz = (mult/10)*fsb; @@ -87,7 +117,7 @@ rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; - if (longhaul_version==2 || longhaul_version==3) { + if (longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) { if (lo & (1<<27)) invalue+=16; } @@ -95,11 +125,45 @@ } +static void do_powersaver(union msr_longhaul *longhaul, + unsigned int clock_ratio_index) +{ + int version; + + switch (cpu_model) { + case CPU_EZRA_T: + version = 3; + break; + case CPU_NEHEMIAH: + version = 0xf; + break; + default: + return; + } + + rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); + longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf; + longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; + longhaul->bits.EnableSoftBusRatio = 1; + longhaul->bits.RevisionKey = 0; + local_irq_disable(); + wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); + local_irq_enable(); + __hlt(); + + rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); + longhaul->bits.EnableSoftBusRatio = 0; + longhaul->bits.RevisionKey = version; + local_irq_disable(); + wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); + local_irq_enable(); +} + /** * longhaul_set_cpu_frequency() * @clock_ratio_index : bitpattern of the new multiplier. * - * Sets a new clock ratio, and -if applicable- a new Front Side Bus + * Sets a new clock ratio. */ static void longhaul_setstate(unsigned int clock_ratio_index) @@ -108,79 +172,71 @@ struct cpufreq_freqs freqs; union msr_longhaul longhaul; union msr_bcr2 bcr2; + static unsigned int old_ratio=-1; + + if (old_ratio == clock_ratio_index) + return; + old_ratio = clock_ratio_index; mult = clock_ratio[clock_ratio_index]; if (mult == -1) return; - speed = calc_speed (mult, fsb); + speed = calc_speed(mult); if ((speed > highest_speed) || (speed < lowest_speed)) return; - freqs.old = calc_speed (longhaul_get_cpu_mult(), fsb); + freqs.old = calc_speed(longhaul_get_cpu_mult()); freqs.new = speed; freqs.cpu = 0; /* longhaul.c is UP only driver */ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - dprintk (KERN_INFO PFX "FSB:%d Mult:%d.%dx\n", fsb, mult/10, mult%10); + dprintk (KERN_INFO PFX "Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", + fsb, mult/10, mult%10, print_speed(speed/1000)); switch (longhaul_version) { - case 1: + + /* + * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B]) + * Software controlled multipliers only. + * + * *NB* Until we get voltage scaling working v1 & v2 are the same code. + * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5b] and Ezra [C5C] + */ + case TYPE_LONGHAUL_V1: + case TYPE_LONGHAUL_V2: rdmsrl (MSR_VIA_BCR2, bcr2.val); /* Enable software clock multiplier */ bcr2.bits.ESOFTBF = 1; bcr2.bits.CLOCKMUL = clock_ratio_index; + local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); + local_irq_enable(); __hlt(); /* Disable software clock multiplier */ rdmsrl (MSR_VIA_BCR2, bcr2.val); bcr2.bits.ESOFTBF = 0; + local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); + local_irq_enable(); break; /* - * Powersaver. (Ezra-T [C5M], Nehemiah [C5N]) + * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N]) * We can scale voltage with this too, but that's currently * disabled until we come up with a decent 'match freq to voltage' * algorithm. - * We also need to do the voltage/freq setting in order depending - * on the direction of scaling (like we do in powernow-k7.c) - * Ezra-T was alleged to do FSB scaling too, but it never worked in practice. + * When we add voltage scaling, we will also need to do the + * voltage/freq setting in order depending on the direction + * of scaling (like we do in powernow-k7.c) + * Nehemiah can do FSB scaling too, but this has never been proven + * to work in practice. */ - case 2: - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; - longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; - longhaul.bits.EnableSoftBusRatio = 1; - /* We must program the revision key only with values we - * know about, not blindly copy it from 0:3 */ - longhaul.bits.RevisionKey = 3; /* SoftVID & SoftBSEL */ - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - __hlt(); - - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.EnableSoftBusRatio = 0; - longhaul.bits.RevisionKey = 3; - wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); - break; - case 3: - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; - longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; - longhaul.bits.EnableSoftBusRatio = 1; - - longhaul.bits.RevisionKey = 0x0; - - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - __hlt(); - - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.EnableSoftBusRatio = 0; - longhaul.bits.RevisionKey = 0xf; - wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); + case TYPE_POWERSAVER: + do_powersaver(&longhaul, clock_ratio_index); break; } @@ -230,7 +286,6 @@ static int __init longhaul_get_ranges(void) { - struct cpuinfo_x86 *c = cpu_data; unsigned long invalue; unsigned int multipliers[32]= { 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, @@ -242,58 +297,66 @@ unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 }; switch (longhaul_version) { - case 1: + case TYPE_LONGHAUL_V1: + case TYPE_LONGHAUL_V2: /* Ugh, Longhaul v1 didn't have the min/max MSRs. Assume min=3.0x & max = whatever we booted at. */ minmult = 30; maxmult = longhaul_get_cpu_mult(); rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); invalue = (lo & (1<<18|1<<19)) >>18; - if (c->x86_model==6) + if (cpu_model==CPU_SAMUEL || cpu_model==CPU_SAMUEL2) fsb = eblcr_fsb_table_v1[invalue]; else fsb = guess_fsb(); break; - case 2: - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - - invalue = longhaul.bits.MaxMHzBR; - if (longhaul.bits.MaxMHzBR4) - invalue += 16; - maxmult=multipliers[invalue]; - - invalue = longhaul.bits.MinMHzBR; - if (longhaul.bits.MinMHzBR4 == 1) - minmult = 30; - else - minmult = multipliers[invalue]; - - fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; - break; - - case 3: - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - - /* - * TODO: This code works, but raises a lot of questions. - * - Some Nehemiah's seem to have broken Min/MaxMHzBR's. - * We get around this by using a hardcoded multiplier of 5.0x - * for the minimimum speed, and the speed we booted up at for the max. - * This is done in longhaul_get_cpu_mult() by reading the EBLCR register. - * - According to some VIA documentation EBLCR is only - * in pre-Nehemiah C3s. How this still works is a mystery. - * We're possibly using something undocumented and unsupported, - * But it works, so we don't grumble. - */ - minmult=50; - maxmult=longhaul_get_cpu_mult(); + case TYPE_POWERSAVER: + /* Ezra-T */ + if (cpu_model==CPU_EZRA_T) { + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + invalue = longhaul.bits.MaxMHzBR; + if (longhaul.bits.MaxMHzBR4) + invalue += 16; + maxmult=multipliers[invalue]; + + invalue = longhaul.bits.MinMHzBR; + if (longhaul.bits.MinMHzBR4 == 1) + minmult = 30; + else + minmult = multipliers[invalue]; + fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; + break; + } - fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; - break; + /* Nehemiah */ + if (cpu_model==CPU_NEHEMIAH) { + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + + /* + * TODO: This code works, but raises a lot of questions. + * - Some Nehemiah's seem to have broken Min/MaxMHzBR's. + * We get around this by using a hardcoded multiplier of 4.0x + * for the minimimum speed, and the speed we booted up at for the max. + * This is done in longhaul_get_cpu_mult() by reading the EBLCR register. + * - According to some VIA documentation EBLCR is only + * in pre-Nehemiah C3s. How this still works is a mystery. + * We're possibly using something undocumented and unsupported, + * But it works, so we don't grumble. + */ + minmult=40; + maxmult=longhaul_get_cpu_mult(); + + /* Starting with the 1.2GHz parts, theres a 200MHz bus. */ + if ((cpu_khz/1000) > 1200) + fsb = 200; + else + fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; + break; + } } - dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n", + dprintk (KERN_INFO PFX "MinMult:%d.%dx MaxMult:%d.%dx\n", minmult/10, minmult%10, maxmult/10, maxmult%10); if (fsb == -1) { @@ -301,10 +364,11 @@ return -EINVAL; } - highest_speed = calc_speed (maxmult, fsb); - lowest_speed = calc_speed (minmult,fsb); - dprintk (KERN_INFO PFX "FSB: %dMHz Lowestspeed=%dMHz Highestspeed=%dMHz\n", - fsb, lowest_speed/1000, highest_speed/1000); + highest_speed = calc_speed(maxmult); + lowest_speed = calc_speed(minmult); + dprintk (KERN_INFO PFX "FSB:%dMHz ", fsb); + dprintk ("Lowest speed:%s ", print_speed(lowest_speed/1000)); + dprintk ("Highest speed:%s\n", print_speed(highest_speed/1000)); if (lowest_speed == highest_speed) { printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n"); @@ -327,7 +391,7 @@ continue; if (ratio > maxmult || ratio < minmult) continue; - longhaul_table[k].frequency = calc_speed (ratio, fsb); + longhaul_table[k].frequency = calc_speed(ratio); longhaul_table[k].index = j; k++; } @@ -403,8 +467,7 @@ static int longhaul_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int target_freq, unsigned int relation) { unsigned int table_index = 0; unsigned int new_clock_ratio = 0; @@ -419,13 +482,15 @@ return 0; } + static unsigned int longhaul_get(unsigned int cpu) { if (cpu) return 0; - return (calc_speed (longhaul_get_cpu_mult(), fsb)); + return calc_speed(longhaul_get_cpu_mult()); } + static int __init longhaul_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *c = cpu_data; @@ -434,26 +499,31 @@ switch (c->x86_model) { case 6: + cpu_model = CPU_SAMUEL; cpuname = "C3 'Samuel' [C5A]"; - longhaul_version=1; + longhaul_version = TYPE_LONGHAUL_V1; memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio)); memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr)); break; - case 7: /* C5B / C5C */ - longhaul_version=1; + case 7: + longhaul_version = TYPE_LONGHAUL_V1; switch (c->x86_mask) { case 0: + cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; /* Note, this is not a typo, early Samuel2's had Samuel1 ratios. */ memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio)); memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr)); break; case 1 ... 15: - if (c->x86_mask < 8) + if (c->x86_mask < 8) { + cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; - else + } else { + cpu_model = CPU_EZRA; cpuname = "C3 'Ezra' [C5C]"; + } memcpy (clock_ratio, ezra_clock_ratio, sizeof(ezra_clock_ratio)); memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr)); break; @@ -461,15 +531,17 @@ break; case 8: + cpu_model = CPU_EZRA_T; cpuname = "C3 'Ezra-T' [C5M]"; - longhaul_version=2; + longhaul_version = TYPE_POWERSAVER; numscales=32; memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio)); memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr)); break; case 9: - longhaul_version=3; + cpu_model = CPU_NEHEMIAH; + longhaul_version = TYPE_POWERSAVER; numscales=32; switch (c->x86_mask) { case 0 ... 1: @@ -495,19 +567,28 @@ break; } - printk (KERN_INFO PFX "VIA %s CPU detected. Longhaul v%d supported.\n", - cpuname, longhaul_version); + printk (KERN_INFO PFX "VIA %s CPU detected. ", cpuname); + switch (longhaul_version) { + case TYPE_LONGHAUL_V1: + case TYPE_LONGHAUL_V2: + printk ("Longhaul v%d supported.\n", longhaul_version); + break; + case TYPE_POWERSAVER: + printk ("Powersaver supported.\n"); + break; + }; ret = longhaul_get_ranges(); if (ret != 0) return ret; - if ((longhaul_version==2) && (dont_scale_voltage==0)) + if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) && + (dont_scale_voltage==0)) longhaul_setup_voltagescaling(); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = calc_speed (longhaul_get_cpu_mult(), fsb); + policy->cur = calc_speed(longhaul_get_cpu_mult()); ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); if (ret) @@ -540,6 +621,7 @@ .attr = longhaul_attr, }; + static int __init longhaul_init(void) { struct cpuinfo_x86 *c = cpu_data; @@ -557,16 +639,17 @@ return -ENODEV; } + static void __exit longhaul_exit(void) { int i=0; - unsigned int new_clock_ratio; - - while (clock_ratio[i] != maxmult) - i++; - new_clock_ratio = longhaul_table[i].index & 0xFF; - longhaul_setstate(new_clock_ratio); + for (i=0; i < numscales; i++) { + if (clock_ratio[i] == maxmult) { + longhaul_setstate(i); + break; + } + } cpufreq_unregister_driver(&longhaul_driver); kfree(longhaul_table); diff -Nru a/arch/i386/kernel/cpu/cpufreq/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c --- a/arch/i386/kernel/cpu/cpufreq/longrun.c 2004-10-18 14:56:48 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/longrun.c 2004-10-18 14:56:48 -07:00 @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include #include @@ -19,7 +19,7 @@ static struct cpufreq_driver longrun_driver; /** - * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz + * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz * values into per cent values. In TMTA microcode, the following is valid: * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) */ @@ -42,18 +42,18 @@ policy->policy = CPUFREQ_POLICY_PERFORMANCE; else policy->policy = CPUFREQ_POLICY_POWERSAVE; - + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); msr_lo &= 0x0000007F; msr_hi &= 0x0000007F; - + if ( longrun_high_freq <= longrun_low_freq ) { /* Assume degenerate Longrun table */ policy->min = policy->max = longrun_high_freq; } else { - policy->min = longrun_low_freq + msr_lo * + policy->min = longrun_low_freq + msr_lo * ((longrun_high_freq - longrun_low_freq) / 100); - policy->max = longrun_low_freq + msr_hi * + policy->max = longrun_low_freq + msr_hi * ((longrun_high_freq - longrun_low_freq) / 100); } policy->cpu = 0; @@ -79,9 +79,9 @@ /* Assume degenerate Longrun table */ pctg_lo = pctg_hi = 100; } else { - pctg_lo = (policy->min - longrun_low_freq) / + pctg_lo = (policy->min - longrun_low_freq) / ((longrun_high_freq - longrun_low_freq) / 100); - pctg_hi = (policy->max - longrun_low_freq) / + pctg_hi = (policy->max - longrun_low_freq) / ((longrun_high_freq - longrun_low_freq) / 100); } @@ -118,7 +118,7 @@ * longrun_verify_poliy - verifies a new CPUFreq policy * @policy: the policy to verify * - * Validates a new CPUFreq policy. This function has to be called with + * Validates a new CPUFreq policy. This function has to be called with * cpufreq_driver locked. */ static int longrun_verify_policy(struct cpufreq_policy *policy) @@ -127,8 +127,8 @@ return -EINVAL; policy->cpu = 0; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && @@ -160,7 +160,7 @@ * TMTA rules: * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq) */ -static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, +static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, unsigned int *high_freq) { u32 msr_lo, msr_hi; @@ -174,9 +174,9 @@ if (cpu_has(c, X86_FEATURE_LRTI)) { /* if the LongRun Table Interface is present, the - * detection is a bit easier: + * detection is a bit easier: * For minimum frequency, read out the maximum - * level (msr_hi), write that into "currently + * level (msr_hi), write that into "currently * selected level", and read out the frequency. * For maximum frequency, read out level zero. */ @@ -223,7 +223,7 @@ cpuid(0x80860007, &eax, &ebx, &ecx, &edx); /* restore values */ - wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); + wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); } /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) @@ -237,7 +237,7 @@ if ((ecx > 95) || (ecx == 0) || (eax < ebx)) return -EIO; - edx = (eax - ebx) / (100 - ecx); + edx = (eax - ebx) / (100 - ecx); *low_freq = edx * 1000; /* back to kHz */ if (*low_freq > *high_freq) @@ -249,7 +249,7 @@ static int __init longrun_cpu_init(struct cpufreq_policy *policy) { - int result = 0; + int result = 0; /* capability check */ if (policy->cpu != 0) @@ -265,15 +265,15 @@ policy->cpuinfo.max_freq = longrun_high_freq; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; longrun_get_policy(policy); - + return 0; } static struct cpufreq_driver longrun_driver = { .flags = CPUFREQ_CONST_LOOPS, - .verify = longrun_verify_policy, - .setpolicy = longrun_set_policy, + .verify = longrun_verify_policy, + .setpolicy = longrun_set_policy, .get = longrun_get, .init = longrun_cpu_init, .name = "longrun", @@ -290,7 +290,7 @@ { struct cpuinfo_x86 *c = cpu_data; - if (c->x86_vendor != X86_VENDOR_TRANSMETA || + if (c->x86_vendor != X86_VENDOR_TRANSMETA || !cpu_has(c, X86_FEATURE_LONGRUN)) return -ENODEV; diff -Nru a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c 2004-10-18 14:57:03 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c 2004-10-18 14:57:03 -07:00 @@ -184,7 +184,7 @@ "The speedstep_centrino module offers voltage scaling" " in addition of frequency scaling. You should use " "that instead of p4-clockmod, if possible.\n"); - /* on P-4s, the TSC runs with constant frequency independent wether + /* on P-4s, the TSC runs with constant frequency independent whether * throttling is active or not. */ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); @@ -195,7 +195,7 @@ return 0; } - /* on P-4s, the TSC runs with constant frequency independent wether + /* on P-4s, the TSC runs with constant frequency independent whether * throttling is active or not. */ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c 2004-10-18 14:55:54 -07:00 @@ -6,8 +6,6 @@ * Licensed under the terms of the GNU GPL License version 2. * Based upon datasheets & sample CPUs kindly provided by AMD. * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - * * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt. * - We cli/sti on stepping A0 CPUs around the FID/VID transition. * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect. @@ -29,21 +27,13 @@ #include #include -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI #include #include #endif #include "powernow-k7.h" -#define DEBUG - -#ifdef DEBUG -#define dprintk(msg...) printk(msg) -#else -#define dprintk(msg...) do { } while(0) -#endif - #define PFX "powernow: " @@ -64,7 +54,7 @@ u8 numpstates; }; -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI union powernow_acpi_control_t { struct { unsigned long fid:5, @@ -97,6 +87,7 @@ */ static int acpi_force; +static int debug; static struct cpufreq_frequency_table *powernow_table; @@ -109,6 +100,21 @@ static unsigned int latency; static char have_a0; +static void dprintk(const char *fmt, ...) +{ + char s[256]; + va_list args; + + if (debug==0) + return; + + va_start(args,fmt); + vsprintf(s, fmt, args); + printk(s); + va_end(args); +} + + static int check_fsb(unsigned int fsbspeed) { int delta; @@ -190,13 +196,13 @@ speed = powernow_table[j].frequency; if ((fid_codes[fid] % 10)==5) { -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI if (have_a0 == 1) powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID; #endif } - dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); if (speed < minimum_speed) @@ -285,7 +291,7 @@ change_VID(vid); change_FID(fid); } - + if (have_a0 == 1) local_irq_enable(); @@ -294,7 +300,7 @@ } -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI struct acpi_processor_performance *acpi_processor_perf; @@ -377,7 +383,7 @@ powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; } - dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, mobile_vid_table[vid]%1000); @@ -467,9 +473,9 @@ (maxfid==pst->maxfid) && (startvid==pst->startvid)) { dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst); - dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid); - dprintk ("fsb: %d\t", pst->fsbspeed); - dprintk ("maxFID: 0x%x\t", pst->maxfid); + dprintk (KERN_INFO PFX " cpuid: 0x%x ", pst->cpuid); + dprintk ("fsb: %d ", pst->fsbspeed); + dprintk ("maxFID: 0x%x ", pst->maxfid); dprintk ("startvid: 0x%x\n", pst->startvid); ret = get_ranges ((char *) pst + sizeof (struct pst_s)); @@ -591,14 +597,14 @@ rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); /* A K7 with powernow technology is set to max frequency by BIOS */ - fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; + fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID]; if (!fsb) { printk(KERN_WARNING PFX "can not determine bus frequency\n"); return -EINVAL; } dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000); - if (dmi_check_system(powernow_dmi_table) || acpi_force) { + if (dmi_check_system(powernow_dmi_table) || acpi_force) { printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); result = powernow_acpi_init(); } else { @@ -628,7 +634,7 @@ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = 20 * latency / fsb; + policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency); policy->cur = powernow_get(0); @@ -648,14 +654,14 @@ }; static struct cpufreq_driver powernow_driver = { - .verify = powernow_verify, - .target = powernow_target, - .get = powernow_get, - .init = powernow_cpu_init, - .exit = powernow_cpu_exit, - .name = "powernow-k7", - .owner = THIS_MODULE, - .attr = powernow_table_attr, + .verify = powernow_verify, + .target = powernow_target, + .get = powernow_get, + .init = powernow_cpu_init, + .exit = powernow_cpu_exit, + .name = "powernow-k7", + .owner = THIS_MODULE, + .attr = powernow_table_attr, }; static int __init powernow_init (void) @@ -668,7 +674,7 @@ static void __exit powernow_exit (void) { -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI if (acpi_processor_perf) { acpi_processor_unregister_performance(acpi_processor_perf, 0); kfree(acpi_processor_perf); @@ -679,8 +685,10 @@ kfree(powernow_table); } +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "enable debug output."); module_param(acpi_force, int, 0444); -MODULE_PARM_DESC(acpi_force, "Force ACPI to be used"); +MODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); MODULE_AUTHOR ("Dave Jones "); MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2004-10-18 14:56:33 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2004-10-18 14:56:33 -07:00 @@ -32,7 +32,7 @@ #include #include -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI #include #include #endif @@ -664,7 +664,7 @@ return -ENODEV; } -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { if (!data->acpi_data.state_count) @@ -948,13 +948,13 @@ * an UP version, and is deprecated by AMD. */ - if (pol->cpu != 0) { - printk(KERN_ERR PFX "init not cpu 0\n"); + if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { + printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); kfree(data); return -ENODEV; } - if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { - printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); + if (pol->cpu != 0) { + printk(KERN_ERR PFX "init not cpu 0\n"); kfree(data); return -ENODEV; } @@ -1024,7 +1024,7 @@ return -ENODEV; } -static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol) +static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol) { struct powernow_k8_data *data = powernow_data[pol->cpu]; @@ -1076,7 +1076,7 @@ .verify = powernowk8_verify, .target = powernowk8_target, .init = powernowk8_cpu_init, - .exit = powernowk8_cpu_exit, + .exit = __devexit_p(powernowk8_cpu_exit), .get = powernowk8_get, .name = "powernow-k8", .owner = THIS_MODULE, diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h 2004-10-18 14:56:33 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h 2004-10-18 14:56:33 -07:00 @@ -29,7 +29,7 @@ * frequency is in kHz */ struct cpufreq_frequency_table *powernow_table; -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI /* the acpi table needs to be kept. it's only available if ACPI was * used to determine valid frequency/vid/fid states */ struct acpi_processor_performance acpi_data; diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c 2004-10-18 14:56:28 -07:00 @@ -10,7 +10,7 @@ * Copyright (C) 2003 Jeremy Fitzhardinge * * WARNING WARNING WARNING - * + * * This driver manipulates the PERF_CTL MSR, which is only somewhat * documented. While it seems to work on my laptop, it has not been * tested anywhere else, and it may not work for you, do strange @@ -23,6 +23,11 @@ #include #include +#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI +#include +#include +#endif + #include #include #include @@ -41,24 +46,24 @@ struct cpu_id { __u8 x86; /* CPU family */ - __u8 x86_vendor; /* CPU vendor */ __u8 x86_model; /* model */ __u8 x86_mask; /* stepping */ }; -static const struct cpu_id cpu_id_banias = { - .x86_vendor = X86_VENDOR_INTEL, - .x86 = 6, - .x86_model = 9, - .x86_mask = 5, +enum { + CPU_BANIAS, + CPU_DOTHAN_A1, + CPU_DOTHAN_A2, + CPU_DOTHAN_B0, }; -static const struct cpu_id cpu_id_dothan_a1 = { - .x86_vendor = X86_VENDOR_INTEL, - .x86 = 6, - .x86_model = 13, - .x86_mask = 1, +static const struct cpu_id cpu_ids[] = { + [CPU_BANIAS] = { 6, 9, 5 }, + [CPU_DOTHAN_A1] = { 6, 13, 1 }, + [CPU_DOTHAN_A2] = { 6, 13, 2 }, + [CPU_DOTHAN_B0] = { 6, 13, 6 }, }; +#define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0])) struct cpu_model { @@ -68,10 +73,11 @@ struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ }; -static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x); +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x); /* Operating points for current CPU */ static struct cpu_model *centrino_model; +static int centrino_cpu; #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE @@ -84,7 +90,7 @@ .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ } -/* +/* * These voltage tables were derived from the Intel Pentium M * datasheet, document 25261202.pdf, Table 5. I have verified they * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium @@ -103,9 +109,9 @@ /* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ static struct cpufreq_frequency_table banias_1000[] = { - OP(600, 844), - OP(800, 972), - OP(900, 988), + OP(600, 844), + OP(800, 972), + OP(900, 988), OP(1000, 1004), { .frequency = CPUFREQ_TABLE_END } }; @@ -135,7 +141,7 @@ }; /* Intel Pentium M processor 1.30GHz (Banias) */ -static struct cpufreq_frequency_table banias_1300[] = +static struct cpufreq_frequency_table banias_1300[] = { OP( 600, 956), OP( 800, 1260), @@ -146,7 +152,7 @@ }; /* Intel Pentium M processor 1.40GHz (Banias) */ -static struct cpufreq_frequency_table banias_1400[] = +static struct cpufreq_frequency_table banias_1400[] = { OP( 600, 956), OP( 800, 1180), @@ -157,7 +163,7 @@ }; /* Intel Pentium M processor 1.50GHz (Banias) */ -static struct cpufreq_frequency_table banias_1500[] = +static struct cpufreq_frequency_table banias_1500[] = { OP( 600, 956), OP( 800, 1116), @@ -169,7 +175,7 @@ }; /* Intel Pentium M processor 1.60GHz (Banias) */ -static struct cpufreq_frequency_table banias_1600[] = +static struct cpufreq_frequency_table banias_1600[] = { OP( 600, 956), OP( 800, 1036), @@ -199,13 +205,13 @@ .max_freq = (max)*1000, \ .op_points = banias_##max, \ } -#define BANIAS(max) _BANIAS(&cpu_id_banias, max, #max) +#define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) /* CPU models, their operating frequency range, and freq/voltage operating points */ -static struct cpu_model models[] = +static struct cpu_model models[] = { - _BANIAS(&cpu_id_banias, 900, " 900"), + _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), BANIAS(1000), BANIAS(1100), BANIAS(1200), @@ -214,6 +220,12 @@ BANIAS(1500), BANIAS(1600), BANIAS(1700), + + /* NULL model_name is a wildcard */ + { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, + { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, + { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, + { NULL, } }; #undef _BANIAS @@ -224,19 +236,30 @@ struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; struct cpu_model *model; - for(model = models; model->model_name != NULL; model++) - if ((strcmp(cpu->x86_model_id, model->model_name) == 0) && - (!centrino_verify_cpu_id(cpu, model->cpu_id))) + for(model = models; model->cpu_id != NULL; model++) + if (centrino_verify_cpu_id(cpu, model->cpu_id) && + (model->model_name == NULL || + strcmp(cpu->x86_model_id, model->model_name) == 0)) break; - if (model->model_name == NULL) { + + if (model->cpu_id == NULL) { + /* No match at all */ printk(KERN_INFO PFX "no support for CPU model \"%s\": " "send /proc/cpuinfo to " MAINTAINER "\n", cpu->x86_model_id); return -ENOENT; } + if (model->op_points == NULL) { + /* Matched a non-match */ + printk(KERN_INFO PFX "no table support for CPU model \"%s\": \n", + cpu->x86_model_id); + printk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n"); + return -ENOENT; + } + centrino_model = model; - + printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n", model->model_name, model->max_freq); @@ -247,31 +270,54 @@ static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; } #endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ -static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x) +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x) { if ((c->x86 == x->x86) && - (c->x86_vendor == x->x86_vendor) && (c->x86_model == x->x86_model) && (c->x86_mask == x->x86_mask)) - return 0; - return -ENODEV; + return 1; + return 0; } -/* Extract clock in kHz from PERF_CTL value */ +/* To be called only after centrino_model is initialized */ static unsigned extract_clock(unsigned msr) { - msr = (msr >> 8) & 0xff; - return msr * 100000; + int i; + + /* + * Extract clock in kHz from PERF_CTL value + * for centrino, as some DSDTs are buggy. + * Ideally, this can be done using the acpi_data structure. + */ + if (centrino_cpu) { + msr = (msr >> 8) & 0xff; + return msr * 100000; + } + + if ((!centrino_model) || (!centrino_model->op_points)) + return 0; + + msr &= 0xffff; + for (i=0;centrino_model->op_points[i].frequency != CPUFREQ_TABLE_END; i++) { + if (msr == centrino_model->op_points[i].index) + return centrino_model->op_points[i].frequency; + } + return 0; } /* Return the current CPU frequency in kHz */ static unsigned int get_cur_freq(unsigned int cpu) { unsigned l, h; - if (cpu) + cpumask_t saved_mask; + + saved_mask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (smp_processor_id() != cpu) return 0; rdmsr(MSR_IA32_PERF_STATUS, l, h); + set_cpus_allowed(current, saved_mask); return extract_clock(l); } @@ -280,13 +326,8 @@ static struct acpi_processor_performance p; -#include -#include - -#define ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP 0x1 - /* - * centrino_cpu_init_acpi - register with ACPI P-States library + * centrino_cpu_init_acpi - register with ACPI P-States library * * Register with the ACPI P-States library (part of drivers/acpi/processor.c) * in order to determine correct frequency and voltage pairings by reading @@ -296,7 +337,7 @@ { union acpi_object arg0 = {ACPI_TYPE_BUFFER}; u32 arg0_buf[3]; - struct acpi_object_list arg_list = {1, &arg0}; + struct acpi_object_list arg_list = {1, &arg0}; unsigned long cur_freq; int result = 0, i; @@ -305,12 +346,12 @@ arg0.buffer.pointer = (u8 *) arg0_buf; arg0_buf[0] = ACPI_PDC_REVISION_ID; arg0_buf[1] = 1; - arg0_buf[2] = ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP; + arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP | ACPI_PDC_EST_CAPABILITY_MSR; p.pdc = &arg_list; /* register with ACPI core */ - if (acpi_processor_register_performance(&p, 0)) + if (acpi_processor_register_performance(&p, policy->cpu)) return -EIO; /* verify the acpi_data */ @@ -318,7 +359,7 @@ printk(KERN_DEBUG "No P-States\n"); result = -ENODEV; goto err_unreg; - } + } if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || (p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { @@ -340,11 +381,10 @@ goto err_unreg; } - if (extract_clock(p.states[i].control) != - (p.states[i].core_frequency * 1000)) { - printk(KERN_DEBUG "Invalid encoded frequency\n"); - result = -EINVAL; - goto err_unreg; + if (p.states[i].core_frequency > p.states[0].core_frequency) { + printk(KERN_DEBUG "P%u has larger frequency than P0, skipping\n", i); + p.states[i].core_frequency = 0; + continue; } } @@ -357,29 +397,43 @@ centrino_model->model_name=NULL; centrino_model->max_freq = p.states[0].core_frequency * 1000; - centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * + centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * (p.state_count + 1), GFP_KERNEL); if (!centrino_model->op_points) { result = -ENOMEM; goto err_kfree; } - cur_freq = get_cur_freq(0); - for (i=0; iop_points[i].index = p.states[i].control; centrino_model->op_points[i].frequency = p.states[i].core_frequency * 1000; + } + centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; + + cur_freq = get_cur_freq(policy->cpu); + + for (i=0; iop_points[i].index) != + (centrino_model->op_points[i].frequency)) { + printk(KERN_DEBUG "Invalid encoded frequency\n"); + result = -EINVAL; + goto err_kfree_all; + } + if (cur_freq == centrino_model->op_points[i].frequency) p.state = i; + if (!p.states[i].core_frequency) + centrino_model->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; } - centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; return 0; + err_kfree_all: + kfree(centrino_model->op_points); err_kfree: kfree(centrino_model); err_unreg: - acpi_processor_unregister_performance(&p, 0); + acpi_processor_unregister_performance(&p, policy->cpu); return (result); } #else @@ -392,21 +446,30 @@ unsigned freq; unsigned l, h; int ret; + int i; - if (policy->cpu != 0) + /* Only Intel makes Enhanced Speedstep-capable CPUs */ + if (cpu->x86_vendor != X86_VENDOR_INTEL || !cpu_has(cpu, X86_FEATURE_EST)) return -ENODEV; - if (!cpu_has(cpu, X86_FEATURE_EST)) - return -ENODEV; + for (i = 0; i < N_IDS; i++) + if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) + break; - if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) && - (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) { - printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " - "send /proc/cpuinfo to " MAINTAINER "\n"); - return -ENODEV; - } + if (i != N_IDS) + centrino_cpu = 1; if (centrino_cpu_init_acpi(policy)) { + if (policy->cpu != 0) + return -ENODEV; + + if (!centrino_cpu) { + printk(KERN_INFO PFX "found unsupported CPU with " + "Enhanced SpeedStep: send /proc/cpuinfo to " + MAINTAINER "\n"); + return -ENODEV; + } + if (centrino_cpu_init_table(policy)) { return -ENODEV; } @@ -415,11 +478,11 @@ /* Check to see if Enhanced SpeedStep is enabled, and try to enable it if not. */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); - + if (!(l & (1<<16))) { l |= (1<<16); wrmsr(MSR_IA32_MISC_ENABLE, l, h); - + /* check to see if it stuck */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); if (!(l & (1<<16))) { @@ -428,7 +491,7 @@ } } - freq = get_cur_freq(0); + freq = get_cur_freq(policy->cpu); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */ @@ -436,7 +499,7 @@ dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n", policy->policy, policy->cur); - + ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points); if (ret) return (ret); @@ -455,7 +518,7 @@ #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI if (!centrino_model->model_name) { - acpi_processor_unregister_performance(&p, 0); + acpi_processor_unregister_performance(&p, policy->cpu); kfree(centrino_model->op_points); kfree(centrino_model); } @@ -493,19 +556,35 @@ unsigned int newstate = 0; unsigned int msr, oldmsr, h; struct cpufreq_freqs freqs; + cpumask_t saved_mask; + int retval; if (centrino_model == NULL) return -ENODEV; + /* + * Support for SMP systems. + * Make sure we are running on the CPU that wants to change frequency + */ + saved_mask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(policy->cpu)); + if (smp_processor_id() != policy->cpu) { + return(-EAGAIN); + } + if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq, - relation, &newstate)) - return -EINVAL; + relation, &newstate)) { + retval = -EINVAL; + goto migrate_end; + } msr = centrino_model->op_points[newstate].index; rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); - if (msr == (oldmsr & 0xffff)) - return 0; + if (msr == (oldmsr & 0xffff)) { + retval = 0; + goto migrate_end; + } /* Hm, old frequency can either be the last value we put in PERF_CTL, or whatever it is now. The trouble is that TM2 @@ -514,31 +593,34 @@ tell us something happened, but it may leave the things on the notifier chain confused; we therefore stick to using the last programmed speed rather than the current speed for - "old". + "old". TODO: work out how the TCC interrupts work, and try to catch the CPU changing things under us. */ - freqs.cpu = 0; + freqs.cpu = policy->cpu; freqs.old = extract_clock(oldmsr); freqs.new = extract_clock(msr); - + dprintk(KERN_INFO PFX "target=%dkHz old=%d new=%d msr=%04x\n", target_freq, freqs.old, freqs.new, msr); - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* all but 16 LSB are "reserved", so treat them with care */ oldmsr &= ~0xffff; msr &= 0xffff; oldmsr |= msr; - + wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - return 0; + retval = 0; +migrate_end: + set_cpus_allowed(current, saved_mask); + return (retval); } static struct freq_attr* centrino_attr[] = { @@ -547,12 +629,12 @@ }; static struct cpufreq_driver centrino_driver = { - .name = "centrino", /* should be speedstep-centrino, + .name = "centrino", /* should be speedstep-centrino, but there's a 16 char limit */ .init = centrino_cpu_init, .exit = centrino_cpu_exit, - .verify = centrino_verify, - .target = centrino_target, + .verify = centrino_verify, + .target = centrino_target, .get = get_cur_freq, .attr = centrino_attr, .owner = THIS_MODULE, diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c --- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c 2004-10-18 14:55:53 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c 2004-10-18 14:55:53 -07:00 @@ -7,7 +7,7 @@ * for chipsets ICH2-M and ICH3-M. * * Many thanks to Ducrot Bruno for finding and fixing the last - * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler + * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler * for extensive testing. * * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* @@ -19,7 +19,7 @@ *********************************************************************/ #include -#include +#include #include #include #include @@ -29,24 +29,24 @@ /* speedstep_chipset: - * It is necessary to know which chipset is used. As accesses to - * this device occur at various places in this module, we need a + * It is necessary to know which chipset is used. As accesses to + * this device occur at various places in this module, we need a * static struct pci_dev * pointing to that device. */ -static struct pci_dev *speedstep_chipset_dev; +static struct pci_dev *speedstep_chipset_dev; /* speedstep_processor */ -static unsigned int speedstep_processor = 0; +static unsigned int speedstep_processor = 0; -/* +/* * There are only two frequency states for each processor. Values * are in kHz for the time being. */ static struct cpufreq_frequency_table speedstep_freqs[] = { - {SPEEDSTEP_HIGH, 0}, + {SPEEDSTEP_HIGH, 0}, {SPEEDSTEP_LOW, 0}, {0, CPUFREQ_TABLE_END}, }; @@ -68,22 +68,21 @@ * speedstep_set_state - set the SpeedStep state * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * - * Tries to change the SpeedStep state. + * Tries to change the SpeedStep state. */ static void speedstep_set_state (unsigned int state) { - u32 pmbase; - u8 pm2_blk; - u8 value; - unsigned long flags; + u32 pmbase; + u8 pm2_blk; + u8 value; + unsigned long flags; if (!speedstep_chipset_dev || (state > 0x1)) return; /* get PMBASE */ pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); - if (!(pmbase & 0x01)) - { + if (!(pmbase & 0x01)) { printk(KERN_ERR "cpufreq: could not find speedstep register\n"); return; } @@ -146,18 +145,16 @@ */ static int speedstep_activate (void) { - u16 value = 0; + u16 value = 0; if (!speedstep_chipset_dev) return -EINVAL; - pci_read_config_word(speedstep_chipset_dev, - 0x00A0, &value); + pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); if (!(value & 0x08)) { value |= 0x08; dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n"); - pci_write_config_word(speedstep_chipset_dev, - 0x00A0, value); + pci_write_config_word(speedstep_chipset_dev, 0x00A0, value); } return 0; @@ -167,15 +164,15 @@ /** * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic * - * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to - * the LPC bridge / PM module which contains all power-management + * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to + * the LPC bridge / PM module which contains all power-management * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected * chipset, or zero on failure. */ static unsigned int speedstep_detect_chipset (void) { speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82801DB_12, + PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, NULL); @@ -183,7 +180,7 @@ return 4; /* 4-M */ speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82801CA_12, + PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, NULL); @@ -198,11 +195,11 @@ NULL); if (speedstep_chipset_dev) { /* speedstep.c causes lockups on Dell Inspirons 8000 and - * 8100 which use a pretty old revision of the 82815 + * 8100 which use a pretty old revision of the 82815 * host brige. Abort on these systems. */ - static struct pci_dev *hostbridge; - u8 rev = 0; + static struct pci_dev *hostbridge; + u8 rev = 0; hostbridge = pci_find_subsys(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_MC, @@ -212,7 +209,7 @@ if (!hostbridge) return 2; /* 2-M */ - + pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev); if (rev < 5) { dprintk(KERN_INFO "cpufreq: hostbridge does not support speedstep\n"); @@ -226,6 +223,23 @@ return 0; } +static unsigned int speedstep_get(unsigned int cpu) +{ + unsigned int speed; + cpumask_t cpus_allowed,affected_cpu_map; + + /* only run on CPU to be set, or on its sibling */ + cpus_allowed = current->cpus_allowed; +#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); + speed=speedstep_get_processor_frequency(speedstep_processor); + set_cpus_allowed(current, cpus_allowed); + return speed; +} /** * speedstep_target - set a new CPUFreq policy @@ -239,7 +253,7 @@ unsigned int target_freq, unsigned int relation) { - unsigned int newstate = 0; + unsigned int newstate = 0; struct cpufreq_freqs freqs; cpumask_t cpus_allowed, affected_cpu_map; int i; @@ -247,14 +261,14 @@ if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) return -EINVAL; + freqs.old = speedstep_get(policy->cpu); + freqs.new = speedstep_freqs[newstate].frequency; + freqs.cpu = policy->cpu; + /* no transition necessary */ if (freqs.old == freqs.new) return 0; - freqs.old = speedstep_get_processor_frequency(speedstep_processor); - freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = policy->cpu; - cpus_allowed = current->cpus_allowed; /* only run on CPU to be set, or on its sibling */ @@ -301,9 +315,9 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) { - int result = 0; - unsigned int speed; - cpumask_t cpus_allowed,affected_cpu_map; + int result = 0; + unsigned int speed; + cpumask_t cpus_allowed,affected_cpu_map; /* capability check */ @@ -324,18 +338,16 @@ &speedstep_freqs[SPEEDSTEP_LOW].frequency, &speedstep_freqs[SPEEDSTEP_HIGH].frequency, &speedstep_set_state); - if (result) { - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed(current, cpus_allowed); + if (result) return result; - } /* get current speed setting */ - speed = speedstep_get_processor_frequency(speedstep_processor); - set_cpus_allowed(current, cpus_allowed); + speed = speedstep_get(policy->cpu); if (!speed) return -EIO; - dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", + dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed / 1000)); @@ -360,11 +372,6 @@ return 0; } -static unsigned int speedstep_get(unsigned int cpu) -{ - return speedstep_get_processor_frequency(speedstep_processor); -} - static struct freq_attr* speedstep_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, NULL, @@ -372,14 +379,14 @@ static struct cpufreq_driver speedstep_driver = { - .name = "speedstep-ich", - .verify = speedstep_verify, - .target = speedstep_target, - .init = speedstep_cpu_init, - .exit = speedstep_cpu_exit, - .get = speedstep_get, - .owner = THIS_MODULE, - .attr = speedstep_attr, + .name = "speedstep-ich", + .verify = speedstep_verify, + .target = speedstep_target, + .init = speedstep_cpu_init, + .exit = speedstep_cpu_exit, + .get = speedstep_get, + .owner = THIS_MODULE, + .attr = speedstep_attr, }; diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c --- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c 2004-10-18 14:56:29 -07:00 @@ -115,6 +115,11 @@ : "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi) : "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0) ); + + /* abort if results are obviously incorrect... */ + if ((high_mhz + low_mhz) < 600) + return -EINVAL; + *high = high_mhz * 1000; *low = low_mhz * 1000; @@ -180,7 +185,7 @@ local_irq_restore(flags); if (new_state == state) { - dprintk(KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n", (freqs.new / 1000), retry, result); + dprintk(KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result); } else { printk(KERN_ERR "cpufreq: change failed with new_state %u and result %u\n", new_state, result); } diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c --- a/arch/i386/kernel/cpu/intel.c 2004-10-18 14:56:27 -07:00 +++ b/arch/i386/kernel/cpu/intel.c 2004-10-18 14:56:27 -07:00 @@ -72,41 +72,44 @@ /* all the cache descriptor types we care about (no TLB or trace cache entries) */ static struct _cache_table cache_table[] __initdata = { - { 0x06, LVL_1_INST, 8 }, - { 0x08, LVL_1_INST, 16 }, - { 0x0a, LVL_1_DATA, 8 }, - { 0x0c, LVL_1_DATA, 16 }, - { 0x22, LVL_3, 512 }, - { 0x23, LVL_3, 1024 }, - { 0x25, LVL_3, 2048 }, - { 0x29, LVL_3, 4096 }, - { 0x2c, LVL_1_DATA, 32 }, - { 0x30, LVL_1_INST, 32 }, - { 0x39, LVL_2, 128 }, - { 0x3b, LVL_2, 128 }, - { 0x3c, LVL_2, 256 }, - { 0x41, LVL_2, 128 }, - { 0x42, LVL_2, 256 }, - { 0x43, LVL_2, 512 }, - { 0x44, LVL_2, 1024 }, - { 0x45, LVL_2, 2048 }, - { 0x60, LVL_1_DATA, 16 }, - { 0x66, LVL_1_DATA, 8 }, - { 0x67, LVL_1_DATA, 16 }, - { 0x68, LVL_1_DATA, 32 }, - { 0x70, LVL_TRACE, 12 }, - { 0x71, LVL_TRACE, 16 }, - { 0x72, LVL_TRACE, 32 }, - { 0x79, LVL_2, 128 }, - { 0x7a, LVL_2, 256 }, - { 0x7b, LVL_2, 512 }, - { 0x7c, LVL_2, 1024 }, - { 0x82, LVL_2, 256 }, - { 0x83, LVL_2, 512 }, - { 0x84, LVL_2, 1024 }, - { 0x85, LVL_2, 2048 }, - { 0x86, LVL_2, 512 }, - { 0x87, LVL_2, 1024 }, + { 0x06, LVL_1_INST, 8 }, /* 4-way set assoc, 32 byte line size */ + { 0x08, LVL_1_INST, 16 }, /* 4-way set assoc, 32 byte line size */ + { 0x0a, LVL_1_DATA, 8 }, /* 2 way set assoc, 32 byte line size */ + { 0x0c, LVL_1_DATA, 16 }, /* 4-way set assoc, 32 byte line size */ + { 0x22, LVL_3, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */ + { 0x23, LVL_3, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x25, LVL_3, 2048 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x29, LVL_3, 4096 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x2c, LVL_1_DATA, 32 }, /* 8-way set assoc, 64 byte line size */ + { 0x30, LVL_1_INST, 32 }, /* 8-way set assoc, 64 byte line size */ + { 0x39, LVL_2, 128 }, /* 4-way set assoc, sectored cache, 64 byte line size */ + { 0x3b, LVL_2, 128 }, /* 2-way set assoc, sectored cache, 64 byte line size */ + { 0x3c, LVL_2, 256 }, /* 4-way set assoc, sectored cache, 64 byte line size */ + { 0x41, LVL_2, 128 }, /* 4-way set assoc, 32 byte line size */ + { 0x42, LVL_2, 256 }, /* 4-way set assoc, 32 byte line size */ + { 0x43, LVL_2, 512 }, /* 4-way set assoc, 32 byte line size */ + { 0x44, LVL_2, 1024 }, /* 4-way set assoc, 32 byte line size */ + { 0x45, LVL_2, 2048 }, /* 4-way set assoc, 32 byte line size */ + { 0x60, LVL_1_DATA, 16 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x66, LVL_1_DATA, 8 }, /* 4-way set assoc, sectored cache, 64 byte line size */ + { 0x67, LVL_1_DATA, 16 }, /* 4-way set assoc, sectored cache, 64 byte line size */ + { 0x68, LVL_1_DATA, 32 }, /* 4-way set assoc, sectored cache, 64 byte line size */ + { 0x70, LVL_TRACE, 12 }, /* 8-way set assoc */ + { 0x71, LVL_TRACE, 16 }, /* 8-way set assoc */ + { 0x72, LVL_TRACE, 32 }, /* 8-way set assoc */ + { 0x78, LVL_2, 1024 }, /* 4-way set assoc, 64 byte line size */ + { 0x79, LVL_2, 128 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7a, LVL_2, 256 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7b, LVL_2, 512 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7c, LVL_2, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7d, LVL_2, 2048 }, /* 8-way set assoc, 64 byte line size */ + { 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */ + { 0x82, LVL_2, 256 }, /* 8-way set assoc, 32 byte line size */ + { 0x83, LVL_2, 512 }, /* 8-way set assoc, 32 byte line size */ + { 0x84, LVL_2, 1024 }, /* 8-way set assoc, 32 byte line size */ + { 0x85, LVL_2, 2048 }, /* 8-way set assoc, 32 byte line size */ + { 0x86, LVL_2, 512 }, /* 4-way set assoc, 64 byte line size */ + { 0x87, LVL_2, 1024 }, /* 8-way set assoc, 64 byte line size */ { 0x00, 0, 0} }; diff -Nru a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h --- a/arch/i386/kernel/cpu/mtrr/mtrr.h 2004-10-18 14:56:20 -07:00 +++ b/arch/i386/kernel/cpu/mtrr/mtrr.h 2004-10-18 14:56:20 -07:00 @@ -52,7 +52,6 @@ }; extern int generic_get_free_region(unsigned long base, unsigned long size); -extern void generic_init_secondary(void); extern int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type); diff -Nru a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c --- a/arch/i386/kernel/cpu/proc.c 2004-10-18 14:57:03 -07:00 +++ b/arch/i386/kernel/cpu/proc.c 2004-10-18 14:57:03 -07:00 @@ -44,8 +44,8 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ - "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "tm2", - "est", NULL, "cid", NULL, NULL, NULL, NULL, NULL, + "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "est", + "tm2", NULL, "cid", NULL, NULL, NULL, "xtpr", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c --- a/arch/i386/kernel/dmi_scan.c 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/kernel/dmi_scan.c 2004-10-18 14:56:28 -07:00 @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -163,27 +163,6 @@ #define MATCH DMI_MATCH /* - * Some machines, usually laptops, can't handle an enabled local APIC. - * The symptoms include hangs or reboots when suspending or resuming, - * attaching or detaching the power cord, or entering BIOS setup screens - * through magic key sequences. - */ -static int __init local_apic_kills_bios(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int enable_local_apic; - if (enable_local_apic == 0) { - enable_local_apic = -1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "Refusing to enable the local APIC.\n", - d->ident); - } -#endif - return 0; -} - - -/* * Toshiba keyboard likes to repeat keys when they are not repeated. */ @@ -284,32 +263,6 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={ - /* Machines which have problems handling enabled local APICs */ - - { local_apic_kills_bios, "Dell Inspiron", { - MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - MATCH(DMI_PRODUCT_NAME, "Inspiron"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "Dell Latitude", { - MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - MATCH(DMI_PRODUCT_NAME, "Latitude"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "IBM Thinkpad T20", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_BOARD_NAME, "264741U"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "ASUS L3C", { - MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - MATCH(DMI_BOARD_NAME, "P4_L3C"), - NO_MATCH, NO_MATCH - } }, - { broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */ MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), NO_MATCH, NO_MATCH, NO_MATCH @@ -490,41 +443,6 @@ { NULL, } }; - - -/* - * Walk the blacklist table running matching functions until someone - * returns 1 or we hit the end. - */ - - -static __init void dmi_check_blacklist(void) -{ -#ifdef CONFIG_ACPI_BOOT -#define ACPI_BLACKLIST_CUTOFF_YEAR 2001 - - if (dmi_ident[DMI_BIOS_DATE]) { - char *s = strrchr(dmi_ident[DMI_BIOS_DATE], '/'); - if (s) { - int year, disable = 0; - s++; - year = simple_strtoul(s,NULL,0); - if (year >= 1000) - disable = year < ACPI_BLACKLIST_CUTOFF_YEAR; - else if (year < 1 || (year > 90 && year <= 99)) - disable = 1; - if (disable && !acpi_force) { - printk(KERN_NOTICE "ACPI disabled because your bios is from %s and too old\n", s); - printk(KERN_NOTICE "You can enable it with acpi=force\n"); - disable_acpi(); - } - } - } -#endif - dmi_check_system(dmi_blacklist); -} - - /* * Process a DMI table entry. Right now all we care about are the BIOS @@ -582,7 +500,7 @@ { int err = dmi_iterate(dmi_decode); if(err == 0) - dmi_check_blacklist(); + dmi_check_system(dmi_blacklist); else printk(KERN_INFO "DMI not present.\n"); } diff -Nru a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c --- a/arch/i386/kernel/doublefault.c 2004-10-18 14:55:55 -07:00 +++ b/arch/i386/kernel/doublefault.c 2004-10-18 14:55:55 -07:00 @@ -13,7 +13,7 @@ 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 + 0x1000000) static void doublefault_fn(void) { diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S 2004-10-18 14:56:27 -07:00 +++ b/arch/i386/kernel/entry.S 2004-10-18 14:56:27 -07:00 @@ -255,11 +255,11 @@ pushl %eax SAVE_ALL GET_THREAD_INFO(%ebp) - cmpl $(nr_syscalls), %eax - jae syscall_badsys testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry + cmpl $(nr_syscalls), %eax + jae syscall_badsys call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) cli @@ -278,11 +278,11 @@ pushl %eax # save orig_eax SAVE_ALL GET_THREAD_INFO(%ebp) - cmpl $(nr_syscalls), %eax - jae syscall_badsys # system call tracing in operation testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry + cmpl $(nr_syscalls), %eax + jae syscall_badsys syscall_call: call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) # store the return value @@ -348,7 +348,7 @@ # perform syscall exit tracing ALIGN syscall_exit_work: - testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %cl + testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl jz work_pending sti # could let do_syscall_trace() call # schedule() instead @@ -489,9 +489,16 @@ jne debug_stack_correct FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn) debug_stack_correct: - pushl $0 - pushl $do_debug - jmp error_code + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx + pushl $0 + pushl %edx + call do_debug + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception /* * NMI is doubly nasty. It can happen _while_ we're handling @@ -540,9 +547,16 @@ jmp nmi_stack_correct ENTRY(int3) + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx pushl $0 - pushl $do_int3 - jmp error_code + pushl %edx + call do_int3 + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception ENTRY(overflow) pushl $0 @@ -886,5 +900,6 @@ .long sys_mq_notify .long sys_mq_getsetattr .long sys_ni_syscall /* reserved for kexec */ + .long sys_waitid syscall_table_size=(.-sys_call_table) diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S --- a/arch/i386/kernel/head.S 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/head.S 2004-10-18 14:55:54 -07:00 @@ -521,6 +521,3 @@ .quad 0x0000000000000000 /* 0xf0 - unused */ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ -#ifdef CONFIG_SMP - .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ -#endif diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c 2004-10-18 14:57:04 -07:00 +++ b/arch/i386/kernel/i386_ksyms.c 2004-10-18 14:57:04 -07:00 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -87,10 +87,10 @@ EXPORT_SYMBOL(cpu_khz); EXPORT_SYMBOL(apm_info); -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ @@ -99,9 +99,9 @@ EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL_NOVERS(__get_user_1); -EXPORT_SYMBOL_NOVERS(__get_user_2); -EXPORT_SYMBOL_NOVERS(__get_user_4); +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); @@ -142,8 +142,8 @@ EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_callout_map); -EXPORT_SYMBOL_NOVERS(__write_lock_failed); -EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(__write_lock_failed); +EXPORT_SYMBOL(__read_lock_failed); /* Global SMP stuff */ EXPORT_SYMBOL(synchronize_irq); @@ -175,8 +175,9 @@ #undef memcmp extern int memcmp(const void *,const void *,__kernel_size_t); -EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(register_die_notifier); #ifdef CONFIG_HAVE_DEC_LOCK EXPORT_SYMBOL(atomic_dec_and_lock); #endif diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c --- a/arch/i386/kernel/i8259.c 2004-10-18 14:57:03 -07:00 +++ b/arch/i386/kernel/i8259.c 2004-10-18 14:57:03 -07:00 @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -12,10 +11,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -225,7 +226,7 @@ * lets ACK and report it. [once per IRQ] */ if (!(spurious_irq_mask & irqmask)) { - printk("spurious 8259A interrupt: IRQ%d.\n", irq); + printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } atomic_inc(&irq_err_count); @@ -238,14 +239,39 @@ } } +static char irq_trigger[2]; +/** + * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ + */ +static void restore_ELCR(char *trigger) +{ + outb(trigger[0], 0x4d0); + outb(trigger[1], 0x4d1); +} + +static void save_ELCR(char *trigger) +{ + /* IRQ 0,1,2,8,13 are marked as reserved */ + trigger[0] = inb(0x4d0) & 0xF8; + trigger[1] = inb(0x4d1) & 0xDE; +} + static int i8259A_resume(struct sys_device *dev) { init_8259A(0); + restore_ELCR(irq_trigger); + return 0; +} + +static int i8259A_suspend(struct sys_device *dev, u32 state) +{ + save_ELCR(irq_trigger); return 0; } static struct sysdev_class i8259_sysdev_class = { set_kset_name("i8259"), + .suspend = i8259A_suspend, .resume = i8259A_resume, }; @@ -362,46 +388,6 @@ } } -static void setup_timer(void) -{ - extern spinlock_t i8253_lock; - unsigned long flags; - - spin_lock_irqsave(&i8253_lock, flags); - outb_p(0x34,PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ - udelay(10); - outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ - udelay(10); - outb(LATCH >> 8 , PIT_CH0); /* MSB */ - spin_unlock_irqrestore(&i8253_lock, flags); -} - -static int timer_resume(struct sys_device *dev) -{ - setup_timer(); - return 0; -} - -static struct sysdev_class timer_sysclass = { - set_kset_name("timer"), - .resume = timer_resume, -}; - -static struct sys_device device_timer = { - .id = 0, - .cls = &timer_sysclass, -}; - -static int __init init_timer_sysfs(void) -{ - int error = sysdev_class_register(&timer_sysclass); - if (!error) - error = sysdev_register(&device_timer); - return error; -} - -device_initcall(init_timer_sysfs); - void __init init_IRQ(void) { int i; @@ -431,7 +417,7 @@ * Set the clock to HZ Hz, we already have a valid * vector now: */ - setup_timer(); + setup_pit_timer(); /* * External FPU? Set up irq13 if so, for diff -Nru a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c --- a/arch/i386/kernel/init_task.c 2004-10-18 14:57:04 -07:00 +++ b/arch/i386/kernel/init_task.c 2004-10-18 14:57:04 -07:00 @@ -40,10 +40,7 @@ /* * per-CPU TSS segments. Threads are completely 'soft' on Linux, - * no more per-task TSS's. The TSS size is kept cacheline-aligned - * so they are allowed to end up in the .data.cacheline_aligned - * section. Since TSS's are completely CPU-local, we want them - * on exact cacheline boundaries, to eliminate cacheline ping-pong. + * no more per-task TSS's. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS; diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/kernel/io_apic.c 2004-10-18 14:56:28 -07:00 @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -85,7 +86,7 @@ * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void __init add_pin_to_irq(unsigned int irq, int apic, int pin) +static void add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; @@ -705,13 +706,15 @@ pirq_entries[i] = -1; pirqs_enabled = 1; - printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); + apic_printk(APIC_VERBOSE, KERN_INFO + "PIRQ redirection, working around broken MP-BIOS.\n"); max = MAX_PIRQS; if (ints[0] < MAX_PIRQS) max = ints[0]; for (i = 0; i < max; i++) { - printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); + apic_printk(APIC_VERBOSE, KERN_DEBUG + "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* * PIRQs are mapped upside down, usually. */ @@ -742,7 +745,7 @@ /* * Find the pin to which IRQ[irq] (ISA) is connected */ -static int __init find_isa_irq_pin(int irq, int type) +static int find_isa_irq_pin(int irq, int type) { int i; @@ -772,8 +775,8 @@ { int apic, i, best_guess = -1; - Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", - bus, slot, pin); + apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " + "slot:%d, pin:%d.\n", bus, slot, pin); if (mp_bus_id_to_pci_bus[bus] == -1) { printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); return -1; @@ -841,7 +844,8 @@ unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } - printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); + apic_printk(APIC_VERBOSE, KERN_INFO + "Broken MPtable reports ISA irq %d\n", irq); return 0; } @@ -1083,10 +1087,12 @@ if ((pin >= 16) && (pin <= 23)) { if (pirq_entries[pin-16] != -1) { if (!pirq_entries[pin-16]) { - printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); + apic_printk(APIC_VERBOSE, KERN_DEBUG + "disabling PIRQ%d\n", pin-16); } else { irq = pirq_entries[pin-16]; - printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", + apic_printk(APIC_VERBOSE, KERN_DEBUG + "using PIRQ%d -> IRQ %d\n", pin-16, irq); } } @@ -1114,11 +1120,7 @@ /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; -#ifdef CONFIG_PCI_MSI int assign_irq_vector(int irq) -#else -int __init assign_irq_vector(int irq) -#endif { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; @@ -1176,7 +1178,7 @@ int apic, pin, idx, irq, first_notcon = 1, vector; unsigned long flags; - printk(KERN_DEBUG "init IO_APIC IRQs\n"); + apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -1195,10 +1197,14 @@ idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, KERN_DEBUG + " IO-APIC (apicid-pin) %d-%d", + mp_ioapics[apic].mpc_apicid, + pin); first_notcon = 0; } else - printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, ", %d-%d", + mp_ioapics[apic].mpc_apicid, pin); continue; } @@ -1239,7 +1245,7 @@ } if (!first_notcon) - printk(" not connected.\n"); + apic_printk(APIC_VERBOSE, " not connected.\n"); } /* @@ -1299,6 +1305,9 @@ union IO_APIC_reg_03 reg_03; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", @@ -1441,6 +1450,9 @@ unsigned int v; int i, j; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); for (i = 0; i < 8; i++) { v = apic_read(base + i*0x10); @@ -1458,6 +1470,9 @@ { unsigned int v, ver, maxlvt; + if (apic_verbosity == APIC_QUIET) + return; + printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", smp_processor_id(), hard_smp_processor_id()); v = apic_read(APIC_ID); @@ -1545,6 +1560,9 @@ unsigned int v; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "\nprinting PIC contents\n"); spin_lock_irqsave(&i8259A_lock, flags); @@ -1680,7 +1698,9 @@ } else { physid_mask_t tmp; tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid); - printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, "Setting %d in the " + "phys_id_present_map\n", + mp_ioapics[apic].mpc_apicid); physids_or(phys_id_present_map, phys_id_present_map, tmp); } @@ -1699,8 +1719,9 @@ * Read the right value from the MPC table and * write it into the ID register. */ - printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", - mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, KERN_INFO + "...changing IO-APIC physical APIC ID to %d ...", + mp_ioapics[apic].mpc_apicid); reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; spin_lock_irqsave(&ioapic_lock, flags); @@ -1714,9 +1735,9 @@ reg_00.raw = io_apic_read(apic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) - panic("could not set ID!\n"); + printk("could not set ID!\n"); else - printk(" ok.\n"); + apic_printk(APIC_VERBOSE, " ok.\n"); } } #else @@ -2031,11 +2052,11 @@ * is from Maciej W. Rozycki - so we do not have to EOI from * the NMI handler or the timer interrupt. */ - printk(KERN_INFO "activating NMI Watchdog ..."); + apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ..."); on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1); - printk(" done.\n"); + apic_printk(APIC_VERBOSE, " done.\n"); } /* @@ -2212,7 +2233,8 @@ return; } printk(" failed :(.\n"); - panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); + panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " + "report. Then try booting with the 'noapic' option"); } /* @@ -2262,6 +2284,98 @@ late_initcall(io_apic_bug_finalize); +struct sysfs_ioapic_data { + struct sys_device dev; + struct IO_APIC_route_entry entry[0]; +}; +static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; + +static int ioapic_suspend(struct sys_device *dev, u32 state) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + spin_lock_irqsave(&ioapic_lock, flags); + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i); + *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static int ioapic_resume(struct sys_device *dev) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + union IO_APIC_reg_00 reg_00; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + + spin_lock_irqsave(&ioapic_lock, flags); + reg_00.raw = io_apic_read(dev->id, 0); + if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { + reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; + io_apic_write(dev->id, 0, reg_00.raw); + } + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1)); + io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0)); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static struct sysdev_class ioapic_sysdev_class = { + set_kset_name("ioapic"), + .suspend = ioapic_suspend, + .resume = ioapic_resume, +}; + +static int __init ioapic_init_sysfs(void) +{ + struct sys_device * dev; + int i, size, error = 0; + + error = sysdev_class_register(&ioapic_sysdev_class); + if (error) + return error; + + for (i = 0; i < nr_ioapics; i++ ) { + size = sizeof(struct sys_device) + nr_ioapic_registers[i] + * sizeof(struct IO_APIC_route_entry); + mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); + if (!mp_ioapic_data[i]) { + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + memset(mp_ioapic_data[i], 0, size); + dev = &mp_ioapic_data[i]->dev; + dev->id = i; + dev->cls = &ioapic_sysdev_class; + error = sysdev_register(dev); + if (error) { + kfree(mp_ioapic_data[i]); + mp_ioapic_data[i] = NULL; + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + } + + return 0; +} + +device_initcall(ioapic_init_sysfs); + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ @@ -2334,7 +2448,8 @@ panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); } - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); + apic_printk(APIC_VERBOSE, KERN_INFO + "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } @@ -2400,19 +2515,12 @@ entry.vector = assign_irq_vector(irq); - Dprintk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " - "IRQ %d Mode:%i Active:%i)\n", ioapic, - mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); - - if (use_pci_vector() && !platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); - if (edge_level) { - irq_desc[irq].handler = &ioapic_level_type; - } else { - irq_desc[irq].handler = &ioapic_edge_type; - } + apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " + "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, + mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, + edge_level, active_high_low); - set_intr_gate(entry.vector, interrupt[irq]); + ioapic_register_intr(irq, entry.vector, edge_level); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); diff -Nru a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c --- a/arch/i386/kernel/ioport.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/kernel/ioport.c 2004-10-18 14:56:29 -07:00 @@ -56,6 +56,7 @@ */ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) { + unsigned long i, max_long, bytes, bytes_updated; struct thread_struct * t = ¤t->thread; struct tss_struct * tss; unsigned long *bitmap; @@ -81,16 +82,37 @@ /* * do it in the per-thread copy and in the TSS ... + * + * Disable preemption via get_cpu() - we must not switch away + * because the ->io_bitmap_max value must match the bitmap + * contents: */ + tss = &per_cpu(init_tss, get_cpu()); + set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); - tss = init_tss + get_cpu(); - if (tss->io_bitmap_base == IO_BITMAP_OFFSET) { /* already active? */ - set_bitmap(tss->io_bitmap, from, num, !turn_on); - } else { - memcpy(tss->io_bitmap, t->io_bitmap_ptr, IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; /* Activate it in the TSS */ - } + + /* + * Search for a (possibly new) maximum. This is simple and stupid, + * to keep it obviously correct: + */ + max_long = 0; + for (i = 0; i < IO_BITMAP_LONGS; i++) + if (t->io_bitmap_ptr[i] != ~0UL) + max_long = i; + + bytes = (max_long + 1) * sizeof(long); + bytes_updated = max(bytes, t->io_bitmap_max); + + t->io_bitmap_max = bytes; + + /* + * Sets the lazy trigger so that the next I/O operation will + * reload the correct bitmap. + */ + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; + put_cpu(); + return 0; } diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c --- a/arch/i386/kernel/irq.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/irq.c 2004-10-18 14:55:54 -07:00 @@ -220,14 +220,16 @@ struct pt_regs *regs, struct irqaction *action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -1025,32 +1027,6 @@ } #endif - -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -1086,27 +1062,13 @@ #endif } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); - - /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; - + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. */ diff -Nru a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/i386/kernel/kprobes.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,349 @@ +/* + * Kernel Probes (KProbes) + * arch/i386/kernel/kprobes.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2002, 2004 + * + * 2002-Oct Created by Vamsi Krishna S Kernel + * Probes initial implementation ( includes contributions from + * Rusty Russell). + * 2004-July Suparna Bhattacharya added jumper probes + * interface to access function arguments. + */ + +#include +#include +#include +#include +#include +#include + +/* kprobe_status settings */ +#define KPROBE_HIT_ACTIVE 0x00000001 +#define KPROBE_HIT_SS 0x00000002 + +static struct kprobe *current_kprobe; +static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; +static struct pt_regs jprobe_saved_regs; +static long *jprobe_saved_esp; +/* copy of the kernel stack at the probe fire time */ +static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; + +/* + * returns non-zero if opcode modifies the interrupt flag. + */ +static inline int is_IF_modifier(kprobe_opcode_t opcode) +{ + switch (opcode) { + case 0xfa: /* cli */ + case 0xfb: /* sti */ + case 0xcf: /* iret/iretd */ + case 0x9d: /* popf/popfd */ + return 1; + } + return 0; +} + +void arch_prepare_kprobe(struct kprobe *p) +{ + memcpy(p->insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); +} + +static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + *p->addr = p->opcode; + regs->eip = (unsigned long)p->addr; +} + +static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->eflags |= TF_MASK; + regs->eflags &= ~IF_MASK; + regs->eip = (unsigned long)&p->insn; +} + +/* + * Interrupts are disabled on entry as trap3 is an interrupt gate and they + * remain disabled thorough out this function. + */ +static inline int kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + int ret = 0; + u8 *addr = (u8 *) (regs->eip - 1); + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + /* Check we're not actually recursing */ + if (kprobe_running()) { + /* We *are* holding lock here, so this is safe. + Disarm the probe we just hit, and ignore it. */ + p = get_kprobe(addr); + if (p) { + disarm_kprobe(p, regs); + ret = 1; + } else { + p = current_kprobe; + if (p->break_handler && p->break_handler(p, regs)) { + goto ss_probe; + } + } + /* If it's not ours, can't be delete race, (we hold lock). */ + goto no_kprobe; + } + + lock_kprobes(); + p = get_kprobe(addr); + if (!p) { + unlock_kprobes(); + if (*addr != BREAKPOINT_INSTRUCTION) { + /* + * The breakpoint instruction was removed right + * after we hit it. Another cpu has removed + * either a probepoint or a debugger breakpoint + * at this address. In either case, no further + * handling of this interrupt is appropriate. + */ + ret = 1; + } + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + kprobe_status = KPROBE_HIT_ACTIVE; + current_kprobe = p; + kprobe_saved_eflags = kprobe_old_eflags + = (regs->eflags & (TF_MASK | IF_MASK)); + if (is_IF_modifier(p->opcode)) + kprobe_saved_eflags &= ~IF_MASK; + + if (p->pre_handler(p, regs)) { + /* handler has already set things up, so skip ss setup */ + return 1; + } + + ss_probe: + prepare_singlestep(p, regs); + kprobe_status = KPROBE_HIT_SS; + return 1; + + no_kprobe: + preempt_enable_no_resched(); + return ret; +} + +/* + * Called after single-stepping. p->addr is the address of the + * instruction whose first byte has been replaced by the "int 3" + * instruction. To avoid the SMP problems that can occur when we + * temporarily put back the original opcode to single-step, we + * single-stepped a copy of the instruction. The address of this + * copy is p->insn. + * + * This function prepares to return from the post-single-step + * interrupt. We have to fix up the stack as follows: + * + * 0) Except in the case of absolute or indirect jump or call instructions, + * the new eip is relative to the copied instruction. We need to make + * it relative to the original instruction. + * + * 1) If the single-stepped instruction was pushfl, then the TF and IF + * flags are set in the just-pushed eflags, and may need to be cleared. + * + * 2) If the single-stepped instruction was a call, the return address + * that is atop the stack is the address following the copied instruction. + * We need to make it the address following the original instruction. + */ +static void resume_execution(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long *tos = (unsigned long *)®s->esp; + unsigned long next_eip = 0; + unsigned long copy_eip = (unsigned long)&p->insn; + unsigned long orig_eip = (unsigned long)p->addr; + + switch (p->insn[0]) { + case 0x9c: /* pushfl */ + *tos &= ~(TF_MASK | IF_MASK); + *tos |= kprobe_old_eflags; + break; + case 0xe8: /* call relative - Fix return addr */ + *tos = orig_eip + (*tos - copy_eip); + break; + case 0xff: + if ((p->insn[1] & 0x30) == 0x10) { + /* call absolute, indirect */ + /* Fix return addr; eip is correct. */ + next_eip = regs->eip; + *tos = orig_eip + (*tos - copy_eip); + } else if (((p->insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */ + ((p->insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */ + /* eip is correct. */ + next_eip = regs->eip; + } + break; + case 0xea: /* jmp absolute -- eip is correct */ + next_eip = regs->eip; + break; + default: + break; + } + + regs->eflags &= ~TF_MASK; + if (next_eip) { + regs->eip = next_eip; + } else { + regs->eip = orig_eip + (regs->eip - copy_eip); + } +} + +/* + * Interrupts are disabled on entry as trap1 is an interrupt gate and they + * remain disabled thoroughout this function. And we hold kprobe lock. + */ +static inline int post_kprobe_handler(struct pt_regs *regs) +{ + if (!kprobe_running()) + return 0; + + if (current_kprobe->post_handler) + current_kprobe->post_handler(current_kprobe, regs, 0); + + resume_execution(current_kprobe, regs); + regs->eflags |= kprobe_saved_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + + /* + * if somebody else is singlestepping across a probe point, eflags + * will have TF set, in which case, continue the remaining processing + * of do_debug, as if this is not a probe hit. + */ + if (regs->eflags & TF_MASK) + return 0; + + return 1; +} + +/* Interrupts disabled, kprobe_lock held. */ +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + if (current_kprobe->fault_handler + && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + return 1; + + if (kprobe_status & KPROBE_HIT_SS) { + resume_execution(current_kprobe, regs); + regs->eflags |= kprobe_old_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + } + return 0; +} + +/* + * Wrapper routine to for handling exceptions. + */ +int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, + void *data) +{ + struct die_args *args = (struct die_args *)data; + switch (val) { + case DIE_INT3: + if (kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_DEBUG: + if (post_kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_GPF: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + case DIE_PAGE_FAULT: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + default: + break; + } + return NOTIFY_DONE; +} + +int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + unsigned long addr; + + jprobe_saved_regs = *regs; + jprobe_saved_esp = ®s->esp; + addr = (unsigned long)jprobe_saved_esp; + + /* + * TBD: As Linus pointed out, gcc assumes that the callee + * owns the argument space and could overwrite it, e.g. + * tailcall optimization. So, to be absolutely safe + * we also save and restore enough stack bytes to cover + * the argument area. + */ + memcpy(jprobes_stack, (kprobe_opcode_t *) addr, MIN_STACK_SIZE(addr)); + regs->eflags &= ~IF_MASK; + regs->eip = (unsigned long)(jp->entry); + return 1; +} + +void jprobe_return(void) +{ + preempt_enable_no_resched(); + asm volatile (" xchgl %%ebx,%%esp \n" + " int3 \n"::"b" + (jprobe_saved_esp):"memory"); +} +void jprobe_return_end(void) +{ +}; + +int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +{ + u8 *addr = (u8 *) (regs->eip - 1); + unsigned long stack_addr = (unsigned long)jprobe_saved_esp; + struct jprobe *jp = container_of(p, struct jprobe, kp); + + if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { + if (®s->esp != jprobe_saved_esp) { + struct pt_regs *saved_regs = + container_of(jprobe_saved_esp, struct pt_regs, esp); + printk("current esp %p does not match saved esp %p\n", + ®s->esp, jprobe_saved_esp); + printk("Saved registers for jprobe %p\n", jp); + show_registers(saved_regs); + printk("Current registers\n"); + show_registers(regs); + BUG(); + } + *regs = jprobe_saved_regs; + memcpy((kprobe_opcode_t *) stack_addr, jprobes_stack, + MIN_STACK_SIZE(stack_addr)); + return 1; + } + return 0; +} diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c --- a/arch/i386/kernel/ldt.c 2004-10-18 14:56:48 -07:00 +++ b/arch/i386/kernel/ldt.c 2004-10-18 14:56:48 -07:00 @@ -142,12 +142,17 @@ err = -EFAULT; up(&mm->context.sem); if (err < 0) - return err; + goto error_return; if (size != bytecount) { /* zero-fill the rest */ - clear_user(ptr+size, bytecount-size); + if (clear_user(ptr+size, bytecount-size) != 0) { + err = -EFAULT; + goto error_return; + } } return bytecount; +error_return: + return err; } static int read_default_ldt(void __user * ptr, unsigned long bytecount) diff -Nru a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c --- a/arch/i386/kernel/microcode.c 2004-10-18 14:56:19 -07:00 +++ b/arch/i386/kernel/microcode.c 2004-10-18 14:56:19 -07:00 @@ -485,6 +485,7 @@ static struct miscdevice microcode_dev = { .minor = MICROCODE_MINOR, .name = "microcode", + .devfs_name = "cpu/microcode", .fops = µcode_fops, }; diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c --- a/arch/i386/kernel/nmi.c 2004-10-18 14:56:32 -07:00 +++ b/arch/i386/kernel/nmi.c 2004-10-18 14:56:32 -07:00 @@ -25,13 +25,17 @@ #include #include #include +#include #include #include #include #include +#include "mach_traps.h" + unsigned int nmi_watchdog = NMI_NONE; +extern int unknown_nmi_panic; static unsigned int nmi_hz = HZ; static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ static unsigned int nmi_p4_cccr_val; @@ -376,7 +380,13 @@ clear_msr_range(0x3F1, 2); /* MSR 0x3F0 seems to have a default value of 0xFC00, but current docs doesn't fully define it, so leave it alone for now. */ - clear_msr_range(0x3A0, 31); + if (boot_cpu_data.x86_model >= 0x3) { + /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */ + clear_msr_range(0x3A0, 26); + clear_msr_range(0x3BC, 3); + } else { + clear_msr_range(0x3A0, 31); + } clear_msr_range(0x3C0, 6); clear_msr_range(0x3C8, 6); clear_msr_range(0x3E0, 2); @@ -426,8 +436,6 @@ nmi_active = 1; } -static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; - /* * the best way to detect whether a CPU has a 'hard lockup' problem * is to check it's local APIC timer IRQ counts. If they are not @@ -459,6 +467,8 @@ alert_counter[i] = 0; } +extern void die_nmi(struct pt_regs *, const char *msg); + void nmi_watchdog_tick (struct pt_regs * regs) { @@ -477,21 +487,8 @@ * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; - if (alert_counter[cpu] == 5*nmi_hz) { - spin_lock(&nmi_print_lock); - /* - * We are in trouble anyway, lets at least try - * to get a message out. - */ - bust_spinlocks(1); - printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip); - show_registers(regs); - printk("console shuts up ...\n"); - console_silent(); - spin_unlock(&nmi_print_lock); - bust_spinlocks(0); - do_exit(SIGSEGV); - } + if (alert_counter[cpu] == 5*nmi_hz) + die_nmi(regs, "NMI Watchdog detected LOCKUP"); } else { last_irq_sums[cpu] = sum; alert_counter[cpu] = 0; @@ -517,6 +514,49 @@ wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); } } + +#ifdef CONFIG_SYSCTL + +static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) +{ + unsigned char reason = get_nmi_reason(); + char buf[64]; + + if (!(reason & 0xc0)) { + sprintf(buf, "NMI received for unknown reason %02x\n", reason); + die_nmi(regs, buf); + } + return 0; +} + +/* + * proc handler for /proc/sys/kernel/unknown_nmi_panic + */ +int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int old_state; + + old_state = unknown_nmi_panic; + proc_dointvec(table, write, file, buffer, length, ppos); + if (!!old_state == !!unknown_nmi_panic) + return 0; + + if (unknown_nmi_panic) { + if (reserve_lapic_nmi() < 0) { + unknown_nmi_panic = 0; + return -EBUSY; + } else { + set_nmi_callback(unknown_nmi_panic_callback); + } + } else { + release_lapic_nmi(); + unset_nmi_callback(); + } + return 0; +} + +#endif EXPORT_SYMBOL(nmi_active); EXPORT_SYMBOL(nmi_watchdog); diff -Nru a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c --- a/arch/i386/kernel/pci-dma.c 2004-10-18 14:56:18 -07:00 +++ b/arch/i386/kernel/pci-dma.c 2004-10-18 14:56:18 -07:00 @@ -13,17 +13,40 @@ #include #include +struct dma_coherent_mem { + void *virt_base; + u32 device_base; + int size; + int flags; + unsigned long *bitmap; +}; + void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int gfp) { void *ret; + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; + int order = get_order(size); /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + if (mem) { + int page = bitmap_find_free_region(mem->bitmap, mem->size, + order); + if (page >= 0) { + *dma_handle = mem->device_base + (page << PAGE_SHIFT); + ret = mem->virt_base + (page << PAGE_SHIFT); + memset(ret, 0, size); + return ret; + } + if (mem->flags & DMA_MEMORY_EXCLUSIVE) + return NULL; + } + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); + ret = (void *)__get_free_pages(gfp, order); if (ret != NULL) { memset(ret, 0, size); @@ -35,5 +58,89 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, get_order(size)); + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; + int order = get_order(size); + + if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { + int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + + bitmap_release_region(mem->bitmap, page, order); + } else + free_pages((unsigned long)vaddr, order); +} + +int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + void __iomem *mem_base; + int pages = size >> PAGE_SHIFT; + int bitmap_size = (pages + 31)/32; + + if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) + goto out; + if (!size) + goto out; + if (dev->dma_mem) + goto out; + + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + mem_base = ioremap(bus_addr, size); + if (!mem_base) + goto out; + + dev->dma_mem = kmalloc(GFP_KERNEL, sizeof(struct dma_coherent_mem)); + if (!dev->dma_mem) + goto out; + memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem)); + dev->dma_mem->bitmap = kmalloc(GFP_KERNEL, bitmap_size); + if (!dev->dma_mem->bitmap) + goto free1_out; + memset(dev->dma_mem->bitmap, 0, bitmap_size); + + dev->dma_mem->virt_base = mem_base; + dev->dma_mem->device_base = device_addr; + dev->dma_mem->size = pages; + dev->dma_mem->flags = flags; + + if (flags & DMA_MEMORY_MAP) + return DMA_MEMORY_MAP; + + return DMA_MEMORY_IO; + + free1_out: + kfree(dev->dma_mem->bitmap); + out: + return 0; +} +EXPORT_SYMBOL(dma_declare_coherent_memory); + +void dma_release_declared_memory(struct device *dev) +{ + struct dma_coherent_mem *mem = dev->dma_mem; + + if(!mem) + return; + dev->dma_mem = NULL; + kfree(mem->bitmap); + kfree(mem); +} +EXPORT_SYMBOL(dma_release_declared_memory); + +void *dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size) +{ + struct dma_coherent_mem *mem = dev->dma_mem; + int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; + int pos, err; + + if (!mem) + return ERR_PTR(-EINVAL); + + pos = (device_addr - mem->device_base) >> PAGE_SHIFT; + err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); + if (err != 0) + return ERR_PTR(err); + return mem->virt_base + (pos << PAGE_SHIFT); } +EXPORT_SYMBOL(dma_mark_declared_memory_occupied); diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c 2004-10-18 14:55:46 -07:00 +++ b/arch/i386/kernel/process.c 2004-10-18 14:55:46 -07:00 @@ -142,13 +142,21 @@ /* endless idle loop with no priority at all */ while (1) { while (!need_resched()) { - void (*idle)(void) = pm_idle; + void (*idle)(void); + /* + * Mark this as an RCU critical section so that + * synchronize_kernel() in the unload path waits + * for our completion. + */ + rcu_read_lock(); + idle = pm_idle; if (!idle) idle = default_idle; irq_stat[smp_processor_id()].idle_timestamp = jiffies; idle(); + rcu_read_unlock(); } schedule(); } @@ -183,18 +191,13 @@ printk("monitor/mwait feature present.\n"); /* * Skip, if setup has overridden idle. - * Also, take care of system with asymmetric CPUs. - * Use, mwait_idle only if all cpus support it. - * If not, we fallback to default_idle() + * One CPU supports mwait => All CPUs supports mwait */ if (!pm_idle) { printk("using mwait in idle threads.\n"); pm_idle = mwait_idle; } - return; } - pm_idle = default_idle; - return; } static int __init idle_setup (char *str) @@ -294,13 +297,22 @@ void exit_thread(void) { struct task_struct *tsk = current; + struct thread_struct *t = &tsk->thread; /* The process may have allocated an io port bitmap... nuke it. */ - if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { + if (unlikely(NULL != t->io_bitmap_ptr)) { int cpu = get_cpu(); - struct tss_struct *tss = init_tss + cpu; - kfree(tsk->thread.io_bitmap_ptr); - tsk->thread.io_bitmap_ptr = NULL; + struct tss_struct *tss = &per_cpu(init_tss, cpu); + + kfree(t->io_bitmap_ptr); + t->io_bitmap_ptr = NULL; + /* + * Careful, clear this in the TSS too: + */ + memset(tss->io_bitmap, 0xff, tss->io_bitmap_max); + t->io_bitmap_max = 0; + tss->io_bitmap_owner = NULL; + tss->io_bitmap_max = 0; tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; put_cpu(); } @@ -369,8 +381,10 @@ tsk = current; if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); - if (!p->thread.io_bitmap_ptr) + if (!p->thread.io_bitmap_ptr) { + p->thread.io_bitmap_max = 0; return -ENOMEM; + } memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr, IO_BITMAP_BYTES); } @@ -401,8 +415,10 @@ err = 0; out: - if (err && p->thread.io_bitmap_ptr) + if (err && p->thread.io_bitmap_ptr) { kfree(p->thread.io_bitmap_ptr); + p->thread.io_bitmap_max = 0; + } return err; } @@ -467,6 +483,37 @@ return 1; } +static inline void +handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss) +{ + if (!next->io_bitmap_ptr) { + /* + * Disable the bitmap via an invalid offset. We still cache + * the previous bitmap owner and the IO bitmap contents: + */ + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + return; + } + if (likely(next == tss->io_bitmap_owner)) { + /* + * Previous owner of the bitmap (hence the bitmap content) + * matches the next task, we dont have to do anything but + * to set a valid offset in the TSS: + */ + tss->io_bitmap_base = IO_BITMAP_OFFSET; + return; + } + /* + * Lazy TSS's I/O bitmap copy. We set an invalid offset here + * and we let the task to get a GPF in case an I/O instruction + * is performed. The handler of the GPF will verify that the + * faulting task has a valid I/O bitmap and, it true, does the + * real copy and restart the instruction. This will save us + * redundant copies when the currently switched task does not + * perform any I/O during its timeslice. + */ + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; +} /* * This special macro can be used to load a debugging register */ @@ -507,7 +554,7 @@ struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; int cpu = smp_processor_id(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ @@ -551,28 +598,9 @@ loaddebug(next, 7); } - if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { - if (next->io_bitmap_ptr) { - /* - * 4 cachelines copy ... not good, but not that - * bad either. Anyone got something better? - * This only affects processes which use ioperm(). - * [Putting the TSSs into 4k-tlb mapped regions - * and playing VM tricks to switch the IO bitmap - * is not really acceptable.] - */ - memcpy(tss->io_bitmap, next->io_bitmap_ptr, - IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; - } else - /* - * a bitmap offset pointing outside of the TSS limit - * causes a nicely controllable SIGSEGV if a process - * tries to use a port IO instruction. The first - * sys_ioperm() call sets up the bitmap properly. - */ - tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; - } + if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) + handle_io_bitmap(next, tss); + return prev_p; } @@ -593,7 +621,7 @@ child_tidptr = (int __user *)regs.edi; if (!newsp) newsp = regs.esp; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, parent_tidptr, child_tidptr); + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } /* diff -Nru a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c --- a/arch/i386/kernel/ptrace.c 2004-10-18 14:56:27 -07:00 +++ b/arch/i386/kernel/ptrace.c 2004-10-18 14:56:27 -07:00 @@ -147,6 +147,7 @@ { long tmp; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); } @@ -370,6 +371,7 @@ else { clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; @@ -391,6 +393,7 @@ if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); @@ -411,6 +414,7 @@ } tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); + set_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -535,14 +539,15 @@ audit_syscall_exit(current, regs->eax); } - if (!test_thread_flag(TIF_SYSCALL_TRACE)) + if (!test_thread_flag(TIF_SYSCALL_TRACE) && + !test_thread_flag(TIF_SINGLESTEP)) return; if (!(current->ptrace & PT_PTRACED)) return; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) && + !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/kernel/setup.c 2004-10-18 14:56:29 -07:00 @@ -49,6 +49,7 @@ #include #include #include "setup_arch_pre.h" +#include /* This value is set up by the early boot code to point to the value immediately after the boot time page tables. It contains a *physical* @@ -218,9 +219,14 @@ .end = 0x0021, .flags = IORESOURCE_BUSY | IORESOURCE_IO }, { - .name = "timer", + .name = "timer0", .start = 0x0040, - .end = 0x005f, + .end = 0x0043, + .flags = IORESOURCE_BUSY | IORESOURCE_IO +}, { + .name = "timer1", + .start = 0x0050, + .end = 0x0053, .flags = IORESOURCE_BUSY | IORESOURCE_IO }, { .name = "keyboard", @@ -809,6 +815,14 @@ if (c == ' ' && !memcmp(from, "highmem=", 8)) highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; + /* + * vmalloc=size forces the vmalloc area to be exactly 'size' + * bytes. This can be used to increase (or decrease) the + * vmalloc area - the default is 128m. + */ + if (c == ' ' && !memcmp(from, "vmalloc=", 8)) + __VMALLOC_RESERVE = memparse(from+8, &from); + c = *(from++); if (!c) break; @@ -991,6 +1005,17 @@ } } +/* + * workaround for Dell systems that neglect to reserve EBDA + */ +static void __init reserve_ebda_region(void) +{ + unsigned int addr; + addr = get_bios_ebda(); + if (addr) + reserve_bootmem(addr, PAGE_SIZE); +} + static unsigned long __init setup_memory(void) { unsigned long bootmap_size, start_pfn, max_low_pfn; @@ -1037,6 +1062,9 @@ */ reserve_bootmem(0, PAGE_SIZE); + /* reserve EBDA region, it's a 4K region */ + reserve_ebda_region(); + /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent PCI prefetch into it (errata #56). Usually the page is reserved anyways, unless you have no PS/2 mouse plugged in. */ @@ -1335,13 +1363,22 @@ /* * NOTE: before this point _nobody_ is allowed to allocate - * any memory using the bootmem allocator. + * any memory using the bootmem allocator. Although the + * alloctor is now initialised only the first 8Mb of the kernel + * virtual address space has been mapped. All allocations before + * paging_init() has completed must use the alloc_bootmem_low_pages() + * variant (which allocates DMA'able memory) and care must be taken + * not to exceed the 8Mb limit. */ #ifdef CONFIG_SMP smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ #endif paging_init(); + + /* + * NOTE: at this point the bootmem allocator is fully available. + */ #ifdef CONFIG_EARLY_PRINTK { diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c --- a/arch/i386/kernel/signal.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/kernel/signal.c 2004-10-18 14:56:29 -07:00 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -269,6 +270,7 @@ struct pt_regs *regs, unsigned long mask) { int tmp, err = 0; + unsigned long eflags; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); @@ -290,7 +292,11 @@ err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user(regs->eip, &sc->eip); err |= __put_user(regs->xcs, (unsigned int __user *)&sc->cs); - err |= __put_user(regs->eflags, &sc->eflags); + eflags = regs->eflags; + if (current->ptrace & PT_PTRACED) { + eflags &= ~TF_MASK; + } + err |= __put_user(eflags, &sc->eflags); err |= __put_user(regs->esp, &sc->esp_at_signal); err |= __put_user(regs->xss, (unsigned int __user *)&sc->ss); @@ -345,18 +351,20 @@ void __user *restorer; struct sigframe __user *frame; int err = 0; + int usig; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __put_user((current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); + usig = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(usig, &frame->sig); if (err) goto give_sigsegv; @@ -395,13 +403,22 @@ /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; + regs->eax = (unsigned long) sig; + regs->edx = (unsigned long) 0; + regs->ecx = (unsigned long) 0; set_fs(USER_DS); regs->xds = __USER_DS; regs->xes = __USER_DS; regs->xss = __USER_DS; regs->xcs = __USER_CS; - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -411,9 +428,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -422,18 +437,20 @@ void __user *restorer; struct rt_sigframe __user *frame; int err = 0; + int usig; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __put_user((current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); + usig = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(usig, &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); @@ -476,13 +493,22 @@ /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; + regs->eax = (unsigned long) usig; + regs->edx = (unsigned long) &frame->info; + regs->ecx = (unsigned long) &frame->uc; set_fs(USER_DS); regs->xds = __USER_DS; regs->xes = __USER_DS; regs->xss = __USER_DS; regs->xcs = __USER_CS; - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -492,9 +518,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* @@ -502,11 +526,9 @@ */ static void -handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs) +handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, + sigset_t *oldset, struct pt_regs * regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - /* Are we from a system call? */ if (regs->orig_eax >= 0) { /* If so, check system call restarting.. */ @@ -534,9 +556,6 @@ else setup_frame(sig, ka, oldset, regs); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -555,6 +574,7 @@ { siginfo_t info; int signr; + struct k_sigaction ka; /* * We want the common case to go fast, which @@ -573,7 +593,7 @@ if (!oldset) oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Reenable any watchpoints before delivering the * signal to user space. The processor register will @@ -583,7 +603,7 @@ __asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7])); /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, oldset, regs); + handle_signal(signr, &info, &ka, oldset, regs); return 1; } diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c --- a/arch/i386/kernel/smp.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/kernel/smp.c 2004-10-18 14:55:54 -07:00 @@ -22,7 +22,6 @@ #include #include -#include #include /* @@ -104,7 +103,7 @@ * about nothing of note with C stepping upwards. */ -struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }}; +DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0, }; /* * the following functions deal with sending IPIs between CPUs. @@ -122,7 +121,7 @@ return SET_APIC_DEST_FIELD(mask); } -inline void __send_IPI_shortcut(unsigned int shortcut, int vector) +void __send_IPI_shortcut(unsigned int shortcut, int vector) { /* * Subtle. In the case of the 'never do double writes' workaround @@ -157,7 +156,7 @@ /* * This is only used on smaller machines. */ -inline void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) +void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) { unsigned long mask = cpus_addr(cpumask)[0]; unsigned long cfg; @@ -230,6 +229,8 @@ local_irq_restore(flags); } +#include /* must come after the send_IPI functions above for inlining */ + /* * Smarter SMP flushing macros. * c/o Linus Torvalds. @@ -255,9 +256,9 @@ */ static inline void leave_mm (unsigned long cpu) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) BUG(); - cpu_clear(cpu, cpu_tlbstate[cpu].active_mm->cpu_vm_mask); + cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); load_cr3(swapper_pg_dir); } @@ -324,8 +325,8 @@ * BUG(); */ - if (flush_mm == cpu_tlbstate[cpu].active_mm) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { + if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { if (flush_va == FLUSH_ALL) local_flush_tlb(); else @@ -457,7 +458,7 @@ unsigned long cpu = smp_processor_id(); __flush_tlb_all(); - if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) leave_mm(cpu); } diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/kernel/smpboot.c 2004-10-18 14:56:29 -07:00 @@ -17,7 +17,7 @@ * Fixes * Felix Koop : NR_CPUS used properly * Jose Renau : Handle single CPU case. - * Alan Cox : By repeated request 8) - Total BogoMIP report. + * Alan Cox : By repeated request 8) - Total BogoMIPS report. * Greg Wright : Fix for kernel stacks panic. * Erich Boleyn : MP v1.4 and additional changes. * Matthias Sattler : Changes for 2.1 kernel map. @@ -72,6 +72,10 @@ /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; +u8 x86_cpu_to_apicid[NR_CPUS] = + { [0 ... NR_CPUS-1] = 0xff }; +EXPORT_SYMBOL(x86_cpu_to_apicid); + /* Set when the idlers are all forked */ int smp_threads_ready; @@ -187,34 +191,6 @@ #define NR_LOOPS 5 -/* - * accurate 64-bit/32-bit division, expanded to 32-bit divisions and 64-bit - * multiplication. Not terribly optimized but we need it at boot time only - * anyway. - * - * result == a / b - * == (a1 + a2*(2^32)) / b - * == a1/b + a2*(2^32/b) - * == a1/b + a2*((2^32-1)/b) + a2/b + (a2*((2^32-1) % b))/b - * ^---- (this multiplication can overflow) - */ - -static unsigned long long __init div64 (unsigned long long a, unsigned long b0) -{ - unsigned int a1, a2; - unsigned long long res; - - a1 = ((unsigned int*)&a)[0]; - a2 = ((unsigned int*)&a)[1]; - - res = a1/b0 + - (unsigned long long)a2 * (unsigned long long)(0xffffffff/b0) + - a2 / b0 + - (a2 * (0xffffffff % b0)) / b0; - - return res; -} - static void __init synchronize_tsc_bp (void) { int i; @@ -224,7 +200,7 @@ unsigned long one_usec; int buggy = 0; - printk("checking TSC synchronization across %u CPUs: ", num_booting_cpus()); + printk(KERN_INFO "checking TSC synchronization across %u CPUs: ", num_booting_cpus()); /* convert from kcyc/sec to cyc/usec */ one_usec = cpu_khz / 1000; @@ -279,7 +255,8 @@ sum += t0; } } - avg = div64(sum, num_booting_cpus()); + avg = sum; + do_div(avg, num_booting_cpus()); sum = 0; for (i = 0; i < NR_CPUS; i++) { @@ -297,18 +274,18 @@ buggy = 1; printk("\n"); } - realdelta = div64(delta, one_usec); + realdelta = delta; + do_div(realdelta, one_usec); if (tsc_values[i] < avg) realdelta = -realdelta; - printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n", i, realdelta); + printk(KERN_INFO "CPU#%d had %ld usecs TSC skew, fixed it up.\n", i, realdelta); } sum += delta; } if (!buggy) printk("passed.\n"); - ; } static void __init synchronize_tsc_ap (void) @@ -492,16 +469,6 @@ unsigned short ss; } stack_start; -static struct task_struct * __init fork_by_hand(void) -{ - struct pt_regs regs; - /* - * don't care about the eip and regs settings since - * we'll never reschedule the forked task. - */ - return copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); -} - #ifdef CONFIG_NUMA /* which logical CPUs are on which nodes */ @@ -797,21 +764,10 @@ * We can't use kernel_thread since we must avoid to * reschedule the child. */ - idle = fork_by_hand(); + idle = fork_idle(cpu); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); - wake_up_forked_process(idle); - - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ - init_idle(idle, cpu); - idle->thread.eip = (unsigned long) start_secondary; - - unhash_process(idle); - /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); @@ -875,6 +831,7 @@ inquire_remote_apic(apicid); } } + x86_cpu_to_apicid[cpu] = apicid; if (boot_error) { /* Try to put things back the way they were before ... */ unmap_cpu_to_logical_apicid(cpu); @@ -957,6 +914,7 @@ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); boot_cpu_logical_apicid = logical_smp_processor_id(); + x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; current_thread_info()->cpu = 0; smp_tune_scheduling(); @@ -1131,213 +1089,6 @@ if (cpu_has_tsc && cpucount && cpu_khz) 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, cpu_domains); -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 = NULL, *last = NULL; - - /* Set up domains */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, 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]; - cpu_domain->parent = phys_domain; - cpu_domain->groups = &sched_group_cpus[i]; - - *phys_domain = SD_CPU_INIT; - phys_domain->span = nodemask; - phys_domain->parent = node_domain; - phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)]; - - *node_domain = SD_NODE_INIT; - node_domain->span = cpu_possible_map; - node_domain->groups = &sched_group_nodes[cpu_to_node(i)]; - } - - /* Set up CPU (sibling) groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - int j; - first = last = 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); - cpu->cpu_power = SCHED_LOAD_SCALE; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - } - - for (i = 0; i < MAX_NUMNODES; i++) { - int j; - cpumask_t nodemask; - struct sched_group *node = &sched_group_nodes[i]; - cpumask_t node_cpumask = node_to_cpumask(i); - - cpus_and(nodemask, node_cpumask, cpu_possible_map); - - if (cpus_empty(nodemask)) - continue; - - first = last = NULL; - /* Set up physical groups */ - for_each_cpu_mask(j, nodemask) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, j); - struct sched_group *cpu = &sched_group_phys[j]; - - if (j != first_cpu(cpu_domain->span)) - continue; - - cpu->cpumask = cpu_domain->span; - /* - * Make each extra sibling increase power by 10% of - * the basic CPU. This is very arbitrary. - */ - cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10; - node->cpu_power += cpu->cpu_power; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - } - - /* Set up nodes */ - first = last = NULL; - for (i = 0; i < MAX_NUMNODES; i++) { - struct sched_group *cpu = &sched_group_nodes[i]; - cpumask_t nodemask; - cpumask_t node_cpumask = node_to_cpumask(i); - - cpus_and(nodemask, node_cpumask, cpu_possible_map); - - if (cpus_empty(nodemask)) - continue; - - cpu->cpumask = nodemask; - /* ->cpu_power already setup */ - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - - mb(); - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - cpu_attach_domain(cpu_domain, i); - } -} -#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, cpu_domains); -static DEFINE_PER_CPU(struct sched_domain, phys_domains); -__init void arch_init_sched_domains(void) -{ - int i; - struct sched_group *first = NULL, *last = NULL; - - /* Set up domains */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - struct sched_domain *phys_domain = &per_cpu(phys_domains, i); - - *cpu_domain = SD_SIBLING_INIT; - cpu_domain->span = cpu_sibling_map[i]; - cpu_domain->parent = phys_domain; - cpu_domain->groups = &sched_group_cpus[i]; - - *phys_domain = SD_CPU_INIT; - phys_domain->span = cpu_possible_map; - phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)]; - } - - /* Set up CPU (sibling) groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - int j; - first = last = 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); - cpu->cpu_power = SCHED_LOAD_SCALE; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - } - - first = last = NULL; - /* Set up physical groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - struct sched_group *cpu = &sched_group_phys[i]; - - if (i != first_cpu(cpu_domain->span)) - continue; - - cpu->cpumask = cpu_domain->span; - /* See SMT+NUMA setup for comment */ - cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - - mb(); - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - cpu_attach_domain(cpu_domain, i); - } -} -#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 */ diff -Nru a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c --- a/arch/i386/kernel/sysenter.c 2004-10-18 14:57:04 -07:00 +++ b/arch/i386/kernel/sysenter.c 2004-10-18 14:57:04 -07:00 @@ -24,7 +24,7 @@ void enable_sep_cpu(void *info) { int cpu = get_cpu(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; @@ -43,18 +43,18 @@ static int __init sysenter_setup(void) { - unsigned long page = get_zeroed_page(GFP_ATOMIC); + void *page = (void *)get_zeroed_page(GFP_ATOMIC); __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC); if (!boot_cpu_has(X86_FEATURE_SEP)) { - memcpy((void *) page, + memcpy(page, &vsyscall_int80_start, &vsyscall_int80_end - &vsyscall_int80_start); return 0; } - memcpy((void *) page, + memcpy(page, &vsyscall_sysenter_start, &vsyscall_sysenter_end - &vsyscall_sysenter_start); diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c --- a/arch/i386/kernel/time.c 2004-10-18 14:56:31 -07:00 +++ b/arch/i386/kernel/time.c 2004-10-18 14:56:31 -07:00 @@ -200,6 +200,18 @@ } EXPORT_SYMBOL(monotonic_clock); +#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER) +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (in_lock_functions(pc)) + return *(unsigned long *)(regs->ebp + 4); + + return pc; +} +EXPORT_SYMBOL(profile_pc); +#endif /* * timer_interrupt() needs to keep up the real-time clock, @@ -321,11 +333,12 @@ static int time_resume(struct sys_device *dev) { + unsigned long flags; unsigned long sec = get_cmos_time() + clock_cmos_diff; - write_seqlock_irq(&xtime_lock); + write_seqlock_irqsave(&xtime_lock, flags); xtime.tv_sec = sec; xtime.tv_nsec = 0; - write_sequnlock_irq(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock, flags); return 0; } diff -Nru a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c --- a/arch/i386/kernel/time_hpet.c 2004-10-18 14:56:17 -07:00 +++ b/arch/i386/kernel/time_hpet.c 2004-10-18 14:56:17 -07:00 @@ -29,7 +29,7 @@ static int use_hpet; /* can be used for runtime check of hpet */ static int boot_hpet_disable; /* boottime override for HPET timer */ -static unsigned long hpet_virt_address; /* hpet kernel virtual address */ +static void __iomem * hpet_virt_address; /* hpet kernel virtual address */ #define FSEC_TO_USEC (1000000000UL) @@ -76,8 +76,7 @@ if (!hpet_address) { return -1; } - hpet_virt_address = (unsigned long) ioremap_nocache(hpet_address, - HPET_MMAP_SIZE); + hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); /* * Read the period, compute tick and quotient. */ @@ -162,11 +161,11 @@ hd.hd_irq[0] = HPET_LEGACY_8254; hd.hd_irq[1] = HPET_LEGACY_RTC; if (ntimer > 2) { - struct hpet *hpet; - struct hpet_timer *timer; + struct hpet __iomem *hpet; + struct hpet_timer __iomem *timer; int i; - hpet = (struct hpet *) hpet_virt_address; + hpet = hpet_virt_address; for (i = 2, timer = &hpet->hpet_timers[2]; i < ntimer; timer++, i++) diff -Nru a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c --- a/arch/i386/kernel/timers/timer_pit.c 2004-10-18 14:56:50 -07:00 +++ b/arch/i386/kernel/timers/timer_pit.c 2004-10-18 14:56:50 -07:00 @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -156,3 +159,44 @@ .monotonic_clock = monotonic_clock_pit, .delay = delay_pit, }; + +void setup_pit_timer(void) +{ + extern spinlock_t i8253_lock; + unsigned long flags; + + spin_lock_irqsave(&i8253_lock, flags); + outb_p(0x34,PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ + udelay(10); + outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ + udelay(10); + outb(LATCH >> 8 , PIT_CH0); /* MSB */ + spin_unlock_irqrestore(&i8253_lock, flags); +} + +static int timer_resume(struct sys_device *dev) +{ + setup_pit_timer(); + return 0; +} + +static struct sysdev_class timer_sysclass = { + set_kset_name("timer"), + .resume = timer_resume, +}; + +static struct sys_device device_timer = { + .id = 0, + .cls = &timer_sysclass, +}; + +static int __init init_timer_sysfs(void) +{ + int error = sysdev_class_register(&timer_sysclass); + if (!error) + error = sysdev_register(&device_timer); + return error; +} + +device_initcall(init_timer_sysfs); + diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c --- a/arch/i386/kernel/timers/timer_tsc.c 2004-10-18 14:56:48 -07:00 +++ b/arch/i386/kernel/timers/timer_tsc.c 2004-10-18 14:56:48 -07:00 @@ -265,7 +265,8 @@ { struct cpufreq_freqs *freq = data; - write_seqlock_irq(&xtime_lock); + if (val != CPUFREQ_RESUMECHANGE) + write_seqlock_irq(&xtime_lock); if (!ref_freq) { ref_freq = freq->old; loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy; @@ -291,7 +292,9 @@ } #endif } - write_sequnlock_irq(&xtime_lock); + + if (val != CPUFREQ_RESUMECHANGE) + write_sequnlock_irq(&xtime_lock); return 0; } diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c 2004-10-18 14:56:16 -07:00 +++ b/arch/i386/kernel/traps.c 2004-10-18 14:56:16 -07:00 @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CONFIG_EISA #include @@ -48,6 +49,7 @@ #include #include +#include #include #include @@ -92,6 +94,18 @@ asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; +struct notifier_block *i386die_chain; +static spinlock_t die_notifier_lock = SPIN_LOCK_UNLOCKED; + +int register_die_notifier(struct notifier_block *nb) +{ + int err = 0; + unsigned long flags; + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&i386die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + return err; +} static int valid_stack_ptr(struct task_struct *task, void *p) { @@ -216,7 +230,7 @@ ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx" + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\nEFLAGS: %08lx" " (%s) \n", smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags, UTS_RELEASE); @@ -234,23 +248,25 @@ * 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++) - { + eip = (u8 *)regs->eip - 43; + for (i = 0; i < 64; i++, eip++) { unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { -bad: + + if (eip < (u8 *)PAGE_OFFSET || __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"); @@ -292,35 +308,53 @@ printk("Kernel BUG\n"); } -spinlock_t die_lock = SPIN_LOCK_UNLOCKED; - void die(const char * str, struct pt_regs * regs, long err) { + static struct { + spinlock_t lock; + u32 lock_owner; + int lock_owner_depth; + } die = { + .lock = SPIN_LOCK_UNLOCKED, + .lock_owner = -1, + .lock_owner_depth = 0 + }; static int die_counter; - int nl = 0; - console_verbose(); - spin_lock_irq(&die_lock); - bust_spinlocks(1); - handle_BUG(regs); - printk(KERN_ALERT "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); + if (die.lock_owner != smp_processor_id()) { + console_verbose(); + spin_lock_irq(&die.lock); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); + } + + if (++die.lock_owner_depth < 3) { + int nl = 0; + handle_BUG(regs); + printk(KERN_ALERT "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); #ifdef CONFIG_PREEMPT - printk("PREEMPT "); - nl = 1; + printk("PREEMPT "); + nl = 1; #endif #ifdef CONFIG_SMP - printk("SMP "); - nl = 1; + printk("SMP "); + nl = 1; #endif #ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC"); - nl = 1; + printk("DEBUG_PAGEALLOC"); + nl = 1; #endif - if (nl) - printk("\n"); - show_registers(regs); + if (nl) + printk("\n"); + notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); + show_registers(regs); + } else + printk(KERN_ERR "Recursive die() failure, output suppressed\n"); + bust_spinlocks(0); - spin_unlock_irq(&die_lock); + die.lock_owner = -1; + spin_unlock_irq(&die.lock); if (in_interrupt()) panic("Fatal exception in interrupt"); @@ -387,6 +421,9 @@ #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } @@ -398,12 +435,18 @@ info.si_errno = 0; \ info.si_code = sicode; \ info.si_addr = (void __user *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ } #define DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ } @@ -415,11 +458,16 @@ info.si_errno = 0; \ info.si_code = sicode; \ info.si_addr = (void __user *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +#ifndef CONFIG_KPROBES DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) +#endif DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) @@ -427,13 +475,40 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) -DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { - if (regs->eflags & X86_EFLAGS_IF) - local_irq_enable(); - + int cpu = get_cpu(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct thread_struct *thread = ¤t->thread; + + /* + * Perform the lazy TSS's I/O bitmap copy. If the TSS has an + * invalid offset set (the LAZY one) and the faulting thread has + * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS + * and we set the offset field correctly. Then we let the CPU to + * restart the faulting instruction. + */ + if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && + thread->io_bitmap_ptr) { + memcpy(tss->io_bitmap, thread->io_bitmap_ptr, + thread->io_bitmap_max); + /* + * If the previously set map was extending to higher ports + * than the current one, pad extra space with 0xff (no access). + */ + if (thread->io_bitmap_max < tss->io_bitmap_max) + memset((char *) tss->io_bitmap + + thread->io_bitmap_max, 0xff, + tss->io_bitmap_max - thread->io_bitmap_max); + tss->io_bitmap_max = thread->io_bitmap_max; + tss->io_bitmap_base = IO_BITMAP_OFFSET; + put_cpu(); + return; + } + put_cpu(); + if (regs->eflags & VM_MASK) goto gp_in_vm86; @@ -451,8 +526,12 @@ return; gp_in_kernel: - if (!fixup_exception(regs)) + if (!fixup_exception(regs)) { + if (notify_die(DIE_GPF, "general protection fault", regs, + error_code, 13, SIGSEGV) == NOTIFY_STOP); + return; die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -496,11 +575,35 @@ printk("Do you have a strange power saving mode enabled?\n"); } +static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; + +void die_nmi (struct pt_regs *regs, const char *msg) +{ + spin_lock(&nmi_print_lock); + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + bust_spinlocks(1); + printk(msg); + printk(" on CPU%d, eip %08lx, registers:\n", + smp_processor_id(), regs->eip); + show_registers(regs); + printk("console shuts up ...\n"); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); + do_exit(SIGSEGV); +} + static void default_do_nmi(struct pt_regs * regs) { unsigned char reason = get_nmi_reason(); if (!(reason & 0xc0)) { + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) + == NOTIFY_STOP) + return; #ifdef CONFIG_X86_LOCAL_APIC /* * Ok, so this is none of the documented NMI sources, @@ -514,6 +617,8 @@ unknown_nmi_error(reason, regs); return; } + if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP) + return; if (reason & 0x80) mem_parity_error(reason, regs); if (reason & 0x40) @@ -557,6 +662,20 @@ nmi_callback = dummy_nmi_callback; } +#ifdef CONFIG_KPROBES +asmlinkage int do_int3(struct pt_regs *regs, long error_code) +{ + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) + == NOTIFY_STOP) + return 1; + /* This is an interrupt gate, because kprobes wants interrupts + disabled. Normal trap handlers don't. */ + restore_interrupts(regs); + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); + return 0; +} +#endif + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -587,6 +706,9 @@ __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, + SIGTRAP) == NOTIFY_STOP) + return; /* It's safe to allow irq's after DR6 has been saved */ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); @@ -875,6 +997,14 @@ _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); } +/* + * This routine sets up an interrupt gate at directory privilege level 3. + */ +static inline void set_system_intr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS); +} + static void __init set_trap_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); @@ -911,7 +1041,7 @@ set_trap_gate(0,÷_error); set_intr_gate(1,&debug); set_intr_gate(2,&nmi); - set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_intr_gate(3, &int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c --- a/arch/i386/kernel/vm86.c 2004-10-18 14:55:55 -07:00 +++ b/arch/i386/kernel/vm86.c 2004-10-18 14:55:55 -07:00 @@ -121,7 +121,7 @@ do_exit(SIGSEGV); } - tss = init_tss + get_cpu(); + tss = &per_cpu(init_tss, get_cpu()); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; load_esp0(tss, ¤t->thread); @@ -303,7 +303,7 @@ asm volatile("movl %%fs,%0":"=m" (tsk->thread.saved_fs)); asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs)); - tss = init_tss + get_cpu(); + tss = &per_cpu(init_tss, get_cpu()); tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; diff -Nru a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S --- a/arch/i386/kernel/vmlinux.lds.S 2004-10-18 14:56:17 -07:00 +++ b/arch/i386/kernel/vmlinux.lds.S 2004-10-18 14:56:17 -07:00 @@ -4,6 +4,7 @@ #include #include +#include OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -11,12 +12,13 @@ jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x9090 @@ -66,9 +68,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/i386/kernel/vsyscall.lds b/arch/i386/kernel/vsyscall.lds --- a/arch/i386/kernel/vsyscall.lds 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,67 +0,0 @@ -/* - * Linker script for vsyscall DSO. The vsyscall page is an ELF shared - * object prelinked to its virtual address, and with only one read-only - * segment (that fits in one page). This script controls its layout. - */ - -/* This must match . */ -VSYSCALL_BASE = 0xffffe000; - -SECTIONS -{ - . = VSYSCALL_BASE + SIZEOF_HEADERS; - - .hash : { *(.hash) } :text - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - - /* This linker script is used both with -r and with -shared. - For the layouts to match, we need to skip more than enough - space for the dynamic symbol table et al. If this amount - is insufficient, ld -shared will barf. Just increase it here. */ - . = VSYSCALL_BASE + 0x400; - - .text : { *(.text) } :text =0x90909090 - - .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr - .eh_frame : { KEEP (*(.eh_frame)) } :text - .dynamic : { *(.dynamic) } :text :dynamic - .useless : { - *(.got.plt) *(.got) - *(.data .data.* .gnu.linkonce.d.*) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - } :text -} - -/* - * We must supply the ELF program headers explicitly to get just one - * PT_LOAD segment, and set the flags explicitly to make segments read-only. - */ -PHDRS -{ - text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ - dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ - eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ -} - -/* - * This controls what symbols we export from the DSO. - */ -VERSION -{ - LINUX_2.5 { - global: - __kernel_vsyscall; - __kernel_sigreturn; - __kernel_rt_sigreturn; - - local: *; - }; -} - -/* The ELF entry point can be used to set the AT_SYSINFO value. */ -ENTRY(__kernel_vsyscall); diff -Nru a/arch/i386/kernel/vsyscall.lds.S b/arch/i386/kernel/vsyscall.lds.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/i386/kernel/vsyscall.lds.S 2004-10-18 14:56:28 -07:00 @@ -0,0 +1,65 @@ +/* + * Linker script for vsyscall DSO. The vsyscall page is an ELF shared + * object prelinked to its virtual address, and with only one read-only + * segment (that fits in one page). This script controls its layout. + */ +#include + +SECTIONS +{ + . = VSYSCALL_BASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + /* This linker script is used both with -r and with -shared. + For the layouts to match, we need to skip more than enough + space for the dynamic symbol table et al. If this amount + is insufficient, ld -shared will barf. Just increase it here. */ + . = VSYSCALL_BASE + 0x400; + + .text : { *(.text) } :text =0x90909090 + + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .dynamic : { *(.dynamic) } :text :dynamic + .useless : { + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + } :text +} + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + LINUX_2.5 { + global: + __kernel_vsyscall; + __kernel_sigreturn; + __kernel_rt_sigreturn; + + local: *; + }; +} + +/* The ELF entry point can be used to set the AT_SYSINFO value. */ +ENTRY(__kernel_vsyscall); diff -Nru a/arch/i386/lib/memcpy.c b/arch/i386/lib/memcpy.c --- a/arch/i386/lib/memcpy.c 2004-10-18 14:57:04 -07:00 +++ b/arch/i386/lib/memcpy.c 2004-10-18 14:57:04 -07:00 @@ -13,13 +13,13 @@ return __memcpy(to, from, n); #endif } -EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL(memcpy); void *memset(void *s, int c, size_t count) { return __memset(s, c, count); } -EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memset); void *memmove(void *dest, const void *src, size_t n) { @@ -41,4 +41,4 @@ } return dest; } -EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL(memmove); diff -Nru a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx.c --- a/arch/i386/lib/mmx.c 2004-10-18 14:56:32 -07:00 +++ b/arch/i386/lib/mmx.c 2004-10-18 14:56:32 -07:00 @@ -2,9 +2,9 @@ #include #include #include +#include #include -#include /* diff -Nru a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c --- a/arch/i386/lib/usercopy.c 2004-10-18 14:55:53 -07:00 +++ b/arch/i386/lib/usercopy.c 2004-10-18 14:55:53 -07:00 @@ -31,6 +31,7 @@ #define __do_strncpy_from_user(dst,src,count,res) \ do { \ int __d0, __d1, __d2; \ + might_sleep(); \ __asm__ __volatile__( \ " testl %1,%1\n" \ " jz 2f\n" \ @@ -119,6 +120,7 @@ #define __do_clear_user(addr,size) \ do { \ int __d0; \ + might_sleep(); \ __asm__ __volatile__( \ "0: rep; stosl\n" \ " movl %2,%0\n" \ diff -Nru a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h --- a/arch/i386/mach-es7000/es7000.h 2004-10-18 14:55:55 -07:00 +++ b/arch/i386/mach-es7000/es7000.h 2004-10-18 14:55:55 -07:00 @@ -29,7 +29,7 @@ #define MIP_BUSY 1 #define MIP_SPIN 0xf0000 -#define MIP_VALID 0x0100000000000000 +#define MIP_VALID 0x0100000000000000ULL #define MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff) #define MIP_RD_LO(VALUE) (VALUE & 0xffffffff) @@ -103,6 +103,13 @@ #define MIP_SW_APIC 0x1020b #define MIP_FUNC(VALUE) (VALUE & 0xff) + +#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_ACPI_BOOT)) +#define IOAPIC_GSI_BOUND(ioapic) ((ioapic+1) * (nr_ioapic_registers[ioapic]-1)) +#define MAX_GSI_MAPSIZE 32 +#endif + +extern unsigned long io_apic_irqs; extern int parse_unisys_oem (char *oemptr, int oem_entries); extern int find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length); diff -Nru a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c --- a/arch/i386/mach-es7000/es7000plat.c 2004-10-18 14:57:03 -07:00 +++ b/arch/i386/mach-es7000/es7000plat.c 2004-10-18 14:57:03 -07:00 @@ -51,27 +51,74 @@ int mip_port; unsigned long mip_addr, host_addr; +#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_ACPI_BOOT)) +static unsigned long cycle_irqs = 0; +static unsigned long free_irqs = 0; +static int gsi_map[MAX_GSI_MAPSIZE] = { [0 ... MAX_GSI_MAPSIZE-1] = -1 }; + +/* + * GSI override for ES7000 platforms. + */ + +static int __init +es7000_gsi_override(int ioapic, int gsi) +{ + static int newgsi = 0; + + if (gsi_map[gsi] != -1) + gsi = gsi_map[gsi]; + else if (cycle_irqs ^ free_irqs) { + newgsi = find_next_bit(&cycle_irqs, IOAPIC_GSI_BOUND(0), newgsi); + __set_bit(newgsi, &free_irqs); + gsi_map[gsi] = newgsi; + gsi = newgsi; + newgsi++; + Dprintk("es7000_gsi_override: free_irqs = 0x%lx\n", free_irqs); + } + + return gsi; +} + static int __init es7000_rename_gsi(int ioapic, int gsi) { + static int initialized = 0; + int i; + + /* + * These should NEVER be true at this point but we'd rather be + * safe than sorry. + */ + if (acpi_disabled || acpi_pci_disabled || acpi_noirq) + return gsi; + if (ioapic) - return gsi; - else { - if (gsi == 0) - return 13; - if (gsi == 1) - return 16; - if (gsi == 4) - return 17; - if (gsi == 6) - return 18; - if (gsi == 7) - return 19; - if (gsi == 8) - return 20; - return gsi; - } + return gsi; + + if (!initialized) { + unsigned long tmp_irqs = 0; + + for (i = 0; i < nr_ioapic_registers[0]; i++) + __set_bit(mp_irqs[i].mpc_srcbusirq, &tmp_irqs); + + cycle_irqs = (~tmp_irqs & io_apic_irqs & ((1 << IOAPIC_GSI_BOUND(0)) - 1)); + + initialized = 1; + Dprintk("es7000_rename_gsi: cycle_irqs = 0x%lx\n", cycle_irqs); + } + + for (i = 0; i < nr_ioapic_registers[0]; i++) { + if (mp_irqs[i].mpc_srcbusirq == gsi) { + if (mp_irqs[i].mpc_dstirq == gsi) + return gsi; + else + return es7000_gsi_override(0, gsi); + } + } + + return gsi; } +#endif // (CONFIG_X86_IO_APIC) && (CONFIG_ACPI_INTERPRETER || CONFIG_ACPI_BOOT) /* * Parse the OEM Table @@ -193,7 +240,7 @@ } } } - printk("ES7000: did not find Unisys ACPI OEM table!\n"); + Dprintk("ES7000: did not find Unisys ACPI OEM table!\n"); return -1; } @@ -237,7 +284,7 @@ } status = ((unsigned long long)mip_reg->off_0 & - (unsigned long long)0xffff0000000000) >> 48; + (unsigned long long)0xffff0000000000ULL) >> 48; mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 & (unsigned long long)~MIP_VALID); return status; diff -Nru a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c --- a/arch/i386/mach-generic/bigsmp.c 2004-10-18 14:56:27 -07:00 +++ b/arch/i386/mach-generic/bigsmp.c 2004-10-18 14:56:27 -07:00 @@ -13,15 +13,41 @@ #include #include #include +#include #include #include #include #include -int dmi_bigsmp; /* can be set by dmi scanners */ +static int dmi_bigsmp; /* can be set by dmi scanners */ + +static __init int hp_ht_bigsmp(struct dmi_system_id *d) +{ +#ifdef CONFIG_X86_GENERICARCH + printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); + dmi_bigsmp = 1; +#endif + return 0; +} + + +static struct dmi_system_id __initdata bigsmp_dmi_table[] = { + { hp_ht_bigsmp, "HP ProLiant DL760 G2", { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_BIOS_VERSION, "P44-"), + }}, + + { hp_ht_bigsmp, "HP ProLiant DL740", { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_BIOS_VERSION, "P47-"), + }}, + { } +}; + static __init int probe_bigsmp(void) { + dmi_check_system(bigsmp_dmi_table); return dmi_bigsmp; } diff -Nru a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c --- a/arch/i386/mach-voyager/voyager_smp.c 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/mach-voyager/voyager_smp.c 2004-10-18 14:56:28 -07:00 @@ -35,7 +35,7 @@ int reboot_smp = 0; /* TLB state -- visible externally, indexed physically */ -struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0 }}; +DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 }; /* CPU IRQ affinity -- set to all ones initially */ static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = ~0UL }; @@ -523,15 +523,6 @@ return cpu_idle(); } -static struct task_struct * __init -fork_by_hand(void) -{ - struct pt_regs regs; - /* don't care about the eip and regs settings since we'll - * never reschedule the forked task. */ - return copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); -} - /* Routine to kick start the given CPU and wait for it to report ready * (or timeout in startup). When this routine returns, the requested @@ -587,16 +578,10 @@ hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF; cpucount++; - idle = fork_by_hand(); + idle = fork_idle(cpu); if(IS_ERR(idle)) panic("failed fork for CPU%d", cpu); - - wake_up_forked_process(idle); - - init_idle(idle, cpu); - idle->thread.eip = (unsigned long) start_secondary; - unhash_process(idle); /* init_tasks (in sched.c) is indexed logically */ stack_start.esp = (void *) idle->thread.esp; @@ -860,9 +845,9 @@ static inline void leave_mm (unsigned long cpu) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) BUG(); - cpu_clear(cpu, cpu_tlbstate[cpu].active_mm->cpu_vm_mask); + cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); load_cr3(swapper_pg_dir); } @@ -883,8 +868,8 @@ smp_processor_id())); */ - if (flush_mm == cpu_tlbstate[cpu].active_mm) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { + if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { if (flush_va == FLUSH_ALL) local_flush_tlb(); else @@ -1218,7 +1203,7 @@ unsigned long cpu = smp_processor_id(); __flush_tlb_all(); - if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) leave_mm(cpu); } @@ -1302,8 +1287,7 @@ int cpu = smp_processor_id(); long weight; - x86_do_profile(regs); - + profile_tick(CPU_PROFILING, regs); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got diff -Nru a/arch/i386/math-emu/fpu_proto.h b/arch/i386/math-emu/fpu_proto.h --- a/arch/i386/math-emu/fpu_proto.h 2004-10-18 14:57:03 -07:00 +++ b/arch/i386/math-emu/fpu_proto.h 2004-10-18 14:57:03 -07:00 @@ -69,7 +69,6 @@ extern void FPU_pop(void); extern int FPU_empty_i(int stnr); extern int FPU_stackoverflow(FPU_REG **st_new_ptr); -extern void FPU_sync_tags(void); extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr); extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag); extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag); diff -Nru a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile --- a/arch/i386/mm/Makefile 2004-10-18 14:56:27 -07:00 +++ b/arch/i386/mm/Makefile 2004-10-18 14:56:27 -07:00 @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o +obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o mmap.o obj-$(CONFIG_DISCONTIGMEM) += discontig.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c --- a/arch/i386/mm/discontig.c 2004-10-18 14:56:32 -07:00 +++ b/arch/i386/mm/discontig.c 2004-10-18 14:56:32 -07:00 @@ -31,6 +31,7 @@ #include #include #include +#include struct pglist_data *node_data[MAX_NUMNODES]; bootmem_data_t node0_bdata; @@ -219,6 +220,17 @@ return reserve_pages; } +/* + * workaround for Dell systems that neglect to reserve EBDA + */ +static void __init reserve_ebda_region_node(void) +{ + unsigned int addr; + addr = get_bios_ebda(); + if (addr) + reserve_bootmem_node(NODE_DATA(0), addr, PAGE_SIZE); +} + unsigned long __init setup_memory(void) { int nid; @@ -318,6 +330,9 @@ */ reserve_bootmem_node(NODE_DATA(0), PAGE_SIZE, PAGE_SIZE); + /* reserve EBDA region, it's a 4K region */ + reserve_ebda_region_node(); + #ifdef CONFIG_ACPI_SLEEP /* * Reserve low memory region for sleep support. @@ -402,15 +417,15 @@ * remapped KVA area - mbligh */ if (!nid) - free_area_init_node(nid, NODE_DATA(nid), 0, - zones_size, start, zholes_size); + free_area_init_node(nid, NODE_DATA(nid), + zones_size, start, zholes_size); else { unsigned long lmem_map; lmem_map = (unsigned long)node_remap_start_vaddr[nid]; lmem_map += sizeof(pg_data_t) + PAGE_SIZE - 1; lmem_map &= PAGE_MASK; - free_area_init_node(nid, NODE_DATA(nid), - (struct page *)lmem_map, zones_size, + NODE_DATA(nid)->node_mem_map = (struct page *)lmem_map; + free_area_init_node(nid, NODE_DATA(nid), zones_size, start, zholes_size); } } diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c 2004-10-18 14:55:53 -07:00 +++ b/arch/i386/mm/fault.c 2004-10-18 14:55:53 -07:00 @@ -24,8 +24,8 @@ #include #include -#include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -107,7 +107,7 @@ desc = (void *)desc + (seg & ~7); } else { /* Must disable preemption while reading the GDT. */ - desc = (u32 *)&cpu_gdt_table[get_cpu()]; + desc = (u32 *)&per_cpu(cpu_gdt_table, get_cpu()); desc = (void *)desc + (seg & ~7); } @@ -226,6 +226,9 @@ /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, + SIGSEGV) == NOTIFY_STOP) + return; /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & (X86_EFLAGS_IF|VM_MASK)) local_irq_enable(); @@ -513,12 +516,13 @@ * an interrupt in the middle of a task switch.. */ int index = pgd_index(address); + unsigned long pgd_paddr; pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; pte_t *pte_k; - asm("movl %%cr3,%0":"=r" (pgd)); - pgd = index + (pgd_t *)__va(pgd); + asm("movl %%cr3,%0":"=r" (pgd_paddr)); + pgd = index + (pgd_t *)__va(pgd_paddr); pgd_k = init_mm.pgd + index; if (!pgd_present(*pgd_k)) diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c 2004-10-18 14:56:49 -07:00 +++ b/arch/i386/mm/init.c 2004-10-18 14:56:49 -07:00 @@ -40,10 +40,12 @@ #include #include +unsigned int __VMALLOC_RESERVE = 128 << 20; + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; -static int do_test_wp_bit(void); +static int noinline do_test_wp_bit(void); /* * Creates a middle page table and puts a pointer to it in the @@ -671,7 +673,7 @@ * This function cannot be __init, since exceptions don't work in that * section. Put this after the callers, so that it cannot be inlined. */ -static int do_test_wp_bit(void) +static int noinline do_test_wp_bit(void) { char tmp_reg; int flag; diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c --- a/arch/i386/mm/ioremap.c 2004-10-18 14:56:27 -07:00 +++ b/arch/i386/mm/ioremap.c 2004-10-18 14:56:27 -07:00 @@ -110,9 +110,9 @@ * have to convert them into an offset in a page-aligned mapping, but the * caller shouldn't need to know that small detail. */ -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) { - void * addr; + void __iomem * addr; struct vm_struct * area; unsigned long offset, last_addr; @@ -125,7 +125,7 @@ * Don't remap the low PCI/ISA area, it's always mapped.. */ if (phys_addr >= 0xA0000 && last_addr < 0x100000) - return phys_to_virt(phys_addr); + return (void __iomem *) phys_to_virt(phys_addr); /* * Don't allow anybody to remap normal RAM that we're using.. @@ -156,12 +156,12 @@ if (!area) return NULL; area->phys_addr = phys_addr; - addr = area->addr; + addr = (void __iomem *) area->addr; if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) { - vunmap(addr); + vunmap((void __force *) addr); return NULL; } - return (void *) (offset + (char *)addr); + return (void __iomem *) (offset + (char __iomem *)addr); } @@ -187,10 +187,10 @@ * Must be freed with iounmap. */ -void *ioremap_nocache (unsigned long phys_addr, unsigned long size) +void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) { unsigned long last_addr; - void *p = __ioremap(phys_addr, size, _PAGE_PCD); + void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD); if (!p) return p; @@ -221,12 +221,12 @@ return p; } -void iounmap(void *addr) +void iounmap(volatile void __iomem *addr) { struct vm_struct *p; - if (addr <= high_memory) + if ((void __force *) addr <= high_memory) return; - p = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr)); + p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); if (!p) { printk("__iounmap: bad address %p\n", addr); return; diff -Nru a/arch/i386/mm/mmap.c b/arch/i386/mm/mmap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/i386/mm/mmap.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,71 @@ +/* + * linux/arch/i386/mm/mmap.c + * + * flexible mmap layout support + * + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Started by Ingo Molnar + */ + +#include +#include + +/* + * Top of mmap area (just below the process stack). + * + * Leave an at least ~128 MB hole. + */ +#define MIN_GAP (128*1024*1024) +#define MAX_GAP (TASK_SIZE/6*5) + +static inline unsigned long mmap_base(struct mm_struct *mm) +{ + unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur; + + if (gap < MIN_GAP) + gap = MIN_GAP; + else if (gap > MAX_GAP) + gap = MAX_GAP; + + return TASK_SIZE - (gap & PAGE_MASK); +} + +/* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: + */ +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + /* + * Fall back to the standard layout if the personality + * bit is set, or if the expected stack growth is unlimited: + */ + if (sysctl_legacy_va_layout || + (current->personality & ADDR_COMPAT_LAYOUT) || + current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) { + mm->mmap_base = TASK_UNMAPPED_BASE; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; + } else { + mm->mmap_base = mmap_base(mm); + mm->get_unmapped_area = arch_get_unmapped_area_topdown; + mm->unmap_area = arch_unmap_area_topdown; + } +} diff -Nru a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c --- a/arch/i386/mm/pageattr.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/mm/pageattr.c 2004-10-18 14:56:29 -07:00 @@ -114,7 +114,7 @@ kpte = lookup_address(address); if (!kpte) return -EINVAL; - kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK); + kpte_page = virt_to_page(kpte); if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { if ((pte_val(*kpte) & _PAGE_PSE) == 0) { pte_t old = *kpte; diff -Nru a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c --- a/arch/i386/oprofile/op_model_athlon.c 2004-10-18 14:57:20 -07:00 +++ b/arch/i386/oprofile/op_model_athlon.c 2004-10-18 14:57:20 -07:00 @@ -70,7 +70,7 @@ /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (counter_config[i].event) { + if (counter_config[i].enabled) { reset_value[i] = counter_config[i].count; CTR_WRITE(counter_config[i].count, msrs, i); @@ -96,7 +96,7 @@ { unsigned int low, high; int i; - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); int is_kernel = !user_mode(regs); for (i = 0 ; i < NUM_COUNTERS; ++i) { diff -Nru a/arch/i386/oprofile/op_model_p4.c b/arch/i386/oprofile/op_model_p4.c --- a/arch/i386/oprofile/op_model_p4.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/oprofile/op_model_p4.c 2004-10-18 14:55:54 -07:00 @@ -419,9 +419,28 @@ msrs->controls[i].addr = addr; } - /* 43 ESCR registers in three discontiguous group */ + /* 43 ESCR registers in three or four discontiguous group */ for (addr = MSR_P4_BSU_ESCR0 + stag; - addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { + addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) { + msrs->controls[i].addr = addr; + } + + /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1 + * to avoid special case in nmi_{save|restore}_registers() */ + if (boot_cpu_data.x86_model >= 0x3) { + for (addr = MSR_P4_BSU_ESCR0 + stag; + addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) { + msrs->controls[i].addr = addr; + } + } else { + for (addr = MSR_P4_IQ_ESCR0 + stag; + addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) { + msrs->controls[i].addr = addr; + } + } + + for (addr = MSR_P4_RAT_ESCR0 + stag; + addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { msrs->controls[i].addr = addr; } @@ -553,7 +572,18 @@ /* clear all escrs (including those outside our concern) */ for (addr = MSR_P4_BSU_ESCR0 + stag; - addr <= MSR_P4_SSU_ESCR0; addr += addr_increment()) { + addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) { + wrmsr(addr, 0, 0); + } + + /* On older models clear also MSR_P4_IQ_ESCR0/1 */ + if (boot_cpu_data.x86_model < 0x3) { + wrmsr(MSR_P4_IQ_ESCR0, 0, 0); + wrmsr(MSR_P4_IQ_ESCR1, 0, 0); + } + + for (addr = MSR_P4_RAT_ESCR0 + stag; + addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { wrmsr(addr, 0, 0); } @@ -578,7 +608,7 @@ /* setup all counters */ for (i = 0 ; i < num_counters ; ++i) { - if (counter_config[i].event) { + if (counter_config[i].enabled) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i)); @@ -595,7 +625,7 @@ { unsigned long ctr, low, high, stag, real; int i; - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); int is_kernel = !user_mode(regs); stag = get_stagger(); diff -Nru a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c --- a/arch/i386/oprofile/op_model_ppro.c 2004-10-18 14:56:48 -07:00 +++ b/arch/i386/oprofile/op_model_ppro.c 2004-10-18 14:56:48 -07:00 @@ -67,7 +67,7 @@ /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (counter_config[i].event) { + if (counter_config[i].enabled) { reset_value[i] = counter_config[i].count; CTR_WRITE(counter_config[i].count, msrs, i); @@ -91,7 +91,7 @@ { unsigned int low, high; int i; - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); int is_kernel = !user_mode(regs); for (i = 0 ; i < NUM_COUNTERS; ++i) { diff -Nru a/arch/i386/pci/common.c b/arch/i386/pci/common.c --- a/arch/i386/pci/common.c 2004-10-18 14:56:29 -07:00 +++ b/arch/i386/pci/common.c 2004-10-18 14:56:29 -07:00 @@ -70,7 +70,7 @@ int i; DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); - for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { + list_for_each(ln, &b->devices) { d = pci_dev_b(ln); if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) seen_host_bridge++; diff -Nru a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c --- a/arch/i386/pci/fixup.c 2004-10-18 14:56:48 -07:00 +++ b/arch/i386/pci/fixup.c 2004-10-18 14:56:48 -07:00 @@ -29,6 +29,7 @@ } pcibios_last_bus = -1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); static void __devinit pci_fixup_i450gx(struct pci_dev *d) { @@ -42,6 +43,7 @@ pci_scan_bus(busno, &pci_root_ops, NULL); pcibios_last_bus = -1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx); static void __devinit pci_fixup_umc_ide(struct pci_dev *d) { @@ -55,6 +57,7 @@ for(i=0; i<4; i++) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); static void __devinit pci_fixup_ncr53c810(struct pci_dev *d) { @@ -67,6 +70,7 @@ d->class = PCI_CLASS_STORAGE_SCSI << 8; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); static void __devinit pci_fixup_ide_bases(struct pci_dev *d) { @@ -86,6 +90,7 @@ } } } +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); static void __devinit pci_fixup_ide_trash(struct pci_dev *d) { @@ -108,6 +113,10 @@ for(i=0; i<4; i++) d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_fixup_ide_trash); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_fixup_ide_trash); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_fixup_ide_trash); static void __devinit pci_fixup_latency(struct pci_dev *d) { @@ -118,6 +127,8 @@ DBG("PCI: Setting max latency to 32\n"); pcibios_max_latency = 32; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency); static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) { @@ -126,6 +137,7 @@ */ d->irq = 9; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi); /* * Addresses issues with problems in the memory write queue timer in @@ -179,6 +191,10 @@ pci_write_config_byte(d, where, v); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); /* * For some reasons Intel decided that certain parts of their @@ -195,6 +211,7 @@ (dev->device & 0xff00) == 0x2400) dev->transparent = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge); /* * Fixup for C1 Halt Disconnect problem on nForce2 systems. @@ -236,115 +253,5 @@ pci_write_config_dword(dev, 0x6c, fixed_val); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); -struct pci_fixup pcibios_fixups[] = { - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82451NX, - .hook = pci_fixup_i450nx - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82454GX, - .hook = pci_fixup_i450gx - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_UMC, - .device = PCI_DEVICE_ID_UMC_UM8886BF, - .hook = pci_fixup_umc_ide - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5513, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .hook = pci_fixup_ide_bases - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5597, - .hook = pci_fixup_latency - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5598, - .hook = pci_fixup_latency - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82371AB_3, - .hook = pci_fixup_piix4_acpi - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801CA_10, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801CA_11, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801DB_9, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8363_0, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8622, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8361, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8367_0, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_NCR, - .device = PCI_DEVICE_ID_NCR_53C810, - .hook = pci_fixup_ncr53c810 - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_ANY_ID, - .hook = pci_fixup_transparent_bridge - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE2, - .hook = pci_fixup_nforce2 - }, - { .pass = 0 } -}; diff -Nru a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c --- a/arch/i386/pci/i386.c 2004-10-18 14:56:21 -07:00 +++ b/arch/i386/pci/i386.c 2004-10-18 14:56:21 -07:00 @@ -164,7 +164,7 @@ } } -static void __init pcibios_assign_resources(void) +static int __init pcibios_assign_resources(void) { struct pci_dev *dev = NULL; int idx; @@ -204,6 +204,7 @@ pci_assign_resource(dev, PCI_ROM_RESOURCE); } } + return 0; } void __init pcibios_resource_survey(void) @@ -212,8 +213,13 @@ pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1); - pcibios_assign_resources(); } + +/** + * called in fs_initcall (one below subsys_initcall), + * give a chance for motherboard reserve resources + */ +fs_initcall(pcibios_assign_resources); int pcibios_enable_resources(struct pci_dev *dev, int mask) { diff -Nru a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c --- a/arch/i386/pci/mmconfig.c 2004-10-18 14:56:48 -07:00 +++ b/arch/i386/pci/mmconfig.c 2004-10-18 14:56:48 -07:00 @@ -1,4 +1,11 @@ /* + * Copyright (C) 2004 Matthew Wilcox + * Copyright (C) 2004 Intel Corp. + * + * This code is released under the GNU General Public License version 2. + */ + +/* * mmconfig.c - Low-level direct PCI config space access via MMCONFIG */ @@ -9,7 +16,7 @@ /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ u32 pci_mmcfg_base_addr; -#define mmcfg_virt_addr (fix_to_virt(FIX_PCIE_MCFG)) +#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) /* The base address of the last MMCONFIG device accessed */ static u32 mmcfg_last_accessed_device; diff -Nru a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c --- a/arch/i386/pci/numa.c 2004-10-18 14:56:17 -07:00 +++ b/arch/i386/pci/numa.c 2004-10-18 14:56:17 -07:00 @@ -100,10 +100,7 @@ } pcibios_last_bus = -1; } - -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); static int __init pci_numa_init(void) { diff -Nru a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c --- a/arch/i386/pci/pcbios.c 2004-10-18 14:55:54 -07:00 +++ b/arch/i386/pci/pcbios.c 2004-10-18 14:55:54 -07:00 @@ -365,7 +365,7 @@ idx = found = 0; while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { idx++; - for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) { + list_for_each(ln, &pci_devices) { d = pci_dev_g(ln); if (d->bus->number == bus && d->devfn == devfn) { list_del(&d->global_list); diff -Nru a/arch/i386/power/Makefile b/arch/i386/power/Makefile --- a/arch/i386/power/Makefile 2004-10-18 14:56:27 -07:00 +++ b/arch/i386/power/Makefile 2004-10-18 14:56:27 -07:00 @@ -1,3 +1,2 @@ obj-$(CONFIG_PM) += cpu.o -obj-$(CONFIG_PM_DISK) += pmdisk.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o diff -Nru a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c --- a/arch/i386/power/cpu.c 2004-10-18 14:56:49 -07:00 +++ b/arch/i386/power/cpu.c 2004-10-18 14:56:49 -07:00 @@ -83,10 +83,10 @@ static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct * t = &per_cpu(init_tss, cpu); set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ - cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); /* This does ltr */ load_LDT(¤t->active_mm->context); /* This does lldt */ diff -Nru a/arch/i386/power/pmdisk.S b/arch/i386/power/pmdisk.S --- a/arch/i386/power/pmdisk.S 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,56 +0,0 @@ -/* Originally gcc generated, modified by hand */ - -#include -#include -#include - - .text - -ENTRY(pmdisk_arch_suspend) - cmpl $0,4(%esp) - jne .L1450 - - movl %esp, saved_context_esp - movl %ebx, saved_context_ebx - movl %ebp, saved_context_ebp - movl %esi, saved_context_esi - movl %edi, saved_context_edi - pushfl ; popl saved_context_eflags - - call pmdisk_suspend - jmp .L1449 - .p2align 4,,7 -.L1450: - movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx - movl %ecx,%cr3 - - movl pm_pagedir_nosave,%ebx - xorl %eax, %eax - xorl %edx, %edx - .p2align 4,,7 -.L1455: - movl 4(%ebx,%edx),%edi - movl (%ebx,%edx),%esi - - movl $1024, %ecx - rep - movsl - - movl %cr3, %ecx; - movl %ecx, %cr3; # flush TLB - - incl %eax - addl $16, %edx - cmpl pmdisk_pages,%eax - jb .L1455 - .p2align 4,,7 -.L1453: - movl saved_context_esp, %esp - movl saved_context_ebp, %ebp - movl saved_context_ebx, %ebx - movl saved_context_esi, %esi - movl saved_context_edi, %edi - pushl saved_context_eflags ; popfl - call pmdisk_resume -.L1449: - ret diff -Nru a/arch/i386/power/swsusp.S b/arch/i386/power/swsusp.S --- a/arch/i386/power/swsusp.S 2004-10-18 14:56:28 -07:00 +++ b/arch/i386/power/swsusp.S 2004-10-18 14:56:28 -07:00 @@ -15,83 +15,47 @@ .text -ENTRY(do_magic) - pushl %ebx - cmpl $0,8(%esp) - jne resume - call do_magic_suspend_1 - call save_processor_state +ENTRY(swsusp_arch_suspend) movl %esp, saved_context_esp - movl %eax, saved_context_eax movl %ebx, saved_context_ebx - movl %ecx, saved_context_ecx - movl %edx, saved_context_edx movl %ebp, saved_context_ebp movl %esi, saved_context_esi movl %edi, saved_context_edi pushfl ; popl saved_context_eflags - call do_magic_suspend_2 - popl %ebx + call swsusp_save ret -resume: +ENTRY(swsusp_arch_resume) movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx movl %ecx,%cr3 - call do_magic_resume_1 - movl $0,loop - cmpl $0,nr_copy_pages - je copy_done -copy_loop: - movl $0,loop2 + movl pagedir_nosave, %ebx + xorl %eax, %eax + xorl %edx, %edx .p2align 4,,7 -copy_one_page: - movl pagedir_nosave,%ecx - movl loop,%eax - movl loop2,%edx - sall $4,%eax - movl 4(%ecx,%eax),%ebx - movl (%ecx,%eax),%eax - movb (%edx,%eax),%al - movb %al,(%edx,%ebx) - - movl loop2,%eax - leal 1(%eax),%edx - movl %edx,loop2 - movl %edx,%eax - cmpl $4095,%eax - jbe copy_one_page - movl loop,%eax - leal 1(%eax),%edx - movl %edx,loop - movl %edx,%eax - cmpl nr_copy_pages,%eax - jb copy_loop -copy_done: - movl $__USER_DS,%eax +copy_loop: + movl 4(%ebx,%edx),%edi + movl (%ebx,%edx),%esi + + movl $1024, %ecx + rep + movsl + + incl %eax + addl $16, %edx + cmpl nr_copy_pages,%eax + jb copy_loop + .p2align 4,,7 - movw %ax, %ds - movw %ax, %es movl saved_context_esp, %esp movl saved_context_ebp, %ebp - movl saved_context_eax, %eax movl saved_context_ebx, %ebx - movl saved_context_ecx, %ecx - movl saved_context_edx, %edx movl saved_context_esi, %esi movl saved_context_edi, %edi - call restore_processor_state + pushl saved_context_eflags ; popfl - call do_magic_resume_2 - popl %ebx + call swsusp_restore ret - - .section .data.nosave -loop: - .quad 0 -loop2: - .quad 0 - .previous diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/Kconfig 2004-10-18 14:57:04 -07:00 @@ -38,6 +38,10 @@ bool default y +config GENERIC_IOMAP + bool + default y + choice prompt "System type" default IA64_GENERIC @@ -72,6 +76,12 @@ config IA64_SGI_SN2 bool "SGI-SN2" + help + Selecting this option will optimize the kernel for use on sn2 based + systems, but the resulting kernel binary will not run on other + types of ia64 systems. If you have an SGI Altix system, it's safe + to select this option. If in doubt, select ia64 generic support + instead. config IA64_HP_SIM bool "Ski-simulator" @@ -270,6 +280,9 @@ depends on IA32_SUPPORT default y +config IA64_MCA_RECOVERY + tristate "MCA recovery from errors other than TLB." + config PERFMON bool "Performance monitor support" help @@ -372,119 +385,7 @@ source "arch/ia64/oprofile/Kconfig" -menu "Kernel hacking" - -choice - prompt "Physical memory granularity" - default IA64_GRANULE_64MB - -config IA64_GRANULE_16MB - bool "16MB" - help - IA-64 identity-mapped regions use a large page size called "granules". - - Select "16MB" for a small granule size. - Select "64MB" for a large granule size. This is the current default. - -config IA64_GRANULE_64MB - bool "64MB" - depends on !(IA64_GENERIC || IA64_HP_ZX1 || IA64_SGI_SN2) - -endchoice - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config IA64_PRINT_HAZARDS - bool "Print possible IA-64 dependency violations to console" - depends on DEBUG_KERNEL - help - Selecting this option prints more information for Illegal Dependency - Faults, that is, for Read-after-Write (RAW), Write-after-Write (WAW), - or Write-after-Read (WAR) violations. This option is ignored if you - are compiling for an Itanium A step processor - (CONFIG_ITANIUM_ASTEP_SPECIFIC). If you're unsure, select Y. - -config DISABLE_VHPT - bool "Disable VHPT" - depends on DEBUG_KERNEL - help - The Virtual Hash Page Table (VHPT) enhances virtual address - translation performance. Normally you want the VHPT active but you - can select this option to disable the VHPT for debugging. If you're - unsure, answer N. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -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 IA64_DEBUG_CMPXCHG - bool "Turn on compare-and-exchange bug checking (slow!)" - depends on DEBUG_KERNEL - help - Selecting this option turns on bug checking for the IA-64 - compare-and-exchange instructions. This is slow! Itaniums - from step B3 or later don't have this problem. If you're unsure, - select N. - -config IA64_DEBUG_IRQ - bool "Turn on irq debug checks (slow!)" - depends on DEBUG_KERNEL - help - Selecting this option turns on bug checking for the IA-64 irq_save - and restore instructions. It's useful for tracking down spinlock - problems, but slow! If you're unsure, select N. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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 SYSVIPC_COMPAT - bool - depends on COMPAT && SYSVIPC - default y -endmenu +source "arch/ia64/Kconfig.debug" source "security/Kconfig" diff -Nru a/arch/ia64/Kconfig.debug b/arch/ia64/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,64 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +choice + prompt "Physical memory granularity" + default IA64_GRANULE_64MB + +config IA64_GRANULE_16MB + bool "16MB" + help + IA-64 identity-mapped regions use a large page size called "granules". + + Select "16MB" for a small granule size. + Select "64MB" for a large granule size. This is the current default. + +config IA64_GRANULE_64MB + bool "64MB" + depends on !(IA64_GENERIC || IA64_HP_ZX1 || IA64_SGI_SN2) + +endchoice + +config IA64_PRINT_HAZARDS + bool "Print possible IA-64 dependency violations to console" + depends on DEBUG_KERNEL + help + Selecting this option prints more information for Illegal Dependency + Faults, that is, for Read-after-Write (RAW), Write-after-Write (WAW), + or Write-after-Read (WAR) violations. This option is ignored if you + are compiling for an Itanium A step processor + (CONFIG_ITANIUM_ASTEP_SPECIFIC). If you're unsure, select Y. + +config DISABLE_VHPT + bool "Disable VHPT" + depends on DEBUG_KERNEL + help + The Virtual Hash Page Table (VHPT) enhances virtual address + translation performance. Normally you want the VHPT active but you + can select this option to disable the VHPT for debugging. If you're + unsure, answer N. + +config IA64_DEBUG_CMPXCHG + bool "Turn on compare-and-exchange bug checking (slow!)" + depends on DEBUG_KERNEL + help + Selecting this option turns on bug checking for the IA-64 + compare-and-exchange instructions. This is slow! Itaniums + from step B3 or later don't have this problem. If you're unsure, + select N. + +config IA64_DEBUG_IRQ + bool "Turn on irq debug checks (slow!)" + depends on DEBUG_KERNEL + help + Selecting this option turns on bug checking for the IA-64 irq_save + and restore instructions. It's useful for tracking down spinlock + problems, but slow! If you're unsure, select N. + +config SYSVIPC_COMPAT + bool + depends on COMPAT && SYSVIPC + default y + +endmenu diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile --- a/arch/ia64/Makefile 2004-10-18 14:55:54 -07:00 +++ b/arch/ia64/Makefile 2004-10-18 14:55:54 -07:00 @@ -13,6 +13,8 @@ export AWK +CHECKFLAGS += -m64 -D__ia64=1 -D__ia64__=1 -D_LP64 -D__LP64__ + OBJCOPYFLAGS := --strip-all LDFLAGS_vmlinux := -static LDFLAGS_MODULE += -T $(srctree)/arch/ia64/module.lds @@ -20,14 +22,12 @@ EXTRA := cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f12-f15,f32-f127 \ - -falign-functions=32 -frename-registers + -falign-functions=32 -frename-registers -fno-optimize-sibling-calls CFLAGS_KERNEL := -mconstant-gp -GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') -GCC_MINOR_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f2 -d'.') - -GAS_STATUS = $(shell $(srctree)/arch/ia64/scripts/check-gas $(CC) $(OBJDUMP)) -CPPFLAGS += $(shell $(srctree)/arch/ia64/scripts/toolchain-flags $(CC) $(OBJDUMP) $(READELF)) +GCC_VERSION := $(call cc-version) +GAS_STATUS = $(shell $(srctree)/arch/ia64/scripts/check-gas "$(CC)" "$(OBJDUMP)") +CPPFLAGS += $(shell $(srctree)/arch/ia64/scripts/toolchain-flags "$(CC)" "$(OBJDUMP)" "$(READELF)") ifeq ($(GAS_STATUS),buggy) $(error Sorry, you need a newer version of the assember, one that is built from \ @@ -37,16 +37,14 @@ ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif -ifeq ($(GCC_VERSION),2) +ifneq ($(shell if [ $(GCC_VERSION) -lt 0300 ] ; then echo "bad"; fi ;),) $(error Sorry, your compiler is too old. GCC v2.96 is known to generate bad code.) endif -ifeq ($(GCC_VERSION),3) - ifeq ($(GCC_MINOR_VERSION),4) +ifeq ($(GCC_VERSION),0304) # Workaround Itanium 1 bugs in gcc 3.4. # cflags-$(CONFIG_ITANIUM) += -mtune=merced cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley - endif endif cflags-$(CONFIG_ITANIUM_BSTEP_SPECIFIC) += -mb-step diff -Nru a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/configs/bigsur_defconfig 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,1132 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Tue Sep 28 13:26:53 2004 +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_IA64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_TIME_INTERPOLATION=y +CONFIG_EFI=y +CONFIG_GENERIC_IOMAP=y +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_VIRTUAL_MEM_MAP is not set +# CONFIG_IA64_CYCLONE is not set +CONFIG_IOSAPIC=y +CONFIG_FORCE_MAX_ZONEORDER=18 +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +# CONFIG_HOTPLUG_CPU is not set +CONFIG_PREEMPT=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_IA32_SUPPORT=y +CONFIG_COMPAT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# +CONFIG_EFI_VARS=y +CONFIG_EFI_PCDP=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# Power management and ACPI +# +CONFIG_PM=y +CONFIG_ACPI=y + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_THERMAL=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y + +# +# Bus options (PCI, PCMCIA) +# +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=4096 + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=m +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=m +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=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=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=m +CONFIG_AGP_I460=m +CONFIG_DRM=y +# CONFIG_DRM_TDFX is not set +CONFIG_DRM_R128=m +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 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_I810 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT 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_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_SEQUENCER_OSS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_OPL3_LIB=m +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CS46XX is not set +CONFIG_SND_CS4281=m +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VX222 is not set + +# +# ALSA USB devices +# +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_USX2Y is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +CONFIG_USB_BLUETOOTH_TTY=m +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# 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_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# 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_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# 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=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +CONFIG_CIFS=m +CONFIG_CIFS_STATS=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +# CONFIG_NCP_FS is not set +# CONFIG_CODA_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 is not set +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_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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=m + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_SYSVIPC_COMPAT=y + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set diff -Nru a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig --- a/arch/ia64/configs/generic_defconfig 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/configs/generic_defconfig 2004-10-18 14:56:29 -07:00 @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc1 +# Tue Aug 24 15:08:24 2004 # # @@ -126,6 +128,7 @@ CONFIG_HOTPLUG_PCI=m # CONFIG_HOTPLUG_PCI_FAKE is not set CONFIG_HOTPLUG_PCI_ACPI=m +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set # CONFIG_HOTPLUG_PCI_PCIE is not set # CONFIG_HOTPLUG_PCI_SHPC is not set @@ -172,6 +175,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_SIZE=4096 @@ -313,6 +317,7 @@ CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=m CONFIG_MD_RAID6=m CONFIG_MD_MULTIPATH=m @@ -365,6 +370,7 @@ # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -575,6 +581,7 @@ # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set # CONFIG_STALDRV is not set +CONFIG_SGI_SNSC=y # # Serial drivers @@ -766,6 +773,7 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set # # USB Host Controller Drivers @@ -918,6 +926,8 @@ CONFIG_FAT_FS=y # CONFIG_MSDOS_FS is not set CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_NTFS_FS=m # CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set @@ -945,7 +955,6 @@ # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -970,6 +979,7 @@ CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m CONFIG_SMB_NLS_DEFAULT=y CONFIG_SMB_NLS_REMOTE="cp437" @@ -1006,7 +1016,7 @@ # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m CONFIG_NLS_CODEPAGE_775=m CONFIG_NLS_CODEPAGE_850=m @@ -1030,7 +1040,7 @@ CONFIG_NLS_CODEPAGE_1250=m CONFIG_NLS_CODEPAGE_1251=m # CONFIG_NLS_ASCII is not set -CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m CONFIG_NLS_ISO8859_4=m @@ -1067,18 +1077,18 @@ # # Kernel hacking # -CONFIG_IA64_GRANULE_16MB=y -# CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_DISABLE_VHPT is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_DEBUG_INFO is not set CONFIG_SYSVIPC_COMPAT=y # @@ -1101,11 +1111,12 @@ # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_AES_GENERIC is not set +# CONFIG_CRYPTO_AES is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set # CONFIG_CRYPTO_TEA is not set # CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set diff -Nru a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig --- a/arch/ia64/configs/sn2_defconfig 2004-10-18 14:55:54 -07:00 +++ b/arch/ia64/configs/sn2_defconfig 2004-10-18 14:55:54 -07:00 @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Fri Sep 24 08:59:00 2004 # # @@ -7,11 +9,11 @@ # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -32,6 +34,8 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -53,6 +57,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y +CONFIG_GENERIC_IOMAP=y # CONFIG_IA64_GENERIC is not set # CONFIG_IA64_DIG is not set # CONFIG_IA64_HP_ZX1 is not set @@ -75,7 +80,7 @@ CONFIG_SMP=y CONFIG_NR_CPUS=512 # CONFIG_HOTPLUG_CPU is not set -# CONFIG_PREEMPT is not set +CONFIG_PREEMPT=y CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y @@ -115,7 +120,7 @@ # CONFIG_PCI=y CONFIG_PCI_DOMAINS=y -# CONFIG_PCI_USE_VECTOR is not set +# CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y @@ -142,6 +147,7 @@ # # Generic Driver Options # +CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set @@ -171,6 +177,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -185,7 +192,8 @@ # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_IDE_SATA is not set -# CONFIG_BLK_DEV_IDEDISK is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -206,7 +214,6 @@ # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set @@ -273,7 +280,8 @@ # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_SVW is not set # CONFIG_SCSI_ATA_PIIX is not set @@ -316,6 +324,7 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=y # CONFIG_MD_RAID6 is not set CONFIG_MD_MULTIPATH=y @@ -329,8 +338,7 @@ # Fusion MPT device support # CONFIG_FUSION=y -CONFIG_FUSION_MAX_SGE=40 -CONFIG_FUSION_ISENSE=m +CONFIG_FUSION_MAX_SGE=128 CONFIG_FUSION_CTL=m # @@ -368,11 +376,13 @@ # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set CONFIG_IPV6=m # CONFIG_IPV6_PRIVACY is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set @@ -527,6 +537,7 @@ # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set # CONFIG_STALDRV is not set +CONFIG_SGI_SNSC=y # # Serial drivers @@ -537,11 +548,11 @@ # Non-8250 serial port support # CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_SGI_L1_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -566,6 +577,7 @@ CONFIG_RAW_DRIVER=m # CONFIG_HPET is not set CONFIG_MAX_RAW_DEVS=256 +CONFIG_MMTIMER=y # # I2C support @@ -600,7 +612,6 @@ # Console display driver support # # CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y # @@ -620,6 +631,7 @@ # CONFIG_USB_DEVICEFS is not set # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -716,7 +728,7 @@ # # File systems # -CONFIG_EXT2_FS=m +CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT2_FS_SECURITY=y @@ -791,7 +803,6 @@ # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -816,10 +827,12 @@ CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m # CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m # CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set # CONFIG_CIFS_POSIX is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set @@ -906,18 +919,18 @@ # # Kernel hacking # -CONFIG_IA64_GRANULE_16MB=y -# CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_DISABLE_VHPT is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +CONFIG_DEBUG_INFO=y +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -CONFIG_DEBUG_INFO=y CONFIG_SYSVIPC_COMPAT=y # @@ -936,6 +949,7 @@ CONFIG_CRYPTO_SHA1=m # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set CONFIG_CRYPTO_DES=m # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set @@ -945,6 +959,7 @@ # CONFIG_CRYPTO_CAST6 is not set # CONFIG_CRYPTO_TEA is not set # CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set CONFIG_CRYPTO_DEFLATE=m # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set diff -Nru a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/configs/tiger_defconfig 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,1028 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Tue Sep 28 09:03:25 2004 +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_IA64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_TIME_INTERPOLATION=y +CONFIG_EFI=y +CONFIG_GENERIC_IOMAP=y +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +# CONFIG_NUMA is not set +CONFIG_VIRTUAL_MEM_MAP=y +CONFIG_IA64_CYCLONE=y +CONFIG_IOSAPIC=y +CONFIG_FORCE_MAX_ZONEORDER=18 +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_PREEMPT is not set +CONFIG_HAVE_DEC_LOCK=y +CONFIG_IA32_SUPPORT=y +CONFIG_COMPAT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# +CONFIG_EFI_VARS=y +CONFIG_EFI_PCDP=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# Power management and ACPI +# +CONFIG_PM=y +CONFIG_ACPI=y + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_THERMAL=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y + +# +# Bus options (PCI, PCMCIA) +# +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=m +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_ACPI=m +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_PCIE is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=4096 + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=m +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_FC_ATTRS=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +CONFIG_SCSI_QLOGIC_1280=y +CONFIG_SCSI_QLA2XXX=y +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_CTL is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=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=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +# CONFIG_E100_NAPI is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +# CONFIG_E1000_NAPI is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +CONFIG_TIGON3=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=y + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_VORTEX is not set +# CONFIG_GAMEPORT_FM801 is not set +# CONFIG_GAMEPORT_CS461x is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_STALDRV is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_ACPI=y +CONFIG_SERIAL_8250_NR_UARTS=6 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=m +CONFIG_AGP_I460=m +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +CONFIG_RAW_DRIVER=m +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_MAX_RAW_DEVS=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=y + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# 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_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# 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=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_POSIX is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_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 is not set +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_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_SYSVIPC_COMPAT=y + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set diff -Nru a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig --- a/arch/ia64/configs/zx1_defconfig 2004-10-18 14:56:33 -07:00 +++ b/arch/ia64/configs/zx1_defconfig 2004-10-18 14:56:33 -07:00 @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2-aegl +# Mon Sep 27 19:03:13 2004 # # @@ -7,33 +9,45 @@ # CONFIG_EXPERIMENTAL=y # CONFIG_CLEAN_COMPILE is not set -CONFIG_STANDALONE=y CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=17 CONFIG_HOTPLUG=y # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set # # Processor type and features @@ -44,54 +58,53 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y +CONFIG_GENERIC_IOMAP=y # CONFIG_IA64_GENERIC is not set # CONFIG_IA64_DIG is not set CONFIG_IA64_HP_ZX1=y # CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_HP_SIM is not set +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y # CONFIG_IA64_PAGE_SIZE_4KB is not set # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_ACPI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y CONFIG_IA64_L1_CACHE_SHIFT=7 -# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set # CONFIG_NUMA is not set CONFIG_VIRTUAL_MEM_MAP=y -CONFIG_IA64_MCA=y # CONFIG_IA64_CYCLONE is not set -CONFIG_PM=y CONFIG_IOSAPIC=y CONFIG_FORCE_MAX_ZONEORDER=18 -# CONFIG_HUGETLB_PAGE_SIZE_4GB is not set -# CONFIG_HUGETLB_PAGE_SIZE_1GB is not set -# CONFIG_HUGETLB_PAGE_SIZE_256MB is not set -CONFIG_HUGETLB_PAGE_SIZE_64MB=y -# CONFIG_HUGETLB_PAGE_SIZE_16MB is not set -# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set -# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set -# CONFIG_HUGETLB_PAGE_SIZE_256KB is not set -CONFIG_IA64_PAL_IDLE=y CONFIG_SMP=y CONFIG_NR_CPUS=16 +# CONFIG_HOTPLUG_CPU is not set # CONFIG_PREEMPT is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# CONFIG_EFI_VARS=y +CONFIG_EFI_PCDP=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y # +# Power management and ACPI +# +CONFIG_PM=y +CONFIG_ACPI=y + +# # ACPI (Advanced Configuration and Power Interface) Support # CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y CONFIG_ACPI_BUTTON=y CONFIG_ACPI_FAN=y CONFIG_ACPI_PROCESSOR=y @@ -101,8 +114,13 @@ CONFIG_ACPI_POWER=y CONFIG_ACPI_PCI=y CONFIG_ACPI_SYSTEM=y + +# +# Bus options (PCI, PCMCIA) +# CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y @@ -112,6 +130,7 @@ CONFIG_HOTPLUG_PCI=y # CONFIG_HOTPLUG_PCI_FAKE is not set CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set # CONFIG_HOTPLUG_PCI_PCIE is not set # CONFIG_HOTPLUG_PCI_SHPC is not set @@ -122,14 +141,16 @@ # CONFIG_PCMCIA is not set # -# Parallel port support +# Device Drivers # -# CONFIG_PARPORT is not set # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set # # Memory Technology Devices (MTD) @@ -137,13 +158,17 @@ # CONFIG_MTD is not set # +# Parallel port support +# +# CONFIG_PARPORT is not set + +# # Plug and Play support # # # 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 @@ -151,10 +176,11 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -# CONFIG_DCSSBLK is not set # # ATA/ATAPI/MFM/RLL support @@ -165,9 +191,9 @@ # # Please see Documentation/ide.txt for help/info on IDE drives # +# CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -187,7 +213,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set # CONFIG_IDEDMA_PCI_AUTO is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set @@ -208,33 +233,13 @@ # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set # CONFIG_IDEDMA_AUTO is not set # CONFIG_BLK_DEV_HD is not set # -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -CONFIG_FUSION=y -CONFIG_FUSION_BOOT=y -CONFIG_FUSION_MAX_SGE=40 - -# # SCSI device support # CONFIG_SCSI=y @@ -254,21 +259,28 @@ # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y # +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set + +# # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_ADVANSYS is not set -CONFIG_SCSI_MEGARAID=y +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set # CONFIG_SCSI_SATA is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -285,6 +297,7 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_QLOGIC_ISP is not set @@ -302,6 +315,28 @@ # CONFIG_SCSI_DEBUG is not set # +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_CTL is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# # Networking support # CONFIG_NET=y @@ -322,19 +357,17 @@ # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set # # IP: Virtual Server Configuration # # CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -353,10 +386,11 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -371,21 +405,27 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=y -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set # # Ethernet (10 or 100Mbit) @@ -429,6 +469,7 @@ # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set # # Ethernet (1000 Mbit) @@ -441,7 +482,6 @@ # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set CONFIG_TIGON3=y @@ -449,47 +489,39 @@ # Ethernet (10000 Mbit) # # CONFIG_IXGB is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set +# CONFIG_S2IO is not set # # Token Ring devices # # CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set # -# Amateur Radio support +# Wireless LAN (non-hamradio) # -# CONFIG_HAMRADIO is not set +# CONFIG_NET_RADIO is not set # -# IrDA (infrared) support +# Wan interfaces # -# CONFIG_IRDA is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # -# Bluetooth support +# ISDN subsystem # -# CONFIG_BT is not set +# CONFIG_ISDN is not set # -# ISDN subsystem +# Telephony Support # -# CONFIG_ISDN is not set +# CONFIG_PHONE is not set # # Input device support @@ -518,6 +550,7 @@ # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set # # Input Device Drivers @@ -541,7 +574,6 @@ # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_HCDP=y CONFIG_SERIAL_8250_ACPI=y CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_EXTENDED=y @@ -560,12 +592,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set - -# # IPMI # # CONFIG_IPMI_HANDLER is not set @@ -575,8 +601,6 @@ # # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set -# CONFIG_NVRAM is not set -# CONFIG_GEN_RTC is not set CONFIG_EFI_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -585,7 +609,6 @@ # # Ftape, the floppy tape device driver # -# CONFIG_FTAPE is not set CONFIG_AGP=y CONFIG_AGP_HP_ZX1=y CONFIG_DRM=y @@ -596,6 +619,7 @@ # CONFIG_DRM_MGA is not set # CONFIG_DRM_SIS is not set # CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set # # I2C support @@ -608,11 +632,13 @@ # CONFIG_I2C_ALGOBIT=y CONFIG_I2C_ALGOPCF=y +# CONFIG_I2C_ALGOPCA is not set # # I2C Hardware Bus support # # CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set # CONFIG_I2C_ALI15X3 is not set # CONFIG_I2C_AMD756 is not set # CONFIG_I2C_AMD8111 is not set @@ -630,30 +656,56 @@ # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set # -# I2C Hardware Sensors Chip support +# Hardware Sensors Chip support # # CONFIG_I2C_SENSOR is not set # CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set # CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set # +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -664,6 +716,167 @@ # CONFIG_DVB is not set # +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=y +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_DEBUG=y +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_BANDWIDTH=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# 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_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# # File systems # CONFIG_EXT2_FS=y @@ -693,6 +906,7 @@ CONFIG_JOLIET=y # CONFIG_ZISOFS is not set CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -700,6 +914,8 @@ CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -707,6 +923,7 @@ # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -747,11 +964,12 @@ CONFIG_EXPORTFS=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 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 # @@ -769,7 +987,6 @@ # 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 @@ -803,6 +1020,7 @@ CONFIG_NLS_ISO8859_8=y # CONFIG_NLS_CODEPAGE_1250 is not set CONFIG_NLS_CODEPAGE_1251=y +# CONFIG_NLS_ASCII is not set CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_2=y CONFIG_NLS_ISO8859_3=y @@ -819,226 +1037,11 @@ CONFIG_NLS_UTF8=y # -# Graphics support -# -CONFIG_FB=y -# CONFIG_FB_CIRRUS is not set -# CONFIG_FB_PM2 is not set -# CONFIG_FB_CYBER2000 is not set -# CONFIG_FB_IMSTT is not set -# CONFIG_FB_RIVA is not set -# CONFIG_FB_MATROX is not set -# CONFIG_FB_RADEON_OLD is not set -CONFIG_FB_RADEON=y -CONFIG_FB_RADEON_I2C=y -CONFIG_FB_RADEON_DEBUG=y -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_SIS is not set -# CONFIG_FB_NEOMAGIC is not set -# CONFIG_FB_KYRO is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_TRIDENT is not set -# CONFIG_FB_PM3 is not set -# CONFIG_FB_VIRTUAL is not set - -# -# Console display driver support -# -CONFIG_VGA_CONSOLE=y -# 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 is not set -# CONFIG_LOGO_LINUX_VGA16 is not set -CONFIG_LOGO_LINUX_CLUT224=y - -# -# Sound -# -CONFIG_SOUND=y - -# -# Advanced Linux Sound Architecture -# -CONFIG_SND=y -CONFIG_SND_SEQUENCER=y -# CONFIG_SND_SEQ_DUMMY is not set -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=y -CONFIG_SND_PCM_OSS=y -CONFIG_SND_SEQUENCER_OSS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set - -# -# Generic devices -# -# CONFIG_SND_DUMMY is not set -# CONFIG_SND_VIRMIDI is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set - -# -# PCI devices -# -# CONFIG_SND_ALI5451 is not set -# CONFIG_SND_AZT3328 is not set -# CONFIG_SND_BT87X is not set -# CONFIG_SND_CS46XX is not set -# CONFIG_SND_CS4281 is not set -# CONFIG_SND_EMU10K1 is not set -# CONFIG_SND_KORG1212 is not set -# CONFIG_SND_NM256 is not set -# CONFIG_SND_RME32 is not set -# CONFIG_SND_RME96 is not set -# CONFIG_SND_RME9652 is not set -# CONFIG_SND_HDSP is not set -# CONFIG_SND_TRIDENT is not set -# CONFIG_SND_YMFPCI is not set -# CONFIG_SND_ALS4000 is not set -# CONFIG_SND_CMIPCI is not set -# CONFIG_SND_ENS1370 is not set -# CONFIG_SND_ENS1371 is not set -# CONFIG_SND_ES1938 is not set -# CONFIG_SND_ES1968 is not set -# CONFIG_SND_MAESTRO3 is not set -CONFIG_SND_FM801=y -# CONFIG_SND_ICE1712 is not set -# CONFIG_SND_ICE1724 is not set -# CONFIG_SND_INTEL8X0 is not set -# CONFIG_SND_SONICVIBES is not set -# CONFIG_SND_VIA82XX is not set -# CONFIG_SND_VX222 is not set - -# -# ALSA USB devices -# -# CONFIG_SND_USB_AUDIO is not set - -# -# Open Sound System -# -# CONFIG_SOUND_PRIME is not set - -# -# USB support -# -CONFIG_USB=y -# CONFIG_USB_DEBUG is not set - -# -# Miscellaneous USB options -# -# CONFIG_USB_DEVICEFS is not set -CONFIG_USB_BANDWIDTH=y -# CONFIG_USB_DYNAMIC_MINORS is not set - -# -# USB Host Controller Drivers -# -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_UHCI_HCD=y - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set -CONFIG_USB_STORAGE=y -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_SDDR55 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set - -# -# USB Human Interface Devices (HID) -# -CONFIG_USB_HID=y -CONFIG_USB_HIDINPUT=y -# CONFIG_HID_FF is not set -CONFIG_USB_HIDDEV=y -# CONFIG_USB_AIPTEK is not set -# CONFIG_USB_WACOM is not set -# CONFIG_USB_KBTAB is not set -# CONFIG_USB_POWERMATE is not set -# CONFIG_USB_XPAD is not set - -# -# USB Imaging devices -# -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# -# CONFIG_USB_DABUSB is not set - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_CATC is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_RTL8150 is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set - -# -# 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_LCD is not set -# CONFIG_USB_LED is not set - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# # Library routines # +# CONFIG_CRC_CCITT is not set CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set # # Profiling support @@ -1048,18 +1051,19 @@ # # Kernel hacking # -CONFIG_IA64_GRANULE_16MB=y -# CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_SYSVIPC_COMPAT=y # # Security options @@ -1069,4 +1073,26 @@ # # Cryptographic options # -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c --- a/arch/ia64/hp/common/sba_iommu.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ia64/hp/common/sba_iommu.c 2004-10-18 14:55:55 -07:00 @@ -191,7 +191,7 @@ static unsigned long iovp_mask; struct ioc { - void *ioc_hpa; /* I/O MMU base address */ + void __iomem *ioc_hpa; /* I/O MMU base address */ char *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ unsigned long ibase; /* pdir IOV Space base */ @@ -203,6 +203,9 @@ /* clearing pdir to prevent races with allocations. */ unsigned int res_bitshift; /* from the RIGHT! */ unsigned int res_size; /* size of resource map in bytes */ +#ifdef CONFIG_NUMA + unsigned int node; /* node where this IOC lives */ +#endif #if DELAYED_RESOURCE_CNT > 0 spinlock_t saved_lock; /* may want to try to get this on a separate cacheline */ /* than res_lock for bigger systems. */ @@ -1057,7 +1060,24 @@ struct ioc *ioc; void *addr; + ioc = GET_IOC(dev); + ASSERT(ioc); + +#ifdef CONFIG_NUMA + { + struct page *page; + page = alloc_pages_node(ioc->node == MAX_NUMNODES ? + numa_node_id() : ioc->node, flags, + get_order(size)); + + if (unlikely(!page)) + return NULL; + + addr = page_address(page); + } +#else addr = (void *) __get_free_pages(flags, get_order(size)); +#endif if (unlikely(!addr)) return NULL; @@ -1081,8 +1101,6 @@ * If device can't bypass or bypass is disabled, pass the 32bit fake * device to map single to get an iova mapping. */ - ioc = GET_IOC(dev); - ASSERT(ioc); *dma_handle = sba_map_single(&ioc->sac_only_dev->dev, addr, size, 0); return addr; @@ -1135,7 +1153,7 @@ { struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ int n_mappings = 0; - u64 *pdirp = 0; + u64 *pdirp = NULL; unsigned long dma_offset = 0; dma_sg--; @@ -1799,6 +1817,10 @@ seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n", ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF)); +#ifdef CONFIG_NUMA + if (ioc->node != MAX_NUMNODES) + seq_printf(s, "NUMA node : %d\n", ioc->node); +#endif seq_printf(s, "IOVA size : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_size)/(1024*1024)); seq_printf(s, "IOVA page size : %ld kb\n", iovp_size/1024); @@ -1853,7 +1875,7 @@ { struct proc_dir_entry *dir, *entry; - dir = proc_mkdir("bus/mckinley", 0); + dir = proc_mkdir("bus/mckinley", NULL); if (!dir) return; @@ -1899,6 +1921,58 @@ printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", pci_domain_nr(bus), bus->number); } +#ifdef CONFIG_NUMA +static void __init +sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + acpi_handle phandle; + unsigned int node; + + ioc->node = MAX_NUMNODES; + + /* + * Check for a _PXM on this node first. We don't typically see + * one here, so we'll end up getting it from the parent. + */ + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer))) { + if (ACPI_FAILURE(acpi_get_parent(handle, &phandle))) + return; + + /* Reset the acpi buffer */ + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + + if (ACPI_FAILURE(acpi_evaluate_object(phandle, "_PXM", NULL, + &buffer))) + return; + } + + if (!buffer.length || !buffer.pointer) + return; + + obj = buffer.pointer; + + if (obj->type != ACPI_TYPE_INTEGER || + obj->integer.value >= MAX_PXM_DOMAINS) { + acpi_os_free(buffer.pointer); + return; + } + + node = pxm_to_nid_map[obj->integer.value]; + acpi_os_free(buffer.pointer); + + if (node >= MAX_NUMNODES || !node_online(node)) + return; + + ioc->node = node; + return; +} +#else +#define sba_map_ioc_to_node(ioc, handle) +#endif + static int __init acpi_sba_ioc_add(struct acpi_device *device) { @@ -1941,6 +2015,8 @@ if (!ioc) return 1; + /* setup NUMA node association */ + sba_map_ioc_to_node(ioc, device->handle); return 0; } diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c --- a/arch/ia64/hp/sim/simserial.c 2004-10-18 14:56:31 -07:00 +++ b/arch/ia64/hp/sim/simserial.c 2004-10-18 14:56:31 -07:00 @@ -50,10 +50,6 @@ #define _INLINE_ inline #endif -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) #define SSC_GETCHAR 21 @@ -275,7 +271,7 @@ * Then from the beginning of the buffer until necessary */ - count = MIN(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), + count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), SERIAL_XMIT_SIZE - info->xmit.tail); console->write(console, info->xmit.buf+info->xmit.tail, count); @@ -1055,7 +1051,7 @@ ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq); } - printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n", + printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n", state->line, state->port, state->irq, uart_config[state->type].name); diff -Nru a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c --- a/arch/ia64/ia32/binfmt_elf32.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ia64/ia32/binfmt_elf32.c 2004-10-18 14:57:03 -07:00 @@ -48,6 +48,7 @@ extern struct page *ia32_shared_page[]; extern unsigned long *ia32_gdt; +extern struct page *ia32_gate_page; struct page * ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int *type) @@ -59,10 +60,25 @@ return pg; } +struct page * +ia32_install_gate_page (struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *pg = ia32_gate_page; + get_page(pg); + if (type) + *type = VM_FAULT_MINOR; + return pg; +} + + static struct vm_operations_struct ia32_shared_page_vm_ops = { .nopage = ia32_install_shared_page }; +static struct vm_operations_struct ia32_gate_page_vm_ops = { + .nopage = ia32_install_gate_page +}; + void ia64_elf32_init (struct pt_regs *regs) { @@ -90,6 +106,29 @@ } /* + * When user stack is not executable, push sigreturn code to stack makes + * segmentation fault raised when returning to kernel. So now sigreturn + * code is locked in specific gate page, which is pointed by pretcode + * when setup_frame_ia32 + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_start = IA32_GATE_OFFSET; + vma->vm_end = vma->vm_start + PAGE_SIZE; + vma->vm_page_prot = PAGE_COPY_EXEC; + vma->vm_flags = VM_READ | VM_MAYREAD | VM_EXEC + | VM_MAYEXEC | VM_RESERVED; + vma->vm_ops = &ia32_gate_page_vm_ops; + down_write(¤t->mm->mmap_sem); + { + insert_vm_struct(current->mm, vma); + } + up_write(¤t->mm->mmap_sem); + } + + /* * Install LDT as anonymous memory. This gives us all-zero segment descriptors * until a task modifies them via modify_ldt(). */ @@ -187,7 +226,7 @@ mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)? PAGE_COPY_EXEC: PAGE_COPY; insert_vm_struct(current->mm, mpnt); - current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff -Nru a/arch/ia64/ia32/elfcore32.h b/arch/ia64/ia32/elfcore32.h --- a/arch/ia64/ia32/elfcore32.h 2004-10-18 14:56:32 -07:00 +++ b/arch/ia64/ia32/elfcore32.h 2004-10-18 14:56:32 -07:00 @@ -103,11 +103,15 @@ elf_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs, elf_fpregset_t *fpu) { struct ia32_user_i387_struct *fpstate = (void*)fpu; + mm_segment_t old_fs; if (!tsk->used_math) return 0; - - save_ia32_fpstate(tsk, fpstate); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + save_ia32_fpstate(tsk, (struct ia32_user_i387_struct __user *) fpstate); + set_fs(old_fs); return 1; } @@ -117,11 +121,15 @@ elf_core_copy_task_xfpregs(struct task_struct *tsk, elf_fpxregset_t *xfpu) { struct ia32_user_fxsr_struct *fpxstate = (void*) xfpu; + mm_segment_t old_fs; if (!tsk->used_math) return 0; - save_ia32_fpxstate(tsk, fpxstate); + old_fs = get_fs(); + set_fs(KERNEL_DS); + save_ia32_fpxstate(tsk, (struct ia32_user_fxsr_struct __user *) fpxstate); + set_fs(old_fs); return 1; } diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S --- a/arch/ia64/ia32/ia32_entry.S 2004-10-18 14:56:32 -07:00 +++ b/arch/ia64/ia32/ia32_entry.S 2004-10-18 14:56:32 -07:00 @@ -41,7 +41,7 @@ zxt4 out1=in1 // newsp mov out3=16 // stacksize (compensates for 16-byte scratch area) adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s - dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK + mov out0=in0 // out0 = clone_flags zxt4 out4=in2 // out4 = parent_tidptr zxt4 out5=in4 // out5 = child_tidptr br.call.sptk.many rp=do_fork @@ -311,7 +311,7 @@ data8 sys_ni_syscall /* old profil syscall holder */ data8 compat_sys_statfs data8 compat_sys_fstatfs /* 100 */ - data8 sys32_ioperm + data8 sys_ni_syscall /* ioperm */ data8 compat_sys_socketcall data8 sys_syslog data8 compat_sys_setitimer @@ -320,7 +320,7 @@ data8 compat_sys_newlstat data8 compat_sys_newfstat data8 sys_ni_syscall - data8 sys32_iopl /* 110 */ + data8 sys_ni_syscall /* iopl */ /* 110 */ data8 sys_vhangup data8 sys_ni_syscall /* used to be sys_idle */ data8 sys_ni_syscall @@ -493,6 +493,8 @@ data8 compat_sys_mq_timedreceive /* 280 */ data8 compat_sys_mq_notify data8 compat_sys_mq_getsetattr + data8 sys_ni_syscall /* reserved for kexec */ + data8 sys32_waitid // guard against failures to increase IA32_NR_syscalls .org ia32_syscall_table + 8*IA32_NR_syscalls diff -Nru a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c --- a/arch/ia64/ia32/ia32_ldt.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/ia32/ia32_ldt.c 2004-10-18 14:57:04 -07:00 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001, 2004 Hewlett-Packard Co * David Mosberger-Tang * * Adapted from arch/i386/kernel/ldt.c @@ -17,25 +17,24 @@ #include "ia32priv.h" -#define P(p) ((void *) (unsigned long) (p)) - /* * read_ldt() is not really atomic - this is not a problem since synchronization of reads * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic, * to protect the security checks done on new descriptors. */ static int -read_ldt (void *ptr, unsigned long bytecount) +read_ldt (void __user *ptr, unsigned long bytecount) { - char *src, *dst, buf[256]; /* temporary buffer (don't overflow kernel stack!) */ unsigned long bytes_left, n; + char __user *src, *dst; + char buf[256]; /* temporary buffer (don't overflow kernel stack!) */ if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE) bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE; bytes_left = bytecount; - src = (void *) IA32_LDT_OFFSET; + src = (void __user *) IA32_LDT_OFFSET; dst = ptr; while (bytes_left) { @@ -61,7 +60,7 @@ } static int -read_default_ldt (void * ptr, unsigned long bytecount) +read_default_ldt (void __user * ptr, unsigned long bytecount) { unsigned long size; int err; @@ -80,7 +79,7 @@ } static int -write_ldt (void * ptr, unsigned long bytecount, int oldmode) +write_ldt (void __user * ptr, unsigned long bytecount, int oldmode) { struct ia32_user_desc ldt_info; __u64 entry; @@ -120,7 +119,7 @@ * memory, but we still need to guard against out-of-memory, hence we must use * put_user(). */ - ret = __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number); + ret = __put_user(entry, (__u64 __user *) IA32_LDT_OFFSET + ldt_info.entry_number); ia32_load_segment_descriptors(current); return ret; } @@ -132,16 +131,16 @@ switch (func) { case 0: - ret = read_ldt(P(ptr), bytecount); + ret = read_ldt(compat_ptr(ptr), bytecount); break; case 1: - ret = write_ldt(P(ptr), bytecount, 1); + ret = write_ldt(compat_ptr(ptr), bytecount, 1); break; case 2: - ret = read_default_ldt(P(ptr), bytecount); + ret = read_default_ldt(compat_ptr(ptr), bytecount); break; case 0x11: - ret = write_ldt(P(ptr), bytecount, 0); + ret = write_ldt(compat_ptr(ptr), bytecount, 0); break; } return ret; diff -Nru a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c --- a/arch/ia64/ia32/ia32_signal.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ia64/ia32/ia32_signal.c 2004-10-18 14:55:54 -07:00 @@ -66,7 +66,7 @@ }; int -copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from) +copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 __user *from) { unsigned long tmp; int err; @@ -78,10 +78,10 @@ err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_code, &from->si_code); - if (from->si_code < 0) + if (to->si_code < 0) err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { - switch (from->si_code >> 16) { + switch (to->si_code >> 16) { case __SI_CHLD >> 16: err |= __get_user(to->si_utime, &from->si_utime); err |= __get_user(to->si_stime, &from->si_stime); @@ -92,7 +92,7 @@ break; case __SI_FAULT >> 16: err |= __get_user(tmp, &from->si_addr); - to->si_addr = (void *) tmp; + to->si_addr = (void __user *) tmp; break; case __SI_POLL >> 16: err |= __get_user(to->si_band, &from->si_band); @@ -110,7 +110,7 @@ } int -copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) +copy_siginfo_to_user32 (siginfo_t32 __user *to, siginfo_t *from) { unsigned int addr; int err; @@ -141,7 +141,8 @@ err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: - err |= __put_user((long)from->si_addr, &to->si_addr); + /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */ + err |= __put_user(from->_sifields._pad[0], &to->si_addr); break; case __SI_POLL >> 16: err |= __put_user(from->si_band, &to->si_band); @@ -202,7 +203,7 @@ */ static int -save_ia32_fpstate_live (struct _fpstate_ia32 *save) +save_ia32_fpstate_live (struct _fpstate_ia32 __user *save) { struct task_struct *tsk = current; struct pt_regs *ptp; @@ -310,7 +311,7 @@ } static int -restore_ia32_fpstate_live (struct _fpstate_ia32 *save) +restore_ia32_fpstate_live (struct _fpstate_ia32 __user *save) { struct task_struct *tsk = current; struct pt_regs *ptp; @@ -339,37 +340,37 @@ fir = ia64_getreg(_IA64_REG_AR_FIR); fdr = ia64_getreg(_IA64_REG_AR_FDR); - __get_user(mxcsr, (unsigned int *)&save->mxcsr); + __get_user(mxcsr, (unsigned int __user *)&save->mxcsr); /* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */ - __get_user(lo, (unsigned int *)&save->cw); + __get_user(lo, (unsigned int __user *)&save->cw); num64 = mxcsr & 0xff10; num64 = (num64 << 32) | (lo & 0x1f3f); - fcr = (fcr & (~0xff1000001f3f)) | num64; + fcr = (fcr & (~0xff1000001f3fUL)) | num64; /* setting bits 0..31 with sw and tag and 32..37 from mxcsr */ - __get_user(lo, (unsigned int *)&save->sw); + __get_user(lo, (unsigned int __user *)&save->sw); /* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */ if ( !(lo & 0x7f) ) lo &= (~0x8080); - __get_user(hi, (unsigned int *)&save->tag); + __get_user(hi, (unsigned int __user *)&save->tag); num64 = mxcsr & 0x3f; num64 = (num64 << 16) | (hi & 0xffff); num64 = (num64 << 16) | (lo & 0xffff); - fsr = (fsr & (~0x3fffffffff)) | num64; + fsr = (fsr & (~0x3fffffffffUL)) | num64; /* setting bits 0..47 with cssel and ipoff */ - __get_user(lo, (unsigned int *)&save->ipoff); - __get_user(hi, (unsigned int *)&save->cssel); + __get_user(lo, (unsigned int __user *)&save->ipoff); + __get_user(hi, (unsigned int __user *)&save->cssel); num64 = hi & 0xffff; num64 = (num64 << 32) | lo; - fir = (fir & (~0xffffffffffff)) | num64; + fir = (fir & (~0xffffffffffffUL)) | num64; /* setting bits 0..47 with datasel and dataoff */ - __get_user(lo, (unsigned int *)&save->dataoff); - __get_user(hi, (unsigned int *)&save->datasel); + __get_user(lo, (unsigned int __user *)&save->dataoff); + __get_user(hi, (unsigned int __user *)&save->datasel); num64 = hi & 0xffff; num64 = (num64 << 32) | lo; - fdr = (fdr & (~0xffffffffffff)) | num64; + fdr = (fdr & (~0xffffffffffffUL)) | num64; ia64_setreg(_IA64_REG_AR_FSR, fsr); ia64_setreg(_IA64_REG_AR_FCR, fcr); @@ -452,8 +453,8 @@ sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler); } -asmlinkage long -ia32_rt_sigsuspend (compat_sigset_t *uset, unsigned int sigsetsize, struct sigscratch *scr) +long +__ia32_rt_sigsuspend (compat_sigset_t *sset, unsigned int sigsetsize, struct sigscratch *scr) { extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall); sigset_t oldset, set; @@ -461,10 +462,7 @@ scr->scratch_unat = 0; /* avoid leaking kernel bits to user level */ memset(&set, 0, sizeof(&set)); - if (sigsetsize > sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) + if (memcpy(&set.sig, &sset->sig, sigsetsize)) return -EFAULT; sigdelsetmask(&set, ~_BLOCKABLE); @@ -492,9 +490,23 @@ } asmlinkage long +ia32_rt_sigsuspend (compat_sigset_t __user *uset, unsigned int sigsetsize, struct sigscratch *scr) +{ + compat_sigset_t set; + + if (sigsetsize > sizeof(compat_sigset_t)) + return -EINVAL; + + if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) + return -EFAULT; + + return __ia32_rt_sigsuspend(&set, sigsetsize, scr); +} + +asmlinkage long ia32_sigsuspend (unsigned int mask, struct sigscratch *scr) { - return ia32_rt_sigsuspend((compat_sigset_t *)&mask, sizeof(mask), scr); + return __ia32_rt_sigsuspend((compat_sigset_t *) &mask, sizeof(mask), scr); } asmlinkage long @@ -512,8 +524,8 @@ } asmlinkage long -sys32_rt_sigaction (int sig, struct sigaction32 *act, - struct sigaction32 *oact, unsigned int sigsetsize) +sys32_rt_sigaction (int sig, struct sigaction32 __user *act, + struct sigaction32 __user *oact, unsigned int sigsetsize) { struct k_sigaction new_ka, old_ka; unsigned int handler, restorer; @@ -547,7 +559,8 @@ asmlinkage long -sys32_rt_sigprocmask (int how, compat_sigset_t *set, compat_sigset_t *oset, unsigned int sigsetsize) +sys32_rt_sigprocmask (int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, + unsigned int sigsetsize) { mm_segment_t old_fs = get_fs(); sigset_t s; @@ -562,7 +575,9 @@ return -EFAULT; } set_fs(KERNEL_DS); - ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sizeof(s)); + ret = sys_rt_sigprocmask(how, + set ? (sigset_t __user *) &s : NULL, + oset ? (sigset_t __user *) &s : NULL, sizeof(s)); set_fs(old_fs); if (ret) return ret; @@ -574,10 +589,9 @@ } asmlinkage long -sys32_rt_sigtimedwait (compat_sigset_t *uthese, siginfo_t32 *uinfo, - struct compat_timespec *uts, unsigned int sigsetsize) +sys32_rt_sigtimedwait (compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo, + struct compat_timespec __user *uts, unsigned int sigsetsize) { - extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *); mm_segment_t old_fs = get_fs(); struct timespec t; siginfo_t info; @@ -589,8 +603,10 @@ if (uts && get_compat_timespec(&t, uts)) return -EFAULT; set_fs(KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL, - sigsetsize); + ret = sys_rt_sigtimedwait((sigset_t __user *) &s, + uinfo ? (siginfo_t __user *) &info : NULL, + uts ? (struct timespec __user *) &t : NULL, + sigsetsize); set_fs(old_fs); if (ret >= 0 && uinfo) { if (copy_siginfo_to_user32(uinfo, &info)) @@ -600,7 +616,7 @@ } asmlinkage long -sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo) +sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 __user *uinfo) { mm_segment_t old_fs = get_fs(); siginfo_t info; @@ -609,13 +625,13 @@ if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs(KERNEL_DS); - ret = sys_rt_sigqueueinfo(pid, sig, &info); + ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); set_fs(old_fs); return ret; } asmlinkage long -sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) +sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigaction32 __user *oact) { struct k_sigaction new_ka, old_ka; unsigned int handler, restorer; @@ -648,7 +664,7 @@ } static int -setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, +setup_sigcontext_ia32 (struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __user *fpstate, struct pt_regs *regs, unsigned long mask) { int err = 0; @@ -657,10 +673,10 @@ if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc))) return -EFAULT; - err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs); - err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs); - err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es); - err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds); + err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int __user *)&sc->fs); + err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int __user *)&sc->gs); + err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int __user *)&sc->es); + err |= __put_user(regs->r16 & 0xffff, (unsigned int __user *)&sc->ds); err |= __put_user(regs->r15, &sc->edi); err |= __put_user(regs->r14, &sc->esi); err |= __put_user(regs->r13, &sc->ebp); @@ -674,14 +690,14 @@ err |= __put_user(current->tss.error_code, &sc->err); #endif err |= __put_user(regs->cr_iip, &sc->eip); - err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); + err |= __put_user(regs->r17 & 0xffff, (unsigned int __user *)&sc->cs); /* * `eflags' is in an ar register for this context */ flag = ia64_getreg(_IA64_REG_AR_EFLAG); err |= __put_user((unsigned int)flag, &sc->eflags); err |= __put_user(regs->r12, &sc->esp_at_signal); - err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); + err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int __user *)&sc->ss); if ( save_ia32_fpstate_live(fpstate) < 0 ) err = -EFAULT; @@ -705,7 +721,7 @@ } static int -restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax) +restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 __user *sc, int *peax) { unsigned int err = 0; @@ -775,10 +791,10 @@ } { - struct _fpstate_ia32 *buf = NULL; + struct _fpstate_ia32 __user *buf = NULL; u32 fpstate_ptr; err |= get_user(fpstate_ptr, &(sc->fpstate)); - buf = (struct _fpstate_ia32 *)(u64)fpstate_ptr; + buf = compat_ptr(fpstate_ptr); if (buf) { err |= restore_ia32_fpstate_live(buf); } @@ -808,7 +824,7 @@ /* * Determine which stack to use.. */ -static inline void * +static inline void __user * get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long esp; @@ -823,14 +839,14 @@ } /* Legacy stack switching not supported */ - return (void *)((esp - frame_size) & -8ul); + return (void __user *)((esp - frame_size) & -8ul); } static int setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { struct exec_domain *ed = current_thread_info()->exec_domain; - struct sigframe_ia32 *frame; + struct sigframe_ia32 __user *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -853,14 +869,19 @@ unsigned int restorer = IA32_SA_RESTORER(ka); err |= __put_user(restorer, &frame->pretcode); } else { - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is popl %eax ; movl $,%eax ; int $0x80 */ - err |= __put_user(0xb858, (short *)(frame->retcode+0)); - err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); - err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4)); - err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + /* Pointing to restorer in ia32 gate page */ + err |= __put_user(IA32_GATE_OFFSET, &frame->pretcode); } + /* This is popl %eax ; movl $,%eax ; int $0x80 + * and there for historical reasons only. + * See arch/i386/kernel/signal.c + */ + + err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_sigreturn, (int __user *)(frame->retcode+2)); + err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); + if (err) goto give_sigsegv; @@ -882,9 +903,7 @@ return 1; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); return 0; } @@ -893,7 +912,8 @@ sigset_t *set, struct pt_regs * regs) { struct exec_domain *ed = current_thread_info()->exec_domain; - struct rt_sigframe_ia32 *frame; + compat_uptr_t pinfo, puc; + struct rt_sigframe_ia32 __user *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -903,8 +923,11 @@ err |= __put_user((ed && ed->signal_invmap && sig < 32 ? ed->signal_invmap[sig] : sig), &frame->sig); - err |= __put_user((long)&frame->info, &frame->pinfo); - err |= __put_user((long)&frame->uc, &frame->puc); + + pinfo = (long __user) &frame->info; + puc = (long __user) &frame->uc; + err |= __put_user(pinfo, &frame->pinfo); + err |= __put_user(puc, &frame->puc); err |= copy_siginfo_to_user32(&frame->info, info); /* Create the ucontext. */ @@ -924,13 +947,19 @@ unsigned int restorer = IA32_SA_RESTORER(ka); err |= __put_user(restorer, &frame->pretcode); } else { - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is movl $,%eax ; int $0x80 */ - err |= __put_user(0xb8, (char *)(frame->retcode+0)); - err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + /* Pointing to rt_restorer in ia32 gate page */ + err |= __put_user(IA32_GATE_OFFSET + 8, &frame->pretcode); } + /* This is movl $,%eax ; int $0x80 + * and there for historical reasons only. + * See arch/i386/kernel/signal.c + */ + + err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_rt_sigreturn, (int __user *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); + if (err) goto give_sigsegv; @@ -952,9 +981,7 @@ return 1; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); return 0; } @@ -975,7 +1002,7 @@ { struct pt_regs *regs = (struct pt_regs *) &stack; unsigned long esp = (unsigned int) regs->r12; - struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(esp - 8); + struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(esp - 8); sigset_t set; int eax; @@ -989,7 +1016,7 @@ sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); - current->blocked = (sigset_t) set; + current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); @@ -1008,9 +1035,8 @@ { struct pt_regs *regs = (struct pt_regs *) &stack; unsigned long esp = (unsigned int) regs->r12; - struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(esp - 4); + struct rt_sigframe_ia32 __user *frame = (struct rt_sigframe_ia32 __user *)(esp - 4); sigset_t set; - stack_t st; int eax; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) @@ -1027,11 +1053,9 @@ if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax)) goto badframe; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, esp); + do_sigaltstack((stack_t __user *) &frame->uc.uc_stack, NULL, esp); return eax; diff -Nru a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c --- a/arch/ia64/ia32/ia32_support.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ia64/ia32/ia32_support.c 2004-10-18 14:55:54 -07:00 @@ -33,6 +33,7 @@ struct page *ia32_shared_page[NR_CPUS]; unsigned long *ia32_boot_gdt; unsigned long *cpu_gdt_table[NR_CPUS]; +struct page *ia32_gate_page; static unsigned long load_desc (u16 selector) @@ -75,7 +76,7 @@ struct ia32_user_desc info; int idx; - if (copy_from_user(&info, (void *)(childregs->r14 & 0xffffffff), sizeof(info))) + if (copy_from_user(&info, (void __user *)(childregs->r14 & 0xffffffff), sizeof(info))) return -EFAULT; if (LDT_empty(&info)) return -EINVAL; @@ -145,6 +146,9 @@ int cpu = smp_processor_id(); ia32_shared_page[cpu] = alloc_page(GFP_KERNEL); + if (!ia32_shared_page[cpu]) + panic("failed to allocate ia32_shared_page[%d]\n", cpu); + cpu_gdt_table[cpu] = page_address(ia32_shared_page[cpu]); /* Copy from the boot cpu's GDT */ @@ -155,23 +159,26 @@ /* * Setup IA32 GDT and TSS */ -void +static void ia32_boot_gdt_init (void) { unsigned long ldt_size; ia32_shared_page[0] = alloc_page(GFP_KERNEL); + if (!ia32_shared_page[0]) + panic("failed to allocate ia32_shared_page[0]\n"); + ia32_boot_gdt = page_address(ia32_shared_page[0]); cpu_gdt_table[0] = ia32_boot_gdt; /* CS descriptor in IA-32 (scrambled) format */ ia32_boot_gdt[__USER_CS >> 3] - = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT, 0xb, 1, 3, 1, 1, 1, 1); /* DS descriptor in IA-32 (scrambled) format */ ia32_boot_gdt[__USER_DS >> 3] - = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT, 0x3, 1, 3, 1, 1, 1, 1); ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); @@ -181,6 +188,27 @@ 0x2, 0, 3, 1, 1, 1, 0); } +static void +ia32_gate_page_init(void) +{ + unsigned long *sr; + + ia32_gate_page = alloc_page(GFP_KERNEL); + sr = page_address(ia32_gate_page); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + *sr++ = 0xb858 | (__IA32_NR_sigreturn << 16) | (0x80cdUL << 48); + + /* This is movl $,%eax ; int $0x80 */ + *sr = 0xb8 | (__IA32_NR_rt_sigreturn << 8) | (0x80cdUL << 40); +} + +void +ia32_mem_init(void) +{ + ia32_boot_gdt_init(); + ia32_gate_page_init(); +} + /* * Handle bad IA32 interrupt via syscall */ @@ -195,7 +223,7 @@ siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */ siginfo.si_flags = 0; siginfo.si_isr = 0; - siginfo.si_addr = 0; + siginfo.si_addr = NULL; siginfo.si_imm = 0; siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); diff -Nru a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h --- a/arch/ia64/ia32/ia32priv.h 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/ia32/ia32priv.h 2004-10-18 14:57:04 -07:00 @@ -168,6 +168,9 @@ #define IA32_SA_HANDLER(ka) ((unsigned long) (ka)->sa.sa_handler & 0xffffffff) #define IA32_SA_RESTORER(ka) ((unsigned long) (ka)->sa.sa_handler >> 32) +#define __IA32_NR_sigreturn 119 +#define __IA32_NR_rt_sigreturn 173 + struct sigaction32 { unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ unsigned int sa_flags; @@ -324,14 +327,16 @@ #define IA32_PAGE_OFFSET 0xc0000000 #define IA32_STACK_TOP IA32_PAGE_OFFSET +#define IA32_GATE_OFFSET IA32_PAGE_OFFSET +#define IA32_GATE_END IA32_PAGE_OFFSET + PAGE_SIZE /* * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can * access them. */ -#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET) -#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) -#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) +#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) +#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) +#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 3*PAGE_SIZE) #define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE @@ -356,7 +361,7 @@ /* This macro yields a string that ld.so will use to load implementation specific libraries for optimization. Not terribly relevant until we have real hardware to play with... */ -#define ELF_PLATFORM 0 +#define ELF_PLATFORM NULL #ifdef __KERNEL__ # define SET_PERSONALITY(EX,IBCS2) \ @@ -434,7 +439,7 @@ | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB) \ | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G)) -#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */ +#define IA32_IOBASE 0x2000000000000000UL /* Virtual address for I/O space */ #define IA32_CR0 0x80000001 /* Enable PG and PE bits */ #define IA32_CR4 0x600 /* MMXEX and FXSR on */ @@ -551,8 +556,8 @@ }; /* Prototypes for use in elfcore32.h */ -extern int save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save); -extern int save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save); +extern int save_ia32_fpstate (struct task_struct *, struct ia32_user_i387_struct __user *); +extern int save_ia32_fpxstate (struct task_struct *, struct ia32_user_fxsr_struct __user *); #endif /* !CONFIG_IA32_SUPPORT */ diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ia64/ia32/sys_ia32.c 2004-10-18 14:56:33 -07:00 @@ -70,10 +70,7 @@ # define DBG(fmt...) #endif -#define A(__x) ((unsigned long)(__x)) -#define AA(__x) ((unsigned long)(__x)) #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) -#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define OFFSET4K(a) ((a) & 0xfff) #define PAGE_START(addr) ((addr) & PAGE_MASK) @@ -82,9 +79,6 @@ #define high2lowuid(uid) ((uid) > 65535 ? 65534 : (uid)) #define high2lowgid(gid) ((gid) > 65535 ? 65534 : (gid)) -extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsigned long, - unsigned long, unsigned long); - /* * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore * while doing so. @@ -93,7 +87,8 @@ static DECLARE_MUTEX(ia32_mmap_sem); asmlinkage long -sys32_execve (char *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp, struct pt_regs *regs) +sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp, + struct pt_regs *regs) { long error; char *filename; @@ -128,7 +123,7 @@ return error; } -int cp_compat_stat(struct kstat *stat, struct compat_stat *ubuf) +int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) { int err; @@ -199,7 +194,7 @@ /* Optimize the case where the old mmap and the new mmap are both anonymous */ if ((old_prot & PROT_WRITE) && (flags & MAP_ANONYMOUS) && !vma->vm_file) { - if (clear_user((void *) start, end - start)) { + if (clear_user((void __user *) start, end - start)) { ret = -EFAULT; goto out; } @@ -211,11 +206,11 @@ return -ENOMEM; if (old_prot) - copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE); + copy_from_user(page, (void __user *) PAGE_START(start), PAGE_SIZE); down_write(¤t->mm->mmap_sem); { - ret = do_mmap(0, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE, + ret = do_mmap(NULL, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE, flags | MAP_FIXED | MAP_ANONYMOUS, 0); } up_write(¤t->mm->mmap_sem); @@ -226,9 +221,10 @@ if (old_prot) { /* copy back the old page contents. */ if (offset_in_page(start)) - copy_to_user((void *) PAGE_START(start), page, offset_in_page(start)); + copy_to_user((void __user *) PAGE_START(start), page, + offset_in_page(start)); if (offset_in_page(end)) - copy_to_user((void *) end, page + offset_in_page(end), + copy_to_user((void __user *) end, page + offset_in_page(end), PAGE_SIZE - offset_in_page(end)); } @@ -236,7 +232,7 @@ /* read the file contents */ inode = file->f_dentry->d_inode; if (!inode->i_fop || !file->f_op->read - || ((*file->f_op->read)(file, (char *) start, end - start, &off) < 0)) + || ((*file->f_op->read)(file, (char __user *) start, end - start, &off) < 0)) { ret = -EINVAL; goto out; @@ -266,9 +262,9 @@ if ((p = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) return p; - p->pp_head = 0; + p->pp_head = NULL; p->ppl_rb = RB_ROOT; - p->pp_hint = 0; + p->pp_hint = NULL; atomic_set(&p->pp_count, 1); return p; } @@ -825,7 +821,7 @@ if (!(flags & MAP_ANONYMOUS) && is_congruent) ret = do_mmap(file, pstart, pend - pstart, prot, flags | MAP_FIXED, poff); else - ret = do_mmap(0, pstart, pend - pstart, + ret = do_mmap(NULL, pstart, pend - pstart, prot | ((flags & MAP_ANONYMOUS) ? 0 : PROT_WRITE), flags | MAP_FIXED | MAP_ANONYMOUS, 0); } @@ -838,7 +834,8 @@ /* read the file contents */ inode = file->f_dentry->d_inode; if (!inode->i_fop || !file->f_op->read - || ((*file->f_op->read)(file, (char *) pstart, pend - pstart, &poff) < 0)) + || ((*file->f_op->read)(file, (char __user *) pstart, pend - pstart, &poff) + < 0)) { sys_munmap(pstart, pend - pstart); return -EINVAL; @@ -927,7 +924,7 @@ }; asmlinkage long -sys32_mmap (struct mmap_arg_struct *arg) +sys32_mmap (struct mmap_arg_struct __user *arg) { struct mmap_arg_struct a; struct file *file = NULL; @@ -1140,7 +1137,7 @@ } asmlinkage long -sys32_pipe (int *fd) +sys32_pipe (int __user *fd) { int retval; int fds[2]; @@ -1155,14 +1152,14 @@ } static inline long -get_tv32 (struct timeval *o, struct compat_timeval *i) +get_tv32 (struct timeval *o, struct compat_timeval __user *i) { return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec))); } static inline long -put_tv32 (struct compat_timeval *o, struct timeval *i) +put_tv32 (struct compat_timeval __user *o, struct timeval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec))); @@ -1192,7 +1189,7 @@ extern struct timezone sys_tz; asmlinkage long -sys32_gettimeofday (struct compat_timeval *tv, struct timezone *tz) +sys32_gettimeofday (struct compat_timeval __user *tv, struct timezone __user *tz) { if (tv) { struct timeval ktv; @@ -1208,7 +1205,7 @@ } asmlinkage long -sys32_settimeofday (struct compat_timeval *tv, struct timezone *tz) +sys32_settimeofday (struct compat_timeval __user *tv, struct timezone __user *tz) { struct timeval ktv; struct timespec kts; @@ -1229,14 +1226,14 @@ } struct getdents32_callback { - struct compat_dirent * current_dir; - struct compat_dirent * previous; + struct compat_dirent __user *current_dir; + struct compat_dirent __user *previous; int count; int error; }; struct readdir32_callback { - struct old_linux32_dirent * dirent; + struct old_linux32_dirent __user * dirent; int count; }; @@ -1244,9 +1241,9 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { - struct compat_dirent * dirent; + struct compat_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; - int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); + int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) @@ -1263,17 +1260,17 @@ || copy_to_user(dirent->d_name, name, namlen) || put_user(0, dirent->d_name + namlen)) return -EFAULT; - dirent = (struct compat_dirent *) ((char *) dirent + reclen); + dirent = (struct compat_dirent __user *) ((char __user *) dirent + reclen); buf->current_dir = dirent; buf->count -= reclen; return 0; } asmlinkage long -sys32_getdents (unsigned int fd, struct compat_dirent *dirent, unsigned int count) +sys32_getdents (unsigned int fd, struct compat_dirent __user *dirent, unsigned int count) { struct file * file; - struct compat_dirent * lastdirent; + struct compat_dirent __user * lastdirent; struct getdents32_callback buf; int error; @@ -1310,7 +1307,7 @@ unsigned int d_type) { struct readdir32_callback * buf = (struct readdir32_callback *) __buf; - struct old_linux32_dirent * dirent; + struct old_linux32_dirent __user * dirent; if (buf->count) return -EINVAL; @@ -1326,7 +1323,7 @@ } asmlinkage long -sys32_readdir (unsigned int fd, void *dirent, unsigned int count) +sys32_readdir (unsigned int fd, void __user *dirent, unsigned int count) { int error; struct file * file; @@ -1357,7 +1354,7 @@ }; asmlinkage long -sys32_old_select (struct sel_arg_struct *arg) +sys32_old_select (struct sel_arg_struct __user *arg) { struct sel_arg_struct a; @@ -1434,7 +1431,7 @@ * so we have to implement this system call here. */ asmlinkage long -sys32_time (int *tloc) +sys32_time (int __user *tloc) { int i; struct timeval tv; @@ -1564,8 +1561,8 @@ } static void -put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, - int tos) +put_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp, + struct switch_stack *swp, int tos) { struct _fpreg_ia32 *f; char buf[32]; @@ -1597,8 +1594,8 @@ } static void -get_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, - int tos) +get_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp, + struct switch_stack *swp, int tos) { if ((regno += tos) >= 8) @@ -1627,7 +1624,7 @@ } int -save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save) +save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1656,7 +1653,7 @@ } static int -restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save) +restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1666,15 +1663,15 @@ if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); - __get_user(num32, (unsigned int *)&save->cwd); + __get_user(num32, (unsigned int __user *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); - __get_user(fsrlo, (unsigned int *)&save->swd); - __get_user(fsrhi, (unsigned int *)&save->twd); + __get_user(fsrlo, (unsigned int __user *)&save->swd); + __get_user(fsrhi, (unsigned int __user *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->fip); + __get_user(num32, (unsigned int __user *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->foo); + __get_user(num32, (unsigned int __user *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* @@ -1689,7 +1686,7 @@ } int -save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) +save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1715,7 +1712,7 @@ ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + put_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos); mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f); __put_user(mxcsr & 0xffff, &save->mxcsr); @@ -1728,7 +1725,7 @@ } static int -restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) +restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1741,15 +1738,15 @@ if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); - __get_user(num32, (unsigned int *)&save->cwd); + __get_user(num32, (unsigned int __user *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); - __get_user(fsrlo, (unsigned int *)&save->swd); - __get_user(fsrhi, (unsigned int *)&save->twd); + __get_user(fsrlo, (unsigned int __user *)&save->swd); + __get_user(fsrhi, (unsigned int __user *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->fip); + __get_user(num32, (unsigned int __user *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->foo); + __get_user(num32, (unsigned int __user *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* @@ -1759,13 +1756,13 @@ ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + get_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos); - __get_user(mxcsr, (unsigned int *)&save->mxcsr); + __get_user(mxcsr, (unsigned int __user *)&save->mxcsr); num64 = mxcsr & 0xff10; - tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000)) | (num64<<32); + tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000UL)) | (num64<<32); num64 = mxcsr & 0x3f; - tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000)) | (num64<<32); + tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000UL)) | (num64<<32); for (i = 0; i < 8; i++) { copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32)); @@ -1823,7 +1820,7 @@ case PTRACE_PEEKDATA: /* read word at location addr */ ret = ia32_peek(regs, child, addr, &value); if (ret == 0) - ret = put_user(value, (unsigned int *) A(data)); + ret = put_user(value, (unsigned int __user *) compat_ptr(data)); else ret = -EIO; goto out_tsk; @@ -1839,7 +1836,7 @@ break; tmp = getreg(child, addr); - if (!put_user(tmp, (unsigned int *) A(data))) + if (!put_user(tmp, (unsigned int __user *) compat_ptr(data))) ret = 0; break; @@ -1853,24 +1850,24 @@ break; case IA32_PTRACE_GETREGS: - if (!access_ok(VERIFY_WRITE, (int *) A(data), 17*sizeof(int))) { + if (!access_ok(VERIFY_WRITE, compat_ptr(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { - put_user(getreg(child, i), (unsigned int *) A(data)); + put_user(getreg(child, i), (unsigned int __user *) compat_ptr(data)); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_SETREGS: - if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) { + if (!access_ok(VERIFY_READ, compat_ptr(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { - get_user(tmp, (unsigned int *) A(data)); + get_user(tmp, (unsigned int __user *) compat_ptr(data)); putreg(child, i, tmp); data += sizeof(int); } @@ -1878,19 +1875,23 @@ break; case IA32_PTRACE_GETFPREGS: - ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data)); + ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct __user *) + compat_ptr(data)); break; case IA32_PTRACE_GETFPXREGS: - ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data)); + ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *) + compat_ptr(data)); break; case IA32_PTRACE_SETFPREGS: - ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data)); + ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct __user *) + compat_ptr(data)); break; case IA32_PTRACE_SETFPXREGS: - ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data)); + ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *) + compat_ptr(data)); break; case PTRACE_SYSCALL: /* continue, stop after next syscall */ @@ -1913,73 +1914,6 @@ return ret; } -/* - * The IA64 maps 4 I/O ports for each 4K page - */ -#define IOLEN ((65536 / 4) * 4096) - -asmlinkage long -sys32_iopl (int level) -{ - extern unsigned long ia64_iobase; - int fd; - struct file * file; - unsigned int old; - unsigned long addr; - mm_segment_t old_fs = get_fs (); - - if (level != 3) - return(-EINVAL); - /* Trying to gain more privileges? */ - old = ia64_getreg(_IA64_REG_AR_EFLAG); - if ((unsigned int) level > ((old >> 12) & 3)) { - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - } - set_fs(KERNEL_DS); - fd = sys_open("/dev/mem", O_SYNC | O_RDWR, 0); - set_fs(old_fs); - if (fd < 0) - return fd; - file = fget(fd); - if (file == NULL) { - sys_close(fd); - return(-EFAULT); - } - - down_write(¤t->mm->mmap_sem); - addr = do_mmap_pgoff(file, IA32_IOBASE, - IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED, - (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); - - if (addr >= 0) { - old = (old & ~0x3000) | (level << 12); - ia64_setreg(_IA64_REG_AR_EFLAG, old); - } - - fput(file); - sys_close(fd); - return 0; -} - -asmlinkage long -sys32_ioperm (unsigned int from, unsigned int num, int on) -{ - - /* - * Since IA64 doesn't have permission bits we'd have to go to - * a lot of trouble to simulate them in software. There's - * no point, only trusted programs can make this call so we'll - * just turn it into an iopl call and let the process have - * access to all I/O ports. - * - * XXX proper ioperm() support should be emulated by - * manipulating the page protections... - */ - return sys32_iopl(3); -} - typedef struct { unsigned int ss_sp; unsigned int ss_flags; @@ -1987,7 +1921,7 @@ } ia32_stack_t; asmlinkage long -sys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32, +sys32_sigaltstack (ia32_stack_t __user *uss32, ia32_stack_t __user *uoss32, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt = (struct pt_regs *) &stack; @@ -1999,9 +1933,9 @@ if (uss32) { if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t))) return -EFAULT; - uss.ss_sp = (void *) (long) buf32.ss_sp; + uss.ss_sp = (void __user *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; - /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the + /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the check and set it to the user requested value later */ if ((buf32.ss_flags != SS_DISABLE) && (buf32.ss_size < MINSIGSTKSZ_IA32)) { ret = -ENOMEM; @@ -2010,14 +1944,15 @@ uss.ss_size = MINSIGSTKSZ; } set_fs(KERNEL_DS); - ret = do_sigaltstack(uss32 ? &uss : NULL, &uoss, pt->r12); - current->sas_ss_size = buf32.ss_size; + ret = do_sigaltstack(uss32 ? (stack_t __user *) &uss : NULL, + (stack_t __user *) &uoss, pt->r12); + current->sas_ss_size = buf32.ss_size; set_fs(old_fs); out: if (ret < 0) return(ret); if (uoss32) { - buf32.ss_sp = (long) uoss.ss_sp; + buf32.ss_sp = (long __user) uoss.ss_sp; buf32.ss_flags = uoss.ss_flags; buf32.ss_size = uoss.ss_size; if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t))) @@ -2056,14 +1991,14 @@ }; asmlinkage long -sys32_sysctl (struct sysctl32 *args) +sys32_sysctl (struct sysctl32 __user *args) { #ifdef CONFIG_SYSCTL struct sysctl32 a32; mm_segment_t old_fs = get_fs (); - void *oldvalp, *newvalp; + void __user *oldvalp, *newvalp; size_t oldlen; - int *namep; + int __user *namep; long ret; if (copy_from_user(&a32, args, sizeof(a32))) @@ -2076,11 +2011,11 @@ * addresses, we KNOW that access_ok() will always succeed, so this is an * expensive NOP, but so what... */ - namep = (int *) A(a32.name); - oldvalp = (void *) A(a32.oldval); - newvalp = (void *) A(a32.newval); + namep = (int __user *) compat_ptr(a32.name); + oldvalp = compat_ptr(a32.oldval); + newvalp = compat_ptr(a32.newval); - if ((oldvalp && get_user(oldlen, (int *) A(a32.oldlenp))) + if ((oldvalp && get_user(oldlen, (int __user *) compat_ptr(a32.oldlenp))) || !access_ok(VERIFY_WRITE, namep, 0) || !access_ok(VERIFY_WRITE, oldvalp, 0) || !access_ok(VERIFY_WRITE, newvalp, 0)) @@ -2088,11 +2023,12 @@ set_fs(KERNEL_DS); lock_kernel(); - ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen); + ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *) &oldlen, + newvalp, (size_t) a32.newlen); unlock_kernel(); set_fs(old_fs); - if (oldvalp && put_user (oldlen, (int *) A(a32.oldlenp))) + if (oldvalp && put_user (oldlen, (int __user *) compat_ptr(a32.oldlenp))) return -EFAULT; return ret; @@ -2102,7 +2038,7 @@ } asmlinkage long -sys32_newuname (struct new_utsname *name) +sys32_newuname (struct new_utsname __user *name) { int ret = sys_newuname(name); @@ -2113,14 +2049,14 @@ } asmlinkage long -sys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid) +sys32_getresuid16 (u16 __user *ruid, u16 __user *euid, u16 __user *suid) { uid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_getresuid(&a, &b, &c); + ret = sys_getresuid((uid_t __user *) &a, (uid_t __user *) &b, (uid_t __user *) &c); set_fs(old_fs); if (put_user(a, ruid) || put_user(b, euid) || put_user(c, suid)) @@ -2129,14 +2065,14 @@ } asmlinkage long -sys32_getresgid16 (u16 *rgid, u16 *egid, u16 *sgid) +sys32_getresgid16 (u16 __user *rgid, u16 __user *egid, u16 __user *sgid) { gid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_getresgid(&a, &b, &c); + ret = sys_getresgid((gid_t __user *) &a, (gid_t __user *) &b, (gid_t __user *) &c); set_fs(old_fs); if (ret) @@ -2153,7 +2089,7 @@ } static int -groups16_to_user(short *grouplist, struct group_info *group_info) +groups16_to_user(short __user *grouplist, struct group_info *group_info) { int i; short group; @@ -2168,7 +2104,7 @@ } static int -groups16_from_user(struct group_info *group_info, short *grouplist) +groups16_from_user(struct group_info *group_info, short __user *grouplist) { int i; short group; @@ -2183,7 +2119,7 @@ } asmlinkage long -sys32_getgroups16 (int gidsetsize, short *grouplist) +sys32_getgroups16 (int gidsetsize, short __user *grouplist) { int i; @@ -2208,7 +2144,7 @@ } asmlinkage long -sys32_setgroups16 (int gidsetsize, short *grouplist) +sys32_setgroups16 (int gidsetsize, short __user *grouplist) { struct group_info *group_info; int retval; @@ -2236,7 +2172,7 @@ asmlinkage long sys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi) { - return sys_truncate((const char *) A(path), ((unsigned long) len_hi << 32) | len_lo); + return sys_truncate(compat_ptr(path), ((unsigned long) len_hi << 32) | len_lo); } asmlinkage long @@ -2246,7 +2182,7 @@ } static int -putstat64 (struct stat64 *ubuf, struct kstat *kbuf) +putstat64 (struct stat64 __user *ubuf, struct kstat *kbuf) { int err; u64 hdev; @@ -2255,8 +2191,8 @@ return -EFAULT; hdev = huge_encode_dev(kbuf->dev); - err = __put_user(hdev, (u32*)&ubuf->st_dev); - err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_dev) + 1); + err = __put_user(hdev, (u32 __user*)&ubuf->st_dev); + err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_dev) + 1); err |= __put_user(kbuf->ino, &ubuf->__st_ino); err |= __put_user(kbuf->ino, &ubuf->st_ino_lo); err |= __put_user(kbuf->ino >> 32, &ubuf->st_ino_hi); @@ -2265,8 +2201,8 @@ err |= __put_user(kbuf->uid, &ubuf->st_uid); err |= __put_user(kbuf->gid, &ubuf->st_gid); hdev = huge_encode_dev(kbuf->rdev); - err = __put_user(hdev, (u32*)&ubuf->st_rdev); - err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_rdev) + 1); + err = __put_user(hdev, (u32 __user*)&ubuf->st_rdev); + err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_rdev) + 1); err |= __put_user(kbuf->size, &ubuf->st_size_lo); err |= __put_user((kbuf->size >> 32), &ubuf->st_size_hi); err |= __put_user(kbuf->atime.tv_sec, &ubuf->st_atime); @@ -2281,7 +2217,7 @@ } asmlinkage long -sys32_stat64 (char *filename, struct stat64 *statbuf) +sys32_stat64 (char __user *filename, struct stat64 __user *statbuf) { struct kstat s; long ret = vfs_stat(filename, &s); @@ -2291,7 +2227,7 @@ } asmlinkage long -sys32_lstat64 (char *filename, struct stat64 *statbuf) +sys32_lstat64 (char __user *filename, struct stat64 __user *statbuf) { struct kstat s; long ret = vfs_lstat(filename, &s); @@ -2301,7 +2237,7 @@ } asmlinkage long -sys32_fstat64 (unsigned int fd, struct stat64 *statbuf) +sys32_fstat64 (unsigned int fd, struct stat64 __user *statbuf) { struct kstat s; long ret = vfs_fstat(fd, &s); @@ -2328,7 +2264,7 @@ }; asmlinkage long -sys32_sysinfo (struct sysinfo32 *info) +sys32_sysinfo (struct sysinfo32 __user *info) { struct sysinfo s; long ret, err; @@ -2336,7 +2272,7 @@ mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_sysinfo(&s); + ret = sys_sysinfo((struct sysinfo __user *) &s); set_fs(old_fs); /* Check to see if any memory value is too large for 32-bit and * scale down if needed. @@ -2379,14 +2315,14 @@ } asmlinkage long -sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec *interval) +sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec __user *interval) { mm_segment_t old_fs = get_fs(); struct timespec t; long ret; set_fs(KERNEL_DS); - ret = sys_sched_rr_get_interval(pid, &t); + ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t); set_fs(old_fs); if (put_compat_timespec(&t, interval)) return -EFAULT; @@ -2394,19 +2330,19 @@ } asmlinkage long -sys32_pread (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) +sys32_pread (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi) { return sys_pread64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); } asmlinkage long -sys32_pwrite (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) +sys32_pwrite (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi) { return sys_pwrite64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); } asmlinkage long -sys32_sendfile (int out_fd, int in_fd, int *offset, unsigned int count) +sys32_sendfile (int out_fd, int in_fd, int __user *offset, unsigned int count) { mm_segment_t old_fs = get_fs(); long ret; @@ -2416,7 +2352,7 @@ return -EFAULT; set_fs(KERNEL_DS); - ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *) &of : NULL, count); set_fs(old_fs); if (!ret && offset && put_user(of, offset)) @@ -2447,7 +2383,7 @@ obrk = mm->brk; ret = sys_brk(brk); if (ret < obrk) - clear_user((void *) ret, PAGE_ALIGN(ret) - ret); + clear_user(compat_ptr(ret), PAGE_ALIGN(ret) - ret); return ret; } @@ -2455,7 +2391,7 @@ * Exactly like fs/open.c:sys_open(), except that it doesn't set the O_LARGEFILE flag. */ asmlinkage long -sys32_open (const char * filename, int flags, int mode) +sys32_open (const char __user * filename, int flags, int mode) { char * tmp; int fd, error; @@ -2487,10 +2423,10 @@ { u32 events; u32 data[2]; -}; +}; asmlinkage long -sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 *event) +sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 __user *event) { mm_segment_t old_fs = get_fs(); struct epoll_event event64; @@ -2508,14 +2444,14 @@ event64.data |= (u64)data_halfword << 32; set_fs(KERNEL_DS); - error = sys_epoll_ctl(epfd, op, fd, &event64); + error = sys_epoll_ctl(epfd, op, fd, (struct epoll_event __user *) &event64); set_fs(old_fs); return error; } asmlinkage long -sys32_epoll_wait(int epfd, struct epoll_event32 *events, int maxevents, +sys32_epoll_wait(int epfd, struct epoll_event32 __user * events, int maxevents, int timeout) { struct epoll_event *events64 = NULL; @@ -2533,8 +2469,8 @@ maxevents * sizeof(struct epoll_event32)))) return error; - /* - * Allocate space for the intermediate copy. If the space needed + /* + * Allocate space for the intermediate copy. If the space needed * is large enough to cause kmalloc to fail, then try again with * __get_free_pages. */ @@ -2543,14 +2479,15 @@ if (events64 == NULL) { events64 = (struct epoll_event *) __get_free_pages(GFP_KERNEL, get_order(size)); - if (events64 == NULL) + if (events64 == NULL) return -ENOMEM; do_free_pages = 1; } /* Do the system call */ set_fs(KERNEL_DS); /* copy_to/from_user should work on kernel mem*/ - numevents = sys_epoll_wait(epfd, events64, maxevents, timeout); + numevents = sys_epoll_wait(epfd, (struct epoll_event __user *) events64, + maxevents, timeout); set_fs(old_fs); /* Don't modify userspace memory if we're returning an error */ @@ -2593,7 +2530,7 @@ * Set a given TLS descriptor: */ asmlinkage int -sys32_set_thread_area (struct ia32_user_desc *u_info) +sys32_set_thread_area (struct ia32_user_desc __user *u_info) { struct thread_struct *t = ¤t->thread; struct ia32_user_desc info; @@ -2654,7 +2591,7 @@ #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) asmlinkage int -sys32_get_thread_area (struct ia32_user_desc *u_info) +sys32_get_thread_area (struct ia32_user_desc __user *u_info) { struct ia32_user_desc info; struct desc_struct *desc; @@ -2682,12 +2619,8 @@ return 0; } -extern asmlinkage long -sys_timer_create(clockid_t which_clock, struct sigevent *timer_event_spec, - timer_t * created_timer_id); - asmlinkage long -sys32_timer_create(u32 clock, struct sigevent32 *se32, timer_t *timer_id) +sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id) { struct sigevent se; mm_segment_t oldfs; @@ -2710,7 +2643,7 @@ oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_timer_create(clock, &se, &t); + err = sys_timer_create(clock, (struct sigevent __user *) &se, (timer_t __user *) &t); set_fs(oldfs); if (!err) @@ -2727,6 +2660,32 @@ (((u64)len_high)<<32) | len_low, advice); } + +asmlinkage long sys32_waitid(int which, compat_pid_t pid, + siginfo_t32 __user *uinfo, int options, + struct compat_rusage __user *uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + info.si_signo = 0; + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, + uru ? &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru && (ret = put_compat_rusage(&ru, uru))) + return ret; + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return copy_siginfo_to_user32(uinfo, &info); +} #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ diff -Nru a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile --- a/arch/ia64/kernel/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/kernel/Makefile 2004-10-18 14:57:04 -07:00 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ @@ -17,29 +17,31 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o obj-$(CONFIG_IA64_CYCLONE) += cyclone.o +obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o +mca_recovery-y += mca_drv.o mca_drv_asm.o # The gate DSO image is built using a special linker script. targets += gate.so gate-syms.o -extra-y += gate.so gate-syms.o gate.lds.s gate.o +extra-y += gate.so gate-syms.o gate.lds gate.o # fp_emulate() expects f2-f5,f16-f31 to contain the user-level state. CFLAGS_traps.o += -mfixed-range=f2-f5,f16-f31 -AFLAGS_gate.lds.o += -P -C -U$(ARCH) +CPPFLAGS_gate.lds := -P -C -U$(ARCH) quiet_cmd_gate = GATE $@ cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@ GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 -$(obj)/gate.so: $(obj)/gate.lds.s $(obj)/gate.o FORCE +$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE $(call if_changed,gate) $(obj)/built-in.o: $(obj)/gate-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o GATECFLAGS_gate-syms.o = -r -$(obj)/gate-syms.o: $(src)/gate.lds.s $(obj)/gate.o FORCE +$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE $(call if_changed,gate) # gate-data.o contains the gate DSO image as data in section .data.gate. diff -Nru a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c --- a/arch/ia64/kernel/acpi-ext.c 2004-10-18 14:57:05 -07:00 +++ b/arch/ia64/kernel/acpi-ext.c 2004-10-18 14:57:05 -07:00 @@ -62,7 +62,7 @@ struct acpi_vendor_info info; info.descriptor = id; - info.data = 0; + info.data = NULL; acpi_walk_resources(obj, METHOD_NAME__CRS, acpi_vendor_resource_match, &info); if (!info.data) diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c --- a/arch/ia64/kernel/acpi.c 2004-10-18 14:56:31 -07:00 +++ b/arch/ia64/kernel/acpi.c 2004-10-18 14:56:31 -07:00 @@ -61,10 +61,16 @@ void (*pm_idle) (void); EXPORT_SYMBOL(pm_idle); void (*pm_power_off) (void); +EXPORT_SYMBOL(pm_power_off); unsigned char acpi_kbd_controller_present = 1; unsigned char acpi_legacy_devices; +#define MAX_SAPICS 256 +u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = + { [0 ... MAX_SAPICS - 1] = -1 }; +EXPORT_SYMBOL(ia64_acpiid_to_sapicid); + const char * acpi_get_sysname (void) { @@ -172,8 +178,8 @@ return -EINVAL; if (lapic->address) { - iounmap((void *) ipi_base_addr); - ipi_base_addr = (unsigned long) ioremap(lapic->address, 0); + iounmap(ipi_base_addr); + ipi_base_addr = ioremap(lapic->address, 0); } return 0; } @@ -193,6 +199,7 @@ #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; #endif + ia64_acpiid_to_sapicid[lsapic->acpi_id] = (lsapic->id << 8) | lsapic->eid; ++available_cpus; } @@ -329,9 +336,9 @@ /* Get base address of IPI Message Block */ if (acpi_madt->lapic_address) - ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0); + ipi_base_addr = ioremap(acpi_madt->lapic_address, 0); - printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr); + printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr); acpi_madt_oem_check(acpi_madt->header.oem_id, acpi_madt->header.oem_table_id); @@ -430,8 +437,9 @@ { int i, j, node_from, node_to; - /* If there's no SRAT, fix the phys_id */ + /* If there's no SRAT, fix the phys_id and mark node 0 online */ if (srat_num_cpus == 0) { + node_set_online(0); node_cpuid[0].phys_id = hard_smp_processor_id(); return; } @@ -643,4 +651,71 @@ return 0; } +#ifdef CONFIG_NUMA +acpi_status __init +acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + struct acpi_table_iosapic *iosapic; + unsigned int gsi_base; + int node; + + /* Only care about objects w/ a method that returns the MADT */ + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + return AE_OK; + + if (!buffer.length || !buffer.pointer) + return AE_OK; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(*iosapic)) { + acpi_os_free(buffer.pointer); + return AE_OK; + } + + iosapic = (struct acpi_table_iosapic *)obj->buffer.pointer; + + if (iosapic->header.type != ACPI_MADT_IOSAPIC) { + acpi_os_free(buffer.pointer); + return AE_OK; + } + + gsi_base = iosapic->global_irq_base; + + acpi_os_free(buffer.pointer); + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + + /* + * OK, it's an IOSAPIC MADT entry, look for a _PXM method to tell + * us which node to associate this with. + */ + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer))) + return AE_OK; + + if (!buffer.length || !buffer.pointer) + return AE_OK; + + obj = buffer.pointer; + + if (obj->type != ACPI_TYPE_INTEGER || + obj->integer.value >= MAX_PXM_DOMAINS) { + acpi_os_free(buffer.pointer); + return AE_OK; + } + + node = pxm_to_nid_map[obj->integer.value]; + acpi_os_free(buffer.pointer); + + if (node >= MAX_NUMNODES || !node_online(node) || + cpus_empty(node_to_cpumask(node))) + return AE_OK; + + /* We know a gsi to node mapping! */ + map_iosapic_to_node(gsi_base, node); + return AE_OK; +} +#endif /* CONFIG_NUMA */ #endif /* CONFIG_ACPI_BOOT */ diff -Nru a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c --- a/arch/ia64/kernel/asm-offsets.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ia64/kernel/asm-offsets.c 2004-10-18 14:57:03 -07:00 @@ -34,6 +34,11 @@ BLANK(); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); + + BLANK(); + DEFINE(IA64_TASK_BLOCKED_OFFSET,offsetof (struct task_struct, blocked)); DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); @@ -188,18 +193,10 @@ DEFINE(IA64_CLONE_VM, CLONE_VM); BLANK(); - /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ - DEFINE(IA64_CPUINFO_ITM_DELTA_OFFSET, offsetof (struct cpuinfo_ia64, itm_delta)); - DEFINE(IA64_CPUINFO_ITM_NEXT_OFFSET, offsetof (struct cpuinfo_ia64, itm_next)); DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); - DEFINE(CLONE_IDLETASK_BIT, 12); -#if CLONE_IDLETASK != (1 << 12) -# error "CLONE_IDLETASK_BIT incorrect, please fix" -#endif - DEFINE(CLONE_SETTLS_BIT, 19); #if CLONE_SETTLS != (1<<19) # error "CLONE_SETTLS_BIT incorrect, please fix" @@ -207,5 +204,21 @@ BLANK(); DEFINE(IA64_MCA_TLB_INFO_SIZE, sizeof (struct ia64_mca_tlb_info)); + /* used by head.S */ + DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); + BLANK(); + /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ + DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr)); + DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source)); + DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift)); + DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc)); + DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset)); + DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle)); + DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter)); + DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter)); + DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU); + DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64); + DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32); + DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); } diff -Nru a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c --- a/arch/ia64/kernel/cyclone.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/kernel/cyclone.c 2004-10-18 14:56:29 -07:00 @@ -1,6 +1,8 @@ +#include #include #include #include +#include /* IBM Summit (EXA) Cyclone counter code*/ #define CYCLONE_CBAR_ADDR 0xFEB00CD0 @@ -15,62 +17,10 @@ use_cyclone = 1; } -static u32* volatile cyclone_timer; /* Cyclone MPMC0 register */ -static u32 last_update_cyclone; - -static unsigned long offset_base; - -static unsigned long get_offset_cyclone(void) -{ - u32 now; - unsigned long offset; - - /* Read the cyclone timer */ - now = readl(cyclone_timer); - /* .. relative to previous update*/ - offset = now - last_update_cyclone; - - /* convert cyclone ticks to nanoseconds */ - offset = (offset*NSEC_PER_SEC)/CYCLONE_TIMER_FREQ; - - /* our adjusted time in nanoseconds */ - return offset_base + offset; -} - -static void update_cyclone(long delta_nsec) -{ - u32 now; - unsigned long offset; - - /* Read the cyclone timer */ - now = readl(cyclone_timer); - /* .. relative to previous update*/ - offset = now - last_update_cyclone; - - /* convert cyclone ticks to nanoseconds */ - offset = (offset*NSEC_PER_SEC)/CYCLONE_TIMER_FREQ; - - offset += offset_base; - - /* Be careful about signed/unsigned comparisons here: */ - if (delta_nsec < 0 || (unsigned long) delta_nsec < offset) - offset_base = offset - delta_nsec; - else - offset_base = 0; - - last_update_cyclone = now; -} - -static void reset_cyclone(void) -{ - offset_base = 0; - last_update_cyclone = readl(cyclone_timer); -} struct time_interpolator cyclone_interpolator = { - .get_offset = get_offset_cyclone, - .update = update_cyclone, - .reset = reset_cyclone, + .source = TIME_SOURCE_MMIO32, + .shift = 32, .frequency = CYCLONE_TIMER_FREQ, .drift = -100, }; @@ -81,6 +31,7 @@ u64 base; /* saved cyclone base address */ u64 offset; /* offset from pageaddr to cyclone_timer register */ int i; + u32* volatile cyclone_timer; /* Cyclone MPMC0 register */ if (!use_cyclone) return -ENODEV; @@ -148,7 +99,7 @@ } } /* initialize last tick */ - last_update_cyclone = readl(cyclone_timer); + cyclone_interpolator.addr = cyclone_timer; register_time_interpolator(&cyclone_interpolator); return 0; diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c --- a/arch/ia64/kernel/efi.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ia64/kernel/efi.c 2004-10-18 14:55:54 -07:00 @@ -48,7 +48,7 @@ prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \ { \ struct ia64_fpreg fr[6]; \ - efi_time_cap_t *atc = 0; \ + efi_time_cap_t *atc = NULL; \ efi_status_t ret; \ \ if (tc) \ @@ -91,7 +91,7 @@ prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) \ { \ struct ia64_fpreg fr[6]; \ - efi_time_t *atm = 0; \ + efi_time_t *atm = NULL; \ efi_status_t ret; \ \ if (tm) \ @@ -109,7 +109,7 @@ unsigned long *data_size, void *data) \ { \ struct ia64_fpreg fr[6]; \ - u32 *aattr = 0; \ + u32 *aattr = NULL; \ efi_status_t ret; \ \ if (attr) \ @@ -172,7 +172,7 @@ unsigned long data_size, efi_char16_t *data) \ { \ struct ia64_fpreg fr[6]; \ - efi_char16_t *adata = 0; \ + efi_char16_t *adata = NULL; \ \ if (data) \ adata = adjust_arg(data); \ @@ -214,7 +214,7 @@ efi_time_t tm; memset(ts, 0, sizeof(ts)); - if ((*efi.get_time)(&tm, 0) != EFI_SUCCESS) + if ((*efi.get_time)(&tm, NULL) != EFI_SUCCESS) return; ts->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); @@ -357,8 +357,10 @@ if (total_mem >= mem_limit) continue; total_mem += (md->num_pages << EFI_PAGE_SHIFT); - if (total_mem > mem_limit) + if (total_mem > mem_limit) { md->num_pages -= ((total_mem - mem_limit) >> EFI_PAGE_SHIFT); + max_addr = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); + } if (md->num_pages == 0) continue; diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S 2004-10-18 14:56:27 -07:00 +++ b/arch/ia64/kernel/entry.S 2004-10-18 14:56:27 -07:00 @@ -128,7 +128,7 @@ (p6) st8 [r2]=in5 // store TLS in r16 for copy_thread() mov out5=in4 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s - dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK + mov out0=in0 // out0 = clone_flags br.call.sptk.many rp=do_fork .ret1: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack @@ -157,7 +157,7 @@ (p6) st8 [r2]=in4 // store TLS in r13 (tp) mov out5=in3 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s - dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK + mov out0=in0 // out0 = clone_flags br.call.sptk.many rp=do_fork .ret2: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack diff -Nru a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S --- a/arch/ia64/kernel/fsys.S 2004-10-18 14:57:19 -07:00 +++ b/arch/ia64/kernel/fsys.S 2004-10-18 14:57:19 -07:00 @@ -8,6 +8,8 @@ * 18-Feb-03 louisk Implement fsys_gettimeofday(). * 28-Feb-03 davidm Fixed several bugs in fsys_gettimeofday(). Tuned it some more, * probably broke it along the way... ;-) + * 13-Jul-04 clameter Implement fsys_clock_gettime and revise fsys_gettimeofday to make + * it capable of using memory based clocks without falling back to C code. */ #include @@ -144,195 +146,206 @@ END(fsys_set_tid_address) /* - * Note 1: This routine uses floating-point registers, but only with registers that - * operate on integers. Because of that, we don't need to set ar.fpsr to the - * kernel default value. - * - * Note 2: For now, we will assume that all CPUs run at the same clock-frequency. - * If that wasn't the case, we would have to disable preemption (e.g., - * by disabling interrupts) between reading the ITC and reading - * local_cpu_data->nsec_per_cyc. - * - * Note 3: On platforms where the ITC-drift bit is set in the SAL feature vector, - * we ought to either skip the ITC-based interpolation or run an ntp-like - * daemon to keep the ITCs from drifting too far apart. + * Ensure that the time interpolator structure is compatible with the asm code */ +#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \ + || IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4 +#error fsys_gettimeofday incompatible with changes to struct time_interpolator +#endif +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_DIVIDE_BY_1000 0x4000 +#define CLOCK_ADD_MONOTONIC 0x8000 ENTRY(fsys_gettimeofday) .prologue .altrp b6 .body - add r9=TI_FLAGS+IA64_TASK_SIZE,r16 - addl r3=THIS_CPU(cpu_info),r0 - -#ifdef CONFIG_SMP - movl r10=__per_cpu_offset - movl r2=sal_platform_features - ;; - - ld8 r2=[r2] - movl r19=xtime // xtime is a timespec struct - - ld8 r10=[r10] // r10 <- __per_cpu_offset[0] - addl r21=THIS_CPU(cpu_info),r0 - ;; - add r10=r21, r10 // r10 <- &cpu_data(time_keeper_id) - tbit.nz p8,p0 = r2, IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT -(p8) br.spnt.many fsys_fallback_syscall -#else - ;; - mov r10=r3 - movl r19=xtime // xtime is a timespec struct -#endif - ld4 r9=[r9] - movl r17=xtime_lock - ;; - - // r32, r33 should contain the 2 args of gettimeofday - adds r21=IA64_CPUINFO_ITM_NEXT_OFFSET, r10 - mov r2=-1 - tnat.nz p6,p7=r32 // guard against NaT args - ;; - - adds r10=IA64_CPUINFO_ITM_DELTA_OFFSET, r10 -(p7) tnat.nz p6,p0=r33 -(p6) br.cond.spnt.few .fail_einval - - adds r8=IA64_CPUINFO_NSEC_PER_CYC_OFFSET, r3 - movl r24=2361183241434822607 // for division hack (only for / 1000) - ;; - - ldf8 f7=[r10] // f7 now contains itm_delta - setf.sig f11=r2 - adds r10=8, r32 - - adds r20=IA64_TIMESPEC_TV_NSEC_OFFSET, r19 // r20 = &xtime->tv_nsec - movl r26=jiffies - - setf.sig f9=r24 // f9 is used for division hack - movl r27=wall_jiffies - - and r9=TIF_ALLWORK_MASK,r9 - movl r25=last_nsec_offset - ;; - - /* - * Verify that we have permission to write to struct timeval. Note: - * Another thread might unmap the mapping before we actually get - * to store the result. That's OK as long as the stores are also - * protect by EX(). - */ -EX(.fail_efault, probe.w.fault r32, 3) // this must come _after_ NaT-check -EX(.fail_efault, probe.w.fault r10, 3) // this must come _after_ NaT-check - nop 0 - - ldf8 f10=[r8] // f10 <- local_cpu_data->nsec_per_cyc value - cmp.ne p8, p0=0, r9 -(p8) br.spnt.many fsys_fallback_syscall - ;; -.retry: // *** seq = read_seqbegin(&xtime_lock); *** - ld4.acq r23=[r17] // since &xtime_lock == &xtime_lock->sequence - ld8 r14=[r25] // r14 (old) = last_nsec_offset - - ld8 r28=[r26] // r28 = jiffies - ld8 r29=[r27] // r29 = wall_jiffies - ;; - - ldf8 f8=[r21] // f8 now contains itm_next - mov.m r31=ar.itc // put time stamp into r31 (ITC) == now - sub r28=r29, r28, 1 // r28 now contains "-(lost + 1)" - ;; - - ld8 r2=[r19] // r2 = sec = xtime.tv_sec - ld8 r29=[r20] // r29 = nsec = xtime.tv_nsec - tbit.nz p9, p10=r23, 0 // p9 <- is_odd(r23), p10 <- is_even(r23) - - setf.sig f6=r28 // f6 <- -(lost + 1) (6 cyc) - ;; - + mov r31 = r32 + tnat.nz p6,p0 = r33 // guard against NaT argument +(p6) br.cond.spnt.few .fail_einval + mov r30 = CLOCK_DIVIDE_BY_1000 + ;; +.gettime: + // Register map + // Incoming r31 = pointer to address where to place result + // r30 = flags determining how time is processed + // r2,r3 = temp r4-r7 preserved + // r8 = result nanoseconds + // r9 = result seconds + // r10 = temporary storage for clock difference + // r11 = preserved: saved ar.pfs + // r12 = preserved: memory stack + // r13 = preserved: thread pointer + // r14 = debug pointer / usable + // r15 = preserved: system call number + // r16 = preserved: current task pointer + // r17 = wall to monotonic use + // r18 = time_interpolator->offset + // r19 = address of wall_to_monotonic + // r20 = pointer to struct time_interpolator / pointer to time_interpolator->address + // r21 = shift factor + // r22 = address of time interpolator->last_counter + // r23 = address of time_interpolator->last_cycle + // r24 = adress of time_interpolator->offset + // r25 = last_cycle value + // r26 = last_counter value + // r27 = pointer to xtime + // r28 = sequence number at the beginning of critcal section + // r29 = address of seqlock + // r30 = time processing flags / memory address + // r31 = pointer to result + // Predicates + // p6,p7 short term use + // p8 = timesource ar.itc + // p9 = timesource mmio64 + // p10 = timesource mmio32 + // p11 = timesource not to be handled by asm code + // p12 = memory time source ( = p9 | p10) + // p13 = do cmpxchg with time_interpolator_last_cycle + // p14 = Divide by 1000 + // p15 = Add monotonic + // + // Note that instructions are optimized for McKinley. McKinley can process two + // bundles simultaneously and therefore we continuously try to feed the CPU + // two bundles and then a stop. + tnat.nz p6,p0 = r31 // branch deferred since it does not fit into bundle structure + mov pr = r30,0xc000 // Set predicates according to function + add r2 = TI_FLAGS+IA64_TASK_SIZE,r16 + movl r20 = time_interpolator + ;; + ld8 r20 = [r20] // get pointer to time_interpolator structure + movl r29 = xtime_lock + ld4 r2 = [r2] // process work pending flags + movl r27 = xtime + ;; // only one bundle here + ld8 r21 = [r20] // first quad with control information + and r2 = TIF_ALLWORK_MASK,r2 +(p6) br.cond.spnt.few .fail_einval // deferred branch + ;; + add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20 + extr r3 = r21,32,32 // time_interpolator->nsec_per_cyc + extr r8 = r21,0,16 // time_interpolator->source + nop.i 123 + cmp.ne p6, p0 = 0, r2 // Fallback if work is scheduled +(p6) br.cond.spnt.many fsys_fallback_syscall + ;; + cmp.eq p8,p12 = 0,r8 // Check for cpu timer + cmp.eq p9,p0 = 1,r8 // MMIO64 ? + extr r2 = r21,24,8 // time_interpolator->jitter + cmp.eq p10,p0 = 2,r8 // MMIO32 ? + cmp.ltu p11,p0 = 2,r8 // function or other clock +(p11) br.cond.spnt.many fsys_fallback_syscall + ;; + setf.sig f7 = r3 // Setup for scaling of counter +(p15) movl r19 = wall_to_monotonic +(p12) ld8 r30 = [r10] + cmp.ne p13,p0 = r2,r0 // need jitter compensation? + extr r21 = r21,16,8 // shift factor + ;; +.time_redo: + .pred.rel.mutex p8,p9,p10 + ld4.acq r28 = [r29] // xtime_lock.sequence. Must come first for locking purposes +(p8) mov r2 = ar.itc // CPU_TIMER. 36 clocks latency!!! + add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20 +(p9) ld8 r2 = [r30] // readq(ti->address). Could also have latency issues.. +(p10) ld4 r2 = [r30] // readw(ti->address) +(p13) add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20 + ;; // could be removed by moving the last add upward + ld8 r26 = [r22] // time_interpolator->last_counter +(p13) ld8 r25 = [r23] // time interpolator->last_cycle + add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20 +(p15) ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET + ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET + nop.i 123 + ;; + ld8 r18 = [r24] // time_interpolator->offset + ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET // xtime.tv_nsec +(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm) + ;; +(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared + sub r10 = r2,r26 // current_counter - last_counter + ;; +(p6) sub r10 = r25,r26 // time we got was less than last_cycle +(p7) mov ar.ccv = r25 // more than last_cycle. Prep for cmpxchg + ;; + setf.sig f8 = r10 + nop.i 123 + ;; +(p7) cmpxchg8.rel r3 = [r23],r2,ar.ccv +EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare time + xmpy.l f8 = f8,f7 // nsec_per_cyc*(counter-last_counter) +(p15) add r9 = r9,r17 // Add wall to monotonic.secs to result secs + ;; +(p15) ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET +(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful redo + // simulate tbit.nz.or p7,p0 = r28,0 + and r28 = ~1,r28 // Make sequence even to force retry if odd + getf.sig r2 = f8 mf - xma.l f8=f6, f7, f8 // f8 (last_tick) <- -(lost + 1)*itm_delta + itm_next (5 cyc) - nop 0 - - setf.sig f12=r31 // f12 <- ITC (6 cyc) - // *** if (unlikely(read_seqretry(&xtime_lock, seq))) continue; *** - ld4 r24=[r17] // r24 = xtime_lock->sequence (re-read) - nop 0 - ;; - - xma.l f8=f11, f8, f12 // f8 (elapsed_cycles) <- (-1*last_tick + now) = (now - last_tick) - nop 0 - ;; - - getf.sig r18=f8 // r18 <- (now - last_tick) - xmpy.l f8=f8, f10 // f8 <- elapsed_cycles*nsec_per_cyc (5 cyc) - add r3=r29, r14 // r3 = (nsec + old) - ;; - - cmp.lt p7, p8=r18, r0 // if now < last_tick, set p7 = 1, p8 = 0 - getf.sig r18=f8 // r18 = elapsed_cycles*nsec_per_cyc (6 cyc) - nop 0 - ;; - -(p10) cmp.ne p9, p0=r23, r24 // if xtime_lock->sequence != seq, set p9 - shr.u r18=r18, IA64_NSEC_PER_CYC_SHIFT // r18 <- offset -(p9) br.spnt.many .retry - ;; - - mov ar.ccv=r14 // ar.ccv = old (1 cyc) - cmp.leu p7, p8=r18, r14 // if (offset <= old), set p7 = 1, p8 = 0 + add r8 = r8,r18 // Add time interpolator offset ;; - -(p8) cmpxchg8.rel r24=[r25], r18, ar.ccv // compare-and-exchange (atomic!) -(p8) add r3=r29, r18 // r3 = (nsec + offset) - ;; - shr.u r3=r3, 3 // initiate dividing r3 by 1000 - ;; - setf.sig f8=r3 // (6 cyc) - mov r10=1000000 // r10 = 1000000 + ld4 r10 = [r29] // xtime_lock.sequence +(p15) add r8 = r8, r17 // Add monotonic.nsecs to nsecs + shr.u r2 = r2,r21 + ;; // overloaded 3 bundles! + // End critical section. + add r8 = r8,r2 // Add xtime.nsecs + cmp4.ne.or p7,p0 = r28,r10 +(p7) br.cond.dpnt.few .time_redo // sequence number changed ? + // Now r8=tv->tv_nsec and r9=tv->tv_sec + mov r10 = r0 + movl r2 = 1000000000 + add r23 = IA64_TIMESPEC_TV_NSEC_OFFSET, r31 +(p14) movl r3 = 2361183241434822607 // Prep for / 1000 hack + ;; +.time_normalize: + mov r21 = r8 + cmp.ge p6,p0 = r8,r2 +(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting some time + ;; +(p14) setf.sig f8 = r20 +(p6) sub r8 = r8,r2 +(p6) add r9 = 1,r9 // two nops before the branch. +(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod +(p6) br.cond.dpnt.few .time_normalize + ;; + // Divided by 8 though shift. Now divide by 125 + // The compiler was able to do that with a multiply + // and a shift and we do the same +EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles +(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it... ;; -(p8) cmp.ne.unc p9, p0=r24, r14 - xmpy.hu f6=f8, f9 // (5 cyc) -(p9) br.spnt.many .retry - ;; - - getf.sig r3=f6 // (6 cyc) + mov r8 = r0 +(p14) getf.sig r2 = f8 ;; - shr.u r3=r3, 4 // end of division, r3 is divided by 1000 (=usec) - ;; - -1: cmp.geu p7, p0=r3, r10 // while (usec >= 1000000) - ;; -(p7) sub r3=r3, r10 // usec -= 1000000 -(p7) adds r2=1, r2 // ++sec -(p7) br.spnt.many 1b - - // finally: r2 = sec, r3 = usec -EX(.fail_efault, st8 [r32]=r2) - adds r9=8, r32 - mov r8=r0 // success +(p14) shr.u r21 = r2, 4 ;; -EX(.fail_efault, st8 [r9]=r3) // store them in the timeval struct - mov r10=0 +EX(.fail_efault, st8 [r31] = r9) +EX(.fail_efault, st8 [r23] = r21) FSYS_RETURN - /* - * Note: We are NOT clearing the scratch registers here. Since the only things - * in those registers are time-related variables and some addresses (which - * can be obtained from System.map), none of this should be security-sensitive - * and we should be fine. - */ - .fail_einval: - mov r8=EINVAL // r8 = EINVAL - mov r10=-1 // r10 = -1 + mov r8 = EINVAL + mov r10 = -1 FSYS_RETURN - .fail_efault: - mov r8=EFAULT // r8 = EFAULT - mov r10=-1 // r10 = -1 + mov r8 = EFAULT + mov r10 = -1 FSYS_RETURN END(fsys_gettimeofday) +ENTRY(fsys_clock_gettime) + .prologue + .altrp b6 + .body + cmp4.ltu p6, p0 = CLOCK_MONOTONIC, r32 + // Fallback if this is not CLOCK_REALTIME or CLOCK_MONOTONIC +(p6) br.spnt.few fsys_fallback_syscall + mov r31 = r33 + shl r30 = r32,15 + br.many .gettime +END(fsys_clock_gettime) + /* * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize). */ @@ -838,7 +851,7 @@ data8 0 // timer_getoverrun data8 0 // timer_delete data8 0 // clock_settime - data8 0 // clock_gettime + data8 fsys_clock_gettime // clock_gettime data8 0 // clock_getres // 1255 data8 0 // clock_nanosleep data8 0 // fstatfs64 diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S --- a/arch/ia64/kernel/head.S 2004-10-18 14:56:48 -07:00 +++ b/arch/ia64/kernel/head.S 2004-10-18 14:56:48 -07:00 @@ -781,8 +781,7 @@ // going to virtual // - for code addresses, set upper bits of addr to KERNEL_START - // - for stack addresses, set upper 3 bits to 0xe.... Dont change any of the - // lower bits since we want it to stay identity mapped + // - for stack addresses, copy from input argument movl r18=KERNEL_START dep r3=0,r3,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT dep r14=0,r14,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/kernel/iosapic.c 2004-10-18 14:56:29 -07:00 @@ -104,7 +104,7 @@ /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ static struct iosapic_intr_info { - char *addr; /* base address of IOSAPIC */ + char __iomem *addr; /* base address of IOSAPIC */ u32 low32; /* current value of low word of Redirection table entry */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ @@ -114,9 +114,12 @@ } iosapic_intr_info[IA64_NUM_VECTORS]; static struct iosapic { - char *addr; /* base address of IOSAPIC */ + char __iomem *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 */ +#ifdef CONFIG_NUMA + unsigned short node; /* numa node association via pxm */ +#endif } iosapic_lists[NR_IOSAPICS]; static int num_iosapic; @@ -176,7 +179,7 @@ { unsigned long pol, trigger, dmode, flags; u32 low32, high32; - char *addr; + char __iomem *addr; int rte_index; char redir; @@ -234,7 +237,7 @@ mask_irq (unsigned int irq) { unsigned long flags; - char *addr; + char __iomem *addr; u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); @@ -258,7 +261,7 @@ unmask_irq (unsigned int irq) { unsigned long flags; - char *addr; + char __iomem *addr; u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); @@ -284,7 +287,7 @@ unsigned long flags; u32 high32, low32; int dest, rte_index; - char *addr; + char __iomem *addr; int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; ia64_vector vec; @@ -409,7 +412,7 @@ }; unsigned int -iosapic_version (char *addr) +iosapic_version (char __iomem *addr) { /* * IOSAPIC Version Register return 32 bit structure like: @@ -454,7 +457,7 @@ int rte_index; int index; unsigned long gsi_base; - char *iosapic_address; + void __iomem *iosapic_address; index = find_iosapic(gsi); if (index < 0) { @@ -488,7 +491,7 @@ } static unsigned int -get_target_cpu (void) +get_target_cpu (unsigned int gsi, int vector) { #ifdef CONFIG_SMP static int cpu = -1; @@ -507,6 +510,34 @@ if (!cpu_online(smp_processor_id())) return hard_smp_processor_id(); +#ifdef CONFIG_NUMA + { + int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; + cpumask_t cpu_mask; + + iosapic_index = find_iosapic(gsi); + if (iosapic_index < 0 || + iosapic_lists[iosapic_index].node == MAX_NUMNODES) + goto skip_numa_setup; + + cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node); + + num_cpus = cpus_weight(cpu_mask); + + if (!num_cpus) + goto skip_numa_setup; + + /* Use vector assigment to distribute across cpus in node */ + cpu_index = vector % num_cpus; + + for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) + numa_cpu = next_cpu(numa_cpu, cpu_mask); + + if (numa_cpu != NR_CPUS) + return cpu_physical_id(numa_cpu); + } +skip_numa_setup: +#endif /* * Otherwise, round-robin interrupt vectors across all the * processors. (It'd be nice if we could be smarter in the @@ -550,7 +581,7 @@ } vector = assign_irq_vector(AUTO_ASSIGN); - dest = get_target_cpu(); + dest = get_target_cpu(gsi, vector); register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger); } @@ -665,7 +696,7 @@ { int num_rte; unsigned int isa_irq, ver; - char *addr; + char __iomem *addr; addr = ioremap(phys_addr, 0); ver = iosapic_version(addr); @@ -680,6 +711,9 @@ iosapic_lists[num_iosapic].addr = addr; iosapic_lists[num_iosapic].gsi_base = gsi_base; iosapic_lists[num_iosapic].num_rte = num_rte; +#ifdef CONFIG_NUMA + iosapic_lists[num_iosapic].node = MAX_NUMNODES; +#endif num_iosapic++; if ((gsi_base == 0) && pcat_compat) { @@ -692,3 +726,20 @@ iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); } } + +#ifdef CONFIG_NUMA +void __init +map_iosapic_to_node(unsigned int gsi_base, int node) +{ + int index; + + index = find_iosapic(gsi_base); + if (index < 0) { + printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", + __FUNCTION__, gsi_base); + return; + } + iosapic_lists[index].node = node; + return; +} +#endif diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ia64/kernel/irq.c 2004-10-18 14:56:50 -07:00 @@ -84,11 +84,13 @@ } }; +#ifdef CONFIG_SMP /* * This is updated when the user sets irq affinity via /proc */ cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)]; +#endif #ifdef CONFIG_IA64_GENERIC irq_desc_t * __ia64_irq_desc (unsigned int irq) @@ -255,14 +257,16 @@ struct pt_regs *regs, struct irqaction *action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -962,7 +966,7 @@ return len; } -static int irq_affinity_write_proc (struct file *file, const char *buffer, +static int irq_affinity_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned int irq = (unsigned long) data; @@ -1137,31 +1141,6 @@ } #endif -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -1196,26 +1175,15 @@ #endif } -cpumask_t prof_cpu_mask = CPU_MASK_ALL; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", 0); + root_irq_dir = proc_mkdir("irq", NULL); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c --- a/arch/ia64/kernel/irq_ia64.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ia64/kernel/irq_ia64.c 2004-10-18 14:56:28 -07:00 @@ -47,7 +47,8 @@ #define IRQ_DEBUG 0 /* default base addr of IPI table */ -unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR); +void __iomem *ipi_base_addr = ((void __iomem *) + (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR)); /* * Legacy IRQ to IA-64 vector translation table. @@ -254,7 +255,7 @@ void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) { - unsigned long ipi_addr; + void __iomem *ipi_addr; unsigned long ipi_data; unsigned long phys_cpu_id; @@ -269,7 +270,7 @@ */ ipi_data = (delivery_mode << 8) | (vector & 0xff); - ipi_addr = ipi_base_addr | (phys_cpu_id << 4) | ((redirect & 1) << 3); + ipi_addr = ipi_base_addr + ((phys_cpu_id << 4) | ((redirect & 1) << 3)); writeq(ipi_data, ipi_addr); } diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/kernel/mca.c 2004-10-18 14:56:29 -07:00 @@ -82,11 +82,6 @@ # define IA64_MCA_DEBUG(fmt...) #endif -typedef struct ia64_fptr { - unsigned long fp; - unsigned long gp; -} ia64_fptr_t; - /* Used by mca_asm.S */ ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; @@ -831,6 +826,31 @@ } +/* Function pointer for extra MCA recovery */ +int (*ia64_mca_ucmc_extension) + (void*,ia64_mca_sal_to_os_state_t*,ia64_mca_os_to_sal_state_t*) + = NULL; + +int +ia64_reg_MCA_extension(void *fn) +{ + if (ia64_mca_ucmc_extension) + return 1; + + ia64_mca_ucmc_extension = fn; + return 0; +} + +void +ia64_unreg_MCA_extension(void) +{ + if (ia64_mca_ucmc_extension) + ia64_mca_ucmc_extension = NULL; +} + +EXPORT_SYMBOL(ia64_reg_MCA_extension); +EXPORT_SYMBOL(ia64_unreg_MCA_extension); + /* * ia64_mca_ucmc_handler * @@ -852,10 +872,19 @@ { pal_processor_state_info_t *psp = (pal_processor_state_info_t *) &ia64_sal_to_os_handoff_state.proc_state_param; - int recover = psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc); + int recover; /* Get the MCA error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); + + /* TLB error is only exist in this SAL error record */ + recover = (psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc)) + /* other error recovery */ + || (ia64_mca_ucmc_extension + && ia64_mca_ucmc_extension( + IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA), + &ia64_sal_to_os_handoff_state, + &ia64_os_to_sal_handoff_state)); /* * Wakeup all the processors which are spinning in the rendezvous diff -Nru a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/kernel/mca_drv.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,639 @@ +/* + * File: mca_drv.c + * Purpose: Generic MCA handling layer + * + * Copyright (C) 2004 FUJITSU LIMITED + * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mca_drv.h" + +/* max size of SAL error record (default) */ +static int sal_rec_max = 10000; + +/* from mca.c */ +static ia64_mca_sal_to_os_state_t *sal_to_os_handoff_state; +static ia64_mca_os_to_sal_state_t *os_to_sal_handoff_state; + +/* from mca_drv_asm.S */ +extern void *mca_handler_bhhook(void); + +static spinlock_t mca_bh_lock = SPIN_LOCK_UNLOCKED; + +typedef enum { + MCA_IS_LOCAL = 0, + MCA_IS_GLOBAL = 1 +} mca_type_t; + +#define MAX_PAGE_ISOLATE 32 + +static struct page *page_isolate[MAX_PAGE_ISOLATE]; +static int num_page_isolate = 0; + +typedef enum { + ISOLATE_NG = 0, + ISOLATE_OK = 1 +} isolate_status_t; + +/* + * This pool keeps pointers to the section part of SAL error record + */ +static struct { + slidx_list_t *buffer; /* section pointer list pool */ + int cur_idx; /* Current index of section pointer list pool */ + int max_idx; /* Maximum index of section pointer list pool */ +} slidx_pool; + +/** + * mca_page_isolate - isolate a poisoned page in order not to use it later + * @paddr: poisoned memory location + * + * Return value: + * ISOLATE_OK / ISOLATE_NG + */ + +static isolate_status_t +mca_page_isolate(unsigned long paddr) +{ + int i; + struct page *p; + + /* whether physical address is valid or not */ + if ( !ia64_phys_addr_valid(paddr) ) + return ISOLATE_NG; + + /* convert physical address to physical page number */ + p = pfn_to_page(paddr>>PAGE_SHIFT); + + /* check whether a page number have been already registered or not */ + for( i = 0; i < num_page_isolate; i++ ) + if( page_isolate[i] == p ) + return ISOLATE_OK; /* already listed */ + + /* limitation check */ + if( num_page_isolate == MAX_PAGE_ISOLATE ) + return ISOLATE_NG; + + /* kick pages having attribute 'SLAB' or 'Reserved' */ + if( PageSlab(p) || PageReserved(p) ) + return ISOLATE_NG; + + /* add attribute 'Reserved' and register the page */ + SetPageReserved(p); + page_isolate[num_page_isolate++] = p; + + return ISOLATE_OK; +} + +/** + * mca_hanlder_bh - Kill the process which occurred memory read error + * @paddr: poisoned address received from MCA Handler + */ + +void +mca_handler_bh(unsigned long paddr) +{ + printk(KERN_DEBUG "OS_MCA: process [pid: %d](%s) encounters MCA.\n", + current->pid, current->comm); + + spin_lock(&mca_bh_lock); + if (mca_page_isolate(paddr) == ISOLATE_OK) { + printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr); + } else { + printk(KERN_DEBUG "Page isolation: ( %lx ) failure.\n", paddr); + } + spin_unlock(&mca_bh_lock); + + /* This process is about to be killed itself */ + force_sig(SIGKILL, current); + schedule(); +} + +/** + * mca_make_peidx - Make index of processor error section + * @slpi: pointer to record of processor error section + * @peidx: pointer to index of processor error section + */ + +static void +mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx) +{ + /* + * calculate the start address of + * "struct cpuid_info" and "sal_processor_static_info_t". + */ + u64 total_check_num = slpi->valid.num_cache_check + + slpi->valid.num_tlb_check + + slpi->valid.num_bus_check + + slpi->valid.num_reg_file_check + + slpi->valid.num_ms_check; + u64 head_size = sizeof(sal_log_mod_error_info_t) * total_check_num + + sizeof(sal_log_processor_info_t); + u64 mid_size = slpi->valid.cpuid_info * sizeof(struct sal_cpuid_info); + + peidx_head(peidx) = slpi; + peidx_mid(peidx) = (struct sal_cpuid_info *) + (slpi->valid.cpuid_info ? ((char*)slpi + head_size) : NULL); + peidx_bottom(peidx) = (sal_processor_static_info_t *) + (slpi->valid.psi_static_struct ? + ((char*)slpi + head_size + mid_size) : NULL); +} + +/** + * mca_make_slidx - Make index of SAL error record + * @buffer: pointer to SAL error record + * @slidx: pointer to index of SAL error record + * + * Return value: + * 1 if record has platform error / 0 if not + */ +#define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \ + { slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \ + hl->hdr = ptr; \ + list_add(&hl->list, &(sect)); \ + slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; } + +static int +mca_make_slidx(void *buffer, slidx_table_t *slidx) +{ + int platform_err = 0; + int record_len = ((sal_log_record_header_t*)buffer)->len; + u32 ercd_pos; + int sects; + sal_log_section_hdr_t *sp; + + /* + * Initialize index referring current record + */ + INIT_LIST_HEAD(&(slidx->proc_err)); + INIT_LIST_HEAD(&(slidx->mem_dev_err)); + INIT_LIST_HEAD(&(slidx->sel_dev_err)); + INIT_LIST_HEAD(&(slidx->pci_bus_err)); + INIT_LIST_HEAD(&(slidx->smbios_dev_err)); + INIT_LIST_HEAD(&(slidx->pci_comp_err)); + INIT_LIST_HEAD(&(slidx->plat_specific_err)); + INIT_LIST_HEAD(&(slidx->host_ctlr_err)); + INIT_LIST_HEAD(&(slidx->plat_bus_err)); + INIT_LIST_HEAD(&(slidx->unsupported)); + + /* + * Extract a Record Header + */ + slidx->header = buffer; + + /* + * Extract each section records + * (arranged from "int ia64_log_platform_info_print()") + */ + for (ercd_pos = sizeof(sal_log_record_header_t), sects = 0; + ercd_pos < record_len; ercd_pos += sp->len, sects++) { + sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos); + if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) { + LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_BUS_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp); + } else { + LOG_INDEX_ADD_SECT_PTR(slidx->unsupported, sp); + } + } + slidx->n_sections = sects; + + return platform_err; +} + +/** + * init_record_index_pools - Initialize pool of lists for SAL record index + * + * Return value: + * 0 on Success / -ENOMEM on Failure + */ +static int +init_record_index_pools(void) +{ + int i; + int rec_max_size; /* Maximum size of SAL error records */ + int sect_min_size; /* Minimum size of SAL error sections */ + /* minimum size table of each section */ + static int sal_log_sect_min_sizes[] = { + sizeof(sal_log_processor_info_t) + sizeof(sal_processor_static_info_t), + sizeof(sal_log_mem_dev_err_info_t), + sizeof(sal_log_sel_dev_err_info_t), + sizeof(sal_log_pci_bus_err_info_t), + sizeof(sal_log_smbios_dev_err_info_t), + sizeof(sal_log_pci_comp_err_info_t), + sizeof(sal_log_plat_specific_err_info_t), + sizeof(sal_log_host_ctlr_err_info_t), + sizeof(sal_log_plat_bus_err_info_t), + }; + + /* + * MCA handler cannot allocate new memory on flight, + * so we preallocate enough memory to handle a SAL record. + * + * Initialize a handling set of slidx_pool: + * 1. Pick up the max size of SAL error records + * 2. Pick up the min size of SAL error sections + * 3. Allocate the pool as enough to 2 SAL records + * (now we can estimate the maxinum of section in a record.) + */ + + /* - 1 - */ + rec_max_size = sal_rec_max; + + /* - 2 - */ + sect_min_size = sal_log_sect_min_sizes[0]; + for (i = 1; i < sizeof sal_log_sect_min_sizes/sizeof(size_t); i++) + if (sect_min_size > sal_log_sect_min_sizes[i]) + sect_min_size = sal_log_sect_min_sizes[i]; + + /* - 3 - */ + slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1; + slidx_pool.buffer = (slidx_list_t *) kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL); + + return slidx_pool.buffer ? 0 : -ENOMEM; +} + + +/***************************************************************************** + * Recovery functions * + *****************************************************************************/ + +/** + * is_mca_global - Check whether this MCA is global or not + * @peidx: pointer of index of processor error section + * @pbci: pointer to pal_bus_check_info_t + * + * Return value: + * MCA_IS_LOCAL / MCA_IS_GLOBAL + */ + +static mca_type_t +is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + + /* + * PAL can request a rendezvous, if the MCA has a global scope. + * If "rz_always" flag is set, SAL requests MCA rendezvous + * in spite of global MCA. + * Therefore it is local MCA when rendezvous has not been requested. + * Failed to rendezvous, the system must be down. + */ + switch (sal_to_os_handoff_state->imsto_rendez_state) { + case -1: /* SAL rendezvous unsuccessful */ + return MCA_IS_GLOBAL; + case 0: /* SAL rendezvous not required */ + return MCA_IS_LOCAL; + case 1: /* SAL rendezvous successful int */ + case 2: /* SAL rendezvous successful int with init */ + default: + break; + } + + /* + * If One or more Cache/TLB/Reg_File/Uarch_Check is here, + * it would be a local MCA. (i.e. processor internal error) + */ + if (psp->tc || psp->cc || psp->rc || psp->uc) + return MCA_IS_LOCAL; + + /* + * Bus_Check structure with Bus_Check.ib (internal bus error) flag set + * would be a global MCA. (e.g. a system bus address parity error) + */ + if (!pbci || pbci->ib) + return MCA_IS_GLOBAL; + + /* + * Bus_Check structure with Bus_Check.eb (external bus error) flag set + * could be either a local MCA or a global MCA. + * + * Referring Bus_Check.bsi: + * 0: Unknown/unclassified + * 1: BERR# + * 2: BINIT# + * 3: Hard Fail + * (FIXME: Are these SGI specific or generic bsi values?) + */ + if (pbci->eb) + switch (pbci->bsi) { + case 0: + /* e.g. a load from poisoned memory */ + return MCA_IS_LOCAL; + case 1: + case 2: + case 3: + return MCA_IS_GLOBAL; + } + + return MCA_IS_GLOBAL; +} + +/** + * recover_from_read_error - Try to recover the errors which type are "read"s. + * @slidx: pointer of index of SAL error record + * @peidx: pointer of index of processor error section + * @pbci: pointer of pal_bus_check_info + * + * Return value: + * 1 on Success / 0 on Failure + */ + +static int +recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + sal_log_mod_error_info_t *smei; + pal_min_state_area_t *pmsa; + struct ia64_psr *psr1, *psr2; + ia64_fptr_t *mca_hdlr_bh = (ia64_fptr_t*)mca_handler_bhhook; + + /* Is target address valid? */ + if (!pbci->tv) + return 0; + + /* + * cpu read or memory-mapped io read + * + * offending process affected process OS MCA do + * kernel mode kernel mode down system + * kernel mode user mode kill the process + * user mode kernel mode down system (*) + * user mode user mode kill the process + * + * (*) You could terminate offending user-mode process + * if (pbci->pv && pbci->pl != 0) *and* if you sure + * the process not have any locks of kernel. + */ + + psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr); + + /* + * Check the privilege level of interrupted context. + * If it is user-mode, then terminate affected process. + */ + if (psr1->cpl != 0) { + smei = peidx_bus_check(peidx, 0); + if (smei->valid.target_identifier) { + /* + * setup for resume to bottom half of MCA, + * "mca_handler_bhhook" + */ + pmsa = (pal_min_state_area_t *)(sal_to_os_handoff_state->pal_min_state | (6ul<<61)); + /* pass to bhhook as 1st argument (gr8) */ + pmsa->pmsa_gr[8-1] = smei->target_identifier; + /* set interrupted return address (but no use) */ + pmsa->pmsa_br0 = pmsa->pmsa_iip; + /* change resume address to bottom half */ + pmsa->pmsa_iip = mca_hdlr_bh->fp; + pmsa->pmsa_gr[1-1] = mca_hdlr_bh->gp; + /* set cpl with kernel mode */ + psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr; + psr2->cpl = 0; + psr2->ri = 0; + + return 1; + } + + } + + return 0; +} + +/** + * recover_from_platform_error - Recover from platform error. + * @slidx: pointer of index of SAL error record + * @peidx: pointer of index of processor error section + * @pbci: pointer of pal_bus_check_info + * + * Return value: + * 1 on Success / 0 on Failure + */ + +static int +recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + int status = 0; + pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + + if (psp->bc && pbci->eb && pbci->bsi == 0) { + switch(pbci->type) { + case 1: /* partial read */ + case 3: /* full line(cpu) read */ + case 9: /* I/O space read */ + status = recover_from_read_error(slidx, peidx, pbci); + break; + case 0: /* unknown */ + case 2: /* partial write */ + case 4: /* full line write */ + case 5: /* implicit or explicit write-back operation */ + case 6: /* snoop probe */ + case 7: /* incoming or outgoing ptc.g */ + case 8: /* write coalescing transactions */ + case 10: /* I/O space write */ + case 11: /* inter-processor interrupt message(IPI) */ + case 12: /* interrupt acknowledge or external task priority cycle */ + default: + break; + } + } + + return status; +} + +/** + * recover_from_processor_error + * @platform: whether there are some platform error section or not + * @slidx: pointer of index of SAL error record + * @peidx: pointer of index of processor error section + * @pbci: pointer of pal_bus_check_info + * + * Return value: + * 1 on Success / 0 on Failure + */ +/* + * Later we try to recover when below all conditions are satisfied. + * 1. Only one processor error section is exist. + * 2. BUS_CHECK is exist and the others are not exist.(Except TLB_CHECK) + * 3. The entry of BUS_CHECK_INFO is 1. + * 4. "External bus error" flag is set and the others are not set. + */ + +static int +recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + + /* + * We cannot recover errors with other than bus_check. + */ + if (psp->cc || psp->rc || psp->uc) + return 0; + + /* + * If there is no bus error, record is weird but we need not to recover. + */ + if (psp->bc == 0 || pbci == NULL) + return 1; + + /* + * Sorry, we cannot handle so many. + */ + if (peidx_bus_check_num(peidx) > 1) + return 0; + /* + * Well, here is only one bus error. + */ + if (pbci->ib || pbci->cc) + return 0; + if (pbci->eb && pbci->bsi > 0) + return 0; + if (psp->ci == 0) + return 0; + + /* + * This is a local MCA and estimated as recoverble external bus error. + * (e.g. a load from poisoned memory) + * This means "there are some platform errors". + */ + if (platform) + return recover_from_platform_error(slidx, peidx, pbci); + /* + * On account of strange SAL error record, we cannot recover. + */ + return 0; +} + +/** + * mca_try_to_recover - Try to recover from MCA + * @rec: pointer to a SAL error record + * + * Return value: + * 1 on Success / 0 on Failure + */ + +static int +mca_try_to_recover(void *rec, + ia64_mca_sal_to_os_state_t *sal_to_os_state, + ia64_mca_os_to_sal_state_t *os_to_sal_state) +{ + int platform_err; + int n_proc_err; + slidx_table_t slidx; + peidx_table_t peidx; + pal_bus_check_info_t pbci; + + /* handoff state from/to mca.c */ + sal_to_os_handoff_state = sal_to_os_state; + os_to_sal_handoff_state = os_to_sal_state; + + /* Make index of SAL error record */ + platform_err = mca_make_slidx(rec, &slidx); + + /* Count processor error sections */ + n_proc_err = slidx_count(&slidx, proc_err); + + /* Now, OS can recover when there is one processor error section */ + if (n_proc_err > 1) + return 0; + else if (n_proc_err == 0) { + /* Weird SAL record ... We need not to recover */ + + return 1; + } + + /* Make index of processor error section */ + mca_make_peidx((sal_log_processor_info_t*)slidx_first_entry(&slidx.proc_err)->hdr, &peidx); + + /* Extract Processor BUS_CHECK[0] */ + *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0); + + /* Check whether MCA is global or not */ + if (is_mca_global(&peidx, &pbci)) + return 0; + + /* Try to recover a processor error */ + return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci); +} + +/* + * ============================================================================= + */ + +int __init mca_external_handler_init(void) +{ + if (init_record_index_pools()) + return -ENOMEM; + + /* register external mca handlers */ + if (ia64_reg_MCA_extension(mca_try_to_recover)){ + printk(KERN_ERR "ia64_reg_MCA_extension failed.\n"); + kfree(slidx_pool.buffer); + return -EFAULT; + } + return 0; +} + +void __exit mca_external_handler_exit(void) +{ + /* unregister external mca handlers */ + ia64_unreg_MCA_extension(); + kfree(slidx_pool.buffer); +} + +module_init(mca_external_handler_init); +module_exit(mca_external_handler_exit); + +module_param(sal_rec_max, int, 0644); +MODULE_PARM_DESC(sal_rec_max, "Max size of SAL error record"); + +MODULE_DESCRIPTION("ia64 platform dependent mca handler driver"); +MODULE_LICENSE("GPL"); diff -Nru a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/kernel/mca_drv.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,113 @@ +/* + * File: mca_drv.h + * Purpose: Define helpers for Generic MCA handling + * + * Copyright (C) 2004 FUJITSU LIMITED + * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) + */ +/* + * Processor error section: + * + * +-sal_log_processor_info_t *info-------------+ + * | sal_log_section_hdr_t header; | + * | ... | + * | sal_log_mod_error_info_t info[0]; | + * +-+----------------+-------------------------+ + * | CACHE_CHECK | ^ num_cache_check v + * +----------------+ + * | TLB_CHECK | ^ num_tlb_check v + * +----------------+ + * | BUS_CHECK | ^ num_bus_check v + * +----------------+ + * | REG_FILE_CHECK | ^ num_reg_file_check v + * +----------------+ + * | MS_CHECK | ^ num_ms_check v + * +-struct cpuid_info *id----------------------+ + * | regs[5]; | + * | reserved; | + * +-sal_processor_static_info_t *regs----------+ + * | valid; | + * | ... | + * | fr[128]; | + * +--------------------------------------------+ + */ + +/* peidx: index of processor error section */ +typedef struct peidx_table { + sal_log_processor_info_t *info; + struct sal_cpuid_info *id; + sal_processor_static_info_t *regs; +} peidx_table_t; + +#define peidx_head(p) (((p)->info)) +#define peidx_mid(p) (((p)->id)) +#define peidx_bottom(p) (((p)->regs)) + +#define peidx_psp(p) (&(peidx_head(p)->proc_state_parameter)) +#define peidx_field_valid(p) (&(peidx_head(p)->valid)) +#define peidx_minstate_area(p) (&(peidx_bottom(p)->min_state_area)) + +#define peidx_cache_check_num(p) (peidx_head(p)->valid.num_cache_check) +#define peidx_tlb_check_num(p) (peidx_head(p)->valid.num_tlb_check) +#define peidx_bus_check_num(p) (peidx_head(p)->valid.num_bus_check) +#define peidx_reg_file_check_num(p) (peidx_head(p)->valid.num_reg_file_check) +#define peidx_ms_check_num(p) (peidx_head(p)->valid.num_ms_check) + +#define peidx_cache_check_idx(p, n) (n) +#define peidx_tlb_check_idx(p, n) (peidx_cache_check_idx(p, peidx_cache_check_num(p)) + n) +#define peidx_bus_check_idx(p, n) (peidx_tlb_check_idx(p, peidx_tlb_check_num(p)) + n) +#define peidx_reg_file_check_idx(p, n) (peidx_bus_check_idx(p, peidx_bus_check_num(p)) + n) +#define peidx_ms_check_idx(p, n) (peidx_reg_file_check_idx(p, peidx_reg_file_check_num(p)) + n) + +#define peidx_mod_error_info(p, name, n) \ +({ int __idx = peidx_##name##_idx(p, n); \ + sal_log_mod_error_info_t *__ret = NULL; \ + if (peidx_##name##_num(p) > n) /*BUG*/ \ + __ret = &(peidx_head(p)->info[__idx]); \ + __ret; }) + +#define peidx_cache_check(p, n) peidx_mod_error_info(p, cache_check, n) +#define peidx_tlb_check(p, n) peidx_mod_error_info(p, tlb_check, n) +#define peidx_bus_check(p, n) peidx_mod_error_info(p, bus_check, n) +#define peidx_reg_file_check(p, n) peidx_mod_error_info(p, reg_file_check, n) +#define peidx_ms_check(p, n) peidx_mod_error_info(p, ms_check, n) + +#define peidx_check_info(proc, name, n) \ +({ \ + sal_log_mod_error_info_t *__info = peidx_mod_error_info(proc, name, n);\ + u64 __temp = __info && __info->valid.check_info \ + ? __info->check_info : 0; \ + __temp; }) + +/* slidx: index of SAL log error record */ + +typedef struct slidx_list { + struct list_head list; + sal_log_section_hdr_t *hdr; +} slidx_list_t; + +typedef struct slidx_table { + sal_log_record_header_t *header; + int n_sections; /* # of section headers */ + struct list_head proc_err; + struct list_head mem_dev_err; + struct list_head sel_dev_err; + struct list_head pci_bus_err; + struct list_head smbios_dev_err; + struct list_head pci_comp_err; + struct list_head plat_specific_err; + struct list_head host_ctlr_err; + struct list_head plat_bus_err; + struct list_head unsupported; /* list of unsupported sections */ +} slidx_table_t; + +#define slidx_foreach_entry(pos, head) \ + list_for_each_entry(pos, head, list) +#define slidx_first_entry(head) \ + (((head)->next != (head)) ? list_entry((head)->next, typeof(slidx_list_t), list) : NULL) +#define slidx_count(slidx, sec) \ +({ int __count = 0; \ + slidx_list_t *__pos; \ + slidx_foreach_entry(__pos, &((slidx)->sec)) { __count++; }\ + __count; }) + diff -Nru a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/kernel/mca_drv_asm.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,45 @@ +/* + * File: mca_drv_asm.S + * Purpose: Assembly portion of Generic MCA handling + * + * Copyright (C) 2004 FUJITSU LIMITED + * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) + */ +#include +#include + +#include +#include + +GLOBAL_ENTRY(mca_handler_bhhook) + invala // clear RSE ? + ;; // + cover // + ;; // + clrrrb // + ;; + alloc r16=ar.pfs,0,2,1,0 // make a new frame + ;; + mov r13=IA64_KR(CURRENT) // current task pointer + ;; + adds r12=IA64_TASK_THREAD_KSP_OFFSET,r13 + ;; + ld8 r12=[r12] // stack pointer + ;; + mov loc0=r16 + movl loc1=mca_handler_bh // recovery C function + ;; + mov out0=r8 // poisoned address + mov b6=loc1 + ;; + mov loc1=rp + ;; + br.call.sptk.many rp=b6 // not return ... + ;; + mov ar.pfs=loc0 + mov rp=loc1 + ;; + mov r8=r0 + br.ret.sptk.many rp + ;; +END(mca_handler_bhhook) diff -Nru a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h --- a/arch/ia64/kernel/minstate.h 2004-10-18 14:56:50 -07:00 +++ b/arch/ia64/kernel/minstate.h 2004-10-18 14:56:50 -07:00 @@ -54,8 +54,7 @@ (pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ #define MINSTATE_END_SAVE_MIN_PHYS \ - or r12=r12,r14; /* make sp a kernel virtual address */ \ - or r13=r13,r14; /* make `current' a kernel virtual address */ \ + dep r12=-1,r12,61,3; /* make sp a kernel virtual address */ \ ;; #ifdef MINSTATE_VIRT @@ -65,7 +64,7 @@ #endif #ifdef MINSTATE_PHYS -# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; dep reg=0,reg,61,3 +# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; tpa reg=reg # define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_PHYS # define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_PHYS #endif @@ -172,7 +171,6 @@ ;; \ .mem.offset 0,0; st8.spill [r16]=r15,16; \ .mem.offset 8,0; st8.spill [r17]=r14,16; \ - dep r14=-1,r0,61,3; \ ;; \ .mem.offset 0,0; st8.spill [r16]=r2,16; \ .mem.offset 8,0; st8.spill [r17]=r3,16; \ diff -Nru a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c --- a/arch/ia64/kernel/module.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/kernel/module.c 2004-10-18 14:56:29 -07:00 @@ -195,10 +195,10 @@ printk(KERN_ERR "%s: value %li out of IMM22 range\n", mod->name, (int64_t)val); return 0; } - ia64_patch((u64) insn, 0x01fffcfe000, ( ((val & 0x200000) << 15) /* bit 21 -> 36 */ - | ((val & 0x1f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x00ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x00007f) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x01fffcfe000UL, ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); return 1; } @@ -209,8 +209,8 @@ printk(KERN_ERR "%s: value %li out of IMM21b range\n", mod->name, (int64_t)val); return 0; } - ia64_patch((u64) insn, 0x11ffffe000, ( ((val & 0x100000) << 16) /* bit 20 -> 36 */ - | ((val & 0x0fffff) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x11ffffe000UL, ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ + | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); return 1; } @@ -253,9 +253,9 @@ long off; b0 = b[0]; b1 = b[1]; - off = ( ((b1 & 0x00fffff000000000) >> 36) /* imm20b -> bit 0 */ - | ((b0 >> 48) << 20) | ((b1 & 0x7fffff) << 36) /* imm39 -> bit 20 */ - | ((b1 & 0x0800000000000000) << 0)); /* i -> bit 59 */ + off = ( ((b1 & 0x00fffff000000000UL) >> 36) /* imm20b -> bit 0 */ + | ((b0 >> 48) << 20) | ((b1 & 0x7fffffUL) << 36) /* imm39 -> bit 20 */ + | ((b1 & 0x0800000000000000UL) << 0)); /* i -> bit 59 */ return (long) plt->bundle[1] + 16*off; } @@ -739,7 +739,7 @@ if (gp_addressable(mod, val)) { /* turn "ld8" into "mov": */ DEBUGP("%s: patching ld8 at %p to mov\n", __FUNCTION__, location); - ia64_patch((u64) location, 0x1fff80fe000, 0x10000000000); + ia64_patch((u64) location, 0x1fff80fe000UL, 0x10000000000UL); } return 0; diff -Nru a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c --- a/arch/ia64/kernel/palinfo.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ia64/kernel/palinfo.c 2004-10-18 14:55:54 -07:00 @@ -446,7 +446,7 @@ "RSE stacked physical registers : %ld\n" "RSE load/store hints : %ld (%s)\n", phys_stacked, hints.ph_data, - hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); + hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)"); if (ia64_pal_debug_info(&iregs, &dregs)) return 0; @@ -479,7 +479,7 @@ "Enable CMCI promotion", "Enable MCA to BINIT promotion", "Enable MCA promotion", - "Enable BEER promotion" + "Enable BERR promotion" }; diff -Nru a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c --- a/arch/ia64/kernel/patch.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ia64/kernel/patch.c 2004-10-18 14:56:48 -07:00 @@ -65,21 +65,21 @@ ia64_patch_imm64 (u64 insn_addr, u64 val) { ia64_patch(insn_addr, - 0x01fffefe000, ( ((val & 0x8000000000000000) >> 27) /* bit 63 -> 36 */ - | ((val & 0x0000000000200000) << 0) /* bit 21 -> 21 */ - | ((val & 0x00000000001f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x000000000000ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x000000000000007f) << 13) /* bit 0 -> 13 */)); - ia64_patch(insn_addr - 1, 0x1ffffffffff, val >> 22); + 0x01fffefe000UL, ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ + | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ + | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1ffffffffffUL, val >> 22); } void ia64_patch_imm60 (u64 insn_addr, u64 val) { ia64_patch(insn_addr, - 0x011ffffe000, ( ((val & 0x0800000000000000) >> 23) /* bit 59 -> 36 */ - | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */)); - ia64_patch(insn_addr - 1, 0x1fffffffffc, val >> 18); + 0x011ffffe000UL, ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ + | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); } /* @@ -130,10 +130,10 @@ while (offp < (s32 *) end) { wp = (u64 *) ia64_imva((char *) offp + *offp); - wp[0] = 0x0000000100000000; /* nop.m 0; nop.i 0; nop.i 0 */ - wp[1] = 0x0004000000000200; - wp[2] = 0x0000000100000011; /* nop.m 0; nop.i 0; br.ret.sptk.many b6 */ - wp[3] = 0x0084006880000200; + wp[0] = 0x0000000100000000UL; /* nop.m 0; nop.i 0; nop.i 0 */ + wp[1] = 0x0004000000000200UL; + wp[2] = 0x0000000100000011UL; /* nop.m 0; nop.i 0; br.ret.sptk.many b6 */ + wp[3] = 0x0084006880000200UL; ia64_fc(wp); ia64_fc(wp + 2); ++offp; } diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c --- a/arch/ia64/kernel/perfmon.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/kernel/perfmon.c 2004-10-18 14:57:04 -07:00 @@ -1513,7 +1513,7 @@ } static ssize_t -pfm_read(struct file *filp, char *buf, size_t size, loff_t *ppos) +pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { pfm_context_t *ctx; pfm_msg_t *msg; @@ -1606,7 +1606,7 @@ } static ssize_t -pfm_write(struct file *file, const char *ubuf, +pfm_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos) { DPRINT(("pfm_write called\n")); @@ -1678,7 +1678,6 @@ pfm_fasync(int fd, struct file *filp, int on) { pfm_context_t *ctx; - unsigned long flags; int ret; if (PFM_IS_FILE(filp) == 0) { @@ -1691,19 +1690,21 @@ printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", current->pid); return -EBADF; } - - - PROTECT_CTX(ctx, flags); - + /* + * we cannot mask interrupts during this call because this may + * may go to sleep if memory is not readily avalaible. + * + * We are protected from the conetxt disappearing by the get_fd()/put_fd() + * done in caller. Serialization of this function is ensured by caller. + */ ret = pfm_do_fasync(fd, filp, ctx, on); + DPRINT(("pfm_fasync called on ctx_fd=%d on=%d async_queue=%p ret=%d\n", fd, on, ctx->ctx_async_queue, ret)); - UNPROTECT_CTX(ctx, flags); - return ret; } @@ -2227,6 +2228,15 @@ static void pfm_free_fd(int fd, struct file *file) { + struct files_struct *files = current->files; + + /* + * there ie no fd_uninstall(), so we do it here + */ + spin_lock(&files->file_lock); + files->fd[fd] = NULL; + spin_unlock(&files->file_lock); + if (file) put_filp(file); put_unused_fd(fd); } @@ -2277,7 +2287,7 @@ * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur) * return -ENOMEM; */ - if (size > task->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; + if (size > task->rlim[RLIMIT_MEMLOCK].rlim_cur) return -ENOMEM; /* * We do the easy to undo allocations first. @@ -2352,7 +2362,7 @@ insert_vm_struct(mm, vma); mm->total_vm += size >> PAGE_SHIFT; - + vm_stat_account(vma); up_write(&task->mm->mmap_sem); /* @@ -2592,7 +2602,7 @@ */ if (task == current) return 0; - if (task->state != TASK_STOPPED) { + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { DPRINT(("cannot attach to non-stopped task [%d] state=%ld\n", task->pid, task->state)); return -EBUSY; } @@ -2659,8 +2669,10 @@ ctx = pfm_context_alloc(); if (!ctx) goto error; - req->ctx_fd = ctx->ctx_fd = pfm_alloc_fd(&filp); - if (req->ctx_fd < 0) goto error_file; + ret = pfm_alloc_fd(&filp); + if (ret < 0) goto error_file; + + req->ctx_fd = ctx->ctx_fd = ret; /* * attach context to file @@ -3985,7 +3997,10 @@ state = ctx->ctx_state; is_system = ctx->ctx_fl_system; - if (state != PFM_CTX_LOADED && state != PFM_CTX_MASKED) return -EINVAL; + /* + * context must be attached to issue the stop command (includes LOADED,MASKED,ZOMBIE) + */ + if (state == PFM_CTX_UNLOADED) return -EINVAL; /* * In system wide and when the context is loaded, access can only happen @@ -4741,7 +4756,7 @@ * the task must be stopped. */ if (PFM_CMD_STOPPED(cmd)) { - if (task->state != TASK_STOPPED) { + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { DPRINT(("[%d] task not in stopped state\n", task->pid)); return -EBUSY; } @@ -4782,7 +4797,7 @@ * system-call entry point (must return long) */ asmlinkage long -sys_perfmonctl (int fd, int cmd, void *arg, int count, long arg5, long arg6, long arg7, +sys_perfmonctl (int fd, int cmd, void __user *arg, int count, long arg5, long arg6, long arg7, long arg8, long stack) { struct pt_regs *regs = (struct pt_regs *)&stack; @@ -6312,15 +6327,15 @@ */ is_self = ctx->ctx_task == task ? 1 : 0; -#ifdef CONFIG_SMP - if (task == current) { -#else /* - * in UP, the state can still be in the registers + * can access PMU is task is the owner of the PMU state on the current CPU + * or if we are running on the CPU bound to the context in system-wide mode + * (that is not necessarily the task the context is attached to in this mode). + * In system-wide we always have can_access_pmu true because a task running on an + * invalid processor is flagged earlier in the call stack (see pfm_stop). */ - if (task == current || GET_PMU_OWNER() == task) { -#endif - can_access_pmu = 1; + can_access_pmu = (GET_PMU_OWNER() == task) || (ctx->ctx_fl_system && ctx->ctx_cpu == smp_processor_id()); + if (can_access_pmu) { /* * Mark the PMU as not owned * This will cause the interrupt handler to do nothing in case an overflow @@ -6330,6 +6345,7 @@ * on. */ SET_PMU_OWNER(NULL, NULL); + DPRINT(("releasing ownership\n")); /* * read current overflow status: diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/kernel/process.c 2004-10-18 14:56:29 -07:00 @@ -74,12 +74,12 @@ show_stack (struct task_struct *task, unsigned long *sp) { if (!task) - unw_init_running(ia64_do_show_stack, 0); + unw_init_running(ia64_do_show_stack, NULL); else { struct unw_frame_info info; unw_init_from_blocked_task(&info, task); - ia64_do_show_stack(&info, 0); + ia64_do_show_stack(&info, NULL); } } @@ -138,7 +138,7 @@ ndirty = (regs->loadrs >> 19); bsp = ia64_rse_skip_regs((unsigned long *) regs->ar_bspstore, ndirty); for (i = 0; i < sof; ++i) { - get_user(val, ia64_rse_skip_regs(bsp, i)); + get_user(val, (unsigned long __user *) ia64_rse_skip_regs(bsp, i)); printk("r%-3u:%c%016lx%s", 32 + i, is_nat ? '*' : ' ', val, ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } @@ -228,18 +228,26 @@ /* endless idle loop with no priority at all */ while (1) { - void (*idle)(void) = pm_idle; - if (!idle) - idle = default_idle; - #ifdef CONFIG_SMP if (!need_resched()) min_xtp(); #endif while (!need_resched()) { + void (*idle)(void); + if (mark_idle) (*mark_idle)(1); + /* + * Mark this as an RCU critical section so that + * synchronize_kernel() in the unload path waits + * for our completion. + */ + rcu_read_lock(); + idle = pm_idle; + if (!idle) + idle = default_idle; (*idle)(); + rcu_read_unlock(); } if (mark_idle) @@ -602,16 +610,18 @@ } asmlinkage long -sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs) +sys_execve (char __user *filename, char __user * __user *argv, char __user * __user *envp, + struct pt_regs *regs) { + char *fname; int error; - filename = getname(filename); - error = PTR_ERR(filename); - if (IS_ERR(filename)) + fname = getname(filename); + error = PTR_ERR(fname); + if (IS_ERR(fname)) goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); + error = do_execve(fname, argv, envp, regs); + putname(fname); out: return error; } @@ -743,7 +753,7 @@ void machine_restart (char *restart_cmd) { - (*efi.reset_system)(EFI_RESET_WARM, 0, 0, 0); + (*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL); } EXPORT_SYMBOL(machine_restart); diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c --- a/arch/ia64/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 @@ -152,7 +152,7 @@ ri = 0; regs->cr_iip += 16; } else if (ri == 2) { - get_user(w0, (char *) regs->cr_iip + 0); + get_user(w0, (char __user *) regs->cr_iip + 0); if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) { /* * rfi'ing to slot 2 of an MLX bundle causes @@ -174,7 +174,7 @@ if (ia64_psr(regs)->ri == 0) { regs->cr_iip -= 16; ri = 2; - get_user(w0, (char *) regs->cr_iip + 0); + get_user(w0, (char __user *) regs->cr_iip + 0); if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) { /* * rfi'ing to slot 2 of an MLX bundle causes @@ -833,7 +833,7 @@ case PT_CFM: urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); if (write_access) { - if (((cfm ^ *data) & 0x3fffffffffU) != 0) { + if (((cfm ^ *data) & 0x3fffffffffUL) != 0) { if (ia64_sync_user_rbs(child, sw, pt->ar_bspstore, urbs_end) < 0) return -1; @@ -997,12 +997,14 @@ } static long -ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) +ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) { + unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val; + struct unw_frame_info info; + struct ia64_fpreg fpval; struct switch_stack *sw; struct pt_regs *pt; long ret, retval; - struct unw_frame_info info; char nat = 0; int i; @@ -1023,12 +1025,21 @@ return -EIO; } + if (access_uarea(child, PT_CR_IPSR, &psr, 0) < 0 + || access_uarea(child, PT_AR_EC, &ec, 0) < 0 + || access_uarea(child, PT_AR_LC, &lc, 0) < 0 + || access_uarea(child, PT_AR_RNAT, &rnat, 0) < 0 + || access_uarea(child, PT_AR_BSP, &bsp, 0) < 0 + || access_uarea(child, PT_CFM, &cfm, 0) + || access_uarea(child, PT_NAT_BITS, &nat_bits, 0)) + return -EIO; + retval = 0; /* control regs */ retval |= __put_user(pt->cr_iip, &ppr->cr_iip); - retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 0); + retval |= __put_user(psr, &ppr->cr_ipsr); /* app regs */ @@ -1039,11 +1050,11 @@ retval |= __put_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); retval |= __put_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); - retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 0); - retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 0); - retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 0); - retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 0); - retval |= access_uarea(child, PT_CFM, &ppr->cfm, 0); + retval |= __put_user(ec, &ppr->ar[PT_AUR_EC]); + retval |= __put_user(lc, &ppr->ar[PT_AUR_LC]); + retval |= __put_user(rnat, &ppr->ar[PT_AUR_RNAT]); + retval |= __put_user(bsp, &ppr->ar[PT_AUR_BSP]); + retval |= __put_user(cfm, &ppr->cfm); /* gr1-gr3 */ @@ -1053,7 +1064,9 @@ /* gr4-gr7 */ for (i = 4; i < 8; i++) { - retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 0); + if (unw_access_gr(&info, i, &val, &nat, 0) < 0) + return -EIO; + retval |= __put_user(val, &ppr->gr[i]); } /* gr8-gr11 */ @@ -1077,7 +1090,9 @@ /* b1-b5 */ for (i = 1; i < 6; i++) { - retval |= unw_access_br(&info, i, &ppr->br[i], 0); + if (unw_access_br(&info, i, &val, 0) < 0) + return -EIO; + __put_user(val, &ppr->br[i]); } /* b6-b7 */ @@ -1088,8 +1103,9 @@ /* fr2-fr5 */ for (i = 2; i < 6; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); + if (unw_get_fr(&info, i, &fpval) < 0) + return -EIO; + retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } /* fr6-fr11 */ @@ -1103,8 +1119,9 @@ /* fr16-fr31 */ for (i = 16; i < 32; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); + if (unw_get_fr(&info, i, &fpval) < 0) + return -EIO; + retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } /* fph */ @@ -1118,22 +1135,25 @@ /* nat bits */ - retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 0); + retval |= __put_user(nat_bits, &ppr->nat); ret = retval ? -EIO : 0; return ret; } static long -ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) +ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) { + unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; + struct unw_frame_info info; struct switch_stack *sw; + struct ia64_fpreg fpval; struct pt_regs *pt; long ret, retval; - struct unw_frame_info info; - char nat = 0; int i; + memset(&fpval, 0, sizeof(fpval)); + retval = verify_area(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs)); if (retval != 0) { return -EIO; @@ -1156,7 +1176,7 @@ /* control regs */ retval |= __get_user(pt->cr_iip, &ppr->cr_iip); - retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 1); + retval |= __get_user(psr, &ppr->cr_ipsr); /* app regs */ @@ -1167,11 +1187,11 @@ retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); retval |= __get_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); - retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 1); - retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 1); - retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 1); - retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 1); - retval |= access_uarea(child, PT_CFM, &ppr->cfm, 1); + retval |= __get_user(ec, &ppr->ar[PT_AUR_EC]); + retval |= __get_user(lc, &ppr->ar[PT_AUR_LC]); + retval |= __get_user(rnat, &ppr->ar[PT_AUR_RNAT]); + retval |= __get_user(bsp, &ppr->ar[PT_AUR_BSP]); + retval |= __get_user(cfm, &ppr->cfm); /* gr1-gr3 */ @@ -1181,11 +1201,9 @@ /* gr4-gr7 */ for (i = 4; i < 8; i++) { - long ret = unw_get_gr(&info, i, &ppr->gr[i], &nat); - if (ret < 0) { - return ret; - } - retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 1); + retval |= __get_user(val, &ppr->gr[i]); + if (unw_set_gr(&info, i, val, 0) < 0) /* NaT bit will be set via PT_NAT_BITS */ + return -EIO; } /* gr8-gr11 */ @@ -1209,7 +1227,8 @@ /* b1-b5 */ for (i = 1; i < 6; i++) { - retval |= unw_access_br(&info, i, &ppr->br[i], 1); + retval |= __get_user(val, &ppr->br[i]); + unw_set_br(&info, i, val); } /* b6-b7 */ @@ -1220,8 +1239,9 @@ /* fr2-fr5 */ for (i = 2; i < 6; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); + retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval)); + if (unw_set_fr(&info, i, fpval) < 0) + return -EIO; } /* fr6-fr11 */ @@ -1235,8 +1255,9 @@ /* fr16-fr31 */ for (i = 16; i < 32; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); + retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval)); + if (unw_set_fr(&info, i, fpval) < 0) + return -EIO; } /* fph */ @@ -1250,7 +1271,15 @@ /* nat bits */ - retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 1); + retval |= __get_user(nat_bits, &ppr->nat); + + retval |= access_uarea(child, PT_CR_IPSR, &psr, 1); + retval |= access_uarea(child, PT_AR_EC, &ec, 1); + retval |= access_uarea(child, PT_AR_LC, &lc, 1); + retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1); + retval |= access_uarea(child, PT_AR_BSP, &bsp, 1); + retval |= access_uarea(child, PT_CFM, &cfm, 1); + retval |= access_uarea(child, PT_NAT_BITS, &nat_bits, 1); ret = retval ? -EIO : 0; return ret; @@ -1429,11 +1458,11 @@ goto out_tsk; case PTRACE_GETREGS: - ret = ptrace_getregs(child, (struct pt_all_user_regs*) data); + ret = ptrace_getregs(child, (struct pt_all_user_regs __user *) data); goto out_tsk; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (struct pt_all_user_regs*) data); + ret = ptrace_setregs(child, (struct pt_all_user_regs __user *) data); goto out_tsk; default: diff -Nru a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c --- a/arch/ia64/kernel/sal.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/kernel/sal.c 2004-10-18 14:57:04 -07:00 @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -262,3 +263,40 @@ p += SAL_DESC_SIZE(*p); } } + +int +ia64_sal_oemcall(struct ia64_sal_retval *isrvp, u64 oemfunc, u64 arg1, + u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) +{ + if (oemfunc < IA64_SAL_OEMFUNC_MIN || oemfunc > IA64_SAL_OEMFUNC_MAX) + return -1; + SAL_CALL(*isrvp, oemfunc, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + return 0; +} +EXPORT_SYMBOL(ia64_sal_oemcall); + +int +ia64_sal_oemcall_nolock(struct ia64_sal_retval *isrvp, u64 oemfunc, u64 arg1, + u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, + u64 arg7) +{ + if (oemfunc < IA64_SAL_OEMFUNC_MIN || oemfunc > IA64_SAL_OEMFUNC_MAX) + return -1; + SAL_CALL_NOLOCK(*isrvp, oemfunc, arg1, arg2, arg3, arg4, arg5, arg6, + arg7); + return 0; +} +EXPORT_SYMBOL(ia64_sal_oemcall_nolock); + +int +ia64_sal_oemcall_reentrant(struct ia64_sal_retval *isrvp, u64 oemfunc, + u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, + u64 arg6, u64 arg7) +{ + if (oemfunc < IA64_SAL_OEMFUNC_MIN || oemfunc > IA64_SAL_OEMFUNC_MAX) + return -1; + SAL_CALL_REENTRANT(*isrvp, oemfunc, arg1, arg2, arg3, arg4, arg5, arg6, + arg7); + return 0; +} +EXPORT_SYMBOL(ia64_sal_oemcall_reentrant); diff -Nru a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c --- a/arch/ia64/kernel/salinfo.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ia64/kernel/salinfo.c 2004-10-18 14:56:48 -07:00 @@ -268,7 +268,7 @@ } static ssize_t -salinfo_event_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry *entry = PDE(inode); @@ -417,11 +417,16 @@ if (!data->saved_num) call_on_cpu(cpu, salinfo_log_read_cpu, data); - data->state = data->log_size ? STATE_LOG_RECORD : STATE_NO_DATA; + if (!data->log_size) { + data->state = STATE_NO_DATA; + clear_bit(cpu, &data->cpu_event); + } else { + data->state = STATE_LOG_RECORD; + } } static ssize_t -salinfo_log_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +salinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry *entry = PDE(inode); @@ -478,7 +483,7 @@ } static ssize_t -salinfo_log_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +salinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry *entry = PDE(inode); diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c --- a/arch/ia64/kernel/setup.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ia64/kernel/setup.c 2004-10-18 14:55:55 -07:00 @@ -680,7 +680,7 @@ break; } - if (ia64_pal_rse_info(&num_phys_stacked, 0) != 0) { + if (ia64_pal_rse_info(&num_phys_stacked, NULL) != 0) { printk(KERN_WARNING "cpu_init: PAL RSE info failed; assuming 96 physical " "stacked regs\n"); num_phys_stacked = 96; diff -Nru a/arch/ia64/kernel/sigframe.h b/arch/ia64/kernel/sigframe.h --- a/arch/ia64/kernel/sigframe.h 2004-10-18 14:56:49 -07:00 +++ b/arch/ia64/kernel/sigframe.h 2004-10-18 14:56:49 -07:00 @@ -17,7 +17,7 @@ * End of architected state. */ - void *handler; /* pointer to the plabel of the signal handler */ + void __user *handler; /* pointer to the plabel of the signal handler */ struct siginfo info; struct sigcontext sc; }; diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c --- a/arch/ia64/kernel/signal.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ia64/kernel/signal.c 2004-10-18 14:56:33 -07:00 @@ -1,7 +1,7 @@ /* * Architecture-specific signal handling support. * - * Copyright (C) 1999-2003 Hewlett-Packard Co + * Copyright (C) 1999-2004 Hewlett-Packard Co * David Mosberger-Tang * * Derived from i386 and Alpha versions. @@ -43,7 +43,7 @@ #endif long -ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) +ia64_rt_sigsuspend (sigset_t __user *uset, size_t sigsetsize, struct sigscratch *scr) { sigset_t oldset, set; @@ -84,7 +84,7 @@ } asmlinkage long -sys_sigaltstack (const stack_t *uss, stack_t *uoss, long arg2, long arg3, long arg4, +sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt = (struct pt_regs *) &stack; @@ -93,7 +93,7 @@ } static long -restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) +restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) { unsigned long ip, flags, nat, um, cfm; long err; @@ -155,7 +155,7 @@ } int -copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) +copy_siginfo_to_user (siginfo_t __user *to, siginfo_t *from) { if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; @@ -211,12 +211,12 @@ ia64_rt_sigreturn (struct sigscratch *scr) { extern char ia64_strace_leave_kernel, ia64_leave_kernel; - struct sigcontext *sc; + struct sigcontext __user *sc; struct siginfo si; sigset_t set; long retval; - sc = &((struct sigframe *) (scr->pt.r12 + 16))->sc; + sc = &((struct sigframe __user *) (scr->pt.r12 + 16))->sc; /* * When we return to the previously executing context, r8 and r10 have already @@ -260,7 +260,7 @@ * It is more difficult to avoid calling this function than to * call it and ignore errors. */ - do_sigaltstack(&sc->sc_stack, 0, scr->pt.r12); + do_sigaltstack(&sc->sc_stack, NULL, scr->pt.r12); return retval; give_sigsegv: @@ -281,7 +281,7 @@ * trampoline starts. Everything else is done at the user-level. */ static long -setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr) +setup_sigcontext (struct sigcontext __user *sc, sigset_t *mask, struct sigscratch *scr) { unsigned long flags = 0, ifs, cfm, nat; long err; @@ -335,7 +335,7 @@ err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); /* ar.ccv */ err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ err |= __put_user(scr->pt.r14, &sc->sc_gr[14]); /* r14 */ - err |= __copy_to_user(&scr->pt.ar_csd, &sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __copy_to_user(&sc->sc_ar25, &scr->pt.ar_csd, 2*8); /* ar.csd & ar.ssd */ err |= __copy_to_user(&sc->sc_gr[2], &scr->pt.r2, 2*8); /* r2-r3 */ err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */ } @@ -352,20 +352,49 @@ } static long +force_sigsegv_info (int sig, void __user *addr) +{ + unsigned long flags; + struct siginfo si; + + if (sig == SIGSEGV) { + /* + * Acquiring siglock around the sa_handler-update is almost + * certainly overkill, but this isn't a + * performance-critical path and I'd rather play it safe + * here than having to debug a nasty race if and when + * something changes in kernel/signal.c that would make it + * no longer safe to modify sa_handler without holding the + * lock. + */ + spin_lock_irqsave(¤t->sighand->siglock, flags); + current->sighand->action[sig - 1].sa.sa_handler = SIG_DFL; + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + } + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = SI_KERNEL; + si.si_pid = current->pid; + si.si_uid = current->uid; + si.si_addr = addr; + force_sig_info(SIGSEGV, &si, current); + return 0; +} + +static long setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct sigscratch *scr) { extern char __kernel_sigtramp[]; unsigned long tramp_addr, new_rbs = 0; - struct sigframe *frame; - struct siginfo si; + struct sigframe __user *frame; long err; - frame = (void *) scr->pt.r12; + frame = (void __user *) scr->pt.r12; tramp_addr = (unsigned long) __kernel_sigtramp; if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) { - frame = (void *) ((current->sas_ss_sp + current->sas_ss_size) - & ~(STACK_ALIGN - 1)); + frame = (void __user *) ((current->sas_ss_sp + current->sas_ss_size) + & ~(STACK_ALIGN - 1)); /* * We need to check for the register stack being on the signal stack * separately, because it's switched separately (memory stack is switched @@ -374,10 +403,10 @@ if (!rbs_on_sig_stack(scr->pt.ar_bspstore)) new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); } - frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1)); + frame = (void __user *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; + return force_sigsegv_info(sig, frame); err = __put_user(sig, &frame->arg0); err |= __put_user(&frame->info, &frame->arg1); @@ -393,8 +422,8 @@ err |= __put_user(sas_ss_flags(scr->pt.r12), &frame->sc.sc_stack.ss_flags); err |= setup_sigcontext(&frame->sc, set, scr); - if (err) - goto give_sigsegv; + if (unlikely(err)) + return force_sigsegv_info(sig, frame); scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */ scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ @@ -422,18 +451,6 @@ current->comm, current->pid, sig, scr->pt.r12, frame->sc.sc_ip, frame->handler); #endif return 1; - - give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = SI_KERNEL; - si.si_pid = current->pid; - si.si_uid = current->uid; - si.si_addr = frame; - force_sig_info(SIGSEGV, &si, current); - return 0; } static long @@ -449,9 +466,6 @@ if (!setup_frame(sig, ka, info, oldset, scr)) return 0; - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); { @@ -471,7 +485,7 @@ long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) { - struct k_sigaction *ka; + struct k_sigaction ka; siginfo_t info; long restart = in_syscall; long errno = scr->pt.r8; @@ -493,7 +507,7 @@ * need to push through a forced SIGSEGV. */ while (1) { - int signr = get_signal_to_deliver(&info, &scr->pt, NULL); + int signr = get_signal_to_deliver(&info, &ka, &scr->pt, NULL); /* * get_signal_to_deliver() may have run a debugger (via notify_parent()) @@ -520,8 +534,6 @@ if (signr <= 0) break; - ka = ¤t->sighand->action[signr - 1]; - if (unlikely(restart)) { switch (errno) { case ERESTART_RESTARTBLOCK: @@ -531,7 +543,7 @@ break; case ERESTARTSYS: - if ((ka->sa.sa_flags & SA_RESTART) == 0) { + if ((ka.sa.sa_flags & SA_RESTART) == 0) { scr->pt.r8 = ERR_CODE(EINTR); /* note: scr->pt.r10 is already -1 */ break; @@ -550,7 +562,7 @@ * Whee! Actually deliver the signal. If the delivery failed, we need to * continue to iterate in this loop so we can deliver the SIGSEGV... */ - if (handle_signal(signr, ka, &info, oldset, scr)) + if (handle_signal(signr, &ka, &info, oldset, scr)) return 1; } diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c --- a/arch/ia64/kernel/smp.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/kernel/smp.c 2004-10-18 14:57:04 -07:00 @@ -225,7 +225,7 @@ void smp_flush_tlb_all (void) { - on_each_cpu((void (*)(void *))local_flush_tlb_all, 0, 1, 1); + on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1); } EXPORT_SYMBOL(smp_flush_tlb_all); diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c --- a/arch/ia64/kernel/smpboot.c 2004-10-18 14:56:20 -07:00 +++ b/arch/ia64/kernel/smpboot.c 2004-10-18 14:56:20 -07:00 @@ -356,19 +356,15 @@ return cpu_idle(); } -static struct task_struct * __devinit -fork_by_hand (void) +struct pt_regs * __devinit idle_regs(struct pt_regs *regs) { - /* - * Don't care about the IP and regs settings since we'll never reschedule the - * forked task. - */ - return copy_process(CLONE_VM|CLONE_IDLETASK, 0, 0, 0, NULL, NULL); + return NULL; } struct create_idle { struct task_struct *idle; struct completion done; + int cpu; }; void @@ -376,7 +372,7 @@ { struct create_idle *c_idle = _c_idle; - c_idle->idle = fork_by_hand(); + c_idle->idle = fork_idle(c_idle->cpu); complete(&c_idle->done); } @@ -384,10 +380,11 @@ do_boot_cpu (int sapicid, int cpu) { int timeout; - struct create_idle c_idle; + struct create_idle c_idle = { + .cpu = cpu, + .done = COMPLETION_INITIALIZER(c_idle.done), + }; DECLARE_WORK(work, do_fork_idle, &c_idle); - - init_completion(&c_idle.done); /* * We can't use kernel_thread since we must avoid to reschedule the child. */ @@ -400,16 +397,6 @@ if (IS_ERR(c_idle.idle)) panic("failed fork for CPU %d", cpu); - wake_up_forked_process(c_idle.idle); - - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ - init_idle(c_idle.idle, cpu); - - unhash_process(c_idle.idle); - task_for_booting_cpu = c_idle.idle; Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); @@ -719,3 +706,4 @@ printk(KERN_ERR "SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); } + diff -Nru a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c --- a/arch/ia64/kernel/sys_ia64.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ia64/kernel/sys_ia64.c 2004-10-18 14:56:33 -07:00 @@ -93,7 +93,7 @@ } asmlinkage unsigned long -ia64_shmat (int shmid, void *shmaddr, int shmflg) +ia64_shmat (int shmid, void __user *shmaddr, int shmflg) { unsigned long raddr; int retval; @@ -183,7 +183,7 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) { unsigned long roff; - struct file *file = 0; + struct file *file = NULL; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c --- a/arch/ia64/kernel/time.c 2004-10-18 14:56:17 -07:00 +++ b/arch/ia64/kernel/time.c 2004-10-18 14:56:17 -07:00 @@ -45,192 +45,7 @@ #endif -static void -itc_reset (void) -{ -} - -/* - * Adjust for the fact that xtime has been advanced by delta_nsec (may be negative and/or - * larger than NSEC_PER_SEC. - */ -static void -itc_update (long delta_nsec) -{ -} - -/* - * Return the number of nano-seconds that elapsed since the last - * update to jiffy. It is quite possible that the timer interrupt - * will interrupt this and result in a race for any of jiffies, - * wall_jiffies or itm_next. Thus, the xtime_lock must be at least - * read synchronised when calling this routine (see do_gettimeofday() - * below for an example). - */ -unsigned long -itc_get_offset (void) -{ - unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; - unsigned long now = ia64_get_itc(), last_tick; - - last_tick = (cpu_data(TIME_KEEPER_ID)->itm_next - - (lost + 1)*cpu_data(TIME_KEEPER_ID)->itm_delta); - - elapsed_cycles = now - last_tick; - return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT; -} - -static struct time_interpolator itc_interpolator = { - .get_offset = itc_get_offset, - .update = itc_update, - .reset = itc_reset -}; - -int -do_settimeofday (struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - { - /* - * This is revolting. We need to set "xtime" correctly. However, the value - * in this location is the value at the most recent update of wall time. - * Discover what correction gettimeofday would have done, and then undo - * it! - */ - nsec -= time_interpolator_get_offset(); - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - time_interpolator_reset(); - } - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - -void -do_gettimeofday (struct timeval *tv) -{ - unsigned long seq, nsec, usec, sec, old, offset; - - while (1) { - seq = read_seqbegin(&xtime_lock); - { - old = last_nsec_offset; - offset = time_interpolator_get_offset(); - sec = xtime.tv_sec; - nsec = xtime.tv_nsec; - } - if (unlikely(read_seqretry(&xtime_lock, seq))) - continue; - /* - * Ensure that for any pair of causally ordered gettimeofday() calls, time - * never goes backwards (even when ITC on different CPUs are not perfectly - * synchronized). (A pair of concurrent calls to gettimeofday() is by - * definition non-causal and hence it makes no sense to talk about - * time-continuity for such calls.) - * - * Doing this in a lock-free and race-free manner is tricky. Here is why - * it works (most of the time): read_seqretry() just succeeded, which - * implies we calculated a consistent (valid) value for "offset". If the - * cmpxchg() below succeeds, we further know that last_nsec_offset still - * has the same value as at the beginning of the loop, so there was - * presumably no timer-tick or other updates to last_nsec_offset in the - * meantime. This isn't 100% true though: there _is_ a possibility of a - * timer-tick occurring right right after read_seqretry() and then getting - * zero or more other readers which will set last_nsec_offset to the same - * value as the one we read at the beginning of the loop. If this - * happens, we'll end up returning a slightly newer time than we ought to - * (the jump forward is at most "offset" nano-seconds). There is no - * danger of causing time to go backwards, though, so we are safe in that - * sense. We could make the probability of this unlucky case occurring - * arbitrarily small by encoding a version number in last_nsec_offset, but - * even without versioning, the probability of this unlucky case should be - * so small that we won't worry about it. - */ - if (offset <= old) { - offset = old; - break; - } else if (likely(cmpxchg(&last_nsec_offset, old, offset) == old)) - break; - - /* someone else beat us to updating last_nsec_offset; try again */ - } - - usec = (nsec + offset) / 1000; - - while (unlikely(usec >= USEC_PER_SEC)) { - usec -= USEC_PER_SEC; - ++sec; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -/* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ -static inline void -ia64_do_profile (struct pt_regs * regs) -{ - unsigned long ip, slot; - extern cpumask_t prof_cpu_mask; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - ip = instruction_pointer(regs); - /* Conserve space in histogram by encoding slot bits in address - * bits 2 and 3 rather than bits 0 and 1. - */ - slot = ip & 3; - ip = (ip & ~3UL) + 4*slot; - - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!cpu_isset(smp_processor_id(), prof_cpu_mask)) - return; - - ip -= (unsigned long) &_stext; - ip >>= prof_shift; - /* - * Don't ignore out-of-bounds IP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (ip > prof_len-1) - ip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[ip]); -} +static struct time_interpolator itc_interpolator; static irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) @@ -249,7 +64,7 @@ printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", ia64_get_itc(), new_itm); - ia64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); while (1) { #ifdef CONFIG_SMP @@ -323,6 +138,18 @@ ia64_set_itm(local_cpu_data->itm_next); } +static int nojitter; + +static int __init nojitter_setup(char *str) +{ + nojitter = 1; + printk("Jitter checking for ITC timers disabled\n"); + return 1; +} + +__setup("nojitter", nojitter_setup); + + void __devinit ia64_init_itm (void) { @@ -340,7 +167,7 @@ if (status != 0) { printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status)); } else { - status = ia64_pal_freq_ratios(&proc_ratio, 0, &itc_ratio); + status = ia64_pal_freq_ratios(&proc_ratio, NULL, &itc_ratio); if (status != 0) printk(KERN_ERR "PAL_FREQ_RATIOS failed with status=%ld\n", status); } @@ -371,7 +198,7 @@ itc_drift = -1; local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; - printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " + printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " "ITC freq=%lu.%03luMHz+/-%ldppm\n", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000, @@ -385,7 +212,23 @@ if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { itc_interpolator.frequency = local_cpu_data->itc_freq; + itc_interpolator.shift = 16; itc_interpolator.drift = itc_drift; + itc_interpolator.source = TIME_SOURCE_CPU; +#ifdef CONFIG_SMP + /* On IA64 in an SMP configuration ITCs are never accurately synchronized. + * Jitter compensation requires a cmpxchg which may limit + * the scalability of the syscalls for retrieving time. + * The ITC synchronization is usually successful to within a few + * ITC ticks but this is not a sure thing. If you need to improve + * timer performance in SMP situations then boot the kernel with the + * "nojitter" option. However, doing so may result in time fluctuating (maybe + * even going backward) if the ITC offsets between the individual CPUs + * are too large. + */ + if (!nojitter) itc_interpolator.jitter = 1; +#endif + itc_interpolator.addr = NULL; register_time_interpolator(&itc_interpolator); } diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c --- a/arch/ia64/kernel/traps.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/kernel/traps.c 2004-10-18 14:57:04 -07:00 @@ -14,9 +14,9 @@ #include #include /* For unblank_screen() */ #include /* for EXPORT_SYMBOL */ +#include #include -#include #include #include #include @@ -112,7 +112,7 @@ int sig, code; /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = break_num; siginfo.si_flags = 0; /* clear __ISR_VALID */ siginfo.si_isr = 0; @@ -282,7 +282,7 @@ fault_ip = regs->cr_iip; if (!fp_fault && (ia64_psr(regs)->ri == 0)) fault_ip -= 16; - if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle))) + if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle))) return -1; if (jiffies - last_time > 5*HZ) @@ -312,7 +312,7 @@ siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = __SI_FAULT; /* default code */ - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); if (isr & 0x11) { siginfo.si_code = FPE_FLTINV; } else if (isr & 0x22) { @@ -336,7 +336,7 @@ siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = __SI_FAULT; /* default code */ - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); if (isr & 0x880) { siginfo.si_code = FPE_FLTOVF; } else if (isr & 0x1100) { @@ -383,7 +383,7 @@ memset(&si, 0, sizeof(si)); si.si_signo = SIGILL; si.si_code = ILL_ILLOPC; - si.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + si.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); force_sig_info(SIGILL, &si, current); rv.fkt = 0; return rv; @@ -445,18 +445,18 @@ case 26: /* NaT Consumption */ if (user_mode(regs)) { - void *addr; + void __user *addr; if (((isr >> 4) & 0xf) == 2) { /* NaT page consumption */ sig = SIGSEGV; code = SEGV_ACCERR; - addr = (void *) ifa; + addr = (void __user *) ifa; } else { /* register NaT consumption */ sig = SIGILL; code = ILL_ILLOPN; - addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); } siginfo.si_signo = sig; siginfo.si_code = code; @@ -477,7 +477,7 @@ siginfo.si_signo = SIGILL; siginfo.si_code = ILL_ILLOPN; siginfo.si_errno = 0; - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = vector; siginfo.si_flags = __ISR_VALID; siginfo.si_isr = isr; @@ -524,7 +524,7 @@ } siginfo.si_signo = SIGTRAP; siginfo.si_errno = 0; - siginfo.si_addr = (void *) ifa; + siginfo.si_addr = (void __user *) ifa; siginfo.si_imm = 0; siginfo.si_flags = __ISR_VALID; siginfo.si_isr = isr; @@ -538,7 +538,7 @@ siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = FPE_FLTINV; - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_flags = __ISR_VALID; siginfo.si_isr = isr; siginfo.si_imm = 0; @@ -565,7 +565,8 @@ siginfo.si_flags = 0; siginfo.si_isr = 0; siginfo.si_imm = 0; - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) + (regs->cr_iip + ia64_psr(regs)->ri); force_sig_info(SIGILL, &siginfo, current); return; } diff -Nru a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c --- a/arch/ia64/kernel/unaligned.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ia64/kernel/unaligned.c 2004-10-18 14:57:03 -07:00 @@ -760,7 +760,7 @@ return -1; } /* this assumes little-endian byte-order: */ - if (copy_from_user(&val, (void *) ifa, len)) + if (copy_from_user(&val, (void __user *) ifa, len)) return -1; setreg(ld.r1, val, 0, regs); @@ -869,7 +869,7 @@ * * extract the value to be stored */ - getreg(ld.imm, &r2, 0, regs); + getreg(ld.imm, &r2, NULL, regs); /* * we rely on the macros in unaligned.h for now i.e., @@ -887,7 +887,7 @@ } /* this assumes little-endian byte-order: */ - if (copy_to_user((void *) ifa, &r2, len)) + if (copy_to_user((void __user *) ifa, &r2, len)) return -1; /* @@ -1036,8 +1036,8 @@ * This assumes little-endian byte-order. Note that there is no "ldfpe" * instruction: */ - if (copy_from_user(&fpr_init[0], (void *) ifa, len) - || copy_from_user(&fpr_init[1], (void *) (ifa + len), len)) + if (copy_from_user(&fpr_init[0], (void __user *) ifa, len) + || copy_from_user(&fpr_init[1], (void __user *) (ifa + len), len)) return -1; DPRINT("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld.r1, ld.imm, ld.x6_sz); @@ -1138,7 +1138,7 @@ * See comments in ldX for descriptions on how the various loads are handled. */ if (ld.x6_op != 0x2) { - if (copy_from_user(&fpr_init, (void *) ifa, len)) + if (copy_from_user(&fpr_init, (void __user *) ifa, len)) return -1; DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz); @@ -1230,7 +1230,7 @@ DDUMP("fpr_init =", &fpr_init, len); DDUMP("fpr_final =", &fpr_final, len); - if (copy_to_user((void *) ifa, &fpr_final, len)) + if (copy_to_user((void __user *) ifa, &fpr_final, len)) return -1; /* @@ -1351,7 +1351,7 @@ DPRINT("iip=%lx ifa=%lx isr=%lx (ei=%d, sp=%d)\n", regs->cr_iip, ifa, regs->cr_ipsr, ipsr->ri, ipsr->it); - if (__copy_from_user(bundle, (void *) regs->cr_iip, 16)) + if (__copy_from_user(bundle, (void __user *) regs->cr_iip, 16)) goto failure; /* @@ -1496,7 +1496,7 @@ si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; + si.si_addr = (void __user *) ifa; si.si_flags = 0; si.si_isr = 0; si.si_imm = 0; diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c --- a/arch/ia64/kernel/unwind.c 2004-10-18 14:57:18 -07:00 +++ b/arch/ia64/kernel/unwind.c 2004-10-18 14:57:18 -07:00 @@ -47,7 +47,6 @@ #include "entry.h" #include "unwind_i.h" -#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define p5 5 #define UNW_LOG_CACHE_SIZE 7 /* each unw_script is ~256 bytes in size */ @@ -447,7 +446,7 @@ int unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write) { - struct ia64_fpreg *addr = 0; + struct ia64_fpreg *addr = NULL; struct pt_regs *pt; if ((unsigned) (regnum - 2) >= 126) { @@ -843,7 +842,7 @@ } sr->gr_save_loc = grsave; sr->any_spills = 0; - sr->imask = 0; + sr->imask = NULL; sr->spill_offset = 0x10; /* default to psp+16 */ } } @@ -963,13 +962,13 @@ desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr) { set_reg(sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, - sr->region_start + MIN((int)t, sr->region_len - 1), 16*size); + sr->region_start + min_t(int, t, sr->region_len - 1), 16*size); } static inline void desc_mem_stack_v (unw_word t, struct unw_state_record *sr) { - sr->curr.reg[UNW_REG_PSP].when = sr->region_start + MIN((int)t, sr->region_len - 1); + sr->curr.reg[UNW_REG_PSP].when = sr->region_start + min_t(int, t, sr->region_len - 1); } static inline void @@ -1005,7 +1004,7 @@ if (reg->where == UNW_WHERE_NONE) reg->where = UNW_WHERE_GR_SAVE; - reg->when = sr->region_start + MIN((int)t, sr->region_len - 1); + reg->when = sr->region_start + min_t(int, t, sr->region_len - 1); } static inline void @@ -1073,7 +1072,7 @@ static inline int desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr) { - if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1)) + if (sr->when_target <= sr->region_start + min_t(int, t, sr->region_len - 1)) return 0; if (qp > 0) { if ((sr->pr_val & (1UL << qp)) == 0) @@ -1114,7 +1113,7 @@ r = sr->curr.reg + decode_abreg(abreg, 0); r->where = where; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = (ytreg & 0x7f); } @@ -1129,7 +1128,7 @@ r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_PSPREL; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = 0x10 - 4*pspoff; } @@ -1144,7 +1143,7 @@ r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_SPREL; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = 4*spoff; } @@ -1206,7 +1205,7 @@ static inline unw_hash_index_t hash (unsigned long ip) { -# define hashmagic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */ +# define hashmagic 0x9e3779b97f4a7c16UL /* based on (sqrt(5)/2-1)*2^64 */ return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE); #undef hashmagic @@ -1231,7 +1230,7 @@ unsigned long ip, pr; if (UNW_DEBUG_ON(0)) - return 0; /* Always regenerate scripts in debug mode */ + return NULL; /* Always regenerate scripts in debug mode */ STAT(++unw.stat.cache.lookups); @@ -1245,7 +1244,7 @@ index = unw.hash[hash(ip)]; if (index >= UNW_CACHE_SIZE) - return 0; + return NULL; script = unw.cache + index; while (1) { @@ -1256,7 +1255,7 @@ return script; } if (script->coll_chain >= UNW_HASH_SIZE) - return 0; + return NULL; script = unw.cache + script->coll_chain; STAT(++unw.stat.cache.collision_chain_traversals); } @@ -1306,7 +1305,7 @@ if (script->ip) { index = hash(script->ip); tmp = unw.cache + unw.hash[index]; - prev = 0; + prev = NULL; while (1) { if (tmp == script) { if (prev) @@ -1511,7 +1510,7 @@ static inline const struct unw_table_entry * lookup (struct unw_table *table, unsigned long rel_ip) { - const struct unw_table_entry *e = 0; + const struct unw_table_entry *e = NULL; unsigned long lo, hi, mid; /* do a binary search for right entry: */ @@ -1537,8 +1536,8 @@ static inline struct unw_script * build_script (struct unw_frame_info *info) { - const struct unw_table_entry *e = 0; - struct unw_script *script = 0; + const struct unw_table_entry *e = NULL; + struct unw_script *script = NULL; struct unw_labeled_state *ls, *next; unsigned long ip = info->ip; struct unw_state_record sr; @@ -1563,7 +1562,7 @@ if (!script) { UNW_DPRINT(0, "unwind.%s: failed to create unwind script\n", __FUNCTION__); STAT(unw.stat.script.build_time += ia64_get_itc() - start); - return 0; + return NULL; } unw.cache[info->prev_script].hint = script - unw.cache; @@ -1836,7 +1835,7 @@ /* don't let obviously bad addresses pollute the cache */ /* FIXME: should really be level 0 but it occurs too often. KAO */ UNW_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip); - info->rp_loc = 0; + info->rp_loc = NULL; return -1; } @@ -2093,12 +2092,12 @@ if (end - start <= 0) { UNW_DPRINT(0, "unwind.%s: ignoring attempt to insert empty unwind table\n", __FUNCTION__); - return 0; + return NULL; } table = kmalloc(sizeof(*table), GFP_USER); if (!table) - return 0; + return NULL; init_unwind_table(table, name, segment_base, gp, table_start, table_end); @@ -2300,7 +2299,7 @@ * EFAULT BUF points outside your accessible address space. */ asmlinkage long -sys_getunwind (void *buf, size_t buf_size) +sys_getunwind (void __user *buf, size_t buf_size) { if (buf && buf_size >= unw.gate_table_size) if (copy_to_user(buf, unw.gate_table, unw.gate_table_size) != 0) diff -Nru a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S --- a/arch/ia64/kernel/vmlinux.lds.S 2004-10-18 14:56:50 -07:00 +++ b/arch/ia64/kernel/vmlinux.lds.S 2004-10-18 14:56:50 -07:00 @@ -42,6 +42,7 @@ *(.text.ivt) *(.text) SCHED_TEXT + LOCK_TEXT *(.gnu.linkonce.t*) } .text2 : AT(ADDR(.text2) - LOAD_OFFSET) @@ -134,12 +135,6 @@ __setup_start = .; *(.init.setup) __setup_end = .; - } - __param : AT(ADDR(__param) - LOAD_OFFSET) - { - __start___param = .; - *(__param) - __stop___param = .; } .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { diff -Nru a/arch/ia64/lib/csum_partial_copy.c b/arch/ia64/lib/csum_partial_copy.c --- a/arch/ia64/lib/csum_partial_copy.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ia64/lib/csum_partial_copy.c 2004-10-18 14:56:33 -07:00 @@ -1,7 +1,7 @@ /* * Network Checksum & Copy routine * - * Copyright (C) 1999, 2003 Hewlett-Packard Co + * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co * Stephane Eranian * * Most of the code has been imported from Linux/Alpha @@ -105,7 +105,7 @@ extern unsigned long do_csum(const unsigned char *, long); static unsigned int -do_csum_partial_copy_from_user (const char *src, char *dst, int len, +do_csum_partial_copy_from_user (const char __user *src, char *dst, int len, unsigned int psum, int *errp) { unsigned long result; @@ -129,10 +129,10 @@ } unsigned int -csum_partial_copy_from_user(const char *src, char *dst, int len, - unsigned int sum, int *errp) +csum_partial_copy_from_user (const char __user *src, char *dst, int len, + unsigned int sum, int *errp) { - if (!access_ok(src, len, VERIFY_READ)) { + if (!access_ok(VERIFY_READ, src, len)) { *errp = -EFAULT; memset(dst, 0, len); return sum; @@ -142,7 +142,7 @@ } unsigned int -csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum) +csum_partial_copy_nocheck(const char __user *src, char *dst, int len, unsigned int sum) { return do_csum_partial_copy_from_user(src, dst, len, sum, NULL); } diff -Nru a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c --- a/arch/ia64/lib/io.c 2004-10-18 14:55:46 -07:00 +++ b/arch/ia64/lib/io.c 2004-10-18 14:55:46 -07:00 @@ -9,7 +9,7 @@ * This needs to be optimized. */ void -__ia64_memcpy_fromio (void *to, unsigned long from, long count) +__ia64_memcpy_fromio (void *to, volatile void __iomem *from, long count) { char *dst = to; @@ -25,7 +25,7 @@ * This needs to be optimized. */ void -__ia64_memcpy_toio (unsigned long to, void *from, long count) +__ia64_memcpy_toio (volatile void __iomem *to, void *from, long count) { char *src = from; @@ -41,7 +41,7 @@ * This needs to be optimized. */ void -__ia64_memset_c_io (unsigned long dst, unsigned long c, long count) +__ia64_memset_c_io (volatile void __iomem *dst, unsigned long c, long count) { unsigned char ch = (char)(c & 0xff); @@ -111,49 +111,49 @@ } unsigned char -__ia64_readb (void *addr) +__ia64_readb (void __iomem *addr) { return ___ia64_readb (addr); } unsigned short -__ia64_readw (void *addr) +__ia64_readw (void __iomem *addr) { return ___ia64_readw (addr); } unsigned int -__ia64_readl (void *addr) +__ia64_readl (void __iomem *addr) { return ___ia64_readl (addr); } unsigned long -__ia64_readq (void *addr) +__ia64_readq (void __iomem *addr) { return ___ia64_readq (addr); } unsigned char -__ia64_readb_relaxed (void *addr) +__ia64_readb_relaxed (void __iomem *addr) { return ___ia64_readb (addr); } unsigned short -__ia64_readw_relaxed (void *addr) +__ia64_readw_relaxed (void __iomem *addr) { return ___ia64_readw (addr); } unsigned int -__ia64_readl_relaxed (void *addr) +__ia64_readl_relaxed (void __iomem *addr) { return ___ia64_readl (addr); } unsigned long -__ia64_readq_relaxed (void *addr) +__ia64_readq_relaxed (void __iomem *addr) { return ___ia64_readq (addr); } diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c --- a/arch/ia64/lib/swiotlb.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ia64/lib/swiotlb.c 2004-10-18 14:56:49 -07:00 @@ -11,6 +11,7 @@ * 03/05/07 davidm Switch from PCI-DMA to generic device DMA API. * 00/12/13 davidm Rename to swiotlb.c and add mark_clean() to avoid * unnecessary i-cache flushing. + * 04/07/.. ak Better overflow handling. Assorted fixes. */ #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -46,6 +48,8 @@ */ #define IO_TLB_SHIFT 11 +int swiotlb_force; + /* * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single_*, to see * if the memory was in fact allocated by this API. @@ -55,8 +59,16 @@ /* * The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and io_tlb_end. * This is command line adjustable via setup_io_tlb_npages. + * Default to 64MB. + */ +static unsigned long io_tlb_nslabs = 32768; + +/* + * When the IOMMU overflows we return a fallback buffer. This sets the size. */ -static unsigned long io_tlb_nslabs = 1024; +static unsigned long io_tlb_overflow = 32*1024; + +void *io_tlb_overflow_buffer; /* * This is a free list describing the number of free entries available from each index @@ -78,15 +90,19 @@ static int __init setup_io_tlb_npages (char *str) { - io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); - - /* avoid tail segment of size < IO_TLB_SEGSIZE */ - io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); - + if (isdigit(*str)) { + io_tlb_nslabs = simple_strtoul(str, &str, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); + /* avoid tail segment of size < IO_TLB_SEGSIZE */ + io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); + } + if (*str == ',') + ++str; + if (!strcmp(str, "force")) + swiotlb_force = 1; return 1; } __setup("swiotlb=", setup_io_tlb_npages); - +/* make io_tlb_overflow tunable too? */ /* * Statically reserve bounce buffer space and initialize bounce buffer data structures for @@ -102,7 +118,7 @@ */ io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT)); if (!io_tlb_start) - BUG(); + panic("Cannot allocate SWIOTLB buffer"); io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT); /* @@ -115,10 +131,22 @@ io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); io_tlb_index = 0; io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); - - printk(KERN_INFO "Placing software IO TLB between 0x%p - 0x%p\n", - (void *) io_tlb_start, (void *) io_tlb_end); -} + + /* + * Get the overflow emergency buffer + */ + io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); + printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n", + virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end)); +} + +static inline int address_needs_mapping(struct device *hwdev, dma_addr_t addr) +{ + dma_addr_t mask = 0xffffffff; + if (hwdev && hwdev->dma_mask) + mask = *hwdev->dma_mask; + return (addr & ~mask) != 0; +} /* * Allocates bounce buffer and returns its kernel virtual address. @@ -184,11 +212,8 @@ index = 0; } while (index != wrap); - /* - * XXX What is a suitable recovery mechanism here? We cannot - * sleep because we are called from with in interrupts! - */ - panic("map_single: could not allocate software IO TLB (%ld bytes)", size); + spin_unlock_irqrestore(&io_tlb_lock, flags); + return NULL; } found: spin_unlock_irqrestore(&io_tlb_lock, flags); @@ -285,7 +310,7 @@ memset(ret, 0, size); dev_addr = virt_to_phys(ret); - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) + if (address_needs_mapping(hwdev,dev_addr)) panic("swiotlb_alloc_consistent: allocated memory is out of range for device"); *dma_handle = dev_addr; return ret; @@ -297,6 +322,28 @@ free_pages((unsigned long) vaddr, get_order(size)); } +static void swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) +{ + /* + * Ran out of IOMMU space for this operation. This is very bad. + * Unfortunately the drivers cannot handle this operation properly. + * unless they check for pci_dma_mapping_error (most don't) + * When the mapping is small enough return a static buffer to limit + * the damage, or panic when the transfer is too big. + */ + + printk(KERN_ERR + "PCI-DMA: Out of SW-IOMMU space for %lu bytes at device %s\n", + size, dev ? dev->bus_id : "?"); + + if (size > io_tlb_overflow && do_panic) { + if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic("PCI-DMA: Memory would be corrupted\n"); + if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic("PCI-DMA: Random memory would be DMAed\n"); + } +} + /* * Map a single buffer of the indicated size for DMA in streaming mode. The PCI address * to use is returned. @@ -308,13 +355,14 @@ swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir) { unsigned long dev_addr = virt_to_phys(ptr); + void *map; if (dir == DMA_NONE) BUG(); /* * Check if the PCI device can DMA to ptr... if so, just return ptr */ - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) == 0) + if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force) /* * Device is bit capable of DMA'ing to the buffer... just return the PCI * address of ptr @@ -324,12 +372,18 @@ /* * get a bounce buffer: */ - dev_addr = virt_to_phys(map_single(hwdev, ptr, size, dir)); + map = map_single(hwdev, ptr, size, dir); + if (!map) { + swiotlb_full(hwdev, size, dir, 1); + map = io_tlb_overflow_buffer; + } + + dev_addr = virt_to_phys(map); /* * Ensure that the address returned is DMA'ble: */ - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) + if (address_needs_mapping(hwdev, dev_addr)) panic("map_single: bounce buffer is not DMA'ble"); return dev_addr; @@ -437,9 +491,17 @@ for (i = 0; i < nelems; i++, sg++) { addr = SG_ENT_VIRT_ADDRESS(sg); dev_addr = virt_to_phys(addr); - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) - sg->dma_address = (dma_addr_t) map_single(hwdev, addr, sg->length, dir); - else + if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) { + sg->dma_address = (dma_addr_t) virt_to_phys(map_single(hwdev, addr, sg->length, dir)); + if (!sg->dma_address) { + /* Don't panic here, we expect pci_map_sg users + to do proper error handling. */ + swiotlb_full(hwdev, sg->length, dir, 0); + swiotlb_unmap_sg(hwdev, sg - i, i, dir); + sg[0].dma_length = 0; + return 0; + } + } else sg->dma_address = dev_addr; sg->dma_length = sg->length; } @@ -460,7 +522,7 @@ for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) - unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir); + unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir); else if (dir == DMA_FROM_DEVICE) mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); } @@ -501,7 +563,7 @@ int swiotlb_dma_mapping_error (dma_addr_t dma_addr) { - return 0; + return (dma_addr == virt_to_phys(io_tlb_overflow_buffer)); } /* diff -Nru a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c --- a/arch/ia64/mm/contig.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ia64/mm/contig.c 2004-10-18 14:56:28 -07:00 @@ -116,19 +116,19 @@ range_start = max(start, free_start); range_end = min(end, rsvd_region[i].start & PAGE_MASK); + free_start = PAGE_ALIGN(rsvd_region[i].end); + if (range_end <= range_start) continue; /* skip over empty range */ - if (range_end - range_start >= needed) { + if (range_end - range_start >= needed) { bootmap_start = __pa(range_start); - return 1; /* done */ + return -1; /* done */ } /* nothing more available in this segment */ if (range_end == end) return 0; - - free_start = PAGE_ALIGN(rsvd_region[i].end); } return 0; } @@ -267,9 +267,8 @@ efi_memmap_walk(find_largest_hole, (u64 *)&max_gap); if (max_gap < LARGE_GAP) { vmem_map = (struct page *) 0; - free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, + free_area_init_node(0, &contig_page_data, zones_size, 0, zholes_size); - mem_map = contig_page_data.node_mem_map; } else { unsigned long map_size; @@ -278,12 +277,12 @@ map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page)); vmalloc_end -= map_size; vmem_map = (struct page *) vmalloc_end; - efi_memmap_walk(create_mem_map_page_table, 0); + efi_memmap_walk(create_mem_map_page_table, NULL); - free_area_init_node(0, &contig_page_data, vmem_map, zones_size, + mem_map = contig_page_data.node_mem_map = vmem_map; + free_area_init_node(0, &contig_page_data, zones_size, 0, zholes_size); - mem_map = contig_page_data.node_mem_map; printk("Virtual mem_map starts at 0x%p\n", mem_map); } #else /* !CONFIG_VIRTUAL_MEM_MAP */ diff -Nru a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c --- a/arch/ia64/mm/discontig.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ia64/mm/discontig.c 2004-10-18 14:56:50 -07:00 @@ -53,11 +53,12 @@ static void __init reassign_cpu_only_nodes(void) { struct node_memblk_s *p; - int i, j, k, nnode, nid, cpu, cpunid; + int i, j, k, nnode, nid, cpu, cpunid, pxm; u8 cslit, slit; static DECLARE_BITMAP(nodes_with_mem, NR_NODES) __initdata; static u8 numa_slit_fix[MAX_NUMNODES * MAX_NUMNODES] __initdata; static int node_flip[NR_NODES] __initdata; + static int old_nid_map[NR_CPUS] __initdata; for (nnode = 0, p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++) if (!test_bit(p->nid, (void *) nodes_with_mem)) { @@ -104,9 +105,14 @@ for (cpu = 0; cpu < NR_CPUS; cpu++) if (node_cpuid[cpu].nid == i) { - /* For nodes not being reassigned just fix the cpu's nid. */ + /* + * For nodes not being reassigned just + * fix the cpu's nid and reverse pxm map + */ if (cpunid < numnodes) { - node_cpuid[cpu].nid = cpunid; + pxm = nid_to_pxm_map[i]; + pxm_to_nid_map[pxm] = + node_cpuid[cpu].nid = cpunid; continue; } @@ -126,6 +132,8 @@ } } + /* save old nid map so we can update the pxm */ + old_nid_map[cpu] = node_cpuid[cpu].nid; node_cpuid[cpu].nid = k; } } @@ -134,14 +142,19 @@ * Fixup temporary nid values for CPU-only nodes. */ for (cpu = 0; cpu < NR_CPUS; cpu++) - if (node_cpuid[cpu].nid == (numnodes + numnodes)) - node_cpuid[cpu].nid = nnode - 1; - else - for (i = 0; i < nnode; i++) - if (node_flip[i] == (node_cpuid[cpu].nid - numnodes)) { - node_cpuid[cpu].nid = i; - break; - } + if (node_cpuid[cpu].nid == (numnodes + numnodes)) { + pxm = nid_to_pxm_map[old_nid_map[cpu]]; + pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = nnode - 1; + } else { + for (i = 0; i < nnode; i++) { + if (node_flip[i] != (node_cpuid[cpu].nid - numnodes)) + continue; + + pxm = nid_to_pxm_map[old_nid_map[cpu]]; + pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = i; + break; + } + } /* * Fix numa_slit by compressing from larger @@ -492,14 +505,17 @@ */ void show_mem(void) { - int i, reserved = 0; - int shared = 0, cached = 0; + int i, total_reserved = 0; + int total_shared = 0, total_cached = 0; + unsigned long total_present = 0; pg_data_t *pgdat; printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { + unsigned long present = pgdat->node_present_pages; + int shared = 0, cached = 0, reserved = 0; printk("Node ID: %d\n", pgdat->node_id); for(i = 0; i < pgdat->node_spanned_pages; i++) { if (!ia64_pfn_valid(pgdat->node_start_pfn+i)) @@ -511,11 +527,19 @@ else if (page_count(pgdat->node_mem_map+i)) shared += page_count(pgdat->node_mem_map+i)-1; } - printk("\t%ld pages of RAM\n", pgdat->node_present_pages); + total_present += present; + total_reserved += reserved; + total_cached += cached; + total_shared += shared; + printk("\t%ld pages of RAM\n", present); printk("\t%d reserved pages\n", reserved); printk("\t%d pages shared\n", shared); printk("\t%d pages swap cached\n", cached); } + printk("%ld pages of RAM\n", total_present); + printk("%d reserved pages\n", total_reserved); + printk("%d pages shared\n", total_shared); + printk("%d pages swap cached\n", total_cached); printk("Total of %ld pages in page table cache\n", pgtable_cache_size); printk("%d free buffer pages\n", nr_free_buffer_pages()); } @@ -607,12 +631,10 @@ unsigned long max_dma; unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; - unsigned long max_gap, pfn_offset = 0; + unsigned long pfn_offset = 0; int node; max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - max_gap = 0; - efi_memmap_walk(find_largest_hole, &max_gap); /* so min() will work in count_node_pages */ for (node = 0; node < numnodes; node++) @@ -664,8 +686,8 @@ pfn_offset = mem_data[node].min_pfn; - free_area_init_node(node, NODE_DATA(node), - vmem_map + pfn_offset, zones_size, + NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset; + free_area_init_node(node, NODE_DATA(node), zones_size, pfn_offset, zholes_size); } diff -Nru a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c --- a/arch/ia64/mm/extable.c 2004-10-18 14:56:27 -07:00 +++ b/arch/ia64/mm/extable.c 2004-10-18 14:56:27 -07:00 @@ -77,7 +77,7 @@ else last = mid - 1; } - return 0; + return NULL; } void diff -Nru a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c --- a/arch/ia64/mm/fault.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/mm/fault.c 2004-10-18 14:57:04 -07:00 @@ -14,7 +14,6 @@ #include #include #include -#include extern void die (char *, struct pt_regs *, long); @@ -40,6 +39,7 @@ vma->vm_mm->total_vm += grow; if (vma->vm_flags & VM_LOCKED) vma->vm_mm->locked_vm += grow; + __vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow); return 0; } @@ -196,7 +196,7 @@ si.si_signo = signal; si.si_errno = 0; si.si_code = code; - si.si_addr = (void *) address; + si.si_addr = (void __user *) address; si.si_isr = isr; si.si_flags = __ISR_VALID; force_sig_info(signal, &si, current); diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/mm/init.c 2004-10-18 14:56:29 -07:00 @@ -67,9 +67,9 @@ if (pgtable_cache_size > (u64) high) { do { if (pgd_quicklist) - free_page((unsigned long)pgd_alloc_one_fast(0)); + free_page((unsigned long)pgd_alloc_one_fast(NULL)); if (pmd_quicklist) - free_page((unsigned long)pmd_alloc_one_fast(0, 0)); + free_page((unsigned long)pmd_alloc_one_fast(NULL, 0)); } while (pgtable_cache_size > (u64) low); } preempt_enable(); @@ -429,20 +429,22 @@ / sizeof(struct page)); if (map_start < map_end) - memmap_init_zone(map_start, (unsigned long) (map_end - map_start), + memmap_init_zone((unsigned long)(map_end - map_start), args->nid, args->zone, page_to_pfn(map_start)); return 0; } void -memmap_init (struct page *start, unsigned long size, int nid, - unsigned long zone, unsigned long start_pfn) +memmap_init (unsigned long size, int nid, unsigned long zone, + unsigned long start_pfn) { if (!vmem_map) - memmap_init_zone(start, size, nid, zone, start_pfn); + memmap_init_zone(size, nid, zone, start_pfn); else { + struct page *start; struct memmap_init_callback_data args; + start = pfn_to_page(start_pfn); args.start = start; args.end = start + size; args.nid = nid; @@ -458,9 +460,9 @@ char byte; struct page *pg = pfn_to_page(pfn); - return (__get_user(byte, (char *) pg) == 0) + return (__get_user(byte, (char __user *) pg) == 0) && ((((u64)pg & PAGE_MASK) == (((u64)(pg + 1) - 1) & PAGE_MASK)) - || (__get_user(byte, (char *) (pg + 1) - 1) == 0)); + || (__get_user(byte, (char __user *) (pg + 1) - 1) == 0)); } EXPORT_SYMBOL(ia64_pfn_valid); @@ -585,6 +587,6 @@ setup_gate(); #ifdef CONFIG_IA32_SUPPORT - ia32_boot_gdt_init(); + ia32_mem_init(); #endif } diff -Nru a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c --- a/arch/ia64/mm/tlb.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ia64/mm/tlb.c 2004-10-18 14:56:48 -07:00 @@ -176,7 +176,7 @@ if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) != 0) { printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with status=%ld;" "defaulting to architected purge page-sizes.\n", status); - purge.mask = 0x115557000; + purge.mask = 0x115557000UL; } purge.max_bits = ia64_fls(purge.mask); diff -Nru a/arch/ia64/oprofile/Kconfig b/arch/ia64/oprofile/Kconfig --- a/arch/ia64/oprofile/Kconfig 2004-10-18 14:56:33 -07:00 +++ b/arch/ia64/oprofile/Kconfig 2004-10-18 14:56:33 -07:00 @@ -16,6 +16,10 @@ whole system, include the kernel, kernel modules, libraries, and applications. + Due to firmware bugs, you may need to use the "nohalt" boot + option if you're using OProfile with the hardware performance + counters. + If unsure, say N. endmenu diff -Nru a/arch/ia64/oprofile/Makefile b/arch/ia64/oprofile/Makefile --- a/arch/ia64/oprofile/Makefile 2004-10-18 14:56:19 -07:00 +++ b/arch/ia64/oprofile/Makefile 2004-10-18 14:56:19 -07:00 @@ -7,3 +7,4 @@ timer_int.o ) oprofile-y := $(DRIVER_OBJS) init.o +oprofile-$(CONFIG_PERFMON) += perfmon.o diff -Nru a/arch/ia64/oprofile/init.c b/arch/ia64/oprofile/init.c --- a/arch/ia64/oprofile/init.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ia64/oprofile/init.c 2004-10-18 14:55:55 -07:00 @@ -12,14 +12,21 @@ #include #include -extern void timer_init(struct oprofile_operations ** ops); +extern int perfmon_init(struct oprofile_operations ** ops); +extern void perfmon_exit(void); int __init oprofile_arch_init(struct oprofile_operations ** ops) { +#ifdef CONFIG_PERFMON + return perfmon_init(ops); +#endif return -ENODEV; } void oprofile_arch_exit(void) { +#ifdef CONFIG_PERFMON + perfmon_exit(); +#endif } diff -Nru a/arch/ia64/oprofile/perfmon.c b/arch/ia64/oprofile/perfmon.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/oprofile/perfmon.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,105 @@ +/** + * @file perfmon.c + * + * @remark Copyright 2003 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include +#include +#include +#include + +static int allow_ints; + +static int +perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, + struct pt_regs *regs, unsigned long stamp) +{ + int cpu = smp_processor_id(); + unsigned long eip = instruction_pointer(regs); + int event = arg->pmd_eventid; + + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; + + /* the owner of the oprofile event buffer may have exited + * without perfmon being shutdown (e.g. SIGSEGV) + */ + if (allow_ints) + oprofile_add_sample(eip, !user_mode(regs), event, cpu); + return 0; +} + + +static int perfmon_start(void) +{ + allow_ints = 1; + return 0; +} + + +static void perfmon_stop(void) +{ + allow_ints = 0; +} + + +#define OPROFILE_FMT_UUID { \ + 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c } + +static pfm_buffer_fmt_t oprofile_fmt = { + .fmt_name = "oprofile_format", + .fmt_uuid = OPROFILE_FMT_UUID, + .fmt_handler = perfmon_handler, +}; + + +static char * get_cpu_type(void) +{ + __u8 family = local_cpu_data->family; + + switch (family) { + case 0x07: + return "ia64/itanium"; + case 0x1f: + return "ia64/itanium2"; + default: + return "ia64/ia64"; + } +} + + +/* all the ops are handled via userspace for IA64 perfmon */ +static struct oprofile_operations perfmon_ops = { + .start = perfmon_start, + .stop = perfmon_stop, +}; + +static int using_perfmon; + +int perfmon_init(struct oprofile_operations ** ops) +{ + int ret = pfm_register_buffer_fmt(&oprofile_fmt); + if (ret) + return -ENODEV; + + perfmon_ops.cpu_type = get_cpu_type(); + *ops = &perfmon_ops; + using_perfmon = 1; + printk(KERN_INFO "oprofile: using perfmon.\n"); + return 0; +} + + +void perfmon_exit(void) +{ + if (!using_perfmon) + return; + + pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); +} diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c --- a/arch/ia64/pci/pci.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ia64/pci/pci.c 2004-10-18 14:56:29 -07:00 @@ -46,8 +46,6 @@ #define DBG(x...) #endif -struct pci_fixup pcibios_fixups[1]; - /* * Low-level SAL-based PCI configuration access functions. Note that SAL * calls are already serialized (via sal_lock), so we don't need another @@ -138,6 +136,11 @@ printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); +#ifdef CONFIG_NUMA +extern acpi_status acpi_map_iosapic (acpi_handle, u32, void*, void**); + + acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL); +#endif /* * PCI IRQ routing is set up by pci_enable_device(), but we * also do it here in case there are still broken drivers that @@ -332,7 +335,7 @@ struct pci_window *window; int i, j; int limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? \ - PCI_ROM_RESOURCE : PCI_NUM_RESOURCES; + PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; for (i = 0; i < limit; i++) { if (!dev->resource[i].start) diff -Nru a/arch/ia64/sn/fakeprom/Makefile b/arch/ia64/sn/fakeprom/Makefile --- a/arch/ia64/sn/fakeprom/Makefile 2004-10-18 14:57:03 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,29 +0,0 @@ -# arch/ia64/sn/fakeprom/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. -# -# Medusa fake PROM support -# - -EXTRA_TARGETS := fpromasm.o main.o fw-emu.o fpmem.o klgraph_init.o \ - fprom vmlinux.sym - -OBJS := $(obj)/fpromasm.o $(obj)/main.o $(obj)/fw-emu.o $(obj)/fpmem.o \ - $(obj)/klgraph_init.o - -LDFLAGS_fprom = -static -T - -.PHONY: fprom - -fprom: $(obj)/fprom - -$(obj)/fprom: $(src)/fprom.lds $(OBJS) arch/ia64/lib/lib.a FORCE - $(call if_changed,ld) - -$(obj)/vmlinux.sym: $(src)/make_textsym System.map - $(src)/make_textsym vmlinux > vmlinux.sym - $(call cmd,cptotop) diff -Nru a/arch/ia64/sn/fakeprom/README b/arch/ia64/sn/fakeprom/README --- a/arch/ia64/sn/fakeprom/README 2004-10-18 14:57:05 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,93 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - -This directory contains the files required to build -the fake PROM image that is currently being used to -boot IA64 kernels running under the SGI Medusa kernel. - -The FPROM currently provides the following functions: - - - PAL emulation for all PAL calls we've made so far. - - SAL emulation for all SAL calls we've made so far. - - EFI emulation for all EFI calls we've made so far. - - builds the "ia64_bootparam" structure that is - passed to the kernel from SAL. This structure - shows the cpu & memory configurations. - - supports medusa boottime options for changing - the number of cpus present - - supports medusa boottime options for changing - the memory configuration. - - - -At some point, this fake PROM will be replaced by the -real PROM. - - - - -To build a fake PROM, cd to this directory & type: - - make - -This will (or should) build a fake PROM named "fprom". - - - - -Use this fprom image when booting the Medusa simulator. The -control file used to boot Medusa should include the -following lines: - - load fprom - load vmlinux - sr pc 0x100000 - sr g 9
#(currently 0xe000000000520000) - -NOTE: There is a script "runsim" in this directory that can be used to -simplify setting up an environment for running under Medusa. - - - - -The following parameters may be passed to the fake PROM to -control the PAL/SAL/EFI parameters passed to the kernel: - - GR[8] = # of cpus - GR[9] = address of primary entry point into the kernel - GR[20] = memory configuration for node 0 - GR[21] = memory configuration for node 1 - GR[22] = memory configuration for node 2 - GR[23] = memory configuration for node 3 - - -Registers GR[20] - GR[23] contain information to specify the -amount of memory present on nodes 0-3. - - - if nothing is specified (all registers are 0), the configuration - defaults to 8 MB on node 0. - - - a mem config entry for node N is passed in GR[20+N] - - - a mem config entry consists of 8 hex digits. Each digit gives the - amount of physical memory available on the node starting at - 1GB*, where dn is the digit number. The amount of memory - is 8MB*2**. (If = 0, the memory size is 0). - - SN1 doesn't support dimms this small but small memory systems - boot faster on Medusa. - - - -An example helps a lot. The following specifies that node 0 has -physical memory 0 to 8MB and 1GB to 1GB+32MB, and that node 1 has -64MB starting at address 0 of the node which is 8GB. - - gr[20] = 0x21 # 0 to 8MB, 1GB to 1GB+32MB - gr[21] = 0x4 # 8GB to 8GB+64MB - diff -Nru a/arch/ia64/sn/fakeprom/fpmem.c b/arch/ia64/sn/fakeprom/fpmem.c --- a/arch/ia64/sn/fakeprom/fpmem.c 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,252 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - - - -/* - * FPROM EFI memory descriptor build routines - * - * - Routines to build the EFI memory descriptor map - * - Should also be usable by the SGI prom to convert - * klconfig to efi_memmap - */ - -#include -#include -#include "fpmem.h" - -/* - * args points to a layout in memory like this - * - * 32 bit 32 bit - * - * numnodes numcpus - * - * 16 bit 16 bit 32 bit - * nasid0 cpuconf membankdesc0 - * nasid1 cpuconf membankdesc1 - * . - * . - * . - * . - * . - */ - -sn_memmap_t *sn_memmap ; -sn_config_t *sn_config ; - -/* - * There is a hole in the node 0 address space. Dont put it - * in the memory map - */ -#define NODE0_HOLE_SIZE (20*MB) -#define NODE0_HOLE_END (4UL*GB) - -#define MB (1024*1024) -#define GB (1024*MB) -#define KERNEL_SIZE (4*MB) -#define PROMRESERVED_SIZE (1*MB) - -#ifdef SGI_SN2 -#define PHYS_ADDRESS(_n, _x) (((long)_n<<38) | (long)_x | 0x3000000000UL) -#define MD_BANK_SHFT 34 -#endif - -/* - * For SN, this may not take an arg and gets the numnodes from - * the prom variable or by traversing klcfg or promcfg - */ -int -GetNumNodes(void) -{ - return sn_config->nodes; -} - -int -GetNumCpus(void) -{ - return sn_config->cpus; -} - -/* For SN, get the index th nasid */ - -int -GetNasid(int index) -{ - return sn_memmap[index].nasid ; -} - -node_memmap_t -GetMemBankInfo(int index) -{ - return sn_memmap[index].node_memmap ; -} - -int -IsCpuPresent(int cnode, int cpu) -{ - return sn_memmap[cnode].cpuconfig & (1UL<type = type; - md->phys_addr = paddr; - md->virt_addr = 0; - md->num_pages = numbytes >> 12; - md->attribute = attr; -} - -int -build_efi_memmap(void *md, int mdsize) -{ - int numnodes = GetNumNodes() ; - int cnode,bank ; - int nasid ; - node_memmap_t membank_info ; - int bsize; - int count = 0 ; - long paddr, hole, numbytes; - - - for (cnode=0;cnode 128*1024*1024) { - numbytes -= 1000; - } - - /* - * Check for the node 0 hole. Since banks cant - * span the hole, we only need to check if the end of - * the range is the end of the hole. - */ - if (paddr+numbytes == NODE0_HOLE_END) - numbytes -= NODE0_HOLE_SIZE; - /* - * UGLY hack - we must skip overr the kernel and - * PROM runtime services but we dont exactly where it is. - * So lets just reserve: - * node 0 - * 0-1MB for PAL - * 1-4MB for SAL - * node 1-N - * 0-1 for SAL - */ - if (bank == 0) { - if (cnode == 0) { - hole = 2*1024*1024; - build_mem_desc(md, EFI_PAL_CODE, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB); - numbytes -= hole; - paddr += hole; - count++ ; - md += mdsize; - hole = 1*1024*1024; - build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, hole, EFI_MEMORY_UC); - numbytes -= hole; - paddr += hole; - count++ ; - md += mdsize; - hole = 1*1024*1024; - build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB); - numbytes -= hole; - paddr += hole; - count++ ; - md += mdsize; - } else { - hole = 2*1024*1024; - build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB); - numbytes -= hole; - paddr += hole; - count++ ; - md += mdsize; - hole = 2*1024*1024; - build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_UC); - numbytes -= hole; - paddr += hole; - count++ ; - md += mdsize; - } - } - build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, numbytes, EFI_MEMORY_WB|EFI_MEMORY_WB); - - md += mdsize ; - count++ ; - } - } - } - return count ; -} - -void -build_init(unsigned long args) -{ - sn_config = (sn_config_t *) (args); - sn_memmap = (sn_memmap_t *)(args + 8) ; /* SN equiv for this is */ - /* init to klconfig start */ -} diff -Nru a/arch/ia64/sn/fakeprom/fpmem.h b/arch/ia64/sn/fakeprom/fpmem.h --- a/arch/ia64/sn/fakeprom/fpmem.h 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,76 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include - -/* - * Structure of the mem config of the node as a SN MI reg - * Medusa supports this reg config. - * - * BankSize nibble to bank size mapping - * - * 1 - 64 MB - * 2 - 128 MB - * 3 - 256 MB - * 4 - 512 MB - * 5 - 1024 MB (1GB) - */ - -#define MBSHIFT 20 - -#ifdef SGI_SN2 -typedef struct node_memmap_s -{ - unsigned int b0size :3, /* 0-2 bank 0 size */ - b0dou :1, /* 3 bank 0 is 2-sided */ - ena0 :1, /* 4 bank 0 enabled */ - r0 :3, /* 5-7 reserved */ - b1size :3, /* 8-10 bank 1 size */ - b1dou :1, /* 11 bank 1 is 2-sided */ - ena1 :1, /* 12 bank 1 enabled */ - r1 :3, /* 13-15 reserved */ - b2size :3, /* 16-18 bank 2 size */ - b2dou :1, /* 19 bank 1 is 2-sided */ - ena2 :1, /* 20 bank 2 enabled */ - r2 :3, /* 21-23 reserved */ - b3size :3, /* 24-26 bank 3 size */ - b3dou :1, /* 27 bank 3 is 2-sided */ - ena3 :1, /* 28 bank 3 enabled */ - r3 :3; /* 29-31 reserved */ -} node_memmap_t ; - -#define SN2_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */ -#define BankPresent(bsize) (bsize<6) -#define BankSizeBytes(bsize) (BankPresent(bsize) ? 1UL<<((bsize)+SN2_BANK_SIZE_SHIFT) : 0) -#define MD_BANKS_PER_NODE 4 -#define MD_BANKSIZE (1UL << 34) -#endif - -typedef struct sn_memmap_s -{ - short nasid ; - short cpuconfig; - node_memmap_t node_memmap ; -} sn_memmap_t ; - -typedef struct sn_config_s -{ - int cpus; - int nodes; - sn_memmap_t memmap[1]; /* start of array */ -} sn_config_t; - - - -extern void build_init(unsigned long); -extern int build_efi_memmap(void *, int); -extern int GetNumNodes(void); -extern int GetNumCpus(void); -extern int IsCpuPresent(int, int); -extern int GetNasid(int); diff -Nru a/arch/ia64/sn/fakeprom/fprom.lds b/arch/ia64/sn/fakeprom/fprom.lds --- a/arch/ia64/sn/fakeprom/fprom.lds 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,103 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - -OUTPUT_FORMAT("elf64-ia64-little") -OUTPUT_ARCH(ia64) -ENTRY(_start) -SECTIONS -{ - v = 0x0000000000000000 ; /* this symbol is here to make debugging with kdb easier... */ - - . = (0x000000000000000 + 0x100000) ; - - _text = .; - .text : AT(ADDR(.text) - 0x0000000000000000 ) - { - *(__ivt_section) - /* these are not really text pages, but the zero page needs to be in a fixed location: */ - *(__special_page_section) - __start_gate_section = .; - *(__gate_section) - __stop_gate_section = .; - *(.text) - } - - /* Global data */ - _data = .; - - .rodata : AT(ADDR(.rodata) - 0x0000000000000000 ) - { *(.rodata) *(.rodata.*) } - .opd : AT(ADDR(.opd) - 0x0000000000000000 ) - { *(.opd) } - .data : AT(ADDR(.data) - 0x0000000000000000 ) - { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } - - __gp = ALIGN (8) + 0x200000; - - .got : AT(ADDR(.got) - 0x0000000000000000 ) - { *(.got.plt) *(.got) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : AT(ADDR(.sdata) - 0x0000000000000000 ) - { *(.sdata) } - _edata = .; - _bss = .; - .sbss : AT(ADDR(.sbss) - 0x0000000000000000 ) - { *(.sbss) *(.scommon) } - .bss : AT(ADDR(.bss) - 0x0000000000000000 ) - { *(.bss) *(COMMON) } - . = ALIGN(64 / 8); - _end = .; - - /* Sections to be discarded */ - /DISCARD/ : { - *(.text.exit) - *(.data.exit) - } - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* These must appear regardless of . */ - /* Discard them for now since Intel SoftSDV cannot handle them. - .comment 0 : { *(.comment) } - .note 0 : { *(.note) } - */ - /DISCARD/ : { *(.comment) } - /DISCARD/ : { *(.note) } -} diff -Nru a/arch/ia64/sn/fakeprom/fpromasm.S b/arch/ia64/sn/fakeprom/fpromasm.S --- a/arch/ia64/sn/fakeprom/fpromasm.S 2004-10-18 14:56:27 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,395 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * (Code copied from or=ther files) - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - - - -#define __ASSEMBLY__ 1 -#include -#include -#include -#include - -/* - * This file contains additional set up code that is needed to get going on - * Medusa. This code should disappear once real hw is available. - * - * On entry to this routine, the following register values are assumed: - * - * gr[8] - BSP cpu - * pr[9] - kernel entry address - * pr[10] - cpu number on the node - * - * NOTE: - * This FPROM may be loaded/executed at an address different from the - * address that it was linked at. The FPROM is linked to run on node 0 - * at address 0x100000. If the code in loaded into another node, it - * must be loaded at offset 0x100000 of the node. In addition, the - * FPROM does the following things: - * - determine the base address of the node it is loaded on - * - add the node base to _gp. - * - add the node base to all addresses derived from "movl" - * instructions. (I couldnt get GPREL addressing to work) - * (maybe newer versions of the tools will support this) - * - scan the .got section and add the node base to all - * pointers in this section. - * - add the node base to all physical addresses in the - * SAL/PAL/EFI table built by the C code. (This is done - * in the C code - not here) - * - add the node base to the TLB entries for vmlinux - */ - -#define KERNEL_BASE 0xe000000000000000 -#define BOOT_PARAM_ADDR 0x40000 - - -/* - * ar.k0 gets set to IOPB_PA value, on 460gx chipset it should - * be 0x00000ffffc000000, but on snia we use the (inverse swizzled) - * IOSPEC_BASE value - */ -#ifdef SGI_SN2 -#define IOPB_PA 0xc000000fcc000000 -#endif - -#define RR_RID 8 - - - -// ==================================================================================== - .text - .align 16 - .global _start - .proc _start -_start: - -// Setup psr and rse for system init - mov psr.l = r0;; - srlz.d;; - invala - mov ar.rsc = r0;; - loadrs - ;; - -// Isolate node number we are running on. - mov r6 = ip;; -#ifdef SGI_SN2 - shr r5 = r6,38 // r5 = node number - dep r6 = 0,r6,0,36 // r6 = base memory address of node - -#endif - - -// Set & relocate gp. - movl r1= __gp;; // Add base memory address - or r1 = r1,r6 // Relocate to boot node - -// Lets figure out who we are & put it in the LID register. -#ifdef SGI_SN2 -// On SN2, we (currently) pass the cpu number in r10 at boot - and r25=3,r10;; - movl r16=0x8000008110000400 // Allow IPIs - mov r17=-1;; - st8 [r16]=r17 - movl r16=0x8000008110060580;; // SHUB_ID - ld8 r27=[r16];; - extr.u r27=r27,32,11;; - shl r26=r25,28;; // Align local cpu# to lid.eid - shl r27=r27,16;; // Align NASID to lid.id - or r26=r26,r27;; // build the LID -#else -// The BR_PI_SELF_CPU_NUM register gives us a value of 0-3. -// This identifies the cpu on the node. -// Merge the cpu number with the NASID to generate the LID. - movl r24=0x80000a0001000020;; // BR_PI_SELF_CPU_NUM - ld8 r25=[r24] // Fetch PI_SELF - movl r27=0x80000a0001600000;; // Fetch REVID to get local NASID - ld8 r27=[r27];; - extr.u r27=r27,32,8;; - shl r26=r25,16;; // Align local cpu# to lid.eid - shl r27=r27,24;; // Align NASID to lid.id - or r26=r26,r27;; // build the LID -#endif - mov cr.lid=r26 // Now put in in the LID register - - movl r2=FPSR_DEFAULT;; - mov ar.fpsr=r2 - movl sp = bootstacke-16;; - or sp = sp,r6 // Relocate to boot node - -// Save the NASID that we are loaded on. - movl r2=base_nasid;; // Save base_nasid for C code - or r2 = r2,r6;; // Relocate to boot node - st8 [r2]=r5 // Uncond st8 - same on all cpus - -// Save the kernel entry address. It is passed in r9 on one of -// the cpus. - movl r2=bsp_entry_pc - cmp.ne p6,p0=r9,r0;; - or r2 = r2,r6;; // Relocate to boot node -(p6) st8 [r2]=r9 // Uncond st8 - same on all cpus - - -// The following can ONLY be done by 1 cpu. Lets set a lock - the -// cpu that gets it does the initilization. The rest just spin waiting -// til initilization is complete. - movl r22 = initlock;; - or r22 = r22,r6 // Relocate to boot node - mov r23 = 1;; - xchg8 r23 = [r22],r23;; - cmp.eq p6,p0 = 0,r23 -(p6) br.cond.spnt.few init -1: ld4 r23 = [r22];; - cmp.eq p6,p0 = 1,r23 -(p6) br.cond.sptk 1b - br initx - -// Add base address of node memory to each pointer in the .got section. -init: movl r16 = _GLOBAL_OFFSET_TABLE_;; - or r16 = r16,r6;; // Relocate to boot node -1: ld8 r17 = [r16];; - cmp.eq p6,p7=0,r17 -(p6) br.cond.sptk.few.clr 2f;; - or r17 = r17,r6;; // Relocate to boot node - st8 [r16] = r17,8 - br 1b -2: - mov r23 = 2;; // All done, release the spinning cpus - st4 [r22] = r23 -initx: - -// -// I/O-port space base address: -// - movl r2 = IOPB_PA;; - mov ar.k0 = r2 - - -// Now call main & pass it the current LID value. - alloc r2=ar.pfs,0,0,2,0 - mov r32=r26 - mov r33=r8;; - br.call.sptk.few rp=fmain - -// Initialize Region Registers -// - mov r10 = r0 - mov r2 = (13<<2) - mov r3 = r0;; -1: cmp4.gtu p6,p7 = 7, r3 - dep r10 = r3, r10, 61, 3 - dep r2 = r3, r2, RR_RID, 4;; -(p7) dep r2 = 0, r2, 0, 1;; -(p6) dep r2 = -1, r2, 0, 1;; - mov rr[r10] = r2 - add r3 = 1, r3;; - srlz.d;; - cmp4.gtu p6,p0 = 8, r3 -(p6) br.cond.sptk.few.clr 1b - -// -// Return value indicates if we are the BSP or AP. -// 1 = BSP, 0 = AP - mov cr.tpr=r0;; - cmp.eq p6,p0=r8,r0 -(p6) br.cond.spnt slave - -// -// Go to kernel C startup routines -// Need to do a "rfi" in order set "it" and "ed" bits in the PSR. -// This is the only way to set them. - - movl r28=BOOT_PARAM_ADDR - movl r2=bsp_entry_pc;; - or r28 = r28,r6;; // Relocate to boot node - or r2 = r2,r6;; // Relocate to boot node - ld8 r2=[r2];; - or r2=r2,r6;; - dep r2=0,r2,61,3;; // convert to phys mode - -// -// Turn on address translation, interrupt collection, psr.ed, protection key. -// Interrupts (PSR.i) are still off here. -// - - movl r3 = ( IA64_PSR_BN | \ - IA64_PSR_AC | \ - IA64_PSR_DB | \ - IA64_PSR_DA | \ - IA64_PSR_IC \ - ) - ;; - mov cr.ipsr = r3 - -// -// Go to kernel C startup routines -// Need to do a "rfi" in order set "it" and "ed" bits in the PSR. -// This is the only way to set them. - - mov r8=r28;; - bsw.1 ;; - mov r28=r8;; - bsw.0 ;; - mov cr.iip = r2 - srlz.d;; - rfi;; - - .endp _start - - - -// Slave processors come here to spin til they get an interrupt. Then they launch themselves to -// the place ap_entry points. No initialization is necessary - the kernel makes no -// assumptions about state on this entry. -// Note: should verify that the interrupt we got was really the ap_wakeup -// interrupt but this should not be an issue on medusa -slave: - nop.i 0x8beef // Medusa - put cpu to sleep til interrupt occurs - mov r8=cr.irr0;; // Check for interrupt pending. - cmp.eq p6,p0=r8,r0 -(p6) br.cond.sptk slave;; - - mov r8=cr.ivr;; // Got one. Must read ivr to accept it - srlz.d;; - mov cr.eoi=r0;; // must write eoi to clear - movl r8=ap_entry;; // now jump to kernel entry - or r8 = r8,r6;; // Relocate to boot node - ld8 r9=[r8],8;; - ld8 r1=[r8] - mov b0=r9;; - br b0 - -// Here is the kernel stack used for the fake PROM - .bss - .align 16384 -bootstack: - .skip 16384 -bootstacke: -initlock: - data4 - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////// -// This code emulates the PAL. Only essential interfaces are emulated. - - - .text - .global pal_emulator - .proc pal_emulator -pal_emulator: - mov r8=-1 - - mov r9=256 - ;; - cmp.gtu p6,p7=r9,r28 /* r28 <= 255? */ -(p6) br.cond.sptk.few static - ;; - mov r9=512 - ;; - cmp.gtu p6,p7=r9,r28 -(p6) br.cond.sptk.few stacked - ;; - -static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ -(p7) br.cond.sptk.few 1f - movl r8=0 /* status = 0 */ - movl r9=0x100000000 /* tc.base */ - movl r10=0x0000000200000003 /* count[0], count[1] */ - movl r11=0x1000000000002000 /* stride[0], stride[1] */ - ;; - -1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ -(p7) br.cond.sptk.few 1f - movl r8=0 /* status = 0 */ - movl r9 =0x100000064 /* proc_ratio (1/100) */ - movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ - movl r11=0x10000000a /* itc_ratio<<32 (1/100) */ - ;; - -1: cmp.eq p6,p7=8,r28 /* PAL_VM_SUMMARY */ -(p7) br.cond.sptk.few 1f - movl r8=0 -#ifdef SGI_SN2 - movl r9=0x0203083001151065 - movl r10=0x183f -#endif - movl r11=0 - ;; - -1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ -(p7) br.cond.sptk.few 1f - movl r8=0 - movl r9=0x60 - movl r10=0x0 - movl r11=0 - ;; - -1: cmp.eq p6,p7=15,r28 /* PAL_PERF_MON_INFO */ -(p7) br.cond.sptk.few 1f - movl r8=0 - movl r9=0x08122004 - movl r10=0x0 - movl r11=0 - mov r2=ar.lc - mov r3=16;; - mov ar.lc=r3 - mov r3=r29;; -5: st8 [r3]=r0,8 - br.cloop.sptk.few 5b;; - mov ar.lc=r2 - mov r3=r29 - movl r2=0x1fff;; /* PMC regs */ - st8 [r3]=r2 - add r3=32,r3 - movl r2=0x3ffff;; /* PMD regs */ - st8 [r3]=r2 - add r3=32,r3 - movl r2=0xf0;; /* cycle regs */ - st8 [r3]=r2 - add r3=32,r3 - movl r2=0x10;; /* retired regs */ - st8 [r3]=r2 - ;; - -1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ -(p7) br.cond.sptk.few 1f - movl r8=0 /* status = 0 */ - movl r9=96 /* num phys stacked */ - movl r10=0 /* hints */ - movl r11=0 - ;; - -1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */ -(p7) br.cond.sptk.few 1f - mov r9=ar.lc - movl r8=524288 /* flush 512k million cache lines (16MB) */ - ;; - mov ar.lc=r8 - movl r8=0xe000000000000000 - ;; -.loop: fc r8 - add r8=32,r8 - br.cloop.sptk.few .loop - sync.i - ;; - srlz.i - ;; - mov ar.lc=r9 - mov r8=r0 -1: br.cond.sptk.few rp - -stacked: - br.ret.sptk.few rp - - .endp pal_emulator - diff -Nru a/arch/ia64/sn/fakeprom/fw-emu.c b/arch/ia64/sn/fakeprom/fw-emu.c --- a/arch/ia64/sn/fakeprom/fw-emu.c 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,775 +0,0 @@ -/* - * PAL & SAL emulation. - * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang - * - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef SGI_SN2 -#include -#include -#endif -#include -#include "fpmem.h" - -#define RSDP_NAME "RSDP" -#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */ -#define APIC_SIG "APIC" /* Multiple APIC Description Table */ -#define DSDT_SIG "DSDT" /* Differentiated System Description Table */ -#define FADT_SIG "FACP" /* Fixed ACPI Description Table */ -#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */ -#define PSDT_SIG "PSDT" /* Persistent System Description Table */ -#define RSDT_SIG "RSDT" /* Root System Description Table */ -#define XSDT_SIG "XSDT" /* Extended System Description Table */ -#define SSDT_SIG "SSDT" /* Secondary System Description Table */ -#define SBST_SIG "SBST" /* Smart Battery Specification Table */ -#define SPIC_SIG "SPIC" /* IOSAPIC table */ -#define SRAT_SIG "SRAT" /* SRAT table */ -#define SLIT_SIG "SLIT" /* SLIT table */ -#define BOOT_SIG "BOOT" /* Boot table */ -#define ACPI_SRAT_REVISION 1 -#define ACPI_SLIT_REVISION 1 - -#define OEMID "SGI" -#ifdef SGI_SN2 -#define PRODUCT "SN2" -#define PROXIMITY_DOMAIN(nasid) (((nasid)>>1) & 255) -#endif - -#define MB (1024*1024UL) -#define GB (MB*1024UL) -#define BOOT_PARAM_ADDR 0x40000 -#define MAX(i,j) ((i) > (j) ? (i) : (j)) -#define MIN(i,j) ((i) < (j) ? (i) : (j)) -#define ALIGN8(p) (((long)(p) +7) & ~7) - -#define FPROM_BUG() do {while (1);} while (0) -#define MAX_SN_NODES 128 -#define MAX_LSAPICS 512 -#define MAX_CPUS 512 -#define MAX_CPUS_NODE 4 -#define CPUS_PER_NODE 4 -#define CPUS_PER_FSB 2 -#define CPUS_PER_FSB_MASK (CPUS_PER_FSB-1) - -#define NUM_EFI_DESCS 2 - -#define RSDP_CHECKSUM_LENGTH 20 - -typedef union ia64_nasid_va { - struct { -#if defined(SGI_SN2) - unsigned long off : 36; /* intra-region offset */ - unsigned long attr : 2; - unsigned long nasid : 11; /* NASID */ - unsigned long off2 : 12; /* fill */ - unsigned long reg : 3; /* region number */ -#endif - } f; - unsigned long l; - void *p; -} ia64_nasid_va; - -typedef struct { - unsigned long pc; - unsigned long gp; -} func_ptr_t; - -#define IS_VIRTUAL_MODE() ({struct ia64_psr psr; asm("mov %0=psr" : "=r"(psr)); psr.dt;}) -#define ADDR_OF(p) (IS_VIRTUAL_MODE() ? ((void*)((long)(p)+PAGE_OFFSET)) : ((void*) (p))) - -#if defined(SGI_SN2) -#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.f.attr = 3; _v.l;}) -#endif - -/* - * The following variables are passed thru registersfrom the configuration file and - * are set via the _start function. - */ -long base_nasid; -long num_cpus; -long bsp_entry_pc=0; -long num_nodes; -long app_entry_pc; -int bsp_lid; -func_ptr_t ap_entry; - - -extern void pal_emulator(void); -static efi_runtime_services_t *efi_runtime_p; -static char fw_mem[( sizeof(efi_system_table_t) - + sizeof(efi_runtime_services_t) - + NUM_EFI_DESCS*sizeof(efi_config_table_t) - + sizeof(struct ia64_sal_systab) - + sizeof(struct ia64_sal_desc_entry_point) - + sizeof(struct ia64_sal_desc_ap_wakeup) - + sizeof(struct acpi20_table_rsdp) - + sizeof(struct acpi_table_xsdt) - + sizeof(struct acpi_table_slit) - + MAX_SN_NODES*MAX_SN_NODES+8 - + sizeof(struct acpi_table_madt) - + 16*MAX_CPUS - + (1+8*MAX_SN_NODES)*(sizeof(efi_memory_desc_t)) - + sizeof(struct acpi_table_srat) - + MAX_CPUS*sizeof(struct acpi_table_processor_affinity) - + MAX_SN_NODES*sizeof(struct acpi_table_memory_affinity) - + sizeof(ia64_sal_desc_ptc_t) + - + MAX_SN_NODES*sizeof(ia64_sal_ptc_domain_info_t) + - + MAX_CPUS*sizeof(ia64_sal_ptc_domain_proc_entry_t) + - + 1024)] __attribute__ ((aligned (8))); - - -static efi_status_t -efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) -{ - if (tm) { - memset(tm, 0, sizeof(*tm)); - tm->year = 2000; - tm->month = 2; - tm->day = 13; - tm->hour = 10; - tm->minute = 11; - tm->second = 12; - } - - if (tc) { - tc->resolution = 10; - tc->accuracy = 12; - tc->sets_to_zero = 1; - } - - return EFI_SUCCESS; -} - -static void -efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data) -{ - while(1); /* Is there a pseudo-op to stop medusa */ -} - -static efi_status_t -efi_success (void) -{ - return EFI_SUCCESS; -} - -static efi_status_t -efi_unimplemented (void) -{ - return EFI_UNSUPPORTED; -} - -#ifdef SGI_SN2 - -#undef cpu_physical_id -#define cpu_physical_id(cpuid) ((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff) - -void -fprom_send_cpei(void) { - long *p, val; - long physid; - long nasid, slice; - - physid = cpu_physical_id(0); - nasid = cpu_physical_id_to_nasid(physid); - slice = cpu_physical_id_to_slice(physid); - - p = (long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT); - val = (1UL<pc = in2; - fp->gp = in3; - } else if (in1 == SAL_VECTOR_OS_MCA || in1 == SAL_VECTOR_OS_INIT) { - } else { - status = -1; - } - ; - } else if (index == SAL_GET_STATE_INFO) { - ; - } else if (index == SAL_GET_STATE_INFO_SIZE) { - r9 = 10000; - ; - } else if (index == SAL_CLEAR_STATE_INFO) { - ; - } else if (index == SAL_MC_RENDEZ) { - ; - } else if (index == SAL_MC_SET_PARAMS) { - ; - } else if (index == SAL_CACHE_FLUSH) { - ; - } else if (index == SAL_CACHE_INIT) { - ; - } else if (index == SAL_UPDATE_PAL) { - ; -#ifdef SGI_SN2 - } else if (index == SN_SAL_LOG_CE) { -#ifdef ajmtestcpei - fprom_send_cpei(); -#else /* ajmtestcpei */ - ; -#endif /* ajmtestcpei */ -#endif - } else if (index == SN_SAL_PROBE) { - r9 = 0UL; - if (in2 == 4) { - r9 = *(unsigned *)in1; - if (r9 == -1) { - status = 1; - } - } else if (in2 == 2) { - r9 = *(unsigned short *)in1; - if (r9 == -1) { - status = 1; - } - } else if (in2 == 1) { - r9 = *(unsigned char *)in1; - if (r9 == -1) { - status = 1; - } - } else if (in2 == 8) { - r9 = *(unsigned long *)in1; - if (r9 == -1) { - status = 1; - } - } else { - status = 2; - } - } else if (index == SN_SAL_GET_KLCONFIG_ADDR) { - r9 = 0x30000; - } else if (index == SN_SAL_CONSOLE_PUTC) { - status = -1; - } else if (index == SN_SAL_CONSOLE_GETC) { - status = -1; - } else if (index == SN_SAL_CONSOLE_POLL) { - status = -1; - } else if (index == SN_SAL_SYSCTL_IOBRICK_MODULE_GET) { - status = -1; - } else { - status = -1; - } - - asm volatile ("" :: "r"(r9), "r"(r10), "r"(r11)); - return ((struct sal_ret_values) {status, r9, r10, r11}); -} - - -/* - * This is here to work around a bug in egcs-1.1.1b that causes the - * compiler to crash (seems like a bug in the new alias analysis code. - */ -void * -id (long addr) -{ - return (void *) addr; -} - - -/* - * Fix the addresses in a function pointer by adding base node address - * to pc & gp. - */ -void -fix_function_pointer(void *fp) -{ - func_ptr_t *_fp; - - _fp = fp; - _fp->pc = __fwtab_pa(base_nasid, _fp->pc); - _fp->gp = __fwtab_pa(base_nasid, _fp->gp); -} - -void -fix_virt_function_pointer(void **fptr) -{ - func_ptr_t *fp; - long *p; - - p = (long*)fptr; - fp = *fptr; - fp->pc = fp->pc | PAGE_OFFSET; - fp->gp = fp->gp | PAGE_OFFSET; - *p |= PAGE_OFFSET; -} - - -int -efi_set_virtual_address_map(void) -{ - efi_runtime_services_t *runtime; - - runtime = efi_runtime_p; - fix_virt_function_pointer((void**)&runtime->get_time); - fix_virt_function_pointer((void**)&runtime->set_time); - fix_virt_function_pointer((void**)&runtime->get_wakeup_time); - fix_virt_function_pointer((void**)&runtime->set_wakeup_time); - fix_virt_function_pointer((void**)&runtime->set_virtual_address_map); - fix_virt_function_pointer((void**)&runtime->get_variable); - fix_virt_function_pointer((void**)&runtime->get_next_variable); - fix_virt_function_pointer((void**)&runtime->set_variable); - fix_virt_function_pointer((void**)&runtime->get_next_high_mono_count); - fix_virt_function_pointer((void**)&runtime->reset_system); - return EFI_SUCCESS; -} - -void -acpi_table_initx(struct acpi_table_header *p, char *sig, int siglen, int revision, int oem_revision) -{ - memcpy(p->signature, sig, siglen); - memcpy(p->oem_id, OEMID, 6); - memcpy(p->oem_table_id, sig, 4); - memcpy(p->oem_table_id+4, PRODUCT, 4); - p->revision = revision; - p->oem_revision = (revision<<16) + oem_revision; - memcpy(p->asl_compiler_id, "FPRM", 4); - p->asl_compiler_revision = 1; -} - -void -acpi_checksum(struct acpi_table_header *p, int length) -{ - u8 *cp, *cpe, checksum; - - p->checksum = 0; - p->length = length; - checksum = 0; - for (cp=(u8*)p, cpe=cp+p->length; cpchecksum = -checksum; -} - -void -acpi_checksum_rsdp20(struct acpi20_table_rsdp *p, int length) -{ - u8 *cp, *cpe, checksum; - - p->checksum = 0; - p->ext_checksum = 0; - p->length = length; - checksum = 0; - for (cp=(u8*)p, cpe=cp+20; cpchecksum = -checksum; - - checksum = 0; - for (cp=(u8*)p, cpe=cp+length; cpext_checksum = -checksum; -} - -int -nasid_present(int nasid) -{ - int cnode; - for (cnode=0; cnode= 1024) - arglen = 1023; - memcpy(cmd_line, args, arglen); - } else { - arglen = 0; - } - cmd_line[arglen] = '\0'; - /* - * For now, just bring up bash. - * If you want to execute all the startup scripts, delete the "init=..". - * You can also edit this line to pass other arguments to the kernel. - * Note: disable kernel text replication. - */ - strcpy(cmd_line, "init=/bin/bash console=ttyS0"); - - memset(efi_systab, 0, sizeof(efi_systab)); - efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; - efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION; - efi_systab->hdr.headersize = sizeof(efi_systab->hdr); - efi_systab->fw_vendor = __fwtab_pa(base_nasid, vendor); - efi_systab->fw_revision = 1; - efi_systab->runtime = __fwtab_pa(base_nasid, efi_runtime); - efi_systab->nr_tables = 2; - efi_systab->tables = __fwtab_pa(base_nasid, efi_tables); - memcpy(vendor, "S\0i\0l\0i\0c\0o\0n\0-\0G\0r\0a\0p\0h\0i\0c\0s\0\0", 40); - - efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE; - efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION; - efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr); - efi_runtime->get_time = __fwtab_pa(base_nasid, &efi_get_time); - efi_runtime->set_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->get_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_set_virtual_address_map); - efi_runtime->get_variable = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->get_next_variable = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_variable = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->get_next_high_mono_count = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->reset_system = __fwtab_pa(base_nasid, &efi_reset_system); - - efi_tables->guid = SAL_SYSTEM_TABLE_GUID; - efi_tables->table = __fwtab_pa(base_nasid, sal_systab); - efi_tables++; - efi_tables->guid = ACPI_20_TABLE_GUID; - efi_tables->table = __fwtab_pa(base_nasid, acpi20_rsdp); - efi_tables++; - - fix_function_pointer(&efi_unimplemented); - fix_function_pointer(&efi_get_time); - fix_function_pointer(&efi_success); - fix_function_pointer(&efi_reset_system); - fix_function_pointer(&efi_set_virtual_address_map); - - - /* fill in the ACPI20 system table - has a pointer to the ACPI table header */ - memcpy(acpi20_rsdp->signature, "RSD PTR ", 8); - acpi20_rsdp->xsdt_address = (u64)__fwtab_pa(base_nasid, acpi_xsdt); - acpi20_rsdp->revision = 2; - acpi_checksum_rsdp20(acpi20_rsdp, sizeof(struct acpi20_table_rsdp)); - - /* Set up the XSDT table - contains pointers to the other ACPI tables */ - acpi_table_initx(&acpi_xsdt->header, XSDT_SIG, 4, 1, 1); - acpi_xsdt->entry[0] = __fwtab_pa(base_nasid, acpi_madt); - acpi_xsdt->entry[1] = __fwtab_pa(base_nasid, acpi_slit); - acpi_xsdt->entry[2] = __fwtab_pa(base_nasid, acpi_srat); - acpi_checksum(&acpi_xsdt->header, sizeof(struct acpi_table_xsdt) + 16); - - /* Set up the APIC table */ - acpi_table_initx(&acpi_madt->header, APIC_SIG, 4, 1, 1); - lsapic20 = (struct acpi_table_lsapic*) (acpi_madt + 1); - for (cnode=0; cnodeheader.type = ACPI_MADT_LSAPIC; - lsapic20->header.length = sizeof(struct acpi_table_lsapic); - lsapic20->acpi_id = cnode*4+cpu; - lsapic20->flags.enabled = 1; -#if defined(SGI_SN2) - lsapic20->eid = nasid&0xffff; - lsapic20->id = (cpu<<4) | (nasid>>16); -#endif - lsapic20 = (struct acpi_table_lsapic*) ((long)lsapic20+sizeof(struct acpi_table_lsapic)); - } - } - acpi_checksum(&acpi_madt->header, (char*)lsapic20 - (char*)acpi_madt); - - /* Set up the SRAT table */ - acpi_table_initx(&acpi_srat->header, SRAT_SIG, 4, ACPI_SRAT_REVISION, 1); - ptr = acpi_srat+1; - for (cnode=0; cnodeheader.type = ACPI_SRAT_MEMORY_AFFINITY; - srat_memory_affinity->header.length = sizeof(struct acpi_table_memory_affinity); - srat_memory_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); - srat_memory_affinity->base_addr_lo = 0; - srat_memory_affinity->length_lo = 0; -#if defined(SGI_SN2) - srat_memory_affinity->base_addr_hi = (nasid<<6) | (3<<4); - srat_memory_affinity->length_hi = (MD_BANKSIZE*MD_BANKS_PER_NODE)>>32; -#endif - srat_memory_affinity->memory_type = ACPI_ADDRESS_RANGE_MEMORY; - srat_memory_affinity->flags.enabled = 1; - } - - for (cnode=0; cnodeheader.type = ACPI_SRAT_PROCESSOR_AFFINITY; - srat_cpu_affinity->header.length = sizeof(struct acpi_table_processor_affinity); - srat_cpu_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); - srat_cpu_affinity->flags.enabled = 1; -#if defined(SGI_SN2) - srat_cpu_affinity->lsapic_eid = nasid&0xffff; - srat_cpu_affinity->apic_id = (cpu<<4) | (nasid>>16); -#endif - } - } - acpi_checksum(&acpi_srat->header, (char*)ptr - (char*)acpi_srat); - - - /* Set up the SLIT table */ - acpi_table_initx(&acpi_slit->header, SLIT_SIG, 4, ACPI_SLIT_REVISION, 1); - acpi_slit->localities = PROXIMITY_DOMAIN(max_nasid)+1; - cp=acpi_slit->entry; - memset(cp, 255, acpi_slit->localities*acpi_slit->localities); - - for (i=0; i<=max_nasid; i++) - for (j=0; j<=max_nasid; j++) - if (nasid_present(i) && nasid_present(j)) - *(cp+PROXIMITY_DOMAIN(i)*acpi_slit->localities+PROXIMITY_DOMAIN(j)) = 10 + MIN(254, 5*abs(i-j)); - - cp = acpi_slit->entry + acpi_slit->localities*acpi_slit->localities; - acpi_checksum(&acpi_slit->header, cp - (char*)acpi_slit); - - - /* fill in the SAL system table: */ - memcpy(sal_systab->signature, "SST_", 4); - sal_systab->size = sizeof(*sal_systab); - sal_systab->sal_rev_minor = 1; - sal_systab->sal_rev_major = 0; - sal_systab->entry_count = 3; - sal_systab->sal_b_rev_major = 0x1; /* set the SN SAL rev to */ - sal_systab->sal_b_rev_minor = 0x0; /* 1.00 */ - - strcpy(sal_systab->oem_id, "SGI"); - strcpy(sal_systab->product_id, "SN2"); - - /* fill in an entry point: */ - sal_ed->type = SAL_DESC_ENTRY_POINT; - sal_ed->pal_proc = __fwtab_pa(base_nasid, pal_desc[0]); - sal_ed->sal_proc = __fwtab_pa(base_nasid, sal_desc[0]); - sal_ed->gp = __fwtab_pa(base_nasid, sal_desc[1]); - - /* kludge the PTC domain info */ - sal_ptc->type = SAL_DESC_PTC; - sal_ptc->num_domains = 0; - sal_ptc->domain_info = __fwtab_pa(base_nasid, sal_ptcdi); - cpus_found = 0; - last_domain = -1; - sal_ptcdi--; - for (cnode=0; cnodenum_domains++; - sal_ptcdi++; - sal_ptcdi->proc_count = 0; - sal_ptcdi->proc_list = __fwtab_pa(base_nasid, sal_ptclid); - last_domain = domain; - } - sal_ptcdi->proc_count++; - sal_ptclid->id = nasid; - sal_ptclid->eid = cpu; - sal_ptclid++; - cpus_found++; - } - } - } - - if (cpus_found != num_cpus) - FPROM_BUG(); - - /* Make the AP WAKEUP entry */ - sal_apwake->type = SAL_DESC_AP_WAKEUP; - sal_apwake->mechanism = IA64_SAL_AP_EXTERNAL_INT; - sal_apwake->vector = 18; - - for (checksum=0, cp=(char*)sal_systab; cp < (char *)efi_memmap; ++cp) - checksum += *cp; - sal_systab->checksum = -checksum; - - /* If the checksum is correct, the kernel tries to use the - * table. We dont build enough table & the kernel aborts. - * Note that the PROM hasd thhhe same problem!! - */ - - md = &efi_memmap[0]; - num_memmd = build_efi_memmap((void *)md, mdsize) ; - - bp = (struct ia64_boot_param*) __fwtab_pa(base_nasid, BOOT_PARAM_ADDR); - bp->efi_systab = __fwtab_pa(base_nasid, &fw_mem); - bp->efi_memmap = __fwtab_pa(base_nasid, efi_memmap); - bp->efi_memmap_size = num_memmd*mdsize; - bp->efi_memdesc_size = mdsize; - bp->efi_memdesc_version = 0x101; - bp->command_line = __fwtab_pa(base_nasid, cmd_line); - bp->console_info.num_cols = 80; - bp->console_info.num_rows = 25; - bp->console_info.orig_x = 0; - bp->console_info.orig_y = 24; - bp->fpswa = 0; - - /* - * Now pick the BSP & store it LID value in - * a global variable. Note if BSP is greater than last cpu, - * pick the last cpu. - */ - for (cnode=0; cnode 0) - continue; - return; - } - } -} diff -Nru a/arch/ia64/sn/fakeprom/klgraph_init.c b/arch/ia64/sn/fakeprom/klgraph_init.c --- a/arch/ia64/sn/fakeprom/klgraph_init.c 2004-10-18 14:55:53 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,205 +0,0 @@ -/* $Id: klgraph_init.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - - -/* - * This is a temporary file that statically initializes the expected - * initial klgraph information that is normally provided by prom. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SYNERGY_WIDGET ((char *)0xc0000e0000000000) -#define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) -#define HUBREG ((char *)0xc0000a0001e00000) -#define WIDGET0 ((char *)0xc0000a0000000000) -#define WIDGET4 ((char *)0xc0000a0000000004) - -#define SYNERGY_WIDGET ((char *)0xc0000e0000000000) -#define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) -#define HUBREG ((char *)0xc0000a0001e00000) -#define WIDGET0 ((char *)0xc0000a0000000000) - -#define convert(a,b,c) temp = (u64 *)a; *temp = b; temp++; *temp = c -void -klgraph_init(void) -{ - - u64 *temp; - /* - * Initialize some hub/xbow registers that allows access to - * Xbridge etc. These are normally done in PROM. - */ - - /* Write IOERR clear to clear the CRAZY bit in the status */ - *(volatile uint64_t *)0xc000000801c001f8 = (uint64_t)0xffffffff; - - /* set widget control register...setting bedrock widget id to a */ - *(volatile uint64_t *)0xc000000801c00020 = (uint64_t)0x801a; - - /* set io outbound widget access...allow all */ - *(volatile uint64_t *)0xc000000801c00110 = (uint64_t)0xff01; - - /* set io inbound widget access...allow all */ - *(volatile uint64_t *)0xc000000801c00118 = (uint64_t)0xff01; - - /* set io crb timeout to max */ - *(volatile uint64_t *)0xc000000801c003c0 = (uint64_t)0xffffff; - *(volatile uint64_t *)0xc000000801c003c0 = (uint64_t)0xffffff; - - /* set local block io permission...allow all */ -// [LB] *(volatile uint64_t *)0xc000000801e04010 = (uint64_t)0xfffffffffffffff; - - /* clear any errors */ - /* clear_ii_error(); medusa should have cleared these */ - - /* set default read response buffers in bridge */ -// [PI] *(volatile u32 *)0xc00000080f000280L = 0xba98; -// [PI] *(volatile u32 *)0xc00000080f000288L = 0xba98; - - /* - * klconfig entries initialization - mankato - */ - convert(0xe000003000030000, 0x00000000beedbabe, 0x0000004800000000); - convert(0xe000003000030010, 0x0003007000000018, 0x800002000f820178); - convert(0xe000003000030020, 0x80000a000f024000, 0x800002000f800000); - convert(0xe000003000030030, 0x0300fafa00012580, 0x00000000040f0000); - convert(0xe000003000030040, 0x0000000000000000, 0x0003097000030070); - convert(0xe000003000030050, 0x00030970000303b0, 0x0003181000033f70); - convert(0xe000003000030060, 0x0003d51000037570, 0x0000000000038330); - convert(0xe000003000030070, 0x0203110100030140, 0x0001000000000101); - convert(0xe000003000030080, 0x0900000000000000, 0x000000004e465e67); - convert(0xe000003000030090, 0x0003097000000000, 0x00030b1000030a40); - convert(0xe0000030000300a0, 0x00030cb000030be0, 0x000315a0000314d0); - convert(0xe0000030000300b0, 0x0003174000031670, 0x0000000000000000); - convert(0xe000003000030100, 0x000000000000001a, 0x3350490000000000); - convert(0xe000003000030110, 0x0000000000000037, 0x0000000000000000); - convert(0xe000003000030140, 0x0002420100030210, 0x0001000000000101); - convert(0xe000003000030150, 0x0100000000000000, 0xffffffffffffffff); - convert(0xe000003000030160, 0x00030d8000000000, 0x0000000000030e50); - convert(0xe0000030000301c0, 0x0000000000000000, 0x0000000000030070); - convert(0xe0000030000301d0, 0x0000000000000025, 0x424f490000000000); - convert(0xe0000030000301e0, 0x000000004b434952, 0x0000000000000000); - convert(0xe000003000030210, 0x00027101000302e0, 0x00010000000e4101); - convert(0xe000003000030220, 0x0200000000000000, 0xffffffffffffffff); - convert(0xe000003000030230, 0x00030f2000000000, 0x0000000000030ff0); - convert(0xe000003000030290, 0x0000000000000000, 0x0000000000030140); - convert(0xe0000030000302a0, 0x0000000000000026, 0x7262490000000000); - convert(0xe0000030000302b0, 0x00000000006b6369, 0x0000000000000000); - convert(0xe0000030000302e0, 0x0002710100000000, 0x00010000000f3101); - convert(0xe0000030000302f0, 0x0500000000000000, 0xffffffffffffffff); - convert(0xe000003000030300, 0x000310c000000000, 0x0003126000031190); - convert(0xe000003000030310, 0x0003140000031330, 0x0000000000000000); - convert(0xe000003000030360, 0x0000000000000000, 0x0000000000030140); - convert(0xe000003000030370, 0x0000000000000029, 0x7262490000000000); - convert(0xe000003000030380, 0x00000000006b6369, 0x0000000000000000); - convert(0xe000003000030970, 0x0000000002010102, 0x0000000000000000); - convert(0xe000003000030980, 0x000000004e465e67, 0xffffffff00000000); - /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */ - convert(0xe0000030000309a0, 0x0000000000037570, 0xffffffff00000000); - convert(0xe0000030000309b0, 0x0000000000030070, 0x0000000000000000); - convert(0xe0000030000309c0, 0x000000000003f420, 0x0000000000000000); - convert(0xe000003000030a40, 0x0000000002010125, 0x0000000000000000); - convert(0xe000003000030a50, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000030a70, 0x0000000000037b78, 0x0000000000000000); - convert(0xe000003000030b10, 0x0000000002010125, 0x0000000000000000); - convert(0xe000003000030b20, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000030b40, 0x0000000000037d30, 0x0000000000000001); - convert(0xe000003000030be0, 0x00000000ff010203, 0x0000000000000000); - convert(0xe000003000030bf0, 0xffffffffffffffff, 0xffffffff000000ff); - convert(0xe000003000030c10, 0x0000000000037ee8, 0x0100010000000200); - convert(0xe000003000030cb0, 0x00000000ff310111, 0x0000000000000000); - convert(0xe000003000030cc0, 0xffffffffffffffff, 0x0000000000000000); - convert(0xe000003000030d80, 0x0000000002010104, 0x0000000000000000); - convert(0xe000003000030d90, 0xffffffffffffffff, 0x00000000000000ff); - convert(0xe000003000030db0, 0x0000000000037f18, 0x0000000000000000); - convert(0xe000003000030dc0, 0x0000000000000000, 0x0003007000060000); - convert(0xe000003000030de0, 0x0000000000000000, 0x0003021000050000); - convert(0xe000003000030df0, 0x000302e000050000, 0x0000000000000000); - convert(0xe000003000030e30, 0x0000000000000000, 0x000000000000000a); - convert(0xe000003000030e50, 0x00000000ff00011a, 0x0000000000000000); - convert(0xe000003000030e60, 0xffffffffffffffff, 0x0000000000000000); - convert(0xe000003000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e); - convert(0xe000003000030e90, 0x000000000000bc6e, 0x0000000000000000); - convert(0xe000003000030f20, 0x0000000002010205, 0x00000000d0020000); - convert(0xe000003000030f30, 0xffffffffffffffff, 0x0000000e0000000e); - convert(0xe000003000030f40, 0x000000000000000e, 0x0000000000000000); - convert(0xe000003000030f50, 0x0000000000038010, 0x00000000000007ff); - convert(0xe000003000030f70, 0x0000000000000000, 0x0000000022001077); - convert(0xe000003000030fa0, 0x0000000000000000, 0x000000000003f4a8); - convert(0xe000003000030ff0, 0x0000000000310120, 0x0000000000000000); - convert(0xe000003000031000, 0xffffffffffffffff, 0xffffffff00000002); - convert(0xe000003000031010, 0x000000000000000e, 0x0000000000000000); - convert(0xe000003000031020, 0x0000000000038088, 0x0000000000000000); - convert(0xe0000030000310c0, 0x0000000002010205, 0x00000000d0020000); - convert(0xe0000030000310d0, 0xffffffffffffffff, 0x0000000f0000000f); - convert(0xe0000030000310e0, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000310f0, 0x00000000000380b8, 0x00000000000007ff); - convert(0xe000003000031120, 0x0000000022001077, 0x00000000000310a9); - convert(0xe000003000031130, 0x00000000580211c1, 0x000000008009104c); - convert(0xe000003000031140, 0x0000000000000000, 0x000000000003f4c0); - convert(0xe000003000031190, 0x0000000000310120, 0x0000000000000000); - convert(0xe0000030000311a0, 0xffffffffffffffff, 0xffffffff00000003); - convert(0xe0000030000311b0, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000311c0, 0x0000000000038130, 0x0000000000000000); - convert(0xe000003000031260, 0x0000000000110106, 0x0000000000000000); - convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); - convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); - convert(0xe000003000031280, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000312a0, 0x00000000ff110013, 0x0000000000000000); - convert(0xe0000030000312b0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe0000030000312c0, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000312e0, 0x0000000000110012, 0x0000000000000000); - convert(0xe0000030000312f0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000031300, 0x000000000000000f, 0x0000000000000000); - convert(0xe000003000031310, 0x0000000000038160, 0x0000000000000000); - convert(0xe000003000031330, 0x00000000ff310122, 0x0000000000000000); - convert(0xe000003000031340, 0xffffffffffffffff, 0xffffffff00000005); - convert(0xe000003000031350, 0x000000000000000f, 0x0000000000000000); - convert(0xe000003000031360, 0x0000000000038190, 0x0000000000000000); - convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); - convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); - convert(0xe000003000031410, 0xffffffffffffffff, 0xffffffff00000006); - convert(0xe000003000031420, 0x000000000000000f, 0x0000000000000000); - convert(0xe000003000031430, 0x00000000000381c0, 0x0000000000000000); - convert(0xe0000030000314d0, 0x00000000ff010201, 0x0000000000000000); - convert(0xe0000030000314e0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000031500, 0x00000000000381f0, 0x000030430000ffff); - convert(0xe000003000031510, 0x000000000000ffff, 0x0000000000000000); - convert(0xe0000030000315a0, 0x00000020ff000201, 0x0000000000000000); - convert(0xe0000030000315b0, 0xffffffffffffffff, 0xffffffff00000001); - convert(0xe0000030000315d0, 0x0000000000038240, 0x00003f3f0000ffff); - convert(0xe0000030000315e0, 0x000000000000ffff, 0x0000000000000000); - convert(0xe000003000031670, 0x00000000ff010201, 0x0000000000000000); - convert(0xe000003000031680, 0xffffffffffffffff, 0x0000000100000002); - convert(0xe0000030000316a0, 0x0000000000038290, 0x000030430000ffff); - convert(0xe0000030000316b0, 0x000000000000ffff, 0x0000000000000000); - convert(0xe000003000031740, 0x00000020ff000201, 0x0000000000000000); - convert(0xe000003000031750, 0xffffffffffffffff, 0x0000000500000003); - convert(0xe000003000031770, 0x00000000000382e0, 0x00003f3f0000ffff); - convert(0xe000003000031780, 0x000000000000ffff, 0x0000000000000000); -} diff -Nru a/arch/ia64/sn/fakeprom/main.c b/arch/ia64/sn/fakeprom/main.c --- a/arch/ia64/sn/fakeprom/main.c 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,109 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - - - -#include -#include -#include - -extern void klgraph_init(void); -void bedrock_init(int); -void synergy_init(int, int); -void sys_fw_init (const char *args, int arglen, int bsp); - -volatile int bootmaster=0; /* Used to pick bootmaster */ -volatile int nasidmaster[128]={0}; /* Used to pick node/synergy masters */ -int init_done=0; -extern int bsp_lid; - -#define get_bit(b,p) (((*p)>>(b))&1) - -int -fmain(int lid, int bsp) { - int syn, nasid, cpu; - - /* - * First lets figure out who we are. This is done from the - * LID passed to us. - */ - nasid = (lid>>16)&0xfff; - cpu = (lid>>28)&3; - syn = 0; - - /* - * Now pick a nasid master to initialize Bedrock registers. - */ - if (test_and_set_bit(8, &nasidmaster[nasid]) == 0) { - bedrock_init(nasid); - test_and_set_bit(9, &nasidmaster[nasid]); - } else - while (get_bit(9, &nasidmaster[nasid]) == 0); - - - /* - * Now pick a BSP & finish init. - */ - if (test_and_set_bit(0, &bootmaster) == 0) { - sys_fw_init(0, 0, bsp); - test_and_set_bit(1, &bootmaster); - } else - while (get_bit(1, &bootmaster) == 0); - - return (lid == bsp_lid); -} - - -void -bedrock_init(int nasid) -{ - nasid = nasid; /* to quiet gcc */ -#if 0 - /* - * Undef if you need fprom to generate a 1 node klgraph - * information .. only works for 1 node for nasid 0. - */ - klgraph_init(); -#endif -} - - -void -synergy_init(int nasid, int syn) -{ - long *base; - long off; - - /* - * Enable all FSB flashed interrupts. - * I'd really like defines for this...... - */ - base = (long*)0x80000e0000000000LL; /* base of synergy regs */ - for (off = 0x2a0; off < 0x2e0; off+=8) /* offset for VEC_MASK_{0-3}_A/B */ - *(base+off/8) = -1LL; - - /* - * Set the NASID in the FSB_CONFIG register. - */ - base = (long*)0x80000e0000000450LL; - *base = (long)((nasid<<16)|(syn<<9)); -} - - -/* Why isnt there a bcopy/memcpy in lib64.a */ - -void* -memcpy(void * dest, const void *src, size_t count) -{ - char *s, *se, *d; - - for(d=dest, s=(char*)src, se=s+count; s []] - If no input file is specified, it defaults to vmlinux. - If no output file name is specified, it defaults to "textsym". -END -exit 1 -} - -err () { - echo "ERROR - $*" >&2 - exit 1 -} - - -OPTS="H" -while getopts "$OPTS" c ; do - case $c in - H) help;; - \?) help;; - esac - -done -shift `expr $OPTIND - 1` - -#OBJDUMP=/usr/bin/ia64-linux-objdump -LINUX=${1:-vmlinux} -TEXTSYM=${2:-${LINUX}.sym} -TMPSYM=${2:-${LINUX}.sym.tmp} -trap "/bin/rm -f $TMPSYM" 0 - -[ -f $VMLINUX ] || help - -$OBJDUMP -t $LINUX | egrep -v '__ks' | sort > $TMPSYM -SN1=`egrep "dig_setup|Synergy_da_indr" $TMPSYM|wc -l` - -# Dataprefix and textprefix correspond to the VGLOBAL_BASE and VPERNODE_BASE. -# Eventually, these values should be: -# dataprefix ffffffff -# textprefix fffffffe -# but right now they're still changing, so make them dynamic. -dataprefix=`awk ' / \.data / { print substr($1, 0, 8) ; exit ; }' $TMPSYM` -textprefix=`awk ' / \.text / { print substr($1, 0, 8) ; exit ; }' $TMPSYM` - -# pipe everything thru sort -echo "TEXTSYM V1.0" -(cat < 0) { - n = n*16 + (index("0123456789abcdef", substr(s,1,1)) - 1) - s = substr(s,2) - } - printf "GLOBAL | %s | DATA | %s | %d\n", $1, $NF, n - } - } - if($NF == "_end") - exit - -} -' $TMPSYM ) | egrep -v " __device| __vendor" | awk -v sn1="$SN1" ' -/GLOBAL/ { - print $0 - if (sn1 != 0) { - /* 32 bits of sn1 physical addrs, */ - print substr($0,1,9) "04" substr($0,20,16) "Phy_" substr($0,36) - } else { - /* 38 bits of sn2 physical addrs, need addr space bits */ - print substr($0,1,9) "3004" substr($0,20,16) "Phy_" substr($0,36) - } - -} ' | sort -k3 - -N=`wc -l $TEXTSYM|awk '{print $1}'` -echo "Generated TEXTSYM file" >&2 -echo " $LINUX --> $TEXTSYM" >&2 -echo " Found $N symbols" >&2 diff -Nru a/arch/ia64/sn/fakeprom/runsim b/arch/ia64/sn/fakeprom/runsim --- a/arch/ia64/sn/fakeprom/runsim 2004-10-18 14:56:27 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,387 +0,0 @@ -#!/bin/sh - -# Script for running PROMs and LINUX kernwls on medusa. -# Type "sim -H" for instructions. - -MEDUSA=${MEDUSA:-/home/rickc/official_medusa/medusa} - -# ------------------ err ----------------------- -err() { - echo "ERROR - $1" - exit 1 -} - -# ---------------- help ---------------------- -help() { -cat <] <-p> | <-k> [] - -p Create PROM control file & links - -k Create LINUX control file & links - -c Control file name [Default: cf] - Path to directory that contains the linux or PROM files. - The directory can be any of the following: - (linux simulations) - worktree - worktree/linux - any directory with vmlinux, vmlinux.sym & fprom files - (prom simulations) - worktree - worktree/stand/arcs/IP37prom/dev - any directory with fw.bin & fw.sim files - - Simulations: - sim [-X ] [-o ] [-M] [] - -c Control file name [Default: cf] - -M Pipe output thru fmtmedusa - -o Output filename (copy of all commands/output) [Default: simout] - -X Specifies number of instructions to execute [Default: 0] - (Used only in auto test mode - not described here) - -Examples: - sim -p # create control file (cf) & links for prom simulations - sim -k # create control file (cf) & links for linux simulations - sim -p -c cfprom # create a prom control file (cfprom) only. No links are made. - - sim # run medusa using previously created links & - # control file (cf). -END -exit 1 -} - -# ----------------------- create control file header -------------------- -create_cf_header() { -cat <>$CF -# -# Template for a control file for running linux kernels under medusa. -# You probably want to make mods here but this is a good starting point. -# - -# Preferences -setenv cpu_stepping A -setenv exceptionPrint off -setenv interrupt_messages off -setenv lastPCsize 100000 -setenv low_power_mode on -setenv partialIntelChipSet on -setenv printIntelMessages off -setenv prom_write_action halt -setenv prom_write_messages on -setenv step_quantum 100 -setenv swizzling on -setenv tsconsole on -setenv uart_echo on -symbols on - -# IDE disk params -setenv diskCylinders 611 -setenv bootDrive C -setenv diskHeads 16 -setenv diskPath idedisk -setenv diskPresent 1 -setenv diskSpt 63 - -# Hardware config -setenv coherency_type nasid -setenv cpu_cache_type default -setenv synergy_cache_type syn_cac_64m_8w -setenv l4_uc_snoop off - -# Numalink config -setenv route_enable on -setenv network_type router # Select [xbar|router] -setenv network_warning 0xff - -END -} - - -# ------------------ create control file entries for linux simulations ------------- -create_cf_linux() { -cat <>$CF -# Kernel specific options -setenv calias_size 0 -setenv mca_on_memory_failure off -setenv LOADPC 0x00100000 # FPROM load address/entry point (8 digits!) -setenv symbol_table vmlinux.sym -load fprom -load vmlinux - -# Useful breakpoints to always have set. Add more if desired. -break 0xe000000000505e00 all # dispatch_to_fault_handler -break panic all # stop on panic -break die_if_kernel all # may as well stop - -END -} - -# ------------------ create control file entries for prom simulations --------------- -create_cf_prom() { - SYM2="" - ADDR="0x80000000ff800000" - [ "$EMBEDDED_LINUX" != "0" ] || SYM2="setenv symbol_table2 vmlinux.sym" - [ "$SIZE" = "8MB" ] || ADDR="0x80000000ffc00000" - cat <>$CF -# PROM specific options -setenv mca_on_memory_failure on -setenv LOADPC 0x80000000ffffffb0 -setenv promFile fw.bin -setenv promAddr $ADDR -setenv symbol_table fw.sym -$SYM2 - -# Useful breakpoints to always have set. Add more if desired. -break ivt_gexx all -break ivt_brk all -break PROM_Panic_Spin all -break PROM_Panic all -break PROM_C_Panic all -break fled_die all -break ResetNow all -break zzzbkpt all - -END -} - - -# ------------------ create control file entries for memory configuration ------------- -create_cf_memory() { -cat <>$CF -# CPU/Memory map format: -# setenv nodeN_memory_config 0xBSBSBSBS -# B=banksize (0=unused, 1=64M, 2=128M, .., 5-1G, c=8M, d=16M, e=32M) -# S=bank enable (0=both disable, 3=both enable, 2=bank1 enable, 1=bank0 enable) -# rightmost digits are for bank 0, the lowest address. -# setenv nodeN_nasid -# specifies the NASID for the node. This is used ONLY if booting the kernel. -# On PROM configurations, set to 0 - PROM will change it later. -# setenv nodeN_cpu_config -# Set bit number N to 1 to enable cpu N. Ex., a value of 5 enables cpu 0 & 2. -# -# Repeat the above 3 commands for each node. -# -# For kernel, default to 32MB. Although this is not a valid hardware configuration, -# it runs faster on medusa. For PROM, 64MB is smallest allowed value. - -setenv node0_cpu_config 0x1 # Enable only cpu 0 on the node -END - -if [ $LINUX -eq 1 ] ; then -cat <>$CF -setenv node0_nasid 0 # cnode 0 has NASID 0 -setenv node0_memory_config 0xe1 # 32MB -END -else -cat <>$CF -setenv node0_memory_config 0x31 # 256MB -END -fi -} - -# -------------------- set links to linux files ------------------------- -set_linux_links() { - if [ -d $D/linux/arch ] ; then - D=$D/linux - elif [ -d $D/arch -o -e vmlinux.sym -o -e $D/vmlinux ] ; then - D=$D - else - err "cant determine directory for linux binaries" - fi - rm -rf vmlinux vmlinux.sym fprom - ln -s $D/vmlinux vmlinux - if [ -f $D/vmlinux.sym ] ; then - ln -s $D/vmlinux.sym vmlinux.sym - elif [ -f $D/System.map ] ; then - ln -s $D/System.map vmlinux.sym - fi - if [ -d $D/arch ] ; then - ln -s $D/arch/ia64/sn/fprom/fprom fprom - else - ln -s $D/fprom fprom - fi - echo " .. Created links to linux files" -} - -# -------------------- set links to prom files ------------------------- -set_prom_links() { - if [ -d $D/stand ] ; then - D=$D/stand/arcs/IP37prom/dev - elif [ -d $D/sal ] ; then - D=$D - else - err "cant determine directory for PROM binaries" - fi - SETUP="/tmp/tmp.$$" - rm -r -f $SETUP - sed 's/export/setenv/' < $D/../../../../.setup | sed 's/=/ /' >$SETUP - egrep -q '^ *setenv *PROMSIZE *8MB|^ *export' $SETUP - if [ $? -eq 0 ] ; then - SIZE="8MB" - else - SIZE="4MB" - fi - grep -q '^ *setenv *LAUNCH_VMLINUX' $SETUP - EMBEDDED_LINUX=$? - PRODUCT=`grep '^ *setenv *PRODUCT' $SETUP | cut -d" " -f3` - rm -f fw.bin fw.map fw.sym vmlinux vmlinux.sym fprom $SETUP - SDIR="${PRODUCT}${SIZE}.O" - BIN="${PRODUCT}ip37prom${SIZE}" - ln -s $D/$SDIR/$BIN.bin fw.bin - ln -s $D/$SDIR/$BIN.map fw.map - ln -s $D/$SDIR/$BIN.sym fw.sym - echo " .. Created links to $SIZE prom files" - if [ $EMBEDDED_LINUX -eq 0 ] ; then - ln -s $D/linux/vmlinux vmlinux - ln -s $D/linux/vmlinux.sym vmlinux.sym - if [ -d linux/arch ] ; then - ln -s $D/linux/arch/ia64/sn/fprom/fprom fprom - else - ln -s $D/linux/fprom fprom - fi - echo " .. Created links to embedded linux files in prom tree" - fi -} - -# --------------- start of shell script -------------------------------- -OUT="simout" -FMTMED=0 -STEPCNT=0 -PROM=0 -LINUX=0 -NCF="cf" -while getopts "HMX:c:o:pk" c ; do - case ${c} in - H) help;; - M) FMTMED=1;; - X) STEPCNT=${OPTARG};; - c) NCF=${OPTARG};; - k) PROM=0;LINUX=1;; - p) PROM=1;LINUX=0;; - o) OUT=${OPTARG};; - \?) exit 1;; - esac -done -shift `expr ${OPTIND} - 1` - -# Check if command is for creating control file and/or links to images. -if [ $PROM -eq 1 -o $LINUX -eq 1 ] ; then - CF=$NCF - [ ! -f $CF ] || err "wont overwrite an existing control file ($CF)" - if [ $# -gt 0 ] ; then - D=$1 - [ -d $D ] || err "cannot find directory $D" - [ $PROM -eq 0 ] || set_prom_links - [ $LINUX -eq 0 ] || set_linux_links - fi - create_cf_header - [ $PROM -eq 0 ] || create_cf_prom - [ $LINUX -eq 0 ] || create_cf_linux - [ ! -f ../idedisk ] || ln -s ../idedisk . - create_cf_memory - echo " .. Basic control file created (in $CF). You might want to edit" - echo " this file (at least, look at it)." - exit 0 -fi - -# Verify that the control file exists -CF=${1:-$NCF} -[ -f $CF ] || err "No control file exists. For help, type: $0 -H" - -# Build the .cf files from the user control file. The .cf file is -# identical except that the actual start & load addresses are inserted -# into the file. In addition, the FPROM commands for configuring memory -# and LIDs are generated. - -rm -f .cf .cf1 .cf2 -awk ' -function strtonum(n) { - if (substr(n,1,2) != "0x") - return int(n) - n = substr(n,3) - r=0 - while (length(n) > 0) { - r = r*16+(index("0123456789abcdef", substr(n,1,1))-1) - n = substr(n,2) - } - return r - } -/^#/ {next} -/^$/ {next} -/^setenv *LOADPC/ {loadpc = $3; next} -/^setenv *node.._cpu_config/ {n=int(substr($2,5,2)); cpuconf[n] = strtonum($3); print; next} -/^setenv *node.._memory_config/ {n=int(substr($2,5,2)); memconf[n] = strtonum($3); print; next} -/^setenv *node.._nasid/ {n=int(substr($2,5,2)); nasid[n] = strtonum($3); print; next} -/^setenv *node._cpu_config/ {n=int(substr($2,5,1)); cpuconf[n] = strtonum($3); print; next} -/^setenv *node._memory_config/ {n=int(substr($2,5,1)); memconf[n] = strtonum($3); print; next} -/^setenv *node._nasid/ {n=int(substr($2,5,1)); nasid[n] = strtonum($3); print; next} - {print} -END { - # Generate the memmap info that starts at the beginning of - # the node the kernel was loaded on. - loadnasid = nasid[0] - cnode = 0 - for (i=0; i<128; i++) { - if (memconf[i] != "") { - printf "sm 0x%x%08x 0x%x%04x%04x\n", - 2*loadnasid, 8*cnodes+8, memconf[i], cpuconf[i], nasid[i] - cnodes++ - cpus += substr("0112122312232334", cpuconf[i]+1,1) - } - } - printf "sm 0x%x00000000 0x%x%08x\n", 2*loadnasid, cnodes, cpus - printf "setenv number_of_nodes %d\n", cnodes - - # Now set the starting PC for each cpu. - cnode = 0 - lowcpu=-1 - for (i=0; i<128; i++) { - if (memconf[i] != "") { - printf "setnode %d\n", cnode - conf = cpuconf[i] - for (j=0; j<4; j++) { - if (conf != int(conf/2)*2) { - printf "setcpu %d\n", j - if (length(loadpc) == 18) - printf "sr pc %s\n", loadpc - else - printf "sr pc 0x%x%s\n", 2*loadnasid, substr(loadpc,3) - if (lowcpu == -1) - lowcpu = j - } - conf = int(conf/2) - } - cnode++ - } - } - printf "setnode 0\n" - printf "setcpu %d\n", lowcpu - } -' <$CF >.cf - -# Now build the .cf1 & .cf2 control files. -CF2_LINES="^sm |^break |^run |^si |^quit |^symbols " -egrep "$CF2_LINES" .cf >.cf2 -egrep -v "$CF2_LINES" .cf >.cf1 -if [ $STEPCNT -ne 0 ] ; then - echo "s $STEPCNT" >>.cf2 - echo "lastpc 1000" >>.cf2 - echo "q" >>.cf2 -fi -if [ -f vmlinux.sym ] ; then - awk '/ _start$/ {print "sr g 9 0x" $3}' < vmlinux.sym >> .cf2 -fi -echo "script-on $OUT" >>.cf2 - -# Now start medusa.... -if [ $FMTMED -ne 0 ] ; then - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 | fmtmedusa -elif [ $STEPCNT -eq 0 ] ; then - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 -else - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 2>&1 -fi diff -Nru a/arch/ia64/sn/io/hwgfs/interface.c b/arch/ia64/sn/io/hwgfs/interface.c --- a/arch/ia64/sn/io/hwgfs/interface.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/sn/io/hwgfs/interface.c 2004-10-18 14:57:04 -07:00 @@ -42,7 +42,7 @@ nd->dentry = lookup_create(nd, is_dir); nd->flags |= LOOKUP_PARENT; - if (unlikely(IS_ERR(nd->dentry))) + if (IS_ERR(nd->dentry)) return PTR_ERR(nd->dentry); if (!nd->dentry->d_inode) @@ -89,7 +89,7 @@ *dentry = lookup_create(&nd, is_dir); - if (unlikely(IS_ERR(*dentry))) + if (IS_ERR(*dentry)) return PTR_ERR(*dentry); *parent_inode = (*dentry)->d_parent->d_inode; return 0; diff -Nru a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c --- a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c 2004-10-18 14:56:49 -07:00 @@ -290,6 +290,7 @@ addr |= __IA64_UNCACHED_OFFSET; dev->resource[idx].start = addr; dev->resource[idx].end = addr + size; + dev->resource[idx].parent = &ioport_resource; } if (dev->resource[idx].flags & IORESOURCE_IO) @@ -322,6 +323,7 @@ addr |= __IA64_UNCACHED_OFFSET; dev->resource[idx].start = addr; dev->resource[idx].end = addr + size; + dev->resource[idx].parent = &iomem_resource; } if (dev->resource[idx].flags & IORESOURCE_MEM) @@ -351,10 +353,24 @@ addr |= __IA64_UNCACHED_OFFSET; dev->resource[PCI_ROM_RESOURCE].start = addr; dev->resource[PCI_ROM_RESOURCE].end = addr + size; + dev->resource[idx].parent = &iomem_resource; if (dev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } - } + } else { + /* + * Remove other ROM resources since they don't have valid + * CPU addresses. + */ + size = dev->resource[PCI_ROM_RESOURCE].end - + dev->resource[PCI_ROM_RESOURCE].start; + + if (size) { + dev->resource[PCI_ROM_RESOURCE].start = 0; + dev->resource[PCI_ROM_RESOURCE].end = 0; + dev->resource[PCI_ROM_RESOURCE].flags = 0; + } + } /* * Update the Command Word on the Card. diff -Nru a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c --- a/arch/ia64/sn/kernel/bte.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ia64/sn/kernel/bte.c 2004-10-18 14:56:32 -07:00 @@ -421,9 +421,10 @@ mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda; for (i = 0; i < BTES_PER_NODE; i++) { - (u64) mynodepda->bte_if[i].bte_base_addr = - REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), - (i == 0 ? IIO_IBLS0 : IIO_IBLS1)); + /* Which link status register should we use? */ + unsigned long link_status = (i == 0 ? IIO_IBLS0 : IIO_IBLS1); + mynodepda->bte_if[i].bte_base_addr = (u64 *) + REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), link_status); /* * Initialize the notification and spinlock diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c --- a/arch/ia64/sn/kernel/setup.c 2004-10-18 14:56:27 -07:00 +++ b/arch/ia64/sn/kernel/setup.c 2004-10-18 14:56:27 -07:00 @@ -64,6 +64,8 @@ unsigned long sn_rtc_cycles_per_second; +EXPORT_SYMBOL(sn_rtc_cycles_per_second); + partid_t sn_partid = -1; char sn_system_serial_number_string[128]; u64 sn_partition_serial_number; diff -Nru a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile --- a/arch/ia64/sn/kernel/sn2/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/sn/kernel/sn2/Makefile 2004-10-18 14:57:04 -07:00 @@ -10,4 +10,4 @@ # obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \ - prominfo_proc.o timer.o timer_interrupt.o + prominfo_proc.o timer.o timer_interrupt.o sn_hwperf.o diff -Nru a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c --- a/arch/ia64/sn/kernel/sn2/prominfo_proc.c 2004-10-18 14:56:18 -07:00 +++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c 2004-10-18 14:56:18 -07:00 @@ -3,10 +3,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1999,2001-2004 Silicon Graphics, Inc. All Rights Reserved. * * Module to export the system's Firmware Interface Tables, including - * PROM revision numbers, in /proc + * PROM revision numbers and banners, in /proc */ #include #include @@ -14,41 +14,14 @@ #include #include #include -#include -#include - -/* to lookup nasids */ +#include #include +#include MODULE_DESCRIPTION("PROM version reporting for /proc"); MODULE_AUTHOR("Chad Talbott"); MODULE_LICENSE("GPL"); -#undef DEBUG_PROMINFO - -#define TRACE_PROMINFO - -#if defined(DEBUG_PROMINFO) -# define DPRINTK(x...) printk(KERN_DEBUG x) -#else -# define DPRINTK(x...) -#endif - -#if defined(TRACE_PROMINFO) && defined(DEBUG_PROMINFO) -# if defined(__GNUC__) -# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ - __FILE__, __LINE__, __FUNCTION__) -# else -# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) -# endif -#else -# define TRACE() -#endif - -/* Sub-regions determined by bits in Node Offset */ -#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ - -#define FIT_SIGNATURE 0x2020205f5449465ful /* Standard Intel FIT entry types */ #define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */ #define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */ @@ -81,12 +54,6 @@ #define FIT_TYPE(q) \ ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK) -#define FIT_ENTRY(type, maj, min, size) \ - ((((unsigned long)(maj) & FIT_MAJOR_MASK) << FIT_MAJOR_SHIFT) | \ - (((unsigned long)(min) & FIT_MINOR_MASK) << FIT_MINOR_SHIFT) | \ - (((unsigned long)(type) & FIT_TYPE_MASK) << FIT_TYPE_SHIFT) | \ - (size)) - struct fit_type_map_t { unsigned char type; const char *name; @@ -125,32 +92,148 @@ return "Unknown type"; } -/* These two routines read the FIT table directly from the FLASH PROM - * on a specific node. The PROM can only be accessed using aligned 64 - * bit reads, so we do that and then shift and mask the result to get - * at each field. + +/* ============ BEGIN temp til old PROMs are no longer supported ============= + * + * The OS should not make direct access to the PROM flash memory. Access to + * this region must be serialized with a PROM lock. If SAL on one cpu is + * updating the FLASH error log at the same time another cpu is accessing the + * PROM, data corruption will occur. + * + * To solve the problem, all flash PROM access has been moved to SAL. Because + * not all systems will have instant PROM updates, we need to support a new OS + * running on a system with old PROMs. + * + * This code should be deleted after 1 OS/PROM release has occurred & the OS + * no longer supports downrev PROMs. (PROM support should be in the 3.50 + * PROMs). + */ +#define SUPPORT_OLD_PROMS +#ifdef SUPPORT_OLD_PROMS + + +#define FIT_SIGNATURE 0x2020205f5449465ful + +/* Sub-regions determined by bits in Node Offset */ +#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ + +/* Offset of PROM banner pointers in SAL A and SAL B */ +#define SAL_A_BANNER_OFFSET (1 * 16) +#define SAL_B_BANNER_OFFSET (3 * 16) + +/* Architected IA64 firmware space */ +#define FW_BASE 0x00000000FF000000 +#define FW_TOP 0x0000000100000000 + +static unsigned long +convert_fw_addr(nasid_t nasid, unsigned long addr) +{ + /* snag just the node-relative offset */ + addr &= ~0ul >> (63-35); + /* the pointer to SAL A is relative to IA-64 compatibility + * space. However, the PROM is mapped at a different offset + * in MMR space (both local and global) + */ + addr += 0x700000000; + return GLOBAL_MMR_ADDR(nasid, addr); +} + +static int +valid_fw_addr(unsigned long addr) +{ + addr &= ~(1ul << 63); /* Clear cached/uncached bit */ + return (addr >= FW_BASE && addr < FW_TOP); +} + +static unsigned long * +lookup_fit(int nasid) +{ + unsigned long *fitp; + unsigned long fit_paddr; + unsigned long *fit_vaddr; + + fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); + fit_paddr = readq(fitp); + fit_vaddr = (unsigned long *) convert_fw_addr(nasid, fit_paddr); + return fit_vaddr; +} +#endif /* SUPPORT_OLD_PROMS */ +/* ============ END temp til old PROMs are no longer supported ============= */ + +static int +get_fit_entry(unsigned long nasid, int index, unsigned long *fentry, + char *banner, int banlen) +{ + int ret; + + ret = ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen); + +#ifdef SUPPORT_OLD_PROMS + /* The following is hack is temporary until PROMs are updated */ + if (ret == SALRET_NOT_IMPLEMENTED) { + unsigned long *fitadr = lookup_fit(nasid); + int nentries; + + if (readq(fitadr) != FIT_SIGNATURE) { + printk(KERN_WARNING "Unrecognized FIT signature"); + return -2; + } + + nentries = (unsigned int) (readq(fitadr + 1) & 0xffffff); + if (index >= nentries) + return -2; + + fentry[0] = readq(fitadr + 2 * index); + fentry[1] = readq(fitadr + 2 * index + 1); + ret = 0; + + if (banner && FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A) { + unsigned long i, qw, *bwp, *qwp; + + banner[0] = '\0'; + qw = fentry[0]; /* Address of SAL A */ + if (!valid_fw_addr(qw)) + return 0; + + qw += SAL_A_BANNER_OFFSET; + qw = convert_fw_addr(nasid, qw); + + qw = readq(qw); /* Address of banner */ + if (!valid_fw_addr(qw)) + return 0; + qw = convert_fw_addr(nasid, qw); + qwp = (unsigned long *) qw; + bwp = (unsigned long *) banner; + for (i=0; i PAGE_SIZE); - p = page; - for (fentry = 0; fentry < nentries; fentry++) - /* each FIT entry is two 64 bit words */ - p += dump_fit_entry(p, fit + 2 * fentry); + for (index=0;;index++) { + BUG_ON(index * 60 > PAGE_SIZE); + if (get_fit_entry(nasid, index, fentry, NULL, 0)) + break; + p += dump_fit_entry(p, fentry); + } return p - page; } static int -dump_version(char *page, unsigned long *fit) +dump_version(char *page, unsigned long nasid) { - int nentries; - int fentry; - unsigned long qw; - - TRACE(); - - nentries = (unsigned)readq(fit + 1); - BUG_ON(nentries * 60 > PAGE_SIZE); - - for (fentry = 0; fentry < nentries; fentry++) { - qw = readq(fit + 2 * fentry + 1); - if (FIT_TYPE(qw) == FIT_ENTRY_SAL_A) - return sprintf(page, "%x.%02x\n", - FIT_MAJOR(qw), FIT_MINOR(qw)); + unsigned long fentry[2]; + char banner[128]; + int index; + int len; + + for (index = 0; ; index++) { + if (get_fit_entry(nasid, index, fentry, banner, + sizeof(banner))) + return 0; + if (FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A) + break; } - return 0; + + len = sprintf(page, "%x.%02x\n", FIT_MAJOR(fentry[1]), + FIT_MINOR(fentry[1])); + page += len; + + if (banner[0]) + len += snprintf(page, PAGE_SIZE-len, "%s\n", banner); + + return len; } /* same as in proc_misc.c */ @@ -228,8 +303,8 @@ { int len = 0; - /* data holds the pointer to this node's FIT */ - len = dump_version(page, (unsigned long *)data); + /* data holds the NASID of the node */ + len = dump_version(page, (unsigned long)data); len = proc_calc_metrics(page, start, off, count, eof, len); return len; } @@ -240,56 +315,13 @@ { int len = 0; - /* data holds the pointer to this node's FIT */ - len = dump_fit(page, (unsigned long *)data); + /* data holds the NASID of the node */ + len = dump_fit(page, (unsigned long)data); len = proc_calc_metrics(page, start, off, count, eof, len); return len; } -/* this is a fake FIT that's used on the medusa simulator which - * doesn't usually run a complete PROM. - */ -#ifdef CONFIG_IA64_SGI_SN_SIM -static unsigned long fakefit[] = { - /* this is all we need to satisfy the code below */ - FIT_SIGNATURE, - FIT_ENTRY(FIT_ENTRY_FIT_HEADER, 0x02, 0x60, 2), - /* dump something arbitrary for - * /proc/sgi_prominfo/nodeX/version */ - 0xbadbeef00fa3ef17ul, - FIT_ENTRY(FIT_ENTRY_SAL_A, 0, 0x99, 0x100) -}; -#endif - -static unsigned long * -lookup_fit(int nasid) -{ - unsigned long *fitp; - unsigned long fit_paddr; - unsigned long *fit_vaddr; - -#ifdef CONFIG_IA64_SGI_SN_SIM - if (IS_RUNNING_ON_SIMULATOR()) - return fakefit; -#endif - - fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); - DPRINTK("pointer to fit at %p\n", (void *)fitp); - fit_paddr = readq(fitp); - DPRINTK("fit pointer contains %lx\n", fit_paddr); - /* snag just the node-relative offset */ - fit_paddr &= ~0ul >> (63-35); - /* the pointer to the FIT is relative to IA-64 compatibility - * space. However, the PROM is mapped at a different offset - * in MMR space (both local and global) - */ - fit_paddr += 0x700000000; - fit_vaddr = (void *)GLOBAL_MMR_ADDR(nasid, fit_paddr); - DPRINTK("fit at %p\n", (void *)fit_vaddr); - return fit_vaddr; -} - /* module entry points */ int __init prominfo_init(void); void __exit prominfo_exit(void); @@ -308,17 +340,12 @@ struct proc_dir_entry **entp; struct proc_dir_entry *p; cnodeid_t cnodeid; - nasid_t nasid; + unsigned long nasid; char name[NODE_NAME_LEN]; if (!ia64_platform_is("sn2")) return 0; - TRACE(); - - DPRINTK("running on cpu %d\n", smp_processor_id()); - DPRINTK("numnodes %d\n", numnodes); - proc_entries = kmalloc(numnodes * sizeof(struct proc_dir_entry *), GFP_KERNEL); @@ -332,12 +359,12 @@ nasid = cnodeid_to_nasid(cnodeid); p = create_proc_read_entry( "fit", 0, *entp, read_fit_entry, - lookup_fit(nasid)); + (void *)nasid); if (p) p->owner = THIS_MODULE; p = create_proc_read_entry( "version", 0, *entp, read_version_entry, - lookup_fit(nasid)); + (void *)nasid); if (p) p->owner = THIS_MODULE; } @@ -351,8 +378,6 @@ struct proc_dir_entry **entp; unsigned cnodeid; char name[NODE_NAME_LEN]; - - TRACE(); for (cnodeid = 0, entp = proc_entries; cnodeid < numnodes; diff -Nru a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,652 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + * + * SGI Altix topology and hardware performance monitoring API. + * Mark Goodwin . + * + * Creates /proc/sgi_sn/sn_topology (read-only) to export + * info about Altix nodes, routers, CPUs and NumaLink + * interconnection/topology. + * + * Also creates a dynamic misc device named "sn_hwperf" + * that supports an ioctl interface to call down into SAL + * to discover hw objects, topology and to read/write + * memory mapped registers, e.g. for performance monitoring. + * The "sn_hwperf" device is registered only after the procfs + * file is first opened, i.e. only if/when it's needed. + * + * This API is used by SGI Performance Co-Pilot and other + * tools, see http://oss.sgi.com/projects/pcp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void *sn_hwperf_salheap = NULL; +static int sn_hwperf_obj_cnt = 0; +static nasid_t sn_hwperf_master_nasid = INVALID_NASID; +static int sn_hwperf_init(void); +static DECLARE_MUTEX(sn_hwperf_init_mutex); + +static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret) +{ + int e; + u64 sz; + struct sn_hwperf_object_info *objbuf = NULL; + + if ((e = sn_hwperf_init()) < 0) { + printk("sn_hwperf_init failed: err %d\n", e); + goto out; + } + + sz = sn_hwperf_obj_cnt * sizeof(struct sn_hwperf_object_info); + if ((objbuf = (struct sn_hwperf_object_info *) vmalloc(sz)) == NULL) { + printk("sn_hwperf_enum_objects: vmalloc(%d) failed\n", (int)sz); + e = -ENOMEM; + goto out; + } + + e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, SN_HWPERF_ENUM_OBJECTS, + 0, sz, (u64) objbuf, 0, 0, NULL); + if (e != SN_HWPERF_OP_OK) { + e = -EINVAL; + vfree(objbuf); + } + +out: + *nobj = sn_hwperf_obj_cnt; + *ret = objbuf; + return e; +} + +static int sn_hwperf_geoid_to_cnode(char *location) +{ + int cnode; + int mod, slot, slab; + int cmod, cslot, cslab; + + if (sscanf(location, "%03dc%02d#%d", &mod, &slot, &slab) != 3) + return -1; + for (cnode = 0; cnode < numnodes; cnode++) { + /* XXX: need a better way than this ... */ + if (sscanf(NODEPDA(cnode)->hwg_node_name, + "hw/module/%03dc%02d/slab/%d", &cmod, &cslot, &cslab) == 3) { + if (mod == cmod && slot == cslot && slab == cslab) + break; + } + } + + return cnode < numnodes ? cnode : -1; +} + +static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) +{ + if (!obj->sn_hwp_this_part) + return -1; + return sn_hwperf_geoid_to_cnode(obj->location); +} + +static int sn_hwperf_generic_ordinal(struct sn_hwperf_object_info *obj, + struct sn_hwperf_object_info *objs) +{ + int ordinal; + struct sn_hwperf_object_info *p; + + for (ordinal=0, p=objs; p != obj; p++) { + if (SN_HWPERF_FOREIGN(p)) + continue; + if (p->location[3] == obj->location[3]) + ordinal++; + } + + return ordinal; +} + +#ifndef MODULE_IOBRICK +/* this will be available when ioif TIO support is added */ +#define MODULE_IOBRICK (MODULE_OPUSBRICK+1) +#endif + +static const char *sn_hwperf_get_brickname(struct sn_hwperf_object_info *obj, + struct sn_hwperf_object_info *objs, int *ordinal) +{ + int i; + const char *objtype = NULL; + + for (i=0; i < MAX_BRICK_TYPES; i++) { + if (brick_types[i] != obj->location[3]) + continue; + switch (i) { + case MODULE_CBRICK: + objtype = "node"; + *ordinal = sn_hwperf_obj_to_cnode(obj); /* cnodeid */ + break; + + case MODULE_RBRICK: + objtype = "router"; + *ordinal = sn_hwperf_generic_ordinal(obj, objs); + break; + + case MODULE_IOBRICK: + objtype = "ionode"; + *ordinal = sn_hwperf_generic_ordinal(obj, objs); + break; + } + break; + } + + if (i == MAX_BRICK_TYPES) { + objtype = "other"; + *ordinal = sn_hwperf_generic_ordinal(obj, objs); + } + + return objtype; +} + +static int sn_topology_show(struct seq_file *s, void *d) +{ + int sz; + int pt; + int e; + int i; + int j; + const char *brickname; + int ordinal; + cpumask_t cpumask; + char slice; + struct cpuinfo_ia64 *c; + struct sn_hwperf_port_info *ptdata; + struct sn_hwperf_object_info *p; + struct sn_hwperf_object_info *obj = d; /* this object */ + struct sn_hwperf_object_info *objs = s->private; /* all objects */ + + if (obj == objs) { + seq_printf(s, "# sn_topology version 1\n"); + seq_printf(s, "# objtype ordinal location partition" + " [attribute value [, ...]]\n"); + } + + if (SN_HWPERF_FOREIGN(obj)) { + /* private in another partition: not interesting */ + return 0; + } + + for (i = 0; obj->name[i]; i++) { + if (obj->name[i] == ' ') + obj->name[i] = '_'; + } + + brickname = sn_hwperf_get_brickname(obj, objs, &ordinal); + seq_printf(s, "%s %d %s %s asic %s", brickname, ordinal, obj->location, + obj->sn_hwp_this_part ? "local" : "shared", obj->name); + + if (obj->location[3] != 'c') + seq_putc(s, '\n'); + else { + seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal)); + for (i=0; i < numnodes; i++) { + seq_printf(s, i ? ":%d" : ", dist %d", + node_distance(ordinal, i)); + } + seq_putc(s, '\n'); + + /* + * CPUs on this node + */ + cpumask = node_to_cpumask(ordinal); + for_each_online_cpu(i) { + if (cpu_isset(i, cpumask)) { + slice = 'a' + cpuid_to_slice(i); + c = cpu_data(i); + seq_printf(s, "cpu %d %s%c local" + " freq %luMHz, arch ia64", + i, obj->location, slice, + c->proc_freq / 1000000); + for_each_online_cpu(j) { + seq_printf(s, j ? ":%d" : ", dist %d", + node_distance( + cpuid_to_cnodeid(i), + cpuid_to_cnodeid(j))); + } + seq_putc(s, '\n'); + } + } + } + + if (obj->ports) { + /* + * numalink ports + */ + sz = obj->ports * sizeof(struct sn_hwperf_port_info); + if ((ptdata = vmalloc(sz)) == NULL) + return -ENOMEM; + e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + SN_HWPERF_ENUM_PORTS, obj->id, sz, + (u64) ptdata, 0, 0, NULL); + if (e != SN_HWPERF_OP_OK) + return -EINVAL; + for (ordinal=0, p=objs; p != obj; p++) { + if (!SN_HWPERF_FOREIGN(p)) + ordinal += p->ports; + } + for (pt = 0; pt < obj->ports; pt++) { + for (p = objs, i = 0; i < sn_hwperf_obj_cnt; i++, p++) { + if (ptdata[pt].conn_id == p->id) { + break; + } + } + if (i >= sn_hwperf_obj_cnt) + continue; + seq_printf(s, "numalink %d %s-%d", + ordinal+pt, obj->location, ptdata[pt].port); + + if (obj->sn_hwp_this_part && p->sn_hwp_this_part) + /* both ends local to this partition */ + seq_puts(s, " local"); + else if (!obj->sn_hwp_this_part && !p->sn_hwp_this_part) + /* both ends of the link in foreign partiton */ + seq_puts(s, " foreign"); + else + /* link straddles a partition */ + seq_puts(s, " shared"); + + /* + * Unlikely, but strictly should query the LLP config + * registers because an NL4R can be configured to run + * NL3 protocol, even when not talking to an NL3 router. + * Ditto for node-node. + */ + seq_printf(s, " endpoint %s-%d, protocol %s\n", + p->location, ptdata[pt].conn_port, + strcmp(obj->name, "NL3Router") == 0 || + strcmp(p->name, "NL3Router") == 0 ? + "LLP3" : "LLP4"); + } + vfree(ptdata); + } + + return 0; +} + +static void *sn_topology_start(struct seq_file *s, loff_t * pos) +{ + struct sn_hwperf_object_info *objs = s->private; + + if (*pos < sn_hwperf_obj_cnt) + return (void *)(objs + *pos); + + return NULL; +} + +static void *sn_topology_next(struct seq_file *s, void *v, loff_t * pos) +{ + ++*pos; + return sn_topology_start(s, pos); +} + +static void sn_topology_stop(struct seq_file *m, void *v) +{ + return; +} + +/* + * /proc/sgi_sn/sn_topology, read-only using seq_file + */ +static struct seq_operations sn_topology_seq_ops = { + .start = sn_topology_start, + .next = sn_topology_next, + .stop = sn_topology_stop, + .show = sn_topology_show +}; + +struct sn_hwperf_op_info { + u64 op; + struct sn_hwperf_ioctl_args *a; + void *p; + int *v0; + int ret; +}; + +static void sn_hwperf_call_sal(void *info) +{ + struct sn_hwperf_op_info *op_info = info; + int r; + + r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op_info->op, + op_info->a->arg, op_info->a->sz, + (u64) op_info->p, 0, 0, op_info->v0); + op_info->ret = r; +} + +static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info) +{ + u32 cpu; + u32 use_ipi; + int r = 0; + cpumask_t save_allowed; + + cpu = (op_info->a->arg & SN_HWPERF_ARG_CPU_MASK) >> 32; + use_ipi = op_info->a->arg & SN_HWPERF_ARG_USE_IPI_MASK; + op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK; + + if (cpu != SN_HWPERF_ARG_ANY_CPU) { + if (cpu >= num_online_cpus() || !cpu_online(cpu)) { + r = -EINVAL; + goto out; + } + } + + if (cpu == SN_HWPERF_ARG_ANY_CPU || cpu == get_cpu()) { + /* don't care, or already on correct cpu */ + sn_hwperf_call_sal(op_info); + } + else { + if (use_ipi) { + /* use an interprocessor interrupt to call SAL */ + smp_call_function_single(cpu, sn_hwperf_call_sal, + op_info, 1, 1); + } + else { + /* migrate the task before calling SAL */ + save_allowed = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + sn_hwperf_call_sal(op_info); + set_cpus_allowed(current, save_allowed); + } + } + r = op_info->ret; + +out: + return r; +} + +/* + * ioctl for "sn_hwperf" misc device + */ +static int +sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) +{ + struct sn_hwperf_ioctl_args a; + struct cpuinfo_ia64 *cdata; + struct sn_hwperf_object_info *objs; + struct sn_hwperf_object_info *cpuobj; + struct sn_hwperf_op_info op_info; + void *p = NULL; + int nobj; + char slice; + int node; + int r; + int v0; + int i; + int j; + + unlock_kernel(); + + /* only user requests are allowed here */ + if ((op & SN_HWPERF_OP_MASK) < 10) { + r = -EINVAL; + goto error; + } + r = copy_from_user(&a, (const void *)arg, + sizeof(struct sn_hwperf_ioctl_args)); + if (r != 0) { + r = -EFAULT; + goto error; + } + + /* + * Allocate memory to hold a kernel copy of the user buffer. The + * buffer contents are either copied in or out (or both) of user + * space depending on the flags encoded in the requested operation. + */ + if (a.ptr) { + p = vmalloc(a.sz); + if (!p) { + r = -ENOMEM; + goto error; + } + } + + if (op & SN_HWPERF_OP_MEM_COPYIN) { + r = copy_from_user(p, (const void *)a.ptr, a.sz); + if (r != 0) { + r = -EFAULT; + goto error; + } + } + + switch (op) { + case SN_HWPERF_GET_CPU_INFO: + if (a.sz == sizeof(u64)) { + /* special case to get size needed */ + *(u64 *) p = (u64) num_online_cpus() * + sizeof(struct sn_hwperf_object_info); + } else + if (a.sz < num_online_cpus() * sizeof(struct sn_hwperf_object_info)) { + r = -ENOMEM; + goto error; + } else + if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { + memset(p, 0, a.sz); + for (i = 0; i < nobj; i++) { + node = sn_hwperf_obj_to_cnode(objs + i); + for_each_online_cpu(j) { + if (node != cpu_to_node(j)) + continue; + cpuobj = (struct sn_hwperf_object_info *) p + j; + slice = 'a' + cpuid_to_slice(j); + cdata = cpu_data(j); + cpuobj->id = j; + snprintf(cpuobj->name, + sizeof(cpuobj->name), + "CPU %luMHz %s", + cdata->proc_freq / 1000000, + cdata->vendor); + snprintf(cpuobj->location, + sizeof(cpuobj->location), + "%s%c", objs[i].location, + slice); + } + } + + vfree(objs); + } + break; + + case SN_HWPERF_GET_NODE_NASID: + if (a.sz != sizeof(u64) || + (node = a.arg) < 0 || node >= numnodes) { + r = -EINVAL; + goto error; + } + *(u64 *)p = (u64)cnodeid_to_nasid(node); + break; + + case SN_HWPERF_GET_OBJ_NODE: + if (a.sz != sizeof(u64) || a.arg < 0) { + r = -EINVAL; + goto error; + } + if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { + if (a.arg >= nobj) { + r = -EINVAL; + vfree(objs); + goto error; + } + if (objs[(i = a.arg)].id != a.arg) { + for (i = 0; i < nobj; i++) { + if (objs[i].id == a.arg) + break; + } + } + if (i == nobj) { + r = -EINVAL; + vfree(objs); + goto error; + } + *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i); + vfree(objs); + } + break; + + case SN_HWPERF_GET_MMRS: + case SN_HWPERF_SET_MMRS: + case SN_HWPERF_OBJECT_DISTANCE: + op_info.p = p; + op_info.a = &a; + op_info.v0 = &v0; + op_info.op = op; + r = sn_hwperf_op_cpu(&op_info); + break; + + default: + /* all other ops are a direct SAL call */ + r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op, + a.arg, a.sz, (u64) p, 0, 0, &v0); + a.v0 = v0; + break; + } + + if (op & SN_HWPERF_OP_MEM_COPYOUT) { + r = copy_to_user((void *)a.ptr, p, a.sz); + if (r != 0) { + r = -EFAULT; + goto error; + } + } + +error: + if (p) + vfree(p); + + lock_kernel(); + return r; +} + +static struct file_operations sn_hwperf_fops = { + .ioctl = sn_hwperf_ioctl, +}; + +static struct miscdevice sn_hwperf_dev = { + MISC_DYNAMIC_MINOR, + "sn_hwperf", + &sn_hwperf_fops +}; + +static int sn_hwperf_init(void) +{ + u64 v; + int salr; + int e = 0; + + /* single threaded, once-only initialization */ + down(&sn_hwperf_init_mutex); + if (sn_hwperf_salheap) { + up(&sn_hwperf_init_mutex); + return e; + } + + /* + * The PROM code needs a fixed reference node. For convenience the + * same node as the console I/O is used. + */ + sn_hwperf_master_nasid = (nasid_t) ia64_sn_get_console_nasid(); + + /* + * Request the needed size and install the PROM scratch area. + * The PROM keeps various tracking bits in this memory area. + */ + salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + (u64) SN_HWPERF_GET_HEAPSIZE, 0, + (u64) sizeof(u64), (u64) &v, 0, 0, NULL); + if (salr != SN_HWPERF_OP_OK) { + e = -EINVAL; + goto out; + } + + if ((sn_hwperf_salheap = vmalloc(v)) == NULL) { + e = -ENOMEM; + goto out; + } + salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + SN_HWPERF_INSTALL_HEAP, 0, v, + (u64) sn_hwperf_salheap, 0, 0, NULL); + if (salr != SN_HWPERF_OP_OK) { + e = -EINVAL; + goto out; + } + + salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + SN_HWPERF_OBJECT_COUNT, 0, + sizeof(u64), (u64) &v, 0, 0, NULL); + if (salr != SN_HWPERF_OP_OK) { + e = -EINVAL; + goto out; + } + sn_hwperf_obj_cnt = (int)v; + +out: + if (e < 0 && sn_hwperf_salheap) { + vfree(sn_hwperf_salheap); + sn_hwperf_salheap = NULL; + sn_hwperf_obj_cnt = 0; + } + + if (!e) { + /* + * Register a dynamic misc device for ioctl. Platforms + * supporting hotplug will create /dev/sn_hwperf, else + * user can to look up the minor number in /proc/misc. + */ + if ((e = misc_register(&sn_hwperf_dev)) != 0) { + printk(KERN_ERR "sn_hwperf_init: misc register " + "for \"sn_hwperf\" failed, err %d\n", e); + } + } + + up(&sn_hwperf_init_mutex); + return e; +} + +int sn_topology_open(struct inode *inode, struct file *file) +{ + int e; + struct seq_file *seq; + struct sn_hwperf_object_info *objbuf; + int nobj; + + if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) { + e = seq_open(file, &sn_topology_seq_ops); + seq = file->private_data; + seq->private = objbuf; + } + + return e; +} + +int sn_topology_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + + if (seq->private) + vfree(seq->private); + return seq_release(inode, file); +} diff -Nru a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c 2004-10-18 14:57:04 -07:00 @@ -3,74 +3,48 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. */ #include #include #ifdef CONFIG_PROC_FS #include +#include #include #include - -static int partition_id_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - - return sprintf(page, "%d\n", sn_local_partid()); +static int partition_id_show(struct seq_file *s, void *p) +{ + seq_printf(s, "%d\n", sn_local_partid()); + return 0; } -static struct proc_dir_entry * sgi_proc_dir; - -void -register_sn_partition_id(void) { - struct proc_dir_entry *entry; - - if (!sgi_proc_dir) { - sgi_proc_dir = proc_mkdir("sgi_sn", 0); - } - entry = create_proc_entry("partition_id", 0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = partition_id_read_proc; - entry->write_proc = NULL; - } +static int partition_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, partition_id_show, NULL); } -static int -system_serial_number_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - return sprintf(page, "%s\n", sn_system_serial_number()); +static int system_serial_number_show(struct seq_file *s, void *p) +{ + seq_printf(s, "%s\n", sn_system_serial_number()); + return 0; } -static int -licenseID_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - return sprintf(page, "0x%lx\n",sn_partition_serial_number_val()); +static int system_serial_number_open(struct inode *inode, struct file *file) +{ + return single_open(file, system_serial_number_show, NULL); } -void -register_sn_serial_numbers(void) { - struct proc_dir_entry *entry; +static int licenseID_show(struct seq_file *s, void *p) +{ + seq_printf(s, "0x%lx\n", sn_partition_serial_number_val()); + return 0; +} - if (!sgi_proc_dir) { - sgi_proc_dir = proc_mkdir("sgi_sn", 0); - } - entry = create_proc_entry("system_serial_number", 0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = system_serial_number_read_proc; - entry->write_proc = NULL; - } - entry = create_proc_entry("licenseID", 0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = licenseID_read_proc; - entry->write_proc = NULL; - } +static int licenseID_open(struct inode *inode, struct file *file) +{ + return single_open(file, licenseID_show, NULL); } /* @@ -81,48 +55,90 @@ */ int sn_force_interrupt_flag = 1; -static int -sn_force_interrupt_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - if (sn_force_interrupt_flag) { - return sprintf(page, "Force interrupt is enabled\n"); - } - return sprintf(page, "Force interrupt is disabled\n"); +static int sn_force_interrupt_show(struct seq_file *s, void *p) +{ + seq_printf(s, "Force interrupt is %s\n", + sn_force_interrupt_flag ? "enabled" : "disabled"); + return 0; } -static int -sn_force_interrupt_write_proc(struct file *file, const char *buffer, - unsigned long count, void *data) +static ssize_t sn_force_interrupt_write_proc(struct file *file, + const __user char *buffer, size_t count, loff_t *data) { - if (*buffer == '0') { - sn_force_interrupt_flag = 0; - } else { - sn_force_interrupt_flag = 1; - } - return 1; + sn_force_interrupt_flag = (*buffer == '0') ? 0 : 1; + return count; } -void -register_sn_force_interrupt(void) { - struct proc_dir_entry *entry; +static int sn_force_interrupt_open(struct inode *inode, struct file *file) +{ + return single_open(file, sn_force_interrupt_show, NULL); +} - if (!sgi_proc_dir) { - sgi_proc_dir = proc_mkdir("sgi_sn", 0); - } - entry = create_proc_entry("sn_force_interrupt",0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = sn_force_interrupt_read_proc; - entry->write_proc = sn_force_interrupt_write_proc; +static int coherence_id_show(struct seq_file *s, void *p) +{ + seq_printf(s, "%d\n", cpuid_to_coherence_id(smp_processor_id())); + return 0; +} + +static int coherence_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, coherence_id_show, NULL); +} + +static struct proc_dir_entry *sn_procfs_create_entry( + const char *name, struct proc_dir_entry *parent, + int (*openfunc)(struct inode *, struct file *), + int (*releasefunc)(struct inode *, struct file *)) +{ + struct proc_dir_entry *e = create_proc_entry(name, 0444, parent); + + if (e) { + e->proc_fops = (struct file_operations *)kmalloc( + sizeof(struct file_operations), GFP_KERNEL); + if (e->proc_fops) { + memset(e->proc_fops, 0, sizeof(struct file_operations)); + e->proc_fops->open = openfunc; + e->proc_fops->read = seq_read; + e->proc_fops->llseek = seq_lseek; + e->proc_fops->release = releasefunc; + } } + + return e; } -void -register_sn_procfs(void) { - register_sn_partition_id(); - register_sn_serial_numbers(); - register_sn_force_interrupt(); +/* /proc/sgi_sn/sn_topology uses seq_file, see sn_hwperf.c */ +extern int sn_topology_open(struct inode *, struct file *); +extern int sn_topology_release(struct inode *, struct file *); + +void register_sn_procfs(void) +{ + static struct proc_dir_entry *sgi_proc_dir = NULL; + struct proc_dir_entry *e; + + BUG_ON(sgi_proc_dir != NULL); + if (!(sgi_proc_dir = proc_mkdir("sgi_sn", 0))) + return; + + sn_procfs_create_entry("partition_id", sgi_proc_dir, + partition_id_open, single_release); + + sn_procfs_create_entry("system_serial_number", sgi_proc_dir, + system_serial_number_open, single_release); + + sn_procfs_create_entry("licenseID", sgi_proc_dir, + licenseID_open, single_release); + + e = sn_procfs_create_entry("sn_force_interrupt", sgi_proc_dir, + sn_force_interrupt_open, single_release); + if (e) + e->proc_fops->write = sn_force_interrupt_write_proc; + + sn_procfs_create_entry("coherence_id", sgi_proc_dir, + coherence_id_open, single_release); + + sn_procfs_create_entry("sn_topology", sgi_proc_dir, + sn_topology_open, sn_topology_release); } #endif /* CONFIG_PROC_FS */ diff -Nru a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c --- a/arch/ia64/sn/kernel/sn2/timer.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ia64/sn/kernel/sn2/timer.c 2004-10-18 14:56:32 -07:00 @@ -20,57 +20,16 @@ extern unsigned long sn_rtc_cycles_per_second; -static volatile unsigned long last_wall_rtc; -static unsigned long rtc_offset; /* updated only when xtime write-lock is held! */ -static long rtc_nsecs_per_cycle; -static long rtc_per_timer_tick; - -static unsigned long -getoffset(void) -{ - return rtc_offset + (GET_RTC_COUNTER() - last_wall_rtc)*rtc_nsecs_per_cycle; -} - - -static void -update(long delta_nsec) -{ - unsigned long rtc_counter = GET_RTC_COUNTER(); - unsigned long offset = rtc_offset + (rtc_counter - last_wall_rtc)*rtc_nsecs_per_cycle; - - /* Be careful about signed/unsigned comparisons here: */ - if (delta_nsec < 0 || (unsigned long) delta_nsec < offset) - rtc_offset = offset - delta_nsec; - else - rtc_offset = 0; - last_wall_rtc = rtc_counter; -} - - -static void -reset(void) -{ - rtc_offset = 0; - last_wall_rtc = GET_RTC_COUNTER(); -} - - -static struct time_interpolator sn2_interpolator = { - .get_offset = getoffset, - .update = update, - .reset = reset -}; +static struct time_interpolator sn2_interpolator; void __init sn_timer_init(void) { sn2_interpolator.frequency = sn_rtc_cycles_per_second; sn2_interpolator.drift = -1; /* unknown */ + sn2_interpolator.shift = 10; /* RTC is 54 bits maximum shift is 10 */ + sn2_interpolator.addr = RTC_COUNTER_ADDR; + sn2_interpolator.source = TIME_SOURCE_MMIO64; register_time_interpolator(&sn2_interpolator); - - rtc_per_timer_tick = sn_rtc_cycles_per_second / HZ; - rtc_nsecs_per_cycle = 1000000000 / sn_rtc_cycles_per_second; - - last_wall_rtc = GET_RTC_COUNTER(); } diff -Nru a/arch/m32r/Kconfig b/arch/m32r/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/Kconfig 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,441 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Linux Kernel Configuration" + +config M32R + bool + default y + +config SBUS + bool + +config UID16 + bool + default y + +config GENERIC_ISA_DMA + bool + default y + +source "init/Kconfig" + + +menu "Processor type and features" + +choice + prompt "Platform Type" + default PLAT_MAPPI + +config PLAT_MAPPI + bool "Mappi-I" + help + The Mappi-I is an FPGA board for SOC (System-On-a-Chip) prototyping. + You can operate a Linux system on this board by using an M32R + softmacro core, which is a fully-synthesizable functional model + described in Verilog-HDL. + + The Mappi-I board was the first platform, which had been used + to port and develop a Linux system for the M32R processor. + Currently, the Mappi-II, an heir to the Mappi-I, is available. + +config PLAT_USRV + bool "uServer" + +config PLAT_M32700UT + bool "M32700UT" + help + The M3T-M32700UT is an evaluation board based on uT-Engine + specification. This board has an M32700 (Chaos) evaluation chip. + You can say Y for SMP, because the M32700 is a single chip + multiprocessor. + +config PLAT_OPSPUT + bool "OPSPUT" + help + The OPSPUT is an evaluation board based on uT-Engine + specification. This board has a OPSP-REP chip. + +config PLAT_OAKS32R + bool "OAKS32R" + help + The OAKS32R is a tiny, inexpensive evaluation board. + Please note that if you say Y here and choose chip "M32102", + say N for MMU and select a no-MMU version kernel, otherwise + a kernel with MMU support will not work, because the M32102 + is a microcontroller for embedded systems and it has no MMU. + +config PLAT_MAPPI2 + bool "Mappi-II(M3A-ZA36/M3A-ZA52)" + +endchoice + +choice + prompt "Processor family" + default CHIP_M32700 + +config CHIP_M32700 + bool "M32700 (Chaos)" + +config CHIP_M32102 + bool "M32102" + +config CHIP_VDEC2 + bool "VDEC2" + +config CHIP_OPSP + bool "OPSP" + +endchoice + +config MMU + bool "Support for memory management hardware" + depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP + default y + +config TLB_ENTRIES + int "TLB Entries" + depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP + default 32 if CHIP_M32700 || CHIP_OPSP + default 16 if CHIP_VDEC2 + + +config ISA_M32R + bool + depends on CHIP_M32102 + default y + +config ISA_M32R2 + bool + depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP + default y + +config ISA_DSP_LEVEL2 + bool + depends on CHIP_M32700 || CHIP_OPSP + default y + +config ISA_DUAL_ISSUE + bool + depends on CHIP_M32700 || CHIP_OPSP + default y + +config BUS_CLOCK + int "Bus Clock [Hz] (integer)" + default "70000000" if PLAT_MAPPI + default "25000000" if PLAT_USRV + default "50000000" if PLAT_M32700UT + default "50000000" if PLAT_OPSPUT + default "33333333" if PLAT_OAKS32R + default "20000000" if PLAT_MAPPI2 + +config TIMER_DIVIDE + int "Timer divider (integer)" + default "128" + +config CPU_LITTLE_ENDIAN + bool "Generate little endian code" + default n + +config MEMORY_START + hex "Physical memory start address (hex)" + default "08000000" if PLAT_MAPPI || PLAT_MAPPI2 + default "08000000" if PLAT_USRV + default "08000000" if PLAT_M32700UT + default "08000000" if PLAT_OPSPUT + default "01000000" if PLAT_OAKS32R + +config MEMORY_SIZE + hex "Physical memory size (hex)" + default "04000000" if PLAT_MAPPI || PLAT_MAPPI2 + default "02000000" if PLAT_USRV + default "01000000" if PLAT_M32700UT + default "01000000" if PLAT_OPSPUT + default "00800000" if PLAT_OAKS32R + +config NOHIGHMEM + bool + default y + +config DISCONTIGMEM + bool "Internal RAM Support" + depends on CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP + default y + +config IRAM_START + hex "Internal memory start address (hex)" + default "00f00000" + depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM + +config IRAM_SIZE + hex "Internal memory size (hex)" + depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM + default "00080000" if CHIP_M32700 + default "00010000" if CHIP_M32102 || CHIP_OPSP + default "00008000" if CHIP_VDEC2 + +# +# Define implied options from the CPU selection here +# + +config RWSEM_GENERIC_SPINLOCK + bool + depends on M32R + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + default n + +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + +config HAVE_DEC_LOCK + bool + depends on (SMP || PREEMPT) + default n + +config SMP + bool "Symmetric multi-processing support" + ---help--- + This enables support for systems with more than one CPU. If you have + a system with only one CPU, like most personal computers, say N. If + you have a system with more than one CPU, say Y. + + If you say N here, the kernel will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on many, but not all, + singleprocessor machines. On a singleprocessor machine, the kernel + will run faster if you say N here. + + People using multiprocessor machines who say Y here should also say + Y to "Enhanced Real Time Clock Support", below. The "Advanced Power + Management" code will be disabled if you say Y here. + + See also the , + and the SMP-HOWTO available at + . + + If you don't know what to do here, say N. + +config CHIP_M32700_TS1 + bool "Workaround code for the M32700 TS1 chip's bug" + depends on (CHIP_M32700 && SMP) + default n + +config NR_CPUS + int "Maximum number of CPUs (2-32)" + range 2 32 + depends on SMP + default "2" + help + This allows you to specify the maximum number of CPUs which this + kernel will support. The maximum supported value is 32 and the + minimum value which makes sense is 2. + + This is purely to save memory - each supported CPU adds + approximately eight kilobytes to the kernel image. + +# Common NUMA Features +config NUMA + bool "Numa Memory Allocation Support" + depends on SMP + default n + +# turning this on wastes a bunch of space. +# Summit needs it only when NUMA is on +config BOOT_IOREMAP + bool + depends on NUMA + default n + +endmenu + + +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" + +config PCI + bool "PCI support" + default n + help + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside + your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or + VESA. If you have PCI, say Y, otherwise N. + + The PCI-HOWTO, available from + , contains valuable + information about which PCI hardware does work under Linux and which + doesn't. + +choice + prompt "PCI access mode" + depends on PCI + default PCI_GOANY + +config PCI_GOBIOS + bool "BIOS" + ---help--- + On PCI systems, the BIOS can be used to detect the PCI devices and + determine their configuration. However, some old PCI motherboards + have BIOS bugs and may crash if this is done. Also, some embedded + 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". + +config PCI_GODIRECT + bool "Direct" + +config PCI_GOANY + bool "Any" + +endchoice + +config PCI_BIOS + bool + depends on PCI && (PCI_GOBIOS || PCI_GOANY) + default y + +config PCI_DIRECT + bool + depends on PCI && (PCI_GODIRECT || PCI_GOANY) + default y + +source "drivers/pci/Kconfig" + +config ISA + bool "ISA support" + help + Find out whether you have ISA slots on your motherboard. ISA is the + name of a bus system, i.e. the way the CPU talks to the other stuff + inside your box. If you have ISA, say Y, otherwise N. + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +endmenu + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/m32r/oprofile/Kconfig" + +menu "Kernel hacking" + +config DEBUG_KERNEL + bool "Kernel debugging" + help + Say Y here if you are developing drivers or trying to debug and + identify kernel problems. + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL + +config DEBUG_SLAB + bool "Debug memory allocations" + depends on DEBUG_KERNEL + help + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. + +config DEBUG_IOVIRT + bool "Memory mapped I/O debugging" + depends on DEBUG_KERNEL + help + Say Y here to get warned whenever an attempt is made to do I/O on + obviously invalid addresses such as those generated when ioremap() + calls are forgotten. Memory mapped I/O will go through an extra + check to catch access to unmapped ISA addresses, an access method + that can still be used by old drivers that are being ported from + 2.0/2.2. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + depends on DEBUG_KERNEL + 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 . Don't say Y + unless you really know what this hack does. + +config DEBUG_SPINLOCK + bool "Spinlock debugging" + depends on DEBUG_KERNEL + help + Say Y here and build SMP to catch missing spinlock initialization + and certain other kinds of spinlock errors commonly made. This is + best used in conjunction with the NMI watchdog so that spinlock + deadlocks are also debuggable. + +config DEBUG_PAGEALLOC + bool "Page alloc debugging" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a large slowdown, but helps to find certain types + of memory corruptions. + +config DEBUG_INFO + bool "Compile the kernel with debug info" + depends on DEBUG_KERNEL + help + If you say Y here the resulting kernel image will include + 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" + help + If you say Y here, various routines which may sleep will become very + noisy if they are called with a spinlock held. + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + 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. + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + diff -Nru a/arch/m32r/Makefile b/arch/m32r/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/Makefile 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,55 @@ +# +# m32r/Makefile +# + +LDFLAGS := +OBJCOPYFLAGS := -O binary -R .note -R .comment -S +LDFLAGS_vmlinux := -e startup_32 +LDFLAGS_BLOB := --format binary --oformat elf32-m32r + +CFLAGS += -pipe -fno-schedule-insns +CFLAGS_KERNEL += -mmodel=medium +CFLAGS_MODULE += -mmodel=large + +ifdef CONFIG_CHIP_VDEC2 +cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst +aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst +else +cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -m32r2 +aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -m32r2 +endif + +cflags-$(CONFIG_ISA_M32R) += -DNO_FPU +aflags-$(CONFIG_ISA_M32R) += -DNO_FPU -Wa,-no-bitinst + +CFLAGS += $(cflags-y) +AFLAGS += $(aflags-y) + +CHECKFLAGS := $(CHECK) -D__m32r__ + +head-y := arch/m32r/kernel/head.o arch/m32r/kernel/init_task.o + +LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +libs-y += arch/m32r/lib/ $(LIBGCC) +core-y += arch/m32r/kernel/ \ + arch/m32r/mm/ \ + arch/m32r/boot/ + +drivers-$(CONFIG_OPROFILE) += arch/m32r/oprofile/ + +boot := arch/m32r/boot + +.PHONY: zImage + +zImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +compressed: zImage + +archclean: + $(Q)$(MAKE) $(clean)=$(boot) + +define archhelp + @echo ' zImage - Compressed kernel image (arch/m32r/boot/zImage)' +endef diff -Nru a/arch/m32r/boot/Makefile b/arch/m32r/boot/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/Makefile 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,19 @@ +# +# arch/m32r/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. + +targets := zImage +subdir- := compressed + +obj-y := setup.o + +$(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo 'Kernel: $@ is ready' + +$(obj)/compressed/vmlinux: FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ + diff -Nru a/arch/m32r/boot/compressed/Makefile b/arch/m32r/boot/compressed/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/Makefile 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,38 @@ +# +# linux/arch/sh/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o \ + m32r-sio.o piggy.o vmlinux.lds +EXTRA_AFLAGS := -traditional + +OBJECTS = $(obj)/head.o $(obj)/misc.o $(obj)/m32r_sio.o + +# +# IMAGE_OFFSET is the load offset of the compression loader +# +#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x2000]) +#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x00400000]) + +LDFLAGS_vmlinux := -T + +$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.S FORCE + $(CPP) $(EXTRA_AFLAGS) -C -P -I include $< >$@ + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r-linux -T +OBJCOPYFLAGS += -R .empty_zero_page + +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) diff -Nru a/arch/m32r/boot/compressed/boot.h b/arch/m32r/boot/compressed/boot.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/boot.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,59 @@ +/* + * 1. load vmlinuz + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinuz | + * +-----------------------+ + * 2. decompressed + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinuz | + * +-----------------------+ + * | | + * BOOT_RELOC_ADDR +-----------------------+ + * | | + * KERNEL_DECOMPRESS_ADDR +-----------------------+ + * | vmlinux | + * +-----------------------+ + * + * 3. relocate copy & jump code + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinuz | + * +-----------------------+ + * | | + * BOOT_RELOC_ADDR +-----------------------+ + * | boot(copy&jump) | + * KERNEL_DECOMPRESS_ADDR +-----------------------+ + * | vmlinux | + * +-----------------------+ + * + * 4. relocate decompressed kernel + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinux | + * +-----------------------+ + * | | + * BOOT_RELOC_ADDR +-----------------------+ + * | boot(copy&jump) | + * KERNEL_DECOMPRESS_ADDR +-----------------------+ + * | | + * +-----------------------+ + * + */ +#ifdef __ASSEMBLY__ +#define __val(x) x +#else +#define __val(x) (x) +#endif + +#define DECOMPRESS_OFFSET_BASE __val(0x00900000) +#define BOOT_RELOC_SIZE __val(0x00001000) + +#define KERNEL_EXEC_ADDR __val(CONFIG_MEMORY_START) +#define KERNEL_DECOMPRESS_ADDR __val(CONFIG_MEMORY_START + \ + DECOMPRESS_OFFSET_BASE + BOOT_RELOC_SIZE) +#define KERNEL_ENTRY __val(CONFIG_MEMORY_START + 0x1000) + +#define BOOT_EXEC_ADDR __val(CONFIG_MEMORY_START) +#define BOOT_RELOC_ADDR __val(CONFIG_MEMORY_START + DECOMPRESS_OFFSET_BASE) diff -Nru a/arch/m32r/boot/compressed/head.S b/arch/m32r/boot/compressed/head.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/head.S 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,115 @@ +/* + * linux/arch/m32r/boot/compressed/head.S + * + * Copyright (c) 2001-2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * Copyright (c) 2004 Hirokazu Takata + */ + + .text +#include +#include +#include +#include +#include + + .global startup + __ALIGN +startup: + ldi r0, #0x0000 /* SPI, disable EI */ + mvtc r0, psw + +/* + * Clear BSS first so that there are no surprises... + */ +#ifdef CONFIG_ISA_DUAL_ISSUE + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + ; R4 = BSS size in longwords (rounded down) + mv r4, r3 || ldi r1, #0 + srli r4, #4 || addi r2, #-4 + beqz r4, .Lendloop1 +.Lloop1: +#ifndef CONFIG_CHIP_M32310 + ; Touch memory for the no-write-allocating cache. + ld r0, @(4,r2) +#endif + st r1, @+r2 || addi r4, #-1 + st r1, @+r2 + st r1, @+r2 + st r1, @+r2 || cmpeq r1, r4 ; R4 = 0? + bnc .Lloop1 +.Lendloop1: + and3 r4, r3, #15 + addi r2, #4 + beqz r4, .Lendloop2 +.Lloop2: + stb r1, @r2 || addi r4, #-1 + addi r2, #1 + bnez r4, .Lloop2 +.Lendloop2: + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + mv r4, r3 + srli r4, #2 ; R4 = BSS size in longwords (rounded down) + ldi r1, #0 ; clear R1 for longwords store + addi r2, #-4 ; account for pre-inc store + beqz r4, .Lendloop1 ; any more to go? +.Lloop1: + st r1, @+r2 ; yep, zero out another longword + addi r4, #-1 ; decrement count + bnez r4, .Lloop1 ; go do some more +.Lendloop1: + and3 r4, r3, #3 ; get no. of remaining BSS bytes to clear + addi r2, #4 ; account for pre-inc store + beqz r4, .Lendloop2 ; any more to go? +.Lloop2: + stb r1, @r2 ; yep, zero out another byte + addi r2, #1 ; bump address + addi r4, #-1 ; decrement count + bnez r4, .Lloop2 ; go do some more +.Lendloop2: + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + seth r0, #shigh(stack_start) + ld sp, @(r0, low(stack_start)) /* set stack point */ + +/* + * decompress the kernel + */ + bl decompress_kernel + +#if defined(CONFIG_CHIP_M32700) + /* Cache flush */ + ldi r0, -1 + ldi r1, 0xd0 ; invalidate i-cache, copy back d-cache + stb r1, @r0 +#else +#error "put your cache flush function, please" +#endif + seth r0, #high(CONFIG_MEMORY_START) + or3 r0, r0, #0x2000 + jmp r0 + + .balign 512 +fake_headers_as_bzImage: + .short 0 + .ascii "HdrS" + .short 0x0202 + .short 0 + .short 0 + .byte 0x00, 0x10 + .short 0 + .byte 0 + .byte 1 + .byte 0x00, 0x80 + .long 0 + .long 0 + diff -Nru a/arch/m32r/boot/compressed/install.sh b/arch/m32r/boot/compressed/install.sh --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/install.sh 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,57 @@ +#!/bin/sh +# +# arch/sh/boot/install.sh +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Adapted from code in arch/i386/boot/install.sh by Russell King +# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy +# Adapted from code in arch/sh/boot/install.sh by Takeo Takahashi +# +# "make install" script for sh architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x /sbin/installkernel ]; then + exec /sbin/installkernel "$@" +fi + +if [ "$2" = "zImage" ]; then +# Compressed install + echo "Installing compressed kernel" + if [ -f $4/vmlinuz-$1 ]; then + mv $4/vmlinuz-$1 $4/vmlinuz.old + fi + + if [ -f $4/System.map-$1 ]; then + mv $4/System.map-$1 $4/System.old + fi + + cat $2 > $4/vmlinuz-$1 + cp $3 $4/System.map-$1 +else +# Normal install + echo "Installing normal kernel" + if [ -f $4/vmlinux-$1 ]; then + mv $4/vmlinux-$1 $4/vmlinux.old + fi + + if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old + fi + + cat $2 > $4/vmlinux-$1 + cp $3 $4/System.map +fi diff -Nru a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/m32r_sio.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,53 @@ +/* + * arch/m32r/boot/compressed/m32r_sio.c + * + * 2003-02-12: Takeo Takahashi + * + */ + +#include +#include +#include + +void putc(char c); + +int puts(const char *s) +{ + char c; + while ((c = *s++)) putc(c); + return 0; +} + +#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) +#define USE_FPGA_MAP 0 + +#if USE_FPGA_MAP +/* + * fpga configuration program uses MMU, and define map as same as + * M32104 uT-Engine board. + */ +#define BOOT_SIO0STS (volatile unsigned short *)(0x02c00000 + 0x20006) +#define BOOT_SIO0TXB (volatile unsigned short *)(0x02c00000 + 0x2000c) +#else +#undef PLD_BASE +#define PLD_BASE 0xa4c00000 +#define BOOT_SIO0STS PLD_ESIO0STS +#define BOOT_SIO0TXB PLD_ESIO0TXB +#endif + +void putc(char c) +{ + + while ((*BOOT_SIO0STS & 0x3) != 0x3) ; + if (c == '\n') { + *BOOT_SIO0TXB = '\r'; + while ((*BOOT_SIO0STS & 0x3) != 0x3) ; + } + *BOOT_SIO0TXB = c; +} +#else +void putc(char c) +{ + /* do nothing */ +} +#endif diff -Nru a/arch/m32r/boot/compressed/misc.c b/arch/m32r/boot/compressed/misc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/misc.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,223 @@ +/* + * arch/m32r/boot/compressed/misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Adapted for SH by Stuart Menefy, Aug 1999 + * + * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000 + * + * 2003-02-12: Support M32R by Takeo Takahashi + * This is based on arch/sh/boot/compressed/misc.c. + */ + +#include +#include + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char input_data[]; +extern int input_len; + +static long bytes_out; +static uch *output_data; +static unsigned long output_ptr; + + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern int puts(const char *); + +extern int _text; /* Defined in vmlinux.lds.S */ +extern int _end; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#define HEAP_SIZE 0x10000 + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr == 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#define STACK_SIZE (4096) +long user_stack [STACK_SIZE]; +long* stack_start = &user_stack[STACK_SIZE]; + +/* return decompressed size */ +long decompress_kernel(void) +{ + insize = 0; + inptr = 0; + bytes_out = 0; + outcnt = 0; + output_data = 0; + output_ptr = CONFIG_MEMORY_START + 0x2000; + free_mem_ptr = (unsigned long)&_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + + makecrc(); + puts("Uncompressing Linux... "); + gunzip(); + puts("Ok, booting the kernel.\n"); + return bytes_out; +} diff -Nru a/arch/m32r/boot/compressed/vmlinux.lds.S b/arch/m32r/boot/compressed/vmlinux.lds.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/vmlinux.lds.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,23 @@ +#include + +OUTPUT_ARCH(m32r) +ENTRY(startup) +SECTIONS +{ + . = CONFIG_MEMORY_START + 0x00400000; + + _text = .; + .text : { *(.text) } = 0 + .rodata : { *(.rodata) } + _etext = .; + + . = ALIGN(32) + (. & (32 - 1)); + .data : { *(.data) } + _edata = .; + + . = ALIGN(32 / 8); + __bss_start = .; + .bss : { *(.bss) } + . = ALIGN(32 / 8); + _end = . ; +} diff -Nru a/arch/m32r/boot/compressed/vmlinux.scr b/arch/m32r/boot/compressed/vmlinux.scr --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/compressed/vmlinux.scr 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,9 @@ +SECTIONS +{ + .data : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; + *(.data) + input_data_end = .; + } +} diff -Nru a/arch/m32r/boot/setup.S b/arch/m32r/boot/setup.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/boot/setup.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,162 @@ +/* + * linux/arch/m32r/boot/setup.S -- A setup code. + * + * Copyright (C) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * and Hitoshi Yamamoto + * + */ +/* $Id$ */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * References to members of the boot_cpu_data structure. + */ + +#define CPU_PARAMS boot_cpu_data +#define M32R_MCICAR 0xfffffff0 +#define M32R_MCDCAR 0xfffffff4 +#define M32R_MCCR 0xfffffffc +#define M32R_BSCR0 0xffffffd2 + +;BSEL +#define BSEL0CR0 0x00ef5000 +#define BSEL0CR1 0x00ef5004 +#define BSEL1CR0 0x00ef5100 +#define BSEL1CR1 0x00ef5104 +#define BSEL0CR0_VAL 0x00000000 +#define BSEL0CR1_VAL 0x01200100 +#define BSEL1CR0_VAL 0x01018000 +#define BSEL1CR1_VAL 0x00200001 + +;SDRAMC +#define SDRAMC_SDRF0 0x00ef6000 +#define SDRAMC_SDRF1 0x00ef6004 +#define SDRAMC_SDIR0 0x00ef6008 +#define SDRAMC_SDIR1 0x00ef600c +#define SDRAMC_SD0ADR 0x00ef6020 +#define SDRAMC_SD0ER 0x00ef6024 +#define SDRAMC_SD0TR 0x00ef6028 +#define SDRAMC_SD0MOD 0x00ef602c +#define SDRAMC_SD1ADR 0x00ef6040 +#define SDRAMC_SD1ER 0x00ef6044 +#define SDRAMC_SD1TR 0x00ef6048 +#define SDRAMC_SD1MOD 0x00ef604c +#define SDRAM0 0x18000000 +#define SDRAM1 0x1c000000 + +/*------------------------------------------------------------------------ + * start up + */ + +/*------------------------------------------------------------------------ + * Kernel entry + */ + .section .boot, "ax" +ENTRY(boot) + +/* Set cache mode */ +#if defined(CONFIG_CHIP_XNUX2) + ldi r0, #-2 ;LDIMM (r0, M32R_MCCR) + ldi r1, #0x0101 ; cache on (with invalidation) +; ldi r1, #0x00 ; cache off + sth r1, @r0 +#elif defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_VDEC2) \ + || defined(CONFIG_CHIP_OPSP) + ldi r0, #-4 ;LDIMM (r0, M32R_MCCR) + ldi r1, #0x73 ; cache on (with invalidation) +; ldi r1, #0x00 ; cache off + st r1, @r0 +#else +#error unknown chip configuration +#endif + +#ifdef CONFIG_SMP + ;; if not BSP (CPU#0) goto AP_loop + seth r5, #shigh(M32R_CPUID_PORTL) + ld r5, @(low(M32R_CPUID_PORTL), r5) + bnez r5, AP_loop +#if !defined(CONFIG_PLAT_USRV) + ;; boot AP + ld24 r5, #0xeff2f8 ; IPICR7 + ldi r6, #0x2 ; IPI to CPU1 + st r6, @r5 +#endif +#endif + +/* + * Now, Jump to stext + * if with MMU, TLB on. + * if with no MMU, only jump. + */ + .global eit_vector +mmu_on: + LDIMM (r13, stext) +#ifdef CONFIG_MMU + bl init_tlb + LDIMM (r2, eit_vector) ; set EVB(cr5) + mvtc r2, cr5 + seth r0, #high(MMU_REG_BASE) ; Set MMU_REG_BASE higher + or3 r0, r0, #low(MMU_REG_BASE) ; Set MMU_REG_BASE lower + ldi r1, #0x01 + st r1, @(MATM_offset,r0) ; Set MATM (T bit ON) + ld r0, @(MATM_offset,r0) ; Check +#else + seth r0,#high(M32R_MCDCAR) + or3 r0,r0,#low(M32R_MCDCAR) + ld24 r1,#0x8080 + st r1,@r0 +#endif /* CONFIG_MMU */ + jmp r13 + nop + nop + +#ifdef CONFIG_SMP +/* + * AP wait loop + */ +ENTRY(AP_loop) + ;; disable interrupt + clrpsw #0x40 + ;; reset EVB + LDIMM (r4, _AP_RE) + seth r5, #high(__PAGE_OFFSET) + or3 r5, r5, #low(__PAGE_OFFSET) + not r5, r5 + and r4, r5 + mvtc r4, cr5 + ;; disable maskable interrupt + seth r4, #high(M32R_ICU_IMASK_PORTL) + or3 r4, r4, #low(M32R_ICU_IMASK_PORTL) + ldi r5, #0 + st r5, @r4 + ld r5, @r4 + ;; enable only IPI + setpsw #0x40 + ;; LOOOOOOOOOOOOOOP!!! + .fillinsn +2: + nop + nop + bra 2b + nop + nop + +#ifdef CONFIG_CHIP_M32700_TS1 + .global dcache_dummy + .balign 16, 0 +dcache_dummy: + .byte 16 +#endif /* CONFIG_CHIP_M32700_TS1 */ +#endif /* CONFIG_SMP */ + + .end + diff -Nru a/arch/m32r/defconfig b/arch/m32r/defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/defconfig 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,635 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +CONFIG_PLAT_M32700UT=y +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_CFC=y +CONFIG_M32700UT_CFC=y +CONFIG_CFC_NUM=1 +# CONFIG_MTD_M32R is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +CONFIG_M32R_AR=y +CONFIG_M32R_AR_VGA=y + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR 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=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# 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_HFSPLUS_FS is not set +# 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/m32r/kernel/Makefile b/arch/m32r/kernel/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/Makefile 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,20 @@ +# +# Makefile for the Linux/M32R kernel. +# + +extra-y := head.o init_task.o vmlinux.lds + +obj-y := process.o entry.o traps.o align.o irq.o setup.o time.o \ + m32r_ksyms.o sys_m32r.o semaphore.o signal.o ptrace.o + +obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_PLAT_MAPPI) += setup_mappi.o io_mappi.o +obj-$(CONFIG_PLAT_MAPPI2) += setup_mappi2.o io_mappi2.o +obj-$(CONFIG_PLAT_USRV) += setup_usrv.o io_usrv.o +obj-$(CONFIG_PLAT_M32700UT) += setup_m32700ut.o io_m32700ut.o +obj-$(CONFIG_PLAT_OPSPUT) += setup_opsput.o io_opsput.o +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_PLAT_OAKS32R) += setup_oaks32r.o io_oaks32r.o + +EXTRA_AFLAGS := -traditional + diff -Nru a/arch/m32r/kernel/align.c b/arch/m32r/kernel/align.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/align.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,585 @@ +/* + * align.c - address exception handler for M32R + * + * Copyright (c) 2003 Hitoshi Yamamoto + */ + +#include +#include +#include + +static int get_reg(struct pt_regs *regs, int nr) +{ + int val; + + if (nr < 4) + val = *(unsigned long *)(®s->r0 + nr); + else if (nr < 7) + val = *(unsigned long *)(®s->r4 + (nr - 4)); + else if (nr < 13) + val = *(unsigned long *)(®s->r7 + (nr - 7)); + else + val = *(unsigned long *)(®s->fp + (nr - 13)); + + return val; +} + +static void set_reg(struct pt_regs *regs, int nr, int val) +{ + if (nr < 4) + *(unsigned long *)(®s->r0 + nr) = val; + else if (nr < 7) + *(unsigned long *)(®s->r4 + (nr - 4)) = val; + else if (nr < 13) + *(unsigned long *)(®s->r7 + (nr - 7)) = val; + else + *(unsigned long *)(®s->fp + (nr - 13)) = val; +} + +#define REG1(insn) (((insn) & 0x0f00) >> 8) +#define REG2(insn) ((insn) & 0x000f) +#define PSW_BC 0x100 + +/* O- instruction */ +#define ISA_LD1 0x20c0 /* ld Rdest, @Rsrc */ +#define ISA_LD2 0x20e0 /* ld Rdest, @Rsrc+ */ +#define ISA_LDH 0x20a0 /* ldh Rdest, @Rsrc */ +#define ISA_LDUH 0x20b0 /* lduh Rdest, @Rsrc */ +#define ISA_ST1 0x2040 /* st Rsrc1, @Rsrc2 */ +#define ISA_ST2 0x2060 /* st Rsrc1, @+Rsrc2 */ +#define ISA_ST3 0x2070 /* st Rsrc1, @-Rsrc2 */ +#define ISA_STH1 0x2020 /* sth Rsrc1, @Rsrc2 */ +#define ISA_STH2 0x2030 /* sth Rsrc1, @Rsrc2+ */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +/* OS instruction */ +#define ISA_ADD 0x00a0 /* add Rdest, Rsrc */ +#define ISA_ADDI 0x4000 /* addi Rdest, #imm8 */ +#define ISA_ADDX 0x0090 /* addx Rdest, Rsrc */ +#define ISA_AND 0x00c0 /* and Rdest, Rsrc */ +#define ISA_CMP 0x0040 /* cmp Rsrc1, Rsrc2 */ +#define ISA_CMPEQ 0x0060 /* cmpeq Rsrc1, Rsrc2 */ +#define ISA_CMPU 0x0050 /* cmpu Rsrc1, Rsrc2 */ +#define ISA_CMPZ 0x0070 /* cmpz Rsrc */ +#define ISA_LDI 0x6000 /* ldi Rdest, #imm8 */ +#define ISA_MV 0x1080 /* mv Rdest, Rsrc */ +#define ISA_NEG 0x0030 /* neg Rdest, Rsrc */ +#define ISA_NOP 0x7000 /* nop */ +#define ISA_NOT 0x00b0 /* not Rdest, Rsrc */ +#define ISA_OR 0x00e0 /* or Rdest, Rsrc */ +#define ISA_SUB 0x0020 /* sub Rdest, Rsrc */ +#define ISA_SUBX 0x0010 /* subx Rdest, Rsrc */ +#define ISA_XOR 0x00d0 /* xor Rdest, Rsrc */ + +/* -S instruction */ +#define ISA_MUL 0x1060 /* mul Rdest, Rsrc */ +#define ISA_MULLO_A0 0x3010 /* mullo Rsrc1, Rsrc2, A0 */ +#define ISA_MULLO_A1 0x3090 /* mullo Rsrc1, Rsrc2, A1 */ +#define ISA_MVFACMI_A0 0x50f2 /* mvfacmi Rdest, A0 */ +#define ISA_MVFACMI_A1 0x50f6 /* mvfacmi Rdest, A1 */ + +static int emu_addi(unsigned short insn, struct pt_regs *regs) +{ + char imm = (char)(insn & 0xff); + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val += imm; + set_reg(regs, dest, val); + + return 0; +} + +static int emu_ldi(unsigned short insn, struct pt_regs *regs) +{ + char imm = (char)(insn & 0xff); + + set_reg(regs, REG1(insn), (int)imm); + + return 0; +} + +static int emu_add(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int src = REG2(insn); + int val; + + val = get_reg(regs, dest); + val += get_reg(regs, src); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_addx(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + unsigned int val, tmp; + + val = regs->psw & PSW_BC ? 1 : 0; + tmp = get_reg(regs, dest); + val += tmp; + val += (unsigned int)get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + /* C bit set */ + if (val < tmp) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_and(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val &= get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_cmp(unsigned short insn, struct pt_regs *regs) +{ + if (get_reg(regs, REG1(insn)) < get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_cmpeq(unsigned short insn, struct pt_regs *regs) +{ + if (get_reg(regs, REG1(insn)) == get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_cmpu(unsigned short insn, struct pt_regs *regs) +{ + if ((unsigned int)get_reg(regs, REG1(insn)) + < (unsigned int)get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_cmpz(unsigned short insn, struct pt_regs *regs) +{ + if (!get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_mv(unsigned short insn, struct pt_regs *regs) +{ + int val; + + val = get_reg(regs, REG2(insn)); + set_reg(regs, REG1(insn), val); + + return 0; +} + +static int emu_neg(unsigned short insn, struct pt_regs *regs) +{ + int val; + + val = get_reg(regs, REG2(insn)); + set_reg(regs, REG1(insn), 0 - val); + + return 0; +} + +static int emu_not(unsigned short insn, struct pt_regs *regs) +{ + int val; + + val = get_reg(regs, REG2(insn)); + set_reg(regs, REG1(insn), ~val); + + return 0; +} + +static int emu_or(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val |= get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_sub(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val -= get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_subx(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + unsigned int val, tmp; + + val = tmp = get_reg(regs, dest); + val -= (unsigned int)get_reg(regs, REG2(insn)); + val -= regs->psw & PSW_BC ? 1 : 0; + set_reg(regs, dest, val); + + /* C bit set */ + if (val > tmp) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_xor(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + unsigned int val; + + val = (unsigned int)get_reg(regs, dest); + val ^= (unsigned int)get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_mul(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int reg1, reg2; + + reg1 = get_reg(regs, dest); + reg2 = get_reg(regs, REG2(insn)); + + __asm__ __volatile__ ( + "mul %0, %1; \n\t" + : "+r" (reg1) : "r" (reg2) + ); + + set_reg(regs, dest, reg1); + + return 0; +} + +static int emu_mullo_a0(unsigned short insn, struct pt_regs *regs) +{ + int reg1, reg2; + + reg1 = get_reg(regs, REG1(insn)); + reg2 = get_reg(regs, REG2(insn)); + + __asm__ __volatile__ ( + "mullo %0, %1, a0; \n\t" + "mvfachi %0, a0; \n\t" + "mvfaclo %1, a0; \n\t" + : "+r" (reg1), "+r" (reg2) + ); + + regs->acc0h = reg1; + regs->acc0l = reg2; + + return 0; +} + +static int emu_mullo_a1(unsigned short insn, struct pt_regs *regs) +{ + int reg1, reg2; + + reg1 = get_reg(regs, REG1(insn)); + reg2 = get_reg(regs, REG2(insn)); + + __asm__ __volatile__ ( + "mullo %0, %1, a0; \n\t" + "mvfachi %0, a0; \n\t" + "mvfaclo %1, a0; \n\t" + : "+r" (reg1), "+r" (reg2) + ); + + regs->acc1h = reg1; + regs->acc1l = reg2; + + return 0; +} + +static int emu_mvfacmi_a0(unsigned short insn, struct pt_regs *regs) +{ + unsigned long val; + + val = (regs->acc0h << 16) | (regs->acc0l >> 16); + set_reg(regs, REG1(insn), (int)val); + + return 0; +} + +static int emu_mvfacmi_a1(unsigned short insn, struct pt_regs *regs) +{ + unsigned long val; + + val = (regs->acc1h << 16) | (regs->acc1l >> 16); + set_reg(regs, REG1(insn), (int)val); + + return 0; +} + +static int emu_m32r2(unsigned short insn, struct pt_regs *regs) +{ + int res = -1; + + if ((insn & 0x7fff) == ISA_NOP) /* nop */ + return 0; + + switch(insn & 0x7000) { + case ISA_ADDI: /* addi Rdest, #imm8 */ + res = emu_addi(insn, regs); + break; + case ISA_LDI: /* ldi Rdest, #imm8 */ + res = emu_ldi(insn, regs); + break; + default: + break; + } + + if (!res) + return 0; + + switch(insn & 0x70f0) { + case ISA_ADD: /* add Rdest, Rsrc */ + res = emu_add(insn, regs); + break; + case ISA_ADDX: /* addx Rdest, Rsrc */ + res = emu_addx(insn, regs); + break; + case ISA_AND: /* and Rdest, Rsrc */ + res = emu_and(insn, regs); + break; + case ISA_CMP: /* cmp Rsrc1, Rsrc2 */ + res = emu_cmp(insn, regs); + break; + case ISA_CMPEQ: /* cmpeq Rsrc1, Rsrc2 */ + res = emu_cmpeq(insn, regs); + break; + case ISA_CMPU: /* cmpu Rsrc1, Rsrc2 */ + res = emu_cmpu(insn, regs); + break; + case ISA_CMPZ: /* cmpz Rsrc */ + res = emu_cmpz(insn, regs); + break; + case ISA_MV: /* mv Rdest, Rsrc */ + res = emu_mv(insn, regs); + break; + case ISA_NEG: /* neg Rdest, Rsrc */ + res = emu_neg(insn, regs); + break; + case ISA_NOT: /* not Rdest, Rsrc */ + res = emu_not(insn, regs); + break; + case ISA_OR: /* or Rdest, Rsrc */ + res = emu_or(insn, regs); + break; + case ISA_SUB: /* sub Rdest, Rsrc */ + res = emu_sub(insn, regs); + break; + case ISA_SUBX: /* subx Rdest, Rsrc */ + res = emu_subx(insn, regs); + break; + case ISA_XOR: /* xor Rdest, Rsrc */ + res = emu_xor(insn, regs); + break; + case ISA_MUL: /* mul Rdest, Rsrc */ + res = emu_mul(insn, regs); + break; + case ISA_MULLO_A0: /* mullo Rsrc1, Rsrc2 */ + res = emu_mullo_a0(insn, regs); + break; + case ISA_MULLO_A1: /* mullo Rsrc1, Rsrc2 */ + res = emu_mullo_a1(insn, regs); + break; + default: + break; + } + + if (!res) + return 0; + + switch(insn & 0x70ff) { + case ISA_MVFACMI_A0: /* mvfacmi Rdest */ + res = emu_mvfacmi_a0(insn, regs); + break; + case ISA_MVFACMI_A1: /* mvfacmi Rdest */ + res = emu_mvfacmi_a1(insn, regs); + break; + default: + break; + } + + return res; +} + +#endif /* CONFIG_ISA_DUAL_ISSUE */ + +/* + * ld : ?010 dest 1100 src + * 0010 dest 1110 src : ld Rdest, @Rsrc+ + * ldh : ?010 dest 1010 src + * lduh : ?010 dest 1011 src + * st : ?010 src1 0100 src2 + * 0010 src1 0110 src2 : st Rsrc1, @+Rsrc2 + * 0010 src1 0111 src2 : st Rsrc1, @-Rsrc2 + * sth : ?010 src1 0010 src2 + */ + +static int insn_check(unsigned long insn, struct pt_regs *regs, + unsigned char **ucp) +{ + int res = 0; + + /* + * 32bit insn + * ld Rdest, @(disp16, Rsrc) + * st Rdest, @(disp16, Rsrc) + */ + if (insn & 0x80000000) { /* 32bit insn */ + *ucp += (short)(insn & 0x0000ffff); + regs->bpc += 4; + } else { /* 16bit insn */ +#ifdef CONFIG_ISA_DUAL_ISSUE + /* parallel exec check */ + if (!(regs->bpc & 0x2) && insn & 0x8000) { + res = emu_m32r2((unsigned short)insn, regs); + regs->bpc += 4; + } else +#endif /* CONFIG_ISA_DUAL_ISSUE */ + regs->bpc += 2; + } + + return res; +} + +static int emu_ld(unsigned long insn32, struct pt_regs *regs) +{ + unsigned char *ucp; + unsigned long val; + unsigned short insn16; + int size, src; + + insn16 = insn32 >> 16; + src = REG2(insn16); + ucp = (unsigned char *)get_reg(regs, src); + + if (insn_check(insn32, regs, &ucp)) + return -1; + + size = insn16 & 0x0040 ? 4 : 2; + if (copy_from_user(&val, ucp, size)) + return -1; + + if (size == 2) + val >>= 16; + + /* ldh sign check */ + if ((insn16 & 0x00f0) == 0x00a0 && (val & 0x8000)) + val |= 0xffff0000; + + set_reg(regs, REG1(insn16), val); + + /* ld increment check */ + if ((insn16 & 0xf0f0) == ISA_LD2) /* ld Rdest, @Rsrc+ */ + set_reg(regs, src, (unsigned long)(ucp + 4)); + + return 0; +} + +static int emu_st(unsigned long insn32, struct pt_regs *regs) +{ + unsigned char *ucp; + unsigned long val; + unsigned short insn16; + int size, src2; + + insn16 = insn32 >> 16; + src2 = REG2(insn16); + + ucp = (unsigned char *)get_reg(regs, src2); + + if (insn_check(insn32, regs, &ucp)) + return -1; + + size = insn16 & 0x0040 ? 4 : 2; + val = get_reg(regs, REG1(insn16)); + if (size == 2) + val <<= 16; + + /* st inc/dec check */ + if ((insn16 & 0xf0e0) == 0x2060) { + if (insn16 & 0x0010) + ucp -= 4; + else + ucp += 4; + + set_reg(regs, src2, (unsigned long)ucp); + } + + if (copy_to_user(ucp, &val, size)) + return -1; + + /* sth inc check */ + if ((insn16 & 0xf0f0) == ISA_STH2) { + ucp += 2; + set_reg(regs, src2, (unsigned long)ucp); + } + + return 0; +} + +int handle_unaligned_access(unsigned long insn32, struct pt_regs *regs) +{ + unsigned short insn16; + int res; + + insn16 = insn32 >> 16; + + /* ld or st check */ + if ((insn16 & 0x7000) != 0x2000) + return -1; + + /* insn alignment check */ + if ((insn16 & 0x8000) && (regs->bpc & 3)) + return -1; + + if (insn16 & 0x0080) /* ld */ + res = emu_ld(insn32, regs); + else /* st */ + res = emu_st(insn32, regs); + + return res; +} + diff -Nru a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/entry.S 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,999 @@ +/* + * linux/arch/m32r/kernel/entry.S + * + * Copyright (c) 2001, 2002 Hirokazu Takata, Hitoshi Yamamoto, H. Kondo + * Copyright (c) 2003 Hitoshi Yamamoto + * Copyright (c) 2004 Hirokazu Takata + * + * Taken from i386 version. + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * Stack layout in 'ret_from_system_call': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in fork.c:copy_process, signal.c:do_signal, + * ptrace.c and ptrace.h + * + * M32Rx/M32R2 M32R + * @(sp) - r4 ditto + * @(0x04,sp) - r5 ditto + * @(0x08,sp) - r6 ditto + * @(0x0c,sp) - *pt_regs ditto + * @(0x10,sp) - r0 ditto + * @(0x14,sp) - r1 ditto + * @(0x18,sp) - r2 ditto + * @(0x1c,sp) - r3 ditto + * @(0x20,sp) - r7 ditto + * @(0x24,sp) - r8 ditto + * @(0x28,sp) - r9 ditto + * @(0x2c,sp) - r10 ditto + * @(0x30,sp) - r11 ditto + * @(0x34,sp) - r12 ditto + * @(0x38,sp) - syscall_nr ditto + * @(0x3c,sp) - acc0h @(0x3c,sp) - acch + * @(0x40,sp) - acc0l @(0x40,sp) - accl + * @(0x44,sp) - acc1h @(0x44,sp) - psw + * @(0x48,sp) - acc1l @(0x48,sp) - bpc + * @(0x4c,sp) - psw @(0x4c,sp) - bbpsw + * @(0x50,sp) - bpc @(0x50,sp) - bbpc + * @(0x54,sp) - bbpsw @(0x54,sp) - spu (cr3) + * @(0x58,sp) - bbpc @(0x58,sp) - fp (r13) + * @(0x5c,sp) - spu (cr3) @(0x5c,sp) - lr (r14) + * @(0x60,sp) - fp (r13) @(0x60,sp) - spi (cr12) + * @(0x64,sp) - lr (r14) @(0x64,sp) - orig_r0 + * @(0x68,sp) - spi (cr2) + * @(0x6c,sp) - orig_r0 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_MMU) +#define sys_madvise sys_ni_syscall +#define sys_readahead sys_ni_syscall +#define sys_mprotect sys_ni_syscall +#define sys_msync sys_ni_syscall +#define sys_mlock sys_ni_syscall +#define sys_munlock sys_ni_syscall +#define sys_mlockall sys_ni_syscall +#define sys_munlockall sys_ni_syscall +#define sys_mremap sys_ni_syscall +#define sys_mincore sys_ni_syscall +#endif /* CONFIG_MMU */ + +#define R4(reg) @reg +#define R5(reg) @(0x04,reg) +#define R6(reg) @(0x08,reg) +#define PTREGS(reg) @(0x0C,reg) +#define R0(reg) @(0x10,reg) +#define R1(reg) @(0x14,reg) +#define R2(reg) @(0x18,reg) +#define R3(reg) @(0x1C,reg) +#define R7(reg) @(0x20,reg) +#define R8(reg) @(0x24,reg) +#define R9(reg) @(0x28,reg) +#define R10(reg) @(0x2C,reg) +#define R11(reg) @(0x30,reg) +#define R12(reg) @(0x34,reg) +#define SYSCALL_NR(reg) @(0x38,reg) +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) +#define ACC0H(reg) @(0x3C,reg) +#define ACC0L(reg) @(0x40,reg) +#define ACC1H(reg) @(0x44,reg) +#define ACC1L(reg) @(0x48,reg) +#define PSW(reg) @(0x4C,reg) +#define BPC(reg) @(0x50,reg) +#define BBPSW(reg) @(0x54,reg) +#define BBPC(reg) @(0x58,reg) +#define SPU(reg) @(0x5C,reg) +#define FP(reg) @(0x60,reg) /* FP = R13 */ +#define LR(reg) @(0x64,reg) +#define SP(reg) @(0x68,reg) +#define ORIG_R0(reg) @(0x6C,reg) +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) +#define ACCH(reg) @(0x3C,reg) +#define ACCL(reg) @(0x40,reg) +#define PSW(reg) @(0x44,reg) +#define BPC(reg) @(0x48,reg) +#define BBPSW(reg) @(0x4C,reg) +#define BBPC(reg) @(0x50,reg) +#define SPU(reg) @(0x54,reg) +#define FP(reg) @(0x58,reg) /* FP = R13 */ +#define LR(reg) @(0x5C,reg) +#define SP(reg) @(0x60,reg) +#define ORIG_R0(reg) @(0x64,reg) +#else +#error unknown isa configuration +#endif + +CF_MASK = 0x00000001 +TF_MASK = 0x00000100 +IF_MASK = 0x00000200 +DF_MASK = 0x00000400 +NT_MASK = 0x00004000 +VM_MASK = 0x00020000 + +#ifdef CONFIG_PREEMPT +#define preempt_stop(x) CLI(x) +#else +#define preempt_stop(x) +#define resume_kernel restore_all +#endif + +ENTRY(ret_from_fork) + ld r0, @sp+ + bl schedule_tail + GET_THREAD_INFO(r8) + bra syscall_exit + +/* + * Return to user mode is not as complex as all this looks, + * but we want the default path for a system call return to + * go as quickly as possible which is why some of this is + * less clear than it otherwise should be. + */ + + ; userspace resumption stub bypassing syscall exit tracing + ALIGN +ret_from_exception: + preempt_stop(r4) +ret_from_intr: + ld r4, PSW(sp) +#ifdef CONFIG_ISA_M32R2 + and3 r4, r4, #0x8800 ; check BSM and BPM bits +#else + and3 r4, r4, #0x8000 ; check BSM bit +#endif + beqz r4, resume_kernel +ENTRY(resume_userspace) + CLI(r4) ; make sure we don't miss an interrupt + ; setting need_resched or sigpending + ; between sampling and the iret + GET_THREAD_INFO(r8) + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done on + ; int/exception return? + bnez r4, work_pending + bra restore_all + +#ifdef CONFIG_PREEMPT +ENTRY(resume_kernel) + GET_THREAD_INFO(r8) + ld r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ? + bnez r9, restore_all +need_resched: + ld r9, @(TI_FLAGS, r8) ; need_resched set ? + and3 r4, r9, #_TIF_NEED_RESCHED + beqz r4, restore_all + ld r4, PSW(sp) ; interrupts off (exception path) ? + and3 r4, r4, #0x4000 + beqz r4, restore_all + LDIMM (r4, PREEMPT_ACTIVE) + st r4, @(TI_PRE_COUNT, r8) + STI(r4) + bl schedule + ldi r4, #0 + st r4, @(TI_PRE_COUNT, r8) + CLI(r4) + bra need_resched +#endif + + ; system call handler stub +ENTRY(system_call) + SWITCH_TO_KERNEL_STACK + SAVE_ALL + STI(r4) ; Enable interrupt + st sp, PTREGS(sp) ; implicit pt_regs parameter + cmpui r7, #NR_syscalls + bnc syscall_badsys + st r7, SYSCALL_NR(sp) ; syscall_nr + ; system call tracing in operation + GET_THREAD_INFO(r8) + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_SYSCALL_TRACE + bnez r4, syscall_trace_entry +syscall_call: + slli r7, #2 ; table jump for the system call + LDIMM (r4, sys_call_table) + add r7, r4 + ld r7, @r7 + jl r7 ; execute system call + st r0, R0(sp) ; save the return value +syscall_exit: + CLI(r4) ; make sure we don't miss an interrupt + ; setting need_resched or sigpending + ; between sampling and the iret + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_ALLWORK_MASK ; current->work + bnez r4, syscall_exit_work +restore_all: + RESTORE_ALL + + # perform work that needs to be done immediately before resumption + # r9 : frags + ALIGN +work_pending: + and3 r4, r9, #_TIF_NEED_RESCHED + beqz r4, work_notifysig +work_resched: + bl schedule + CLI(r4) ; make sure we don't miss an interrupt + ; setting need_resched or sigpending + ; between sampling and the iret + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done other + ; than syscall tracing? + beqz r4, restore_all + and3 r4, r4, #_TIF_NEED_RESCHED + bnez r4, work_resched + +work_notifysig: ; deal with pending signals and + ; notify-resume requests + mv r0, sp ; arg1 : struct pt_regs *regs + ldi r1, #0 ; arg2 : sigset_t *oldset + mv r2, r9 ; arg3 : __u32 thread_info_flags + bl do_notify_resume + bra restore_all + + ; perform syscall exit tracing + ALIGN +syscall_trace_entry: + ldi r4, #-ENOSYS + st r4, R0(sp) + bl do_syscall_trace + ld r0, ORIG_R0(sp) + ld r1, R1(sp) + ld r2, R2(sp) + ld r3, R3(sp) + ld r4, R4(sp) + ld r5, R5(sp) + ld r6, R6(sp) + ld r7, SYSCALL_NR(sp) + cmpui r7, #NR_syscalls + bc syscall_call + bra syscall_exit + + ; perform syscall exit tracing + ALIGN +syscall_exit_work: + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_SYSCALL_TRACE + beqz r4, work_pending + STI(r4) ; could let do_syscall_trace() call + ; schedule() instead + bl do_syscall_trace + bra resume_userspace + + ALIGN +syscall_fault: + SAVE_ALL + GET_THREAD_INFO(r8) + ldi r4, #-EFAULT + st r4, R0(sp) + bra resume_userspace + + ALIGN +syscall_badsys: + ldi r4, #-ENOSYS + st r4, R0(sp) + bra resume_userspace + + .global eit_vector + + .equ ei_vec_table, eit_vector + 0x0200 + +/* + * EI handler routine + */ +ENTRY(ei_handler) +#if defined(CONFIG_CHIP_M32700) + SWITCH_TO_KERNEL_STACK + ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI). +#endif + SAVE_ALL + mv r1, sp ; arg1(regs) +#if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \ + || defined(CONFIG_CHIP_OPSP) + +; GET_ICU_STATUS; + seth r0, #shigh(M32R_ICU_ISTS_ADDR) + ld r0, @(low(M32R_ICU_ISTS_ADDR),r0) + st r0, @-sp +#if defined(CONFIG_SMP) + /* + * If IRQ == 0 --> Nothing to do, Not write IMASK + * If IRQ == IPI --> Do IPI handler, Not write IMASK + * If IRQ != 0, IPI --> Do do_IRQ(), Write IMASK + */ + slli r0, #4 + srli r0, #24 ; r0(irq_num<<2) + ;; IRQ exist check +#if defined(CONFIG_CHIP_M32700) + /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */ + beqz r0, 3f ; if (!irq_num) goto exit +#else + beqz r0, 1f ; if (!irq_num) goto exit +#endif /* WORKAROUND */ + ;; IPI check + cmpi r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check + bc 2f + cmpi r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check + bnc 2f + LDIMM (r2, ei_vec_table) + add r2, r0 + ld r2, @r2 + beqz r2, 1f ; if (no IPI handler) goto exit + mv r0, r1 ; arg0(regs) + jl r2 + .fillinsn +1: + addi sp, #4 + bra ret_to_intr +#if defined(CONFIG_CHIP_M32700) + /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */ + .fillinsn +3: + ld24 r14, #0x00070000 + seth r0, #shigh(M32R_ICU_IMASK_ADDR) + st r14, @(low(M32R_ICU_IMASK_ADDR), r0) + addi sp, #4 + bra ret_to_intr +#endif /* WORKAROUND */ + ;; do_IRQ + .fillinsn +2: + srli r0, #2 +#if defined(CONFIG_PLAT_USRV) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, 9f + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + .fillinsn +9: +#elif defined(CONFIG_PLAT_M32700UT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(M32700UT_LAN_ICUISTS) + or3 r0, r0, #low(M32700UT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(M32700UT_LCD_ICUISTS) + or3 r0, r0, #low(M32700UT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#elif defined(CONFIG_PLAT_OPSPUT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(OPSPUT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(OPSPUT_LAN_ICUISTS) + or3 r0, r0, #low(OPSPUT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(OPSPUT_LCD_ICUISTS) + or3 r0, r0, #low(OPSPUT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#endif /* CONFIG_PLAT_OPSPUT */ + bl do_IRQ ; r0(irq), r1(regs) +#else /* not CONFIG_SMP */ + srli r0, #22 ; r0(irq) +#if defined(CONFIG_PLAT_USRV) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, 1f + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + .fillinsn +1: +#elif defined(CONFIG_PLAT_M32700UT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(M32700UT_LAN_ICUISTS) + or3 r0, r0, #low(M32700UT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(M32700UT_LCD_ICUISTS) + or3 r0, r0, #low(M32700UT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#elif defined(CONFIG_PLAT_OPSPUT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(OPSPUT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(OPSPUT_LAN_ICUISTS) + or3 r0, r0, #low(OPSPUT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(OPSPUT_LCD_ICUISTS) + or3 r0, r0, #low(OPSPUT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#endif /* CONFIG_PLAT_OPSPUT */ + bl do_IRQ +#endif /* CONFIG_SMP */ + ld r14, @sp+ + seth r0, #shigh(M32R_ICU_IMASK_ADDR) + st r14, @(low(M32R_ICU_IMASK_ADDR),r0) +#else +#error no chip configuration +#endif +ret_to_intr: + bra ret_from_intr + +/* + * Default EIT handler + */ + ALIGN +int_msg: + .asciz "Unknown interrupt\n" + .byte 0 + +ENTRY(default_eit_handler) + push r0 + mvfc r0, psw + push r1 + push r2 + push r3 + push r0 + LDIMM (r0, __KERNEL_DS) + mv r0, r1 + mv r0, r2 + LDIMM (r0, int_msg) + bl printk + pop r0 + pop r3 + pop r2 + pop r1 + mvtc r0, psw + pop r0 +infinit: + bra infinit + +#ifdef CONFIG_MMU +/* + * Access Exception handler + */ +ENTRY(ace_handler) + SWITCH_TO_KERNEL_STACK + SAVE_ALL + + seth r2, #shigh(MMU_REG_BASE) /* Check status register */ + ld r4, @(low(MESTS_offset),r2) + st r4, @(low(MESTS_offset),r2) + srl3 r1, r4, #4 +#ifdef CONFIG_CHIP_M32700 + and3 r1, r1, #0x0000ffff + ; WORKAROUND: ignore TME bit for the M32700(TS1). +#endif /* CONFIG_CHIP_M32700 */ + beqz r1, inst +oprand: + ld r2, @(low(MDEVA_offset),r2) ; set address + srli r2, #12 + slli r2, #12 + srli r1, #1 + bra 1f +inst: + and3 r1, r4, #2 + srli r1, #1 + or3 r1, r1, #8 + mvfc r2, bpc ; set address + .fillinsn +1: + mvfc r3, psw + mv r0, sp + and3 r3, r3, 0x800 + srli r3, #9 + or r1, r3 + /* + * do_page_fault(): + * r0 : struct pt_regs *regs + * r1 : unsigned long error-code + * r2 : unsigned long address + * error-code: + * +------+------+------+------+ + * | bit3 | bit2 | bit1 | bit0 | + * +------+------+------+------+ + * bit 3 == 0:means data, 1:means instruction + * bit 2 == 0:means kernel, 1:means user-mode + * bit 1 == 0:means read, 1:means write + * bit 0 == 0:means no page found 1:means protection fault + * + */ + bl do_page_fault + bra ret_from_intr +#endif /* CONFIG_MMU */ + + +ENTRY(alignment_check) +/* void alignment_check(int error_code) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + ldi r1, #0x30 ; error_code + mv r0, sp ; pt_regs + bl do_alignment_check +error_code: + bra ret_from_exception + +ENTRY(rie_handler) +/* void rie_handler(int error_code) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + mvfc r0, bpc + ld r1, @r0 + seth r0, #0xa0f0 + st r1, @r0 + ldi r1, #0x20 ; error_code + mv r0, sp ; pt_regs + bl do_rie_handler + bra error_code + +ENTRY(pie_handler) +/* void pie_handler(int error_code) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + ldi r1, #0 ; error_code ; FIXME + mv r0, sp ; pt_regs + bl do_pie_handler + bra error_code + +ENTRY(debug_trap) + .global withdraw_debug_trap + /* void debug_trap(void) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + mv r0, sp ; pt_regs + bl withdraw_debug_trap + ldi r1, #0 ; error_code + mv r0, sp ; pt_regs + bl do_debug_trap + bra error_code + + +/* Cache flushing handler */ +ENTRY(cache_flushing_handler) + .global _flush_cache_all + /* void _flush_cache_all(void); */ + SWITCH_TO_KERNEL_STACK + push r0 + push r1 + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push lr + bl _flush_cache_all + pop lr + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + pop r0 + rte + +.data +ENTRY(sys_call_table) + .long sys_restart_syscall /* 0 - old "setup()" system call*/ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_lchown + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid + .long sys_getuid + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_cacheflush /* for M32R */ /* old stty syscall holder */ + .long sys_cachectl /* for M32R */ /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 - old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid + .long sys_getgid + .long sys_signal + .long sys_geteuid + .long sys_getegid /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall /* sys_olduname */ + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid /* 70 */ + .long sys_setregid + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups /* 80 */ + .long sys_setgroups + .long sys_ni_syscall /* sys_oldselect */ + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long old_readdir + .long sys_ni_syscall /* 90 - old_mmap syscall holder */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm */ + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_uname + .long sys_ni_syscall /* 110 - iopl */ + .long sys_vhangup + .long sys_ni_syscall /* for idle */ + .long sys_ni_syscall /* for vm86old */ + .long sys_wait4 + .long sys_swapoff /* 115 */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_ni_syscall /* sys_modify_ldt */ + .long sys_adjtimex + .long sys_mprotect /* 125 */ + .long sys_sigprocmask + .long sys_ni_syscall /* sys_create_module */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130 sys_get_kernel_syms */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid + .long sys_setfsgid + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_mremap + .long sys_setresuid + .long sys_getresuid /* 165 */ + .long sys_tas /* vm86 */ + .long sys_ni_syscall /* sys_query_module */ + .long sys_poll + .long sys_nfsservctl + .long sys_setresgid /* 170 */ + .long sys_getresgid + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_chown + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_lchown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_chown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_mincore + .long sys_madvise + .long sys_getdents64 /* 220 */ + .long sys_fcntl64 + .long sys_ni_syscall /* reserved for TUX */ + .long sys_ni_syscall /* Reserved for Security */ + .long sys_gettid + .long sys_readahead /* 225 */ + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr /* 230 */ + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr /* 235 */ + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_tkill + .long sys_sendfile64 + .long sys_futex /* 240 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_ni_syscall /* reserved for "set_thread_area" system call */ + .long sys_ni_syscall /* reserved for "get_thread_area" system call */ + .long sys_io_setup /* 245 */ + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel + .long sys_fadvise64 /* 250 */ + .long sys_ni_syscall + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 255 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 270 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_ni_syscall /* Reserved for sys_vserver */ + .long sys_ni_syscall /* Reserved for sys_mbind */ + .long sys_ni_syscall /* Reserved for sys_get_mempolicy */ + .long sys_ni_syscall /* Reserved for sys_set_mempolicy */ + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive /* 280 */ + .long sys_mq_notify + .long sys_mq_getsetattr + .long sys_ni_syscall /* reserved for kexec */ + .long sys_waitid + +syscall_table_size=(.-sys_call_table) + diff -Nru a/arch/m32r/kernel/head.S b/arch/m32r/kernel/head.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/head.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,287 @@ +/* + * linux/arch/m32r/kernel/head.S + * + * M32R startup code. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +/* $Id$ */ + +#include +__INIT +__INITDATA + + .text +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * References to members of the boot_cpu_data structure. + */ + .text + .global start_kernel + .global __bss_start + .global _end +ENTRY(stext) +ENTRY(_stext) +ENTRY(startup_32) + /* Setup up the stack pointer */ + LDIMM (r0, spi_stack_top) + LDIMM (r1, spu_stack_top) + mvtc r0, spi + mvtc r1, spu + + /* Initilalize PSW */ + ldi r0, #0x0000 /* use SPI, disable EI */ + mvtc r0, psw + + /* Set up the stack pointer */ + LDIMM (r0, stack_start) + ld r0, @r0 + mvtc r0, spi + +/* + * Clear BSS first so that there are no surprises... + */ +#ifdef CONFIG_ISA_DUAL_ISSUE + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + ; R4 = BSS size in longwords (rounded down) + mv r4, r3 || ldi r1, #0 + srli r4, #4 || addi r2, #-4 + beqz r4, .Lendloop1 +.Lloop1: +#ifndef CONFIG_CHIP_M32310 + ; Touch memory for the no-write-allocating cache. + ld r0, @(4,r2) +#endif + st r1, @+r2 || addi r4, #-1 + st r1, @+r2 + st r1, @+r2 + st r1, @+r2 || cmpeq r1, r4 ; R4 = 0? + bnc .Lloop1 +.Lendloop1: + and3 r4, r3, #15 + addi r2, #4 + beqz r4, .Lendloop2 +.Lloop2: + stb r1, @r2 || addi r4, #-1 + addi r2, #1 + bnez r4, .Lloop2 +.Lendloop2: + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + mv r4, r3 + srli r4, #2 ; R4 = BSS size in longwords (rounded down) + ldi r1, #0 ; clear R1 for longwords store + addi r2, #-4 ; account for pre-inc store + beqz r4, .Lendloop1 ; any more to go? +.Lloop1: + st r1, @+r2 ; yep, zero out another longword + addi r4, #-1 ; decrement count + bnez r4, .Lloop1 ; go do some more +.Lendloop1: + and3 r4, r3, #3 ; get no. of remaining BSS bytes to clear + addi r2, #4 ; account for pre-inc store + beqz r4, .Lendloop2 ; any more to go? +.Lloop2: + stb r1, @r2 ; yep, zero out another byte + addi r2, #1 ; bump address + addi r4, #-1 ; decrement count + bnez r4, .Lloop2 ; go do some more +.Lendloop2: + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +#if 0 /* M32R_FIXME */ +/* + * Copy data segment from ROM to RAM. + */ + .global ROM_D, TOP_DATA, END_DATA + + LDIMM (r1, ROM_D) + LDIMM (r2, TOP_DATA) + LDIMM (r3, END_DATA) + addi r2, #-4 + addi r3, #-4 +loop1: + ld r0, @r1+ + st r0, @+r2 + cmp r2, r3 + bc loop1 +#endif /* 0 */ + +/* Jump to kernel */ + LDIMM (r2, start_kernel) + jl r2 + .fillinsn +1: + bra 1b ; main should never return here, but + ; just in case, we know what happens. + +#ifdef CONFIG_SMP +/* + * AP startup routine + */ + .text + .global eit_vector +ENTRY(startup_AP) +;; setup EVB + LDIMM (r4, eit_vector) + mvtc r4, cr5 + +;; enable MMU + LDIMM (r2, init_tlb) + jl r2 + seth r4, #high(MATM) + or3 r4, r4, #low(MATM) + ldi r5, #0x01 + st r5, @r4 ; Set MATM Reg(T bit ON) + ld r6, @r4 ; MATM Check + LDIMM (r5, 1f) + jmp r5 ; enable MMU + nop + .fillinsn +1: +;; ISN check + ld r6, @r4 ; MATM Check + seth r4, #high(M32R_ICU_ISTS_ADDR) + or3 r4, r4, #low(M32R_ICU_ISTS_ADDR) + ld r5, @r4 ; Read ISTSi reg. + mv r6, r5 + slli r5, #13 ; PIML check + srli r5, #13 ; + seth r4, #high(M32R_ICU_IMASK_ADDR) + or3 r4, r4, #low(M32R_ICU_IMASK_ADDR) + st r5, @r4 ; Write IMASKi reg. + slli r6, #4 ; ISN check + srli r6, #26 ; + seth r4, #high(M32R_IRQ_IPI5) + or3 r4, r4, #low(M32R_IRQ_IPI5) + bne r4, r6, 2f ; if (ISN != CPU_BOOT_IPI) goto sleep; + +;; check cpu_bootout_map and set cpu_bootin_map + LDIMM (r4, cpu_bootout_map) + ld r4, @r4 + seth r5, #high(M32R_CPUID_PORTL) + or3 r5, r5, #low(M32R_CPUID_PORTL) + ld r5, @r5 + ldi r6, #1 + sll r6, r5 + and r4, r6 + beqz r4, 2f + LDIMM (r4, cpu_bootin_map) + ld r5, @r4 + or r5, r6 + st r6, @r4 + +;; clear PSW + ldi r4, #0 + mvtc r4, psw + +;; setup SPI + LDIMM (r4, stack_start) + ld r4, @r4 + mvtc r4, spi + +;; setup BPC (start_secondary) + LDIMM (r4, start_secondary) + mvtc r4, bpc + + rte ; goto startup_secondary + nop + nop + + .fillinsn +2: + ;; disable MMU + seth r4, #high(MATM) + or3 r4, r4, #low(MATM) + ldi r5, #0 + st r5, @r4 ; Set MATM Reg(T bit OFF) + ld r6, @r4 ; MATM Check + LDIMM (r4, 3f) + seth r5, #high(__PAGE_OFFSET) + or3 r5, r5, #low(__PAGE_OFFSET) + not r5, r5 + and r4, r5 + jmp r4 ; disable MMU + nop + .fillinsn +3: + ;; SLEEP and wait IPI + LDIMM (r4, AP_loop) + seth r5, #high(__PAGE_OFFSET) + or3 r5, r5, #low(__PAGE_OFFSET) + not r5, r5 + and r4, r5 + jmp r4 + nop + nop +#endif /* CONFIG_SMP */ + +ENTRY(stack_start) + .long init_thread_union+8192 + .long __KERNEL_DS + +/* + * This is initialized to create a identity-mapping at 0-4M (for bootup + * purposes) and another mapping of the 0-4M area at virtual address + * PAGE_OFFSET. + */ + .text + +#define MOUNT_ROOT_RDONLY 1 +#define RAMDISK_FLAGS 0 ; 1024KB +#define ORIG_ROOT_DEV 0x0100 ; /dev/ram0 (major:01, minor:00) +#define LOADER_TYPE 1 ; (??? - non-zero value seems + ; to be needed to boot from initrd) + +#define COMMAND_LINE "" + + .section .empty_zero_page, "aw" +ENTRY(empty_zero_page) + .long MOUNT_ROOT_RDONLY /* offset: +0x00 */ + .long RAMDISK_FLAGS + .long ORIG_ROOT_DEV + .long LOADER_TYPE + .long 0 /* INITRD_START */ /* +0x10 */ + .long 0 /* INITRD_SIZE */ + .long 0 /* CPU_CLOCK */ + .long 0 /* BUS_CLOCK */ + .long 0 /* TIMER_DIVIDE */ /* +0x20 */ + .balign 256,0 + .asciz COMMAND_LINE + .byte 0 + .balign 4096,0,4096 + +/*------------------------------------------------------------------------ + * Stack area + */ + .section .spi + ALIGN + .global spi_stack_top + .zero 1024 +spi_stack_top: + + .section .spu + ALIGN + .global spu_stack_top + .zero 1024 +spu_stack_top: + + .end diff -Nru a/arch/m32r/kernel/init_task.c b/arch/m32r/kernel/init_task.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/init_task.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,41 @@ +/* orig : i386 init_task.c */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct fs_struct init_fs = INIT_FS; +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); +struct mm_struct init_mm = INIT_MM(init_mm); + +EXPORT_SYMBOL(init_mm); + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + +EXPORT_SYMBOL(init_task); + diff -Nru a/arch/m32r/kernel/io_m32700ut.c b/arch/m32r/kernel/io_m32700ut.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/io_m32700ut.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,455 @@ +/* + * linux/arch/m32r/kernel/io_mappi.c + * + * Typical I/O routines for M32700UT board. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ + +#define PORT2ADDR(port) _port2addr(port) +#define PORT2ADDR_USB(port) _port2addr_usb(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) +static __inline__ void *__port2addr_ata(unsigned long port) +{ + static int dummy_reg; + + switch (port) { + case 0x1f0: return (void *)0xac002000; + case 0x1f1: return (void *)0xac012800; + case 0x1f2: return (void *)0xac012002; + case 0x1f3: return (void *)0xac012802; + case 0x1f4: return (void *)0xac012004; + case 0x1f5: return (void *)0xac012804; + case 0x1f6: return (void *)0xac012006; + case 0x1f7: return (void *)0xac012806; + case 0x3f6: return (void *)0xac01200e; + default: return (void *)&dummy_reg; + } +} +#endif + +/* + * M32700UT-LAN is located in the extended bus space + * from 0x10000000 to 0x13ffffff on physical address. + * The base address of LAN controller(LAN91C111) is 0x300. + */ +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x10000000); +} +static __inline__ void *_port2addr_usb(unsigned long port) +{ + return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return *(volatile unsigned char *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned char *buf = (unsigned char *)addr; + + while (count--) *buf++ = _ne_inb(portp); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)portp = b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = cpu_to_le16(w); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inb(PORT2ADDR_NE(port)); + +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned char *)__port2addr_ata(port); + } +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inw(PORT2ADDR_NE(port)); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned short *)__port2addr_ata(port); + } +#endif +#if defined(CONFIG_USB) + else if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned char *)__port2addr_ata(port); + } else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned short *)__port2addr_ata(port); + } else +#endif +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned char *)__port2addr_ata(port) = b; + } else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned short *)__port2addr_ata(port) = w; + } else +#endif +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned char *)__port2addr_ata(port) = b; + } else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned short *)__port2addr_ata(port) = w; + } else +#endif +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_insb(PORT2ADDR_NE(port), addr, count); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + unsigned char *buf = addr; + unsigned char *portp = __port2addr_ata(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } +#endif + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to read data + * from the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while(count--) *(volatile unsigned char *)portp = *buf++; +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to write data + * into the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while(count--) *(volatile unsigned short *)portp = *buf++; +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while(count--) *(volatile unsigned short *)portp = *buf++; +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff -Nru a/arch/m32r/kernel/io_mappi.c b/arch/m32r/kernel/io_mappi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/io_mappi.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,368 @@ +/* + * linux/arch/m32r/kernel/io_mappi.c + * + * Typical I/O routines for Mappi board. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +/* $Id: io_mappi.c,v 1.9 2003/12/02 07:18:08 fujiwara Exp $ */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) +#define M32R_PCC_IOSTART1 0x2000 +#define M32R_PCC_IOEND1 (M32R_PCC_IOSTART1 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_M32RPCC */ + +#define PORT2ADDR(port) _port2addr(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)((port<<1) + NONCACHE_OFFSET + 0x0C000000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return (unsigned char) *(volatile unsigned short *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + unsigned short tmp; + + tmp = *(volatile unsigned short *)portp; + return le16_to_cpu(tmp); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned short *)portp = (unsigned short)b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = cpu_to_le16(w); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread(0, port, &b, sizeof(b), 1, 0); + return b; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned char b; + pcc_ioread(1, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread(0, port, &w, sizeof(w), 1, 0); + return w; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned short w; + pcc_ioread(1, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread(0, port, &l, sizeof(l), 1, 0); + return l; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned short l; + pcc_ioread(1, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread(0, port, &b, sizeof(b), 1, 0); + return b; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned char b; + pcc_ioread(1, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread(0, port, &w, sizeof(w), 1, 0); + return w; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned short w; + pcc_ioread(1, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &b, sizeof(b), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &w, sizeof(w), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &l, sizeof(l), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &b, sizeof(b), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &w, sizeof(w), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320){ + portp = PORT2ADDR_NE(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_ioread(1, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = _ne_inw(portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_ioread(1, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outw(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff -Nru a/arch/m32r/kernel/io_mappi2.c b/arch/m32r/kernel/io_mappi2.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/io_mappi2.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,370 @@ +/* + * linux/arch/m32r/kernel/io_mappi2.c + * + * Typical I/O routines for Mappi2 board. + * + * Copyright (c) 2001-2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +/* $Id:$ */ + +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_MAPPI2_CFC */ + +#define PORT2ADDR(port) _port2addr(port) +#define PORT2ADDR_NE(port) _port2addr_ne(port) +#define PORT2ADDR_USB(port) _port2addr_usb(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +#ifdef CONFIG_CHIP_OPSP +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x10000000); +} +#else +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x04000000); +} +#endif +static __inline__ void *_port2addr_usb(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x14000000); +} +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return (unsigned char) *(volatile unsigned char *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ +#if 1 /* byte swap */ + unsigned short tmp,tmp2; + tmp = *(volatile unsigned short *)portp; + tmp2 = (tmp>>8|tmp<<8); + return tmp2; +#else + return *(volatile unsigned short *)portp; +#endif +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned short tmp; + unsigned char *buf = addr; + + tmp = *(volatile unsigned char *)portp; + while (count--) *buf++ = *(volatile unsigned char *)portp; +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)portp = (unsigned char)b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = (w>>8|w<<8); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inb(PORT2ADDR_NE(port)); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inw(PORT2ADDR_NE(port)); +#if defined(CONFIG_USB) + else if (port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if (port >= 0x340 && port < 0x3a0) + v = *(volatile unsigned short *)PORT2ADDR_USB(port); + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if (port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if (port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_insb(PORT2ADDR_NE(port), addr, count); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } +#endif + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + portp = PORT2ADDR_NE(port); + while (count--) *(volatile unsigned short *)portp = *buf++; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff -Nru a/arch/m32r/kernel/io_oaks32r.c b/arch/m32r/kernel/io_oaks32r.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/io_oaks32r.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,243 @@ +/* + * linux/arch/m32r/kernel/io_oaks32r.c + * + * Typical I/O routines for OAKS32R board. + * + * Copyright (c) 2001-2004 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +/* $Id$ */ + +#include +#include +#include +#include + +#define PORT2ADDR(port) _port2addr(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)((port<<1) + NONCACHE_OFFSET + 0x02000000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return *(volatile unsigned char *)(portp+1); +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + unsigned short tmp; + + tmp = *(unsigned short *)(portp) & 0xff; + tmp |= *(unsigned short *)(portp+2) << 8; + return tmp; +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned char *buf = addr; + while (count--) *buf++ = *(volatile unsigned char *)(portp+1); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)(portp+1) = b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = (w >> 8); + *(volatile unsigned short *)(portp+2) = (w & 0xff); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inb(PORT2ADDR_NE(port)); + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inw(PORT2ADDR_NE(port)); + + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inb(PORT2ADDR_NE(port)); + else + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inw(PORT2ADDR_NE(port)); + else + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= 0x300 && port < 0x320) + _ne_insb(PORT2ADDR_NE(port), addr, count); + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = _ne_inw(portp); + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outw(*buf++, portp); + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff -Nru a/arch/m32r/kernel/io_opsput.c b/arch/m32r/kernel/io_opsput.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/io_opsput.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,377 @@ +/* + * linux/arch/m32r/kernel/io_mappi.c + * + * Typical I/O routines for OPSPUT board. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ + +#define PORT2ADDR(port) _port2addr(port) +#define PORT2ADDR_USB(port) _port2addr_usb(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +/* + * OPSPUT-LAN is located in the extended bus space + * from 0x10000000 to 0x13ffffff on physical address. + * The base address of LAN controller(LAN91C111) is 0x300. + */ +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x10000000); +} +static __inline__ void *_port2addr_usb(unsigned long port) +{ + return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return *(volatile unsigned char *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned char *buf = (unsigned char *)addr; + + while (count--) *buf++ = _ne_inb(portp); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)portp = b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = cpu_to_le16(w); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inb(PORT2ADDR_NE(port)); + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inw(PORT2ADDR_NE(port)); +#if defined(CONFIG_USB) + else if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); + else +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_insb(PORT2ADDR_NE(port), addr, count); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } +#endif + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to read data + * from the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to write data + * into the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while(count--) *(volatile unsigned short *)portp = *buf++; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff -Nru a/arch/m32r/kernel/io_usrv.c b/arch/m32r/kernel/io_usrv.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/io_usrv.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,247 @@ +/* + * linux/arch/m32r/kernel/io_usrv.c + * + * Typical I/O routines for uServer board. + * + * Copyright (c) 2001 - 2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + */ + +#include +#include +#include +#include + +#include +#include "../drivers/m32r_cfc.h" + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#define CFC_IOSTART CFC_IOPORT_BASE +#define CFC_IOEND (CFC_IOSTART + (M32R_PCC_MAPSIZE * M32R_MAX_PCC) - 1) + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) +#define UART0_REGSTART 0x04c20000 +#define UART1_REGSTART 0x04c20100 +#define UART_IOMAP_SIZE 8 +#define UART0_IOSTART 0x3f8 +#define UART0_IOEND (UART0_IOSTART + UART_IOMAP_SIZE - 1) +#define UART1_IOSTART 0x2f8 +#define UART1_IOEND (UART1_IOSTART + UART_IOMAP_SIZE - 1) +#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ + +#define PORT2ADDR(port) _port2addr(port) + +static __inline__ void *_port2addr(unsigned long port) +{ +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + if (port >= UART0_IOSTART && port <= UART0_IOEND) + port = ((port - UART0_IOSTART) << 1) + UART0_REGSTART; + else if (port >= UART1_IOSTART && port <= UART1_IOEND) + port = ((port - UART1_IOSTART) << 1) + UART1_REGSTART; +#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ + return (void *)(port + NONCACHE_OFFSET); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char b; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else { + b = *(volatile unsigned char *)PORT2ADDR(port); + delay(); + return b; + } +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short w; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else { + w = *(volatile unsigned short *)PORT2ADDR(port); + delay(); + return w; + } +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + + return v; +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + else + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_ioread_byte(0, port, addr, sizeof(unsigned char), count, 1); + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_ioread_word(0, port, addr, sizeof(unsigned short), count, + 1); + else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) + *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), + count, 1); + else { + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, (void *)addr, sizeof(unsigned short), + count, 1); + else { + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned long *)portp = *buf++; +} diff -Nru a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/irq.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,1020 @@ +/* + * linux/arch/m32r/kernel/irq.c + * + * Copyright (c) 2003, 2004 Hitoshi Yamamoto + * + * Taken from i386 2.6.4 version. + */ + +/* + * linux/arch/i386/kernel/irq.c + * + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + */ + +/* + * (mostly architecture independent, will move to kernel/irq.c in 2.5.) + * + * IRQs are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; + +static void register_irq_proc (unsigned int irq); + +/* + * Special irq handlers. + */ + +irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ return IRQ_NONE; } + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesn't deserve + * a generic callback i think. + */ + printk("unexpected IRQ trap at vector %02x\n", irq); +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +atomic_t irq_err_count; +atomic_t irq_mis_count; + +/* + * Generic, controller-independent functions: + */ + +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *) v, j; + struct irqaction * action; + unsigned long flags; + + if (i == 0) { + seq_printf(p, " "); + for (j=0; jtypename); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + 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, "ERR: %10u\n", atomic_read(&irq_err_count)); + seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); + } + return 0; +} + +#ifdef CONFIG_SMP +inline void synchronize_irq(unsigned int irq) +{ + while (irq_desc[irq].status & IRQ_INPROGRESS) + cpu_relax(); +} +#endif + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, + struct pt_regs *regs, struct irqaction *action) +{ + int status = 1; /* Force the "do bottom halves" bit */ + int ret, retval = 0; + + if (!(action->flags & SA_INTERRUPT)) + local_irq_enable(); + + do { + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + action = action->next; + retval |= ret; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + local_irq_disable(); + return retval; +} + +static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + struct irqaction *action; + + if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { + printk(KERN_ERR "irq event %d: bogus return value %x\n", + irq, action_ret); + } else { + printk(KERN_ERR "irq %d: nobody cared!\n", irq); + } + dump_stack(); + printk(KERN_ERR "handlers:\n"); + action = desc->action; + do { + printk(KERN_ERR "[<%p>]", action->handler); + print_symbol(" (%s)", + (unsigned long)action->handler); + printk("\n"); + action = action->next; + } while (action); +} + +static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + static int count = 100; + + if (count) { + count--; + __report_bad_irq(irq, desc, action_ret); + } +} + +static int noirqdebug; + +static int __init noirqdebug_setup(char *str) +{ + noirqdebug = 1; + printk("IRQ lockup detection disabled\n"); + return 1; +} + +__setup("noirqdebug", noirqdebug_setup); + +/* + * If 99,900 of the previous 100,000 interrupts have not been handled then + * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to + * turn the IRQ off. + * + * (The other 100-of-100,000 interrupts may have been a correctly-functioning + * device sharing an IRQ with the failing one) + * + * Called under desc->lock + */ +static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + if (action_ret != IRQ_HANDLED) { + desc->irqs_unhandled++; + if (action_ret != IRQ_NONE) + report_bad_irq(irq, desc, action_ret); + } + + desc->irq_count++; + if (desc->irq_count < 100000) + return; + + desc->irq_count = 0; + if (desc->irqs_unhandled > 99900) { + /* + * The interrupt is stuck + */ + __report_bad_irq(irq, desc, action_ret); + /* + * Now kill the IRQ + */ + printk(KERN_EMERG "Disabling IRQ #%d\n", irq); + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + desc->irqs_unhandled = 0; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + +inline void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + disable_irq_nosync(irq); + if (desc->action) + synchronize_irq(irq); +} + +/** + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + irq_desc_t *desc = irq_desc + irq; + struct irqaction * action; + unsigned int status; + + irq_enter(); + +#ifdef CONFIG_DEBUG_STACKOVERFLOW + /* FIXME M32R */ +#endif + kstat_this_cpu.irqs[irq]++; + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (unlikely(!action)) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + irqreturn_t action_ret; + + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); + if (likely(!(desc->status & IRQ_PENDING))) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); + + irq_exit(); + +#if defined(CONFIG_SMP) + if (irq == M32R_IRQ_MFT2) + smp_send_timer(); +#endif /* CONFIG_SMP */ + + return 1; +} + +int can_request_irq(unsigned int irq, unsigned long irqflags) +{ + struct irqaction *action; + + if (irq >= NR_IRQS) + return 0; + action = irq_desc[irq].action; + if (action) { + if (irqflags & action->flags & SA_SHIRQ) + action = NULL; + } + return !action; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + cpus_clear(action->mask); + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +EXPORT_SYMBOL(request_irq); + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function must not be called from interrupt context. + */ + +void free_irq(unsigned int irq, void *dev_id) +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + synchronize_irq(irq); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return; + } +} + +EXPORT_SYMBOL(free_irq); + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + +unsigned long probe_irq_on(void) +{ + unsigned int i; + irq_desc_t *desc; + unsigned long val; + unsigned long delay; + + down(&probe_sem); + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ barrier(); + + /* + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; + } + spin_unlock_irq(&desc->lock); + } + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ barrier(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; + } + spin_unlock_irq(&desc->lock); + } + + return val; +} + +EXPORT_SYMBOL(probe_irq_on); + +/* + * Return a mask of triggered interrupts (this + * can handle only legacy ISA interrupts). + */ + +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. + */ +unsigned int probe_irq_mask(unsigned long val) +{ + int i; + unsigned int mask; + + mask = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (i < 16 && !(status & IRQ_WAITING)) + mask |= 1 << i; + + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + return mask & val; +} + +/* + * Return the one interrupt that triggered (this can + * handle any interrupt source). + */ + +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. + */ + +int probe_irq_off(unsigned long val) +{ + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +EXPORT_SYMBOL(probe_irq_off); + +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; + + if (desc->handler == &no_irq_type) + return -ENOSYS; + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS); + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); + return 0; +} + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; + +#ifdef CONFIG_SMP + +static struct proc_dir_entry *smp_affinity_entry[NR_IRQS]; + +cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL }; + +static int irq_affinity_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]); + if (count - len < 2) + return -EINVAL; + len += sprintf(page + len, "\n"); + return len; +} + +static int irq_affinity_write_proc(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int irq = (long)data, full_count = count, err; + cpumask_t new_value, tmp; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = cpumask_parse(buffer, count, new_value); + if (err) + return err; + + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + cpus_and(tmp, new_value, cpu_online_map); + if (cpus_empty(tmp)) + return -EINVAL; + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, + cpumask_of_cpu(first_cpu(new_value))); + + return full_count; +} + +#endif + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); + if (count - len < 2) + return -EINVAL; + len += sprintf(page + len, "\n"); + return len; +} + +static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + cpumask_t *mask = (cpumask_t *)data; + unsigned long full_count = count, err; + cpumask_t new_value; + + err = cpumask_parse(buffer, count, new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || + irq_dir[irq]) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + +#ifdef CONFIG_SMP + { + struct proc_dir_entry *entry; + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } + + smp_affinity_entry[irq] = entry; + } +#endif +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + if (!entry) + return; + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) + register_irq_proc(i); +} + diff -Nru a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/m32r_ksyms.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) +extern struct drive_info_struct drive_info; +EXPORT_SYMBOL(drive_info); +#endif + +/* platform dependent support */ +EXPORT_SYMBOL(boot_cpu_data); +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down_trylock); + +/* Networking helper routines. */ +/* Delay loops */ +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(__delay); +EXPORT_SYMBOL(__const_udelay); + +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); + +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); + +EXPORT_SYMBOL(strncpy_from_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(clear_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(__generic_copy_from_user); +EXPORT_SYMBOL(__generic_copy_to_user); +EXPORT_SYMBOL(strnlen_user); + +#ifdef CONFIG_SMP +#ifdef CONFIG_CHIP_M32700_TS1 +extern void *dcache_dummy; +EXPORT_SYMBOL(dcache_dummy); +#endif +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(cpu_callout_map); + +/* Global SMP stuff */ +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(smp_call_function); + +/* TLB flushing */ +EXPORT_SYMBOL(smp_flush_tlb_page); +EXPORT_SYMBOL_GPL(smp_flush_tlb_all); +#endif + +/* compiler generated symbol */ +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __lshldi3(void); +extern void __lshrdi3(void); +extern void __muldi3(void); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__lshldi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__muldi3); + +/* memory and string operations */ +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(memcpy); +/* EXPORT_SYMBOL(memcpy_fromio); // not implement yet */ +/* EXPORT_SYMBOL(memcpy_toio); // not implement yet */ +EXPORT_SYMBOL(memset); +/* EXPORT_SYMBOL(memset_io); // not implement yet */ +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(copy_page); +EXPORT_SYMBOL(clear_page); + +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strncpy); + +EXPORT_SYMBOL(_inb); +EXPORT_SYMBOL(_inw); +EXPORT_SYMBOL(_inl); +EXPORT_SYMBOL(_outb); +EXPORT_SYMBOL(_outw); +EXPORT_SYMBOL(_outl); +EXPORT_SYMBOL(_inb_p); +EXPORT_SYMBOL(_inw_p); +EXPORT_SYMBOL(_inl_p); +EXPORT_SYMBOL(_outb_p); +EXPORT_SYMBOL(_outw_p); +EXPORT_SYMBOL(_outl_p); +EXPORT_SYMBOL(_insb); +EXPORT_SYMBOL(_insw); +EXPORT_SYMBOL(_insl); +EXPORT_SYMBOL(_outsb); +EXPORT_SYMBOL(_outsw); +EXPORT_SYMBOL(_outsl); +EXPORT_SYMBOL(_readb); +EXPORT_SYMBOL(_readw); +EXPORT_SYMBOL(_readl); +EXPORT_SYMBOL(_writeb); +EXPORT_SYMBOL(_writew); +EXPORT_SYMBOL(_writel); + diff -Nru a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/module.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,253 @@ +/* Kernel module help for M32R. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc_exec(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +#define COPY_UNALIGNED_WORD(sw, tw, align) \ +{ \ + void *__s = &(sw), *__t = &(tw); \ + unsigned short *__s2 = __s, *__t2 =__t; \ + unsigned char *__s1 = __s, *__t1 =__t; \ + switch ((align)) \ + { \ + case 0: \ + *(unsigned long *) __t = *(unsigned long *) __s; \ + break; \ + case 2: \ + *__t2++ = *__s2++; \ + *__t2 = *__s2; \ + break; \ + default: \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1 = *__s1; \ + break; \ + } \ +} + +#define COPY_UNALIGNED_HWORD(sw, tw, align) \ + { \ + void *__s = &(sw), *__t = &(tw); \ + unsigned short *__s2 = __s, *__t2 =__t; \ + unsigned char *__s1 = __s, *__t1 =__t; \ + switch ((align)) \ + { \ + case 0: \ + *__t2 = *__s2; \ + break; \ + default: \ + *__t1++ = *__s1++; \ + *__t1 = *__s1; \ + break; \ + } \ + } + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + Elf32_Addr relocation; + uint32_t *location; + uint32_t value; + unsigned short *hlocation; + unsigned short hvalue; + int svalue; + int align; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + relocation = sym->st_value + rel[i].r_addend; + align = (int)location & 3; + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_M32R_32_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_HI16_ULO_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + relocation = (relocation >>16) & 0xffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_HI16_SLO_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + if (relocation & 0x8000) relocation += 0x10000; + relocation = (relocation >>16) & 0xffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_16_RELA: + hlocation = (unsigned short *)location; + relocation = relocation & 0xffff; + /* RELA must has 0 at relocation field. */ + hvalue = relocation; + COPY_UNALIGNED_WORD (hvalue, *hlocation, align); + break; + case R_M32R_SDA16_RELA: + case R_M32R_LO16_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + relocation = relocation & 0xffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_24_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + relocation = relocation & 0xffffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_18_PCREL_RELA: + relocation = (relocation - (Elf32_Addr) location); + if (relocation < -0x20000 || 0x1fffc < relocation) + { + printk(KERN_ERR "module %s: relocation overflow: %u\n", + me->name, relocation); + return -ENOEXEC; + } + COPY_UNALIGNED_WORD (*location, value, align); + if (value & 0xffff) + { + /* RELA must has 0 at relocation field. */ + printk(KERN_ERR "module %s: illegal relocation field: %u\n", + me->name, value); + return -ENOEXEC; + } + relocation = (relocation >> 2) & 0xffff; + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_10_PCREL_RELA: + hlocation = (unsigned short *)location; + relocation = (relocation - (Elf32_Addr) location); + COPY_UNALIGNED_HWORD (*hlocation, hvalue, align); + svalue = (int)hvalue; + svalue = (signed char)svalue << 2; + relocation += svalue; + relocation = (relocation >> 2) & 0xff; + hvalue = hvalue & 0xff00; + hvalue += relocation; + COPY_UNALIGNED_HWORD (hvalue, *hlocation, align); + break; + case R_M32R_26_PCREL_RELA: + relocation = (relocation - (Elf32_Addr) location); + if (relocation < -0x2000000 || 0x1fffffc < relocation) + { + printk(KERN_ERR "module %s: relocation overflow: %u\n", + me->name, relocation); + return -ENOEXEC; + } + COPY_UNALIGNED_WORD (*location, value, align); + if (value & 0xffffff) + { + /* RELA must has 0 at relocation field. */ + printk(KERN_ERR "module %s: illegal relocation field: %u\n", + me->name, value); + return -ENOEXEC; + } + relocation = (relocation >> 2) & 0xffffff; + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ +#if 0 + printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +#endif + return 0; + +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff -Nru a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/process.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,356 @@ +/* + * linux/arch/m32r/kernel/process.c + * orig : sh + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + * Taken from sh version. + * Copyright (C) 1995 Linus Torvalds + * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + */ + +#undef DEBUG_PROCESS +#ifdef DEBUG_PROCESS +#define DPRINTK(fmt, args...) printk("%s:%d:%s: " fmt, __FILE__, __LINE__, \ + __FUNCTION__, ##args) +#else +#define DPRINTK(fmt, args...) +#endif + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +static int hlt_counter=0; + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + return tsk->thread.lr; +} + +/* + * Powermanagement idle function, if any.. + */ +void (*pm_idle)(void) = NULL; + +void disable_hlt(void) +{ + hlt_counter++; +} + +EXPORT_SYMBOL(disable_hlt); + +void enable_hlt(void) +{ + hlt_counter--; +} + +EXPORT_SYMBOL(enable_hlt); + +/* + * We use this is we don't have any better + * idle routine.. + */ +void default_idle(void) +{ + /* M32R_FIXME: Please use "cpu_sleep" mode. */ + cpu_relax(); +} + +/* + * On SMP it's slightly faster (but much more power-consuming!) + * to poll the ->work.need_resched flag instead of waiting for the + * cross-CPU IPI to arrive. Use this option with caution. + */ +static void poll_idle (void) +{ + /* M32R_FIXME */ + cpu_relax(); +} + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle (void) +{ + /* endless idle loop with no priority at all */ + while (1) { + while (!need_resched()) { + void (*idle)(void) = pm_idle; + + if (!idle) + idle = default_idle; + + idle(); + } + schedule(); + } +} + +void machine_restart(char *__unused) +{ + printk("Please push reset button!\n"); + while (1) + cpu_relax(); +} + +EXPORT_SYMBOL(machine_restart); + +void machine_halt(void) +{ + printk("Please push reset button!\n"); + while (1) + cpu_relax(); +} + +EXPORT_SYMBOL(machine_halt); + +void machine_power_off(void) +{ + /* M32R_FIXME */ +} + +EXPORT_SYMBOL(machine_power_off); + +static int __init idle_setup (char *str) +{ + if (!strncmp(str, "poll", 4)) { + printk("using poll in idle threads.\n"); + pm_idle = poll_idle; + } else if (!strncmp(str, "sleep", 4)) { + printk("using sleep in idle threads.\n"); + pm_idle = default_idle; + } + + return 1; +} + +__setup("idle=", idle_setup); + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("BPC[%08lx]:PSW[%08lx]:LR [%08lx]:FP [%08lx]\n", \ + regs->bpc, regs->psw, regs->lr, regs->fp); + printk("BBPC[%08lx]:BBPSW[%08lx]:SPU[%08lx]:SPI[%08lx]\n", \ + regs->bbpc, regs->bbpsw, regs->spu, regs->spi); + printk("R0 [%08lx]:R1 [%08lx]:R2 [%08lx]:R3 [%08lx]\n", \ + regs->r0, regs->r1, regs->r2, regs->r3); + printk("R4 [%08lx]:R5 [%08lx]:R6 [%08lx]:R7 [%08lx]\n", \ + regs->r4, regs->r5, regs->r6, regs->r7); + printk("R8 [%08lx]:R9 [%08lx]:R10[%08lx]:R11[%08lx]\n", \ + regs->r8, regs->r9, regs->r10, regs->r11); + printk("R12[%08lx]\n", \ + regs->r12); + +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + printk("ACC0H[%08lx]:ACC0L[%08lx]\n", \ + regs->acc0h, regs->acc0l); + printk("ACC1H[%08lx]:ACC1L[%08lx]\n", \ + regs->acc1h, regs->acc1l); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + printk("ACCH[%08lx]:ACCL[%08lx]\n", \ + regs->acch, regs->accl); +#else +#error unknown isa configuration +#endif +} + +/* + * Create a kernel thread + */ + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg) +{ + fn(arg); + do_exit(-1); +} + +int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof (regs)); + regs.r1 = (unsigned long)fn; + regs.r2 = (unsigned long)arg; + + regs.bpc = (unsigned long)kernel_thread_helper; + + regs.psw = M32R_PSW_BIE; + + /* Ok, create the new process. */ + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, + NULL); +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + /* Nothing to do. */ + DPRINTK("pid = %d\n", current->pid); +} + +void flush_thread(void) +{ + DPRINTK("pid = %d\n", current->pid); + memset(¤t->thread.debug_trap, 0, sizeof(struct debug_trap)); +} + +void release_thread(struct task_struct *dead_task) +{ + /* do nothing */ + DPRINTK("pid = %d\n", dead_task->pid); +} + +/* Fill in the fpu structure for a core dump.. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) +{ + return 0; /* Task didn't use the fpu at all. */ +} + +int copy_thread(int nr, unsigned long clone_flags, unsigned long spu, + unsigned long unused, struct task_struct *tsk, struct pt_regs *regs) +{ + struct pt_regs *childregs; + unsigned long sp = (unsigned long)tsk->thread_info + THREAD_SIZE; + extern void ret_from_fork(void); + + tsk->set_child_tid = tsk->clear_child_tid = NULL; + + /* Copy registers */ + sp -= sizeof (struct pt_regs); + childregs = (struct pt_regs *)sp; + *childregs = *regs; + + childregs->spu = spu; + childregs->r0 = 0; /* Child gets zero as return value */ + regs->r0 = tsk->pid; + tsk->thread.sp = (unsigned long)childregs; + tsk->thread.lr = (unsigned long)ret_from_fork; + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + /* M32R_FIXME */ +} + +/* + * Capture the user space registers if the task is not running (in user space) + */ +int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) +{ + /* M32R_FIXME */ + return 1; +} + +asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, + struct pt_regs regs) +{ +#ifdef CONFIG_MMU + return do_fork(SIGCHLD, regs.spu, ®s, 0, NULL, NULL); +#else + return -EINVAL; +#endif /* CONFIG_MMU */ +} + +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, + unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, struct pt_regs regs) +{ + if (!newsp) + newsp = regs.spu; + + return do_fork(clone_flags, newsp, ®s, 0, NULL, NULL); +} + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, + struct pt_regs regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, ®s, 0, + NULL, NULL); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, char __user * __user *uenvp, + unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, + struct pt_regs regs) +{ + int error; + char *filename; + + filename = getname(ufilename); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + + error = do_execve(filename, uargv, uenvp, ®s); + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); +out: + return error; +} + +/* + * These bracket the sleeping functions.. + */ +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + /* M32R_FIXME */ + return (0); +} + diff -Nru a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/ptrace.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,858 @@ +/* + * linux/arch/m32r/kernel/ptrace.c + * + * Copyright (C) 2002 Hirokazu Takata, Takeo Takahashi + * Copyright (C) 2004 Hirokazu Takata + * + * Original x86 implementation: + * By Ross Biro 1/23/92 + * edited by Linus Torvalds + * + * Some code taken from sh version: + * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka + * Some code taken from arm version: + * Copyright (C) 2000 Russell King + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + * + * Note: if a user thread is execve'd from kernel space, the + * kernel stack will not be empty on entry to the kernel, so + * ptracing these tasks will fail. + */ +static inline struct pt_regs * +get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task->thread_info + THREAD_SIZE + - sizeof(struct pt_regs)); +} + +/* + * This routine will get a word off of the process kernel stack. + */ +static inline unsigned long int +get_stack_long(struct task_struct *task, int offset) +{ + unsigned long *stack; + + stack = (unsigned long *)get_user_regs(task); + + return stack[offset]; +} + +/* + * This routine will put a word on the process kernel stack. + */ +static inline int +put_stack_long(struct task_struct *task, int offset, unsigned long data) +{ + unsigned long *stack; + + stack = (unsigned long *)get_user_regs(task); + stack[offset] = data; + + return 0; +} + +static int reg_offset[] = { + PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, + PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_FP, PT_LR, PT_SPU, +}; + +/* + * Read the word at offset "off" into the "struct user". We + * actually access the pt_regs stored on the kernel stack. + */ +static int ptrace_read_user(struct task_struct *tsk, unsigned long off, + unsigned long __user *data) +{ + unsigned long tmp; +#ifndef NO_FPU + struct user * dummy = NULL; +#endif + + if ((off & 3) || (off < 0) || (off > sizeof(struct user) - 3)) + return -EIO; + + off >>= 2; + switch (off) { + case PT_EVB: + __asm__ __volatile__ ( + "mvfc %0, cr5 \n\t" + : "=r" (tmp) + ); + break; + case PT_CBR: { + unsigned long psw; + psw = get_stack_long(tsk, PT_PSW); + tmp = ((psw >> 8) & 1); + } + break; + case PT_PSW: { + unsigned long psw, bbpsw; + psw = get_stack_long(tsk, PT_PSW); + bbpsw = get_stack_long(tsk, PT_BBPSW); + tmp = ((psw >> 8) & 0xff) | ((bbpsw & 0xff) << 8); + } + break; + case PT_PC: + tmp = get_stack_long(tsk, PT_BPC); + break; + case PT_BPC: + off = PT_BBPC; + /* fall through */ + default: + if (off < (sizeof(struct pt_regs) >> 2)) + tmp = get_stack_long(tsk, off); +#ifndef NO_FPU + else if (off >= (long)(&dummy->fpu >> 2) && + off < (long)(&dummy->u_fpvalid >> 2)) { + if (!tsk->used_math) { + if (off == (long)(&dummy->fpu.fpscr >> 2)) + tmp = FPSCR_INIT; + else + tmp = 0; + } else + tmp = ((long *)(&tsk->thread.fpu >> 2)) + [off - (long)&dummy->fpu]; + } else if (off == (long)(&dummy->u_fpvalid >> 2)) + tmp = tsk->used_math; +#endif /* not NO_FPU */ + else + tmp = 0; + } + + return put_user(tmp, data); +} + +static int ptrace_write_user(struct task_struct *tsk, unsigned long off, + unsigned long data) +{ + int ret = -EIO; +#ifndef NO_FPU + struct user * dummy = NULL; +#endif + + if ((off & 3) || off < 0 || + off > sizeof(struct user) - 3) + return -EIO; + + off >>= 2; + switch (off) { + case PT_EVB: + case PT_BPC: + case PT_SPI: + /* We don't allow to modify evb. */ + ret = 0; + break; + case PT_PSW: + case PT_CBR: { + /* We allow to modify only cbr in psw */ + unsigned long psw; + psw = get_stack_long(tsk, PT_PSW); + psw = (psw & ~0x100) | ((data & 1) << 8); + ret = put_stack_long(tsk, PT_PSW, psw); + } + break; + case PT_PC: + off = PT_BPC; + data &= ~1; + /* fall through */ + default: + if (off < (sizeof(struct pt_regs) >> 2)) + ret = put_stack_long(tsk, off, data); +#ifndef NO_FPU + else if (off >= (long)(&dummy->fpu >> 2) && + off < (long)(&dummy->u_fpvalid >> 2)) { + tsk->used_math = 1; + ((long *)&tsk->thread.fpu) + [off - (long)&dummy->fpu] = data; + ret = 0; + } else if (off == (long)(&dummy->u_fpvalid >> 2)) { + tsk->used_math = data ? 1 : 0; + ret = 0; + } +#endif /* not NO_FPU */ + break; + } + + return ret; +} + +/* + * Get all user integer registers. + */ +static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) +{ + struct pt_regs *regs = get_user_regs(tsk); + + return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; +} + +/* + * Set all user integer registers. + */ +static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) +{ + struct pt_regs newregs; + int ret; + + ret = -EFAULT; + if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { + struct pt_regs *regs = get_user_regs(tsk); + *regs = newregs; + ret = 0; + } + + return ret; +} + + +static inline int +check_condition_bit(struct task_struct *child) +{ + return (int)((get_stack_long(child, PT_PSW) >> 8) & 1); +} + +static int +check_condition_src(unsigned long op, unsigned long regno1, + unsigned long regno2, struct task_struct *child) +{ + unsigned long reg1, reg2; + + reg2 = get_stack_long(child, reg_offset[regno2]); + + switch (op) { + case 0x0: /* BEQ */ + reg1 = get_stack_long(child, reg_offset[regno1]); + return reg1 == reg2; + case 0x1: /* BNE */ + reg1 = get_stack_long(child, reg_offset[regno1]); + return reg1 != reg2; + case 0x8: /* BEQZ */ + return reg2 == 0; + case 0x9: /* BNEZ */ + return reg2 != 0; + case 0xa: /* BLTZ */ + return (int)reg2 < 0; + case 0xb: /* BGEZ */ + return (int)reg2 >= 0; + case 0xc: /* BLEZ */ + return (int)reg2 <= 0; + case 0xd: /* BGTZ */ + return (int)reg2 > 0; + default: + /* never reached */ + return 0; + } +} + +static void +compute_next_pc_for_16bit_insn(unsigned long insn, unsigned long pc, + unsigned long *next_pc, + struct task_struct *child) +{ + unsigned long op, op2, op3; + unsigned long disp; + unsigned long regno; + int parallel = 0; + + if (insn & 0x00008000) + parallel = 1; + if (pc & 3) + insn &= 0x7fff; /* right slot */ + else + insn >>= 16; /* left slot */ + + op = (insn >> 12) & 0xf; + op2 = (insn >> 8) & 0xf; + op3 = (insn >> 4) & 0xf; + + if (op == 0x7) { + switch (op2) { + case 0xd: /* BNC */ + case 0x9: /* BNCL */ + if (!check_condition_bit(child)) { + disp = (long)(insn << 24) >> 22; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0x8: /* BCL */ + case 0xc: /* BC */ + if (check_condition_bit(child)) { + disp = (long)(insn << 24) >> 22; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0xe: /* BL */ + case 0xf: /* BRA */ + disp = (long)(insn << 24) >> 22; + *next_pc = (pc & ~0x3) + disp; + return; + break; + } + } else if (op == 0x1) { + switch (op2) { + case 0x0: + if (op3 == 0xf) { /* TRAP */ +#if 1 + /* pass through */ +#else + /* kernel space is not allowed as next_pc */ + unsigned long evb; + unsigned long trapno; + trapno = insn & 0xf; + __asm__ __volatile__ ( + "mvfc %0, cr5\n" + :"=r"(evb) + : + ); + *next_pc = evb + (trapno << 2); + return; +#endif + } else if (op3 == 0xd) { /* RTE */ + *next_pc = get_stack_long(child, PT_BPC); + return; + } + break; + case 0xc: /* JC */ + if (op3 == 0xc && check_condition_bit(child)) { + regno = insn & 0xf; + *next_pc = get_stack_long(child, + reg_offset[regno]); + return; + } + break; + case 0xd: /* JNC */ + if (op3 == 0xc && !check_condition_bit(child)) { + regno = insn & 0xf; + *next_pc = get_stack_long(child, + reg_offset[regno]); + return; + } + break; + case 0xe: /* JL */ + case 0xf: /* JMP */ + if (op3 == 0xc) { /* JMP */ + regno = insn & 0xf; + *next_pc = get_stack_long(child, + reg_offset[regno]); + return; + } + break; + } + } + if (parallel) + *next_pc = pc + 4; + else + *next_pc = pc + 2; +} + +static void +compute_next_pc_for_32bit_insn(unsigned long insn, unsigned long pc, + unsigned long *next_pc, + struct task_struct *child) +{ + unsigned long op; + unsigned long op2; + unsigned long disp; + unsigned long regno1, regno2; + + op = (insn >> 28) & 0xf; + if (op == 0xf) { /* branch 24-bit relative */ + op2 = (insn >> 24) & 0xf; + switch (op2) { + case 0xd: /* BNC */ + case 0x9: /* BNCL */ + if (!check_condition_bit(child)) { + disp = (long)(insn << 8) >> 6; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0x8: /* BCL */ + case 0xc: /* BC */ + if (check_condition_bit(child)) { + disp = (long)(insn << 8) >> 6; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0xe: /* BL */ + case 0xf: /* BRA */ + disp = (long)(insn << 8) >> 6; + *next_pc = (pc & ~0x3) + disp; + return; + } + } else if (op == 0xb) { /* branch 16-bit relative */ + op2 = (insn >> 20) & 0xf; + switch (op2) { + case 0x0: /* BEQ */ + case 0x1: /* BNE */ + case 0x8: /* BEQZ */ + case 0x9: /* BNEZ */ + case 0xa: /* BLTZ */ + case 0xb: /* BGEZ */ + case 0xc: /* BLEZ */ + case 0xd: /* BGTZ */ + regno1 = ((insn >> 24) & 0xf); + regno2 = ((insn >> 16) & 0xf); + if (check_condition_src(op2, regno1, regno2, child)) { + disp = (long)(insn << 16) >> 14; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + } + } + *next_pc = pc + 4; +} + +static inline void +compute_next_pc(unsigned long insn, unsigned long pc, + unsigned long *next_pc, struct task_struct *child) +{ + if (insn & 0x80000000) + compute_next_pc_for_32bit_insn(insn, pc, next_pc, child); + else + compute_next_pc_for_16bit_insn(insn, pc, next_pc, child); +} + +static int +register_debug_trap(struct task_struct *child, unsigned long next_pc, + unsigned long next_insn, unsigned long *code) +{ + struct debug_trap *p = &child->thread.debug_trap; + unsigned long addr = next_pc & ~3; + + if (p->nr_trap != 0) { + printk("kernel BUG at %s %d: p->nr_trap = %d\n", + __FILE__, __LINE__, p->nr_trap); + return -1; + } + p->addr = addr; + p->insn = next_insn; + p->nr_trap++; + if (next_pc & 3) { + *code = (next_insn & 0xffff0000) | 0x10f1; + /* xxx --> TRAP1 */ + } else { + if ((next_insn & 0x80000000) || (next_insn & 0x8000)) { + *code = 0x10f17000; + /* TRAP1 --> NOP */ + } else { + *code = (next_insn & 0xffff) | 0x10f10000; + /* TRAP1 --> xxx */ + } + } + return 0; +} + +int withdraw_debug_trap_for_signal(struct task_struct *child) +{ + struct debug_trap *p = &child->thread.debug_trap; + int nr_trap = p->nr_trap; + + if (nr_trap) { + access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1); + p->nr_trap = 0; + p->addr = 0; + p->insn = 0; + } + return nr_trap; +} + +static int +unregister_debug_trap(struct task_struct *child, unsigned long addr, + unsigned long *code) +{ + struct debug_trap *p = &child->thread.debug_trap; + + if (p->nr_trap != 1 || p->addr != addr) { + /* The trap may be requested from debugger. + * ptrace should do nothing in this case. + */ + return 0; + } + *code = p->insn; + p->insn = 0; + p->addr = 0; + p->nr_trap--; + return 1; +} + +static void +unregister_all_debug_traps(struct task_struct *child) +{ + struct debug_trap *p = &child->thread.debug_trap; + + if (p->nr_trap) { + access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1); + p->addr = 0; + p->insn = 0; + p->nr_trap = 0; + } +} + +static inline void +invalidate_cache(void) +{ +#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP) + + _flush_cache_copyback_all(); + +#else /* ! CONFIG_CHIP_M32700 */ + + /* Invalidate cache */ + __asm__ __volatile__ ( + "ldi r0, #-1 \n\t" + "ldi r1, #0 \n\t" + "stb r1, @r0 ; cache off \n\t" + "; \n\t" + "ldi r0, #-2 \n\t" + "ldi r1, #1 \n\t" + "stb r1, @r0 ; cache invalidate \n\t" + ".fillinsn \n" + "0: \n\t" + "ldb r1, @r0 ; invalidate check \n\t" + "bnez r1, 0b \n\t" + "; \n\t" + "ldi r0, #-1 \n\t" + "ldi r1, #1 \n\t" + "stb r1, @r0 ; cache on \n\t" + : : : "r0", "r1", "memory" + ); + /* FIXME: copying-back d-cache and invalidating i-cache are needed. + */ +#endif /* CONFIG_CHIP_M32700 */ +} + +/* Embed a debug trap (TRAP1) code */ +static int +embed_debug_trap(struct task_struct *child, unsigned long next_pc) +{ + unsigned long next_insn, code; + unsigned long addr = next_pc & ~3; + + if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0) + != sizeof(next_insn)) { + return -1; /* error */ + } + + /* Set a trap code. */ + if (register_debug_trap(child, next_pc, next_insn, &code)) { + return -1; /* error */ + } + if (access_process_vm(child, addr, &code, sizeof(code), 1) + != sizeof(code)) { + return -1; /* error */ + } + return 0; /* success */ +} + +void +embed_debug_trap_for_signal(struct task_struct *child) +{ + unsigned long next_pc; + unsigned long pc, insn; + int ret; + + pc = get_stack_long(child, PT_BPC); + ret = access_process_vm(child, pc&~3, &insn, sizeof(insn), 0); + if (ret != sizeof(insn)) { + printk("kernel BUG at %s %d: access_process_vm returns %d\n", + __FILE__, __LINE__, ret); + return; + } + compute_next_pc(insn, pc, &next_pc, child); + if (next_pc & 0x80000000) { + printk("kernel BUG at %s %d: next_pc = 0x%08x\n", + __FILE__, __LINE__, (int)next_pc); + return; + } + if (embed_debug_trap(child, next_pc)) { + printk("kernel BUG at %s %d: embed_debug_trap error\n", + __FILE__, __LINE__); + return; + } + invalidate_cache(); +} + +void +withdraw_debug_trap(struct pt_regs *regs) +{ + unsigned long addr; + unsigned long code; + + addr = (regs->bpc - 2) & ~3; + regs->bpc -= 2; + if (unregister_debug_trap(current, addr, &code)) { + access_process_vm(current, addr, &code, sizeof(code), 1); + invalidate_cache(); + } +} + +static void +init_debug_traps(struct task_struct *child) +{ + struct debug_trap *p = &child->thread.debug_trap; + p->nr_trap = 0; + p->addr = 0; + p->insn = 0; +} + + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void ptrace_disable(struct task_struct *child) +{ + /* nothing to do.. */ +} + +static int +do_ptrace(long request, struct task_struct *child, long addr, long data) +{ + unsigned long tmp; + int ret; + + switch (request) { + /* + * read word at location "addr" in the child process. + */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (ret == sizeof(tmp)) + ret = put_user(tmp,(unsigned long __user *) data); + else + ret = -EIO; + break; + + /* + * read the word at location addr in the USER area. + */ + case PTRACE_PEEKUSR: + ret = ptrace_read_user(child, addr, + (unsigned long __user *)data); + break; + + /* + * write the word at location addr. + */ + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + ret = access_process_vm(child, addr, &data, sizeof(data), 1); + if (ret == sizeof(data)) { + ret = 0; + if (request == PTRACE_POKETEXT) { + invalidate_cache(); + } + } else { + ret = -EIO; + } + break; + + /* + * write the word at location addr in the USER area. + */ + case PTRACE_POKEUSR: + ret = ptrace_write_user(child, addr, data); + break; + + /* + * continue/restart and stop at next (return from) syscall + */ + case PTRACE_SYSCALL: + case PTRACE_CONT: + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + ret = 0; + unregister_all_debug_traps(child); + invalidate_cache(); + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + } + + /* + * execute single instruction. + */ + case PTRACE_SINGLESTEP: { + unsigned long next_pc; + unsigned long pc, insn; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + if ((child->ptrace & PT_DTRACE) == 0) { + /* Spurious delayed TF traps may occur */ + child->ptrace |= PT_DTRACE; + } + + /* Compute next pc. */ + pc = get_stack_long(child, PT_BPC); + + if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) + != sizeof(insn)) + break; + + compute_next_pc(insn, pc, &next_pc, child); + if (next_pc & 0x80000000) + break; + + if (embed_debug_trap(child, next_pc)) + break; + + invalidate_cache(); + child->exit_code = data; + + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + /* + * detach a process that was attached. + */ + case PTRACE_DETACH: + ret = 0; + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: + ret = ptrace_getregs(child, (void __user *)data); + break; + + case PTRACE_SETREGS: + ret = ptrace_setregs(child, (void __user *)data); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + if (ret == 0) + init_debug_traps(child); + goto out_tsk; + } + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret == 0) + ret = do_ptrace(request, child, addr, data); + +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + + return ret; +} + +/* notification of system call entry/exit + * - triggered by current->work.syscall_trace + */ +void do_syscall_trace(void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + diff -Nru a/arch/m32r/kernel/semaphore.c b/arch/m32r/kernel/semaphore.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/semaphore.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,186 @@ +/* + * linux/arch/m32r/semaphore.c + * orig : i386 2.6.4 + * + * M32R semaphore implementation. + * + * Copyright (c) 2002 - 2004 Hitoshi Yamamoto + */ + +/* + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + * + * Portions Copyright 1999 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * rw semaphores implemented November 1999 by Benjamin LaHaise + */ +#include +#include +#include +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to acquire the semaphore, while the "sleeping" + * variable is a count of such acquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is protected + * by the spinlock in the semaphore's waitqueue head. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +asmlinkage void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +asmlinkage void __sched __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); + + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock in + * the wait_queue_head. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irqrestore(&sem->wait.lock, flags); + + schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); + tsk->state = TASK_UNINTERRUPTIBLE; + } + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); + tsk->state = TASK_RUNNING; +} + +asmlinkage int __sched __down_interruptible(struct semaphore * sem) +{ + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); + + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + if (signal_pending(current)) { + retval = -EINTR; + sem->sleepers = 0; + atomic_add(sleepers, &sem->count); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock in + * wait_queue_head. The "-1" is because we're + * still hoping to get the semaphore. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irqrestore(&sem->wait.lock, flags); + + schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); + tsk->state = TASK_INTERRUPTIBLE; + } + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); + + tsk->state = TASK_RUNNING; + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + * + * We could have done the trylock with a + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +asmlinkage int __down_trylock(struct semaphore * sem) +{ + int sleepers; + unsigned long flags; + + spin_lock_irqsave(&sem->wait.lock, flags); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock in the + * wait_queue_head. + */ + if (!atomic_add_negative(sleepers, &sem->count)) { + wake_up_locked(&sem->wait); + } + + spin_unlock_irqrestore(&sem->wait.lock, flags); + return 1; +} diff -Nru a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/setup.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,403 @@ +/* + * linux/arch/m32r/kernel/setup.c + * + * Setup routines for Renesas M32R + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MMU +extern void init_mmu(void); +#endif + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) \ + || defined(CONFIG_BLK_DEV_IDE_MODULE) \ + || defined(CONFIG_BLK_DEV_HD_MODULE) +struct drive_info_struct { char dummy[32]; } drive_info; +#endif + +extern char _end[]; + +/* + * Machine setup.. + */ +struct cpuinfo_m32r boot_cpu_data; + +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +#if defined(CONFIG_VGA_CONSOLE) +struct screen_info screen_info = { + .orig_video_lines = 25, + .orig_video_cols = 80, + .orig_video_mode = 0, + .orig_video_ega_bx = 0, + .orig_video_isVGA = 1, + .orig_video_points = 8 +}; +#endif + +extern int root_mountflags; + +static char command_line[COMMAND_LINE_SIZE]; + +static struct resource data_resource = { + .name = "Kernel data", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +static struct resource code_resource = { + .name = "Kernel code", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +unsigned long memory_start; +unsigned long memory_end; + +void __init setup_arch(char **); +int get_cpuinfo(char *); + +static __inline__ void parse_mem_cmdline(char ** cmdline_p) +{ + char c = ' '; + char *to = command_line; + char *from = COMMAND_LINE; + int len = 0; + int usermem = 0; + + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + + memory_start = (unsigned long)CONFIG_MEMORY_START+PAGE_OFFSET; + memory_end = memory_start+(unsigned long)CONFIG_MEMORY_SIZE; + + for ( ; ; ) { + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; + + { + unsigned long mem_size; + + usermem = 1; + mem_size = memparse(from+4, &from); + memory_end = memory_start + mem_size; + } + } + c = *(from++); + if (!c) + break; + + if (COMMAND_LINE_SIZE <= ++len) + break; + + *(to++) = c; + } + *to = '\0'; + *cmdline_p = command_line; + if (usermem) + printk(KERN_INFO "user-defined physical RAM map:\n"); +} + +#ifndef CONFIG_DISCONTIGMEM +static unsigned long __init setup_memory(void) +{ + unsigned long start_pfn, max_low_pfn, bootmap_size; + + start_pfn = PFN_UP( __pa(_end) ); + max_low_pfn = PFN_DOWN( __pa(memory_end) ); + + /* + * Initialize the boot-time allocator (with low memory only): + */ + bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, + CONFIG_MEMORY_START>>PAGE_SHIFT, max_low_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + { + unsigned long curr_pfn; + unsigned long last_pfn; + unsigned long pages; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(__pa(memory_start)); + + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(__pa(memory_end)); + + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; + + pages = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages)); + } + + /* + * Reserve the kernel text and + * Reserve the bootmem bitmap. We do this in two steps (first step + * was init_bootmem()), because this catches the (definitely buggy) + * case of us accidentally initializing the bootmem allocator with + * an invalid RAM area. + */ + reserve_bootmem(CONFIG_MEMORY_START + PAGE_SIZE, + (PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE - 1) + - CONFIG_MEMORY_START); + + /* + * reserve physical page 0 - it's a special BIOS page on many boxes, + * enabling clean reboots, SMP operation, laptop functions. + */ + reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE); + + /* + * reserve memory hole + */ +#ifdef CONFIG_MEMHOLE + reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE); +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + if (LOADER_TYPE && INITRD_START) { + if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { + reserve_bootmem(INITRD_START, INITRD_SIZE); + initrd_start = INITRD_START ? + INITRD_START + PAGE_OFFSET : 0; + + initrd_end = initrd_start + INITRD_SIZE; + printk("initrd:start[%08lx],size[%08lx]\n", + initrd_start, INITRD_SIZE); + } else { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + INITRD_START + INITRD_SIZE, + max_low_pfn << PAGE_SHIFT); + + initrd_start = 0; + } + } +#endif + + return max_low_pfn; +} +#else /* CONFIG_DISCONTIGMEM */ +extern unsigned long setup_memory(void); +#endif /* CONFIG_DISCONTIGMEM */ + +#define M32R_PCC_PCATCR 0x00ef7014 /* will move to m32r.h */ + +void __init setup_arch(char **cmdline_p) +{ + ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); + + boot_cpu_data.cpu_clock = M32R_CPUCLK; + boot_cpu_data.bus_clock = M32R_BUSCLK; + boot_cpu_data.timer_divide = M32R_TIMER_DIVIDE; + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); +#endif + + if (!MOUNT_ROOT_RDONLY) + root_mountflags &= ~MS_RDONLY; + +#ifdef CONFIG_VT +#if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +#endif + +#ifdef CONFIG_DISCONTIGMEM + numnodes = 2; +#endif /* CONFIG_DISCONTIGMEM */ + + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + + code_resource.start = virt_to_phys(_text); + code_resource.end = virt_to_phys(_etext)-1; + data_resource.start = virt_to_phys(_etext); + data_resource.end = virt_to_phys(_edata)-1; + + parse_mem_cmdline(cmdline_p); + + setup_memory(); + + paging_init(); +} + +#ifdef CONFIG_PROC_FS +/* + * Get CPU information for use by the procfs. + */ +static int show_cpuinfo(struct seq_file *m, void *v) +{ + struct cpuinfo_m32r *c = v; + unsigned long cpu = c - cpu_data; + +#ifdef CONFIG_SMP + if (!cpu_online(cpu)) + return 0; +#endif /* CONFIG_SMP */ + + seq_printf(m, "processor\t: %ld\n", cpu); + +#ifdef CONFIG_CHIP_VDEC2 + seq_printf(m, "cpu family\t: VDEC2\n" + "cache size\t: Unknown\n"); +#elif CONFIG_CHIP_M32700 + seq_printf(m,"cpu family\t: M32700\n" + "cache size\t: I-8KB/D-8KB\n"); +#elif CONFIG_CHIP_M32102 + seq_printf(m,"cpu family\t: M32102\n" + "cache size\t: I-8KB\n"); +#elif CONFIG_CHIP_OPSP + seq_printf(m,"cpu family\t: OPSP\n" + "cache size\t: I-8KB/D-8KB\n"); +#elif CONFIG_CHIP_MP + seq_printf(m, "cpu family\t: M32R-MP\n" + "cache size\t: I-xxKB/D-xxKB\n"); +#else + seq_printf(m, "cpu family\t: Unknown\n"); +#endif + seq_printf(m, "bogomips\t: %lu.%02lu\n", + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); +#ifdef CONFIG_PLAT_MAPPI + seq_printf(m, "Machine\t\t: Mappi Evaluation board\n"); +#elif CONFIG_PLAT_MAPPI2 + seq_printf(m, "Machine\t\t: Mappi-II Evaluation board\n"); +#elif CONFIG_PLAT_M32700UT + seq_printf(m, "Machine\t\t: M32700UT Evaluation board\n"); +#elif CONFIG_PLAT_OPSPUT + seq_printf(m, "Machine\t\t: OPSPUT Evaluation board\n"); +#elif CONFIG_PLAT_USRV + seq_printf(m, "Machine\t\t: uServer\n"); +#elif CONFIG_PLAT_OAKS32R + seq_printf(m, "Machine\t\t: OAKS32R\n"); +#else + seq_printf(m, "Machine\t\t: Unknown\n"); +#endif + +#define PRINT_CLOCK(name, value) \ + seq_printf(m, name " clock\t: %d.%02dMHz\n", \ + ((value) / 1000000), ((value) % 1000000)/10000) + + PRINT_CLOCK("CPU", (int)c->cpu_clock); + PRINT_CLOCK("Bus", (int)c->bus_clock); + + seq_printf(m, "\n"); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? cpu_data + *pos : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; +#endif /* CONFIG_PROC_FS */ + +unsigned long cpu_initialized __initdata = 0; + +/* + * cpu_init() initializes state that is per-CPU. Some data is already + * initialized (naturally) in the bootstrap process. + * We reload them nevertheless, this function acts as a + * 'CPU state barrier', nothing should get across. + */ +#if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \ + || defined(CONFIG_CHIP_OPSP) +void __init cpu_init (void) +{ + int cpu_id = smp_processor_id(); + + if (test_and_set_bit(cpu_id, &cpu_initialized)) { + printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id); + for ( ; ; ) + local_irq_enable(); + } + printk(KERN_INFO "Initializing CPU#%d\n", cpu_id); + + /* Set up and load the per-CPU TSS and LDT */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + if (current->mm) + BUG(); + + /* Force FPU initialization */ + current_thread_info()->status = 0; + current->used_math = 0; + +#ifdef CONFIG_MMU + /* Set up MMU */ + init_mmu(); +#endif + + /* Set up ICUIMASK */ + outl(0x00070000, M32R_ICU_IMASK_PORTL); /* imask=111 */ +} +#endif /* defined(CONFIG_CHIP_VDEC2) ... */ + diff -Nru a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/setup_m32700ut.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,478 @@ +/* + * linux/arch/m32r/kernel/setup_m32700ut.c + * + * Setup routines for Renesas M32700UT Board + * + * Copyright (c) 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * M32700 Interrupt Control Unit (Level 1) + */ +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +static icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; + +static void disable_m32700ut_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_m32700ut_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_m32700ut(unsigned int irq) +{ + disable_m32700ut_irq(irq); +} + +static void end_m32700ut_irq(unsigned int irq) +{ + enable_m32700ut_irq(irq); +} + +static unsigned int startup_m32700ut_irq(unsigned int irq) +{ + enable_m32700ut_irq(irq); + return (0); +} + +static void shutdown_m32700ut_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_irq_type = +{ + "M32700UT-IRQ", + startup_m32700ut_irq, + shutdown_m32700ut_irq, + enable_m32700ut_irq, + disable_m32700ut_irq, + mask_and_ack_m32700ut, + end_m32700ut_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT (Level 2) + */ +#define irq2pldirq(x) ((x) - M32700UT_PLD_IRQ_BASE) +#define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +typedef struct { + unsigned short icucr; /* ICU Control Register */ +} pld_icu_data_t; + +static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ]; + +static void disable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// disable_m32700ut_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// enable_m32700ut_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_pld(unsigned int irq) +{ + disable_m32700ut_pld_irq(irq); +// mask_and_ack_m32700ut(M32R_IRQ_INT1); +} + +static void end_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + end_m32700ut_irq(M32R_IRQ_INT1); +} + +static unsigned int startup_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + return (0); +} + +static void shutdown_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// shutdown_m32700ut_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_pld_irq_type = +{ + "M32700UT-PLD-IRQ", + startup_m32700ut_pld_irq, + shutdown_m32700ut_pld_irq, + enable_m32700ut_pld_irq, + disable_m32700ut_pld_irq, + mask_and_ack_m32700ut_pld, + end_m32700ut_pld_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT-LAN (Level 2) + */ +#define irq2lanpldirq(x) ((x) - M32700UT_LAN_PLD_IRQ_BASE) +#define lanpldirq2port(x) (unsigned long)((int)M32700UT_LAN_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lanpld_icu_data[M32700UT_NUM_LAN_PLD_IRQ]; + +static void disable_m32700ut_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_lanpld(unsigned int irq) +{ + disable_m32700ut_lanpld_irq(irq); +} + +static void end_m32700ut_lanpld_irq(unsigned int irq) +{ + enable_m32700ut_lanpld_irq(irq); + end_m32700ut_irq(M32R_IRQ_INT0); +} + +static unsigned int startup_m32700ut_lanpld_irq(unsigned int irq) +{ + enable_m32700ut_lanpld_irq(irq); + return (0); +} + +static void shutdown_m32700ut_lanpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_lanpld_irq_type = +{ + "M32700UT-PLD-LAN-IRQ", + startup_m32700ut_lanpld_irq, + shutdown_m32700ut_lanpld_irq, + enable_m32700ut_lanpld_irq, + disable_m32700ut_lanpld_irq, + mask_and_ack_m32700ut_lanpld, + end_m32700ut_lanpld_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT-LCD (Level 2) + */ +#define irq2lcdpldirq(x) ((x) - M32700UT_LCD_PLD_IRQ_BASE) +#define lcdpldirq2port(x) (unsigned long)((int)M32700UT_LCD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lcdpld_icu_data[M32700UT_NUM_LCD_PLD_IRQ]; + +static void disable_m32700ut_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_lcdpld(unsigned int irq) +{ + disable_m32700ut_lcdpld_irq(irq); +} + +static void end_m32700ut_lcdpld_irq(unsigned int irq) +{ + enable_m32700ut_lcdpld_irq(irq); + end_m32700ut_irq(M32R_IRQ_INT2); +} + +static unsigned int startup_m32700ut_lcdpld_irq(unsigned int irq) +{ + enable_m32700ut_lcdpld_irq(irq); + return (0); +} + +static void shutdown_m32700ut_lcdpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_lcdpld_irq_type = +{ + "M32700UT-PLD-LCD-IRQ", + startup_m32700ut_lcdpld_irq, + shutdown_m32700ut_lcdpld_irq, + enable_m32700ut_lcdpld_irq, + disable_m32700ut_lcdpld_irq, + mask_and_ack_m32700ut_lcdpld, + end_m32700ut_lcdpld_irq +}; + +void __init init_IRQ(void) +{ +#if defined(CONFIG_SMC91X) + /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/ + irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED; + irq_desc[M32700UT_LAN_IRQ_LAN].handler = &m32700ut_lanpld_irq_type; + irq_desc[M32700UT_LAN_IRQ_LAN].action = 0; + irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */ + lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ + disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN); +#endif /* CONFIG_SMC91X */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_m32700ut_irq(M32R_IRQ_MFT2); + + /* SIO0 : receive */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO0_R); + + /* SIO0 : send */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO0_S); + + /* SIO1 : receive */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO1_R); + + /* SIO1 : send */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO1_S); + + /* DMA1 : */ + irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_DMA1].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_DMA1].action = 0; + irq_desc[M32R_IRQ_DMA1].depth = 1; + icu_data[M32R_IRQ_DMA1].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_DMA1); + +#ifdef CONFIG_SERIAL_M32R_PLDSIO + /* INT#1: SIO0 Receive on PLD */ + irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_RCV].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_RCV].action = 0; + irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV); + + /* INT#1: SIO0 Send on PLD */ + irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_SND].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_SND].action = 0; + irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND); +#endif /* CONFIG_SERIAL_M32R_PLDSIO */ + + /* INT#1: CFC IREQ on PLD */ + irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFIREQ].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CFIREQ].action = 0; + irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ); + + /* INT#1: CFC Insert on PLD */ + irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_INSERT].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CFC_INSERT].action = 0; + irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT); + + /* INT#1: CFC Eject on PLD */ + irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_EJECT].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CFC_EJECT].action = 0; + irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT); + + /* + * INT0# is used for LAN, DIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_m32700ut_irq(M32R_IRQ_INT0); + + /* + * INT1# is used for UART, MMC, CF Controller in FPGA. + * We enable it here. + */ + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_m32700ut_irq(M32R_IRQ_INT1); + +#if defined(CONFIG_USB) + outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ + + irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED; + irq_desc[M32700UT_LCD_IRQ_USB_INT1].handler = &m32700ut_lcdpld_irq_type; + irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0; + irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1; + lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ + disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1); +#endif + /* + * INT2# is used for BAT, USB, AUDIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; + enable_m32700ut_irq(M32R_IRQ_INT2); + +//#if defined(CONFIG_M32R_AR_VGA) + /* + * INT3# is used for AR + */ + irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT3].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_INT3].action = 0; + irq_desc[M32R_IRQ_INT3].depth = 1; + icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_m32700ut_irq(M32R_IRQ_INT3); +//#endif /* CONFIG_M32R_ARV */ +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static struct resource smc91x_resources[] = { + [0] = { + .start = (LAN_IOSTART), + .end = (LAN_IOEND), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = M32700UT_LAN_IRQ_LAN, + .end = M32700UT_LAN_IRQ_LAN, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(platform_init); diff -Nru a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/setup_mappi.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,160 @@ +/* + * linux/arch/m32r/kernel/setup_mappi.c + * + * Setup routines for Renesas MAPPI Board + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[NR_IRQS]; + +static void disable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi(unsigned int irq) +{ + disable_mappi_irq(irq); +} + +static void end_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); +} + +static unsigned int startup_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); + return (0); +} + +static void shutdown_mappi_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type mappi_irq_type = +{ + "MAPPI-IRQ", + startup_mappi_irq, + shutdown_mappi_irq, + enable_mappi_irq, + disable_mappi_irq, + mask_and_ack_mappi, + end_mappi_irq +}; + +void __init init_IRQ(void) +{ + static int once = 0; + + if (once) + return; + else + once++; + +#ifdef CONFIG_NE2000 + /* INT0 : LAN controller (RTL8019AS) */ + irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT0].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_INT0].action = 0; + irq_desc[M32R_IRQ_INT0].depth = 1; + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_mappi_irq(M32R_IRQ_INT0); +#endif /* CONFIG_M32R_NE2000 */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_mappi_irq(M32R_IRQ_MFT2); + +#ifdef CONFIG_SERIAL_M32R_SIO + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_S); + + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_SERIAL_M32R_SIO */ + +#if defined(CONFIG_M32RPCC) + /* INT1 : pccard0 interrupt */ + irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_INT1].action = 0; + irq_desc[M32R_IRQ_INT1].depth = 1; + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; + disable_mappi_irq(M32R_IRQ_INT1); + + /* INT2 : pccard1 interrupt */ + irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT2].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_INT2].action = 0; + irq_desc[M32R_IRQ_INT2].depth = 1; + icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; + disable_mappi_irq(M32R_IRQ_INT2); +#endif /* CONFIG_M32RPCC */ +} diff -Nru a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/setup_mappi2.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,212 @@ +/* + * linux/arch/m32r/kernel/setup_mappi.c + * + * Setup routines for Renesas MAPPI-II(M3A-ZA36) Board + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[NR_IRQS]; + +static void disable_mappi2_irq(unsigned int irq) +{ + unsigned long port, data; + + if ((irq == 0) ||(irq >= NR_IRQS)) { + printk("bad irq 0x%08x\n", irq); + return; + } + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_mappi2_irq(unsigned int irq) +{ + unsigned long port, data; + + if ((irq == 0) ||(irq >= NR_IRQS)) { + printk("bad irq 0x%08x\n", irq); + return; + } + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi2(unsigned int irq) +{ + disable_mappi2_irq(irq); +} + +static void end_mappi2_irq(unsigned int irq) +{ + enable_mappi2_irq(irq); +} + +static unsigned int startup_mappi2_irq(unsigned int irq) +{ + enable_mappi2_irq(irq); + return (0); +} + +static void shutdown_mappi2_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type mappi2_irq_type = +{ + "MAPPI2-IRQ", + startup_mappi2_irq, + shutdown_mappi2_irq, + enable_mappi2_irq, + disable_mappi2_irq, + mask_and_ack_mappi2, + end_mappi2_irq +}; + +void __init init_IRQ(void) +{ +#if defined(CONFIG_SMC91X) + /* INT0 : LAN controller (SMC91111) */ + irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT0].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_INT0].action = 0; + irq_desc[M32R_IRQ_INT0].depth = 1; + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_mappi2_irq(M32R_IRQ_INT0); +#endif /* CONFIG_SMC91X */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_mappi2_irq(M32R_IRQ_MFT2); + +#ifdef CONFIG_SERIAL_M32R_SIO + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO0_S); + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_M32R_USE_DBG_CONSOLE */ + +#if defined(CONFIG_USB) + /* INT1 : USB Host controller interrupt */ + irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT1].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_INT1].action = 0; + irq_desc[M32R_IRQ_INT1].depth = 1; + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; + disable_mappi2_irq(M32R_IRQ_INT1); +#endif /* CONFIG_USB */ + +#if defined(CONFIG_M32R_CFC) + /* ICUCR40: CFC IREQ */ + irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type; + irq_desc[PLD_IRQ_CFIREQ].action = 0; + irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ +// icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; + icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; + disable_mappi2_irq(PLD_IRQ_CFIREQ); + + /* ICUCR41: CFC Insert */ + irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi2_irq_type; + irq_desc[PLD_IRQ_CFC_INSERT].action = 0; + irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ + icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; +// icu_data[PLD_IRQ_CFC_INSERT].icucr = 0; + disable_mappi2_irq(PLD_IRQ_CFC_INSERT); + + /* ICUCR42: CFC Eject */ + irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi2_irq_type; + irq_desc[PLD_IRQ_CFC_EJECT].action = 0; + irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ + icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; +// icu_data[PLD_IRQ_CFC_EJECT].icucr = 0; + disable_mappi2_irq(PLD_IRQ_CFC_EJECT); + +#endif /* CONFIG_MAPPI2_CFC */ +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static struct resource smc91x_resources[] = { + [0] = { + .start = (LAN_IOSTART), + .end = (LAN_IOEND), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = M32R_IRQ_INT0, + .end = M32R_IRQ_INT0, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(platform_init); diff -Nru a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/setup_oaks32r.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,143 @@ +/* + * linux/arch/m32r/kernel/setup_oaks32r.c + * + * Setup routines for OAKS32R Board + * + * Copyright (c) 2002-2004 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[NR_IRQS]; + +static void disable_oaks32r_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_oaks32r_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi(unsigned int irq) +{ + disable_oaks32r_irq(irq); +} + +static void end_oaks32r_irq(unsigned int irq) +{ + enable_oaks32r_irq(irq); +} + +static unsigned int startup_oaks32r_irq(unsigned int irq) +{ + enable_oaks32r_irq(irq); + return (0); +} + +static void shutdown_oaks32r_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type oaks32r_irq_type = +{ + "OAKS32R-IRQ", + startup_oaks32r_irq, + shutdown_oaks32r_irq, + enable_oaks32r_irq, + disable_oaks32r_irq, + mask_and_ack_mappi, + end_oaks32r_irq +}; + +void __init init_IRQ(void) +{ + static int once = 0; + + if (once) + return; + else + once++; + +#ifdef CONFIG_NE2000 + /* INT3 : LAN controller (RTL8019AS) */ + irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT3].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_INT3].action = 0; + irq_desc[M32R_IRQ_INT3].depth = 1; + icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_oaks32r_irq(M32R_IRQ_INT3); +#endif /* CONFIG_M32R_NE2000 */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_oaks32r_irq(M32R_IRQ_MFT2); + +#ifdef CONFIG_SERIAL_M32R_SIO + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO0_S); + + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_SERIAL_M32R_SIO */ + +} diff -Nru a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/setup_opsput.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,482 @@ +/* + * linux/arch/m32r/kernel/setup_opsput.c + * + * Setup routines for Renesas OPSPUT Board + * + * Copyright (c) 2002-2004 + * Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * OPSP Interrupt Control Unit (Level 1) + */ +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +static icu_data_t icu_data[OPSPUT_NUM_CPU_IRQ]; + +static void disable_opsput_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_opsput_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_opsput(unsigned int irq) +{ + disable_opsput_irq(irq); +} + +static void end_opsput_irq(unsigned int irq) +{ + enable_opsput_irq(irq); +} + +static unsigned int startup_opsput_irq(unsigned int irq) +{ + enable_opsput_irq(irq); + return (0); +} + +static void shutdown_opsput_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_irq_type = +{ + "OPSPUT-IRQ", + startup_opsput_irq, + shutdown_opsput_irq, + enable_opsput_irq, + disable_opsput_irq, + mask_and_ack_opsput, + end_opsput_irq +}; + +/* + * Interrupt Control Unit of PLD on OPSPUT (Level 2) + */ +#define irq2pldirq(x) ((x) - OPSPUT_PLD_IRQ_BASE) +#define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +typedef struct { + unsigned short icucr; /* ICU Control Register */ +} pld_icu_data_t; + +static pld_icu_data_t pld_icu_data[OPSPUT_NUM_PLD_IRQ]; + +static void disable_opsput_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// disable_opsput_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_opsput_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// enable_opsput_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_opsput_pld(unsigned int irq) +{ + disable_opsput_pld_irq(irq); +// mask_and_ack_opsput(M32R_IRQ_INT1); +} + +static void end_opsput_pld_irq(unsigned int irq) +{ + enable_opsput_pld_irq(irq); + end_opsput_irq(M32R_IRQ_INT1); +} + +static unsigned int startup_opsput_pld_irq(unsigned int irq) +{ + enable_opsput_pld_irq(irq); + return (0); +} + +static void shutdown_opsput_pld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// shutdown_opsput_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_pld_irq_type = +{ + "OPSPUT-PLD-IRQ", + startup_opsput_pld_irq, + shutdown_opsput_pld_irq, + enable_opsput_pld_irq, + disable_opsput_pld_irq, + mask_and_ack_opsput_pld, + end_opsput_pld_irq +}; + +/* + * Interrupt Control Unit of PLD on OPSPUT-LAN (Level 2) + */ +#define irq2lanpldirq(x) ((x) - OPSPUT_LAN_PLD_IRQ_BASE) +#define lanpldirq2port(x) (unsigned long)((int)OPSPUT_LAN_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lanpld_icu_data[OPSPUT_NUM_LAN_PLD_IRQ]; + +static void disable_opsput_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_opsput_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_opsput_lanpld(unsigned int irq) +{ + disable_opsput_lanpld_irq(irq); +} + +static void end_opsput_lanpld_irq(unsigned int irq) +{ + enable_opsput_lanpld_irq(irq); + end_opsput_irq(M32R_IRQ_INT0); +} + +static unsigned int startup_opsput_lanpld_irq(unsigned int irq) +{ + enable_opsput_lanpld_irq(irq); + return (0); +} + +static void shutdown_opsput_lanpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_lanpld_irq_type = +{ + "OPSPUT-PLD-LAN-IRQ", + startup_opsput_lanpld_irq, + shutdown_opsput_lanpld_irq, + enable_opsput_lanpld_irq, + disable_opsput_lanpld_irq, + mask_and_ack_opsput_lanpld, + end_opsput_lanpld_irq +}; + +/* + * Interrupt Control Unit of PLD on OPSPUT-LCD (Level 2) + */ +#define irq2lcdpldirq(x) ((x) - OPSPUT_LCD_PLD_IRQ_BASE) +#define lcdpldirq2port(x) (unsigned long)((int)OPSPUT_LCD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lcdpld_icu_data[OPSPUT_NUM_LCD_PLD_IRQ]; + +static void disable_opsput_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_opsput_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_opsput_lcdpld(unsigned int irq) +{ + disable_opsput_lcdpld_irq(irq); +} + +static void end_opsput_lcdpld_irq(unsigned int irq) +{ + enable_opsput_lcdpld_irq(irq); + end_opsput_irq(M32R_IRQ_INT2); +} + +static unsigned int startup_opsput_lcdpld_irq(unsigned int irq) +{ + enable_opsput_lcdpld_irq(irq); + return (0); +} + +static void shutdown_opsput_lcdpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_lcdpld_irq_type = +{ + "OPSPUT-PLD-LCD-IRQ", + startup_opsput_lcdpld_irq, + shutdown_opsput_lcdpld_irq, + enable_opsput_lcdpld_irq, + disable_opsput_lcdpld_irq, + mask_and_ack_opsput_lcdpld, + end_opsput_lcdpld_irq +}; + +void __init init_IRQ(void) +{ +#if defined(CONFIG_SMC91X) + /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/ + irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED; + irq_desc[OPSPUT_LAN_IRQ_LAN].handler = &opsput_lanpld_irq_type; + irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0; + irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */ + lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ + disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN); +#endif /* CONFIG_SMC91X */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_opsput_irq(M32R_IRQ_MFT2); + + /* SIO0 : receive */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO0_R); + + /* SIO0 : send */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO0_S); + + /* SIO1 : receive */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO1_R); + + /* SIO1 : send */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO1_S); + + /* DMA1 : */ + irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_DMA1].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_DMA1].action = 0; + irq_desc[M32R_IRQ_DMA1].depth = 1; + icu_data[M32R_IRQ_DMA1].icucr = 0; + disable_opsput_irq(M32R_IRQ_DMA1); + +#ifdef CONFIG_SERIAL_M32R_PLDSIO + /* INT#1: SIO0 Receive on PLD */ + irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_RCV].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_RCV].action = 0; + irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV); + + /* INT#1: SIO0 Send on PLD */ + irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_SND].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_SND].action = 0; + irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_opsput_pld_irq(PLD_IRQ_SIO0_SND); +#endif /* CONFIG_SERIAL_M32R_PLDSIO */ + +#if defined(CONFIG_M32R_CFC) + /* INT#1: CFC IREQ on PLD */ + irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFIREQ].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_CFIREQ].action = 0; + irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_opsput_pld_irq(PLD_IRQ_CFIREQ); + + /* INT#1: CFC Insert on PLD */ + irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_INSERT].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_CFC_INSERT].action = 0; + irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ + disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT); + + /* INT#1: CFC Eject on PLD */ + irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_EJECT].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_CFC_EJECT].action = 0; + irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ + disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT); +#endif /* CONFIG_M32R_CFC */ + + + /* + * INT0# is used for LAN, DIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_opsput_irq(M32R_IRQ_INT0); + + /* + * INT1# is used for UART, MMC, CF Controller in FPGA. + * We enable it here. + */ + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_opsput_irq(M32R_IRQ_INT1); + +#if defined(CONFIG_USB) + outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ + + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED; + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].handler = &opsput_lcdpld_irq_type; + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0; + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1; + lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ + disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1); +#endif + /* + * INT2# is used for BAT, USB, AUDIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; + enable_opsput_irq(M32R_IRQ_INT2); + +//#if defined(CONFIG_M32R_AR_VGA) + /* + * INT3# is used for AR + */ + irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT3].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_INT3].action = 0; + irq_desc[M32R_IRQ_INT3].depth = 1; + icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_opsput_irq(M32R_IRQ_INT3); +//#endif /* CONFIG_M32R_ARV */ +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static struct resource smc91x_resources[] = { + [0] = { + .start = (LAN_IOSTART), + .end = (LAN_IOEND), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OPSPUT_LAN_IRQ_LAN, + .end = OPSPUT_LAN_IRQ_LAN, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(platform_init); diff -Nru a/arch/m32r/kernel/setup_usrv.c b/arch/m32r/kernel/setup_usrv.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/setup_usrv.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,256 @@ +/* + * linux/arch/m32r/kernel/setup_usrv.c + * + * Setup routines for MITSUBISHI uServer + * + * Copyright (c) 2001, 2002, 2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#if !defined(CONFIG_SMP) +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; + +static void disable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi(unsigned int irq) +{ + disable_mappi_irq(irq); +} + +static void end_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); +} + +static unsigned int startup_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); + return 0; +} + +static void shutdown_mappi_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type mappi_irq_type = +{ + "M32700-IRQ", + startup_mappi_irq, + shutdown_mappi_irq, + enable_mappi_irq, + disable_mappi_irq, + mask_and_ack_mappi, + end_mappi_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT (Level 2) + */ +#define irq2pldirq(x) ((x) - M32700UT_PLD_IRQ_BASE) +#define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +typedef struct { + unsigned short icucr; /* ICU Control Register */ +} pld_icu_data_t; + +static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ]; + +static void disable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_pld(unsigned int irq) +{ + disable_m32700ut_pld_irq(irq); +} + +static void end_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + end_mappi_irq(M32R_IRQ_INT1); +} + +static unsigned int startup_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + return 0; +} + +static void shutdown_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); + port = pldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_pld_irq_type = +{ + "USRV-PLD-IRQ", + startup_m32700ut_pld_irq, + shutdown_m32700ut_pld_irq, + enable_m32700ut_pld_irq, + disable_m32700ut_pld_irq, + mask_and_ack_m32700ut_pld, + end_m32700ut_pld_irq +}; + +void __init init_IRQ(void) +{ + static int once = 0; + int i; + + if (once) + return; + else + once++; + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_mappi_irq(M32R_IRQ_MFT2); + +#if defined(CONFIG_SERIAL_M32R_SIO) + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_S); + + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_SERIAL_M32R_SIO */ + + /* INT#67-#71: CFC#0 IREQ on PLD */ + for (i = 0 ; i < CONFIG_CFC_NUM ; i++ ) { + irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CF0 + i].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CF0 + i].action = 0; + irq_desc[PLD_IRQ_CF0 + i].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr + = PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CF0 + i); + } + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + /* INT#76: 16552D#0 IREQ on PLD */ + irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_UART0].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_UART0].action = 0; + irq_desc[PLD_IRQ_UART0].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr + = PLD_ICUCR_ISMOD03; /* 'H' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_UART0); + + /* INT#77: 16552D#1 IREQ on PLD */ + irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_UART1].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_UART1].action = 0; + irq_desc[PLD_IRQ_UART1].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr + = PLD_ICUCR_ISMOD03; /* 'H' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_UART1); +#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ + +#if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE) + /* INT#80: AK4524 IREQ on PLD */ + irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SNDINT].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_SNDINT].action = 0; + irq_desc[PLD_IRQ_SNDINT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr + = PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_SNDINT); +#endif /* CONFIG_IDC_AK4524 || CONFIG_IDC_AK4524_MODULE */ + + /* + * INT1# is used for UART, MMC, CF Controller in FPGA. + * We enable it here. + */ + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD11; + enable_mappi_irq(M32R_IRQ_INT1); +} + diff -Nru a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/signal.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,621 @@ +/* + * linux/arch/m32r/kernel/signal.c + * + * Copyright (c) 2003 Hitoshi Yamamoto + * + * Taken from i386 version. + * Copyright (C) 1991, 1992 Linus Torvalds + * + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson + * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +int do_signal(struct pt_regs *, sigset_t *); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int +sys_sigsuspend(old_sigset_t mask, unsigned long r1, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs.r0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(®s, &saveset)) + return regs.r0; + } +} + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs.r0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(®s, &saveset)) + return regs.r0; + } +} + +asmlinkage 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; +} + +asmlinkage int +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + return do_sigaltstack(uss, uoss, regs.spu); +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ +// char *pretcode; + int sig; + struct sigcontext sc; +// struct _fpstate fpstate; + unsigned long extramask[_NSIG_WORDS-1]; + char retcode[4]; +}; + +struct rt_sigframe +{ +// char *pretcode; + int sig; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; +// struct _fpstate fpstate; + char retcode[8]; +}; + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, + int *r0_p) +{ + unsigned int err = 0; + + /* 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->sc_##x) + COPY(r4); + COPY(r5); + COPY(r6); + COPY(pt_regs); + /* COPY(r0); Skip r0 */ + COPY(r1); + COPY(r2); + COPY(r3); + COPY(r7); + COPY(r8); + COPY(r9); + COPY(r10); + COPY(r11); + COPY(r12); +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + COPY(acc0h); + COPY(acc0l); + COPY(acc1h); + COPY(acc1l); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + COPY(acch); + COPY(accl); +#else +#error unknown isa configuration +#endif + COPY(psw); + COPY(bpc); + COPY(bbpsw); + COPY(bbpc); + COPY(spu); + COPY(fp); + COPY(lr); + COPY(spi); +#undef COPY + + regs->syscall_nr = -1; /* disable syscall checks */ + err |= __get_user(*r0_p, &sc->sc_r0); + + return err; +} + +asmlinkage int +sys_sigreturn(unsigned long r0, unsigned long r1, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + struct sigframe __user *frame = (struct sigframe __user *)regs.spu; + sigset_t set; + int result; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(®s, &frame->sc, &result)) + goto badframe; + return result; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int +sys_rt_sigreturn(unsigned long r0, unsigned long r1, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.spu; + sigset_t set; + stack_t st; + int result; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &result)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs.spu); + + return result; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +/* + * Set up a signal frame. + */ + +static int +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, + unsigned long mask) +{ + int err = 0; + +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(r4); + COPY(r5); + COPY(r6); + COPY(pt_regs); + COPY(r0); + COPY(r1); + COPY(r2); + COPY(r3); + COPY(r7); + COPY(r8); + COPY(r9); + COPY(r10); + COPY(r11); + COPY(r12); +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + COPY(acc0h); + COPY(acc0l); + COPY(acc1h); + COPY(acc1l); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + COPY(acch); + COPY(accl); +#else +#error unknown isa configuration +#endif + COPY(psw); + COPY(bpc); + COPY(bbpsw); + COPY(bbpc); + COPY(spu); + COPY(fp); + COPY(lr); + COPY(spi); +#undef COPY + + err |= __put_user(mask, &sc->oldmask); + + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void __user * +get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) +{ + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (sas_ss_flags(sp) == 0) + sp = current->sas_ss_sp + current->sas_ss_size; + } + + return (void __user *)((sp - frame_size) & -8ul); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe __user *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->spu, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(signal, &frame->sig); + if (err) + goto give_sigsegv; + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + if (err) + goto give_sigsegv; + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + if (err) + goto give_sigsegv; + } + + if (ka->sa.sa_flags & SA_RESTORER) + regs->lr = (unsigned long)ka->sa.sa_restorer; + else { + /* This is : ldi r7, #__NR_sigreturn ; trap #2 */ + unsigned long code = 0x670010f2 | (__NR_sigreturn << 16); + + regs->lr = (unsigned long)frame->retcode; + err |= __put_user(code, (long __user *)(frame->retcode+0)); + if (err) + goto give_sigsegv; + flush_cache_sigtramp((unsigned long)frame->retcode); + } + + /* Set up registers for signal handler */ + regs->spu = (unsigned long)frame; + regs->r0 = signal; /* Arg for signal handler */ + regs->r1 = (unsigned long)&frame->sc; + regs->bpc = (unsigned long)ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p\n", + current->comm, current->pid, frame, regs->pc); +#endif + + return; + +give_sigsegv: + force_sigsegv(sig, current); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->spu, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(signal, &frame->sig); + if (err) + goto give_sigsegv; + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto give_sigsegv; + + /* 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(sas_ss_flags(regs->spu), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->lr = (unsigned long)ka->sa.sa_restorer; + else { + /* This is : ldi r7, #__NR_rt_sigreturn ; trap #2 */ + unsigned long code1 = 0x97f00000 | (__NR_rt_sigreturn); + unsigned long code2 = 0x10f2f000; + + regs->lr = (unsigned long)frame->retcode; + err |= __put_user(code1, (long __user *)(frame->retcode+0)); + err |= __put_user(code2, (long __user *)(frame->retcode+4)); + if (err) + goto give_sigsegv; + flush_cache_sigtramp((unsigned long)frame->retcode); + } + + /* Set up registers for signal handler */ + regs->spu = (unsigned long)frame; + regs->r0 = signal; /* Arg for signal handler */ + regs->r1 = (unsigned long)&frame->info; + regs->r2 = (unsigned long)&frame->uc; + regs->bpc = (unsigned long)ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p\n", + current->comm, current->pid, frame, regs->pc); +#endif + + return; + +give_sigsegv: + force_sigsegv(sig, current); +} + +/* + * OK, we're invoking a handler + */ + +static void +handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) +{ + unsigned short inst; + + /* Are we from a system call? */ + if (regs->syscall_nr >= 0) { + /* If so, check system call restarting.. */ + switch (regs->r0) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + regs->r0 = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->r0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->r0 = regs->orig_r0; + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; + } + } + + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + */ +int do_signal(struct pt_regs *regs, sigset_t *oldset) +{ + siginfo_t info; + int signr; + struct k_sigaction ka; + unsigned short inst; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + if (current->flags & PF_FREEZE) { + refrigerator(0); + goto no_signal; + } + + if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + /* Reenable any watchpoints before delivering the + * signal to user space. The processor register will + * have been cleared if the watchpoint triggered + * inside the kernel. + */ + + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &ka, &info, oldset, regs); + return 1; + } + + no_signal: + /* Did we come from a system call? */ + if (regs->syscall_nr >= 0) { + /* Restart the system call - no handlers present */ + if (regs->r0 == -ERESTARTNOHAND || + regs->r0 == -ERESTARTSYS || + regs->r0 == -ERESTARTNOINTR) { + regs->r0 = regs->orig_r0; + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; + } + if (regs->r0 == -ERESTART_RESTARTBLOCK){ + regs->r0 = regs->orig_r0; + regs->r7 = __NR_restart_syscall; + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; + } + } + return 0; +} + +/* + * notification of userspace execution resumption + * - triggered by current->work.notify_resume + */ +void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, + __u32 thread_info_flags) +{ + /* Pending single-step? */ + if (thread_info_flags & _TIF_SINGLESTEP) + clear_thread_flag(TIF_SINGLESTEP); + + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs,oldset); + + clear_thread_flag(TIF_IRET); +} diff -Nru a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/smp.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,965 @@ +/* + * linux/arch/m32r/kernel/smp.c + * + * M32R SMP support routines. + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto + * + * Taken from i386 version. + * (c) 1995 Alan Cox, Building #3 + * (c) 1998-99, 2000 Ingo Molnar + * + * This code is released under the GNU General Public License version 2 or + * later. + */ + +#undef DEBUG_SMP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Data structures and variables */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/* + * 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; + +struct call_data_struct { + void (*func) (void *info); + void *info; + atomic_t started; + atomic_t finished; + int wait; +} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); + +static struct call_data_struct *call_data; + +/* + * For flush_cache_all() + */ +static spinlock_t flushcache_lock = SPIN_LOCK_UNLOCKED; +static volatile unsigned long flushcache_cpumask = 0; + +/* + * For flush_tlb_others() + */ +static volatile cpumask_t flush_cpumask; +static struct mm_struct *flush_mm; +static struct vm_area_struct *flush_vma; +static volatile unsigned long flush_va; +static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED; +#define FLUSH_ALL 0xffffffff + +DECLARE_PER_CPU(int, prof_multiplier); +DECLARE_PER_CPU(int, prof_old_multiplier); +DECLARE_PER_CPU(int, prof_counter); + +extern spinlock_t ipi_lock[]; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Function Prototypes */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +void smp_send_reschedule(int); +void smp_reschedule_interrupt(void); + +void smp_flush_cache_all(void); +void smp_flush_cache_all_interrupt(void); + +void smp_flush_tlb_all(void); +static void flush_tlb_all_ipi(void *); + +void smp_flush_tlb_mm(struct mm_struct *); +void smp_flush_tlb_range(struct vm_area_struct *, unsigned long, \ + unsigned long); +void smp_flush_tlb_page(struct vm_area_struct *, unsigned long); +static void flush_tlb_others(cpumask_t, struct mm_struct *, + struct vm_area_struct *, unsigned long); +void smp_invalidate_interrupt(void); + +void smp_send_stop(void); +static void stop_this_cpu(void *); + +int smp_call_function(void (*) (void *), void *, int, int); +void smp_call_function_interrupt(void); + +void smp_send_timer(void); +void smp_ipi_timer_interrupt(struct pt_regs *); +void smp_local_timer_interrupt(struct pt_regs *); + +void send_IPI_allbutself(int, int); +static void send_IPI_mask(cpumask_t, int, int); +unsigned long send_IPI_mask_phys(cpumask_t, int, int); + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Rescheduling request Routines */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_send_reschedule + * + * Description: This routine requests other CPU to execute rescheduling. + * 1.Send 'RESCHEDULE_IPI' to other CPU. + * Request other CPU to execute 'smp_reschedule_interrupt()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpu_id - Target CPU ID + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_send_reschedule(int cpu_id) +{ + WARN_ON(cpu_is_offline(cpu_id)); + send_IPI_mask(cpumask_of_cpu(cpu_id), RESCHEDULE_IPI, 1); +} + +/*==========================================================================* + * Name: smp_reschedule_interrupt + * + * Description: This routine executes on CPU which received + * 'RESCHEDULE_IPI'. + * Rescheduling is processed at the exit of interrupt + * operation. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_reschedule_interrupt(void) +{ + /* nothing to do */ +} + +/*==========================================================================* + * Name: smp_flush_cache_all + * + * Description: This routine sends a 'INVALIDATE_CACHE_IPI' to all other + * CPUs in the system. + * + * Born on Date: 2003-05-28 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_cache_all(void) +{ + cpumask_t cpumask; + unsigned long *mask; + + preempt_disable(); + cpumask = cpu_online_map; + cpu_clear(smp_processor_id(), cpumask); + spin_lock(&flushcache_lock); + mask=cpus_addr(cpumask); + atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask); + send_IPI_mask(cpumask, INVALIDATE_CACHE_IPI, 0); + _flush_cache_copyback_all(); + while (flushcache_cpumask) + mb(); + spin_unlock(&flushcache_lock); + preempt_enable(); +} + +void smp_flush_cache_all_interrupt(void) +{ + _flush_cache_copyback_all(); + clear_bit(smp_processor_id(), &flushcache_cpumask); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* TLB flush request Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_flush_tlb_all + * + * Description: This routine flushes all processes TLBs. + * 1.Request other CPU to execute 'flush_tlb_all_ipi()'. + * 2.Execute 'do_flush_tlb_all_local()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_all(void) +{ + unsigned long flags; + + preempt_disable(); + local_irq_save(flags); + __flush_tlb_all(); + local_irq_restore(flags); + smp_call_function(flush_tlb_all_ipi, 0, 1, 1); + preempt_enable(); +} + +/*==========================================================================* + * Name: flush_tlb_all_ipi + * + * Description: This routine flushes all local TLBs. + * 1.Execute 'do_flush_tlb_all_local()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: *info - not used + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void flush_tlb_all_ipi(void *info) +{ + __flush_tlb_all(); +} + +/*==========================================================================* + * Name: smp_flush_tlb_mm + * + * Description: This routine flushes the specified mm context TLB's. + * + * Born on Date: 2002.02.05 + * + * Arguments: *mm - a pointer to the mm struct for flush TLB + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_mm(struct mm_struct *mm) +{ + int cpu_id = smp_processor_id(); + cpumask_t cpu_mask; + unsigned long *mmc = &mm->context[cpu_id]; + unsigned long flags; + + preempt_disable(); + cpu_mask = mm->cpu_vm_mask; + cpu_clear(cpu_id, cpu_mask); + + if (*mmc != NO_CONTEXT) { + local_irq_save(flags); + *mmc = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + else + cpu_clear(cpu_id, mm->cpu_vm_mask); + local_irq_restore(flags); + } + if (!cpus_empty(cpu_mask)) + flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL); + + preempt_enable(); +} + +/*==========================================================================* + * Name: smp_flush_tlb_range + * + * Description: This routine flushes a range of pages. + * + * Born on Date: 2002.02.05 + * + * Arguments: *mm - a pointer to the mm struct for flush TLB + * start - not used + * end - not used + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + smp_flush_tlb_mm(vma->vm_mm); +} + +/*==========================================================================* + * Name: smp_flush_tlb_page + * + * Description: This routine flushes one page. + * + * Born on Date: 2002.02.05 + * + * Arguments: *vma - a pointer to the vma struct include va + * va - virtual address for flush TLB + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va) +{ + struct mm_struct *mm = vma->vm_mm; + int cpu_id = smp_processor_id(); + cpumask_t cpu_mask; + unsigned long *mmc = &mm->context[cpu_id]; + unsigned long flags; + + preempt_disable(); + cpu_mask = mm->cpu_vm_mask; + cpu_clear(cpu_id, cpu_mask); + +#ifdef DEBUG_SMP + if (!mm) + BUG(); +#endif + + if (*mmc != NO_CONTEXT) { + local_irq_save(flags); + va &= PAGE_MASK; + va |= (*mmc & MMU_CONTEXT_ASID_MASK); + __flush_tlb_page(va); + local_irq_restore(flags); + } + if (!cpus_empty(cpu_mask)) + flush_tlb_others(cpu_mask, mm, vma, va); + + preempt_enable(); +} + +/*==========================================================================* + * Name: flush_tlb_others + * + * Description: This routine requests other CPU to execute flush TLB. + * 1.Setup parmeters. + * 2.Send 'INVALIDATE_TLB_IPI' to other CPU. + * Request other CPU to execute 'smp_invalidate_interrupt()'. + * 3.Wait for other CPUs operation finished. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpumask - bitmap of target CPUs + * *mm - a pointer to the mm struct for flush TLB + * *vma - a pointer to the vma struct include va + * va - virtual address for flush TLB + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, + struct vm_area_struct *vma, unsigned long va) +{ + unsigned long *mask; +#ifdef DEBUG_SMP + unsigned long flags; + __save_flags(flags); + if (!(flags & 0x0040)) /* Interrupt Disable NONONO */ + BUG(); +#endif /* DEBUG_SMP */ + + /* + * A couple of (to be removed) sanity checks: + * + * - we do not send IPIs to not-yet booted CPUs. + * - current CPU must not be in mask + * - mask must exist :) + */ + BUG_ON(cpus_empty(cpumask)); + + BUG_ON(cpu_isset(smp_processor_id(), cpumask)); + BUG_ON(!mm); + + /* If a CPU which we ran on has gone down, OK. */ + cpus_and(cpumask, cpumask, cpu_online_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. + * Temporarily this turns IRQs off, so that lockups are + * detected by the NMI watchdog. + */ + spin_lock(&tlbstate_lock); + + flush_mm = mm; + flush_vma = vma; + flush_va = va; + mask=cpus_addr(cpumask); + atomic_set_mask(*mask, (atomic_t *)&flush_cpumask); + + /* + * We have to send the IPI only to + * CPUs affected. + */ + send_IPI_mask(cpumask, INVALIDATE_TLB_IPI, 0); + + while (!cpus_empty(flush_cpumask)) { + /* nothing. lockup detection does not belong here */ + mb(); + } + + flush_mm = NULL; + flush_vma = NULL; + flush_va = 0; + spin_unlock(&tlbstate_lock); +} + +/*==========================================================================* + * Name: smp_invalidate_interrupt + * + * Description: This routine executes on CPU which received + * 'INVALIDATE_TLB_IPI'. + * 1.Flush local TLB. + * 2.Report flush TLB process was finished. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_invalidate_interrupt(void) +{ + int cpu_id = smp_processor_id(); + unsigned long *mmc = &flush_mm->context[cpu_id]; + + if (!cpu_isset(cpu_id, flush_cpumask)) + return; + + if (flush_va == FLUSH_ALL) { + *mmc = NO_CONTEXT; + if (flush_mm == current->active_mm) + activate_context(flush_mm); + else + cpu_clear(cpu_id, flush_mm->cpu_vm_mask); + } else { + unsigned long va = flush_va; + + if (*mmc != NO_CONTEXT) { + va &= PAGE_MASK; + va |= (*mmc & MMU_CONTEXT_ASID_MASK); + __flush_tlb_page(va); + } + } + cpu_clear(cpu_id, flush_cpumask); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Stop CPU request Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_send_stop + * + * Description: This routine requests stop all CPUs. + * 1.Request other CPU to execute 'stop_this_cpu()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 1, 0); +} + +/*==========================================================================* + * Name: stop_this_cpu + * + * Description: This routine halt CPU. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void stop_this_cpu(void *dummy) +{ + int cpu_id = smp_processor_id(); + + /* + * Remove this CPU: + */ + cpu_clear(cpu_id, cpu_online_map); + + /* + * PSW IE = 1; + * IMASK = 0; + * goto SLEEP + */ + local_irq_disable(); + outl(0, M32R_ICU_IMASK_PORTL); + inl(M32R_ICU_IMASK_PORTL); /* dummy read */ + local_irq_enable(); + + for ( ; ; ); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Call function Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_call_function + * + * Description: This routine sends a 'CALL_FUNCTION_IPI' to all other CPUs + * in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: *func - The function to run. This must be fast and + * non-blocking. + * *info - An arbitrary pointer to pass to the function. + * nonatomic - currently unused. + * wait - If true, wait (atomically) until function has + * completed on other CPUs. + * + * Returns: 0 on success, else a negative status code. Does not return + * until remote CPUs are nearly ready to execute <> or + * are or have executed. + * + * Cautions: You must not call this function with disabled interrupts or + * from a hardware interrupt handler, you may call it from a + * bottom half handler. + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +int smp_call_function(void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + struct call_data_struct data; + int cpus; + +#ifdef DEBUG_SMP + unsigned long flags; + __save_flags(flags); + if (!(flags & 0x0040)) /* Interrupt Disable NONONO */ + BUG(); +#endif /* DEBUG_SMP */ + + /* Holding any lock stops cpus from going down. */ + spin_lock(&call_lock); + cpus = num_online_cpus() - 1; + + if (!cpus) { + spin_unlock(&call_lock); + return 0; + } + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + call_data = &data; + mb(); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(CALL_FUNCTION_IPI, 0); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + barrier(); + + if (wait) + while (atomic_read(&data.finished) != cpus) + barrier(); + spin_unlock(&call_lock); + + return 0; +} + +/*==========================================================================* + * Name: smp_call_function_interrupt + * + * Description: This routine executes on CPU which received + * 'CALL_FUNCTION_IPI'. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_call_function_interrupt(void) +{ + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int 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); + /* + * At this point the info structure may be out of scope unless wait==1 + */ + irq_enter(); + (*func)(info); + irq_exit(); + + if (wait) { + mb(); + atomic_inc(&call_data->finished); + } +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Timer Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_send_timer + * + * Description: This routine sends a 'LOCAL_TIMER_IPI' to all other CPUs + * in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_send_timer(void) +{ + send_IPI_allbutself(LOCAL_TIMER_IPI, 1); +} + +/*==========================================================================* + * Name: smp_send_timer + * + * Description: This routine executes on CPU which received + * 'LOCAL_TIMER_IPI'. + * + * Born on Date: 2002.02.05 + * + * Arguments: *regs - a pointer to the saved regster info + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_ipi_timer_interrupt(struct pt_regs *regs) +{ + irq_enter(); + smp_local_timer_interrupt(regs); + irq_exit(); +} + +/*==========================================================================* + * Name: smp_local_timer_interrupt + * + * Description: Local timer interrupt handler. It does both profiling and + * process statistics/rescheduling. + * We do profiling in every local tick, statistics/rescheduling + * happen only every 'profiling multiplier' ticks. The default + * multiplier is 1 and it can be changed by writing the new + * multiplier value into /proc/profile. + * + * Born on Date: 2002.02.05 + * + * Arguments: *regs - a pointer to the saved regster info + * + * Returns: void (cannot fail) + * + * Original: arch/i386/kernel/apic.c + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy use per_cpu structure. + *==========================================================================*/ +void smp_local_timer_interrupt(struct pt_regs *regs) +{ + int user = user_mode(regs); + int cpu_id = smp_processor_id(); + + /* + * The profiling function is SMP safe. (nothing can mess + * around with "current", and the profiling counters are + * updated with atomic operations). This is especially + * useful with a profiling multiplier != 1 + */ + + profile_tick(CPU_PROFILING, regs); + + if (--per_cpu(prof_counter, cpu_id) <= 0) { + /* + * The multiplier may have changed since the last time we got + * to this point as a result of the user writing to + * /proc/profile. In this case we need to adjust the APIC + * timer accordingly. + * + * Interrupts are already masked off at this point. + */ + per_cpu(prof_counter, cpu_id) + = per_cpu(prof_multiplier, cpu_id); + if (per_cpu(prof_counter, cpu_id) + != per_cpu(prof_old_multiplier, cpu_id)) + { + per_cpu(prof_old_multiplier, cpu_id) + = per_cpu(prof_counter, cpu_id); + } + + update_process_times(user); + } +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Send IPI Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: send_IPI_allbutself + * + * Description: This routine sends a IPI to all other CPUs in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: ipi_num - Number of IPI + * try - 0 : Send IPI certainly. + * !0 : The following IPI is not sended when Target CPU + * has not received the before IPI. + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void send_IPI_allbutself(int ipi_num, int try) +{ + cpumask_t cpumask; + + cpumask = cpu_online_map; + cpu_clear(smp_processor_id(), cpumask); + + send_IPI_mask(cpumask, ipi_num, try); +} + +/*==========================================================================* + * Name: send_IPI_mask + * + * Description: This routine sends a IPI to CPUs in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpu_mask - Bitmap of target CPUs logical ID + * ipi_num - Number of IPI + * try - 0 : Send IPI certainly. + * !0 : The following IPI is not sended when Target CPU + * has not received the before IPI. + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void send_IPI_mask(cpumask_t cpumask, int ipi_num, int try) +{ + cpumask_t physid_mask, tmp; + int cpu_id, phys_id; + int num_cpus = num_online_cpus(); + + if (num_cpus <= 1) /* NO MP */ + return; + + cpus_and(tmp, cpumask, cpu_online_map); + BUG_ON(!cpus_equal(cpumask, tmp)); + + physid_mask = CPU_MASK_NONE; + for_each_cpu_mask(cpu_id, cpumask){ + if ((phys_id = cpu_to_physid(cpu_id)) != -1) + cpu_set(phys_id, physid_mask); + } + + send_IPI_mask_phys(physid_mask, ipi_num, try); +} + +/*==========================================================================* + * Name: send_IPI_mask_phys + * + * Description: This routine sends a IPI to other CPUs in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpu_mask - Bitmap of target CPUs physical ID + * ipi_num - Number of IPI + * try - 0 : Send IPI certainly. + * !0 : The following IPI is not sended when Target CPU + * has not received the before IPI. + * + * Returns: IPICRi regster value. + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num, + int try) +{ + spinlock_t *ipilock; + unsigned long flags = 0; + volatile unsigned long *ipicr_addr; + unsigned long ipicr_val; + unsigned long my_physid_mask; + unsigned long mask = cpus_addr(physid_mask)[0]; + + + if (mask & ~physids_coerce(phys_cpu_present_map)) + BUG(); + if (ipi_num >= NR_IPIS) + BUG(); + + mask <<= IPI_SHIFT; + ipilock = &ipi_lock[ipi_num]; + ipicr_addr = (volatile unsigned long *)(M32R_ICU_IPICR_ADDR + + (ipi_num << 2)); + my_physid_mask = ~(1 << smp_processor_id()); + + /* + * lock ipi_lock[i] + * check IPICRi == 0 + * write IPICRi (send IPIi) + * unlock ipi_lock[i] + */ + __asm__ __volatile__ ( + ";; LOCK ipi_lock[i] \n\t" + ".fillinsn \n" + "1: \n\t" + "mvfc %1, psw \n\t" + "clrpsw #0x40 -> nop \n\t" + DCACHE_CLEAR("r4", "r5", "%2") + "lock r4, @%2 \n\t" + "addi r4, #-1 \n\t" + "unlock r4, @%2 \n\t" + "mvtc %1, psw \n\t" + "bnez r4, 2f \n\t" + LOCK_SECTION_START(".balign 4 \n\t") + ".fillinsn \n" + "2: \n\t" + "ld r4, @%2 \n\t" + "blez r4, 2b \n\t" + "bra 1b \n\t" + LOCK_SECTION_END + ";; CHECK IPICRi == 0 \n\t" + ".fillinsn \n" + "3: \n\t" + "ld %0, @%3 \n\t" + "and %0, %6 \n\t" + "beqz %0, 4f \n\t" + "bnez %5, 5f \n\t" + "bra 3b \n\t" + ";; WRITE IPICRi (send IPIi) \n\t" + ".fillinsn \n" + "4: \n\t" + "st %4, @%3 \n\t" + ";; UNLOCK ipi_lock[i] \n\t" + ".fillinsn \n" + "5: \n\t" + "ldi r4, #1 \n\t" + "st r4, @%2 \n\t" + : "=&r"(ipicr_val) + : "r"(flags), "r"(&ipilock->lock), "r"(ipicr_addr), + "r"(mask), "r"(try), "r"(my_physid_mask) + : "memory", "r4" +#ifdef CONFIG_CHIP_M32700_TS1 + , "r5" +#endif /* CONFIG_CHIP_M32700_TS1 */ + ); + + return ipicr_val; +} diff -Nru a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/smpboot.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,635 @@ +/* + * linux/arch/m32r/kernel/smpboot.c + * orig : i386 2.4.10 + * + * M32R SMP booting functions + * + * Copyright (c) 2001, 2002, 2003 Hitoshi Yamamoto + * + * Taken from i386 version. + * (c) 1995 Alan Cox, Building #3 + * (c) 1998, 1999, 2000 Ingo Molnar + * + * Much of the core SMP work is based on previous work by Thomas Radke, to + * whom a great many thanks are extended. + * + * Thanks to Intel for making available several different Pentium, + * Pentium Pro and Pentium-II/Xeon MP machines. + * Original development of Linux SMP code supported by Caldera. + * + * This code is released under the GNU General Public License version 2 or + * later. + * + * Fixes + * Felix Koop : NR_CPUS used properly + * Jose Renau : Handle single CPU case. + * Alan Cox : By repeated request + * 8) - Total BogoMIP report. + * Greg Wright : Fix for kernel stacks panic. + * Erich Boleyn : MP v1.4 and additional changes. + * Matthias Sattler : Changes for 2.1 kernel map. + * Michel Lespinasse : Changes for 2.1 kernel map. + * Michael Chastain : Change trampoline.S to gnu as. + * Alan Cox : Dumb bug: 'B' step PPro's are fine + * Ingo Molnar : Added APIC timers, based on code + * from Jose Renau + * Ingo Molnar : various cleanups and rewrites + * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. + * Maciej W. Rozycki : Bits for genuine 82489DX APICs + * Martin J. Bligh : Added support for multi-quad systems + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DEBUG_SMP +#ifdef DEBUG_SMP +#define Dprintk(x...) printk(x) +#else +#define Dprintk(x...) +#endif + +extern int cpu_idle(void); +extern cpumask_t cpu_initialized; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Data structures and variables */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/* Processor that is doing the boot up */ +static unsigned int bsp_phys_id = -1; + +/* Bitmask of physically existing CPUs */ +physid_mask_t phys_cpu_present_map; + +/* Bitmask of currently online CPUs */ +cpumask_t cpu_online_map; + +cpumask_t cpu_bootout_map; +cpumask_t cpu_bootin_map; +cpumask_t cpu_callout_map; +static cpumask_t cpu_callin_map; + +/* Per CPU bogomips and other parameters */ +struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned; + +/* Set when the idlers are all forked */ +int smp_threads_ready; + +static int cpucount; +static cpumask_t smp_commenced_mask; + +extern struct { + void * spi; + unsigned short ss; +} stack_start; + +/* which physical physical ID maps to which logical CPU number */ +static volatile int physid_2_cpu[NR_CPUS]; + +/* which logical CPU number maps to which physical ID */ +volatile int cpu_2_physid[NR_CPUS]; + +DEFINE_PER_CPU(int, prof_multiplier) = 1; +DEFINE_PER_CPU(int, prof_old_multiplier) = 1; +DEFINE_PER_CPU(int, prof_counter) = 1; + +spinlock_t ipi_lock[NR_IPIS]; + +static unsigned int calibration_result; + +unsigned long cache_decay_ticks = HZ / 100; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Function Prototypes */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +void smp_prepare_boot_cpu(void); +void smp_prepare_cpus(unsigned int); +static void smp_tune_scheduling(void); +static void init_ipi_lock(void); +static void do_boot_cpu(int); +int __cpu_up(unsigned int); +void smp_cpus_done(unsigned int); + +int start_secondary(void *); +static void smp_callin(void); +static void smp_online(void); + +static void show_mp_info(int); +static void smp_store_cpu_info(int); +static void show_cpu_info(int); +int setup_profiling_timer(unsigned int); +static void init_cpu_to_physid(void); +static void map_cpu_to_physid(int, int); +static void unmap_cpu_to_physid(int, int); + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Boot up APs Routins : BSP */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +void __devinit smp_prepare_boot_cpu(void) +{ + bsp_phys_id = hard_smp_processor_id(); + physid_set(bsp_phys_id, phys_cpu_present_map); + cpu_set(0, cpu_online_map); /* BSP's cpu_id == 0 */ + cpu_set(0, cpu_callout_map); + cpu_set(0, cpu_callin_map); + + /* + * Initialize the logical to physical CPU number mapping + */ + init_cpu_to_physid(); + map_cpu_to_physid(0, bsp_phys_id); + current_thread_info()->cpu = 0; +} + +/*==========================================================================* + * Name: smp_prepare_cpus (old smp_boot_cpus) + * + * Description: This routine boot up APs. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + int phys_id; + unsigned long nr_cpu; + + nr_cpu = inl(M32R_FPGA_NUM_OF_CPUS_PORTL); + if (nr_cpu > NR_CPUS) { + printk(KERN_INFO "NUM_OF_CPUS reg. value [%ld] > NR_CPU [%d]", + nr_cpu, NR_CPUS); + goto smp_done; + } + for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++) + physid_set(phys_id, phys_cpu_present_map); + + show_mp_info(nr_cpu); + + init_ipi_lock(); + + /* + * Setup boot CPU information + */ + smp_store_cpu_info(0); /* Final full version of the data */ + smp_tune_scheduling(); + + /* + * If SMP should be disabled, then really disable it! + */ + if (!max_cpus) { + printk(KERN_INFO "SMP mode deactivated by commandline.\n"); + goto smp_done; + } + + /* + * Now scan the CPU present map and fire up the other CPUs. + */ + Dprintk("CPU present map : %lx\n", physids_coerce(phys_cpu_present_map)); + + for (phys_id = 0 ; phys_id < NR_CPUS ; phys_id++) { + /* + * Don't even attempt to start the boot CPU! + */ + if (phys_id == bsp_phys_id) + continue; + + if (!physid_isset(phys_id, phys_cpu_present_map)) + continue; + + if ((max_cpus >= 0) && (max_cpus <= cpucount + 1)) + continue; + + do_boot_cpu(phys_id); + + /* + * Make sure we unmap all failed CPUs + */ + if (physid_to_cpu(phys_id) == -1) { + physid_clear(phys_id, phys_cpu_present_map); + printk("phys CPU#%d not responding - " \ + "cannot use it.\n", phys_id); + } + } + +smp_done: + Dprintk("Boot done.\n"); +} + +static void __init smp_tune_scheduling(void) +{ + /* Nothing to do. */ +} + +/* + * init_ipi_lock : Initialize IPI locks. + */ +static void __init init_ipi_lock(void) +{ + int ipi; + + for (ipi = 0 ; ipi < NR_IPIS ; ipi++) + ipi_lock[ipi] = SPIN_LOCK_UNLOCKED; +} + +/*==========================================================================* + * Name: do_boot_cpu + * + * Description: This routine boot up one AP. + * + * Born on Date: 2002.02.05 + * + * Arguments: phys_id - Target CPU physical ID + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +static void __init do_boot_cpu(int phys_id) +{ + struct task_struct *idle; + unsigned long send_status, boot_status; + int timeout, cpu_id; + + cpu_id = ++cpucount; + + /* + * We can't use kernel_thread since we must avoid to + * reschedule the child. + */ + idle = fork_idle(cpu_id); + if (IS_ERR(idle)) + panic("failed fork for CPU#%d.", cpu_id); + + idle->thread.lr = (unsigned long)start_secondary; + + map_cpu_to_physid(cpu_id, phys_id); + + /* So we see what's up */ + printk("Booting processor %d/%d\n", phys_id, cpu_id); + stack_start.spi = (void *)idle->thread.sp; + idle->thread_info->cpu = cpu_id; + + /* + * Send Startup IPI + * 1.IPI received by CPU#(phys_id). + * 2.CPU#(phys_id) enter startup_AP (arch/m32r/kernel/head.S) + * 3.CPU#(phys_id) enter start_secondary() + */ + send_status = 0; + boot_status = 0; + + cpu_set(phys_id, cpu_bootout_map); + + /* Send Startup IPI */ + send_IPI_mask_phys(cpumask_of_cpu(phys_id), CPU_BOOT_IPI, 0); + + Dprintk("Waiting for send to finish...\n"); + timeout = 0; + + /* Wait 100[ms] */ + do { + Dprintk("+"); + udelay(1000); + send_status = !cpu_isset(phys_id, cpu_bootin_map); + } while (send_status && (timeout++ < 100)); + + Dprintk("After Startup.\n"); + + if (!send_status) { + /* + * allow APs to start initializing. + */ + Dprintk("Before Callout %d.\n", cpu_id); + cpu_set(cpu_id, cpu_callout_map); + Dprintk("After Callout %d.\n", cpu_id); + + /* + * Wait 5s total for a response + */ + for (timeout = 0; timeout < 5000; timeout++) { + if (cpu_isset(cpu_id, cpu_callin_map)) + break; /* It has booted */ + udelay(1000); + } + + if (cpu_isset(cpu_id, cpu_callin_map)) { + /* number CPUs logically, starting from 1 (BSP is 0) */ + Dprintk("OK.\n"); + } else { + boot_status = 1; + printk("Not responding.\n"); + } + } else + printk("IPI never delivered???\n"); + + if (send_status || boot_status) { + unmap_cpu_to_physid(cpu_id, phys_id); + cpu_clear(cpu_id, cpu_callout_map); + cpu_clear(cpu_id, cpu_callin_map); + cpu_clear(cpu_id, cpu_initialized); + cpucount--; + } +} + +int __devinit __cpu_up(unsigned int cpu_id) +{ + int timeout; + + cpu_set(cpu_id, smp_commenced_mask); + + /* + * Wait 5s total for a response + */ + for (timeout = 0; timeout < 5000; timeout++) { + if (cpu_isset(cpu_id, cpu_online_map)) + break; + udelay(1000); + } + if (!cpu_isset(cpu_id, cpu_online_map)) + BUG(); + + return 0; +} + +void __init smp_cpus_done(unsigned int max_cpus) +{ + int cpu_id, timeout; + unsigned long bogosum = 0; + + for (timeout = 0; timeout < 5000; timeout++) { + if (cpus_equal(cpu_callin_map, cpu_online_map)) + break; + udelay(1000); + } + if (!cpus_equal(cpu_callin_map, cpu_online_map)) + BUG(); + + for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++) + show_cpu_info(cpu_id); + + /* + * Allow the user to impress friends. + */ + Dprintk("Before bogomips.\n"); + if (cpucount) { + for_each_cpu_mask(cpu_id, cpu_online_map) + bogosum += cpu_data[cpu_id].loops_per_jiffy; + + printk(KERN_INFO "Total of %d processors activated " \ + "(%lu.%02lu BogoMIPS).\n", cpucount + 1, + bogosum / (500000 / HZ), + (bogosum / (5000 / HZ)) % 100); + Dprintk("Before bogocount - setting activated=1.\n"); + } +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Activate a secondary processor Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: start_secondary + * + * Description: This routine activate a secondary processor. + * + * Born on Date: 2002.02.05 + * + * Arguments: *unused - currently unused. + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +int __init start_secondary(void *unused) +{ + cpu_init(); + smp_callin(); + while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) + rep_nop(); + + smp_online(); + + /* + * low-memory mappings have been cleared, flush them from + * the local TLBs too. + */ + local_flush_tlb_all(); + + return cpu_idle(); +} + +/*==========================================================================* + * Name: smp_callin + * + * Description: This routine activate a secondary processor. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +static void __init smp_callin(void) +{ + int phys_id = hard_smp_processor_id(); + int cpu_id = smp_processor_id(); + unsigned long timeout; + + if (cpu_isset(cpu_id, cpu_callin_map)) { + printk("huh, phys CPU#%d, CPU#%d already present??\n", + phys_id, cpu_id); + BUG(); + } + Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpu_id, phys_id); + + /* Waiting 2s total for startup (udelay is not yet working) */ + timeout = jiffies + (2 * HZ); + while (time_before(jiffies, timeout)) { + /* Has the boot CPU finished it's STARTUP sequence ? */ + if (cpu_isset(cpu_id, cpu_callout_map)) + break; + rep_nop(); + } + + if (!time_before(jiffies, timeout)) { + printk("BUG: CPU#%d started up but did not get a callout!\n", + cpu_id); + BUG(); + } + + /* Allow the master to continue. */ + cpu_set(cpu_id, cpu_callin_map); +} + +static void __init smp_online(void) +{ + int cpu_id = smp_processor_id(); + + local_irq_enable(); + + /* Get our bogomips. */ + calibrate_delay(); + + /* Save our processor parameters */ + smp_store_cpu_info(cpu_id); + + cpu_set(cpu_id, cpu_online_map); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Boot up CPUs common Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +static void __init show_mp_info(int nr_cpu) +{ + int i; + char cpu_model0[17], cpu_model1[17], cpu_ver[9]; + + strncpy(cpu_model0, (char *)M32R_FPGA_CPU_NAME_ADDR, 16); + strncpy(cpu_model1, (char *)M32R_FPGA_MODEL_ID_ADDR, 16); + strncpy(cpu_ver, (char *)M32R_FPGA_VERSION_ADDR, 8); + + cpu_model0[16] = '\0'; + for (i = 15 ; i >= 0 ; i--) { + if (cpu_model0[i] != ' ') + break; + cpu_model0[i] = '\0'; + } + cpu_model1[16] = '\0'; + for (i = 15 ; i >= 0 ; i--) { + if (cpu_model1[i] != ' ') + break; + cpu_model1[i] = '\0'; + } + cpu_ver[8] = '\0'; + for (i = 7 ; i >= 0 ; i--) { + if (cpu_ver[i] != ' ') + break; + cpu_ver[i] = '\0'; + } + + printk(KERN_INFO "M32R-mp information\n"); + printk(KERN_INFO " On-chip CPUs : %d\n", nr_cpu); + printk(KERN_INFO " CPU model : %s/%s(%s)\n", cpu_model0, + cpu_model1, cpu_ver); +} + +/* + * The bootstrap kernel entry code has set these up. Save them for + * a given CPU + */ +static void __init smp_store_cpu_info(int cpu_id) +{ + struct cpuinfo_m32r *ci = cpu_data + cpu_id; + + *ci = boot_cpu_data; + ci->loops_per_jiffy = loops_per_jiffy; +} + +static void __init show_cpu_info(int cpu_id) +{ + struct cpuinfo_m32r *ci = &cpu_data[cpu_id]; + + printk("CPU#%d : ", cpu_id); + +#define PRINT_CLOCK(name, value) \ + printk(name " clock %d.%02dMHz", \ + ((value) / 1000000), ((value) % 1000000) / 10000) + + PRINT_CLOCK("CPU", (int)ci->cpu_clock); + PRINT_CLOCK(", Bus", (int)ci->bus_clock); + printk(", loops_per_jiffy[%ld]\n", ci->loops_per_jiffy); +} + +/* + * the frequency of the profiling timer can be changed + * by writing a multiplier value into /proc/profile. + */ +int setup_profiling_timer(unsigned int multiplier) +{ + int i; + + /* + * Sanity check. [at least 500 APIC cycles should be + * between APIC interrupts as a rule of thumb, to avoid + * irqs flooding us] + */ + if ( (!multiplier) || (calibration_result / multiplier < 500)) + return -EINVAL; + + /* + * Set the new multiplier for each CPU. CPUs don't start using the + * new values until the next timer interrupt in which they do process + * accounting. At that time they also adjust their APIC timers + * accordingly. + */ + for (i = 0; i < NR_CPUS; ++i) + per_cpu(prof_multiplier, i) = multiplier; + + return 0; +} + +/* Initialize all maps between cpu number and apicids */ +static void __init init_cpu_to_physid(void) +{ + int i; + + for (i = 0 ; i < NR_CPUS ; i++) { + cpu_2_physid[i] = -1; + physid_2_cpu[i] = -1; + } +} + +/* + * set up a mapping between cpu and apicid. Uses logical apicids for multiquad, + * else physical apic ids + */ +static void __init map_cpu_to_physid(int cpu_id, int phys_id) +{ + physid_2_cpu[phys_id] = cpu_id; + cpu_2_physid[cpu_id] = phys_id; +} + +/* + * undo a mapping between cpu and apicid. Uses logical apicids for multiquad, + * else physical apic ids + */ +static void __init unmap_cpu_to_physid(int cpu_id, int phys_id) +{ + physid_2_cpu[phys_id] = -1; + cpu_2_physid[cpu_id] = -1; +} + diff -Nru a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/sys_m32r.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,217 @@ +/* + * linux/arch/m32r/kernel/sys_m32r.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/M32R platform. + * + * Taken from i386 version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * sys_tas() - test-and-set + * linuxthreads testing version + */ +#ifndef CONFIG_SMP +asmlinkage int sys_tas(int *addr) +{ + int oldval; + unsigned long flags; + + if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) + return -EFAULT; + local_irq_save(flags); + oldval = *addr; + *addr = 1; + local_irq_restore(flags); + return oldval; +} +#else /* CONFIG_SMP */ +#include + +static spinlock_t tas_lock = SPIN_LOCK_UNLOCKED; + +asmlinkage int sys_tas(int *addr) +{ + int oldval; + + if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) + return -EFAULT; + + spin_lock(&tas_lock); + oldval = *addr; + *addr = 1; + spin_unlock(&tas_lock); + + return oldval; +} +#endif /* CONFIG_SMP */ + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way Unix traditionally does this, though. + */ +asmlinkage int +sys_pipe(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, struct pt_regs regs) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +asmlinkage long sys_mmap2(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; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc(uint call, int first, int second, + int third, void __user *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + case SEMOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, (const struct timespec __user *)fifth); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void __user * __user *) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf __user *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge __user *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf __user *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, + (struct msqid_ds __user *) ptr); + case SHMAT: { + ulong raddr; + + if ((ret = verify_area(VERIFY_WRITE, (ulong __user *) third, + sizeof(ulong)))) + return ret; + ret = do_shmat (first, (char __user *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong __user *) third); + } + case SHMDT: + return sys_shmdt ((char __user *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds __user *) ptr); + default: + return -ENOSYS; + } +} + +asmlinkage int sys_uname(struct old_utsname * name) +{ + int err; + if (!name) + return -EFAULT; + down_read(&uts_sem); + err=copy_to_user(name, &system_utsname, sizeof (*name)); + up_read(&uts_sem); + return err?-EFAULT:0; +} + +asmlinkage int sys_cacheflush(void *addr, int bytes, int cache) +{ + /* This should flush more selectivly ... */ + _flush_cache_all(); + return 0; +} + +asmlinkage int sys_cachectl(char *addr, int nbytes, int op) +{ + /* Not implemented yet. */ + return -ENOSYS; +} + diff -Nru a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/time.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,317 @@ +/* + * linux/arch/m32r/kernel/time.c + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + * Taken from i386 version. + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1996, 1997, 1998 Ralf Baechle + * + * This file contains the time handling details for PC-style clocks as + * found in some MIPS systems. + * + * Some code taken from sh version. + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka + * Copyright (C) 2000 Philipp Rumpf + */ + +#undef DEBUG_TIMER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifdef CONFIG_SMP +extern void send_IPI_allbutself(int, int); +extern void smp_local_timer_interrupt(struct pt_regs *); +#endif + +u64 jiffies_64 = INITIAL_JIFFIES; + +EXPORT_SYMBOL(jiffies_64); + +extern unsigned long wall_jiffies; +#define TICK_SIZE (tick_nsec / 1000) + +/* + * Change this if you have some constant time drift + */ + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +static unsigned long latch; + +static unsigned long do_gettimeoffset(void) +{ + unsigned long elapsed_time = 0; /* [us] */ + +#if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ + || defined(CONFIG_CHIP_OPSP) +#ifndef CONFIG_SMP + + unsigned long count; + + /* timer count may underflow right here */ + count = inl(M32R_MFT2CUT_PORTL); + + if (inl(M32R_ICU_CR18_PORTL) & 0x00000100) /* underflow check */ + count = 0; + + count = (latch - count) * TICK_SIZE; + elapsed_time = (count + latch / 2) / latch; + /* NOTE: LATCH is equal to the "interval" value (= reload count). */ + +#else /* CONFIG_SMP */ + unsigned long count; + static unsigned long p_jiffies = -1; + static unsigned long p_count = 0; + + /* timer count may underflow right here */ + count = inl(M32R_MFT2CUT_PORTL); + + if (jiffies == p_jiffies && count > p_count) + count = 0; + + p_jiffies = jiffies; + p_count = count; + + count = (latch - count) * TICK_SIZE; + elapsed_time = (count + latch / 2) / latch; + /* NOTE: LATCH is equal to the "interval" value (= reload count). */ +#endif /* CONFIG_SMP */ +#elif defined(CONFIG_CHIP_M32310) +#warning do_gettimeoffse not implemented +#else +#error no chip configuration +#endif + + return elapsed_time; +} + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long seq; + unsigned long usec, sec; + unsigned long max_ntp_tick = tick_usec - tickadj; + + do { + unsigned long lost; + + seq = read_seqbegin(&xtime_lock); + + usec = do_gettimeoffset(); + lost = jiffies - wall_jiffies; + + /* + * If time_adjust is negative then NTP is slowing the clock + * so make sure not to go into next possible interval. + * Better to lose some accuracy than have time go backwards.. + */ + if (unlikely(time_adjust < 0)) { + usec = min(usec, max_ntp_tick); + if (lost) + usec += lost * max_ntp_tick; + } else if (unlikely(lost)) + usec += lost * tick_usec; + + sec = xtime.tv_sec; + usec += (xtime.tv_nsec / 1000); + } while (read_seqretry(&xtime_lock, seq)); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +EXPORT_SYMBOL(do_gettimeofday); + +int do_settimeofday(struct timespec *tv) +{ + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_nsec; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + /* + * This is revolting. We need to set "xtime" correctly. However, the + * value in this location is the value at the most recent update of + * wall time. Discover what correction gettimeofday() would have + * made, and then undo it! + */ + nsec -= do_gettimeoffset() * NSEC_PER_USEC; + nsec -= (jiffies - wall_jiffies) * TICK_NSEC; + + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_sequnlock_irq(&xtime_lock); + clock_was_set(); + + return 0; +} + +EXPORT_SYMBOL(do_settimeofday); + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ +static __inline__ int set_rtc_mmss(unsigned long nowtime) +{ + return 0; +} + +/* last time the cmos clock got updated */ +static long last_rtc_update = 0; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static __inline__ void do_timer_interrupt(int irq, void *dev_id, + struct pt_regs * regs) +{ + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if ((time_status & STA_UNSYNC) == 0 + && xtime.tv_sec > last_rtc_update + 660 + && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2 + && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2) + { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; + } + /* As we return to user mode fire off the other CPU schedulers.. + this is basically because we don't yet share IRQ's around. + This message is rigged to be safe on the 386 - basically it's + a hack, so don't look closely for now.. */ + +#ifdef CONFIG_SMP + smp_local_timer_interrupt(regs); +#endif +} + +irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + write_seqlock(&xtime_lock); + do_timer_interrupt(irq, NULL, regs); + write_sequnlock(&xtime_lock); + +#ifndef CONFIG_SMP + profile_tick(CPU_PROFILING, regs); +#endif + + return IRQ_HANDLED; +} + +struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, + "MFT2", NULL, NULL }; + +void __init time_init(void) +{ + unsigned int epoch, year, mon, day, hour, min, sec; + + sec = min = hour = day = mon = year = 0; + epoch = 0; + + year = 23; + mon = 4; + day = 17; + + /* Attempt to guess the epoch. This is the same heuristic as in rtc.c + so no stupid things will happen to timekeeping. Who knows, maybe + Ultrix also uses 1952 as epoch ... */ + if (year > 10 && year < 44) + epoch = 1980; + else if (year < 96) + epoch = 1952; + year += epoch; + + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); + wall_to_monotonic.tv_sec = -xtime.tv_sec; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; + +#if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ + || defined(CONFIG_CHIP_OPSP) + + /* M32102 MFT setup */ + setup_irq(M32R_IRQ_MFT2, &irq0); + { + unsigned long bus_clock; + unsigned short divide; + + bus_clock = boot_cpu_data.bus_clock; + divide = boot_cpu_data.timer_divide; + latch = (bus_clock/divide + HZ / 2) / HZ; + + printk("Timer start : latch = %ld\n", latch); + + outl((M32R_MFTMOD_CC_MASK | M32R_MFTMOD_TCCR \ + |M32R_MFTMOD_CSSEL011), M32R_MFT2MOD_PORTL); + outl(latch, M32R_MFT2RLD_PORTL); + outl(latch, M32R_MFT2CUT_PORTL); + outl(0, M32R_MFT2CMPRLD_PORTL); + outl((M32R_MFTCR_MFT2MSK|M32R_MFTCR_MFT2EN), M32R_MFTCR_PORTL); + } + +#elif defined(CONFIG_CHIP_M32310) +#warning time_init not implemented +#else +#error no chip configuration +#endif +} + +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies * (1000000000 / HZ); +} + diff -Nru a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/traps.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,330 @@ +/* + * linux/arch/m32r/kernel/traps.c + * + * Copyright (C) 2001, 2002 Hirokazu Takata, Hiroyuki Kondo, + * Hitoshi Yamamoto + */ + +/* $Id$ */ + +/* + * 'traps.c' handles hardware traps and faults after we have saved some + * state in 'entry.S'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +asmlinkage void alignment_check(void); +asmlinkage void ei_handler(void); +asmlinkage void rie_handler(void); +asmlinkage void debug_trap(void); +asmlinkage void cache_flushing_handler(void); + +#ifdef CONFIG_SMP +extern void smp_reschedule_interrupt(void); +extern void smp_invalidate_interrupt(void); +extern void smp_call_function_interrupt(void); +extern void smp_ipi_timer_interrupt(void); +extern void smp_flush_cache_all_interrupt(void); + +/* + * for Boot AP function + */ +asm ( + " .section .eit_vector4,\"ax\" \n" + " .global _AP_RE \n" + " .global startup_AP \n" + "_AP_RE: \n" + " .fill 32, 4, 0 \n" + "_AP_EI: bra startup_AP \n" + " .previous \n" +); +#endif /* CONFIG_SMP */ + +extern unsigned long eit_vector[]; +#define BRA_INSN(func, entry) \ + ((unsigned long)func - (unsigned long)eit_vector - entry*4)/4 \ + + 0xff000000UL + +void set_eit_vector_entries(void) +{ + extern void default_eit_handler(void); + extern void system_call(void); + extern void pie_handler(void); + extern void ace_handler(void); + extern void tme_handler(void); + extern void _flush_cache_copyback_all(void); + + eit_vector[0] = 0xd0c00001; /* seth r0, 0x01 */ + eit_vector[1] = BRA_INSN(default_eit_handler, 1); + eit_vector[4] = 0xd0c00010; /* seth r0, 0x10 */ + eit_vector[5] = BRA_INSN(default_eit_handler, 5); + eit_vector[8] = BRA_INSN(rie_handler, 8); + eit_vector[12] = BRA_INSN(alignment_check, 12); + eit_vector[16] = 0xff000000UL; + eit_vector[17] = BRA_INSN(debug_trap, 17); + eit_vector[18] = BRA_INSN(system_call, 18); + eit_vector[19] = 0xff000000UL; + eit_vector[20] = 0xff000000UL; + eit_vector[21] = 0xff000000UL; + eit_vector[22] = 0xff000000UL; + eit_vector[23] = 0xff000000UL; + eit_vector[24] = 0xff000000UL; + eit_vector[25] = 0xff000000UL; + eit_vector[26] = 0xff000000UL; + eit_vector[27] = 0xff000000UL; + eit_vector[28] = BRA_INSN(cache_flushing_handler, 28); + eit_vector[29] = 0xff000000UL; + eit_vector[30] = 0xff000000UL; + eit_vector[31] = 0xff000000UL; + eit_vector[32] = BRA_INSN(ei_handler, 32); + eit_vector[64] = BRA_INSN(pie_handler, 64); + eit_vector[68] = BRA_INSN(ace_handler, 68); + eit_vector[72] = BRA_INSN(tme_handler, 72); +#ifdef CONFIG_SMP + eit_vector[184] = (unsigned long)smp_reschedule_interrupt; + eit_vector[185] = (unsigned long)smp_invalidate_interrupt; + eit_vector[186] = (unsigned long)smp_call_function_interrupt; + eit_vector[187] = (unsigned long)smp_ipi_timer_interrupt; + eit_vector[188] = (unsigned long)smp_flush_cache_all_interrupt; + eit_vector[189] = 0; + eit_vector[190] = 0; + eit_vector[191] = 0; +#endif + _flush_cache_copyback_all(); +} + +void __init trap_init(void) +{ + set_eit_vector_entries(); + + /* + * Should be a barrier for any external CPU state. + */ + cpu_init(); +} + +int kstack_depth_to_print = 24; + +void show_trace(struct task_struct *task, unsigned long *stack) +{ + unsigned long addr; + + if (!stack) + stack = (unsigned long*)&stack; + + printk("Call Trace: "); + while (!kstack_end(stack)) { + addr = *stack++; + if (__kernel_text_address(addr)) { + printk("[<%08lx>] ", addr); + print_symbol("%s\n", addr); + } + } + printk("\n"); +} + +void show_stack(struct task_struct *task, unsigned long *sp) +{ + unsigned long *stack; + int i; + + /* + * debugging aid: "show_stack(NULL);" prints the + * back trace for this cpu. + */ + + if(sp==NULL) { + if (task) + sp = (unsigned long *)task->thread.sp; + else + sp=(unsigned long*)&sp; + } + + stack = sp; + for(i=0; i < kstack_depth_to_print; i++) { + if (kstack_end(stack)) + break; + if (i && ((i % 4) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + printk("\n"); + show_trace(task, sp); +} + +void dump_stack(void) +{ + unsigned long stack; + + show_trace(current, &stack); +} + +EXPORT_SYMBOL(dump_stack); + +static void show_registers(struct pt_regs *regs) +{ + int i = 0; + int in_kernel = 1; + unsigned long sp; + + printk("CPU: %d\n", smp_processor_id()); + show_regs(regs); + + sp = (unsigned long) (1+regs); + if (user_mode(regs)) { + in_kernel = 0; + sp = regs->spu; + printk("SPU: %08lx\n", sp); + } else { + printk("SPI: %08lx\n", sp); + } + printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)", + current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current); + + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (in_kernel) { + printk("\nStack: "); + show_stack(current, (unsigned long*) sp); + + printk("\nCode: "); + if (regs->bpc < PAGE_OFFSET) + goto bad; + + for(i=0;i<20;i++) { + unsigned char c; + if (__get_user(c, &((unsigned char*)regs->bpc)[i])) { +bad: + printk(" Bad PC value."); + break; + } + printk("%02x ", c); + } + } + printk("\n"); +} + +spinlock_t die_lock = SPIN_LOCK_UNLOCKED; + +void die(const char * str, struct pt_regs * regs, long err) +{ + console_verbose(); + spin_lock_irq(&die_lock); + bust_spinlocks(1); + printk("%s: %04lx\n", str, err & 0xffff); + show_registers(regs); + bust_spinlocks(0); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +static __inline__ void die_if_kernel(const char * str, + struct pt_regs * regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); +} + +static __inline__ void do_trap(int trapnr, int signr, const char * str, + struct pt_regs * regs, long error_code, siginfo_t *info) +{ + if (user_mode(regs)) { + /* trap_signal */ + struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + if (info) + force_sig_info(signr, info, tsk); + else + force_sig(signr, tsk); + return; + } else { + /* kernel_trap */ + if (!fixup_exception(regs)) + die(str, regs, error_code); + return; + } +} + +#define DO_ERROR(trapnr, signr, str, name) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + do_trap(trapnr, signr, 0, regs, error_code, NULL); \ +} + +#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ + do_trap(trapnr, signr, str, regs, error_code, &info); \ +} + +DO_ERROR( 1, SIGTRAP, "debug trap", debug_trap) +DO_ERROR_INFO(0x20, SIGILL, "reserved instruction ", rie_handler, ILL_ILLOPC, regs->bpc) +DO_ERROR_INFO(0x100, SIGILL, "privilege instruction", pie_handler, ILL_PRVOPC, regs->bpc) + +extern int handle_unaligned_access(unsigned long, struct pt_regs *); + +/* This code taken from arch/sh/kernel/traps.c */ +asmlinkage void do_alignment_check(struct pt_regs *regs, long error_code) +{ + mm_segment_t oldfs; + unsigned long insn; + int tmp; + + oldfs = get_fs(); + + if (user_mode(regs)) { + local_irq_enable(); + current->thread.error_code = error_code; + current->thread.trap_no = 0x17; + + set_fs(USER_DS); + if (copy_from_user(&insn, (void *)regs->bpc, 4)) { + set_fs(oldfs); + goto uspace_segv; + } + tmp = handle_unaligned_access(insn, regs); + set_fs(oldfs); + + if (!tmp) + return; + + uspace_segv: + printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " + "access\n", current->comm); + force_sig(SIGSEGV, current); + } else { + set_fs(KERNEL_DS); + if (copy_from_user(&insn, (void *)regs->bpc, 4)) { + set_fs(oldfs); + die("insn faulting in do_address_error", regs, 0); + } + handle_unaligned_access(insn, regs); + set_fs(oldfs); + } +} + diff -Nru a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/kernel/vmlinux.lds.S 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,143 @@ +/* ld script to make M32R Linux kernel + */ + +#include +#include +#include +#include + +OUTPUT_ARCH(m32r) +ENTRY(startup_32) +#if defined(__LITTLE_ENDIAN__) + jiffies = jiffies_64; +#else + jiffies = jiffies_64 + 4; +#endif +SECTIONS +{ + . = CONFIG_MEMORY_START + __PAGE_OFFSET; + eit_vector = .; + + . = . + 0x1000; + .empty_zero_page : { *(.empty_zero_page) } = 0 + + /* read-only */ + _text = .; /* Text and read-only data */ + .boot : { *(.boot) } = 0 + .text : { + *(.text) + SCHED_TEXT + LOCK_TEXT + *(.fixup) + *(.gnu.warning) + } = 0x9090 +#ifdef CONFIG_SMP + . = ALIGN(65536); + .eit_vector4 : { *(.eit_vector4) } +#endif + _etext = .; /* End of text section */ + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + RODATA + + /* writeable */ + .data : { /* Data */ + *(.spu) + *(.spi) + *(.data) + CONSTRUCTORS + } + + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + /* will be freed after init */ + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + .init.data : { *(.init.data) } + . = ALIGN(16); + __setup_start = .; + .init.setup : { *(.init.setup) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + } + __initcall_end = .; + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; + SECURITY_INIT + . = ALIGN(4); + __alt_instructions = .; + .altinstructions : { *(.altinstructions) } + __alt_instructions_end = .; + .altinstr_replacement : { *(.altinstr_replacement) } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : { *(.exit.text) } + .exit.data : { *(.exit.data) } + . = ALIGN(4096); + __initramfs_start = .; + .init.ramfs : { *(.init.ramfs) } + __initramfs_end = .; + . = ALIGN(32); + __per_cpu_start = .; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = .; + . = ALIGN(4096); + __init_end = .; + /* freed after init ends here */ + + __bss_start = .; /* BSS */ + .bss : { *(.bss) } + . = ALIGN(4); + __bss_stop = .; + + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -Nru a/arch/m32r/lib/Makefile b/arch/m32r/lib/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/Makefile 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,7 @@ +# +# Makefile for M32R-specific library files.. +# + +lib-y := checksum.o ashxdi3.o memset.o memcpy.o getuser.o \ + putuser.o delay.o strlen.o usercopy.o csum_partial_copy.o + diff -Nru a/arch/m32r/lib/ashxdi3.S b/arch/m32r/lib/ashxdi3.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/ashxdi3.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,297 @@ +/* + * linux/arch/m32r/lib/ashxdi3.S + * + * Copyright (C) 2001,2002 Hiroyuki Kondo, and Hirokazu Takata + * + */ +/* $Id$ */ + +#include + +; +; input (r0,r1) src +; input r2 shift val +; r3 scratch +; output (r0,r1) +; + +#ifdef CONFIG_ISA_DUAL_ISSUE + +#ifndef __LITTLE_ENDIAN__ + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r1, r0 || srai r0, #31 + addi r2, #-32 + sra r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 || srl r1, r2 + sra r0, r2 || neg r2, r2 + sll r3, r2 + or r1, r3 || jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r0, r1 || addi r2, #-32 + sll r0, r2 || ldi r1, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 || sll r0, r2 + sll r1, r2 || neg r2, r2 + srl r3, r2 + or r0, r3 || jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r1, r0 || addi r2, #-32 + ldi r0, #0 || srl r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 || srl r1, r2 + srl r0, r2 || neg r2, r2 + sll r3, r2 + or r1, r3 || jmp r14 + +#else /* LITTLE_ENDIAN */ + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r0, r1 || srai r1, #31 + addi r2, #-32 + sra r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 || srl r0, r2 + sra r1, r2 || neg r2, r2 + sll r3, r2 + or r0, r3 || jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r1, r0 || addi r2, #-32 + sll r1, r2 || ldi r0, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 || sll r1, r2 + sll r0, r2 || neg r2, r2 + srl r3, r2 + or r1, r3 || jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r0, r1 || addi r2, #-32 + ldi r1, #0 || srl r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 || srl r0, r2 + srl r1, r2 || neg r2, r2 + sll r3, r2 + or r0, r3 || jmp r14 + +#endif + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +#ifndef __LITTLE_ENDIAN__ + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r1, r0 + srai r0, #31 + addi r2, #-32 + sra r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 + srl r1, r2 + sra r0, r2 + neg r2, r2 + sll r3, r2 + or r1, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r0, r1 + addi r2, #-32 + sll r0, r2 + ldi r1, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 + sll r0, r2 + sll r1, r2 + neg r2, r2 + srl r3, r2 + or r0, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r1, r0 + ldi r0, #0 + addi r2, #-32 + srl r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 + srl r1, r2 + srl r0, r2 + neg r2, r2 + sll r3, r2 + or r1, r3 + .fillinsn +2: + jmp r14 + +#else + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r0, r1 + srai r1, #31 + addi r2, #-32 + sra r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 + srl r0, r2 + sra r1, r2 + neg r2, r2 + sll r3, r2 + or r0, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r1, r0 + addi r2, #-32 + sll r1, r2 + ldi r0, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 + sll r1, r2 + sll r0, r2 + neg r2, r2 + srl r3, r2 + or r1, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r0, r1 + ldi r1, #0 + addi r2, #-32 + srl r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 + srl r0, r2 + srl r1, r2 + neg r2, r2 + sll r3, r2 + or r0, r3 + .fillinsn +2: + jmp r14 + +#endif + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end + diff -Nru a/arch/m32r/lib/checksum.S b/arch/m32r/lib/checksum.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/checksum.S 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,322 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Pentium Pro/II routines: + * Alexander Kjeldaas + * Finn Arne Gangstad + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception + * handling. + * Andi Kleen, add zeroing on error + * converted to pure assembler + * Hirokazu Takata,Hiroyuki Kondo rewrite for the m32r architecture. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +/* $Id$ */ + + +#include +#include +#include +#include + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +/* +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) + */ + + +#ifdef CONFIG_ISA_DUAL_ISSUE + + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ + + .text +ENTRY(csum_partial) + ; Function args + ; r0: unsigned char *buff + ; r1: int len + ; r2: unsigned int sum + + push r2 || ldi r2, #0 + and3 r7, r0, #1 ; Check alignment. + beqz r7, 1f ; Jump if alignment is ok. + ; 1-byte mis aligned + ldub r4, @r0 || addi r0, #1 + ; clear c-bit || Alignment uses up bytes. + cmp r0, r0 || addi r1, #-1 + ldi r3, #0 || addx r2, r4 + addx r2, r3 + .fillinsn +1: + and3 r4, r0, #2 ; Check alignment. + beqz r4, 2f ; Jump if alignment is ok. + ; clear c-bit || Alignment uses up two bytes. + cmp r0, r0 || addi r1, #-2 + bgtz r1, 1f ; Jump if we had at least two bytes. + bra 4f || addi r1, #2 + .fillinsn ; len(r1) was < 2. Deal with it. +1: + ; 2-byte aligned + lduh r4, @r0 || ldi r3, #0 + addx r2, r4 || addi r0, #2 + addx r2, r3 + .fillinsn +2: + ; 4-byte aligned + cmp r0, r0 ; clear c-bit + srl3 r6, r1, #5 + beqz r6, 2f + .fillinsn + +1: ld r3, @r0+ + ld r4, @r0+ ; +4 + ld r5, @r0+ ; +8 + ld r3, @r0+ || addx r2, r3 ; +12 + ld r4, @r0+ || addx r2, r4 ; +16 + ld r5, @r0+ || addx r2, r5 ; +20 + ld r3, @r0+ || addx r2, r3 ; +24 + ld r4, @r0+ || addx r2, r4 ; +28 + addx r2, r5 || addi r6, #-1 + addx r2, r3 + addx r2, r4 + bnez r6, 1b + + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn +2: and3 r6, r1, #0x1c ; withdraw len + beqz r6, 4f + srli r6, #2 + .fillinsn + +3: ld r4, @r0+ || addi r6, #-1 + addx r2, r4 + bnez r6, 3b + + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn +4: and3 r1, r1, #3 + beqz r1, 7f ; if len == 0 goto end + and3 r6, r1, #2 + beqz r6, 5f ; if len < 2 goto 5f(1byte) + lduh r4, @r0 || addi r0, #2 + addi r1, #-2 || slli r4, #16 + addx r2, r4 + beqz r1, 6f + .fillinsn +5: ldub r4, @r0 || ldi r1, #0 +#ifndef __LITTLE_ENDIAN__ + slli r4, #8 +#endif + addx r2, r4 + .fillinsn +6: addx r2, r1 + .fillinsn +7: + and3 r0, r2, #0xffff + srli r2, #16 + add r0, r2 + srl3 r2, r0, #16 + beqz r2, 1f + addi r0, #1 + and3 r0, r0, #0xffff + .fillinsn +1: + beqz r7, 1f ; swap the upper byte for the lower + and3 r2, r0, #0xff + srl3 r0, r0, #8 + slli r2, #8 + or r0, r2 + .fillinsn +1: + pop r2 || cmp r0, r0 + addx r0, r2 || ldi r2, #0 + addx r0, r2 + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ + + .text +ENTRY(csum_partial) + ; Function args + ; r0: unsigned char *buff + ; r1: int len + ; r2: unsigned int sum + + push r2 + ldi r2, #0 + and3 r7, r0, #1 ; Check alignment. + beqz r7, 1f ; Jump if alignment is ok. + ; 1-byte mis aligned + ldub r4, @r0 + addi r0, #1 + addi r1, #-1 ; Alignment uses up bytes. + cmp r0, r0 ; clear c-bit + ldi r3, #0 + addx r2, r4 + addx r2, r3 + .fillinsn +1: + and3 r4, r0, #2 ; Check alignment. + beqz r4, 2f ; Jump if alignment is ok. + addi r1, #-2 ; Alignment uses up two bytes. + cmp r0, r0 ; clear c-bit + bgtz r1, 1f ; Jump if we had at least two bytes. + addi r1, #2 ; len(r1) was < 2. Deal with it. + bra 4f + .fillinsn +1: + ; 2-byte aligned + lduh r4, @r0 + addi r0, #2 + ldi r3, #0 + addx r2, r4 + addx r2, r3 + .fillinsn +2: + ; 4-byte aligned + cmp r0, r0 ; clear c-bit + srl3 r6, r1, #5 + beqz r6, 2f + .fillinsn + +1: ld r3, @r0+ + ld r4, @r0+ ; +4 + ld r5, @r0+ ; +8 + addx r2, r3 + addx r2, r4 + addx r2, r5 + ld r3, @r0+ ; +12 + ld r4, @r0+ ; +16 + ld r5, @r0+ ; +20 + addx r2, r3 + addx r2, r4 + addx r2, r5 + ld r3, @r0+ ; +24 + ld r4, @r0+ ; +28 + addi r6, #-1 + addx r2, r3 + addx r2, r4 + bnez r6, 1b + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn + +2: and3 r6, r1, #0x1c ; withdraw len + beqz r6, 4f + srli r6, #2 + .fillinsn + +3: ld r4, @r0+ + addi r6, #-1 + addx r2, r4 + bnez r6, 3b + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn + +4: and3 r1, r1, #3 + beqz r1, 7f ; if len == 0 goto end + and3 r6, r1, #2 + beqz r6, 5f ; if len < 2 goto 5f(1byte) + + lduh r4, @r0 + addi r0, #2 + addi r1, #-2 + slli r4, #16 + addx r2, r4 + beqz r1, 6f + .fillinsn +5: ldub r4, @r0 +#ifndef __LITTLE_ENDIAN__ + slli r4, #8 +#endif + addx r2, r4 + .fillinsn +6: ldi r5, #0 + addx r2, r5 + .fillinsn +7: + and3 r0, r2, #0xffff + srli r2, #16 + add r0, r2 + srl3 r2, r0, #16 + beqz r2, 1f + addi r0, #1 + and3 r0, r0, #0xffff + .fillinsn +1: + beqz r7, 1f + mv r2, r0 + srl3 r0, r2, #8 + and3 r2, r2, #0xff + slli r2, #8 + or r0, r2 + .fillinsn +1: + pop r2 + cmp r0, r0 + addx r0, r2 + ldi r2, #0 + addx r0, r2 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +/* +unsigned int csum_partial_copy_generic (const char *src, char *dst, + int len, int sum, int *src_err_ptr, int *dst_err_ptr) + */ + +/* + * Copy from ds while checksumming, otherwise like csum_partial + * + * The macros SRC and DST specify the type of access for the instruction. + * thus we can call a custom exception handler for all access types. + * + * FIXME: could someone double-check whether I haven't mixed up some SRC and + * DST definitions? It's damn hard to trigger all cases. I hope I got + * them all but there's no guarantee. + */ + +ENTRY(csum_partial_copy_generic) + nop + nop + nop + nop + jmp r14 + nop + nop + nop + diff -Nru a/arch/m32r/lib/csum_partial_copy.c b/arch/m32r/lib/csum_partial_copy.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/csum_partial_copy.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,58 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * MIPS specific IP/TCP/UDP checksumming routines + * + * Authors: Ralf Baechle, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include + +#include +#include +#include +#include + +/* + * Copy while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy_nocheck (const char *src, char *dst, + int len, unsigned int sum) +{ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} +EXPORT_SYMBOL(csum_partial_copy_nocheck); + +/* + * Copy from userspace and compute checksum. If we catch an exception + * then zero the rest of the buffer. + */ +unsigned int csum_partial_copy_from_user (const char __user *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + int missing; + + missing = copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len-missing, sum); +} +EXPORT_SYMBOL(csum_partial_copy_from_user); diff -Nru a/arch/m32r/lib/delay.c b/arch/m32r/lib/delay.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/delay.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,126 @@ +/* + * linux/arch/m32r/lib/delay.c + * + * Copyright (c) 2002 Hitoshi Yamamoto, Hirokazu Takata + * Copyright (c) 2004 Hirokazu Takata + */ + +/* $Id$ */ + +#include +#include +#ifdef CONFIG_SMP +#include +#include +#include +#endif /* CONFIG_SMP */ +#include + +void __delay(unsigned long loops) +{ +#ifdef CONFIG_ISA_DUAL_ISSUE + __asm__ __volatile__ ( + "beqz %0, 2f \n\t" + "addi %0, #-1 \n\t" + + " .fillinsn \n\t" + "1: \n\t" + "cmpz %0 || addi %0, #-1 \n\t" + "bc 2f || cmpz %0 \n\t" + "bc 2f || addi %0, #-1 \n\t" + "cmpz %0 || addi %0, #-1 \n\t" + "bc 2f || cmpz %0 \n\t" + "bnc 1b || addi %0, #-1 \n\t" + " .fillinsn \n\t" + "2: \n\t" + : "+r" (loops) + : "r" (0) + : "cbit" + ); +#else + __asm__ __volatile__ ( + "beqz %0, 2f \n\t" + " .fillinsn \n\t" + "1: \n\t" + "addi %0, #-1 \n\t" + "blez %0, 2f \n\t" + "addi %0, #-1 \n\t" + "blez %0, 2f \n\t" + "addi %0, #-1 \n\t" + "blez %0, 2f \n\t" + "addi %0, #-1 \n\t" + "bgtz %0, 1b \n\t" + " .fillinsn \n\t" + "2:i \n\t" + : "+r" (loops) + : "r" (0) + ); +#endif +} + +void __const_udelay(unsigned long xloops) +{ +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + /* + * loops [1] = (xloops >> 32) [sec] * loops_per_jiffy [1/jiffy] + * * HZ [jiffy/sec] + * = (xloops >> 32) [sec] * (loops_per_jiffy * HZ) [1/sec] + * = (((xloops * loops_per_jiffy) >> 32) * HZ) [1] + * + * NOTE: + * - '[]' depicts variable's dimension in the above equation. + * - "rac" instruction rounds the accumulator in word size. + */ + __asm__ __volatile__ ( + "srli %0, #1 \n\t" + "mulwhi %0, %1 ; a0 \n\t" + "mulwu1 %0, %1 ; a1 \n\t" + "sadd ; a0 += (a1 >> 16) \n\t" + "rac a0, a0, #1 \n\t" + "mvfacmi %0, a0 \n\t" + : "+r" (xloops) + : "r" (current_cpu_data.loops_per_jiffy) + : "a0", "a1" + ); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + /* + * u64 ull; + * ull = (u64)xloops * (u64)current_cpu_data.loops_per_jiffy; + * xloops = (ull >> 32); + */ + __asm__ __volatile__ ( + "and3 r4, %0, #0xffff \n\t" + "and3 r5, %1, #0xffff \n\t" + "mul r4, r5 \n\t" + "srl3 r6, %0, #16 \n\t" + "srli r4, #16 \n\t" + "mul r5, r6 \n\t" + "add r4, r5 \n\t" + "and3 r5, %0, #0xffff \n\t" + "srl3 r6, %1, #16 \n\t" + "mul r5, r6 \n\t" + "add r4, r5 \n\t" + "srl3 r5, %0, #16 \n\t" + "srli r4, #16 \n\t" + "mul r5, r6 \n\t" + "add r4, r5 \n\t" + "mv %0, r4 \n\t" + : "+r" (xloops) + : "r" (current_cpu_data.loops_per_jiffy) + : "r4", "r5", "r6" + ); +#else +#error unknown isa configuration +#endif + __delay(xloops * HZ); +} + +void __udelay(unsigned long usecs) +{ + __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ +} + +void __ndelay(unsigned long nsecs) +{ + __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ +} diff -Nru a/arch/m32r/lib/getuser.S b/arch/m32r/lib/getuser.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/getuser.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,88 @@ +/* + * __get_user functions. + * + * (C) Copyright 2001 Hirokazu Takata + * + * These functions have a non-standard call interface + * to make them more efficient, especially as they + * return an error value in addition to the "real" + * return value. + */ + +#include + +/* + * __get_user_X + * + * Inputs: r0 contains the address + * + * Outputs: r0 is error code (0 or -EFAULT) + * r1 contains zero-extended value + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text + .balign 4 + .globl __get_user_1 +__get_user_1: +1: ldub r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_2 +__get_user_2: +2: lduh r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_4 +__get_user_4: +3: ld r1, @r0 || ldi r0, #0 + jmp r14 + +bad_get_user: + ldi r1, #0 || ldi r0, #-14 + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text + .balign 4 + .globl __get_user_1 +__get_user_1: +1: ldub r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_2 +__get_user_2: +2: lduh r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_4 +__get_user_4: +3: ld r1, @r0 + ldi r0, #0 + jmp r14 + +bad_get_user: + ldi r1, #0 + ldi r0, #-14 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +.section __ex_table,"a" + .long 1b,bad_get_user + .long 2b,bad_get_user + .long 3b,bad_get_user +.previous + + .end diff -Nru a/arch/m32r/lib/memcpy.S b/arch/m32r/lib/memcpy.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/memcpy.S 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,95 @@ +/* + * linux/arch/m32r/lib/memcpy.S + * + * Copyright (C) 2001 Hiroyuki Kondo, and Hirokazu Takata + * Copyright (C) 2004 Hirokazu Takata + * + * void *memcopy(void *dst, const void *src, int n); + * + * dst: r0 + * src: r1 + * n : r2 + */ +/* $Id$ */ + + + .text +#include +#include +#include + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text +ENTRY(memcpy) +memcopy: + mv r4, r0 || mv r7, r0 + or r7, r1 || cmpz r2 + jc r14 || cmpeq r0, r1 ; return if r2=0 + jc r14 ; return if r0=r1 + + and3 r7, r7, #3 + bnez r7, byte_copy + srl3 r3, r2, #2 + and3 r2, r2, #3 + beqz r3, byte_copy + addi r4, #-4 +word_copy: + ld r7, @r1+ || addi r3, #-1 + st r7, @+r4 || cmpz r2 + bnez r3, word_copy + addi r4, #4 || jc r14 ; return if r2=0 +#if defined(CONFIG_ISA_M32R2) +byte_copy: + ldb r7, @r1 || addi r1, #1 + addi r2, #-1 || stb r7, @r4+ + bnez r2, byte_copy +#elif defined(CONFIG_ISA_M32R) +byte_copy: + ldb r7, @r1 || addi r1, #1 + addi r2, #-1 || stb r7, @r4 + addi r4, #1 + bnez r2, byte_copy +#else +#error unknown isa configuration +#endif +end_memcopy: + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text +ENTRY(memcpy) +memcopy: + mv r4, r0 + mv r7, r0 + or r7, r1 + beq r0, r1, end_memcopy + beqz r2, end_memcopy + + and3 r7, r7, #3 + bnez r7, byte_copy + srl3 r3, r2, #2 + and3 r2, r2, #3 + beqz r3, byte_copy + addi r4, #-4 +word_copy: + ld r7, @r1+ + addi r3, #-1 + st r7, @+r4 + bnez r3, word_copy + beqz r2, end_memcopy + addi r4, #4 +byte_copy: + ldb r7, @r1 + addi r1, #1 + addi r2, #-1 + stb r7, @r4 + addi r4, #1 + bnez r2, byte_copy +end_memcopy: + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end diff -Nru a/arch/m32r/lib/memset.S b/arch/m32r/lib/memset.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/memset.S 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,178 @@ +/* + * linux/arch/m32r/lib/memset.S + * + * Copyright (C) 2001,2002 Hiroyuki Kondo, and Hirokazu Takata + * Copyright (C) 2004 Hirokazu Takata + * + * void *memset(void *dst, int val, int len); + * + * dst: r0 + * val: r1 + * len: r2 + * ret: r0 + * + */ +/* $Id$ */ + +#include + + .text + .global memset + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .align 4 +memset: + mv r4, r0 || cmpz r2 + jc r14 + cmpui r2, #16 + bnc qword_align_check + cmpui r2, #4 + bc byte_set +word_align_check: /* len >= 4 */ + and3 r3, r4, #3 + beqz r3, word_set + addi r3, #-4 + neg r3, r3 /* r3 = -(r3 - 4) */ +align_word: + stb r1, @r4 || addi r4, #1 + addi r2, #-1 || addi r3, #-1 + bnez r3, align_word + cmpui r2, #4 + bc byte_set +word_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 || addi r4, #-4 + sll3 r3, r1, #16 + or r1, r3 || addi r2, #-4 +word_set_loop: + st r1, @+r4 || addi r2, #-4 + bgtz r2, word_set_loop + bnez r2, byte_set_wrap + st r1, @+r4 + jmp r14 + +qword_align_check: /* len >= 16 */ + and3 r3, r4, #15 + bnez r3, word_align_check +qword_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 || addi r4, #-4 + sll3 r3, r1, #16 + or r1, r3 || ldi r5, #16 +qword_set_loop: + ld r3, @(4,r4) /* cache line allocate */ + st r1, @+r4 || addi r2, #-16 + st r1, @+r4 || cmpu r2, r5 + st r1, @+r4 + st r1, @+r4 + bnc qword_set_loop || cmpz r2 + jc r14 +word_set_wrap: + cmpui r2, #4 + bc byte_set + addi r2, #-4 + bra word_set_loop + +byte_set_wrap: + addi r2, #4 + addi r4, #4 || cmpz r2 + jc r14 +#if defined(CONFIG_ISA_M32R2) +byte_set: + addi r2, #-1 || stb r1, @r4+ + bnez r2, byte_set +#elif defined(CONFIG_ISA_M32R) +byte_set: + addi r2, #-1 || stb r1, @r4 + addi r4, #1 + bnez r2, byte_set +#else +#error unknown isa configuration +#endif +end_memset: + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .align 4 +memset: + mv r4, r0 + beqz r2, end_memset + cmpui r2, #16 + bnc qword_align_check + cmpui r2, #4 + bc byte_set +word_align_check: /* len >= 4 */ + and3 r3, r4, #3 + beqz r3, word_set + addi r3, #-4 + neg r3, r3 /* r3 = -(r3 - 4) */ +align_word: + stb r1, @r4 + addi r4, #1 + addi r2, #-1 + addi r3, #-1 + bnez r3, align_word + cmpui r2, #4 + bc byte_set +word_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 + sll3 r3, r1, #16 + or r1, r3 + addi r2, #-4 + addi r4, #-4 +word_set_loop: + st r1, @+r4 + addi r2, #-4 + bgtz r2, word_set_loop + bnez r2, byte_set_wrap + st r1, @+r4 + jmp r14 + +qword_align_check: /* len >= 16 */ + and3 r3, r4, #15 + bnez r3, word_align_check +qword_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 + sll3 r3, r1, #16 + or r1, r3 + addi r4, #-4 +qword_set_loop: + ld r3, @(4,r4) /* cache line allocate */ + addi r2, #-16 + st r1, @+r4 + st r1, @+r4 + cmpui r2, #16 + st r1, @+r4 + st r1, @+r4 + bnc qword_set_loop + bnez r2, word_set_wrap + jmp r14 +word_set_wrap: + cmpui r2, #4 + bc byte_set + addi r2, #-4 + bra word_set_loop + +byte_set_wrap: + addi r2, #4 + addi r4, #4 + beqz r2, end_memset +byte_set: + addi r2, #-1 + stb r1, @r4 + addi r4, #1 + bnez r2, byte_set +end_memset: + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end diff -Nru a/arch/m32r/lib/putuser.S b/arch/m32r/lib/putuser.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/putuser.S 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,84 @@ +/* + * __put_user functions. + * + * (C) Copyright 1998 Linus Torvalds + * (C) Copyright 2001 Hirokazu Takata + * + * These functions have a non-standard call interface + * to make them more efficient. + */ + +#include + +/* + * __put_user_X + * + * Inputs: r0 contains the address + * r1 contains the value + * + * Outputs: r0 is error code (0 or -EFAULT) + * r1 is corrupted (will contain "current_task"). + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text + .balign 4 + .globl __put_user_1 +__put_user_1: +1: stb r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_2 +__put_user_2: +2: sth r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_4 +__put_user_4: +3: st r1, @r0 || ldi r0, #0 + jmp r14 + +bad_put_user: + ldi r0, #-14 || jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text + .balign 4 + .globl __put_user_1 +__put_user_1: +1: stb r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_2 +__put_user_2: +2: sth r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_4 +__put_user_4: +3: st r1, @r0 + ldi r0, #0 + jmp r14 + +bad_put_user: + ldi r0, #-14 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +.section __ex_table,"a" + .long 1b,bad_put_user + .long 2b,bad_put_user + .long 3b,bad_put_user +.previous diff -Nru a/arch/m32r/lib/strlen.S b/arch/m32r/lib/strlen.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/strlen.S 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,120 @@ +/* + * linux/arch/m32r/strlen.S -- strlen code. + * + * Copyright (C) 2001 Hirokazu Takata + * + * size_t strlen(const char *s); + * + */ +/* $Id$ */ + + +#include +#include +#include + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text +ENTRY(strlen) + mv r6, r0 || ldi r2, #0 + and3 r0, r0, #3 + bnez r0, strlen_byte +; +strlen_word: + ld r0, @r6+ +; + seth r5, #high(0x01010101) + or3 r5, r5, #low(0x01010101) + sll3 r7, r5, #7 +strlen_word_loop: + ld r1, @r6+ || not r4, r0 + sub r0, r5 || and r4, r7 + and r4, r0 + bnez r4, strlen_last_bytes + ld r0, @r6+ || not r4, r1 + sub r1, r5 || and r4, r7 + and r4, r1 || addi r2, #4 + bnez r4, strlen_last_bytes + addi r2, #4 || bra.s strlen_word_loop + + ; NOTE: If a null char. exists, return 0. + ; if ((x - 0x01010101) & ~x & 0x80808080) + ; return 0; +; +strlen_byte: + ldb r1, @r6 || addi r6, #1 + beqz r1, strlen_exit + addi r2, #1 || bra.s strlen_byte +; +strlen_last_bytes: + ldi r0, #4 || addi r6, #-8 +; +strlen_byte_loop: + ldb r1, @r6 || addi r6, #1 + addi r0, #-1 || cmpz r1 + bc.s strlen_exit || cmpz r0 + addi r2, #1 || bnc.s strlen_byte_loop +; +strlen_exit: + mv r0, r2 || jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text +ENTRY(strlen) + mv r6, r0 + ldi r2, #0 + and3 r0, r0, #3 + bnez r0, strlen_byte +; +strlen_word: + ld r0, @r6+ +; + seth r5, #high(0x01010101) + or3 r5, r5, #low(0x01010101) + sll3 r7, r5, #7 +strlen_word_loop: + ld r1, @r6+ + not r4, r0 ; NOTE: If a null char. exists, return 0. + sub r0, r5 ; if ((x - 0x01010101) & ~x & 0x80808080) + and r4, r7 ; return 0; + and r4, r0 + bnez r4, strlen_last_bytes + addi r2, #4 +; + ld r0, @r6+ + not r4, r1 ; NOTE: If a null char. exists, return 0. + sub r1, r5 ; if ((x - 0x01010101) & ~x & 0x80808080) + and r4, r7 ; return 0; + and r4, r1 + bnez r4, strlen_last_bytes + addi r2, #4 + bra strlen_word_loop +; +strlen_byte: + ldb r1, @r6 + addi r6, #1 + beqz r1, strlen_exit + addi r2, #1 + bra strlen_byte +; +strlen_last_bytes: + ldi r0, #4 + addi r6, #-8 +; +strlen_byte_loop: + ldb r1, @r6 + addi r6, #1 + addi r0, #-1 + beqz r1, strlen_exit + addi r2, #1 + bnez r0, strlen_byte_loop +; +strlen_exit: + mv r0, r2 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end diff -Nru a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/lib/usercopy.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,391 @@ +/* + * User address space access functions. + * The non inlined parts of asm-m32r/uaccess.h are here. + * + * Copyright 1997 Andi Kleen + * Copyright 1997 Linus Torvalds + * Copyright 2001, 2002, 2004 Hirokazu Takata + */ +#include +#include +#include +#include +#include + +unsigned long +__generic_copy_to_user(void *to, const void *from, unsigned long n) +{ + prefetch(from); + if (access_ok(VERIFY_WRITE, to, n)) + __copy_user(to,from,n); + return n; +} + +unsigned long +__generic_copy_from_user(void *to, const void *from, unsigned long n) +{ + prefetchw(to); + if (access_ok(VERIFY_READ, from, n)) + __copy_user_zeroing(to,from,n); + else + memset(to, 0, n); + return n; +} + + +/* + * Copy a null terminated string from userspace. + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +#define __do_strncpy_from_user(dst,src,count,res) \ +do { \ + int __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " beqz %1, 2f\n" \ + " .fillinsn\n" \ + "0: ldb r14, @%3 || addi %3, #1\n" \ + " stb r14, @%4 || addi %4, #1\n" \ + " beqz r14, 1f\n" \ + " addi %1, #-1\n" \ + " bnez %1, 0b\n" \ + " .fillinsn\n" \ + "1: sub %0, %1\n" \ + " .fillinsn\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "3: seth r14, #high(2b)\n" \ + " or3 r14, r14, #low(2b)\n" \ + " jmp r14 || ldi %0, #%5\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ + "=&r" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ + "4"(dst) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +#define __do_strncpy_from_user(dst,src,count,res) \ +do { \ + int __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " beqz %1, 2f\n" \ + " .fillinsn\n" \ + "0: ldb r14, @%3\n" \ + " stb r14, @%4\n" \ + " addi %3, #1\n" \ + " addi %4, #1\n" \ + " beqz r14, 1f\n" \ + " addi %1, #-1\n" \ + " bnez %1, 0b\n" \ + " .fillinsn\n" \ + "1: sub %0, %1\n" \ + " .fillinsn\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "3: ldi %0, #%5\n" \ + " seth r14, #high(2b)\n" \ + " or3 r14, r14, #low(2b)\n" \ + " jmp r14\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ + "=&r" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ + "4"(dst) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#endif /* CONFIG_ISA_DUAL_ISSUE */ + +long +__strncpy_from_user(char *dst, const char *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +long +strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + + +/* + * Zero Userspace + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +#define __do_clear_user(addr,size) \ +do { \ + int __dst, __c; \ + __asm__ __volatile__( \ + " beqz %1, 9f\n" \ + " and3 r14, %0, #3\n" \ + " bnez r14, 2f\n" \ + " and3 r14, %1, #3\n" \ + " bnez r14, 2f\n" \ + " and3 %1, %1, #3\n" \ + " beqz %2, 2f\n" \ + " addi %0, #-4\n" \ + " .fillinsn\n" \ + "0: ; word clear \n" \ + " st %6, @+%0 || addi %2, #-1\n" \ + " bnez %2, 0b\n" \ + " beqz %1, 9f\n" \ + " .fillinsn\n" \ + "2: ; byte clear \n" \ + " stb %6, @%0 || addi %1, #-1\n" \ + " addi %0, #1\n" \ + " bnez %1, 2b\n" \ + " .fillinsn\n" \ + "9:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "4: slli %2, #2\n" \ + " seth r14, #high(9b)\n" \ + " or3 r14, r14, #low(9b)\n" \ + " jmp r14 || add %1, %2\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,4b\n" \ + " .long 2b,9b\n" \ + ".previous\n" \ + : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ + : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +#define __do_clear_user(addr,size) \ +do { \ + int __dst, __c; \ + __asm__ __volatile__( \ + " beqz %1, 9f\n" \ + " and3 r14, %0, #3\n" \ + " bnez r14, 2f\n" \ + " and3 r14, %1, #3\n" \ + " bnez r14, 2f\n" \ + " and3 %1, %1, #3\n" \ + " beqz %2, 2f\n" \ + " addi %0, #-4\n" \ + " .fillinsn\n" \ + "0: st %6, @+%0 ; word clear \n" \ + " addi %2, #-1\n" \ + " bnez %2, 0b\n" \ + " beqz %1, 9f\n" \ + " .fillinsn\n" \ + "2: stb %6, @%0 ; byte clear \n" \ + " addi %1, #-1\n" \ + " addi %0, #1\n" \ + " bnez %1, 2b\n" \ + " .fillinsn\n" \ + "9:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "4: slli %2, #2\n" \ + " add %1, %2\n" \ + " seth r14, #high(9b)\n" \ + " or3 r14, r14, #low(9b)\n" \ + " jmp r14\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,4b\n" \ + " .long 2b,9b\n" \ + ".previous\n" \ + : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ + : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +unsigned long +clear_user(void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __do_clear_user(to, n); + return n; +} + +unsigned long +__clear_user(void *to, unsigned long n) +{ + __do_clear_user(to, n); + return n; +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +long strnlen_user(const char *s, long n) +{ + unsigned long mask = -__addr_ok(s); + unsigned long res; + + __asm__ __volatile__( + " and %0, %5 || mv r1, %1\n" + " beqz %0, strnlen_exit\n" + " and3 r0, %1, #3\n" + " bnez r0, strnlen_byte_loop\n" + " cmpui %0, #4\n" + " bc strnlen_byte_loop\n" + "strnlen_word_loop:\n" + "0: ld r0, @%1+\n" + " pcmpbz r0\n" + " bc strnlen_last_bytes_fixup\n" + " addi %0, #-4\n" + " beqz %0, strnlen_exit\n" + " bgtz %0, strnlen_word_loop\n" + "strnlen_last_bytes:\n" + " mv %0, %4\n" + "strnlen_last_bytes_fixup:\n" + " addi %1, #-4\n" + "strnlen_byte_loop:\n" + "1: ldb r0, @%1 || addi %0, #-1\n" + " beqz r0, strnlen_exit\n" + " addi %1, #1\n" + " bnez %0, strnlen_byte_loop\n" + "strnlen_exit:\n" + " sub %1, r1\n" + " add3 %0, %1, #1\n" + " .fillinsn\n" + "9:\n" + ".section .fixup,\"ax\"\n" + " .balign 4\n" + "4: addi %1, #-4\n" + " .fillinsn\n" + "5: seth r1, #high(9b)\n" + " or3 r1, r1, #low(9b)\n" + " jmp r1 || ldi %0, #0\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .balign 4\n" + " .long 0b,4b\n" + " .long 1b,5b\n" + ".previous" + : "=&r" (res), "=r" (s) + : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) + : "r0", "r1", "cbit"); + + /* NOTE: strnlen_user() algorism: + * { + * char *p; + * for (p = s; n-- && *p != '\0'; ++p) + * ; + * return p - s + 1; + * } + */ + + /* NOTE: If a null char. exists, return 0. + * if ((x - 0x01010101) & ~x & 0x80808080)\n" + * return 0;\n" + */ + + return res & mask; +} + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +long strnlen_user(const char *s, long n) +{ + unsigned long mask = -__addr_ok(s); + unsigned long res; + + __asm__ __volatile__( + " and %0, %5\n" + " mv r1, %1\n" + " beqz %0, strnlen_exit\n" + " and3 r0, %1, #3\n" + " bnez r0, strnlen_byte_loop\n" + " cmpui %0, #4\n" + " bc strnlen_byte_loop\n" + " sll3 r3, %6, #7\n" + "strnlen_word_loop:\n" + "0: ld r0, @%1+\n" + " not r2, r0\n" + " sub r0, %6\n" + " and r2, r3\n" + " and r2, r0\n" + " bnez r2, strnlen_last_bytes_fixup\n" + " addi %0, #-4\n" + " beqz %0, strnlen_exit\n" + " bgtz %0, strnlen_word_loop\n" + "strnlen_last_bytes:\n" + " mv %0, %4\n" + "strnlen_last_bytes_fixup:\n" + " addi %1, #-4\n" + "strnlen_byte_loop:\n" + "1: ldb r0, @%1\n" + " addi %0, #-1\n" + " beqz r0, strnlen_exit\n" + " addi %1, #1\n" + " bnez %0, strnlen_byte_loop\n" + "strnlen_exit:\n" + " sub %1, r1\n" + " add3 %0, %1, #1\n" + " .fillinsn\n" + "9:\n" + ".section .fixup,\"ax\"\n" + " .balign 4\n" + "4: addi %1, #-4\n" + " .fillinsn\n" + "5: ldi %0, #0\n" + " seth r1, #high(9b)\n" + " or3 r1, r1, #low(9b)\n" + " jmp r1\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .balign 4\n" + " .long 0b,4b\n" + " .long 1b,5b\n" + ".previous" + : "=&r" (res), "=r" (s) + : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) + : "r0", "r1", "r2", "r3", "cbit"); + + /* NOTE: strnlen_user() algorism: + * { + * char *p; + * for (p = s; n-- && *p != '\0'; ++p) + * ; + * return p - s + 1; + * } + */ + + /* NOTE: If a null char. exists, return 0. + * if ((x - 0x01010101) & ~x & 0x80808080)\n" + * return 0;\n" + */ + + return res & mask; +} + +#endif /* CONFIG_ISA_DUAL_ISSUE */ + diff -Nru a/arch/m32r/m32700ut/defconfig.m32700ut.smp b/arch/m32r/m32700ut/defconfig.m32700ut.smp --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/m32700ut/defconfig.m32700ut.smp 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,662 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=15 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +CONFIG_PLAT_M32700UT=y +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +CONFIG_SMP=y +CONFIG_CHIP_M32700_TS1=y +CONFIG_NR_CPUS=2 +# CONFIG_NUMA is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_CFC=y +CONFIG_M32700UT_CFC=y +CONFIG_CFC_NUM=1 +# CONFIG_MTD_M32R is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +CONFIG_M32R_AR=y +CONFIG_M32R_AR_VGA=y + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_EPSON_S1D13806=y +# 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_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_LOGO_M32R_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR 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=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# 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_HFSPLUS_FS is not set +# 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/m32r/m32700ut/defconfig.m32700ut.up b/arch/m32r/m32700ut/defconfig.m32700ut.up --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/m32700ut/defconfig.m32700ut.up 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,659 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +CONFIG_PLAT_M32700UT=y +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_CFC=y +CONFIG_M32700UT_CFC=y +CONFIG_CFC_NUM=1 +# CONFIG_MTD_M32R is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +CONFIG_M32R_AR=y +CONFIG_M32R_AR_VGA=y + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_EPSON_S1D13806=y +# 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_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_LOGO_M32R_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR 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=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# 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_HFSPLUS_FS is not set +# 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB b/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,249 @@ +# .gdbinit file +# $Id: dot.gdbinit_200MHz_16MB,v 1.1 2004/08/17 02:58:11 takata Exp $ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $ +#----- +# target platform: m32700ut + +# setting +set width 0d70 +set radix 0d16 + +debug_chaos + +# clk xin:cpu:bif:bus=25:200:50:50 +define clock_init + set *(unsigned long *)0x00ef4008 = 0x00000000 + set *(unsigned long *)0x00ef4004 = 0 + shell sleep 0.1 + # NOTE: Please change the master clock source from PLL-clock to Xin-clock + # and switch off PLL, before resetting the clock gear ratio. + + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00041302 + # Ch0-ADR (size:16MB) + set *(unsigned long *)0x00ef6020 = 0x08000002 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010517 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x08ffffff (16MB) +end + +# Initialize BSEL3 for UT-CFC +define cfc_init + set $sfrbase = 0xa0ef0000 +# too fast +# set *(unsigned long *)($sfrbase + 0x5300) = 0x0b0b8000 +# set *(unsigned long *)($sfrbase + 0x5304) = 0x00102204 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f8000 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f1fdf +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013220f +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013330f +end +document cfc_init + CF controller initialization +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Initialize TLB entries +define init_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set *(unsigned long *)($addr + 0x4) = 0 + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define tlb_init + set $itlb=0xfe000000 + init_tlb_entries $itlb 0d32 + set $dtlb=0xfe000800 + init_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + # SDRAM: 16MB + set *(unsigned long *)0x00ef6020 = 0x08000002 + cfc_init + # USB + set *(unsigned short *)0xb0301000 = 0x100 + + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d200000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d50000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x console=tty1 video=s1d13xxxfb:mode:240x320-16 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs,rsize=1024,wsize=1024 nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 mem=16M \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc = 0x08001000 + set *(unsigned char *)0xffffffff = 0x03 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + set $pc = 0 + b *0x04001000 + b *0x08001000 + b *0x08002000 + si + c + tlb_init + del + setup + load_modules + boot +end + +define si + stepi + x/i $pc + show_reg +end + +sdireset +sdireset +file vmlinux +target m32rsdi +set $pc = 0 +b *0x04001000 +b *0x08001000 +b *0x08002000 +c +tlb_init +del +setup +load_modules +boot + diff -Nru a/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB b/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,249 @@ +# .gdbinit file +# $Id: dot.gdbinit_300MHz_32MB,v 1.1 2004/08/17 02:58:11 takata Exp $ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $ +#----- +# target platform: m32700ut + +# setting +set width 0d70 +set radix 0d16 + +debug_chaos + +# clk xin:cpu:bif:bus=25:300:75:75 +define clock_init + set *(unsigned long *)0x00ef4008 = 0x00000000 + set *(unsigned long *)0x00ef4004 = 0 + shell sleep 0.1 + # NOTE: Please change the master clock source from PLL-clock to Xin-clock + # and switch off PLL, before resetting the clock gear ratio. + + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 5 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00051502 + # Ch0-ADR (size:16MB) + set *(unsigned long *)0x00ef6020 = 0x08000002 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010e24 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x08ffffff (16MB) +end + +# Initialize BSEL3 for UT-CFC +define cfc_init + set $sfrbase = 0xa0ef0000 +# too fast +# set *(unsigned long *)($sfrbase + 0x5300) = 0x0b0b8000 +# set *(unsigned long *)($sfrbase + 0x5304) = 0x00102204 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f8000 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f1fdf +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013220f +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013330f +end +document cfc_init + CF controller initialization +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Initialize TLB entries +define init_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set *(unsigned long *)($addr + 0x4) = 0 + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define tlb_init + set $itlb=0xfe000000 + init_tlb_entries $itlb 0d32 + set $dtlb=0xfe000800 + init_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + # SDRAM: 16MB + set *(unsigned long *)0x00ef6020 = 0x08000002 + cfc_init + # USB + set *(unsigned short *)0xb0301000 = 0x100 + + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d300000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d75000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x console=tty1 video=s1d13xxxfb:mode:240x320-16 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs,rsize=1024,wsize=1024 nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 mem=16M \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc = 0x08001000 + set *(unsigned char *)0xffffffff = 0x03 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + set $pc = 0 + b *0x04001000 + b *0x08001000 + b *0x08002000 + si + c + tlb_init + del + setup + load_modules + boot +end + +define si + stepi + x/i $pc + show_reg +end + +sdireset +sdireset +file vmlinux +target m32rsdi +set $pc = 0 +b *0x04001000 +b *0x08001000 +b *0x08002000 +c +tlb_init +del +setup +load_modules +boot + diff -Nru a/arch/m32r/mappi/defconfig.nommu b/arch/m32r/mappi/defconfig.nommu --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mappi/defconfig.nommu 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,529 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_PLAT_MAPPI=y +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +# CONFIG_MMU is not set +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x00000000 +CONFIG_MEMORY_SIZE=0x00E00000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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 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 is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +# 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_HFSPLUS_FS is not set +# 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/m32r/mappi/defconfig.smp b/arch/m32r/mappi/defconfig.smp --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mappi/defconfig.smp 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,646 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=15 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_PLAT_MAPPI=y +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=10000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_NOHIGHMEM=y +CONFIG_DISCONTIGMEM=y +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +CONFIG_SMP=y +CONFIG_CHIP_M32700_TS1=y +CONFIG_NR_CPUS=2 +# CONFIG_NUMA is not set + +# +# M32R drivers +# +CONFIG_M32RPCC=y +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# 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_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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 is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# 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_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# 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 is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +CONFIG_JFFS_PROC_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/m32r/mappi/defconfig.up b/arch/m32r/mappi/defconfig.up --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mappi/defconfig.up 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,642 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_PLAT_MAPPI=y +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=10000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_NOHIGHMEM=y +CONFIG_DISCONTIGMEM=y +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +CONFIG_M32RPCC=y +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# 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_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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 is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# 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_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# 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 is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +CONFIG_JFFS_PROC_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/m32r/mappi/dot.gdbinit b/arch/m32r/mappi/dot.gdbinit --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mappi/dot.gdbinit 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,242 @@ +# .gdbinit file +# $Id$ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.8 2004/02/27 07:08:32 takata Exp $ +#----- +# target platform: mappi + +# setting +set width 0d70 +set radix 0d16 +debug_chaos + +# clk xin:cpu:bif:bus=30:360:180:90 +define clock_init + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 5 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize programmable ports +define port_init + set $sfrbase = 0x00ef0000 + set *(unsigned short *)0x00ef1060 = 0x5555 + set *(unsigned short *)0x00ef1062 = 0x5555 + set *(unsigned short *)0x00ef1064 = 0x5555 + set *(unsigned short *)0x00ef1066 = 0x5555 + set *(unsigned short *)0x00ef1068 = 0x5555 + set *(unsigned short *)0x00ef106a = 0x0000 + set *(unsigned short *)0x00ef106e = 0x5555 + set *(unsigned short *)0x00ef1070 = 0x5555 + # LED ON + set *(unsigned char *)($sfrbase + 0x1015) = 0xff + set *(unsigned char *)($sfrbase + 0x1085) = 0xff + shell sleep 0.1 + # LED OFF + set *(unsigned char *)($sfrbase + 0x1085) = 0x00 +end +document port_init + P5=LED(output), P6.b4=LAN_RESET(output) +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00051502 + # Ch0-ADR (size:64MB) + set *(unsigned long *)0x00ef6020 = 0x08000004 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010e2b + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x0bffffff (64MB) +end + +# Initialize LAN controller +define lanc_init + set $sfrbase = 0x00ef0000 + # Set BSEL3 (BSEL3 for the Chaos's bselc) + set *(unsigned long *)($sfrbase + 0x5300) = 0x0a0a8040 + set *(unsigned long *)($sfrbase + 0x5304) = 0x01120203 + set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001 + # Reset (P5=LED,P6.b4=LAN_RESET) + set *(unsigned short *)($sfrbase + 0x106c) = 0x0000 + set *(unsigned char *)($sfrbase + 0x1016) = 0xff + set *(unsigned char *)($sfrbase + 0x1086) = 0xff + shell sleep 0.1 + # swivel: 0=normal, 4=reverse +# set *(unsigned char *)($sfrbase + 0x1086) = 0x00 + set *(unsigned char *)($sfrbase + 0x1086) = 0x04 + set *(unsigned long *)(0x0c000330) = 0xffffffff + # Set mac address + set $lanc = (void*)0x0c000300 + set *(unsigned long *)($lanc + 0x0000) = 0x00610010 + set *(unsigned long *)($lanc + 0x0004) = 0x00200030 + set *(unsigned long *)($lanc + 0x0008) = 0x00400050 + set *(unsigned long *)($lanc + 0x000c) = 0x00600007 +end +document lanc_init + LAN controller initialization + ex.) MAC address: 10 20 30 40 50 60 +end + +# LCD & CRT dual-head setting (8bpp) +define dispc_init + set $sfrbase = 0x00ef0000 + # BSEL4 Dispc + set *(unsigned long *)($sfrbase + 0x5400) = 0x0e0e8000 + set *(unsigned long *)($sfrbase + 0x5404) = 0x0012220a +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + port_init + sdram_init + lanc_init + dispc_init + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d360000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d90000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc=0x08001000 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup +#load_module +#set_breakpoints +#boot + diff -Nru a/arch/m32r/mappi/dot.gdbinit.nommu b/arch/m32r/mappi/dot.gdbinit.nommu --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mappi/dot.gdbinit.nommu 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,245 @@ +# .gdbinit file +# $Id$ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.5 2004/01/23 08:23:25 takata Exp $ +#----- +# target platform: mappi + +# setting +set width 0d70 +set radix 0d16 +debug_chaos + +# clk xin:cpu:bif:bus=25:200:50:50 +define clock_init + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize programmable ports +define port_init + set $sfrbase = 0x00ef0000 + set *(unsigned short *)0x00ef1060 = 0x5555 + set *(unsigned short *)0x00ef1062 = 0x5555 + set *(unsigned short *)0x00ef1064 = 0x5555 + set *(unsigned short *)0x00ef1066 = 0x5555 + set *(unsigned short *)0x00ef1068 = 0x5555 + set *(unsigned short *)0x00ef106a = 0x0000 + set *(unsigned short *)0x00ef106e = 0x5555 + set *(unsigned short *)0x00ef1070 = 0x5555 + # LED ON + set *(unsigned char *)($sfrbase + 0x1015) = 0xff + set *(unsigned char *)($sfrbase + 0x1085) = 0xff + shell sleep 0.1 + # LED OFF + set *(unsigned char *)($sfrbase + 0x1085) = 0x00 +end +document port_init + P5=LED(output), P6.b4=LAN_RESET(output) +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00051502 + # Ch0-ADR (size:64MB) + set *(unsigned long *)0x00ef6020 = 0x00000004 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010f05 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x0bffffff (64MB) +end + +# Initialize LAN controller +define lanc_init + set $sfrbase = 0x00ef0000 + # Set BSEL3 (BSEL3 for the Chaos's bselc) + set *(unsigned long *)($sfrbase + 0x5300) = 0x07078040 + set *(unsigned long *)($sfrbase + 0x5304) = 0x01110102 + set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001 + # Reset (P5=LED,P6.b4=LAN_RESET) + set *(unsigned short *)($sfrbase + 0x106c) = 0x0000 + set *(unsigned char *)($sfrbase + 0x1016) = 0xff + set *(unsigned char *)($sfrbase + 0x1086) = 0xff + shell sleep 0.1 + # swivel: 0=normal, 4=reverse +# set *(unsigned char *)($sfrbase + 0x1086) = 0x00 + set *(unsigned char *)($sfrbase + 0x1086) = 0x04 + set *(unsigned long *)(0x0c000330) = 0xffffffff + # Set mac address + set $lanc = (void*)0x0c000300 + set *(unsigned long *)($lanc + 0x0000) = 0x00610010 + set *(unsigned long *)($lanc + 0x0004) = 0x00200030 + set *(unsigned long *)($lanc + 0x0008) = 0x00400050 + set *(unsigned long *)($lanc + 0x000c) = 0x00600007 +end +document lanc_init + LAN controller initialization + ex.) MAC address: 10 20 30 40 50 60 +end + +# LCD & CRT dual-head setting (8bpp) +define dispc_init + set $sfrbase = 0x00ef0000 + # BSEL4 Dispc + set *(unsigned long *)($sfrbase + 0x5400) = 0x06078000 + set *(unsigned long *)($sfrbase + 0x5404) = 0x00101101 +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + port_init + sdram_init + lanc_init + dispc_init + set $evb=0x00000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x00002000 + # INITRD_START + #set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + #set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d200000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d50000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.bbox-httpd nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc=0x00001000 + set *(long *)0xfffffff4=0x8080 +# b load_flat_binary +# set *(unsigned char *)0x08001003=0x63 +# set *(unsigned char *)0x08001003=0x02 + si +# c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup +load_modules +boot + diff -Nru a/arch/m32r/mappi/dot.gdbinit.smp b/arch/m32r/mappi/dot.gdbinit.smp --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mappi/dot.gdbinit.smp 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,344 @@ +# .gdbinit file +# $Id$ + +# setting +set width 0d70 +set radix 0d16 +debug_chaos + +# clk xin:cpu:bif:bus=1:4:2:1 +define clock_init_on + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +# set *(unsigned long *)0x00ef4008 = 0x0201 +end + +# clk xin:cpu:bif:bus=1:4:1:1 +define clock_init_on_1411 + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:4:2:1 +define clock_init_on_1421 + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:8:2:1 +define clock_init_on_1821 + set *(unsigned long *)0x00ef4024 = 3 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:8:4:1 +define clock_init_on_1841 + set *(unsigned long *)0x00ef4024 = 3 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:16:8:1 +define clock_init_on_11681 + set *(unsigned long *)0x00ef4024 = 4 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x7 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:1:1:1 +define clock_init_off + # CPU + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + # BIF + set *(unsigned long *)0x00ef4020 = 0 + # BUS + set *(unsigned long *)0x00ef4024 = 0 + # PLL + set *(unsigned long *)0x00ef4008 = 0x0000 +end + +# Initialize programmable ports +define port_init + set $sfrbase = 0x00ef0000 + set *(unsigned short *)0x00ef1060 = 0x5555 + set *(unsigned short *)0x00ef1062 = 0x5555 + set *(unsigned short *)0x00ef1064 = 0x5555 + set *(unsigned short *)0x00ef1066 = 0x5555 + set *(unsigned short *)0x00ef1068 = 0x5555 + set *(unsigned short *)0x00ef106a = 0x0000 + set *(unsigned short *)0x00ef106e = 0x5555 + set *(unsigned short *)0x00ef1070 = 0x5555 + # LED ON + set *(unsigned char *)($sfrbase + 0x1015) = 0xff + set *(unsigned char *)($sfrbase + 0x1085) = 0xff + shell sleep 0.1 + # LED OFF + set *(unsigned char *)($sfrbase + 0x1085) = 0x00 +end +document port_init + P5=LED(output), P6.b4=LAN_RESET(output) +end + +# Initialize SDRAM controller for Mappi +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00010002 + # Ch0-ADR + set *(unsigned long *)0x00ef6020 = 0x08000004 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010107 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + Mappi SDRAM controller initialization + 0x08000000 - 0x0bffffff (64MB) +end + +# Initialize LAN controller for Mappi +define lanc_init + set $sfrbase = 0x00ef0000 + # Set BSEL3 (BSEL3 for the Chaos's bselc) +# set *(unsigned long *)($sfrbase + 0x5300) = 0x01018040 +# set *(unsigned long *)($sfrbase + 0x5304) = 0x01011101 + set *(unsigned long *)($sfrbase + 0x5300) = 0x04048000 + set *(unsigned long *)($sfrbase + 0x5304) = 0x01011103 + set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001 + # Reset (P5=LED,P6.b4=LAN_RESET) + set *(unsigned short *)($sfrbase + 0x106c) = 0x0000 + set *(unsigned char *)($sfrbase + 0x1016) = 0xff + set *(unsigned char *)($sfrbase + 0x1086) = 0xff + shell sleep 0.1 +# set *(unsigned char *)($sfrbase + 0x1086) = 0x00 + set *(unsigned char *)($sfrbase + 0x1086) = 0x04 + set *(unsigned long *)(0x0c000330) = 0xffffffff + # Set mac address + set $lanc = (void*)0x0c000300 + set *(unsigned long *)($lanc + 0x0000) = 0x00610010 + set *(unsigned long *)($lanc + 0x0004) = 0x00200030 + set *(unsigned long *)($lanc + 0x0008) = 0x00400050 + set *(unsigned long *)($lanc + 0x000c) = 0x00600007 +end +document lanc_init + Mappi LAN controller initialization + ex.) MAC address: 10 20 30 40 50 60 +end + +# LCD & CRT dual-head setting (8bpp) +define dispc_init + set $sfrbase = 0x00ef0000 + # BSEL4 Dispc + # 20MHz +# set *(unsigned long *)($sfrbase + 0x5400) = 0x02028282 +# set *(unsigned long *)($sfrbase + 0x5404) = 0x00122202 + # 40MHz + set *(unsigned long *)($sfrbase + 0x5400) = 0x04048000 + set *(unsigned long *)($sfrbase + 0x5404) = 0x00101103 +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + use_mon_code + while ($i < 0d32 ) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb +end + + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set $task = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$fp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 +# clock_init_on_1411 + clock_init_on_1421 +# clock_init_on_1821 +# clock_init_on_1841 +# clock_init_on_11681 +# clock_init_off + shell sleep 0.1 + port_init + sdram_init + lanc_init + dispc_init + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +# load ramdisk_082a0000.mot +# load romfs_082a0000.mot +# use_mon_code +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START +# set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d160000000 +# set *(unsigned long *)($param + 0x0018) = 0d80000000 +# set *(unsigned long *)($param + 0x0018) = 0d40000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d40000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=tty1 console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +# set {char[0x200]}($param + 0x100) = "console=tty1 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $pc=0x08001000 + set *(unsigned char *)0x08001003=0x03 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +## Boot MP +define boot_mp + set_kernel_parameters + set *(unsigned long *)0x00f00000 = boot - 0x80000000 + set *(unsigned long *)0x00eff2f8 = 0x2 + x 0x00eff2f8 + + set $pc=0x08001000 + si + c +end +document boot_mp + Boot BSP +end + +## Boot UP +define boot_up + set_kernel_parameters + set $pc=0x08001000 + si + c +end +document boot_up + Boot BSP +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot_mp +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup diff -Nru a/arch/m32r/mm/Makefile b/arch/m32r/mm/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/Makefile 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,12 @@ +# +# Makefile for the Linux M32R-specific parts of the memory manager. +# + +ifdef CONFIG_MMU +obj-y := init.o fault.o mmu.o extable.o ioremap.o cache.o page.o +else +obj-y := init.o fault-nommu.o mmu.o extable.o ioremap-nommu.o cache.o page.o +endif + +obj-$(CONFIG_DISCONTIGMEM) += discontig.o + diff -Nru a/arch/m32r/mm/cache.c b/arch/m32r/mm/cache.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/cache.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,68 @@ +/* + * linux/arch/m32r/mm/cache.c + * + * Copyright (C) 2002 Hirokazu Takata + */ + +/* $Id$ */ + +#include +#include + +#undef MCCR + +#if defined(CONFIG_CHIP_XNUX2) || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_OPSP) +/* Cache Control Register */ +#define MCCR ((volatile unsigned long*)0xfffffffc) +#define MCCR_CC (1UL << 7) /* Cache mode modify bit */ +#define MCCR_IIV (1UL << 6) /* I-cache invalidate */ +#define MCCR_DIV (1UL << 5) /* D-cache invalidate */ +#define MCCR_DCB (1UL << 4) /* D-cache copy back */ +#define MCCR_ICM (1UL << 1) /* I-cache mode [0:off,1:on] */ +#define MCCR_DCM (1UL << 0) /* D-cache mode [0:off,1:on] */ +#define MCCR_ICACHE_INV (MCCR_CC|MCCR_IIV) +#define MCCR_DCACHE_CB (MCCR_CC|MCCR_DCB) +#define MCCR_DCACHE_CBINV (MCCR_CC|MCCR_DIV|MCCR_DCB) +#define CHECK_MCCR(mccr) (mccr = *MCCR) +#elif defined(CONFIG_CHIP_M32102) +#define MCCR ((volatile unsigned long*)0xfffffffc) +#define MCCR_IIV (1UL << 8) /* I-cache invalidate */ +#define MCCR_ICACHE_INV MCCR_IIV +#endif /* CONFIG_CHIP_XNUX2 || CONFIG_CHIP_M32700 */ + +#ifndef MCCR +#error Unknown cache type. +#endif + + +/* Copy back and invalidate D-cache and invalidate I-cache all */ +void _flush_cache_all(void) +{ +#if defined(CONFIG_CHIP_M32102) + *MCCR = MCCR_ICACHE_INV; +#else + unsigned long mccr; + + /* Copyback and invalidate D-cache */ + /* Invalidate I-cache */ + *MCCR = MCCR_ICACHE_INV | MCCR_DCACHE_CBINV; + while ((mccr = *MCCR) & MCCR_IIV); /* loop while invalidating... */ +#endif +} + +/* Copy back D-cache and invalidate I-cache all */ +void _flush_cache_copyback_all(void) +{ +#if defined(CONFIG_CHIP_M32102) + *MCCR = MCCR_ICACHE_INV; +#else + unsigned long mccr; + + /* Copyback D-cache */ + /* Invalidate I-cache */ + *MCCR = MCCR_ICACHE_INV | MCCR_DCACHE_CB; + while ((mccr = *MCCR) & MCCR_IIV); /* loop while invalidating... */ + +#endif +} + diff -Nru a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/discontig.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,170 @@ +/* + * linux/arch/m32r/mm/discontig.c + * + * Discontig memory support + * + * Copyright (c) 2003 Hitoshi Yamamoto + */ + +#include +#include +#include +#include +#include + +#include + +extern char _end[]; + +struct pglist_data *node_data[MAX_NUMNODES]; +static bootmem_data_t node_bdata[MAX_NUMNODES] __initdata; + +pg_data_t m32r_node_data[MAX_NUMNODES]; + +/* Memory profile */ +typedef struct { + unsigned long start_pfn; + unsigned long pages; + unsigned long holes; + unsigned long free_pfn; +} mem_prof_t; +static mem_prof_t mem_prof[MAX_NUMNODES]; + +static void __init mem_prof_init(void) +{ + unsigned long start_pfn, holes, free_pfn; + const unsigned long zone_alignment = 1UL << (MAX_ORDER - 1); + unsigned long ul; + mem_prof_t *mp; + + /* Node#0 SDRAM */ + mp = &mem_prof[0]; + mp->start_pfn = PFN_UP(CONFIG_MEMORY_START); + mp->pages = PFN_DOWN(CONFIG_MEMORY_SIZE); + mp->holes = 0; + mp->free_pfn = PFN_UP(__pa(_end)); + + /* Node#1 internal SRAM */ + mp = &mem_prof[1]; + start_pfn = free_pfn = PFN_UP(CONFIG_IRAM_START); + holes = 0; + if (start_pfn & (zone_alignment - 1)) { + ul = zone_alignment; + while (start_pfn >= ul) + ul += zone_alignment; + + start_pfn = ul - zone_alignment; + holes = free_pfn - start_pfn; + } + + mp->start_pfn = start_pfn; + mp->pages = PFN_DOWN(CONFIG_IRAM_SIZE) + holes; + mp->holes = holes; + mp->free_pfn = PFN_UP(CONFIG_IRAM_START); +} + +unsigned long __init setup_memory(void) +{ + unsigned long bootmap_size; + unsigned long min_pfn; + int nid; + mem_prof_t *mp; + + max_low_pfn = 0; + min_low_pfn = -1; + + mem_prof_init(); + + for (nid = 0 ; nid < numnodes ; nid++) { + mp = &mem_prof[nid]; + NODE_DATA(nid)=(pg_data_t *)&m32r_node_data[nid]; + NODE_DATA(nid)->bdata = &node_bdata[nid]; + min_pfn = mp->start_pfn; + max_pfn = mp->start_pfn + mp->pages; + bootmap_size = init_bootmem_node(NODE_DATA(nid), mp->free_pfn, + mp->start_pfn, max_pfn); + + free_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn), + PFN_PHYS(mp->pages)); + + reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn), + PFN_PHYS(mp->free_pfn - mp->start_pfn) + bootmap_size); + + if (max_low_pfn < max_pfn) + max_low_pfn = max_pfn; + + if (min_low_pfn > min_pfn) + min_low_pfn = min_pfn; + } + +#ifdef CONFIG_BLK_DEV_INITRD + if (LOADER_TYPE && INITRD_START) { + if (INITRD_START + INITRD_SIZE <= PFN_PHYS(max_low_pfn)) { + reserve_bootmem_node(NODE_DATA(0), INITRD_START, + INITRD_SIZE); + initrd_start = INITRD_START ? + INITRD_START + PAGE_OFFSET : 0; + + initrd_end = initrd_start + INITRD_SIZE; + printk("initrd:start[%08lx],size[%08lx]\n", + initrd_start, INITRD_SIZE); + } else { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + INITRD_START + INITRD_SIZE, + PFN_PHYS(max_low_pfn)); + + initrd_start = 0; + } + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + return max_low_pfn; +} + +#define START_PFN(nid) \ + (NODE_DATA(nid)->bdata->node_boot_start >> PAGE_SHIFT) +#define MAX_LOW_PFN(nid) (NODE_DATA(nid)->bdata->node_low_pfn) + +unsigned long __init zone_sizes_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES], zholes_size[MAX_NR_ZONES]; + unsigned long low, start_pfn; + unsigned long holes = 0; + int nid, i; + mem_prof_t *mp; + + pgdat_list = NULL; + for (nid = numnodes - 1 ; nid >= 0 ; nid--) { + NODE_DATA(nid)->pgdat_next = pgdat_list; + pgdat_list = NODE_DATA(nid); + } + + for (nid = 0 ; nid < numnodes ; nid++) { + mp = &mem_prof[nid]; + for (i = 0 ; i < MAX_NR_ZONES ; i++) { + zones_size[i] = 0; + zholes_size[i] = 0; + } + start_pfn = START_PFN(nid); + low = MAX_LOW_PFN(nid); + zones_size[ZONE_DMA] = low - start_pfn; + zholes_size[ZONE_DMA] = mp->holes; + holes += zholes_size[ZONE_DMA]; + + free_area_init_node(nid, NODE_DATA(nid), zones_size, + start_pfn, zholes_size); + } + + /* + * For test + * Use all area of internal RAM. + * see __alloc_pages() + */ + NODE_DATA(1)->node_zones->pages_min = 0; + NODE_DATA(1)->node_zones->pages_low = 0; + NODE_DATA(1)->node_zones->pages_high = 0; + + return holes; +} + diff -Nru a/arch/m32r/mm/extable.c b/arch/m32r/mm/extable.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/extable.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,22 @@ +/* + * linux/arch/i386/mm/extable.c + */ + +#include +#include +#include +#include + +int fixup_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + fixup = search_exception_tables(regs->bpc); + if (fixup) { + regs->bpc = fixup->fixup; + return 1; + } + + return 0; +} + diff -Nru a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/fault-nommu.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,164 @@ +/* + * linux/arch/m32r/mm/fault.c + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto, and H. Kondo + * + * Some code taken from i386 version. + * Copyright (C) 1995 Linus Torvalds + */ + +/* $Id: fault-nommu.c,v 1.1 2004/03/30 06:40:59 sakugawa Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern void die(const char *, struct pt_regs *, long); + +#ifndef CONFIG_SMP +asmlinkage unsigned int tlb_entry_i_dat; +asmlinkage unsigned int tlb_entry_d_dat; +#define tlb_entry_i tlb_entry_i_dat +#define tlb_entry_d tlb_entry_d_dat +#else +unsigned int tlb_entry_i_dat[NR_CPUS]; +unsigned int tlb_entry_d_dat[NR_CPUS]; +#define tlb_entry_i tlb_entry_i_dat[smp_processor_id()] +#define tlb_entry_d tlb_entry_d_dat[smp_processor_id()] +#endif + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out + */ +void bust_spinlocks(int yes) +{ + int loglevel_save = console_loglevel; + + if (yes) { + oops_in_progress = 1; + return; + } +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; +} + +void do_BUG(const char *file, int line) +{ + bust_spinlocks(1); + printk("kernel BUG at %s:%d!\n", file, line); +} + +/*======================================================================* + * do_page_fault() + *======================================================================* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + * + * ARGUMENT: + * regs : M32R SP reg. + * error_code : See below + * address : M32R MMU MDEVA reg. (Operand ACE) + * : M32R BPC reg. (Instruction ACE) + * + * error_code : + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * bit 2 == 0 means kernel, 1 means user-mode + *======================================================================*/ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, + unsigned long address) +{ + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + + bust_spinlocks(1); + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n",address); + printk(" printing bpc:\n"); + printk(KERN_ALERT "bpc = %08lx\n", regs->bpc); + + die("Oops", regs, error_code); + bust_spinlocks(0); + do_exit(SIGKILL); +} + +/*======================================================================* + * update_mmu_cache() + *======================================================================*/ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, + pte_t pte) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_page() : flushes one page + *======================================================================*/ +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_range() : flushes a range of pages + *======================================================================*/ +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_mm() : flushes the specified mm context TLB's + *======================================================================*/ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_all() : flushes all processes TLBs + *======================================================================*/ +void local_flush_tlb_all(void) +{ + BUG(); +} + diff -Nru a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/fault.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,572 @@ +/* + * linux/arch/m32r/mm/fault.c + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto, and H. Kondo + * + * Some code taken from i386 version. + * Copyright (C) 1995 Linus Torvalds + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For unblank_screen() */ +#include +#include + +#include +#include +#include +#include +#include +#include + +extern void die(const char *, struct pt_regs *, long); + +#ifndef CONFIG_SMP +asmlinkage unsigned int tlb_entry_i_dat; +asmlinkage unsigned int tlb_entry_d_dat; +#define tlb_entry_i tlb_entry_i_dat +#define tlb_entry_d tlb_entry_d_dat +#else +unsigned int tlb_entry_i_dat[NR_CPUS]; +unsigned int tlb_entry_d_dat[NR_CPUS]; +#define tlb_entry_i tlb_entry_i_dat[smp_processor_id()] +#define tlb_entry_d tlb_entry_d_dat[smp_processor_id()] +#endif + +extern void init_tlb(void); + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out + */ +void bust_spinlocks(int yes) +{ + int loglevel_save = console_loglevel; + + if (yes) { + oops_in_progress = 1; + return; + } +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; +} + +/*======================================================================* + * do_page_fault() + *======================================================================* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + * + * ARGUMENT: + * regs : M32R SP reg. + * error_code : See below + * address : M32R MMU MDEVA reg. (Operand ACE) + * : M32R BPC reg. (Instruction ACE) + * + * error_code : + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * bit 2 == 0 means kernel, 1 means user-mode + * bit 3 == 0 means data, 1 means instruction + *======================================================================*/ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, + unsigned long address) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct * vma; + unsigned long page, addr; + int write; + siginfo_t info; + + /* + * If BPSW IE bit enable --> set PSW IE bit + */ + if (regs->psw & M32R_PSW_BIE) + local_irq_enable(); + + tsk = current; + + info.si_code = SEGV_MAPERR; + + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + * + * This verifies that the fault happens in kernel space + * (error_code & 4) == 0, and that the fault was not a + * protection error (error_code & 1) == 0. + */ + if (address >= TASK_SIZE && !(error_code & 4)) + goto vmalloc_fault; + + mm = tsk->mm; + + /* + * If we're in an interrupt or have no user context or are running in an + * atomic region then we must not take the fault.. + */ + if (in_atomic() || !mm) + goto bad_area_nosemaphore; + + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the + * kernel and should generate an OOPS. Unfortunatly, in the case of an + * erroneous fault occuring in a code path which already holds mmap_sem + * we will deadlock attempting to validate the fault against the + * address space. Luckily the kernel only validly references user + * space from well defined areas of code, which are listed in the + * exceptions table. + * + * As the vast majority of faults will be valid we will only perform + * the source reference check when there is a possibilty of a deadlock. + * Attempt to lock the address space, if we cannot we then validate the + * source. If this is invalid we can skip the address space check, + * thus avoiding the deadlock. + */ + if (!down_read_trylock(&mm->mmap_sem)) { + if ((error_code & 4) == 0 && + !search_exception_tables(regs->psw)) + goto bad_area_nosemaphore; + down_read(&mm->mmap_sem); + } + + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +#if 0 + if (error_code & 4) { + /* + * accessing the stack below "spu" is always a bug. + * The "+ 4" is there due to the push instruction + * doing pre-decrement on the stack and that + * doesn't show up until later.. + */ + if (address + 4 < regs->spu) + goto bad_area; + } +#endif + if (expand_stack(vma, address)) + goto bad_area; +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + info.si_code = SEGV_ACCERR; + write = 0; + switch (error_code & 3) { + default: /* 3: write, present */ + /* fall through */ + case 2: /* write, not present */ + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + write++; + break; + case 1: /* read, present */ + case 0: /* read, not present */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + +survive: + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + addr = (address & PAGE_MASK) | (error_code & 8); + switch (handle_mm_fault(mm, vma, addr, write)) { + case VM_FAULT_MINOR: + tsk->min_flt++; + break; + case VM_FAULT_MAJOR: + tsk->maj_flt++; + break; + case VM_FAULT_SIGBUS: + goto do_sigbus; + case VM_FAULT_OOM: + goto out_of_memory; + default: + BUG(); + } + + up_read(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up_read(&mm->mmap_sem); + +bad_area_nosemaphore: + /* User mode accesses just cause a SIGSEGV */ + if (error_code & 4) { + tsk->thread.address = address; + tsk->thread.error_code = error_code | (address >= TASK_SIZE); + tsk->thread.trap_no = 14; + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void __user *)address; + force_sig_info(SIGSEGV, &info, tsk); + return; + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + if (fixup_exception(regs)) + return; + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + + bust_spinlocks(1); + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n",address); + printk(KERN_ALERT " printing bpc:\n"); + printk("%08lx\n", regs->bpc); + page = *(unsigned long *)MPTB; + page = ((unsigned long *) page)[address >> PGDIR_SHIFT]; + printk(KERN_ALERT "*pde = %08lx\n", page); + if (page & _PAGE_PRESENT) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; + printk(KERN_ALERT "*pte = %08lx\n", page); + } + die("Oops", regs, error_code); + bust_spinlocks(0); + do_exit(SIGKILL); + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up_read(&mm->mmap_sem); + if (tsk->pid == 1) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: killing process %s\n", tsk->comm); + if (error_code & 4) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up_read(&mm->mmap_sem); + + /* Kernel mode? Handle exception or die */ + if (!(error_code & 4)) + goto no_context; + + tsk->thread.address = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void __user *)address; + force_sig_info(SIGBUS, &info, tsk); + return; + +vmalloc_fault: + { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + * + * Do _not_ use "tsk" here. We might be inside + * an interrupt in the middle of a task switch.. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + pte_t *pte_k; + + pgd = (pgd_t *)*(unsigned long *)MPTB; + pgd = offset + (pgd_t *)pgd; + pgd_k = init_mm.pgd + offset; + + if (!pgd_present(*pgd_k)) + goto no_context; + + /* + * set_pgd(pgd, *pgd_k); here would be useless on PAE + * and redundant with the set_pmd() on non-PAE. + */ + + pmd = pmd_offset(pgd, address); + pmd_k = pmd_offset(pgd_k, address); + if (!pmd_present(*pmd_k)) + goto no_context; + set_pmd(pmd, *pmd_k); + + pte_k = pte_offset_kernel(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; + + addr = (address & PAGE_MASK) | (error_code & 8); + update_mmu_cache(NULL, addr, *pte_k); + return; + } +} + +/*======================================================================* + * update_mmu_cache() + *======================================================================*/ +#define TLB_MASK (NR_TLB_ENTRIES - 1) +#define ITLB_END (unsigned long *)(ITLB_BASE + (NR_TLB_ENTRIES * 8)) +#define DTLB_END (unsigned long *)(DTLB_BASE + (NR_TLB_ENTRIES * 8)) +void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr, + pte_t pte) +{ + unsigned long *entry1, *entry2; + unsigned long pte_data, flags; + unsigned int *entry_dat; + int inst = vaddr & 8; + int i; + + /* Ptrace may call this routine. */ + if (vma && current->active_mm != vma->vm_mm) + return; + + local_irq_save(flags); + + vaddr = (vaddr & PAGE_MASK) | get_asid(); + +#ifdef CONFIG_CHIP_OPSP + entry1 = (unsigned long *)ITLB_BASE; + for(i = 0 ; i < NR_TLB_ENTRIES; i++) { + if(*entry1++ == vaddr) { + pte_data = pte_val(pte); + set_tlb_data(entry1, pte_data); + break; + } + entry1++; + } + entry2 = (unsigned long *)DTLB_BASE; + for(i = 0 ; i < NR_TLB_ENTRIES ; i++) { + if(*entry2++ == vaddr) { + pte_data = pte_val(pte); + set_tlb_data(entry2, pte_data); + break; + } + entry2++; + } + local_irq_restore(flags); + return; +#else + pte_data = pte_val(pte); + + /* + * Update TLB entries + * entry1: ITLB entry address + * entry2: DTLB entry address + */ + __asm__ __volatile__ ( + "seth %0, #high(%4) \n\t" + "st %2, @(%5, %0) \n\t" + "ldi %1, #1 \n\t" + "st %1, @(%6, %0) \n\t" + "add3 r4, %0, %7 \n\t" + ".fillinsn \n" + "1: \n\t" + "ld %1, @(%6, %0) \n\t" + "bnez %1, 1b \n\t" + "ld %0, @r4+ \n\t" + "ld %1, @r4 \n\t" + "st %3, @+%0 \n\t" + "st %3, @+%1 \n\t" + : "=&r" (entry1), "=&r" (entry2) + : "r" (vaddr), "r" (pte_data), "i" (MMU_REG_BASE), + "i" (MSVA_offset), "i" (MTOP_offset), "i" (MIDXI_offset) + : "r4", "memory" + ); + + if ((!inst && entry2 >= DTLB_END) || (inst && entry1 >= ITLB_END)) + goto notfound; + +found: + local_irq_restore(flags); + + return; + + /* Valid entry not found */ +notfound: + /* + * Update ITLB or DTLB entry + * entry1: TLB entry address + * entry2: TLB base address + */ + if (!inst) { + entry2 = (unsigned long *)DTLB_BASE; + entry_dat = &tlb_entry_d; + } else { + entry2 = (unsigned long *)ITLB_BASE; + entry_dat = &tlb_entry_i; + } + entry1 = entry2 + (((*entry_dat - 1) & TLB_MASK) << 1); + + for (i = 0 ; i < NR_TLB_ENTRIES ; i++) { + if (!(entry1[1] & 2)) /* Valid bit check */ + break; + + if (entry1 != entry2) + entry1 -= 2; + else + entry1 += TLB_MASK << 1; + } + + if (i >= NR_TLB_ENTRIES) { /* Empty entry not found */ + entry1 = entry2 + (*entry_dat << 1); + *entry_dat = (*entry_dat + 1) & TLB_MASK; + } + *entry1++ = vaddr; /* Set TLB tag */ + set_tlb_data(entry1, pte_data); + + goto found; +#endif +} + +/*======================================================================* + * flush_tlb_page() : flushes one page + *======================================================================*/ +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if (vma->vm_mm && mm_context(vma->vm_mm) != NO_CONTEXT) { + unsigned long flags; + + local_irq_save(flags); + page &= PAGE_MASK; + page |= (mm_context(vma->vm_mm) & MMU_CONTEXT_ASID_MASK); + __flush_tlb_page(page); + local_irq_restore(flags); + } +} + +/*======================================================================* + * flush_tlb_range() : flushes a range of pages + *======================================================================*/ +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct mm_struct *mm; + + mm = vma->vm_mm; + if (mm_context(mm) != NO_CONTEXT) { + unsigned long flags; + int size; + + local_irq_save(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (NR_TLB_ENTRIES / 4)) { /* Too many TLB to flush */ + mm_context(mm) = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + } else { + unsigned long asid; + + asid = mm_context(mm) & MMU_CONTEXT_ASID_MASK; + start &= PAGE_MASK; + end += (PAGE_SIZE - 1); + end &= PAGE_MASK; + + start |= asid; + end |= asid; + while (start < end) { + __flush_tlb_page(start); + start += PAGE_SIZE; + } + } + local_irq_restore(flags); + } +} + +/*======================================================================* + * flush_tlb_mm() : flushes the specified mm context TLB's + *======================================================================*/ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + /* Invalidate all TLB of this process. */ + /* Instead of invalidating each TLB, we get new MMU context. */ + if (mm_context(mm) != NO_CONTEXT) { + unsigned long flags; + + local_irq_save(flags); + mm_context(mm) = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + local_irq_restore(flags); + } +} + +/*======================================================================* + * flush_tlb_all() : flushes all processes TLBs + *======================================================================*/ +void local_flush_tlb_all(void) +{ + unsigned long flags; + + local_irq_save(flags); + __flush_tlb_all(); + local_irq_restore(flags); +} + +/*======================================================================* + * init_mmu() + *======================================================================*/ +void __init init_mmu(void) +{ + tlb_entry_i = 0; + tlb_entry_d = 0; + mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; + set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); + *(volatile unsigned long *)MPTB = (unsigned long)swapper_pg_dir; +} diff -Nru a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/init.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,250 @@ +/* + * linux/arch/m32r/mm/init.c + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto + * + * Some code taken from sh version. + * Copyright (C) 1999 Niibe Yutaka + * Based on linux/arch/i386/mm/init.c: + * Copyright (C) 1995 Linus Torvalds + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* References to section boundaries */ +extern char _text, _etext, _edata; +extern char __init_begin, __init_end; + +pgd_t swapper_pg_dir[1024]; + +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + +void show_mem(void) +{ + int total = 0, reserved = 0; + int shared = 0, cached = 0; + int highmem = 0; + struct page *page; + pg_data_t *pgdat; + unsigned long i; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; ++i) { + page = pgdat->node_mem_map + i; + total++; + if (PageHighMem(page)) + highmem++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; + } + } + printk("%d pages of RAM\n", total); + printk("%d pages of HIGHMEM\n",highmem); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); +} + +/* + * Cache of MMU context last used. + */ +#ifndef CONFIG_SMP +unsigned long mmu_context_cache_dat; +#else +unsigned long mmu_context_cache_dat[NR_CPUS]; +#endif +static unsigned long hole_pages; + +/* + * function prototype + */ +void __init paging_init(void); +void __init mem_init(void); +void free_initmem(void); +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long, unsigned long); +#endif + +/* It'd be good if these lines were in the standard header file. */ +#define START_PFN(nid) \ + (NODE_DATA(nid)->bdata->node_boot_start >> PAGE_SHIFT) +#define MAX_LOW_PFN(nid) (NODE_DATA(nid)->bdata->node_low_pfn) + +#ifndef CONFIG_DISCONTIGMEM +unsigned long __init zone_sizes_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long max_dma; + unsigned long low; + unsigned long start_pfn; + +#ifdef CONFIG_MMU + start_pfn = START_PFN(0); + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = MAX_LOW_PFN(0); + + if (low < max_dma){ + zones_size[ZONE_DMA] = low - start_pfn; + zones_size[ZONE_NORMAL] = 0; + } else { + zones_size[ZONE_DMA] = low - start_pfn; + zones_size[ZONE_NORMAL] = low - max_dma; + } +#else + zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT; + zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT; + start_pfn = __MEMORY_START >> PAGE_SHIFT; +#endif /* CONFIG_MMU */ + + free_area_init_node(0, NODE_DATA(0), zones_size, start_pfn, 0); + + mem_map = contig_page_data.node_mem_map; + + return 0; +} +#else /* CONFIG_DISCONTIGMEM */ +extern unsigned long zone_sizes_init(void); +#endif /* CONFIG_DISCONTIGMEM */ + +/*======================================================================* + * paging_init() : sets up the page tables + *======================================================================*/ +void __init paging_init(void) +{ +#ifdef CONFIG_MMU + int i; + pgd_t *pg_dir; + + /* We don't need kernel mapping as hardware support that. */ + pg_dir = swapper_pg_dir; + + for (i = 0 ; i < USER_PTRS_PER_PGD * 2 ; i++) + pgd_val(pg_dir[i]) = 0; +#endif /* CONFIG_MMU */ + hole_pages = zone_sizes_init(); +} + +int __init reservedpages_count(void) +{ + int reservedpages, nid, i; + + reservedpages = 0; + for (nid = 0 ; nid < numnodes ; nid++) + for (i = 0 ; i < MAX_LOW_PFN(nid) - START_PFN(nid) ; i++) + if (PageReserved(NODE_DATA(nid)->node_mem_map + i)) + reservedpages++; + + return reservedpages; +} + +/*======================================================================* + * mem_init() : + * orig : arch/sh/mm/init.c + *======================================================================*/ +void __init mem_init(void) +{ + int codesize, reservedpages, datasize, initsize; + int nid; +#ifndef CONFIG_MMU + extern unsigned long memory_end; +#endif + + num_physpages = 0; + for (nid = 0 ; nid < numnodes ; nid++) + num_physpages += MAX_LOW_PFN(nid) - START_PFN(nid) + 1; + + num_physpages -= hole_pages; + +#ifndef CONFIG_DISCONTIGMEM + max_mapnr = num_physpages; +#endif /* CONFIG_DISCONTIGMEM */ + +#ifdef CONFIG_MMU + high_memory = (void *)__va(PFN_PHYS(MAX_LOW_PFN(0))); +#else + high_memory = (void *)(memory_end & PAGE_MASK); +#endif /* CONFIG_MMU */ + + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); + + /* this will put all low memory onto the freelists */ + for (nid = 0 ; nid < numnodes ; nid++) + totalram_pages += free_all_bootmem_node(NODE_DATA(nid)); + + reservedpages = reservedpages_count() - hole_pages; + codesize = (unsigned long) &_etext - (unsigned long)&_text; + datasize = (unsigned long) &_edata - (unsigned long)&_etext; + initsize = (unsigned long) &__init_end - (unsigned long)&__init_begin; + + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " + "%dk reserved, %dk data, %dk init)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +} + +/*======================================================================* + * free_initmem() : + * orig : arch/sh/mm/init.c + *======================================================================*/ +void free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + totalram_pages++; + } + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", \ + (int)(&__init_end - &__init_begin) >> 10); +} + +#ifdef CONFIG_BLK_DEV_INITRD +/*======================================================================* + * free_initrd_mem() : + * orig : arch/sh/mm/init.c + *======================================================================*/ +void free_initrd_mem(unsigned long start, unsigned long end) +{ + unsigned long p; + for (p = start; p < end; p += PAGE_SIZE) { + ClearPageReserved(virt_to_page(p)); + set_page_count(virt_to_page(p), 1); + free_page(p); + totalram_pages++; + } + printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif + diff -Nru a/arch/m32r/mm/ioremap-nommu.c b/arch/m32r/mm/ioremap-nommu.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/ioremap-nommu.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,52 @@ +/* + * linux/arch/m32r/mm/ioremap-nommu.c + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo + * + * Taken from mips version. + * (C) Copyright 1995 1996 Linus Torvalds + * (C) Copyright 2001 Ralf Baechle + */ + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ + +#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL)) + +void __iomem * +__ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + return (void *)phys_addr; +} + +#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1) + +void iounmap(volatile void __iomem *addr) +{ +} + diff -Nru a/arch/m32r/mm/ioremap.c b/arch/m32r/mm/ioremap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/ioremap.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,192 @@ +/* + * linux/arch/m32r/mm/ioremap.c + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo + * + * Taken from mips version. + * (C) Copyright 1995 1996 Linus Torvalds + * (C) Copyright 2001 Ralf Baechle + */ + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +static inline void +remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + unsigned long pfn; + pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ + | _PAGE_WRITE | flags); + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + if (address >= end) + BUG(); + pfn = phys_addr >> PAGE_SHIFT; + do { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, pfn_pte(pfn, pgprot)); + address += PAGE_SIZE; + pfn++; + pte++; + } while (address && (address < end)); +} + +static inline int +remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + if (address >= end) + BUG(); + do { + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int +remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + int error; + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + if (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; + if (!pmd) + break; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + break; + error = 0; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); + flush_tlb_all(); + return error; +} + +/* + * Generic mapping function (not visible outside): + */ + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ + +#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL)) + +void __iomem * +__ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void __iomem * addr; + struct vm_struct * area; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Map objects in the low 512mb of address space using KSEG1, otherwise + * map using page tables. + */ + if (IS_LOW512(phys_addr) && IS_LOW512(phys_addr + size - 1)) + return (void *) KSEG1ADDR(phys_addr); + + /* + * Don't allow anybody to remap normal RAM that we're using.. + */ + if (phys_addr < virt_to_phys(high_memory)) { + char *t_addr, *t_end; + struct page *page; + + t_addr = __va(phys_addr); + t_end = t_addr + (size - 1); + + for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) + if(!PageReserved(page)) + return NULL; + } + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr + 1) - phys_addr; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + area->phys_addr = phys_addr; + addr = (void __iomem *) area->addr; + if (remap_area_pages((unsigned long)addr, phys_addr, size, flags)) { + vunmap((void __force *) addr); + return NULL; + } + + return (void __iomem *) (offset + (char __iomem *)addr); +} + +#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1) + +void iounmap(volatile void __iomem *addr) +{ + if (!IS_KSEG1(addr)) + vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} + diff -Nru a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/mmu.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,350 @@ +/* + * linux/arch/m32r/mm/mmu.S + * + * Copyright (C) 2001 by Hiroyuki Kondo + */ + +/* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */ + +#include /* CONFIG_MMU */ +#include +#include +#include + + .text +#ifdef CONFIG_MMU + +#include +#include +#include +#include + +/* + * TLB Miss Exception handler + */ + .balign 16 +ENTRY(tme_handler) + .global tlb_entry_i_dat + .global tlb_entry_d_dat + + SWITCH_TO_KERNEL_STACK + +#if defined(CONFIG_ISA_M32R2) + st r0, @-sp + st r1, @-sp + st r2, @-sp + st r3, @-sp + + seth r3, #high(MMU_REG_BASE) + ld r1, @(MESTS_offset, r3) ; r1: status (MESTS reg.) + ld r0, @(MDEVP_offset, r3) ; r0: PFN + ASID (MDEVP reg.) + st r1, @(MESTS_offset, r3) ; clear status (MESTS reg.) + and3 r1, r1, #(MESTS_IT) + bnez r1, 1f ; instruction TLB miss? + +;; data TLB miss +;; input +;; r0: PFN + ASID (MDEVP reg.) +;; r1 - r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry base address +;; r2: &tlb_entry_{i|d}_dat +;; r3: free + +#ifndef CONFIG_SMP + seth r2, #high(tlb_entry_d_dat) + or3 r2, r2, #low(tlb_entry_d_dat) +#else /* CONFIG_SMP */ + ldi r1, #-8192 + seth r2, #high(tlb_entry_d_dat) + or3 r2, r2, #low(tlb_entry_d_dat) + and r1, sp + ld r1, @(16, r1) ; current_thread_info->cpu + slli r1, #2 + add r2, r1 +#endif /* !CONFIG_SMP */ + seth r1, #high(DTLB_BASE) + or3 r1, r1, #low(DTLB_BASE) + bra 2f + + .balign 16 + .fillinsn +1: +;; instrucntion TLB miss +;; input +;; r0: MDEVP reg. (included ASID) +;; r1 - r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry base address +;; r2: &tlb_entry_{i|d}_dat +;; r3: free + ldi r3, #-4096 + and3 r0, r0, #(MMU_CONTEXT_ASID_MASK) + mvfc r1, bpc + and r1, r3 + or r0, r1 ; r0: PFN + ASID +#ifndef CONFIG_SMP + seth r2, #high(tlb_entry_i_dat) + or3 r2, r2, #low(tlb_entry_i_dat) +#else /* CONFIG_SMP */ + ldi r1, #-8192 + seth r2, #high(tlb_entry_i_dat) + or3 r2, r2, #low(tlb_entry_i_dat) + and r1, sp + ld r1, @(16, r1) ; current_thread_info->cpu + slli r1, #2 + add r2, r1 +#endif /* !CONFIG_SMP */ + seth r1, #high(ITLB_BASE) + or3 r1, r1, #low(ITLB_BASE) + + .fillinsn +2: +;; select TLB entry +;; input +;; r0: PFN + ASID +;; r1: TLB entry base address +;; r2: &tlb_entry_{i|d}_dat +;; r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2, r3: free +#ifdef CONFIG_ISA_DUAL_ISSUE + ld r3, @r2 || srli r1, #3 +#else + ld r3, @r2 + srli r1, #3 +#endif + add r1, r3 + ; tlb_entry_{d|i}_dat++; + addi r3, #1 + and3 r3, r3, #(NR_TLB_ENTRIES - 1) +#ifdef CONFIG_ISA_DUAL_ISSUE + st r3, @r2 || slli r1, #3 +#else + st r3, @r2 + slli r1, #3 +#endif + +;; load pte +;; input +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2, r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2: pte_data +;; r3: free + ; pgd = *(unsigned long *)MPTB; + ld24 r2, #(-MPTB - 1) + srl3 r3, r0, #22 +#ifdef CONFIG_ISA_DUAL_ISSUE + not r2, r2 || slli r3, #2 ; r3: pgd offset +#else + not r2, r2 + slli r3, #2 +#endif + ld r2, @r2 ; r2: pgd base addr (MPTB reg.) + or r3, r2 ; r3: pmd addr + + ; pmd = pmd_offset(pgd, address); + ld r3, @r3 ; r3: pmd data + ldi r2, #-4096 + beqz r3, 3f ; pmd_none(*pmd) ? + + ; pte = pte_offset(pmd, address); + and r2, r3 ; r2: pte base addr + srl3 r3, r0, #10 + and3 r3, r3, #0xffc ; r3: pte offset + or r3, r2 + seth r2, #0x8000 + or r3, r2 ; r3: pte addr + + ; pte_data = (unsigned long)pte_val(*pte); + ld r2, @r3 ; r2: pte data + or3 r2, r2, #2 ; _PAGE_PRESENT(=2) + + .fillinsn +5: +;; set tlb +;; input +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2: pte_data +;; r3: free + st r0, @r1 ; set_tlb_tag(entry++, address); + st r2, @+r1 ; set_tlb_data(entry, pte_data); + + .fillinsn +6: + ld r3, @sp+ + ld r2, @sp+ + ld r1, @sp+ + ld r0, @sp+ + rte + + .fillinsn +3: +;; error +;; input +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2, r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2: pte_data +;; r3: free +#ifdef CONFIG_ISA_DUAL_ISSUE + bra 5b || ldi r2, #2 +#else + ldi r2, #2 ; r2: pte_data = 0 | _PAGE_PRESENT(=2) + bra 5b +#endif + +#elif defined (CONFIG_ISA_M32R) + + st sp, @-sp + st r0, @-sp + st r1, @-sp + st r2, @-sp + st r3, @-sp + st r4, @-sp + + seth r3, #high(MMU_REG_BASE) + ld r0, @(MDEVA_offset,r3) ; r0: address (MDEVA reg.) + mvfc r2, bpc ; r2: bpc + ld r1, @(MESTS_offset,r3) ; r1: status (MESTS reg.) + st r1, @(MESTS_offset,r3) ; clear status (MESTS reg.) + and3 r1, r1, #(MESTS_IT) + beqz r1, 1f ; data TLB miss? + +;; instrucntion TLB miss + mv r0, r2 ; address = bpc; + ; entry = (unsigned long *)ITLB_BASE+tlb_entry_i*2; + seth r3, #shigh(tlb_entry_i_dat) + ld r4, @(low(tlb_entry_i_dat),r3) + sll3 r2, r4, #3 + seth r1, #high(ITLB_BASE) + or3 r1, r1, #low(ITLB_BASE) + add r2, r1 ; r2: entry + addi r4, #1 ; tlb_entry_i++; + and3 r4, r4, #(NR_TLB_ENTRIES-1) + st r4, @(low(tlb_entry_i_dat),r3) + bra 2f + .fillinsn +1: +;; data TLB miss + ; entry = (unsigned long *)DTLB_BASE+tlb_entry_d*2; + seth r3, #shigh(tlb_entry_d_dat) + ld r4, @(low(tlb_entry_d_dat),r3) + sll3 r2, r4, #3 + seth r1, #high(DTLB_BASE) + or3 r1, r1, #low(DTLB_BASE) + add r2, r1 ; r2: entry + addi r4, #1 ; tlb_entry_d++; + and3 r4, r4, #(NR_TLB_ENTRIES-1) + st r4, @(low(tlb_entry_d_dat),r3) + .fillinsn +2: +;; load pte +; r0: address, r2: entry +; r1,r3,r4: (free) + ; pgd = *(unsigned long *)MPTB; + ld24 r1, #(-MPTB-1) + not r1, r1 + ld r1, @r1 + srl3 r4, r0, #22 + sll3 r3, r4, #2 + add r3, r1 ; r3: pgd + ; pmd = pmd_offset(pgd, address); + ld r1, @r3 ; r1: pmd + beqz r1, 3f ; pmd_none(*pmd) ? +; + and3 r1, r1, #0xeff + ldi r4, #611 ; _KERNPG_TABLE(=611) + beq r1, r4, 4f ; !pmd_bad(*pmd) ? + .fillinsn +3: + ldi r1, #0 ; r1: pte_data = 0 + bra 5f + .fillinsn +4: + ; pte = pte_offset(pmd, address); + ld r4, @r3 ; r4: pte + ldi r3, #-4096 + and r4, r3 + srl3 r3, r0, #10 + and3 r3, r3, #0xffc + add r4, r3 + seth r3, #0x8000 + add r4, r3 ; r4: pte + ; pte_data = (unsigned long)pte_val(*pte); + ld r1, @r4 ; r1: pte_data + .fillinsn + +;; set tlb +; r0: address, r1: pte_data, r2: entry +; r3,r4: (free) +5: + ldi r3, #-4096 ; set_tlb_tag(entry++, address); + and r3, r0 + seth r4, #shigh(MASID) + ld r4, @(low(MASID),r4) ; r4: MASID + and3 r4, r4, #(MMU_CONTEXT_ASID_MASK) + or r3, r4 + st r3, @r2 + or3 r4, r1, #2 ; _PAGE_PRESENT(=2) + st r4, @(4,r2) ; set_tlb_data(entry, pte_data); + + ld r4, @sp+ + ld r3, @sp+ + ld r2, @sp+ + ld r1, @sp+ + ld r0, @sp+ + ld sp, @sp+ + rte + +#else +#error unknown isa configuration +#endif + +ENTRY(init_tlb) +;; Set MMU Register + seth r0, #high(MMU_REG_BASE) ; Set MMU_REG_BASE higher + or3 r0, r0, #low(MMU_REG_BASE) ; Set MMU_REG_BASE lower + ldi r1, #0 + st r1, @(MPSZ_offset,r0) ; Set MPSZ Reg(Page size 4KB:0 16KB:1 64KB:2) + ldi r1, #0 + st r1, @(MASID_offset,r0) ; Set ASID Zero + +;; Set TLB + seth r0, #high(ITLB_BASE) ; Set ITLB_BASE higher + or3 r0, r0, #low(ITLB_BASE) ; Set ITLB_BASE lower + seth r1, #high(DTLB_BASE) ; Set DTLB_BASE higher + or3 r1, r1, #low(DTLB_BASE) ; Set DTLB_BASE lower + ldi r2, #0 + ldi r3, #NR_TLB_ENTRIES + addi r0, #-4 + addi r1, #-4 +clear_tlb: + st r2, @+r0 ; VPA <- 0 + st r2, @+r0 ; PPA <- 0 + st r2, @+r1 ; VPA <- 0 + st r2, @+r1 ; PPA <- 0 + addi r3, #-1 + bnez r3, clear_tlb +;; + jmp r14 + +ENTRY(m32r_itlb_entrys) +ENTRY(m32r_otlb_entrys) + +#endif /* CONFIG_MMU */ + +.end + diff -Nru a/arch/m32r/mm/page.S b/arch/m32r/mm/page.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/mm/page.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,82 @@ +/* + * linux/arch/m32r/mm/page.S + * + * Clear/Copy page with CPU + * + * Copyright (C) 2004 The Free Software Initiative of Japan + * + * Written by Niibe Yutaka + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + .text + .global copy_page + /* + * copy_page (to, from) + * + * PAGE_SIZE = 4096-byte + * Cache line = 16-byte + * 16 * 256 + */ + .align 4 +copy_page: + ldi r2, #255 + ld r3, @r0 /* cache line allocate */ + ld r4, @r1+ + ld r5, @r1+ + ld r6, @r1+ + ld r7, @r1+ + .fillinsn +0: + st r4, @r0 + st r5, @+r0 + st r6, @+r0 + st r7, @+r0 + ld r4, @r1+ + addi r0, #4 + ld r5, @r1+ + ld r6, @r1+ + ld r7, @r1+ + ld r3, @r0 /* cache line allocate */ + addi r2, #-1 + bnez r2, 0b + + st r4, @r0 + st r5, @+r0 + st r6, @+r0 + st r7, @+r0 + jmp r14 + + .text + .global clear_page + /* + * clear_page (to) + * + * PAGE_SIZE = 4096-byte + * Cache line = 16-byte + * 16 * 256 + */ + .align 4 +clear_page: + ldi r2, #255 + ldi r4, #0 + ld r3, @r0 /* cache line allocate */ + .fillinsn +0: + st r4, @r0 + st r4, @+r0 + st r4, @+r0 + st r4, @+r0 + addi r0, #4 + ld r3, @r0 /* cache line allocate */ + addi r2, #-1 + bnez r2, 0b + + st r4, @r0 + st r4, @+r0 + st r4, @+r0 + st r4, @+r0 + jmp r14 diff -Nru a/arch/m32r/oaks32r/defconfig.nommu b/arch/m32r/oaks32r/defconfig.nommu --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/oaks32r/defconfig.nommu 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,521 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +CONFIG_PLAT_OAKS32R=y +# CONFIG_PLAT_MAPPI2 is not set +# CONFIG_CHIP_M32700 is not set +CONFIG_CHIP_M32102=y +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_ISA_M32R=y +CONFIG_BUS_CLOCK=33333333 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x01000000 +CONFIG_MEMORY_SIZE=0x00800000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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 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 is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +# 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_HFSPLUS_FS is not set +# 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/m32r/oaks32r/dot.gdbinit.nommu b/arch/m32r/oaks32r/dot.gdbinit.nommu --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/oaks32r/dot.gdbinit.nommu 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,155 @@ +# .gdbinit file +# $Id: dot.gdbinit.oaks32r,v 1.2 2004/04/15 02:33:14 takata Exp $ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.10 2004/04/15 02:10:45 takata Exp $ +#----- +# target platform: oaks32r + +# setting +set width 0d70 +set radix 0d16 + +# clk xin:cpu:bus=16:66:33 +define clock_init + set *(unsigned long *)0x00ef4008 = 1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4000 = 0x00020100 +end + +# Initialize programmable ports +define port_init + set *(unsigned long *)0x00ef1000 = 0x1 + set *(unsigned long *)0x00ef1060 = 0x01400001 + set *(unsigned long *)0x00ef1064 = 0x00015555 + set *(unsigned long *)0x00ef1068 = 0x55555050 + set *(unsigned long *)0x00ef106c = 0x05150040 +end + +# Initialize SDRAM controller +define sdram_init + set *(unsigned long *)0x00ef6008 = 0x00000182 + set *(unsigned long *)0x00ef600c = 0x00000001 + shell sleep 0.1 + set *(unsigned long *)0x00ef602c = 0x00000010 + set *(unsigned long *)0x00ef6028 = 0x00000300 + set *(unsigned long *)0x00ef6048 = 0x00000001 + set *(unsigned long *)0x00ef6020 = 0x01000041 + set *(unsigned long *)0x00ef6004 = 0x00010117 + set *(unsigned long *)0x00ef6010 = 0x00000001 + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x01000000 - 0x017fffff (8MB) +end + +# Initialize LAN controller +define lanc_init + set *(unsigned long *)0x00ef5008 = 0x03031303 + #RST DRV (P64) + set *(unsigned char *)0x00ef1046 = 0x08 + set *(unsigned char *)0x00ef1026 = 0xff + set *(unsigned char *)0x00ef1026 = 0x00 + set *(unsigned short *)0x02000630 = 0xffff +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + port_init + sdram_init + lanc_init +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x01002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x00000000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d66666667 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d33333333 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + +# set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.busybox.flat nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc = 0x01001000 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x00000020 + b *0x00000030 +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup +#load_modules +#set_breakpoints +#boot + diff -Nru a/arch/m32r/oprofile/Kconfig b/arch/m32r/oprofile/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/oprofile/Kconfig 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,23 @@ + +menu "Profiling support" + depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +endmenu + diff -Nru a/arch/m32r/oprofile/Makefile b/arch/m32r/oprofile/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/oprofile/Makefile 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,9 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) init.o diff -Nru a/arch/m32r/oprofile/init.c b/arch/m32r/oprofile/init.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/oprofile/init.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,25 @@ +/** + * @file init.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include + +extern void timer_init(struct oprofile_operations ** ops); + +int __init oprofile_arch_init(struct oprofile_operations ** ops) +{ + return -ENODEV; +} + + +void oprofile_arch_exit(void) +{ +} diff -Nru a/arch/m32r/opsput/defconfig.opsput b/arch/m32r/opsput/defconfig.opsput --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/opsput/defconfig.opsput 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,598 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +CONFIG_PLAT_OPSPUT=y +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +# CONFIG_CHIP_M32700 is not set +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +CONFIG_CHIP_OPSP=y +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_PREEMPT is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32R_CFC is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR 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=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# 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_HFSPLUS_FS is not set +# 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=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# 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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/m32r/opsput/dot.gdbinit b/arch/m32r/opsput/dot.gdbinit --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m32r/opsput/dot.gdbinit 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,180 @@ +# .gdbinit file +# $Id: dot.gdbinit,v 1.1 2004/07/27 06:54:20 sakugawa Exp $ + +# setting +set width 0d70 +set radix 0d16 +set height 0 +debug_chaos + +define tlb_init + set $tlbbase = 0xfe000000 + set *(unsigned long *)($tlbbase + 0x04) = 0x0 + set *(unsigned long *)($tlbbase + 0x0c) = 0x0 + set *(unsigned long *)($tlbbase + 0x14) = 0x0 + set *(unsigned long *)($tlbbase + 0x1c) = 0x0 + set *(unsigned long *)($tlbbase + 0x24) = 0x0 + set *(unsigned long *)($tlbbase + 0x2c) = 0x0 + set *(unsigned long *)($tlbbase + 0x34) = 0x0 + set *(unsigned long *)($tlbbase + 0x3c) = 0x0 + set *(unsigned long *)($tlbbase + 0x44) = 0x0 + set *(unsigned long *)($tlbbase + 0x4c) = 0x0 + set *(unsigned long *)($tlbbase + 0x54) = 0x0 + set *(unsigned long *)($tlbbase + 0x5c) = 0x0 + set *(unsigned long *)($tlbbase + 0x64) = 0x0 + set *(unsigned long *)($tlbbase + 0x6c) = 0x0 + set *(unsigned long *)($tlbbase + 0x74) = 0x0 + set *(unsigned long *)($tlbbase + 0x7c) = 0x0 + set *(unsigned long *)($tlbbase + 0x84) = 0x0 + set *(unsigned long *)($tlbbase + 0x8c) = 0x0 + set *(unsigned long *)($tlbbase + 0x94) = 0x0 + set *(unsigned long *)($tlbbase + 0x9c) = 0x0 + set *(unsigned long *)($tlbbase + 0xa4) = 0x0 + set *(unsigned long *)($tlbbase + 0xac) = 0x0 + set *(unsigned long *)($tlbbase + 0xb4) = 0x0 + set *(unsigned long *)($tlbbase + 0xbc) = 0x0 + set *(unsigned long *)($tlbbase + 0xc4) = 0x0 + set *(unsigned long *)($tlbbase + 0xcc) = 0x0 + set *(unsigned long *)($tlbbase + 0xd4) = 0x0 + set *(unsigned long *)($tlbbase + 0xdc) = 0x0 + set *(unsigned long *)($tlbbase + 0xe4) = 0x0 + set *(unsigned long *)($tlbbase + 0xec) = 0x0 + set *(unsigned long *)($tlbbase + 0xf4) = 0x0 + set *(unsigned long *)($tlbbase + 0xfc) = 0x0 + set $tlbbase = 0xfe000800 + set *(unsigned long *)($tlbbase + 0x04) = 0x0 + set *(unsigned long *)($tlbbase + 0x0c) = 0x0 + set *(unsigned long *)($tlbbase + 0x14) = 0x0 + set *(unsigned long *)($tlbbase + 0x1c) = 0x0 + set *(unsigned long *)($tlbbase + 0x24) = 0x0 + set *(unsigned long *)($tlbbase + 0x2c) = 0x0 + set *(unsigned long *)($tlbbase + 0x34) = 0x0 + set *(unsigned long *)($tlbbase + 0x3c) = 0x0 + set *(unsigned long *)($tlbbase + 0x44) = 0x0 + set *(unsigned long *)($tlbbase + 0x4c) = 0x0 + set *(unsigned long *)($tlbbase + 0x54) = 0x0 + set *(unsigned long *)($tlbbase + 0x5c) = 0x0 + set *(unsigned long *)($tlbbase + 0x64) = 0x0 + set *(unsigned long *)($tlbbase + 0x6c) = 0x0 + set *(unsigned long *)($tlbbase + 0x74) = 0x0 + set *(unsigned long *)($tlbbase + 0x7c) = 0x0 + set *(unsigned long *)($tlbbase + 0x84) = 0x0 + set *(unsigned long *)($tlbbase + 0x8c) = 0x0 + set *(unsigned long *)($tlbbase + 0x94) = 0x0 + set *(unsigned long *)($tlbbase + 0x9c) = 0x0 + set *(unsigned long *)($tlbbase + 0xa4) = 0x0 + set *(unsigned long *)($tlbbase + 0xac) = 0x0 + set *(unsigned long *)($tlbbase + 0xb4) = 0x0 + set *(unsigned long *)($tlbbase + 0xbc) = 0x0 + set *(unsigned long *)($tlbbase + 0xc4) = 0x0 + set *(unsigned long *)($tlbbase + 0xcc) = 0x0 + set *(unsigned long *)($tlbbase + 0xd4) = 0x0 + set *(unsigned long *)($tlbbase + 0xdc) = 0x0 + set *(unsigned long *)($tlbbase + 0xe4) = 0x0 + set *(unsigned long *)($tlbbase + 0xec) = 0x0 + set *(unsigned long *)($tlbbase + 0xf4) = 0x0 + set *(unsigned long *)($tlbbase + 0xfc) = 0x0 +end + +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x88002000 + # INITRD_START +# set *(unsigned long *)($param + 0x0010) = 0x08300000 + # INITRD_SIZE +# set *(unsigned long *)($param + 0x0014) = 0x00400000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d200000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d50000000 +# set *(unsigned long *)($param + 0x001c) = 0d25000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x\ + root=/dev/nfsroot \ + nfsroot=192.168.0.1:/project/m32r-linux/export/root.2.6 \ + nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \ + mem=16m \0" +end + +define boot + set_kernel_parameters + set $pc=0x88001000 + set $fp=0 + set $evb=0x88000000 + # I/D-Cache ON + +# IPI +# set *(long *)0x00eff2f8 = 0x2 + set $fp=0 +# set *(unsigned long *)0xa0ef4000 = 0x100 + si +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + use_mon_code + while ($i < 0d32 ) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end +# use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb +end + +define show_regs + printf " R0[%08lx] R1[%08lx] R2[%08lx] R3[%08lx]\n",$r0,$r1,$r2,$r3 + printf " R4[%08lx] R5[%08lx] R6[%08lx] R7[%08lx]\n",$r4,$r5,$r6,$r7 + printf " R8[%08lx] R9[%08lx] R10[%08lx] R11[%08lx]\n",$r8,$r9,$r10,$r11 + printf "R12[%08lx] FP[%08lx] LR[%08lx] SP[%08lx]\n",$r12,$fp,$lr,$sp + printf "PSW[%08lx] CBR[%08lx] SPI[%08lx] SPU[%08lx]\n",$psw,$cbr,$spi,$spu + printf "BPC[%08lx] PC[%08lx] ACCL[%08lx] ACCH[%08lx]\n",$bpc,$pc,$accl,$acch + printf "EVB[%08lx]\n",$evb +end + +define setup + debug_chaos + set *(unsigned long *)0xa0ef6004 = 0x0001053f + set *(unsigned long *)0xa0ef6028 = 0x00031102 +# set *(unsigned long *)0xa0ef400c = 0x2 +end + +sdireset +sdireset +file vmlinux +target m32rsdi +set $pc=0x0 +b *0x30000 +c +setup +tlb_init +load_modules +#set *(long *)0xa0ef4000=0x101 +#set *(long *)0xa0ef400c=0x002 + +boot +#b tme_handler +b *0x88000020 + + + + diff -Nru a/arch/m68k/Kconfig b/arch/m68k/Kconfig --- a/arch/m68k/Kconfig 2004-10-18 14:56:33 -07:00 +++ b/arch/m68k/Kconfig 2004-10-18 14:56:33 -07:00 @@ -21,12 +21,10 @@ config RWSEM_XCHGADD_ALGORITHM bool - mainmenu "Linux/68k Kernel Configuration" source "init/Kconfig" - menu "Platform dependent setup" config EISA @@ -355,7 +353,6 @@ endmenu - menu "General setup" source "fs/Kconfig.binfmt" @@ -447,7 +444,6 @@ source "drivers/Kconfig" - menu "Character devices" config ATARI_MFPSER @@ -652,47 +648,10 @@ source "fs/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting" - depends on DEBUG_KERNEL - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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. - -endmenu +source "arch/m68k/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/m68k/Kconfig.debug b/arch/m68k/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m68k/Kconfig.debug 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,5 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +endmenu diff -Nru a/arch/m68k/Makefile b/arch/m68k/Makefile --- a/arch/m68k/Makefile 2004-10-18 14:57:03 -07:00 +++ b/arch/m68k/Makefile 2004-10-18 14:57:03 -07:00 @@ -28,7 +28,7 @@ LDFLAGS_vmlinux = -N endif -CHECK := $(CHECK) -D__mc68000__=1 -I$(shell $(CC) -print-file-name=include) +CHECKFLAGS += -D__mc68000__ -I$(shell $(CC) -print-file-name=include) # without -fno-strength-reduce the 53c7xx.c driver fails ;-( CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 diff -Nru a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile --- a/arch/m68k/kernel/Makefile 2004-10-18 14:56:49 -07:00 +++ b/arch/m68k/kernel/Makefile 2004-10-18 14:56:49 -07:00 @@ -7,7 +7,7 @@ else extra-y := sun3-head.o endif -extra-y += vmlinux.lds.s +extra-y += vmlinux.lds obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o diff -Nru a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c --- a/arch/m68k/kernel/bios32.c 2004-10-18 14:56:32 -07:00 +++ b/arch/m68k/kernel/bios32.c 2004-10-18 14:56:32 -07:00 @@ -77,11 +77,6 @@ static unsigned int io_base; static unsigned int mem_base; -struct pci_fixup pcibios_fixups[] = -{ - { 0 } -}; - /* * static void disable_dev(struct pci_dev *dev) * diff -Nru a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c --- a/arch/m68k/kernel/m68k_ksyms.c 2004-10-18 14:56:50 -07:00 +++ b/arch/m68k/kernel/m68k_ksyms.c 2004-10-18 14:56:50 -07:00 @@ -16,7 +16,6 @@ #include #include #include -#include asmlinkage long long __ashldi3 (long long, int); asmlinkage long long __ashrdi3 (long long, int); @@ -72,18 +71,18 @@ explicitly (the C compiler generates them). Fortunately, their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(__muldi3); - -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(__muldi3); + +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(get_wchan); diff -Nru a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c --- a/arch/m68k/kernel/process.c 2004-10-18 14:57:05 -07:00 +++ b/arch/m68k/kernel/process.c 2004-10-18 14:57:05 -07:00 @@ -232,7 +232,7 @@ child_tidptr = (int *)regs->d4; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, + return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); } diff -Nru a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c --- a/arch/m68k/kernel/ptrace.c 2004-10-18 14:56:27 -07:00 +++ b/arch/m68k/kernel/ptrace.c 2004-10-18 14:56:27 -07:00 @@ -379,11 +379,8 @@ if (!current->thread.work.delayed_trace && !current->thread.work.syscall_trace) return; - 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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c --- a/arch/m68k/kernel/signal.c 2004-10-18 14:56:48 -07:00 +++ b/arch/m68k/kernel/signal.c 2004-10-18 14:56:48 -07:00 @@ -842,9 +842,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); goto adjust_stack; } @@ -925,9 +923,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); goto adjust_stack; } diff -Nru a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c --- a/arch/m68k/kernel/time.c 2004-10-18 14:56:20 -07:00 +++ b/arch/m68k/kernel/time.c 2004-10-18 14:56:20 -07:00 @@ -38,24 +38,6 @@ return -1; } -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -63,9 +45,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) { do_timer(regs); - - if (!user_mode(regs)) - do_profile(regs->pc); + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_HEARTBEAT /* use power LED as a heartbeat instead -- much more useful diff -Nru a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds --- a/arch/m68k/kernel/vmlinux-std.lds 2004-10-18 14:57:03 -07:00 +++ b/arch/m68k/kernel/vmlinux-std.lds 2004-10-18 14:57:03 -07:00 @@ -51,9 +51,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds --- a/arch/m68k/kernel/vmlinux-sun3.lds 2004-10-18 14:55:46 -07:00 +++ b/arch/m68k/kernel/vmlinux-sun3.lds 2004-10-18 14:55:46 -07:00 @@ -45,9 +45,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c --- a/arch/m68k/q40/q40ints.c 2004-10-18 14:57:03 -07:00 +++ b/arch/m68k/q40/q40ints.c 2004-10-18 14:57:03 -07:00 @@ -19,12 +19,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff -Nru a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig --- a/arch/m68knommu/Kconfig 2004-10-18 14:56:48 -07:00 +++ b/arch/m68knommu/Kconfig 2004-10-18 14:56:48 -07:00 @@ -5,6 +5,10 @@ mainmenu "uClinux/68k (w/o MMU) Kernel Configuration" +config M68KNOMMU + bool + default y + config MMU bool default n @@ -25,7 +29,6 @@ bool default n - source "init/Kconfig" menu "Processor type and features" @@ -388,7 +391,7 @@ a lot of RAM, and you need to able to allocate very large contiguous chunks. If unsure, say N. -choice +choice prompt "RAM size" default AUTO @@ -421,7 +424,7 @@ endchoice -choice +choice prompt "RAM bus width" default RAMAUTOBIT @@ -472,7 +475,6 @@ endmenu - menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" config PCI @@ -511,64 +513,10 @@ source "fs/Kconfig" -menu "Kernel hacking" - -config FULLDEBUG - bool "Full Symbolic/Source Debugging support" - help - Enable debuging symbols on kernel build. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - 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 "Magic SysRq key" - help - Enables console device to interpret special characters as - commands to dump state information. - -config HIGHPROFILE - bool "Use fast second timer for profiling" - depends on COLDFIRE - help - Use a fast secondary clock to produce profiling information. - -config BOOTPARAM - bool 'Compiled-in Kernel Boot Parameter' - -config BOOTPARAM_STRING - string 'Kernel Boot Parameter' - default 'console=ttyS0,19200' - depends on BOOTPARAM - -config DUMPTOFLASH - bool "Panic/Dump to FLASH" - depends on COLDFIRE - help - Dump any panic of trap output into a flash memory segment - for later analysis. - -config NO_KERNEL_MSG - bool "Suppress Kernel BUG Messages" - help - Do not output any debug BUG messages within the kernel. - -config BDM_DISABLE - bool "Disable BDM signals" - depends on (EXPERIMENTAL && COLDFIRE) - help - Disable the ColdFire CPU's BDM signals. - -endmenu +source "arch/m68knommu/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/m68knommu/Kconfig.debug 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,42 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debuging symbols on kernel build. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + depends on COLDFIRE + help + Use a fast secondary clock to produce profiling information. + +config BOOTPARAM + bool 'Compiled-in Kernel Boot Parameter' + +config BOOTPARAM_STRING + string 'Kernel Boot Parameter' + default 'console=ttyS0,19200' + depends on BOOTPARAM + +config DUMPTOFLASH + bool "Panic/Dump to FLASH" + depends on COLDFIRE + help + Dump any panic of trap output into a flash memory segment + for later analysis. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config BDM_DISABLE + bool "Disable BDM signals" + depends on (EXPERIMENTAL && COLDFIRE) + help + Disable the ColdFire CPU's BDM signals. + +endmenu diff -Nru a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile --- a/arch/m68knommu/kernel/Makefile 2004-10-18 14:56:27 -07:00 +++ b/arch/m68knommu/kernel/Makefile 2004-10-18 14:56:27 -07:00 @@ -2,7 +2,7 @@ # Makefile for arch/m68knommu/kernel. # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds obj-y += dma.o entry.o init_task.o m68k_ksyms.o process.o ptrace.o semaphore.o \ setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o diff -Nru a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c --- a/arch/m68knommu/kernel/asm-offsets.c 2004-10-18 14:57:04 -07:00 +++ b/arch/m68knommu/kernel/asm-offsets.c 2004-10-18 14:57:04 -07:00 @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) diff -Nru a/arch/m68knommu/kernel/comempci.c b/arch/m68knommu/kernel/comempci.c --- a/arch/m68knommu/kernel/comempci.c 2004-10-18 14:56:32 -07:00 +++ b/arch/m68knommu/kernel/comempci.c 2004-10-18 14:56:32 -07:00 @@ -351,8 +351,6 @@ } /*****************************************************************************/ -struct pci_fixup pcibios_fixups[] = { { 0 } }; - void pcibios_fixup_bus(struct pci_bus *b) { } diff -Nru a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c --- a/arch/m68knommu/kernel/m68k_ksyms.c 2004-10-18 14:57:03 -07:00 +++ b/arch/m68knommu/kernel/m68k_ksyms.c 2004-10-18 14:57:03 -07:00 @@ -16,7 +16,6 @@ #include #include #include -#include #include extern void dump_thread(struct pt_regs *, struct user *); @@ -50,16 +49,16 @@ explicitly (the C compiler generates them). Fortunately, their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memmove); - -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memmove); + +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(get_wchan); @@ -79,27 +78,27 @@ extern void __umodsi3(void); /* gcc lib functions */ -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__divsi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(__modsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__mulsi3); -EXPORT_SYMBOL_NOVERS(__udivsi3); -EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulsi3); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umodsi3); -EXPORT_SYMBOL_NOVERS(is_in_rom); +EXPORT_SYMBOL(is_in_rom); #ifdef CONFIG_COLDFIRE extern unsigned int *dma_device_address; extern unsigned long dma_base_addr, _ramend; -EXPORT_SYMBOL_NOVERS(dma_base_addr); -EXPORT_SYMBOL_NOVERS(dma_device_address); -EXPORT_SYMBOL_NOVERS(_ramend); +EXPORT_SYMBOL(dma_base_addr); +EXPORT_SYMBOL(dma_device_address); +EXPORT_SYMBOL(_ramend); extern asmlinkage void trap(void); extern void *_ramvec; -EXPORT_SYMBOL_NOVERS(trap); -EXPORT_SYMBOL_NOVERS(_ramvec); +EXPORT_SYMBOL(trap); +EXPORT_SYMBOL(_ramvec); #endif /* CONFIG_COLDFIRE */ diff -Nru a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c --- a/arch/m68knommu/kernel/process.c 2004-10-18 14:56:18 -07:00 +++ b/arch/m68knommu/kernel/process.c 2004-10-18 14:56:18 -07:00 @@ -188,7 +188,7 @@ newsp = regs->d2; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL); + return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); } int copy_thread(int nr, unsigned long clone_flags, diff -Nru a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c --- a/arch/m68knommu/kernel/ptrace.c 2004-10-18 14:56:32 -07:00 +++ b/arch/m68knommu/kernel/ptrace.c 2004-10-18 14:56:32 -07:00 @@ -133,13 +133,6 @@ ret = ptrace_attach(child); goto out_tsk; } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; @@ -376,10 +369,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; - 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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c --- a/arch/m68knommu/kernel/signal.c 2004-10-18 14:56:33 -07:00 +++ b/arch/m68knommu/kernel/signal.c 2004-10-18 14:56:33 -07:00 @@ -616,9 +616,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); goto adjust_stack; } @@ -685,9 +683,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); goto adjust_stack; } diff -Nru a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c --- a/arch/m68knommu/kernel/time.c 2004-10-18 14:56:33 -07:00 +++ b/arch/m68knommu/kernel/time.c 2004-10-18 14:56:33 -07:00 @@ -41,24 +41,6 @@ return -1; } -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -75,9 +57,8 @@ write_seqlock(&xtime_lock); do_timer(regs); - - if (!user_mode(regs)) - do_profile(regs->pc); + if (current->pid) + profile_tick(CPU_PROFILING, regs); /* * If we have an externally synchronized Linux clock, then update diff -Nru a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S --- a/arch/m68knommu/kernel/vmlinux.lds.S 2004-10-18 14:56:29 -07:00 +++ b/arch/m68knommu/kernel/vmlinux.lds.S 2004-10-18 14:56:29 -07:00 @@ -284,9 +284,6 @@ __setup_start = .; *(.init.setup) __setup_end = .; - __start___param = .; - *(__param) - __stop___param = .; __initcall_start = .; *(.initcall1.init) *(.initcall2.init) diff -Nru a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c --- a/arch/m68knommu/platform/5307/timers.c 2004-10-18 14:57:05 -07:00 +++ b/arch/m68knommu/platform/5307/timers.c 2004-10-18 14:57:05 -07:00 @@ -110,17 +110,8 @@ { /* Reset ColdFire timer2 */ mcf_proftp->ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; - - if (!user_mode(regs)) { - if (prof_buffer && current->pid) { - extern int _stext; - unsigned long ip = instruction_pointer(regs); - ip -= (unsigned long) &_stext; - ip >>= prof_shift; - if (ip < prof_len) - prof_buffer[ip]++; - } - } + if (current->pid) + profile_tick(CPU_PROFILING, regs); } /***************************************************************************/ diff -Nru a/arch/mips/Kconfig b/arch/mips/Kconfig --- a/arch/mips/Kconfig 2004-10-18 14:56:29 -07:00 +++ b/arch/mips/Kconfig 2004-10-18 14:56:29 -07:00 @@ -381,7 +381,7 @@ evaluation board. Features : kernel debugging, serial terminal, NFS root fs, on-board - ether port USB, AC97, PCI, PCI VGA card & framebuffer console, + ether port USB, AC97, PCI, PCI VGA card & framebuffer console, IDE controller, PS2 keyboard, PS2 mouse, etc. config DDB5477 @@ -400,7 +400,7 @@ int "bus frequency (in kHZ, 0 for auto-detect)" depends on DDB5477 default 0 - + config NEC_OSPREY bool "Support for NEC Osprey board" select DMA_NONCOHERENT @@ -513,15 +513,15 @@ endchoice -choice +choice prompt "AMD/Alchemy Au1x00 board support" depends on SOC_AU1X00 help These are evaluation boards built by AMD/Alchemy to showcase their Au1X00 Internet Edge Processors. The SOC design - is based on the MIPS32 architecture running at 266/400/500MHz - with many integrated peripherals. Further information can be - found at their website, . Say Y here if you + is based on the MIPS32 architecture running at 266/400/500MHz + with many integrated peripherals. Further information can be + found at their website, . Say Y here if you wish to build a kernel for this platform. config MIPS_PB1000 @@ -1091,7 +1091,6 @@ endmenu - menu "CPU selection" choice @@ -1194,7 +1193,7 @@ This option select the standard 4kB Linux page size. On some R3000-family processors this is the only available page size. Using 4kB page size will minimize memory consumption and is therefore - recommended for low memory systems. + recommended for low memory systems. config PAGE_SIZE_8KB bool "8kB" @@ -1382,21 +1381,6 @@ This allows applications to run more reliably even when the system is under load. -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -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 RTC_DS1742 bool "DS1742 BRAM/RTC support" depends on TOSHIBA_JMR3927 || TOSHIBA_RBTX4927 @@ -1562,7 +1546,7 @@ default "ramdisk.gz" help This is the filename of the ramdisk image to be built into the - kernel. Relative pathnames are relative to arch/mips/ramdisk/. + kernel. Relative pathnames are relative to arch/mips/ramdisk/. The ramdisk image is not part of the kernel distribution; you must provide one yourself. @@ -1572,119 +1556,7 @@ source "fs/Kconfig" -menu "Kernel hacking" - -config CROSSCOMPILE - bool "Are you using a crosscompiler" - help - Say Y here if you are compiling the kernel on a different - architecture than the one it is intended to run on. - -config CMDLINE - string "Default kernel command string" - default "" - help - On some platforms, there is currently no way for the boot loader to - pass arguments to the kernel. For these platforms, you can supply - some command-line options at build time by entering them here. In - other cases you can specify kernel args so that you don't have - to set them up in board prom initialization routines. - -config DEBUG_KERNEL - bool "Kernel debugging" - -config DEBUG_STACK_USAGE - bool "Enable stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config KGDB - bool "Remote GDB kernel debugging" - depends on DEBUG_KERNEL - select DEBUG_INFO - help - If you say Y here, it will be possible to remotely debug the MIPS - kernel using gdb. This enlarges your kernel image disk size by - several megabytes and requires a machine with more than 16 MB, - better 32 MB RAM to avoid excessive linking time. This is only - useful for kernel hackers. If unsure, say N. - -config GDB_CONSOLE - bool "Console output to GDB" - depends on KGDB - help - If you are using GDB for remote debugging over a serial port and - would like kernel messages to be formatted into GDB $O packets so - that GDB prints them as program output, say 'Y'. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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 SB1XXX_CORELIS - bool "Corelis Debugger" - depends on SIBYTE_SB1xxx_SOC - select DEBUG_INFO - help - Select compile flags that produce code that can be processed by the - Corelis mksym utility and UDB Emulator. - -config RUNTIME_DEBUG - bool "Enable run-time debugging" - depends on DEBUG_KERNEL - help - If you say Y here, some debugging macros will do run-time checking. - If you say N here, those macros will mostly turn to no-ops. See - include/asm-mips/debug.h for debuging macros. - If unsure, say N. - - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config MIPS_UNCACHED - bool "Run uncached" - depends on DEBUG_KERNEL && !SMP && !SGI_IP27 - help - If you say Y here there kernel will disable all CPU caches. This will - reduce the system's performance dramatically but can help finding - otherwise hard to track bugs. It can also useful if you're doing - hardware debugging with a logic analyzer and need to see all traffic - on the bus. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - -endmenu +source "arch/mips/Kconfig.debug" source "security/Kconfig" diff -Nru a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/mips/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,76 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config CROSSCOMPILE + bool "Are you using a crosscompiler" + help + Say Y here if you are compiling the kernel on a different + architecture than the one it is intended to run on. + +config CMDLINE + string "Default kernel command string" + default "" + help + On some platforms, there is currently no way for the boot loader to + pass arguments to the kernel. For these platforms, you can supply + some command-line options at build time by entering them here. In + other cases you can specify kernel args so that you don't have + to set them up in board prom initialization routines. + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config KGDB + bool "Remote GDB kernel debugging" + depends on DEBUG_KERNEL + select DEBUG_INFO + help + If you say Y here, it will be possible to remotely debug the MIPS + kernel using gdb. This enlarges your kernel image disk size by + several megabytes and requires a machine with more than 16 MB, + better 32 MB RAM to avoid excessive linking time. This is only + useful for kernel hackers. If unsure, say N. + +config GDB_CONSOLE + bool "Console output to GDB" + depends on KGDB + help + If you are using GDB for remote debugging over a serial port and + would like kernel messages to be formatted into GDB $O packets so + that GDB prints them as program output, say 'Y'. + +config SB1XXX_CORELIS + bool "Corelis Debugger" + depends on SIBYTE_SB1xxx_SOC + select DEBUG_INFO + help + Select compile flags that produce code that can be processed by the + Corelis mksym utility and UDB Emulator. + +config RUNTIME_DEBUG + bool "Enable run-time debugging" + depends on DEBUG_KERNEL + help + If you say Y here, some debugging macros will do run-time checking. + If you say N here, those macros will mostly turn to no-ops. See + include/asm-mips/debug.h for debuging macros. + If unsure, say N. + +config MIPS_UNCACHED + bool "Run uncached" + depends on DEBUG_KERNEL && !SMP && !SGI_IP27 + help + If you say Y here there kernel will disable all CPU caches. This will + reduce the system's performance dramatically but can help finding + otherwise hard to track bugs. It can also useful if you're doing + hardware debugging with a logic analyzer and need to see all traffic + on the bus. + +endmenu diff -Nru a/arch/mips/Makefile b/arch/mips/Makefile --- a/arch/mips/Makefile 2004-10-18 14:55:54 -07:00 +++ b/arch/mips/Makefile 2004-10-18 14:55:54 -07:00 @@ -56,14 +56,12 @@ # cflags-y := -I $(TOPDIR)/include/asm/gcc cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -cflags-y += $(call check_gcc, -finline-limit=100000,) +cflags-y += $(call cc-option, -finline-limit=100000) LDFLAGS_vmlinux += -G 0 -static -n MODFLAGS += -mlong-calls cflags-$(CONFIG_SB1XXX_CORELIS) += -mno-sched-prolog -fno-omit-frame-pointer -check_warning = $(shell if $(CC) $(1) -c -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) - # # Use: $(call set_gccflags,,,,,) # @@ -162,7 +160,7 @@ cflags-$(CONFIG_CPU_NEVADA) += \ $(call set_gccflags,rm5200,mips4,r5000,mips4,mips2) \ -Wa,--trap -# $(call check_gcc,-mmad,) +# $(call cc-option,-mmad) cflags-$(CONFIG_CPU_RM7000) += \ $(call set_gccflags,rm7000,mips4,r5000,mips4,mips2) \ @@ -643,7 +641,7 @@ # none has been choosen above. # -AFLAGS_vmlinux.lds.o := \ +CPPFLAGS_vmlinux.lds := \ -D"LOADADDR=$(load-y)" \ -D"JIFFIES=$(JIFFIES)" \ -imacros $(srctree)/include/asm-$(ARCH)/sn/mapped_kernel.h diff -Nru a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c --- a/arch/mips/au1000/common/time.c 2004-10-18 14:56:28 -07:00 +++ b/arch/mips/au1000/common/time.c 2004-10-18 14:56:28 -07:00 @@ -38,11 +38,11 @@ #include #include #include +#include #include #include #include -#include #include #include diff -Nru a/arch/mips/baget/irq.c b/arch/mips/baget/irq.c --- a/arch/mips/baget/irq.c 2004-10-18 14:56:48 -07:00 +++ b/arch/mips/baget/irq.c 2004-10-18 14:56:48 -07:00 @@ -180,7 +180,7 @@ static void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction *action; - int do_random, cpu; + int ret, do_random, cpu; cpu = smp_processor_id(); irq_enter(); @@ -194,8 +194,9 @@ action = *(irq + irq_action); do_random = 0; do { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + do_random |= action->flags; action = action->next; } while (action); if (do_random & SA_SAMPLE_RANDOM) diff -Nru a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig --- a/arch/mips/configs/jaguar-atx_defconfig 2004-10-18 14:57:03 -07:00 +++ b/arch/mips/configs/jaguar-atx_defconfig 2004-10-18 14:57:03 -07:00 @@ -306,10 +306,10 @@ # CONFIG_R8169 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set -CONFIG_MV64340_ETH=y -CONFIG_MV64340_ETH_0=y -CONFIG_MV64340_ETH_1=y -CONFIG_MV64340_ETH_2=y +CONFIG_MV643XX_ETH=y +CONFIG_MV643XX_ETH_0=y +CONFIG_MV643XX_ETH_1=y +CONFIG_MV643XX_ETH_2=y # # Ethernet (10000 Mbit) diff -Nru a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig --- a/arch/mips/configs/ocelot_c_defconfig 2004-10-18 14:56:17 -07:00 +++ b/arch/mips/configs/ocelot_c_defconfig 2004-10-18 14:56:17 -07:00 @@ -303,7 +303,7 @@ # CONFIG_R8169 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set -# CONFIG_MV64340_ETH is not set +# CONFIG_MV643XX_ETH is not set # # Ethernet (10000 Mbit) diff -Nru a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig --- a/arch/mips/configs/tb0226_defconfig 2004-10-18 14:56:33 -07:00 +++ b/arch/mips/configs/tb0226_defconfig 2004-10-18 14:56:33 -07:00 @@ -272,7 +272,6 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_NAT=y CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_TOS=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y # CONFIG_IP_PNP_DHCP is not set diff -Nru a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig --- a/arch/mips/configs/tb0229_defconfig 2004-10-18 14:57:04 -07:00 +++ b/arch/mips/configs/tb0229_defconfig 2004-10-18 14:57:04 -07:00 @@ -229,7 +229,6 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_NAT=y CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_TOS=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y # CONFIG_IP_PNP_DHCP is not set diff -Nru a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile --- a/arch/mips/kernel/Makefile 2004-10-18 14:56:29 -07:00 +++ b/arch/mips/kernel/Makefile 2004-10-18 14:56:29 -07:00 @@ -2,7 +2,7 @@ # Makefile for the Linux/MIPS kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \ diff -Nru a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c --- a/arch/mips/kernel/irixsig.c 2004-10-18 14:56:50 -07:00 +++ b/arch/mips/kernel/irixsig.c 2004-10-18 14:56:50 -07:00 @@ -121,9 +121,7 @@ return; segv_and_exit: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); } static void inline diff -Nru a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c --- a/arch/mips/kernel/irq.c 2004-10-18 14:55:55 -07:00 +++ b/arch/mips/kernel/irq.c 2004-10-18 14:55:55 -07:00 @@ -144,14 +144,16 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -872,30 +874,6 @@ #endif -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data, new_value; - unsigned long full_count = count, err; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -931,26 +909,15 @@ #endif } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff -Nru a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c --- a/arch/mips/kernel/mips_ksyms.c 2004-10-18 14:56:17 -07:00 +++ b/arch/mips/kernel/mips_ksyms.c 2004-10-18 14:56:17 -07:00 @@ -26,36 +26,36 @@ /* * String functions */ -EXPORT_SYMBOL_NOVERS(memchr); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(strcat); -EXPORT_SYMBOL_NOVERS(strchr); +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strchr); #ifdef CONFIG_MIPS64 -EXPORT_SYMBOL_NOVERS(strncmp); +EXPORT_SYMBOL(strncmp); #endif -EXPORT_SYMBOL_NOVERS(strlen); -EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(strncat); -EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strstr); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(kernel_thread); /* * Userspace access stuff. */ -EXPORT_SYMBOL_NOVERS(__copy_user); -EXPORT_SYMBOL_NOVERS(__bzero); -EXPORT_SYMBOL_NOVERS(__strncpy_from_user_nocheck_asm); -EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm); -EXPORT_SYMBOL_NOVERS(__strlen_user_nocheck_asm); -EXPORT_SYMBOL_NOVERS(__strlen_user_asm); -EXPORT_SYMBOL_NOVERS(__strnlen_user_nocheck_asm); -EXPORT_SYMBOL_NOVERS(__strnlen_user_asm); +EXPORT_SYMBOL(__copy_user); +EXPORT_SYMBOL(__bzero); +EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm); +EXPORT_SYMBOL(__strncpy_from_user_asm); +EXPORT_SYMBOL(__strlen_user_nocheck_asm); +EXPORT_SYMBOL(__strlen_user_asm); +EXPORT_SYMBOL(__strnlen_user_nocheck_asm); +EXPORT_SYMBOL(__strnlen_user_asm); EXPORT_SYMBOL(csum_partial); diff -Nru a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c --- a/arch/mips/kernel/signal.c 2004-10-18 14:56:49 -07:00 +++ b/arch/mips/kernel/signal.c 2004-10-18 14:56:49 -07:00 @@ -406,9 +406,7 @@ return; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); } #endif @@ -475,19 +473,15 @@ return; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); } extern void setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); static inline void handle_signal(unsigned long sig, siginfo_t *info, - sigset_t *oldset, struct pt_regs *regs) + struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - switch(regs->regs[0]) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND: @@ -539,6 +533,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) { + struct k_sigaction ka; siginfo_t info; int signr; @@ -564,9 +559,9 @@ if (!oldset) oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - handle_signal(signr, &info, oldset, regs); + handle_signal(signr, &info, &ka, oldset, regs); return 1; } diff -Nru a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c --- a/arch/mips/kernel/signal32.c 2004-10-18 14:56:32 -07:00 +++ b/arch/mips/kernel/signal32.c 2004-10-18 14:56:32 -07:00 @@ -574,9 +574,7 @@ return; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); } static inline void setup_rt_frame(struct k_sigaction * ka, @@ -647,9 +645,7 @@ return; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); } static inline void handle_signal(unsigned long sig, siginfo_t *info, diff -Nru a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c --- a/arch/mips/kernel/signal_n32.c 2004-10-18 14:56:33 -07:00 +++ b/arch/mips/kernel/signal_n32.c 2004-10-18 14:56:33 -07:00 @@ -208,7 +208,5 @@ return; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); } diff -Nru a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c --- a/arch/mips/kernel/smp.c 2004-10-18 14:56:16 -07:00 +++ b/arch/mips/kernel/smp.c 2004-10-18 14:56:16 -07:00 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -254,16 +253,6 @@ cpu_set(0, cpu_callin_map); } -static struct task_struct * __init fork_by_hand(void) -{ - struct pt_regs regs; - /* - * don't care about the eip and regs settings since - * we'll never reschedule the forked task. - */ - return copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); -} - /* * Startup the CPU with this logical number */ @@ -275,19 +264,9 @@ * The following code is purely to make sure * Linux can schedule processes on this slave. */ - idle = fork_by_hand(); + idle = fork_idle(cpu); if (IS_ERR(idle)) panic("failed fork for CPU %d\n", cpu); - - wake_up_forked_process(idle); - - /* - * We remove it from the pidhash and the runqueue once we've - * got the process: - */ - init_idle(idle, cpu); - - unhash_process(idle); prom_boot_secondary(cpu, idle); diff -Nru a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c --- a/arch/mips/kernel/syscall.c 2004-10-18 14:56:49 -07:00 +++ b/arch/mips/kernel/syscall.c 2004-10-18 14:56:49 -07:00 @@ -180,7 +180,7 @@ newsp = regs.regs[29]; parent_tidptr = (int *) regs.regs[6]; child_tidptr = (int *) regs.regs[7]; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } diff -Nru a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c --- a/arch/mips/kernel/sysirix.c 2004-10-18 14:57:03 -07:00 +++ b/arch/mips/kernel/sysirix.c 2004-10-18 14:57:03 -07:00 @@ -810,8 +810,8 @@ return err; err |= __put_user(current->utime, &tbuf->tms_utime); err |= __put_user(current->stime, &tbuf->tms_stime); - err |= __put_user(current->cutime, &tbuf->tms_cutime); - err |= __put_user(current->cstime, &tbuf->tms_cstime); + err |= __put_user(current->signal->cutime, &tbuf->tms_cutime); + err |= __put_user(current->signal->cstime, &tbuf->tms_cstime); } return err; diff -Nru a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c --- a/arch/mips/kernel/time.c 2004-10-18 14:56:29 -07:00 +++ b/arch/mips/kernel/time.c 2004-10-18 14:56:29 -07:00 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -417,23 +416,8 @@ */ void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - if (!user_mode(regs)) { - if (prof_buffer && current->pid) { - unsigned long pc = regs->cp0_epc; - - pc -= (unsigned long) _stext; - pc >>= prof_shift; - /* - * Dont ignore out-of-bounds pc values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } - } - + if (current->pid) + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_SMP /* in UP mode, update_process_times() is invoked by do_timer() */ update_process_times(user_mode(regs)); diff -Nru a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S --- a/arch/mips/kernel/vmlinux.lds.S 2004-10-18 14:56:28 -07:00 +++ b/arch/mips/kernel/vmlinux.lds.S 2004-10-18 14:56:28 -07:00 @@ -29,6 +29,7 @@ .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } =0 @@ -96,9 +97,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; .early_initcall.init : { __earlyinitcall_start = .; diff -Nru a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c --- a/arch/mips/mips-boards/generic/time.c 2004-10-18 14:56:33 -07:00 +++ b/arch/mips/mips-boards/generic/time.c 2004-10-18 14:56:33 -07:00 @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff -Nru a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c --- a/arch/mips/mm/fault.c 2004-10-18 14:56:27 -07:00 +++ b/arch/mips/mm/fault.c 2004-10-18 14:56:27 -07:00 @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff -Nru a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c --- a/arch/mips/momentum/jaguar_atx/prom.c 2004-10-18 14:57:19 -07:00 +++ b/arch/mips/momentum/jaguar_atx/prom.c 2004-10-18 14:57:19 -07:00 @@ -40,7 +40,7 @@ return "Momentum Jaguar-ATX"; } -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH extern unsigned char prom_mac_addr_base[6]; static void burn_clocks(void) @@ -230,7 +230,7 @@ mips_machgroup = MACH_GROUP_MOMENCO; mips_machtype = MACH_MOMENCO_JAGUAR_ATX; -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH /* get the base MAC address for on-board ethernet ports */ get_mac(prom_mac_addr_base); #endif diff -Nru a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c --- a/arch/mips/momentum/ocelot_c/prom.c 2004-10-18 14:56:32 -07:00 +++ b/arch/mips/momentum/ocelot_c/prom.c 2004-10-18 14:56:32 -07:00 @@ -32,7 +32,7 @@ extern unsigned long marvell_base; extern unsigned long cpu_clock; -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH extern unsigned char prom_mac_addr_base[6]; #endif @@ -45,7 +45,7 @@ #endif } -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH static void burn_clocks(void) { int i; @@ -227,7 +227,7 @@ mips_machgroup = MACH_GROUP_MOMENCO; mips_machtype = MACH_MOMENCO_OCELOT_C; -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH /* get the base MAC address for on-board ethernet ports */ get_mac(prom_mac_addr_base); #endif diff -Nru a/arch/mips/pci/fixup-atlas.c b/arch/mips/pci/fixup-atlas.c --- a/arch/mips/pci/fixup-atlas.c 2004-10-18 14:55:53 -07:00 +++ b/arch/mips/pci/fixup-atlas.c 2004-10-18 14:55:53 -07:00 @@ -60,13 +60,7 @@ printk ("saa9730_base = %x\n", saa9730_base); } -#endif - +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, + atlas_saa9730_base_fixup); -struct pci_fixup pcibios_fixups[] __initdata = { -#ifdef CONFIG_KGDB - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, - atlas_saa9730_base_fixup}, #endif - { 0 } -}; diff -Nru a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c --- a/arch/mips/pci/fixup-au1000.c 2004-10-18 14:55:54 -07:00 +++ b/arch/mips/pci/fixup-au1000.c 2004-10-18 14:55:54 -07:00 @@ -102,7 +102,3 @@ { return irq_tab_alchemy[slot][pin]; } - -struct pci_fixup pcibios_fixups[] __initdata = { -{ 0 } -}; diff -Nru a/arch/mips/pci/fixup-capcella.c b/arch/mips/pci/fixup-capcella.c --- a/arch/mips/pci/fixup-capcella.c 2004-10-18 14:56:28 -07:00 +++ b/arch/mips/pci/fixup-capcella.c 2004-10-18 14:56:28 -07:00 @@ -42,7 +42,3 @@ { return irq_tab_capcella[slot][pin]; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff -Nru a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c --- a/arch/mips/pci/fixup-cobalt.c 2004-10-18 14:56:29 -07:00 +++ b/arch/mips/pci/fixup-cobalt.c 2004-10-18 14:56:29 -07:00 @@ -41,6 +41,9 @@ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 7); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, + qube_raq_via_bmIDE_fixup); + static void qube_raq_galileo_fixup(struct pci_dev *dev) { unsigned short galileo_id; @@ -73,13 +76,8 @@ } } -struct pci_fixup pcibios_fixups[] __initdata = { - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, - qube_raq_via_bmIDE_fixup}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_GALILEO, PCI_ANY_ID, - qube_raq_galileo_fixup}, - 0 -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_GALILEO, PCI_ANY_ID, + qube_raq_galileo_fixup); static char irq_tab_cobalt[] __initdata = { [COBALT_PCICONF_CPU] = 0, diff -Nru a/arch/mips/pci/fixup-ddb5074.c b/arch/mips/pci/fixup-ddb5074.c --- a/arch/mips/pci/fixup-ddb5074.c 2004-10-18 14:56:13 -07:00 +++ b/arch/mips/pci/fixup-ddb5074.c 2004-10-18 14:56:13 -07:00 @@ -17,8 +17,5 @@ pci_write_config_byte(dev, 0x7e, t8); } -struct pci_fixup pcibios_fixups[] __initdata = { - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, - ddb5074_fixup }, - {0} -}; +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + ddb5074_fixup); diff -Nru a/arch/mips/pci/fixup-ddb5477.c b/arch/mips/pci/fixup-ddb5477.c --- a/arch/mips/pci/fixup-ddb5477.c 2004-10-18 14:56:32 -07:00 +++ b/arch/mips/pci/fixup-ddb5477.c 2004-10-18 14:56:32 -07:00 @@ -41,6 +41,11 @@ pci_write_config_byte(dev, 0x41, old | 0xd0); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + ddb5477_fixup); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1535, + ddb5477_fixup); + /* * Fixup baseboard AMD chip so that tx does not underflow. * bcr_18 |= 0x0800 @@ -69,12 +74,5 @@ outw(temp, ioaddr + PCNET32_WIO_BDP); } -struct pci_fixup pcibios_fixups[] __initdata = { - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, - ddb5477_fixup }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1535, - ddb5477_fixup }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, - ddb5477_amd_lance_fixup }, - {0} -}; +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, + ddb5477_amd_lance_fixup); diff -Nru a/arch/mips/pci/fixup-ip32.c b/arch/mips/pci/fixup-ip32.c --- a/arch/mips/pci/fixup-ip32.c 2004-10-18 14:57:03 -07:00 +++ b/arch/mips/pci/fixup-ip32.c 2004-10-18 14:57:03 -07:00 @@ -44,7 +44,3 @@ { return irq_tab_mace[slot][pin]; } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff -Nru a/arch/mips/pci/fixup-jaguar.c b/arch/mips/pci/fixup-jaguar.c --- a/arch/mips/pci/fixup-jaguar.c 2004-10-18 14:57:18 -07:00 +++ b/arch/mips/pci/fixup-jaguar.c 2004-10-18 14:57:18 -07:00 @@ -36,7 +36,3 @@ return 0; panic("Whooops in pcibios_map_irq"); } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff -Nru a/arch/mips/pci/fixup-lasat.c b/arch/mips/pci/fixup-lasat.c --- a/arch/mips/pci/fixup-lasat.c 2004-10-18 14:56:32 -07:00 +++ b/arch/mips/pci/fixup-lasat.c 2004-10-18 14:56:32 -07:00 @@ -4,7 +4,3 @@ void __init pcibios_fixup_irqs(void) { } - -struct pci_fixup pcibios_fixups[] __initdata = { - { 0 } -}; diff -Nru a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c --- a/arch/mips/pci/fixup-malta.c 2004-10-18 14:55:54 -07:00 +++ b/arch/mips/pci/fixup-malta.c 2004-10-18 14:55:54 -07:00 @@ -79,6 +79,8 @@ } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, + malta_piix_func0_fixup); static void __init malta_piix_func1_fixup(struct pci_dev *pdev) { @@ -96,10 +98,5 @@ } } -struct pci_fixup pcibios_fixups[] __initdata = { - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, - malta_piix_func0_fixup}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, - malta_piix_func1_fixup}, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, + malta_piix_func1_fixup); diff -Nru a/arch/mips/pci/fixup-mpc30x.c b/arch/mips/pci/fixup-mpc30x.c --- a/arch/mips/pci/fixup-mpc30x.c 2004-10-18 14:56:32 -07:00 +++ b/arch/mips/pci/fixup-mpc30x.c 2004-10-18 14:56:32 -07:00 @@ -42,7 +42,3 @@ return irq_tab_mpc30x[slot]; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff -Nru a/arch/mips/pci/fixup-ocelot-c.c b/arch/mips/pci/fixup-ocelot-c.c --- a/arch/mips/pci/fixup-ocelot-c.c 2004-10-18 14:57:19 -07:00 +++ b/arch/mips/pci/fixup-ocelot-c.c 2004-10-18 14:57:19 -07:00 @@ -33,7 +33,3 @@ return 0; panic("Whooops in pcibios_map_irq"); } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff -Nru a/arch/mips/pci/fixup-ocelot-g.c b/arch/mips/pci/fixup-ocelot-g.c --- a/arch/mips/pci/fixup-ocelot-g.c 2004-10-18 14:56:29 -07:00 +++ b/arch/mips/pci/fixup-ocelot-g.c 2004-10-18 14:56:29 -07:00 @@ -29,7 +29,3 @@ return -1; } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff -Nru a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c --- a/arch/mips/pci/fixup-sni.c 2004-10-18 14:56:27 -07:00 +++ b/arch/mips/pci/fixup-sni.c 2004-10-18 14:56:27 -07:00 @@ -82,7 +82,3 @@ return irq_tab_rm200[slot][pin]; } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff -Nru a/arch/mips/pci/fixup-tb0219.c b/arch/mips/pci/fixup-tb0219.c --- a/arch/mips/pci/fixup-tb0219.c 2004-10-18 14:57:03 -07:00 +++ b/arch/mips/pci/fixup-tb0219.c 2004-10-18 14:57:03 -07:00 @@ -58,7 +58,3 @@ return irq; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff -Nru a/arch/mips/pci/fixup-tb0226.c b/arch/mips/pci/fixup-tb0226.c --- a/arch/mips/pci/fixup-tb0226.c 2004-10-18 14:56:49 -07:00 +++ b/arch/mips/pci/fixup-tb0226.c 2004-10-18 14:56:49 -07:00 @@ -77,7 +77,3 @@ return irq; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff -Nru a/arch/mips/pci/fixup-yosemite.c b/arch/mips/pci/fixup-yosemite.c --- a/arch/mips/pci/fixup-yosemite.c 2004-10-18 14:56:29 -07:00 +++ b/arch/mips/pci/fixup-yosemite.c 2004-10-18 14:56:29 -07:00 @@ -33,7 +33,3 @@ return 3; /* Everything goes to one irq bit */ } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff -Nru a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c --- a/arch/mips/pci/pci-ip27.c 2004-10-18 14:57:04 -07:00 +++ b/arch/mips/pci/pci-ip27.c 2004-10-18 14:57:04 -07:00 @@ -329,6 +329,9 @@ pci_disable_swapping(d); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, + pci_fixup_ioc3); + static void __init pci_fixup_isp1020(struct pci_dev *d) { struct bridge_controller *bc = BRIDGE_CONTROLLER(d->bus); @@ -353,6 +356,9 @@ pci_enable_swapping(d); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, + pci_fixup_isp1020); + static void __init pci_fixup_isp2x00(struct pci_dev *d) { struct bridge_controller *bc = BRIDGE_CONTROLLER(d->bus); @@ -427,14 +433,7 @@ /*d->resource[1].flags |= 1; */ } -struct pci_fixup pcibios_fixups[] = { - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, - pci_fixup_ioc3}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, - pci_fixup_isp1020}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100, - pci_fixup_isp2x00}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200, - pci_fixup_isp2x00}, - {0} -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100, + pci_fixup_isp2x00); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200, + pci_fixup_isp2x00); diff -Nru a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c --- a/arch/mips/pci/pci-sb1250.c 2004-10-18 14:56:17 -07:00 +++ b/arch/mips/pci/pci-sb1250.c 2004-10-18 14:56:17 -07:00 @@ -279,7 +279,3 @@ return 0; } arch_initcall(sb1250_pcibios_init); - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff -Nru a/arch/mips/pmc-sierra/yosemite/ht.c b/arch/mips/pmc-sierra/yosemite/ht.c --- a/arch/mips/pmc-sierra/yosemite/ht.c 2004-10-18 14:56:28 -07:00 +++ b/arch/mips/pmc-sierra/yosemite/ht.c 2004-10-18 14:56:28 -07:00 @@ -414,11 +414,6 @@ titan_ht_config_write_dword }; - -struct pci_fixup pcibios_fixups[] = { - {0} -}; - void __init pcibios_fixup_bus(struct pci_bus *c) { titan_ht_pcibios_fixup_bus(c); diff -Nru a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c --- a/arch/mips/sgi-ip27/ip27-memory.c 2004-10-18 14:56:27 -07:00 +++ b/arch/mips/sgi-ip27/ip27-memory.c 2004-10-18 14:56:27 -07:00 @@ -225,7 +225,7 @@ pfn_t end_pfn = node_getmaxclick(node) + 1; zones_size[ZONE_DMA] = end_pfn - start_pfn; - free_area_init_node(node, NODE_DATA(node), NULL, + free_area_init_node(node, NODE_DATA(node), zones_size, start_pfn, NULL); if (end_pfn > max_low_pfn) diff -Nru a/arch/mips/vr41xx/common/giu.c b/arch/mips/vr41xx/common/giu.c --- a/arch/mips/vr41xx/common/giu.c 2004-10-18 14:55:54 -07:00 +++ b/arch/mips/vr41xx/common/giu.c 2004-10-18 14:55:54 -07:00 @@ -63,6 +63,12 @@ static uint32_t giu_base; +static struct irqaction giu_cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + #define read_giuint(offset) readw(giu_base + (offset)) #define write_giuint(val, offset) writew((val), giu_base + (offset)) @@ -303,7 +309,6 @@ }; static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS]; -static struct irqaction giu_cascade = {no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL}; static int no_irq_number(int irq) { diff -Nru a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c --- a/arch/mips/vr41xx/common/icu.c 2004-10-18 14:55:54 -07:00 +++ b/arch/mips/vr41xx/common/icu.c 2004-10-18 14:55:54 -07:00 @@ -51,6 +51,12 @@ static uint32_t icu1_base; static uint32_t icu2_base; +static struct irqaction icu_cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + static unsigned char sysint1_assign[16] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char sysint2_assign[16] = { @@ -159,218 +165,268 @@ { irq_desc_t *desc = irq_desc + PIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MPIUINTREG); - val |= mask; - write_icu1(val, MPIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_piuint); + void vr41xx_disable_piuint(uint16_t mask) { irq_desc_t *desc = irq_desc + PIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MPIUINTREG); - val &= ~mask; - write_icu1(val, MPIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_piuint); + void vr41xx_enable_aiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + AIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MAIUINTREG); - val |= mask; - write_icu1(val, MAIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_aiuint); + void vr41xx_disable_aiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + AIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MAIUINTREG); - val &= ~mask; - write_icu1(val, MAIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_aiuint); + void vr41xx_enable_kiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + KIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MKIUINTREG); - val |= mask; - write_icu1(val, MKIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_kiuint); + void vr41xx_disable_kiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + KIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MKIUINTREG); - val &= ~mask; - write_icu1(val, MKIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_kiuint); + void vr41xx_enable_dsiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + DSIU_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MDSIUINTREG); - val |= mask; - write_icu1(val, MDSIUINTREG); + set_icu1(MDSIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_enable_dsiuint); + void vr41xx_disable_dsiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + DSIU_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MDSIUINTREG); - val &= ~mask; - write_icu1(val, MDSIUINTREG); + clear_icu1(MDSIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_disable_dsiuint); + void vr41xx_enable_firint(uint16_t mask) { irq_desc_t *desc = irq_desc + FIR_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MFIRINTREG); - val |= mask; - write_icu2(val, MFIRINTREG); + set_icu2(MFIRINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_enable_firint); + void vr41xx_disable_firint(uint16_t mask) { irq_desc_t *desc = irq_desc + FIR_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MFIRINTREG); - val &= ~mask; - write_icu2(val, MFIRINTREG); + clear_icu2(MFIRINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_disable_firint); + void vr41xx_enable_pciint(void) { irq_desc_t *desc = irq_desc + PCI_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(PCIINT0, MPCIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(PCIINT0, MPCIINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_pciint); + void vr41xx_disable_pciint(void) { irq_desc_t *desc = irq_desc + PCI_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(0, MPCIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MPCIINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_pciint); + void vr41xx_enable_scuint(void) { irq_desc_t *desc = irq_desc + SCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(SCUINT0, MSCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(SCUINT0, MSCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_scuint); + void vr41xx_disable_scuint(void) { irq_desc_t *desc = irq_desc + SCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(0, MSCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MSCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_scuint); + void vr41xx_enable_csiint(uint16_t mask) { irq_desc_t *desc = irq_desc + CSI_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MCSIINTREG); - val |= mask; - write_icu2(val, MCSIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + set_icu2(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_csiint); + void vr41xx_disable_csiint(uint16_t mask) { irq_desc_t *desc = irq_desc + CSI_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MCSIINTREG); - val &= ~mask; - write_icu2(val, MCSIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu2(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_csiint); + void vr41xx_enable_bcuint(void) { irq_desc_t *desc = irq_desc + BCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(BCUINTR, MBCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(BCUINTR, MBCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_bcuint); + void vr41xx_disable_bcuint(void) { irq_desc_t *desc = irq_desc + BCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(0, MBCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MBCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_bcuint); + /*=======================================================================*/ static unsigned int startup_sysint1_irq(unsigned int irq) @@ -673,8 +729,6 @@ early_initcall(vr41xx_icu_init); /*=======================================================================*/ - -static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL}; static inline void init_vr41xx_icu_irq(void) { diff -Nru a/arch/mips/vr41xx/common/serial.c b/arch/mips/vr41xx/common/serial.c --- a/arch/mips/vr41xx/common/serial.c 2004-10-18 14:56:28 -07:00 +++ b/arch/mips/vr41xx/common/serial.c 2004-10-18 14:56:28 -07:00 @@ -115,7 +115,7 @@ port.line = vr41xx_serial_ports; port.uartclk = SIU_BASE_BAUD * 16; port.irq = SIU_IRQ; - port.flags = UPF_RESOURCES | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; switch (current_cpu_data.cputype) { case CPU_VR4111: case CPU_VR4121: @@ -160,7 +160,7 @@ port.line = vr41xx_serial_ports; port.uartclk = DSIU_BASE_BAUD * 16; port.irq = DSIU_IRQ; - port.flags = UPF_RESOURCES | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.mapbase = DSIU_BASE; port.regshift = 0; port.iotype = UPIO_MEM; diff -Nru a/arch/mips/vr41xx/common/vrc4173.c b/arch/mips/vr41xx/common/vrc4173.c --- a/arch/mips/vr41xx/common/vrc4173.c 2004-10-18 14:56:48 -07:00 +++ b/arch/mips/vr41xx/common/vrc4173.c 2004-10-18 14:56:48 -07:00 @@ -316,6 +316,96 @@ spin_lock_init(&vrc4173_giu_lock); } +void vrc4173_enable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MPIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MPIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_eanble_piuint); + +void vrc4173_disable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MPIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MPIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_piuint); + +void vrc4173_enable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MAIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MAIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_enable_aiuint); + +void vrc4173_disable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MAIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MAIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_aiuint); + +void vrc4173_enable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MKIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MKIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_enable_kiuint); + +void vrc4173_disable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MKIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MKIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_kiuint); + static void enable_vrc4173_irq(unsigned int irq) { uint16_t val; diff -Nru a/arch/parisc/Kconfig b/arch/parisc/Kconfig --- a/arch/parisc/Kconfig 2004-10-18 14:56:33 -07:00 +++ b/arch/parisc/Kconfig 2004-10-18 14:56:33 -07:00 @@ -106,7 +106,7 @@ depends on PA8X00 help Enable this if you want to support 64bit kernel on PA-RISC platform. - + At the moment, only people willing to use more than 2GB of RAM, or having a 64bit-only capable PA-RISC machine should say Y here. @@ -188,76 +188,10 @@ source "arch/parisc/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_RWLOCK - bool "Read-write spinlock debugging" - depends on DEBUG_KERNEL && SMP - help - If you say Y here then read-write lock processing will count how many - times it has tried to get the lock and issue an error message after - too many attempts. If you suspect a rwlock problem or a kernel - hacker asks for this option then say Y. Otherwise say N. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - 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 DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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. - -endmenu +source "arch/parisc/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/parisc/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,14 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_RWLOCK + bool "Read-write spinlock debugging" + depends on DEBUG_KERNEL && SMP + help + If you say Y here then read-write lock processing will count how many + times it has tried to get the lock and issue an error message after + too many attempts. If you suspect a rwlock problem or a kernel + hacker asks for this option then say Y. Otherwise say N. + +endmenu diff -Nru a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile --- a/arch/parisc/kernel/Makefile 2004-10-18 14:56:28 -07:00 +++ b/arch/parisc/kernel/Makefile 2004-10-18 14:56:28 -07:00 @@ -4,7 +4,7 @@ head-y := head.o head-$(CONFIG_PARISC64) := head64.o -extra-y := init_task.o $(head-y) vmlinux.lds.s +extra-y := init_task.o $(head-y) vmlinux.lds AFLAGS_entry.o := -traditional AFLAGS_pacache.o := -traditional diff -Nru a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c --- a/arch/parisc/kernel/asm-offsets.c 2004-10-18 14:55:55 -07:00 +++ b/arch/parisc/kernel/asm-offsets.c 2004-10-18 14:55:55 -07:00 @@ -32,11 +32,11 @@ #include #include #include -#include +#include +#include #include #include -#include #include #define DEFINE(sym, val) \ diff -Nru a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c --- a/arch/parisc/kernel/cache.c 2004-10-18 14:56:29 -07:00 +++ b/arch/parisc/kernel/cache.c 2004-10-18 14:56:29 -07:00 @@ -245,7 +245,7 @@ void flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); - struct vm_area_struct *mpnt = NULL; + struct vm_area_struct *mpnt; struct prio_tree_iter iter; unsigned long offset; unsigned long addr; @@ -272,8 +272,7 @@ * to flush one address here for them all to become coherent */ flush_dcache_mmap_lock(mapping); - while ((mpnt = vma_prio_tree_next(mpnt, &mapping->i_mmap, - &iter, pgoff, pgoff)) != NULL) { + vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; addr = mpnt->vm_start + offset; diff -Nru a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c --- a/arch/parisc/kernel/hardware.c 2004-10-18 14:56:29 -07:00 +++ b/arch/parisc/kernel/hardware.c 2004-10-18 14:56:29 -07:00 @@ -7,7 +7,7 @@ * Reference Specification", March 7, 1999, version 0.96. This * is available at http://parisc-linux.org/documentation/ * - * Copyright 1999 by Alex deVries + * Copyright 1999 by Alex deVries * and copyright 1999 The Puffin Group Inc. * * This program is free software; you can redistribute it and/or modify diff -Nru a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c --- a/arch/parisc/kernel/pci.c 2004-10-18 14:55:53 -07:00 +++ b/arch/parisc/kernel/pci.c 2004-10-18 14:55:53 -07:00 @@ -146,15 +146,6 @@ return str; } -/* Used in drivers/pci/quirks.c */ -struct pci_fixup pcibios_fixups[] = { -#ifdef CONFIG_SUPERIO - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci }, -#endif - { 0 } -}; - - /* * Called by pci_set_master() - a driver interface. * diff -Nru a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c --- a/arch/parisc/kernel/process.c 2004-10-18 14:57:04 -07:00 +++ b/arch/parisc/kernel/process.c 2004-10-18 14:57:04 -07:00 @@ -262,7 +262,7 @@ if(usp == 0) usp = regs->gr[30]; - return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0, user_tid, NULL); + return do_fork(clone_flags, usp, regs, 0, user_tid, NULL); } int diff -Nru a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c --- a/arch/parisc/kernel/ptrace.c 2004-10-18 14:55:55 -07:00 +++ b/arch/parisc/kernel/ptrace.c 2004-10-18 14:55:55 -07:00 @@ -404,11 +404,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - 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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c --- a/arch/parisc/kernel/smp.c 2004-10-18 14:57:04 -07:00 +++ b/arch/parisc/kernel/smp.c 2004-10-18 14:57:04 -07:00 @@ -486,24 +486,6 @@ } /* - * Create the idle task for a new Slave CPU. DO NOT use kernel_thread() - * because that could end up calling schedule(). If it did, the new idle - * task could get scheduled before we had a chance to remove it from the - * run-queue... - */ -static struct task_struct *fork_by_hand(void) -{ - struct pt_regs regs; - - /* - * don't care about the regs settings since - * we'll never reschedule the forked task. - */ - return copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); -} - - -/* * Bring one cpu online. */ int __init smp_boot_one_cpu(int cpuid) @@ -521,13 +503,10 @@ * Sheesh . . . */ - idle = fork_by_hand(); + idle = fork_idle(cpuid); if (IS_ERR(idle)) panic("SMP: fork failed for CPU:%d", cpuid); - wake_up_forked_process(idle); - init_idle(idle, cpuid); - unhash_process(idle); idle->thread_info->cpu = cpuid; /* Let _start know what logical CPU we're booting diff -Nru a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c --- a/arch/parisc/kernel/time.c 2004-10-18 14:57:19 -07:00 +++ b/arch/parisc/kernel/time.c 2004-10-18 14:57:19 -07:00 @@ -47,44 +47,6 @@ extern void smp_do_timer(struct pt_regs *regs); #endif -static inline void -parisc_do_profile(struct pt_regs *regs) -{ - unsigned long pc = regs->iaoq[0]; -#if 0 - extern unsigned long prof_cpu_mask; -#endif - extern char _stext; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - -#if 0 - /* FIXME: when we have irq affinity to cpu, we need to - * only look at the cpus specified in this mask - */ - - if (!((1 << smp_processor_id()) & prof_cpu_mask)) - return; -#endif - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { long now; @@ -92,7 +54,7 @@ int nticks; int cpu = smp_processor_id(); - parisc_do_profile(regs); + profile_tick(CPU_PROFILING, regs); now = mfctl(16); /* initialize next_tick to time at last clocktick */ diff -Nru a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S --- a/arch/parisc/kernel/vmlinux.lds.S 2004-10-18 14:56:17 -07:00 +++ b/arch/parisc/kernel/vmlinux.lds.S 2004-10-18 14:56:17 -07:00 @@ -52,6 +52,7 @@ .text ALIGN(16) : { *(.text) SCHED_TEXT + LOCK_TEXT *(.text.do_softirq) *(.text.sys_exit) *(.text.do_sigaltstack) @@ -130,9 +131,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/parisc/lib/debuglocks.c b/arch/parisc/lib/debuglocks.c --- a/arch/parisc/lib/debuglocks.c 2004-10-18 14:56:33 -07:00 +++ b/arch/parisc/lib/debuglocks.c 2004-10-18 14:56:33 -07:00 @@ -25,8 +25,8 @@ #include #include #include +#include /* in_interrupt() */ #include -#include /* in_interrupt() */ #undef INIT_STUCK #define INIT_STUCK 1L << 30 diff -Nru a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c --- a/arch/parisc/mm/init.c 2004-10-18 14:56:31 -07:00 +++ b/arch/parisc/mm/init.c 2004-10-18 14:56:31 -07:00 @@ -804,7 +804,7 @@ ZONE_DMA zone. */ zones_size[ZONE_DMA] = pmem_ranges[i].pages; - free_area_init_node(i,NODE_DATA(i),NULL,zones_size, + free_area_init_node(i, NODE_DATA(i), zones_size, pmem_ranges[i].start_pfn, 0); #ifdef CONFIG_DISCONTIGMEM diff -Nru a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c --- a/arch/ppc/8260_io/fcc_enet.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc/8260_io/fcc_enet.c 2004-10-18 14:56:29 -07:00 @@ -1986,9 +1986,9 @@ fccp = fcp->fccp; if (duplex) - fccp->fcc_fpsmr |= FCC_PSMR_FDE; + fccp->fcc_fpsmr |= FCC_PSMR_FDE | FCC_PSMR_LPB; else - fccp->fcc_fpsmr &= ~FCC_PSMR_FDE; + fccp->fcc_fpsmr &= ~(FCC_PSMR_FDE | FCC_PSMR_LPB); /* Enable transmit/receive */ fccp->fcc_gfmr |= FCC_GFMR_ENR | FCC_GFMR_ENT; diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c --- a/arch/ppc/8xx_io/uart.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/8xx_io/uart.c 2004-10-18 14:56:49 -07:00 @@ -2592,7 +2592,7 @@ state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; - printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n", + printk(KERN_INFO "ttyS%d at 0x%04x is a %s\n", i, (unsigned int)(state->port), (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC"); #ifdef CONFIG_SERIAL_CONSOLE diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig --- a/arch/ppc/Kconfig 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/Kconfig 2004-10-18 14:57:04 -07:00 @@ -49,7 +49,7 @@ There are four types of PowerPC chips supported. The more common types (601, 603, 604, 740, 750, 7400), the Motorola embedded versions (821, 823, 850, 855, 860, 52xx, 8260), the IBM embedded - versions (403 and 405) and the high end 64 bit Power processors + versions (403 and 405) and the high end 64 bit Power processors (POWER 3, POWER4, and IBM 970 also known as G5) Unless you are building a kernel for one of the embedded processor systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx. @@ -626,7 +626,7 @@ bool depends on 8xx || 8260 default y - + config PPC_MPC52xx bool @@ -685,7 +685,8 @@ config PPC_GEN550 bool - depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || PRPMC750 || K2 || PRPMC800 + depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || \ + PRPMC750 || K2 || PRPMC800 || LOPEC default y config FORCE @@ -811,10 +812,6 @@ config HIGHMEM bool "High memory support" -config KERNEL_ELF - bool - default y - source "fs/Kconfig.binfmt" config PROC_DEVICETREE @@ -832,10 +829,11 @@ Some PReP systems have residual data passed to the kernel by the firmware. This allows detection of memory size, devices present and other useful pieces of information. Sometimes this information is - not present or incorrect. + not present or incorrect, in which case it could lead to the machine + behaving incorrectly. If this happens, either disable PREP_RESIDUAL + or pass the 'noresidual' option to the kernel. - Unless you expect to boot on a PReP system, there is no need to - select Y. + If you are running a PReP system, say Y here, otherwise say N. config PROC_PREPRESIDUAL bool "Support for reading of PReP Residual Data in /proc" @@ -1043,13 +1041,13 @@ bool depends on PCI && 8260 && !8272 default y - + config 8260_PCI9 bool " Enable workaround for MPC826x erratum PCI 9" depends on PCI_8260 default y -choice +choice prompt " IDMA channel for PCI 9 workaround" depends on 8260_PCI9 @@ -1228,128 +1226,7 @@ source "arch/ppc/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and to CONFIG_SMP to include code to check for missing - spinlock initialization and some other common spinlock errors. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - help - This options enables additional error checking for high memory - systems. Disable for production systems. - -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. - -config KGDB - bool "Include kgdb kernel debugger" - depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) - select DEBUG_INFO - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -choice - prompt "Serial Port" - depends on KGDB - default KGDB_TTYS1 - -config KGDB_TTYS0 - bool "ttyS0" - -config KGDB_TTYS1 - bool "ttyS1" - -config KGDB_TTYS2 - bool "ttyS2" - -config KGDB_TTYS3 - bool "ttyS3" - -endchoice - -config KGDB_CONSOLE - bool "Enable serial console thru kgdb port" - depends on KGDB && 8xx || CPM2 - help - If you enable this, all serial console messages will be sent - over the gdb stub. - If unsure, say N. - -config XMON - bool "Include xmon kernel debugger" - depends on DEBUG_KERNEL - help - Include in-kernel hooks for the xmon kernel monitor/debugger. - Unless you are intending to debug the kernel, say N here. - -config BDI_SWITCH - bool "Include BDI-2000 user context switcher" - depends on DEBUG_KERNEL - help - Include in-kernel support for the Abatron BDI2000 debugger. - Unless you are intending to debug the kernel with one of these - machines, say N here. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use some sort of debugger to - debug the kernel. - If you don't debug the kernel, you can say N. - -config BOOTX_TEXT - bool "Support for early boot text console (BootX or OpenFirmware only)" - depends PPC_OF - help - Say Y here to see progress messages from the boot firmware in text - mode. Requires either BootX or Open Firmware. - -config SERIAL_TEXT_DEBUG - bool "Support for early boot texts over serial port" - depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx - -config PPC_OCP - bool - depends on IBM_OCP || FSL_OCP - default y - -endmenu +source "arch/ppc/Kconfig.debug" source "security/Kconfig" diff -Nru a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/Kconfig.debug 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,84 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) + select DEBUG_INFO + help + Include in-kernel hooks for kgdb, the Linux kernel source level + debugger. See for more information. + Unless you are intending to debug the kernel, say N here. + +choice + prompt "Serial Port" + depends on KGDB + default KGDB_TTYS1 + +config KGDB_TTYS0 + bool "ttyS0" + +config KGDB_TTYS1 + bool "ttyS1" + +config KGDB_TTYS2 + bool "ttyS2" + +config KGDB_TTYS3 + bool "ttyS3" + +endchoice + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB && 8xx || CPM2 + help + If you enable this, all serial console messages will be sent + over the gdb stub. + If unsure, say N. + +config XMON + bool "Include xmon kernel debugger" + depends on DEBUG_KERNEL + help + Include in-kernel hooks for the xmon kernel monitor/debugger. + Unless you are intending to debug the kernel, say N here. + +config BDI_SWITCH + bool "Include BDI-2000 user context switcher" + depends on DEBUG_KERNEL + help + Include in-kernel support for the Abatron BDI2000 debugger. + Unless you are intending to debug the kernel with one of these + machines, say N here. + +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on DEBUG_KERNEL && PROC_FS + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. + +config BOOTX_TEXT + bool "Support for early boot text console (BootX or OpenFirmware only)" + depends PPC_OF + help + Say Y here to see progress messages from the boot firmware in text + mode. Requires either BootX or Open Firmware. + +config SERIAL_TEXT_DEBUG + bool "Support for early boot texts over serial port" + depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx + +config PPC_OCP + bool + depends on IBM_OCP || FSL_OCP + default y + +endmenu diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile --- a/arch/ppc/Makefile 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/Makefile 2004-10-18 14:55:54 -07:00 @@ -13,7 +13,7 @@ # This must match PAGE_OFFSET in include/asm-ppc/page.h. KERNELLOAD := $(CONFIG_KERNEL_START) -HAS_BIARCH := $(shell if $(CC) -m32 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi;) +HAS_BIARCH := $(call cc-option-yn, -m32) ifeq ($(HAS_BIARCH),y) AS := $(AS) -a32 LD := $(LD) -m elf32ppc @@ -24,10 +24,10 @@ CPPFLAGS += -Iarch/$(ARCH) AFLAGS += -Iarch/$(ARCH) CFLAGS += -Iarch/$(ARCH) -msoft-float -pipe \ - -ffixed-r2 -Wno-uninitialized -mmultiple + -ffixed-r2 -mmultiple CPP = $(CC) -E $(CFLAGS) -CHECK := $(CHECK) -D__powerpc__=1 +CHECKFLAGS += -D__powerpc__ ifndef CONFIG_E500 CFLAGS += -mstring @@ -70,7 +70,7 @@ all: zImage -AFLAGS_vmlinux.lds.o := -Upowerpc +CPPFLAGS_vmlinux.lds := -Upowerpc # All the instructions talk about "make bzImage". bzImage: zImage @@ -104,16 +104,15 @@ include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s $(call filechk,gen-asm-offsets) -ifdef CONFIG_6xx -# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later -NEW_AS := $(shell echo dssall | $(AS) -many -o /dev/null >/dev/null 2>&1 ; echo $$?) -GOODVER := 2.12.1 -else -NEW_AS := 0 -endif +# Use the file '.tmp_gas_check' for binutils tests, as gas won't output +# to stdout and these checks are run even on install targets. +TOUT := .tmp_gas_check +# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec +# instructions. +AS_ALTIVEC := $(shell echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; echo $$?) # gcc-3.4 and binutils-2.14 are a fatal combination. -GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) -BAD_GCC_AS := $(shell echo mftb 5 | $(AS) -mppc -many -o /dev/null >/dev/null 2>&1 && echo 0 || echo 1) +GCC_VERSION := $(call cc-version) +BAD_GCC_AS := $(shell echo mftb 5 | $(AS) -mppc -many -o $(TOUT) >/dev/null 2>&1 && echo 0 || echo 1) checkbin: ifeq ($(GCC_VERSION)$(BAD_GCC_AS),03041) @@ -122,13 +121,16 @@ @echo '*** Please upgrade your binutils or downgrade your gcc' @false endif -ifneq ($(NEW_AS),0) +ifneq ($(AS_ALTIVEC),0) + echo $(AS_ALTIVEC) @echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' @echo 'correctly with old versions of binutils.' - @echo '*** Please upgrade your binutils to ${GOODVER} or newer' + @echo '*** Please upgrade your binutils to 2.12.1 or newer' @false endif @true CLEAN_FILES += include/asm-$(ARCH)/offsets.h \ - arch/$(ARCH)/kernel/asm-offsets.s + arch/$(ARCH)/kernel/asm-offsets.s \ + $(TOUT) + diff -Nru a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c --- a/arch/ppc/amiga/config.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc/amiga/config.c 2004-10-18 14:56:50 -07:00 @@ -423,9 +423,6 @@ mach_floppy_setup = amiga_floppy_setup; #endif mach_reset = amiga_reset; -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif #ifdef CONFIG_HEARTBEAT mach_heartbeat = amiga_heartbeat; #endif diff -Nru a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile --- a/arch/ppc/boot/Makefile 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc/boot/Makefile 2004-10-18 14:56:33 -07:00 @@ -23,12 +23,12 @@ # for cleaning subdir- += simple openfirmware -host-progs := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree) +hostprogs-y := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree) .PHONY: $(BOOT_TARGETS) $(bootdir-y) $(BOOT_TARGETS): $(bootdir-y) $(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \ - $(addprefix $(obj)/,$(host-progs)) + $(addprefix $(obj)/,$(hostprogs-y)) $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS) diff -Nru a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c --- a/arch/ppc/boot/common/misc-common.c 2004-10-18 14:56:31 -07:00 +++ b/arch/ppc/boot/common/misc-common.c 2004-10-18 14:56:31 -07:00 @@ -17,7 +17,7 @@ #include /* for va_ bits */ #include #include -#include "zlib.h" +#include #include "nonstdio.h" /* If we're on a PReP, assume we have a keyboard controller @@ -202,11 +202,10 @@ while(1); /* Halt */ } -void *zalloc(void *x, unsigned items, unsigned size) +static void *zalloc(unsigned size) { void *p = avail_ram; - size *= items; size = (size + 7) & -8; avail_ram += size; if (avail_ram > end_avail) { @@ -216,18 +215,12 @@ return p; } -void zfree(void *x, void *addr, unsigned nb) -{ -} - #define HEAD_CRC 2 #define EXTRA_FIELD 4 #define ORIG_NAME 8 #define COMMENT 0x10 #define RESERVED 0xe0 -#define DEFLATED 8 - void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) { z_stream s; @@ -236,7 +229,7 @@ /* skip header */ i = 10; flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { puts("bad gzipped data\n"); exit(); } @@ -255,24 +248,24 @@ exit(); } - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); + /* Initialize ourself. */ + s.workspace = zalloc(zlib_inflate_workspacesize()); + r = zlib_inflateInit2(&s, -MAX_WBITS); if (r != Z_OK) { - puts("inflateInit2 returned "); puthex(r); puts("\n"); + puts("zlib_inflateInit2 returned "); puthex(r); puts("\n"); exit(); } s.next_in = src + i; s.avail_in = *lenp - i; s.next_out = dst; s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); + r = zlib_inflate(&s, Z_FINISH); if (r != Z_OK && r != Z_STREAM_END) { puts("inflate returned "); puthex(r); puts("\n"); exit(); } *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); + zlib_inflateEnd(&s); } void @@ -525,6 +518,11 @@ * because on some platforms we give inb/outb an exact location, and * on others it's an offset from a given location. -- Tom */ + +void ISA_init(unsigned long base) +{ + ISA_io = (unsigned char *)base; +} void outb(int port, unsigned char val) diff -Nru a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c --- a/arch/ppc/boot/common/ns16550.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/boot/common/ns16550.c 2004-10-18 14:57:04 -07:00 @@ -5,14 +5,14 @@ #include #include #include -#include #include #include +#include "nonstdio.h" +#include "serial.h" + #define SERIAL_BAUD 9600 -extern void outb(int port, unsigned char val); -extern unsigned char inb(int port); extern unsigned long ISA_io; static struct serial_state rs_table[RS_TABLE_SIZE] = { diff -Nru a/arch/ppc/boot/common/serial_stub.c b/arch/ppc/boot/common/serial_stub.c --- a/arch/ppc/boot/common/serial_stub.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/boot/common/serial_stub.c 2004-10-18 14:57:04 -07:00 @@ -11,11 +11,6 @@ * is" without any warranty of any kind, whether express or implied. */ -void __attribute__ ((weak)) -serial_fixups(void) -{ -} - unsigned long __attribute__ ((weak)) serial_init(int chan, void *ignored) { diff -Nru a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S --- a/arch/ppc/boot/common/util.S 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc/boot/common/util.S 2004-10-18 14:57:05 -07:00 @@ -41,7 +41,7 @@ /* Test for a 601 */ mfpvr r10 srwi r10,r10,16 - cmpi 0,r10,1 /* 601 ? */ + cmpwi 0,r10,1 /* 601 ? */ beq .clearbats_601 /* Clear BATs */ @@ -117,9 +117,9 @@ /* Wait for the invalidation to complete */ mfspr r8,PVR srwi r8,r8,16 - cmpli cr0,r8,0x8000 /* 7450 */ - cmpli cr1,r8,0x8001 /* 7455 */ - cmpli cr2,r8,0x8002 /* 7457 */ + cmplwi cr0,r8,0x8000 /* 7450 */ + cmplwi cr1,r8,0x8001 /* 7455 */ + cmplwi cr2,r8,0x8002 /* 7457 */ cror 4*cr0+eq,4*cr0+eq,4*cr1+eq /* Now test if any are true. */ cror 4*cr0+eq,4*cr0+eq,4*cr2+eq bne 2f @@ -190,7 +190,7 @@ udelay: mfspr r4,PVR srwi r4,r4,16 - cmpi 0,r4,1 /* 601 ? */ + cmpwi 0,r4,1 /* 601 ? */ bne .udelay_not_601 00: li r0,86 /* Instructions / microsecond? */ mtctr r0 @@ -213,16 +213,16 @@ 1: mftbu r5 mftb r6 mftbu r7 - cmp 0,r5,r7 + cmpw 0,r5,r7 bne 1b /* Get [synced] base time */ addc r9,r6,r4 /* Compute end time */ addze r8,r5 2: mftbu r5 - cmp 0,r5,r8 + cmpw 0,r5,r8 blt 2b bgt 3f mftb r6 - cmp 0,r6,r9 + cmpw 0,r6,r9 blt 2b 3: blr diff -Nru a/arch/ppc/boot/include/nonstdio.h b/arch/ppc/boot/include/nonstdio.h --- a/arch/ppc/boot/include/nonstdio.h 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc/boot/include/nonstdio.h 2004-10-18 14:56:28 -07:00 @@ -30,3 +30,5 @@ extern void puts(const char *); extern void udelay(long delay); extern unsigned char inb(int port); +extern void board_isa_init(void); +extern void ISA_init(unsigned long base); diff -Nru a/arch/ppc/boot/include/serial.h b/arch/ppc/boot/include/serial.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/boot/include/serial.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,46 @@ +/* + * A really private header file for the (dumb) serial driver in arch/ppc/boot + * + * Shamelessly taken from include/linux/serialP.h: + * + * Copyright (C) 1997 by Theodore Ts'o. + * + * Redistribution of this file is permitted under the terms of the GNU + * Public License (GPL) + */ + +#ifndef _PPC_BOOT_SERIALP_H +#define _PPC_BOOT_SERIALP_H + +/* + * This is our internal structure for each serial port's state. + * + * Many fields are paralleled by the structure used by the serial_struct + * structure. + * + * Given that this is how SERIAL_PORT_DFNS are done, and that we need + * to use a few of their fields, we need to have our own copy of it. + */ +struct serial_state { + int magic; + int baud_base; + unsigned long port; + int irq; + int flags; + int hub6; + int type; + int line; + int revision; /* Chip revision (950) */ + int xmit_fifo_size; + int custom_divisor; + int count; + u8 *iomem_base; + u16 iomem_reg_shift; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + unsigned long icount; + int io_type; + void *info; + void *dev; +}; +#endif /* _PPC_BOOT_SERIAL_H */ diff -Nru a/arch/ppc/boot/include/zlib.h b/arch/ppc/boot/include/zlib.h --- a/arch/ppc/boot/include/zlib.h 2004-10-18 14:56:17 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,430 +0,0 @@ -/* - * This file is derived from zlib.h and zconf.h from the zlib-0.95 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. - */ - -/* - * ==FILEVERSION 960122== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 0.95, Aug 16th, 1995. - - Copyright (C) 1995 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - gzip@prep.ai.mit.edu madler@alumni.caltech.edu - */ - -#ifndef _ZLIB_H -#define _ZLIB_H - -/* #include "zconf.h" */ /* included directly here */ - -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */ - -/* - The library does not install any signal handler. It is recommended to - add at least a handler for SIGSEGV when decompressing; the library checks - the consistency of the input data whenever possible but may go nuts - for some forms of corrupted input. - */ - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints - * at addresses which are not a multiple of their size. - * Under DOS, -DFAR=far or -DFAR=__far may be needed. - */ - -#ifndef STDC -# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus) -# define STDC -# endif -#endif - -#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */ -# include -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -#ifndef FAR -# define FAR -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - 1 << (windowBits+2) + 1 << (memLevel+9) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -typedef Byte FAR Bytef; -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -/* end of original zconf.h */ - -#define ZLIB_VERSION "0.95P" - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms may be added later and will have the same - stream interface. - - For compression the application must provide the output buffer and - may optionally provide the input buffer for optimization. For decompression, - the application must provide the input buffer and may optionally provide - the output buffer for optimization. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidp opaque; /* private data object passed to zalloc and zfree */ - - Byte data_type; /* best guess about the data type: ascii or binary */ - -} z_stream; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_FULL_FLUSH 2 -#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */ -#define Z_FINISH 4 -#define Z_PACKET_FLUSH 5 -/* See deflate() below for the usage of these constants */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -/* error codes for the compression/decompression functions */ - -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Used to set the data_type field */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -extern char *zlib_version; -/* The application can compare zlib_version and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - */ - - /* basic functions */ - -extern int inflateInit OF((z_stream *strm)); -/* - Initializes the internal stream state for decompression. The fields - zalloc and zfree must be initialized before by the caller. If zalloc and - zfree are set to Z_NULL, inflateInit updates them to use default allocation - functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory. msg is set to null if there is no error message. - inflateInit does not perform any decompression: this will be done by - inflate(). -*/ - - -extern int inflate OF((z_stream *strm, int flush)); -/* - Performs one or both of the following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() always provides as much output as possible - (until there is no more input data or no more space in the output buffer). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). - - If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, - inflate flushes as much output as possible to the output buffer. The - flushing behavior of inflate is not specified for values of the flush - parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the - current implementation actually flushes as much output as possible - anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data - has been consumed, it is expecting to see the length field of a stored - block; if not, it returns Z_DATA_ERROR. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - inflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if the end of the - compressed data has been reached and all uncompressed output has been - produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if - the stream structure was inconsistent (for example if next_in or next_out - was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no - progress is possible or if there was not enough room in the output buffer - when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then - call inflateSync to look for a good compression block. */ - - -extern int inflateEnd OF((z_stream *strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* advanced functions */ - -extern int inflateInit2 OF((z_stream *strm, - int windowBits)); -/* - This is another version of inflateInit with more compression options. The - fields next_out, zalloc and zfree must be initialized before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library (the value 16 will be allowed soon). The - default value is 15 if inflateInit is used instead. If a compressed stream - with a larger window size is given as input, inflate() will return with - the error code Z_DATA_ERROR instead of trying to allocate a larger window. - - If next_out is not null, the library will use this buffer for the history - buffer; the buffer must either be large enough to hold the entire output - data, or have at least 1<msg=z_errmsg[1-err], err) -/* To be used only when the state is known to be valid */ - -#ifndef NULL -#define NULL ((void *) 0) -#endif - - /* common constants */ - -#define DEFLATED 8 - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - - /* functions */ - -#include -#define zmemcpy memcpy -#define zmemzero(dest, len) memset(dest, 0, len) - -/* Diagnostic functions */ -#ifdef DEBUG_ZLIB -# include -# ifndef verbose -# define verbose 0 -# endif -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len)); - -/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */ -/* void zcfree OF((voidpf opaque, voidpf ptr)); */ - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr, size) \ - (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size)) -#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);} - -/* deflate.h -- internal compression state - * Copyright (C) 1995 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/*+++++*/ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -local inflate_blocks_statef * inflate_blocks_new OF(( - z_stream *z, - check_func c, /* check function */ - uInt w)); /* window size */ - -local int inflate_blocks OF(( - inflate_blocks_statef *, - z_stream *, - int)); /* initial return code */ - -local void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_addhistory OF(( - inflate_blocks_statef *, - z_stream *)); - -local int inflate_packet_flush OF(( - inflate_blocks_statef *)); - -/*+++++*/ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s FAR inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt Nalloc; /* number of these allocated here */ - Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit machines) */ - union { - uInt Base; /* literal, length base, or distance base */ - inflate_huft *Next; /* pointer to next level of table */ - } more; -}; - -#ifdef DEBUG_ZLIB - local uInt inflate_hufts; -#endif - -local int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *)); /* distance tree result */ - -local int inflate_trees_free OF(( - inflate_huft *, /* tables to free */ - z_stream *)); /* for zfree function */ - - -/*+++++*/ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -local inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_stream *)); - -local int inflate_codes OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -local void inflate_codes_free OF(( - inflate_codes_statef *, - z_stream *)); - - -/*+++++*/ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* inflate private state */ -struct internal_state { - - /* mode */ - enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ - mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int inflateReset( - z_stream *z -) -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, &c); - Trace((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd( - z_stream *z -) -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z, &c); - ZFREE(z, z->state, sizeof(struct internal_state)); - z->state = Z_NULL; - Trace((stderr, "inflate: end\n")); - return Z_OK; -} - - -int inflateInit2( - z_stream *z, - int w -) -{ - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; -/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */ -/* if (z->zfree == Z_NULL) z->zfree = zcfree; */ - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Trace((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit( - z_stream *z -) -{ - return inflateInit2(z, DEF_WBITS); -} - - -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate( - z_stream *z, - int f -) -{ - int r; - uInt b; - - if (z == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED) - { - z->state->mode = BAD; - z->msg = "unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = "invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - if ((b = NEXTBYTE) & 0x20) - { - z->state->mode = BAD; - z->msg = "invalid reserved bit"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = "incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib header ok\n")); - z->state->mode = BLOCKS; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = inflate_packet_flush(z->state->blocks); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r != Z_STREAM_END) - return r; - r = Z_OK; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = "incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ - -int inflateIncomp( - z_stream *z -) -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return inflate_addhistory(z->state->blocks, z); -} - - -int inflateSync( - z_stream *z -) -{ - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - if (*p == (Byte)(m < 2 ? 0 : 0xff)) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; -} - -#undef NEEDBYTE -#undef NEXTBYTE - -/*+++++*/ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONEB, /* finished last block, done */ - BADB} /* got a data error--stuck here */ - mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - int nblens; /* # elements allocated at blens */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_huft *tl, *td; /* trees to free */ - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* And'ing with mask[n] masks the lower n bits */ -local uInt inflate_mask[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -/* copy as much as possible from the sliding window to the output area */ -local int inflate_flush OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -/*+++++*/ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -local int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_stream *)); - - -/*+++++*/ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* Table for deflate from PKZIP's appnote.txt. */ -local uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -local void inflate_blocks_reset( - inflate_blocks_statef *s, - z_stream *z, - uLongf *c -) -{ - if (s->checkfn != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - if (s->mode == CODES) - { - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - } - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(0L, Z_NULL, 0); - Trace((stderr, "inflate: blocks reset\n")); -} - - -local inflate_blocks_statef *inflate_blocks_new( - z_stream *z, - check_func c, - uInt w -) -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Trace((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, &s->check); - return s; -} - - -local int inflate_blocks( - inflate_blocks_statef *s, - z_stream *z, - int r -) -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Trace((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Trace((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.tl = Z_NULL; /* don't try to free these */ - s->sub.decode.td = Z_NULL; - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Trace((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BADB; - z->msg = "invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if (((~b) >> 16) != (b & 0xffff)) - { - s->mode = BADB; - z->msg = "invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : TYPE; - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BADB; - z->msg = "too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (t < 19) - t = 19; - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.trees.nblens = t; - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - s->mode = BADB; - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->word.what.Bits; - c = h->more.Base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - s->mode = BADB; - z->msg = "invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - inflate_trees_free(s->sub.trees.tb, z); - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = BADB; - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - inflate_trees_free(td, z); - inflate_trees_free(tl, z); - r = Z_MEM_ERROR; - LEAVE - } - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - s->sub.decode.codes = c; - s->sub.decode.tl = tl; - s->sub.decode.td = td; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONEB; - case DONEB: - r = Z_STREAM_END; - LEAVE - case BADB: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -local int inflate_blocks_free( - inflate_blocks_statef *s, - z_stream *z, - uLongf *c -) -{ - inflate_blocks_reset(s, z, c); - ZFREE(z, s->window, s->end - s->window); - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - Trace((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -local int inflate_addhistory( - inflate_blocks_statef *s, - z_stream *z -) -{ - uLong b; /* bit buffer */ /* NOT USED HERE */ - uInt k; /* bits in bit buffer */ /* NOT USED HERE */ - uInt t; /* temporary storage */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - if (s->read != s->write) - return Z_STREAM_ERROR; - if (s->mode != TYPE) - return Z_DATA_ERROR; - - /* we're ready to rock */ - LOAD - /* while there is input ready, copy to output buffer, moving - * pointers as needed. - */ - while (n) { - t = n; /* how many to do */ - /* is there room until end of buffer? */ - if (t > m) t = m; - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, t); - zmemcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WRAP */ /* expand WRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - - -/* - * At the end of a Deflate-compressed PPP packet, we expect to have seen - * a `stored' block type value but not the (zero) length bytes. - */ -local int inflate_packet_flush( - inflate_blocks_statef *s -) -{ - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; - return Z_OK; -} - - -/*+++++*/ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - uIntf *, /* list of base values for non-simple codes */ - uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - z_stream *)); /* for zalloc function */ - -local voidpf falloc OF(( - voidpf, /* opaque pointer (not used) */ - uInt, /* number of items */ - uInt)); /* size of item */ - -local void ffree OF(( - voidpf q, /* opaque pointer (not used) */ - voidpf p, /* what to free (not used) */ - uInt n)); /* number of bytes (not used) */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* actually lengths - 2; also see note #13 above about 258 */ -local uInt cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */ -local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -local uInt cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ -#define N_MAX 288 /* maximum number of codes in any set */ - -#ifdef DEBUG_ZLIB - uInt inflate_hufts; -#endif - -local int huft_build( - uIntf *b, /* code lengths in bits (all assumed <= BMAX) */ - uInt n, /* number of codes (assumed <= N_MAX) */ - uInt s, /* number of simple-valued codes (0..s-1) */ - uIntf *d, /* list of base values for non-simple codes */ - uIntf *e, /* list of extra bits for non-simple codes */ - inflate_huft * FAR *t, /* result: starting table */ - uIntf *m, /* maximum lookup bits, returns actual */ - z_stream *zs /* for zalloc function */ -) -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (all zero length codes or an - over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - uInt v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (inflate_huft *)ZALLOC - (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) - { - if (h) - inflate_trees_free(u[0], zs); - return Z_MEM_ERROR; /* not enough memory */ - } - q->word.Nalloc = z + 1; -#ifdef DEBUG_ZLIB - inflate_hufts += z + 1; -#endif - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->next)) = Z_NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - r.next = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h-1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -local int inflate_trees_bits( - uIntf *c, /* 19 code lengths */ - uIntf *bb, /* bits tree desired/actual depth */ - inflate_huft * FAR *tb, /* bits tree result */ - z_stream *z /* for zfree function */ -) -{ - int r; - - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tb, z); - z->msg = "incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - return r; -} - - -local int inflate_trees_dynamic( - uInt nl, /* number of literal/length codes */ - uInt nd, /* number of distance codes */ - uIntf *c, /* that many (total) code lengths */ - uIntf *bl, /* literal desired/actual bit depth */ - uIntf *bd, /* distance desired/actual bit depth */ - inflate_huft * FAR *tl, /* literal/length tree result */ - inflate_huft * FAR *td, /* distance tree result */ - z_stream *z /* for zfree function */ -) -{ - int r; - - /* build literal/length tree */ - if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tl, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - return r; - } - - /* build distance tree */ - if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - inflate_trees_free(*td, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - inflate_trees_free(*tl, z); - return r; -#endif - } - - /* done */ - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -local int fixed_lock = 0; -local int fixed_built = 0; -#define FIXEDH 530 /* number of hufts used by fixed tables */ -local uInt fixed_left = FIXEDH; -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; - - -local voidpf falloc(q, n, s) -voidpf q; /* opaque pointer (not used) */ -uInt n; /* number of items */ -uInt s; /* size of item */ -{ - Assert(s == sizeof(inflate_huft) && n <= fixed_left, - "inflate_trees falloc overflow"); - if (q) s++; /* to make some compilers happy */ - fixed_left -= n; - return (voidpf)(fixed_mem + fixed_left); -} - - -local void ffree(q, p, n) -voidpf q; -voidpf p; -uInt n; -{ - Assert(0, "inflate_trees ffree called!"); - if (q) q = p; /* to make some compilers happy */ -} - - -local int inflate_trees_fixed( - uIntf *bl, /* literal desired/actual bit depth */ - uIntf *bd, /* distance desired/actual bit depth */ - inflate_huft * FAR *tl, /* literal/length tree result */ - inflate_huft * FAR *td /* distance tree result */ -) -{ - /* build fixed tables if not built already--lock out other instances */ - while (++fixed_lock > 1) - fixed_lock--; - if (!fixed_built) - { - int k; /* temporary variable */ - unsigned c[288]; /* length list for huft_build */ - z_stream z; /* for falloc function */ - - /* set up fake z_stream for memory routines */ - z.zalloc = falloc; - z.zfree = ffree; - z.opaque = Z_NULL; - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 7; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); - - /* done */ - fixed_built = 1; - } - fixed_lock--; - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - - -local int inflate_trees_free( - inflate_huft *t, /* table to free */ - z_stream *z /* for zfree function */ -) -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register inflate_huft *p, *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != Z_NULL) - { - q = (--p)->next; - ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft)); - p = q; - } - return Z_OK; -} - -/*+++++*/ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ - mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -local inflate_codes_statef *inflate_codes_new( - uInt bl, - uInt bd, - inflate_huft *tl, - inflate_huft *td, - z_stream *z -) -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -local int inflate_codes( - inflate_blocks_statef *s, - z_stream *z, - int r -) -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -local void inflate_codes_free( - inflate_codes_statef *c, - z_stream *z -) -{ - ZFREE(z, c, sizeof(struct inflate_codes_state)); - Tracev((stderr, "inflate: codes free\n")); -} - -/*+++++*/ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* copy as much as possible from the sliding window to the output area */ -local int inflate_flush( - inflate_blocks_statef *s, - z_stream *z, - int r -) -{ - uInt n; - Bytef *p, *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} - - -/*+++++*/ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -local int inflate_fast( - uInt bl, - uInt bd, - inflate_huft *tl, - inflate_huft *td, - inflate_blocks_statef *s, - z_stream *z -) -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; - else - { - z->msg = "invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = "invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} - - -/*+++++*/ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */ - -char *zlib_version = ZLIB_VERSION; - -char *z_errmsg[] = { -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -""}; - - -/*+++++*/ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf) {s1 += *buf++; s2 += s1;} -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); -#define DO16(buf) DO8(buf); DO8(buf); - -/* ========================================================================= */ -uLong adler32(adler, buf, len) - uLong adler; - Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - k -= 16; - } - if (k != 0) do { - DO1(buf); - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} diff -Nru a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c --- a/arch/ppc/boot/openfirmware/coffmain.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/boot/openfirmware/coffmain.c 2004-10-18 14:56:32 -07:00 @@ -12,7 +12,6 @@ #include "nonstdio.h" #include "of1275.h" -#include "zlib.h" /* Passed from the linker */ extern char __image_begin, __image_end; diff -Nru a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c --- a/arch/ppc/boot/openfirmware/common.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/boot/openfirmware/common.c 2004-10-18 14:56:49 -07:00 @@ -7,10 +7,10 @@ * 2 of the License, or (at your option) any later version. */ -#include "zlib.h" #include "nonstdio.h" #include "of1275.h" #include +#include #include #include @@ -30,12 +30,11 @@ static struct memchunk *freechunks; -static void *zalloc(void *x, unsigned items, unsigned size) +static void *zalloc(unsigned size) { void *p; struct memchunk **mpp, *mp; - size *= items; size = (size + 7) & -8; heap_use += size; if (heap_use > heap_max) @@ -57,74 +56,57 @@ return p; } -static void zfree(void *x, void *addr, unsigned nb) -{ - struct memchunk *mp = addr; - - nb = (nb + 7) & -8; - heap_use -= nb; - if (avail_ram == addr + nb) { - avail_ram = addr; - return; - } - mp->size = nb; - mp->next = freechunks; - freechunks = mp; -} - #define HEAD_CRC 2 #define EXTRA_FIELD 4 #define ORIG_NAME 8 #define COMMENT 0x10 #define RESERVED 0xe0 -#define DEFLATED 8 - void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) { - z_stream s; - int r, i, flags; + z_stream s; + int r, i, flags; - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n\r"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n\r"); - exit(); - } + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); + } - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n\r", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n\r", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); + /* Initialize ourself. */ + s.workspace = zalloc(zlib_inflate_workspacesize()); + r = zlib_inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("zlib_inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = zlib_inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + zlib_inflateEnd(&s); } /* Make a bi_rec in OF. We need to be passed a name for BI_BOOTLOADER_ID, diff -Nru a/arch/ppc/boot/openfirmware/misc.S b/arch/ppc/boot/openfirmware/misc.S --- a/arch/ppc/boot/openfirmware/misc.S 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc/boot/openfirmware/misc.S 2004-10-18 14:56:33 -07:00 @@ -16,7 +16,7 @@ setup_bats: mfpvr 5 rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,5,1 + cmpwi 0,5,1 li 0,0 bne 4f mtibatl 3,0 /* invalidate BAT first */ diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile --- a/arch/ppc/boot/simple/Makefile 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc/boot/simple/Makefile 2004-10-18 14:55:53 -07:00 @@ -64,6 +64,7 @@ zimageinitrd-$(CONFIG_OCOTEA) := zImage.initrd-TREE end-$(CONFIG_OCOTEA) := ocotea entrypoint-$(CONFIG_OCOTEA) := 0x01000000 + extra.o-$(CONFIG_OCOTEA) := pibs.o extra.o-$(CONFIG_EV64260) := direct.o misc-ev64260.o end-$(CONFIG_EV64260) := ev64260 @@ -73,7 +74,7 @@ zimageinitrd-$(CONFIG_GEMINI) := zImage.initrd-STRIPELF end-$(CONFIG_GEMINI) := gemini - extra.o-$(CONFIG_K2) := legacy.o + extra.o-$(CONFIG_K2) := prepmap.o end-$(CONFIG_K2) := k2 cacheflag-$(CONFIG_K2) := -include $(clear_L2_L3) @@ -89,7 +90,7 @@ end-$(motorola) := pplus # Overrides previous assingment - extra.o-$(CONFIG_PPLUS) := legacy.o + extra.o-$(CONFIG_PPLUS) := prepmap.o extra.o-$(CONFIG_LOPEC) := mpc10x_memory.o zimage-$(pcore) := zImage-STRIPELF @@ -100,7 +101,7 @@ zimage-$(CONFIG_PPC_PREP) := zImage-PPLUS zimageinitrd-$(CONFIG_PPC_PREP) := zImage.initrd-PPLUS - extra.o-$(CONFIG_PPC_PREP) := legacy.o + extra.o-$(CONFIG_PPC_PREP) := prepmap.o misc-$(CONFIG_PPC_PREP) += misc-prep.o mpc10x_memory.o end-$(CONFIG_PPC_PREP) := prep diff -Nru a/arch/ppc/boot/simple/chrpmap.S b/arch/ppc/boot/simple/chrpmap.S --- a/arch/ppc/boot/simple/chrpmap.S 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,19 +0,0 @@ -/* - * arch/ppc/boot/simple/chrpmap.S - * - * Author: Tom Rini - * - * This will go and setup ISA_io to 0xFE00000 and return. - */ - -#include - - .text - - .globl serial_fixups -serial_fixups: - lis r3,ISA_io@h /* Load ISA_io */ - ori r3,r3,ISA_io@l - lis r4,0xFE00 /* Load the value, 0xFE00000 */ - stw r4,0(r3) /* store */ - blr diff -Nru a/arch/ppc/boot/simple/chrpmap.c b/arch/ppc/boot/simple/chrpmap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/boot/simple/chrpmap.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,12 @@ +/* + * 2004 (C) IBM. This file is licensed under the terms of the GNU General + * Public License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include + +void board_isa_init(void) +{ + ISA_init(0xFE000000); +} diff -Nru a/arch/ppc/boot/simple/legacy.S b/arch/ppc/boot/simple/legacy.S --- a/arch/ppc/boot/simple/legacy.S 2004-10-18 14:56:29 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,19 +0,0 @@ -/* - * arch/ppc/boot/simple/legacy.S - * - * Author: Tom Rini - * - * This will go and setup ISA_io to 0x8000000 and return. - */ - -#include - - .text - - .globl serial_fixups -serial_fixups: - lis r3,ISA_io@h /* Load ISA_io */ - ori r3,r3,ISA_io@l - lis r4,0x8000 /* Load the value, 0x8000000 */ - stw r4,0(r3) /* store */ - blr diff -Nru a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c --- a/arch/ppc/boot/simple/misc-embedded.c 2004-10-18 14:56:16 -07:00 +++ b/arch/ppc/boot/simple/misc-embedded.c 2004-10-18 14:56:16 -07:00 @@ -22,7 +22,6 @@ #endif #include "nonstdio.h" -#include "zlib.h" /* The linker tells us where the image is. */ extern char __image_begin, __image_end; @@ -71,6 +70,14 @@ extern void flush_instruction_cache(void); extern void gunzip(void *, int, unsigned char *, int *); extern void embed_config(bd_t **bp); + +/* Weak function for boards which don't need to build the + * board info struct because they are using PPCBoot/U-Boot. + */ +void __attribute__ ((weak)) +embed_config(bd_t **bdp) +{ +} unsigned long load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) diff -Nru a/arch/ppc/boot/simple/misc-prep.c b/arch/ppc/boot/simple/misc-prep.c --- a/arch/ppc/boot/simple/misc-prep.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/boot/simple/misc-prep.c 2004-10-18 14:55:54 -07:00 @@ -88,6 +88,7 @@ ofinit(OFW_interface); } + board_isa_init(); #if defined(CONFIG_VGA_CONSOLE) vga_init((unsigned char *)0xC0000000); #endif /* CONFIG_VGA_CONSOLE */ diff -Nru a/arch/ppc/boot/simple/misc-spruce.c b/arch/ppc/boot/simple/misc-spruce.c --- a/arch/ppc/boot/simple/misc-spruce.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/boot/simple/misc-spruce.c 2004-10-18 14:56:32 -07:00 @@ -26,7 +26,6 @@ /* Define some important locations of the Spruce. */ #define SPRUCE_PCI_CONFIG_ADDR 0xfec00000 #define SPRUCE_PCI_CONFIG_DATA 0xfec00004 -#define SPRUCE_ISA_IO_BASE 0xf8000000 /* PCI configuration space access routines. */ unsigned int *pci_config_address = (unsigned int *)SPRUCE_PCI_CONFIG_ADDR; @@ -85,8 +84,6 @@ out_le32((unsigned *)pci_config_data, val); } - -unsigned long isa_io_base = SPRUCE_ISA_IO_BASE; #define PCNET32_WIO_RDP 0x10 #define PCNET32_WIO_RAP 0x12 diff -Nru a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c --- a/arch/ppc/boot/simple/misc.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/boot/simple/misc.c 2004-10-18 14:56:49 -07:00 @@ -29,7 +29,6 @@ #include #include "nonstdio.h" -#include "zlib.h" /* Default cmdline */ #ifdef CONFIG_CMDLINE @@ -49,7 +48,9 @@ * Val Henson has requested that Gemini doesn't wait for the * user to edit the cmdline or not. */ -#if (defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \ +#if (defined(CONFIG_SERIAL_8250_CONSOLE) \ + || defined(CONFIG_VGA_CONSOLE) \ + || defined(CONFIG_SERIAL_MPC52xx_CONSOLE)) \ && !defined(CONFIG_GEMINI) #define INTERACTIVE_CONSOLE 1 #endif @@ -95,9 +96,8 @@ #endif char *cp; struct bi_record *rec; - unsigned long initrd_loc, TotalMemory = 0; + unsigned long initrd_loc = 0, TotalMemory = 0; - serial_fixups(); #ifdef CONFIG_SERIAL_8250_CONSOLE com_port = serial_init(0, NULL); #endif @@ -221,7 +221,7 @@ puts("\n"); puts("Uncompressing Linux..."); - gunzip(NULL, 0x400000, zimage_start, &zimage_size); + gunzip(0x0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); /* get the bi_rec address */ @@ -268,10 +268,16 @@ return rec; } +void __attribute__ ((weak)) +board_isa_init(void) +{ +} + /* Allow decompress_kernel to be hooked into. This is the default. */ void * __attribute__ ((weak)) load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, void *ign1, void *ign2) { + board_isa_init(); return decompress_kernel(load_addr, num_words, cksum); } diff -Nru a/arch/ppc/boot/simple/pibs.c b/arch/ppc/boot/simple/pibs.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/boot/simple/pibs.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,101 @@ +/* + * 2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include + +extern unsigned long decompress_kernel(unsigned long load_addr, int num_words, + unsigned long cksum); + +/* We need to make sure that this is before the images to ensure + * that it's in a mapped location. - Tom */ +bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot"))); +bd_t *hold_residual = &hold_resid_buf; + +/* String functions lifted from lib/vsprintf.c and lib/ctype.c */ +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + +/** + * simple_strtoull - convert a string to an unsigned long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) +{ + unsigned long long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } else if (base == 16) { + if (cp[0] == '0' && toupper(cp[1]) == 'X') + cp += 2; + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +void * +load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, + void *ign1, void *ign2) +{ + unsigned long long mac64; + + decompress_kernel(load_addr, num_words, cksum); + + mac64 = simple_strtoull((char *)OCOTEA_PIBS_MAC_BASE, 0, 16); + memcpy(hold_residual->bi_enetaddr, (char *)&mac64+2, 6); + mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET), 0, 16); + memcpy(hold_residual->bi_enet1addr, (char *)&mac64+2, 6); + mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*2), 0, 16); + memcpy(hold_residual->bi_enet2addr, (char *)&mac64+2, 6); + mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*3), 0, 16); + memcpy(hold_residual->bi_enet3addr, (char *)&mac64+2, 6); + return (void *)hold_residual; +} diff -Nru a/arch/ppc/boot/simple/prepmap.c b/arch/ppc/boot/simple/prepmap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/boot/simple/prepmap.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,12 @@ +/* + * 2004 (C) IBM. This file is licensed under the terms of the GNU General + * Public License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include + +void board_isa_init(void) +{ + ISA_init(0x80000000); +} diff -Nru a/arch/ppc/boot/simple/relocate.S b/arch/ppc/boot/simple/relocate.S --- a/arch/ppc/boot/simple/relocate.S 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc/boot/simple/relocate.S 2004-10-18 14:56:29 -07:00 @@ -50,7 +50,7 @@ * Check if we need to relocate ourselves to the link addr or were * we loaded there to begin with. */ - cmp cr0,r3,r4 + cmpw cr0,r3,r4 beq start_ldr /* If 0, we don't need to relocate */ /* Move this code somewhere safe. This is max(load + size, end) @@ -122,7 +122,7 @@ GETSYM(r4, start) mr r3,r8 /* Get the load addr */ - cmp cr0,r4,r3 /* If we need to copy from the end, do so */ + cmpw cr0,r4,r3 /* If we need to copy from the end, do so */ bgt do_relocate_from_end do_relocate_from_start: @@ -165,7 +165,7 @@ subi r4,r4,4 li r0,0 50: stwu r0,4(r3) - cmp cr0,r3,r4 + cmpw cr0,r3,r4 bne 50b 90: mr r9,r1 /* Save old stack pointer (in case it matters) */ lis r1,.stack@h diff -Nru a/arch/ppc/boot/utils/mkbugboot.c b/arch/ppc/boot/utils/mkbugboot.c --- a/arch/ppc/boot/utils/mkbugboot.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/boot/utils/mkbugboot.c 2004-10-18 14:56:32 -07:00 @@ -1,5 +1,5 @@ /* - * arch/ppc/pp3boot/mkbugboot.c + * arch/ppc/boot/utils/mkbugboot.c * * Makes a Motorola PPCBUG ROM bootable image which can be flashed * into one of the FLASH banks on a Motorola PowerPlus board. @@ -21,6 +21,11 @@ #include #include #include +#ifdef __sun__ +#include +#else +#include +#endif #ifdef __i386__ #define cpu_to_be32(x) le32_to_cpu(x) @@ -48,11 +53,6 @@ /* size of read buffer */ #define SIZE 0x1000 - -/* typedef long int32_t; */ -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -typedef unsigned char uint8_t; /* PPCBUG ROM boot header */ typedef struct bug_boot_header { diff -Nru a/arch/ppc/boot/utils/mktree.c b/arch/ppc/boot/utils/mktree.c --- a/arch/ppc/boot/utils/mktree.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/boot/utils/mktree.c 2004-10-18 14:56:49 -07:00 @@ -15,7 +15,11 @@ #include #include #include +#ifdef __sun__ +#include +#else #include +#endif /* This gets tacked on the front of the image. There are also a few * bytes allocated after the _start label used by the boot rom (see diff -Nru a/arch/ppc/configs/mvme5100_defconfig b/arch/ppc/configs/mvme5100_defconfig --- a/arch/ppc/configs/mvme5100_defconfig 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/configs/mvme5100_defconfig 2004-10-18 14:55:54 -07:00 @@ -1,26 +1,48 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Wed Sep 22 09:53:26 2004 # CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_GENERIC_IOMAP=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_EMBEDDED is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -33,24 +55,26 @@ CONFIG_KMOD=y # -# Platform support +# Processor # -CONFIG_PPC=y -CONFIG_PPC32=y CONFIG_6xx=y # CONFIG_40x is not set +# CONFIG_44x is not set # CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8xx is not set +# CONFIG_E500 is not set +CONFIG_ALTIVEC=y +# CONFIG_TAU is not set +# CONFIG_CPU_FREQ is not set +CONFIG_PPC_STD_MMU=y # -# IBM 4xx options +# Platform options # -# CONFIG_8260 is not set -CONFIG_GENERIC_ISA_DMA=y -CONFIG_PPC_STD_MMU=y # CONFIG_PPC_MULTIPLATFORM is not set # CONFIG_APUS is not set -# CONFIG_WILLOW_2 is not set +# CONFIG_WILLOW is not set # CONFIG_PCORE is not set # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set @@ -66,34 +90,30 @@ # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set +# CONFIG_EST8260 is not set +# CONFIG_SBC82xx is not set +# CONFIG_SBS8260 is not set +# CONFIG_RPX8260 is not set +# CONFIG_TQM8260 is not set +# CONFIG_ADS8272 is not set +# CONFIG_LITE5200 is not set # CONFIG_MVME5100_IPMC761_PRESENT is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set -CONFIG_ALTIVEC=y -# CONFIG_TAU is not set -# CONFIG_CPU_FREQ is not set +# CONFIG_HIGHMEM is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="ip=on" # -# General setup +# Bus options # -# CONFIG_HIGHMEM is not set +CONFIG_GENERIC_ISA_DMA=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y -CONFIG_KCORE_ELF=y -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set # CONFIG_PCI_LEGACY_PROC is not set # CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set -# CONFIG_PPC601_SYNC_FIX is not set -CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="ip=on" # # Advanced setup @@ -110,14 +130,28 @@ CONFIG_BOOT_LOAD=0x00800000 # +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# # Memory Technology Devices (MTD) # # CONFIG_MTD is not set # +# Parallel port support +# +# CONFIG_PARPORT is not set + +# # Plug and Play support # -# CONFIG_PNP is not set # # Block devices @@ -129,46 +163,46 @@ # CONFIG_BLK_DEV_UMEM is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y +# CONFIG_LBD is not set # -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# ATA/IDE/MFM/RLL support +# ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# CONFIG_BLK_DEV_IDE=y # # Please see Documentation/ide.txt for help/info on IDE drives # -# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_IDEDISK_STROKE is not set # CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set # # IDE chipset support/bugfixes # +CONFIG_IDE_GENERIC=y # CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set # -# SCSI support +# SCSI device support # CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y # # SCSI support type (disk, tape, CD-ROM) @@ -184,64 +218,70 @@ # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_REPORT_LUNS is not set # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set + +# # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY 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 # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_NCR53C8XX is not set -CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set -# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=32 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR 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=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA6322 is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# # Fusion MPT device support # # CONFIG_FUSION is not set # -# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# IEEE 1394 (FireWire) support # # CONFIG_IEEE1394 is not set @@ -251,6 +291,10 @@ # CONFIG_I2O is not set # +# Macintosh device drivers +# + +# # Networking support # CONFIG_NET=y @@ -261,86 +305,90 @@ CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK_DEV is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +CONFIG_INET_TUNNEL=m + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set # # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=m +# CONFIG_IP_NF_CT_ACCT is not set +# CONFIG_IP_NF_CT_PROTO_SCTP is not set CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m -# CONFIG_IP_NF_TFTP is not set -# CONFIG_IP_NF_AMANDA is not set +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m # CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -CONFIG_IP_NF_MATCH_MAC=m -CONFIG_IP_NF_MATCH_PKTTYPE=m -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_LIMIT is not set +# CONFIG_IP_NF_MATCH_IPRANGE is not set +# CONFIG_IP_NF_MATCH_MAC is not set +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +# CONFIG_IP_NF_MATCH_MARK is not set +# CONFIG_IP_NF_MATCH_MULTIPORT is not set +# CONFIG_IP_NF_MATCH_TOS is not set +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +# CONFIG_IP_NF_MATCH_AH_ESP is not set +# CONFIG_IP_NF_MATCH_LENGTH is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_MATCH_TCPMSS is not set CONFIG_IP_NF_MATCH_HELPER=m -CONFIG_IP_NF_MATCH_STATE=m -CONFIG_IP_NF_MATCH_CONNTRACK=m -CONFIG_IP_NF_MATCH_UNCLEAN=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_MIRROR=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -# CONFIG_IP_NF_NAT_LOCAL is not set -# CONFIG_IP_NF_NAT_SNMP_BASIC is not set -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_STATE is not set +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set +# CONFIG_IP_NF_MATCH_SCTP is not set +# CONFIG_IP_NF_FILTER is not set # CONFIG_IP_NF_TARGET_LOG is not set -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_COMPAT_IPCHAINS=m +# CONFIG_IP_NF_TARGET_ULOG is not set +# CONFIG_IP_NF_TARGET_TCPMSS is not set +# CONFIG_IP_NF_NAT is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set # CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_XFRM_USER is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE 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 @@ -352,29 +400,33 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # # ARCnet devices # # CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y CONFIG_MII=y -# CONFIG_OAKNET is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set @@ -382,17 +434,26 @@ # # Tulip family network device support # -# CONFIG_NET_TULIP is not set +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=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=y -# CONFIG_EEPRO100_PIO is not set -# CONFIG_E100 is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_E100_NAPI is not set # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set @@ -403,6 +464,7 @@ # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set # # Ethernet (1000 Mbit) @@ -421,52 +483,39 @@ # Ethernet (10000 Mbit) # # CONFIG_IXGB is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set +# CONFIG_S2IO is not set # -# Wireless LAN (non-hamradio) +# Token Ring devices # -# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set # -# Token Ring devices (depends on LLC=y) +# Wireless LAN (non-hamradio) # -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces # # CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # ISDN subsystem # -# CONFIG_ISDN_BOOL is not set +# CONFIG_ISDN is not set # -# Graphics support +# Telephony Support # -# CONFIG_FB is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set +# CONFIG_PHONE is not set # # Input device support @@ -483,18 +532,16 @@ # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y # CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set # # Input Device Drivers # # -# Macintosh device drivers -# - -# # Character devices # +# CONFIG_VT is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -502,6 +549,7 @@ # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set # @@ -510,27 +558,8 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# I2C Hardware Sensors Mainboard support -# - -# -# I2C Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # # IPMI @@ -551,11 +580,23 @@ # # Ftape, the floppy tape device driver # -# CONFIG_FTAPE is not set # CONFIG_AGP is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set -# CONFIG_HANGCHECK_TIMER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# # # Multimedia devices @@ -568,6 +609,26 @@ # CONFIG_DVB is not set # +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# # File systems # CONFIG_EXT2_FS=y @@ -592,17 +653,20 @@ # # DOS/FAT/NT Filesystems # -# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set # CONFIG_NTFS_FS is not set # # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS 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 # @@ -611,6 +675,7 @@ # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set @@ -625,19 +690,21 @@ # Network File Systems # CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set +CONFIG_NFS_V3=y # CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y # CONFIG_EXPORTFS is not set CONFIG_SUNRPC=y -# CONFIG_SUNRPC_GSS is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 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 # @@ -647,31 +714,26 @@ CONFIG_MSDOS_PARTITION=y # -# Sound +# Native Language Support # -# CONFIG_SOUND is not set +# CONFIG_NLS is not set # -# USB support -# -# CONFIG_USB is not set -# CONFIG_USB_GADGET is not set - -# -# Bluetooth support +# Library routines # -# CONFIG_BT is not set +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set # -# Library routines +# Profiling support # -# CONFIG_CRC32 is not set +# CONFIG_PROFILING is not set # # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set -# CONFIG_KALLSYMS is not set # # Security options diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile --- a/arch/ppc/kernel/Makefile 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/kernel/Makefile 2004-10-18 14:57:03 -07:00 @@ -9,7 +9,7 @@ extra-$(CONFIG_8xx) := head_8xx.o extra-$(CONFIG_6xx) += idle_6xx.o extra-$(CONFIG_POWER4) += idle_power4.o -extra-y += vmlinux.lds.s +extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ diff -Nru a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c --- a/arch/ppc/kernel/align.c 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc/kernel/align.c 2004-10-18 14:55:53 -07:00 @@ -37,6 +37,7 @@ #define U 0x10 /* update index register */ #define M 0x20 /* multiple load/store */ #define S 0x40 /* single-precision fp, or byte-swap value */ +#define SX 0x40 /* byte count in XER */ #define HARD 0x80 /* string, stwcx. */ #define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ @@ -88,10 +89,10 @@ INVALID, /* 01 0 0101: lwax */ INVALID, /* 01 0 0110 */ INVALID, /* 01 0 0111 */ - { 0, LD+HARD }, /* 01 0 1000: lswx */ - { 0, LD+HARD }, /* 01 0 1001: lswi */ - { 0, ST+HARD }, /* 01 0 1010: stswx */ - { 0, ST+HARD }, /* 01 0 1011: stswi */ + { 4, LD+M+HARD+SX }, /* 01 0 1000: lswx */ + { 4, LD+M+HARD }, /* 01 0 1001: lswi */ + { 4, ST+M+HARD+SX }, /* 01 0 1010: stswx */ + { 4, ST+M+HARD }, /* 01 0 1011: stswi */ INVALID, /* 01 0 1100 */ INVALID, /* 01 0 1101 */ INVALID, /* 01 0 1110 */ @@ -189,7 +190,9 @@ #endif int i, t; int reg, areg; + int offset, nb0; unsigned char __user *addr; + unsigned char *rptr; union { long l; float f; @@ -206,7 +209,8 @@ * an alignment fault. -- paulus */ - instr = *((unsigned int *)regs->nip); + if (__get_user(instr, (unsigned int __user *) regs->nip)) + return 0; opcode = OPCD(instr); reg = RS(instr); areg = RA(instr); @@ -230,7 +234,7 @@ nb = aligninfo[instr].len; if (nb == 0) { - long *p; + long __user *p; int i; if (instr != DCBZ) @@ -242,13 +246,19 @@ * case when we are running with the cache disabled * for debugging. */ - p = (long *) (regs->dar & -L1_CACHE_BYTES); + p = (long __user *) (regs->dar & -L1_CACHE_BYTES); + if (user_mode(regs) + && verify_area(VERIFY_WRITE, p, L1_CACHE_BYTES)) + return -EFAULT; for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i) - p[i] = 0; + if (__put_user(0, p+i)) + return -EFAULT; return 1; } flags = aligninfo[instr].flags; + if ((flags & (LD|ST)) == 0) + return 0; /* For the 4xx-family & Book-E processors, the 'dar' field of the * pt_regs structure is overloaded and is really from the DEAR. @@ -256,6 +266,66 @@ addr = (unsigned char __user *)regs->dar; + if (flags & M) { + /* lmw, stmw, lswi/x, stswi/x */ + nb0 = 0; + if (flags & HARD) { + if (flags & SX) { + nb = regs->xer & 127; + if (nb == 0) + return 1; + } else { + if (__get_user(instr, + (unsigned int __user *)regs->nip)) + return 0; + nb = (instr >> 11) & 0x1f; + if (nb == 0) + nb = 32; + } + if (nb + reg * 4 > 128) { + nb0 = nb + reg * 4 - 128; + nb = 128 - reg * 4; + } + } else { + /* lwm, stmw */ + nb = (32 - reg) * 4; + } + rptr = (unsigned char *) ®s->gpr[reg]; + if (flags & LD) { + for (i = 0; i < nb; ++i) + if (__get_user(rptr[i], addr+i)) + return -EFAULT; + if (nb0 > 0) { + rptr = (unsigned char *) ®s->gpr[0]; + addr += nb; + for (i = 0; i < nb0; ++i) + if (__get_user(rptr[i], addr+i)) + return -EFAULT; + } + for (; (i & 3) != 0; ++i) + rptr[i] = 0; + } else { + for (i = 0; i < nb; ++i) + if (__put_user(rptr[i], addr+i)) + return -EFAULT; + if (nb0 > 0) { + rptr = (unsigned char *) ®s->gpr[0]; + addr += nb; + for (i = 0; i < nb0; ++i) + if (__put_user(rptr[i], addr+i)) + return -EFAULT; + } + } + return 1; + } + + offset = 0; + if (nb < 4) { + /* read/write the least significant bits */ + data.l = 0; + offset = 4 - nb; + } + /* Verify the address of the operand */ if (user_mode(regs)) { if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb)) @@ -268,45 +338,26 @@ giveup_fpu(current); preempt_enable(); } - if (flags & M) - return 0; /* too hard for now */ - /* If we read the operand, copy it in */ + /* If we read the operand, copy it in, else get register values */ if (flags & LD) { - if (nb == 2) { - data.v[0] = data.v[1] = 0; - if (__get_user(data.v[2], addr) - || __get_user(data.v[3], addr+1)) + for (i = 0; i < nb; ++i) + if (__get_user(data.v[offset+i], addr+i)) return -EFAULT; - } else { - for (i = 0; i < nb; ++i) - if (__get_user(data.v[i], addr+i)) - return -EFAULT; - } + } else if (flags & F) { + data.d = current->thread.fpr[reg]; + } else { + data.l = regs->gpr[reg]; } switch (flags & ~U) { - case LD+SE: + case LD+SE: /* sign extend */ if (data.v[2] >= 0x80) data.v[0] = data.v[1] = -1; - /* fall through */ - case LD: - regs->gpr[reg] = data.l; - break; - case LD+S: - if (nb == 2) { - SWAP(data.v[2], data.v[3]); - } else { - SWAP(data.v[0], data.v[3]); - SWAP(data.v[1], data.v[2]); - } - regs->gpr[reg] = data.l; - break; - case ST: - data.l = regs->gpr[reg]; break; + + case LD+S: /* byte-swap */ case ST+S: - data.l = regs->gpr[reg]; if (nb == 2) { SWAP(data.v[2], data.v[3]); } else { @@ -314,50 +365,34 @@ SWAP(data.v[1], data.v[2]); } break; - case LD+F: - current->thread.fpr[reg] = data.d; - break; - case ST+F: - data.d = current->thread.fpr[reg]; - break; - /* these require some floating point conversions... */ - /* we'd like to use the assignment, but we have to compile - * the kernel with -msoft-float so it doesn't use the - * fp regs for copying 8-byte objects. */ + + /* Single-precision FP load and store require conversions... */ case LD+F+S: preempt_disable(); enable_kernel_fp(); - cvt_fd(&data.f, ¤t->thread.fpr[reg], ¤t->thread.fpscr); - /* current->thread.fpr[reg] = data.f; */ + cvt_fd(&data.f, &data.d, ¤t->thread.fpscr); preempt_enable(); break; case ST+F+S: preempt_disable(); enable_kernel_fp(); - cvt_df(¤t->thread.fpr[reg], &data.f, ¤t->thread.fpscr); - /* data.f = current->thread.fpr[reg]; */ + cvt_df(&data.d, &data.f, ¤t->thread.fpscr); preempt_enable(); break; - default: - printk("align: can't handle flags=%x\n", flags); - return 0; } if (flags & ST) { - if (nb == 2) { - if (__put_user(data.v[2], addr) - || __put_user(data.v[3], addr+1)) + for (i = 0; i < nb; ++i) + if (__put_user(data.v[offset+i], addr+i)) return -EFAULT; - } else { - for (i = 0; i < nb; ++i) - if (__put_user(data.v[i], addr+i)) - return -EFAULT; - } + } else if (flags & F) { + current->thread.fpr[reg] = data.d; + } else { + regs->gpr[reg] = data.l; } - if (flags & U) { + if (flags & U) regs->gpr[areg] = regs->dar; - } return 1; } diff -Nru a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c --- a/arch/ppc/kernel/asm-offsets.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/kernel/asm-offsets.c 2004-10-18 14:56:32 -07:00 @@ -129,6 +129,13 @@ DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); + DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); return 0; } diff -Nru a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S --- a/arch/ppc/kernel/cpu_setup_6xx.S 2004-10-18 14:56:17 -07:00 +++ b/arch/ppc/kernel/cpu_setup_6xx.S 2004-10-18 14:56:17 -07:00 @@ -172,9 +172,9 @@ setup_750cx: mfspr r10, SPRN_HID1 rlwinm r10,r10,4,28,31 - cmpi cr0,r10,7 - cmpi cr1,r10,9 - cmpi cr2,r10,11 + cmpwi cr0,r10,7 + cmpwi cr1,r10,9 + cmpwi cr2,r10,11 cror 4*cr0+eq,4*cr0+eq,4*cr1+eq cror 4*cr0+eq,4*cr0+eq,4*cr2+eq bnelr @@ -218,10 +218,10 @@ /* All of the bits we have to set..... */ - ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_LRSTK + ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_LRSTK | HID0_BTIC BEGIN_FTR_SECTION - ori r11,r11,HID0_BTIC -END_FTR_SECTION_IFCLR(CPU_FTR_NO_BTIC) + xori r11,r11,HID0_BTIC +END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC) BEGIN_FTR_SECTION oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) @@ -287,12 +287,12 @@ /* Now deal with CPU type dependent registers */ mfspr r3,PVR srwi r3,r3,16 - cmpli cr0,r3,0x8000 /* 7450 */ - cmpli cr1,r3,0x000c /* 7400 */ - cmpli cr2,r3,0x800c /* 7410 */ - cmpli cr3,r3,0x8001 /* 7455 */ - cmpli cr4,r3,0x8002 /* 7457 */ - cmpli cr5,r3,0x7000 /* 750FX */ + cmplwi cr0,r3,0x8000 /* 7450 */ + cmplwi cr1,r3,0x000c /* 7400 */ + cmplwi cr2,r3,0x800c /* 7410 */ + cmplwi cr3,r3,0x8001 /* 7455 */ + cmplwi cr4,r3,0x8002 /* 7457 */ + cmplwi cr5,r3,0x7000 /* 750FX */ /* cr1 is 7400 || 7410 */ cror 4*cr1+eq,4*cr1+eq,4*cr2+eq /* cr0 is 74xx */ @@ -323,7 +323,7 @@ /* If rev 2.x, backup HID2 */ mfspr r3,PVR andi. r3,r3,0xff00 - cmpi cr0,r3,0x0200 + cmpwi cr0,r3,0x0200 bne 1f mfspr r4,SPRN_HID2 stw r4,CS_HID2(r5) @@ -354,12 +354,12 @@ /* Now deal with CPU type dependent registers */ mfspr r3,PVR srwi r3,r3,16 - cmpli cr0,r3,0x8000 /* 7450 */ - cmpli cr1,r3,0x000c /* 7400 */ - cmpli cr2,r3,0x800c /* 7410 */ - cmpli cr3,r3,0x8001 /* 7455 */ - cmpli cr4,r3,0x8002 /* 7457 */ - cmpli cr5,r3,0x7000 /* 750FX */ + cmplwi cr0,r3,0x8000 /* 7450 */ + cmplwi cr1,r3,0x000c /* 7400 */ + cmplwi cr2,r3,0x800c /* 7410 */ + cmplwi cr3,r3,0x8001 /* 7455 */ + cmplwi cr4,r3,0x8002 /* 7457 */ + cmplwi cr5,r3,0x7000 /* 750FX */ /* cr1 is 7400 || 7410 */ cror 4*cr1+eq,4*cr1+eq,4*cr2+eq /* cr0 is 74xx */ @@ -412,7 +412,7 @@ /* If rev 2.x, restore HID2 with low voltage bit cleared */ mfspr r3,PVR andi. r3,r3,0xff00 - cmpi cr0,r3,0x0200 + cmpwi cr0,r3,0x0200 bne 4f lwz r4,CS_HID2(r5) rlwinm r4,r4,0,19,17 @@ -426,7 +426,7 @@ mftbl r5 3: mftbl r6 sub r6,r6,r5 - cmpli cr0,r6,10000 + cmplwi cr0,r6,10000 ble 3b /* Setup final PLL */ mtspr SPRN_HID1,r4 diff -Nru a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S --- a/arch/ppc/kernel/cpu_setup_power4.S 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/kernel/cpu_setup_power4.S 2004-10-18 14:56:49 -07:00 @@ -112,7 +112,9 @@ /* We only deal with 970 for now */ mfspr r0,SPRN_PVR srwi r0,r0,16 - cmpwi r0,0x39 + cmpwi cr0,r0,0x39 + cmpwi cr1,r0,0x3c + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq bne 1f /* Save HID0,1,4 and 5 */ @@ -144,7 +146,9 @@ /* We only deal with 970 for now */ mfspr r0,SPRN_PVR srwi r0,r0,16 - cmpwi r0,0x39 + cmpwi cr0,r0,0x39 + cmpwi cr1,r0,0x3c + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq bne 1f /* Clear interrupt prefix */ diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c --- a/arch/ppc/kernel/cputable.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/kernel/cputable.c 2004-10-18 14:56:32 -07:00 @@ -55,7 +55,7 @@ #endif /* We need to mark all pages as being coherent if we're SMP or we - * have a 754x and an MPC107 host bridge. + * have a 74[45]x and an MPC107 host bridge. */ #if defined(CONFIG_SMP) || defined(CONFIG_MPC10X_BRIDGE) #define CPU_FTR_COMMON CPU_FTR_NEED_COHERENT @@ -63,6 +63,17 @@ #define CPU_FTR_COMMON 0 #endif +/* The powersave features NAP & DOZE seems to confuse BDI when + debugging. So if a BDI is used, disable theses + */ +#ifndef CONFIG_BDI_SWITCH +#define CPU_FTR_MAYBE_CAN_DOZE CPU_FTR_CAN_DOZE +#define CPU_FTR_MAYBE_CAN_NAP CPU_FTR_CAN_NAP +#else +#define CPU_FTR_MAYBE_CAN_DOZE 0 +#define CPU_FTR_MAYBE_CAN_NAP 0 +#endif + struct cpu_spec cpu_specs[] = { #if CLASSIC_PPC { /* 601 */ @@ -76,8 +87,8 @@ { /* 603 */ 0xffff0000, 0x00030000, "603", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -85,8 +96,8 @@ { /* 603e */ 0xffff0000, 0x00060000, "603e", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -94,8 +105,8 @@ { /* 603ev */ 0xffff0000, 0x00070000, "603ev", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -139,8 +150,8 @@ { /* 740/750 (0x4202, don't support TAU ?) */ 0xffffffff, 0x00084202, "740/750", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -148,8 +159,8 @@ { /* 745/755 */ 0xfffff000, 0x00083000, "745/755", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -157,8 +168,8 @@ { /* 750CX (80100 and 8010x?) */ 0xfffffff0, 0x00080100, "750CX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750cx @@ -166,8 +177,8 @@ { /* 750CX (82201 and 82202) */ 0xfffffff0, 0x00082200, "750CX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750cx @@ -175,8 +186,8 @@ { /* 750CXe (82214) */ 0xfffffff0, 0x00082210, "750CXe", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750cx @@ -184,8 +195,8 @@ { /* 750FX rev 1.x */ 0xffffff00, 0x70000100, "750FX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM, COMMON_PPC, 32, 32, @@ -194,8 +205,8 @@ { /* 750FX rev 2.0 must disable HID0[DPM] */ 0xffffffff, 0x70000200, "750FX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NO_DPM, COMMON_PPC, 32, 32, @@ -204,8 +215,8 @@ { /* 750FX (All revs except 2.0) */ 0xffff0000, 0x70000000, "750FX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC, 32, 32, @@ -213,8 +224,8 @@ }, { /* 750GX */ 0xffff0000, 0x70020000, "750GX", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC, 32, 32, @@ -223,8 +234,8 @@ { /* 740/750 (L2CR bit need fixup for 740) */ 0xffff0000, 0x00080000, "740/750", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -232,9 +243,9 @@ { /* 7400 rev 1.1 ? (no TAU) */ 0xffffffff, 0x000c1101, "7400 (1.1)", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | - CPU_FTR_CAN_NAP, + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, 32, 32, __setup_cpu_7400 @@ -242,9 +253,9 @@ { /* 7400 */ 0xffff0000, 0x000c0000, "7400", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | - CPU_FTR_CAN_NAP, + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, 32, 32, __setup_cpu_7400 @@ -252,9 +263,9 @@ { /* 7410 */ 0xffff0000, 0x800c0000, "7410", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | - CPU_FTR_CAN_NAP, + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, 32, 32, __setup_cpu_7410 @@ -272,7 +283,7 @@ { /* 7450 2.1 */ 0xffffffff, 0x80000201, "7450", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | CPU_FTR_NEED_COHERENT, @@ -283,7 +294,7 @@ { /* 7450 2.3 and newer */ 0xffff0000, 0x80000000, "7450", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT, @@ -305,7 +316,7 @@ { /* 7455 rev 2.0 */ 0xffffffff, 0x80010200, "7455", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS, @@ -316,7 +327,7 @@ { /* 7455 others */ 0xffff0000, 0x80010000, "7455", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, @@ -327,7 +338,7 @@ { /* 7447/7457 Rev 1.0 */ 0xffffffff, 0x80020100, "7447/7457", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC, @@ -338,7 +349,7 @@ { /* 7447/7457 Rev 1.1 */ 0xffffffff, 0x80020101, "7447/7457", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC, @@ -349,7 +360,7 @@ { /* 7447/7457 Rev 1.2 and later */ 0xffff0000, 0x80020000, "7447/7457", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, @@ -360,7 +371,7 @@ { /* 7447A */ 0xffff0000, 0x80030000, "7447A", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, @@ -371,15 +382,15 @@ { /* 82xx (8240, 8245, 8260 are all 603e cores) */ 0x7fff0000, 0x00810000, "82xx", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB, COMMON_PPC, 32, 32, __setup_cpu_603 }, { /* All G2_LE (603e core, plus some) have the same pvr */ 0x7fff0000, 0x00820000, "G2_LE", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -440,7 +451,16 @@ 0xffff0000, 0x00390000, "PPC970", CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP, + CPU_FTR_ALTIVEC_COMP | CPU_FTR_MAYBE_CAN_NAP, + COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_ALTIVEC_COMP, + 128, 128, + __setup_cpu_ppc970 + }, + { /* PPC970FX */ + 0xffff0000, 0x003c0000, "PPC970FX", + CPU_FTR_COMMON | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_ALTIVEC_COMP | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_ALTIVEC_COMP, 128, 128, __setup_cpu_ppc970 @@ -449,7 +469,8 @@ #ifdef CONFIG_8xx { /* 8xx */ 0xffff0000, 0x00500000, "8xx", - /* CPU_FTR_CAN_DOZE is possible, if the 8xx code is there.... */ + /* CPU_FTR_MAYBE_CAN_DOZE is possible, + * if the 8xx code is there.... */ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, 16, 16, @@ -590,7 +611,7 @@ #ifdef CONFIG_E500 { /* e500 */ 0xffff0000, 0x80200000, "e500", - /* xxx - galak: add CPU_FTR_CAN_DOZE */ + /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, 32, 32, diff -Nru a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c --- a/arch/ppc/kernel/dma-mapping.c 2004-10-18 14:55:46 -07:00 +++ b/arch/ppc/kernel/dma-mapping.c 2004-10-18 14:55:46 -07:00 @@ -41,11 +41,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -381,6 +381,7 @@ break; } } +EXPORT_SYMBOL(__dma_sync); #ifdef CONFIG_HIGHMEM /* @@ -438,3 +439,4 @@ __dma_sync((void *)start, size, direction); #endif } +EXPORT_SYMBOL(__dma_sync_page); diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S --- a/arch/ppc/kernel/entry.S 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/kernel/entry.S 2004-10-18 14:57:03 -07:00 @@ -206,7 +206,7 @@ andi. r11,r11,_TIF_SYSCALL_TRACE bne- syscall_dotrace syscall_dotrace_cont: - cmpli 0,r0,NR_syscalls + cmplwi 0,r0,NR_syscalls lis r10,sys_call_table@h ori r10,r10,sys_call_table@l slwi r0,r0,2 @@ -222,7 +222,7 @@ #endif mr r6,r3 li r11,-_LAST_ERRNO - cmpl 0,r3,r11 + cmplw 0,r3,r11 rlwinm r12,r1,0,0,18 /* current_thread_info() */ blt+ 30f lwz r11,TI_LOCAL_FLAGS(r12) diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S --- a/arch/ppc/kernel/head.S 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/kernel/head.S 2004-10-18 14:56:32 -07:00 @@ -800,7 +800,7 @@ tophys(r6,0) /* get __pa constant */ addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f add r4,r4,r6 addi r4,r4,THREAD /* want last_task_used_math->thread */ @@ -927,7 +927,7 @@ tophys(r6,0) addis r3,r6,last_task_used_altivec@ha lwz r4,last_task_used_altivec@l(r3) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f add r4,r4,r6 addi r4,r4,THREAD /* want THREAD of last_task_used_altivec */ @@ -992,11 +992,11 @@ SYNC MTMSRD(r5) /* enable use of AltiVec now */ isync - cmpi 0,r3,0 + cmpwi 0,r3,0 beqlr- /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) - cmpi 0,r5,0 + cmpwi 0,r5,0 SAVE_32VR(0, r4, r3) mfvscr vr0 li r4,THREAD_VSCR @@ -1030,11 +1030,11 @@ MTMSRD(r5) /* enable use of fpu now */ SYNC_601 isync - cmpi 0,r3,0 + cmpwi 0,r3,0 beqlr- /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) - cmpi 0,r5,0 + cmpwi 0,r5,0 SAVE_32FPRS(0, r3) mffs fr0 stfd fr0,THREAD_FPSCR-4(r3) @@ -1539,7 +1539,7 @@ #ifndef CONFIG_PPC64BRIDGE mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 + cmpwi 0,r9,1 bne 4f ori r11,r11,4 /* set up BAT registers for 601 */ li r8,0x7f /* valid, block length = 8MB */ @@ -1591,7 +1591,7 @@ lwz r8,4(r8) mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 + cmpwi 0,r9,1 beq 1f mtspr DBAT3L,r8 mtspr DBAT3U,r11 diff -Nru a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S --- a/arch/ppc/kernel/head_44x.S 2004-10-18 14:56:27 -07:00 +++ b/arch/ppc/kernel/head_44x.S 2004-10-18 14:56:27 -07:00 @@ -41,16 +41,9 @@ #include #include #include +#include "head_booke.h" -/* - * Macros - */ -#define SET_IVOR(vector_number, vector_label) \ - li r26,vector_label@l; \ - mtspr SPRN_IVOR##vector_number,r26; \ - sync - /* As with the other PowerPC ports, it is expected that when code * execution begins here, the following registers contain valid, yet * optional, information: @@ -301,234 +294,6 @@ * Interrupt vectors must be aligned on a 16 byte boundary. * We align on a 32 byte cache line boundary for good measure. */ - -#define NORMAL_EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ - mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG4W,r1; \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - beq 1f; \ - mfspr r1,SPRG3; /* if from user, start at top of */\ - lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ - addi r1,r1,THREAD_SIZE; \ -1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r1); \ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r10,SPRG4R; \ - mfspr r12,SRR0; \ - stw r10,GPR1(r11); \ - mfspr r9,SRR1; \ - stw r10,0(r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for critical exceptions. This is a little different - * from the normal exception prolog above since a critical exception - * can potentially occur at any point during normal exception processing. - * Thus we cannot use the same SPRG registers as the normal prolog above. - * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. For Book E - * processors, we also have a reserved register (SPRG2) that is only used - * in critical exceptions so we can free up a GPR to use as the base for - * indirect access to the critical exception save area. This is necessary - * since the MMU is always on and the save area is offset from KERNELBASE. - */ -#define CRITICAL_EXCEPTION_PROLOG \ - mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ - lis r8,crit_save@ha; \ - stw r10,crit_r10@l(r8); \ - stw r11,crit_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,crit_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,crit_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,crit_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,crit_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,crit_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,crit_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,crit_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,crit_srr1@l(r8); \ - mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,critical_stack_top@h; \ - ori r11,r11,critical_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,CSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,CSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for machine check exceptions. This is similar to - * the critical exception prolog, except that machine check exceptions - * have their own save area. For Book E processors, we also have a - * reserved register (SPRG6) that is only used in machine check exceptions - * so we can free up a GPR to use as the base for indirect access to the - * machine check exception save area. This is necessary since the MMU - * is always on and the save area is offset from KERNELBASE. - */ -#define MCHECK_EXCEPTION_PROLOG \ - mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ - lis r8,mcheck_save@ha; \ - stw r10,mcheck_r10@l(r8); \ - stw r11,mcheck_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,mcheck_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,mcheck_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,mcheck_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,mcheck_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,mcheck_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,mcheck_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,mcheck_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,mcheck_srr1@l(r8); \ - mfspr r10,CSRR0; \ - stw r10,mcheck_csrr0@l(r8); \ - mfspr r10,CSRR1; \ - stw r10,mcheck_csrr1@l(r8); \ - mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,mcheck_stack_top@h; \ - ori r11,r11,mcheck_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,MCSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,MCSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception vectors. - */ -#define START_EXCEPTION(label) \ - .align 5; \ -label: - -#define FINISH_EXCEPTION(func) \ - bl transfer_to_handler_full; \ - .long func; \ - .long ret_from_except_full - -#define EXCEPTION(n, label, hdlr, xfer) \ - START_EXCEPTION(label); \ - NORMAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define CRITICAL_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - CRITICAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define MCHECK_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - MCHECK_EXCEPTION_PROLOG; \ - lis r4,MCSR_MCS@h; \ - mtspr SPRN_MCSR,r4; \ - mfspr r5,SPRN_ESR; \ - stw r5,_ESR(r11); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, mcheck_transfer_to_handler, \ - ret_from_mcheck_exc) - -#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - lis r10,msr@h; \ - ori r10,r10,msr@l; \ - copyee(r10, r9); \ - bl tfer; \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ - ret_from_except) interrupt_base: /* Critical Input Interrupt */ diff -Nru a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/kernel/head_booke.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,240 @@ +#ifndef __HEAD_BOOKE_H__ +#define __HEAD_BOOKE_H__ + +/* + * Macros used for common Book-e exception handling + */ + +#define SET_IVOR(vector_number, vector_label) \ + li r26,vector_label@l; \ + mtspr SPRN_IVOR##vector_number,r26; \ + sync + +#define NORMAL_EXCEPTION_PROLOG \ + mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ + mtspr SPRN_SPRG1,r11; \ + mtspr SPRN_SPRG4W,r1; \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + beq 1f; \ + mfspr r1,SPRG3; /* if from user, start at top of */\ + lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ + addi r1,r1,THREAD_SIZE; \ +1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ + tophys(r11,r1); \ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mfspr r10,SPRG0; \ + stw r10,GPR10(r11); \ + mfspr r12,SPRG1; \ + stw r12,GPR11(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r10,SPRG4R; \ + mfspr r12,SRR0; \ + stw r10,GPR1(r11); \ + mfspr r9,SRR1; \ + stw r10,0(r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception prolog for critical exceptions. This is a little different + * from the normal exception prolog above since a critical exception + * can potentially occur at any point during normal exception processing. + * Thus we cannot use the same SPRG registers as the normal prolog above. + * Instead we use a couple of words of memory at low physical addresses. + * This is OK since we don't support SMP on these processors. For Book E + * processors, we also have a reserved register (SPRG2) that is only used + * in critical exceptions so we can free up a GPR to use as the base for + * indirect access to the critical exception save area. This is necessary + * since the MMU is always on and the save area is offset from KERNELBASE. + */ +#define CRITICAL_EXCEPTION_PROLOG \ + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ + lis r8,crit_save@ha; \ + stw r10,crit_r10@l(r8); \ + stw r11,crit_r11@l(r8); \ + mfspr r10,SPRG0; \ + stw r10,crit_sprg0@l(r8); \ + mfspr r10,SPRG1; \ + stw r10,crit_sprg1@l(r8); \ + mfspr r10,SPRG4R; \ + stw r10,crit_sprg4@l(r8); \ + mfspr r10,SPRG5R; \ + stw r10,crit_sprg5@l(r8); \ + mfspr r10,SPRG7R; \ + stw r10,crit_sprg7@l(r8); \ + mfspr r10,SPRN_PID; \ + stw r10,crit_pid@l(r8); \ + mfspr r10,SRR0; \ + stw r10,crit_srr0@l(r8); \ + mfspr r10,SRR1; \ + stw r10,crit_srr1@l(r8); \ + mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,critical_stack_top@h; \ + ori r11,r11,critical_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,CSRR0; \ + stw r1,GPR1(r11); \ + mfspr r9,CSRR1; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception prolog for machine check exceptions. This is similar to + * the critical exception prolog, except that machine check exceptions + * have their own save area. For Book E processors, we also have a + * reserved register (SPRG6) that is only used in machine check exceptions + * so we can free up a GPR to use as the base for indirect access to the + * machine check exception save area. This is necessary since the MMU + * is always on and the save area is offset from KERNELBASE. + */ +#define MCHECK_EXCEPTION_PROLOG \ + mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ + lis r8,mcheck_save@ha; \ + stw r10,mcheck_r10@l(r8); \ + stw r11,mcheck_r11@l(r8); \ + mfspr r10,SPRG0; \ + stw r10,mcheck_sprg0@l(r8); \ + mfspr r10,SPRG1; \ + stw r10,mcheck_sprg1@l(r8); \ + mfspr r10,SPRG4R; \ + stw r10,mcheck_sprg4@l(r8); \ + mfspr r10,SPRG5R; \ + stw r10,mcheck_sprg5@l(r8); \ + mfspr r10,SPRG7R; \ + stw r10,mcheck_sprg7@l(r8); \ + mfspr r10,SPRN_PID; \ + stw r10,mcheck_pid@l(r8); \ + mfspr r10,SRR0; \ + stw r10,mcheck_srr0@l(r8); \ + mfspr r10,SRR1; \ + stw r10,mcheck_srr1@l(r8); \ + mfspr r10,CSRR0; \ + stw r10,mcheck_csrr0@l(r8); \ + mfspr r10,CSRR1; \ + stw r10,mcheck_csrr1@l(r8); \ + mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,mcheck_stack_top@h; \ + ori r11,r11,mcheck_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,MCSRR0; \ + stw r1,GPR1(r11); \ + mfspr r9,MCSRR1; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception vectors. + */ +#define START_EXCEPTION(label) \ + .align 5; \ +label: + +#define FINISH_EXCEPTION(func) \ + bl transfer_to_handler_full; \ + .long func; \ + .long ret_from_except_full + +#define EXCEPTION(n, label, hdlr, xfer) \ + START_EXCEPTION(label); \ + NORMAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + xfer(n, hdlr) + +#define CRITICAL_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(label); \ + CRITICAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define MCHECK_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(label); \ + MCHECK_EXCEPTION_PROLOG; \ + mfspr r5,SPRN_ESR; \ + stw r5,_ESR(r11); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, mcheck_transfer_to_handler, \ + ret_from_mcheck_exc) + +#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ + li r10,trap; \ + stw r10,TRAP(r11); \ + lis r10,msr@h; \ + ori r10,r10,msr@l; \ + copyee(r10, r9); \ + bl tfer; \ + .long hdlr; \ + .long ret + +#define COPY_EE(d, s) rlwimi d,s,0,16,16 +#define NOCOPY(d, s) + +#define EXC_XFER_STD(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ + ret_from_except) + +#define EXC_XFER_EE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_EE_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ + ret_from_except) + + +#endif /* __HEAD_BOOKE_H__ */ diff -Nru a/arch/ppc/kernel/head_e500.S b/arch/ppc/kernel/head_e500.S --- a/arch/ppc/kernel/head_e500.S 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/kernel/head_e500.S 2004-10-18 14:56:49 -07:00 @@ -41,15 +41,7 @@ #include #include #include - -/* - * Macros - */ - -#define SET_IVOR(vector_number, vector_label) \ - li r26,vector_label@l; \ - mtspr SPRN_IVOR##vector_number,r26; \ - sync +#include "head_booke.h" /* As with the other PowerPC ports, it is expected that when code * execution begins here, the following registers contain valid, yet @@ -370,232 +362,6 @@ * Interrupt vectors must be aligned on a 16 byte boundary. * We align on a 32 byte cache line boundary for good measure. */ - -#define NORMAL_EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ - mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG4W,r1; \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - beq 1f; \ - mfspr r1,SPRG3; /* if from user, start at top of */\ - lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ - addi r1,r1,THREAD_SIZE; \ -1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r1); \ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r10,SPRG4R; \ - mfspr r12,SRR0; \ - stw r10,GPR1(r11); \ - mfspr r9,SRR1; \ - stw r10,0(r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for critical exceptions. This is a little different - * from the normal exception prolog above since a critical exception - * can potentially occur at any point during normal exception processing. - * Thus we cannot use the same SPRG registers as the normal prolog above. - * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. For Book E - * processors, we also have a reserved register (SPRG2) that is only used - * in critical exceptions so we can free up a GPR to use as the base for - * indirect access to the critical exception save area. This is necessary - * since the MMU is always on and the save area is offset from KERNELBASE. - */ -#define CRITICAL_EXCEPTION_PROLOG \ - mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ - lis r8,crit_save@ha; \ - stw r10,crit_r10@l(r8); \ - stw r11,crit_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,crit_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,crit_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,crit_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,crit_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,crit_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,crit_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,crit_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,crit_srr1@l(r8); \ - mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,critical_stack_top@h; \ - ori r11,r11,critical_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,CSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,CSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for machine check exceptions. This is similar to - * the critical exception prolog, except that machine check exceptions - * have their own save area. For Book E processors, we also have a - * reserved register (SPRG6) that is only used in machine check exceptions - * so we can free up a GPR to use as the base for indirect access to the - * machine check exception save area. This is necessary since the MMU - * is always on and the save area is offset from KERNELBASE. - */ -#define MCHECK_EXCEPTION_PROLOG \ - mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ - lis r8,mcheck_save@ha; \ - stw r10,mcheck_r10@l(r8); \ - stw r11,mcheck_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,mcheck_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,mcheck_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,mcheck_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,mcheck_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,mcheck_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,mcheck_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,mcheck_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,mcheck_srr1@l(r8); \ - mfspr r10,CSRR0; \ - stw r10,mcheck_csrr0@l(r8); \ - mfspr r10,CSRR1; \ - stw r10,mcheck_csrr1@l(r8); \ - mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,mcheck_stack_top@h; \ - ori r11,r11,mcheck_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,MCSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,MCSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception vectors. - */ -#define START_EXCEPTION(label) \ - .align 5; \ -label: - -#define FINISH_EXCEPTION(func) \ - bl transfer_to_handler_full; \ - .long func; \ - .long ret_from_except_full - -#define EXCEPTION(n, label, hdlr, xfer) \ - START_EXCEPTION(label); \ - NORMAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define CRITICAL_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - CRITICAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define MCHECK_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - MCHECK_EXCEPTION_PROLOG; \ - mfspr r5,SPRN_ESR; \ - stw r5,_ESR(r11); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, mcheck_transfer_to_handler, \ - ret_from_mcheck_exc) - -#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - lis r10,msr@h; \ - ori r10,r10,msr@l; \ - copyee(r10, r9); \ - bl tfer; \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ - ret_from_except) interrupt_base: /* Critical Input Interrupt */ diff -Nru a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c --- a/arch/ppc/kernel/idle.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/kernel/idle.c 2004-10-18 14:55:54 -07:00 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -65,3 +66,36 @@ default_idle(); return 0; } + +#if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx) +/* + * Register the sysctl to set/clear powersave_nap. + */ +extern unsigned long powersave_nap; + +static ctl_table powersave_nap_ctl_table[]={ + { + .ctl_name = KERN_PPC_POWERSAVE_NAP, + .procname = "powersave-nap", + .data = &powersave_nap, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { 0, }, +}; +static ctl_table powersave_nap_sysctl_root[] = { + { 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, }, + { 0,}, +}; + +static int __init +register_powersave_nap_sysctl(void) +{ + register_sysctl_table(powersave_nap_sysctl_root, 0); + + return 0; +} + +__initcall(register_powersave_nap_sysctl); +#endif diff -Nru a/arch/ppc/kernel/idle_6xx.S b/arch/ppc/kernel/idle_6xx.S --- a/arch/ppc/kernel/idle_6xx.S 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc/kernel/idle_6xx.S 2004-10-18 14:56:33 -07:00 @@ -79,12 +79,12 @@ /* Now check if user or arch enabled NAP mode */ lis r4,powersave_nap@ha lwz r4,powersave_nap@l(r4) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f lis r3,HID0_NAP@h 1: END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) - cmpi 0,r3,0 + cmpwi 0,r3,0 beqlr /* Clear MSR:EE */ @@ -133,7 +133,7 @@ /* Go to low speed mode on some 750FX */ lis r4,powersave_lowspeed@ha lwz r4,powersave_lowspeed@l(r4) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f mfspr r4,SPRN_HID1 oris r4,r4,0x0001 diff -Nru a/arch/ppc/kernel/idle_power4.S b/arch/ppc/kernel/idle_power4.S --- a/arch/ppc/kernel/idle_power4.S 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc/kernel/idle_power4.S 2004-10-18 14:55:55 -07:00 @@ -56,7 +56,7 @@ /* Now check if user or arch enabled NAP mode */ lis r4,powersave_nap@ha lwz r4,powersave_nap@l(r4) - cmpi 0,r4,0 + cmpwi 0,r4,0 beqlr /* Clear MSR:EE */ diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c --- a/arch/ppc/kernel/irq.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/kernel/irq.c 2004-10-18 14:56:49 -07:00 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -414,13 +415,15 @@ handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) { int status = 0; + int ret; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -620,32 +623,6 @@ return full_count; } -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - int err; - int full_count = count; - cpumask_t *mask = (cpumask_t *)data; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -673,23 +650,14 @@ smp_affinity_entry[irq] = entry; } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); - /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/kernel/misc.S 2004-10-18 14:57:03 -07:00 @@ -214,7 +214,7 @@ mtmsr r0 /* If switching to PLL1, disable HID0:BTIC */ - cmpli cr0,r3,0 + cmplwi cr0,r3,0 beq 1f mfspr r5,HID0 rlwinm r5,r5,0,27,25 @@ -239,7 +239,7 @@ stw r4,nap_save_hid1@l(r6) /* If switching to PLL0, enable HID0:BTIC */ - cmpli cr0,r3,0 + cmplwi cr0,r3,0 bne 1f mfspr r5,HID0 ori r5,r5,HID0_BTIC @@ -470,7 +470,7 @@ ori r9,r9,mmu_hash_lock@l tophys(r9,r9) 10: lwarx r7,0,r9 - cmpi 0,r7,0 + cmpwi 0,r7,0 bne- 10b stwcx. r8,0,r9 bne- 10b @@ -551,7 +551,7 @@ ori r9,r9,mmu_hash_lock@l tophys(r9,r9) 10: lwarx r7,0,r9 - cmpi 0,r7,0 + cmpwi 0,r7,0 bne- 10b stwcx. r8,0,r9 bne- 10b @@ -599,7 +599,7 @@ #else mfspr r3,PVR rlwinm r3,r3,16,16,31 - cmpi 0,r3,1 + cmpwi 0,r3,1 beqlr /* for 601, do nothing */ /* 603/604 processor - use invalidate-all bit in HID0 */ mfspr r3,HID0 @@ -617,10 +617,9 @@ * flush_icache_range(unsigned long start, unsigned long stop) */ _GLOBAL(flush_icache_range) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ +BEGIN_FTR_SECTION + blr /* for 601, do nothing */ +END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE) li r5,L1_CACHE_LINE_SIZE-1 andc r3,r3,r5 subf r4,r3,r4 @@ -735,10 +734,9 @@ * void __flush_dcache_icache(void *page) */ _GLOBAL(__flush_dcache_icache) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ +BEGIN_FTR_SECTION + blr /* for 601, do nothing */ +END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE) rlwinm r3,r3,0,0,19 /* Get page base address */ li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ mtctr r4 @@ -764,10 +762,9 @@ * void __flush_dcache_icache_phys(unsigned long physaddr) */ _GLOBAL(__flush_dcache_icache_phys) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ +BEGIN_FTR_SECTION + blr /* for 601, do nothing */ +END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE) mfmsr r10 rlwinm r0,r10,0,28,26 /* clear DR */ mtmsr r0 @@ -1144,7 +1141,7 @@ li r4,0 /* new sp (unused) */ li r0,__NR_clone sc - cmpi 0,r3,0 /* parent or child? */ + cmpwi 0,r3,0 /* parent or child? */ bne 1f /* return if parent */ li r0,0 /* make top-level stack frame */ stwu r0,-16(r1) diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c --- a/arch/ppc/kernel/pci.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc/kernel/pci.c 2004-10-18 14:56:29 -07:00 @@ -33,6 +33,7 @@ unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; +int pcibios_assign_bus_offset = 1; void pcibios_make_OF_bus_map(void); @@ -45,11 +46,6 @@ static int reparent_resources(struct resource *parent, struct resource *res); static void fixup_rev1_53c810(struct pci_dev* dev); static void fixup_cpc710_pci64(struct pci_dev* dev); -#ifdef CONFIG_PPC_PMAC -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; #endif @@ -64,20 +60,6 @@ static int pci_bus_count; -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64}, - { 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, 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 } -}; - static void fixup_rev1_53c810(struct pci_dev* dev) { @@ -90,6 +72,7 @@ dev->class = PCI_CLASS_STORAGE_SCSI; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); static void fixup_broken_pcnet32(struct pci_dev* dev) @@ -100,6 +83,7 @@ pci_name_device(dev); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); static void fixup_cpc710_pci64(struct pci_dev* dev) @@ -112,6 +96,7 @@ dev->resource[1].start = dev->resource[1].end = 0; dev->resource[1].flags = 0; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64); static void pcibios_fixup_resources(struct pci_dev *dev) @@ -158,9 +143,9 @@ if (ppc_md.pcibios_fixup_resources) ppc_md.pcibios_fixup_resources(dev); } +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); -void -pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, +void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, struct resource *res) { unsigned long offset = 0; @@ -173,6 +158,7 @@ region->start = res->start - offset; region->end = res->end - offset; } +EXPORT_SYMBOL(pcibios_resource_to_bus); /* * We need to avoid collisions with `mirrored' VGA ports @@ -187,8 +173,7 @@ * but we want to try to avoid allocating at 0x2900-0x2bff * which might have be mirrored at 0x0100-0x03ff.. */ -void -pcibios_align_resource(void *data, struct resource *res, unsigned long size, +void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align) { struct pci_dev *dev = data; @@ -208,7 +193,7 @@ } } } - +EXPORT_SYMBOL(pcibios_align_resource); /* * Handle resources of PCI devices. If the world were perfect, we could @@ -427,7 +412,7 @@ r = &dev->resource[i]; if (!r->flags || (r->flags & IORESOURCE_UNSET)) continue; - if (pci_find_parent_resource(bus->self, r) != pr) + if (pci_find_parent_resource(dev, r) != pr) continue; if (r->end >= res->start && res->end >= r->start) { *conflict = r; @@ -1279,7 +1264,7 @@ bus = pci_scan_bus(hose->first_busno, hose->ops, hose); hose->last_busno = bus->subordinate; if (pci_assign_all_busses || next_busno <= hose->last_busno) - next_busno = hose->last_busno+1; + next_busno = hose->last_busno + pcibios_assign_bus_offset; } pci_bus_count = next_busno; @@ -1723,6 +1708,32 @@ res->sibling = NULL; res->child = NULL; } + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len) + return NULL; + if (max && len > max) + len = max; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) + return (void __iomem *) start; + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); + /* * Null PCI config access functions, for the case when we can't diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c --- a/arch/ppc/kernel/ppc_htab.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/kernel/ppc_htab.c 2004-10-18 14:55:54 -07:00 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -34,9 +35,6 @@ static int ppc_htab_show(struct seq_file *m, void *v); static ssize_t ppc_htab_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos); -int proc_dol2crvec(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos); - extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern unsigned long _SDR1; @@ -438,3 +436,32 @@ *ppos += *lenp; return 0; } + +#ifdef CONFIG_SYSCTL +/* + * Register our sysctl. + */ +static ctl_table htab_ctl_table[]={ + { + .ctl_name = KERN_PPC_L2CR, + .procname = "l2cr", + .mode = 0644, + .proc_handler = &proc_dol2crvec, + }, + { 0, }, +}; +static ctl_table htab_sysctl_root[] = { + { 1, "kernel", NULL, 0, 0755, htab_ctl_table, }, + { 0,}, +}; + +static int __init +register_ppc_htab_sysctl(void) +{ + register_sysctl_table(htab_sysctl_root, 0); + + return 0; +} + +__initcall(register_ppc_htab_sysctl); +#endif diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c --- a/arch/ppc/kernel/ppc_ksyms.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/kernel/ppc_ksyms.c 2004-10-18 14:57:03 -07:00 @@ -352,3 +352,7 @@ extern unsigned long agp_special_page; EXPORT_SYMBOL(agp_special_page); #endif +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) +EXPORT_SYMBOL(__mtdcr); +EXPORT_SYMBOL(__mfdcr); +#endif diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c --- a/arch/ppc/kernel/process.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc/kernel/process.c 2004-10-18 14:56:29 -07:00 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include extern unsigned long _get_SP(void); @@ -555,8 +555,7 @@ CHECK_FULL_REGS(regs); if (usp == 0) usp = regs->gpr[1]; /* stack pointer for child */ - return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0, - parent_tidp, child_tidp); + return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); } int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, @@ -662,7 +661,7 @@ ++count; sp = *(unsigned long *)sp; } -#if !CONFIG_KALLSYMS +#ifndef CONFIG_KALLSYMS if (count > 0) printk("\n"); #endif diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c --- a/arch/ppc/kernel/setup.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/kernel/setup.c 2004-10-18 14:57:04 -07:00 @@ -418,7 +418,6 @@ * are used for initrd_start and initrd_size, * otherwise they contain 0xdeadbeef. */ - cmd_line[0] = 0; if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { strlcpy(cmd_line, (char *)r3 + KERNELBASE, sizeof(cmd_line)); @@ -484,6 +483,9 @@ char *name; int offset; + if (of_stdout_device == NULL) + return -ENODEV; + /* The user has requested a console so this is already set up. */ if (strstr(saved_command_line, "console=")) return -EBUSY; @@ -742,6 +744,10 @@ /* Initialize OCP device list */ ocp_early_init(); if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab); +#endif + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; #endif ppc_md.setup_arch(); diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c --- a/arch/ppc/kernel/signal.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/kernel/signal.c 2004-10-18 14:57:04 -07:00 @@ -270,7 +270,7 @@ static int restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig) { - unsigned long save_r2; + unsigned long save_r2 = 0; #if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE) unsigned long msr; #endif @@ -404,9 +404,7 @@ printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int sig) @@ -556,9 +554,7 @@ printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* @@ -604,7 +600,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; - struct k_sigaction *ka; + struct k_sigaction ka; unsigned long frame, newsp; int signr, ret; @@ -613,9 +609,7 @@ newsp = frame = 0; - signr = get_signal_to_deliver(&info, regs, NULL); - - ka = (signr == 0)? NULL: ¤t->sighand->action[signr-1]; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (TRAP(regs) == 0x0C00 /* System Call! */ && regs->ccr & 0x10000000 /* error signalled */ @@ -626,7 +620,7 @@ if (signr > 0 && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK || (ret == ERESTARTSYS - && !(ka->sa.sa_flags & SA_RESTART)))) { + && !(ka.sa.sa_flags & SA_RESTART)))) { /* make the system call return an EINTR error */ regs->result = -EINTR; regs->gpr[3] = EINTR; @@ -645,7 +639,7 @@ if (signr == 0) return 0; /* no signals delivered */ - if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size + if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size && !on_sig_stack(regs->gpr[1])) newsp = current->sas_ss_sp + current->sas_ss_size; else @@ -653,17 +647,14 @@ newsp &= ~0xfUL; /* Whee! Actually deliver the signal. */ - if (ka->sa.sa_flags & SA_SIGINFO) - handle_rt_signal(signr, ka, &info, oldset, regs, newsp); + if (ka.sa.sa_flags & SA_SIGINFO) + handle_rt_signal(signr, &ka, &info, oldset, regs, newsp); else - handle_signal(signr, ka, &info, oldset, regs, newsp); - - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; + handle_signal(signr, &ka, &info, oldset, regs, newsp); - if (!(ka->sa.sa_flags & SA_NODEFER)) { + if (!(ka.sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked,¤t->blocked,&ka.sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c --- a/arch/ppc/kernel/smp.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/kernel/smp.c 2004-10-18 14:57:04 -07:00 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -364,22 +363,15 @@ int __cpu_up(unsigned int cpu) { - struct pt_regs regs; struct task_struct *p; char buf[32]; int c; /* create a process for the processor */ /* only regs.msr is actually used, and 0 is OK for it */ - memset(®s, 0, sizeof(struct pt_regs)); - p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); + p = fork_idle(cpu); if (IS_ERR(p)) panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - wake_up_forked_process(p); - - init_idle(p, cpu); - unhash_process(p); - secondary_ti = p->thread_info; p->thread_info->cpu = cpu; diff -Nru a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c --- a/arch/ppc/kernel/time.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/kernel/time.c 2004-10-18 14:56:49 -07:00 @@ -108,41 +108,18 @@ return delta; } -extern char _stext; - -static inline void ppc_do_profile (struct pt_regs *regs) +#ifdef CONFIG_SMP +unsigned long profile_pc(struct pt_regs *regs) { - unsigned long nip; - extern unsigned long prof_cpu_mask; - - profile_hook(regs); + unsigned long pc = instruction_pointer(regs); - if (user_mode(regs)) - return; + if (in_lock_functions(pc)) + return regs->link; - if (!prof_buffer) - return; - - nip = instruction_pointer(regs); - - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!((1<>= prof_shift; - /* - * Don't ignore out-of-bounds EIP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (nip > prof_len-1) - nip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[nip]); + return pc; } +EXPORT_SYMBOL(profile_pc); +#endif /* * timer_interrupt - gets called when the decrementer overflows, @@ -161,10 +138,10 @@ irq_enter(); - while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) { + while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { jiffy_stamp += tb_ticks_per_jiffy; - ppc_do_profile(regs); + profile_tick(CPU_PROFILING, regs); if (smp_processor_id()) continue; diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c --- a/arch/ppc/kernel/traps.c 2004-10-18 14:56:17 -07:00 +++ b/arch/ppc/kernel/traps.c 2004-10-18 14:56:17 -07:00 @@ -357,7 +357,7 @@ /* Illegal instruction emulation support. Originally written to * provide the PVR to user applications using the mfspr rd, PVR. - * Return non-zero if we can't emulate, or EFAULT if the associated + * Return non-zero if we can't emulate, or -EFAULT if the associated * memory access caused an access fault. Return zero on success. * * There are a couple of ways to do this, either "decode" the instruction @@ -368,16 +368,19 @@ #define INST_MFSPR_PVR 0x7c1f42a6 #define INST_MFSPR_PVR_MASK 0xfc1fffff +#define INST_DCBA 0x7c0005ec +#define INST_DCBA_MASK 0x7c0007fe + +#define INST_MCRXR 0x7c000400 +#define INST_MCRXR_MASK 0x7c0007fe + static int emulate_instruction(struct pt_regs *regs) { u32 instword; u32 rd; - int retval; - - retval = -EINVAL; if (!user_mode(regs)) - return retval; + return -EINVAL; CHECK_FULL_REGS(regs); if (get_user(instword, (u32 __user *)(regs->nip))) @@ -388,10 +391,24 @@ if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { rd = (instword >> 21) & 0x1f; regs->gpr[rd] = mfspr(PVR); - retval = 0; - regs->nip += 4; + return 0; + } + + /* Emulating the dcba insn is just a no-op. */ + if ((instword & INST_DCBA_MASK) == INST_DCBA) + return 0; + + /* Emulate the mcrxr insn. */ + if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { + int shift = (instword >> 21) & 0x1c; + unsigned long msk = 0xf0000000UL >> shift; + + regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); + regs->xer &= ~0xf0000000UL; + return 0; } - return retval; + + return -EINVAL; } /* @@ -528,17 +545,23 @@ return; } - if (reason & REASON_PRIVILEGED) { - /* Try to emulate it if we should. */ - if (emulate_instruction(regs) == 0) { + /* Try to emulate it if we should. */ + if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { + switch (emulate_instruction(regs)) { + case 0: + regs->nip += 4; emulate_single_step(regs); return; + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + return; } - _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - return; } - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + if (reason & REASON_PRIVILEGED) + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); + else + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } void SingleStepException(struct pt_regs *regs) diff -Nru a/arch/ppc/kernel/vector.S b/arch/ppc/kernel/vector.S --- a/arch/ppc/kernel/vector.S 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/kernel/vector.S 2004-10-18 14:57:04 -07:00 @@ -106,7 +106,7 @@ 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fmadds fr0,fr0,fr1,fr2 + fmadds fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b @@ -133,7 +133,7 @@ 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fnmsubs fr0,fr0,fr1,fr2 + fnmsubs fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b diff -Nru a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S --- a/arch/ppc/kernel/vmlinux.lds.S 2004-10-18 14:57:19 -07:00 +++ b/arch/ppc/kernel/vmlinux.lds.S 2004-10-18 14:57:19 -07:00 @@ -32,6 +32,7 @@ { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.got1) __got2_start = .; @@ -102,9 +103,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S --- a/arch/ppc/lib/checksum.S 2004-10-18 14:56:27 -07:00 +++ b/arch/ppc/lib/checksum.S 2004-10-18 14:56:27 -07:00 @@ -80,13 +80,13 @@ adde r0,r0,r5 /* be unnecessary to unroll this loop */ bdnz 2b andi. r4,r4,3 -3: cmpi 0,r4,2 +3: cmpwi 0,r4,2 blt+ 4f lhz r5,4(r3) addi r3,r3,2 subi r4,r4,2 adde r0,r0,r5 -4: cmpi 0,r4,1 +4: cmpwi 0,r4,1 bne+ 5f lbz r5,4(r3) slwi r5,r5,8 /* Upper byte of word */ @@ -143,7 +143,7 @@ adde r0,r0,r9 bdnz 82b 13: andi. r5,r5,3 -3: cmpi 0,r5,2 +3: cmpwi 0,r5,2 blt+ 4f 83: lhz r6,4(r3) addi r3,r3,2 @@ -151,7 +151,7 @@ 93: sth r6,4(r4) addi r4,r4,2 adde r0,r0,r6 -4: cmpi 0,r5,1 +4: cmpwi 0,r5,1 bne+ 5f 84: lbz r6,4(r3) 94: stb r6,4(r4) @@ -188,7 +188,7 @@ 97: stbu r6,1(r4) bdnz 97b src_error: - cmpi 0,r7,0 + cmpwi 0,r7,0 beq 1f li r6,-EFAULT stw r6,0(r7) @@ -196,7 +196,7 @@ blr dst_error: - cmpi 0,r8,0 + cmpwi 0,r8,0 beq 1f li r6,-EFAULT stw r6,0(r8) diff -Nru a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c --- a/arch/ppc/lib/rheap.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc/lib/rheap.c 2004-10-18 14:56:28 -07:00 @@ -216,7 +216,7 @@ /* Grow the after block backwards */ if (before == NULL && after != NULL) { - (int8_t *) after->start -= size; + after->start = (int8_t *)after->start - size; after->size += size; return; } @@ -407,7 +407,7 @@ /* blk still in free list, with updated start and/or size */ if (bs == s || be == e) { if (bs == s) - (int8_t *) blk->start += size; + blk->start = (int8_t *)blk->start + size; blk->size -= size; } else { @@ -471,7 +471,7 @@ newblk->owner = owner; /* blk still in free list, with updated start, size */ - (int8_t *) blk->start += size; + blk->start = (int8_t *)blk->start + size; blk->size -= size; start = newblk->start; @@ -535,7 +535,7 @@ /* blk still in free list, with updated start and/or size */ if (bs == s || be == e) { if (bs == s) - (int8_t *) blk->start += size; + blk->start = (int8_t *)blk->start + size; blk->size -= size; } else { diff -Nru a/arch/ppc/math-emu/op-common.h b/arch/ppc/math-emu/op-common.h --- a/arch/ppc/math-emu/op-common.h 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc/math-emu/op-common.h 2004-10-18 14:56:50 -07:00 @@ -82,7 +82,6 @@ if (X##_e <= _FP_WFRACBITS_##fs) \ { \ _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ - __ret |= _FP_ROUND(wc, X); \ _FP_FRAC_SLL_##wc(X, 1); \ if (_FP_FRAC_OVERP_##wc(fs, X)) \ { \ diff -Nru a/arch/ppc/mm/44x_mmu.c b/arch/ppc/mm/44x_mmu.c --- a/arch/ppc/mm/44x_mmu.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc/mm/44x_mmu.c 2004-10-18 14:56:33 -07:00 @@ -72,7 +72,7 @@ static void __init ppc44x_pin_tlb(int slot, unsigned int virt, unsigned int phys) { - unsigned long attrib; + unsigned long attrib = 0; __asm__ __volatile__("\ clrrwi %2,%2,10\n\ diff -Nru a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c --- a/arch/ppc/mm/4xx_mmu.c 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc/mm/4xx_mmu.c 2004-10-18 14:55:53 -07:00 @@ -52,6 +52,7 @@ #include #include "mmu_decl.h" +extern int __map_without_ltlbs; /* * MMU_init_hw does the chip-specific initialization of the MMU hardware. */ @@ -101,6 +102,10 @@ v = KERNELBASE; p = PPC_MEMSTART; s = 0; + + if (__map_without_ltlbs) { + return s; + } while (s <= (total_lowmem - LARGE_PAGE_SIZE_16M)) { pmd_t *pmdp; diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c --- a/arch/ppc/mm/init.c 2004-10-18 14:56:19 -07:00 +++ b/arch/ppc/mm/init.c 2004-10-18 14:56:19 -07:00 @@ -104,6 +104,7 @@ * -- Cort */ int __map_without_bats; +int __map_without_ltlbs; /* max amount of RAM to use */ unsigned long __max_memory; @@ -202,6 +203,10 @@ /* Check for nobats option (used in mapin_ram). */ if (strstr(cmd_line, "nobats")) { __map_without_bats = 1; + } + + if (strstr(cmd_line, "noltlbs")) { + __map_without_ltlbs = 1; } /* Look for mem= option on command line */ diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c --- a/arch/ppc/mm/pgtable.c 2004-10-18 14:56:17 -07:00 +++ b/arch/ppc/mm/pgtable.c 2004-10-18 14:56:17 -07:00 @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -270,6 +271,18 @@ if (addr > high_memory && (unsigned long) addr < ioremap_bot) vunmap((void *) (PAGE_MASK & (unsigned long)addr)); } + +void __iomem *ioport_map(unsigned long port, unsigned int len) +{ + return (void __iomem *) (port + _IO_BASE); +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); int map_page(unsigned long va, phys_addr_t pa, int flags) diff -Nru a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c --- a/arch/ppc/platforms/4xx/ebony.c 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc/platforms/4xx/ebony.c 2004-10-18 14:57:05 -07:00 @@ -4,9 +4,11 @@ * Ebony board specific routines * * Matt Porter - * * Copyright 2002 MontaVista Software Inc. * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -118,7 +120,7 @@ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 63: EMAC 1 WOL */ }; -extern void abort(void); +static struct ibm44x_clocks clocks __initdata; static void __init ebony_calibrate_decr(void) @@ -143,18 +145,7 @@ break; } - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - - /* Set the time base to zero */ - mtspr(SPRN_TBWL, 0); - mtspr(SPRN_TBWU, 0); - - /* Clear any pending timer interrupts */ - mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); - - /* Enable decrementer interrupt */ - mtspr(SPRN_TCR, TCR_DIE); + ibm44x_calibrate_decr(freq); } static int @@ -283,7 +274,7 @@ memset(&port, 0, sizeof(port)); port.membase = ioremap64(PPC440GP_UART0_ADDR, 8); port.irq = 0; - port.uartclk = BASE_BAUD * 16; + port.uartclk = clocks.uart0; port.regshift = 0; port.iotype = SERIAL_IO_MEM; port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; @@ -306,7 +297,6 @@ ebony_setup_arch(void) { unsigned char * vpd_base; - struct ibm44x_clocks clocks; struct ocp_def *def; struct ocp_func_emac_data *emacdata; @@ -361,10 +351,6 @@ ROOT_DEV = Root_HDA1; #endif -#ifdef CONFIG_VT - conswitchp = &dummy_con; -#endif - ebony_early_serial_map(); ibm4xxPIC_InitSenses = ebony_IRQ_initsenses; @@ -374,152 +360,17 @@ printk("IBM Ebony port (MontaVista Software, Inc. (source@mvista.com))\n"); } -static void -ebony_restart(char *cmd) -{ - local_irq_disable(); - abort(); -} - -static void -ebony_power_off(void) -{ - local_irq_disable(); - for(;;); -} - -static void -ebony_halt(void) -{ - local_irq_disable(); - for(;;); -} - -/* - * Read the 440GP memory controller to get size of system memory. - */ -static unsigned long __init -ebony_find_end_of_memory(void) -{ - u32 i, bank_config; - u32 mem_size = 0; - - for (i=0; i<4; i++) - { - switch (i) - { - case 0: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR); - break; - case 1: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR); - break; - case 2: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR); - break; - case 3: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR); - break; - } - - bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); - - if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE)) - continue; - switch (SDRAM_CONFIG_BANK_SIZE(bank_config)) - { - case SDRAM_CONFIG_SIZE_8M: - mem_size += PPC44x_MEM_SIZE_8M; - break; - case SDRAM_CONFIG_SIZE_16M: - mem_size += PPC44x_MEM_SIZE_16M; - break; - case SDRAM_CONFIG_SIZE_32M: - mem_size += PPC44x_MEM_SIZE_32M; - break; - case SDRAM_CONFIG_SIZE_64M: - mem_size += PPC44x_MEM_SIZE_64M; - break; - case SDRAM_CONFIG_SIZE_128M: - mem_size += PPC44x_MEM_SIZE_128M; - break; - case SDRAM_CONFIG_SIZE_256M: - mem_size += PPC44x_MEM_SIZE_256M; - break; - case SDRAM_CONFIG_SIZE_512M: - mem_size += PPC44x_MEM_SIZE_512M; - break; - } - } - return mem_size; -} - -static void __init -ebony_init_irq(void) -{ - int i; - - ppc4xx_pic_init(); - - for (i = 0; i < NR_IRQS; i++) - irq_desc[i].handler = ppc4xx_pic; -} - -#ifdef CONFIG_SERIAL_TEXT_DEBUG -#include -#include -#include - -static struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in */ -}; - -static void -ebony_progress(char *s, unsigned short hex) -{ - volatile char c; - volatile unsigned long com_port; - u16 shift; - - com_port = (unsigned long)rs_table[0].iomem_base; - shift = rs_table[0].iomem_reg_shift; - - while ((c = *s++) != 0) { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = c; - - } - - /* Send LF/CR to pretty up output */ - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\r'; - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\n'; -} -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { parse_bootinfo((struct bi_record *) (r3 + KERNELBASE)); + ibm44x_platform_init(); + ppc_md.setup_arch = ebony_setup_arch; ppc_md.show_cpuinfo = ebony_show_cpuinfo; - ppc_md.init_IRQ = ebony_init_irq; ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ - ppc_md.find_end_of_memory = ebony_find_end_of_memory; - - ppc_md.restart = ebony_restart; - ppc_md.power_off = ebony_power_off; - ppc_md.halt = ebony_halt; - ppc_md.calibrate_decr = ebony_calibrate_decr; ppc_md.time_init = todc_time_init; ppc_md.set_rtc_time = todc_set_rtc_time; @@ -528,9 +379,6 @@ ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_SERIAL_TEXT_DEBUG - ppc_md.progress = ebony_progress; -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ #ifdef CONFIG_KGDB ppc_md.early_serial_map = ebony_early_serial_map; #endif diff -Nru a/arch/ppc/platforms/4xx/ebony.h b/arch/ppc/platforms/4xx/ebony.h --- a/arch/ppc/platforms/4xx/ebony.h 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/platforms/4xx/ebony.h 2004-10-18 14:56:49 -07:00 @@ -40,21 +40,21 @@ #define EBONY_RTC_SIZE 0x2000 /* Flash */ -#define EBONY_FPGA_ADDR 0x0000000148300000 +#define EBONY_FPGA_ADDR 0x0000000148300000ULL #define EBONY_BOOT_SMALL_FLASH(x) (x & 0x20) #define EBONY_ONBRD_FLASH_EN(x) (x & 0x02) #define EBONY_FLASH_SEL(x) (x & 0x01) -#define EBONY_SMALL_FLASH_LOW1 0x00000001ff800000 -#define EBONY_SMALL_FLASH_LOW2 0x00000001ff880000 -#define EBONY_SMALL_FLASH_HIGH1 0x00000001fff00000 -#define EBONY_SMALL_FLASH_HIGH2 0x00000001fff80000 +#define EBONY_SMALL_FLASH_LOW1 0x00000001ff800000ULL +#define EBONY_SMALL_FLASH_LOW2 0x00000001ff880000ULL +#define EBONY_SMALL_FLASH_HIGH1 0x00000001fff00000ULL +#define EBONY_SMALL_FLASH_HIGH2 0x00000001fff80000ULL #define EBONY_SMALL_FLASH_SIZE 0x80000 -#define EBONY_LARGE_FLASH_LOW 0x00000001ff800000 -#define EBONY_LARGE_FLASH_HIGH 0x00000001ffc00000 +#define EBONY_LARGE_FLASH_LOW 0x00000001ff800000ULL +#define EBONY_LARGE_FLASH_HIGH 0x00000001ffc00000ULL #define EBONY_LARGE_FLASH_SIZE 0x400000 -#define EBONY_SMALL_FLASH_BASE 0x00000001fff80000 -#define EBONY_LARGE_FLASH_BASE 0x00000001ff800000 +#define EBONY_SMALL_FLASH_BASE 0x00000001fff80000ULL +#define EBONY_LARGE_FLASH_BASE 0x00000001ff800000ULL /* * Serial port defines diff -Nru a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c --- a/arch/ppc/platforms/4xx/ocotea.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc/platforms/4xx/ocotea.c 2004-10-18 14:56:50 -07:00 @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -57,27 +58,21 @@ */ #include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h" -extern void abort(void); +bd_t __res; + +static struct ibm44x_clocks clocks __initdata; static void __init ocotea_calibrate_decr(void) { unsigned int freq; - freq = OCOTEA_SYSCLK; - - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - - /* Set the time base to zero */ - mtspr(SPRN_TBWL, 0); - mtspr(SPRN_TBWU, 0); - - /* Clear any pending timer interrupts */ - mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + if (mfspr(SPRN_CCR1) & CCR1_TCS) + freq = OCOTEA_TMR_CLK; + else + freq = clocks.cpu; - /* Enable decrementer interrupt */ - mtspr(SPRN_TCR, TCR_DIE); + ibm44x_calibrate_decr(freq); } static int @@ -88,6 +83,7 @@ return 0; } + static inline int ocotea_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) { @@ -107,6 +103,46 @@ return PCI_IRQ_TABLE_LOOKUP; } +static void __init ocotea_set_emacdata(void) +{ + struct ocp_def *def; + struct ocp_func_emac_data *emacdata; + int i; + + /* + * Note: Current rev. board only operates in Group 4a + * mode, so we always set EMAC0-1 for SMII and EMAC2-3 + * for RGMII (though these could run in RTBI just the same). + * + * The FPGA reg 3 information isn't even suitable for + * determining the phy_mode, so if the board becomes + * usable in !4a, it will be necessary to parse an environment + * variable from the firmware or similar to properly configure + * the phy_map/phy_mode. + */ + /* Set phy_map, phy_mode, and mac_addr for each EMAC */ + for (i=0; i<4; i++) { + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i); + emacdata = def->additions; + if (i < 2) { + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_SMII; + } + else { + emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */ + emacdata->phy_mode = PHY_MODE_RGMII; + } + if (i == 0) + memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); + else if (i == 1) + memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6); + else if (i == 2) + memcpy(emacdata->mac_addr, __res.bi_enet2addr, 6); + else if (i == 3) + memcpy(emacdata->mac_addr, __res.bi_enet3addr, 6); + } +} + #define PCIX_READW(offset) \ (readw((u32)pcix_reg_base+offset)) @@ -209,7 +245,7 @@ TODC_ALLOC(); static void __init -ocotea_early_serial_map(const struct ibm44x_clocks *clks) +ocotea_early_serial_map(void) { struct uart_port port; @@ -217,7 +253,7 @@ memset(&port, 0, sizeof(port)); port.membase = ioremap64(PPC440GX_UART0_ADDR, 8); port.irq = UART0_INT; - port.uartclk = clks->uart0; + port.uartclk = clocks.uart0; port.regshift = 0; port.iotype = SERIAL_IO_MEM; port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; @@ -229,7 +265,7 @@ port.membase = ioremap64(PPC440GX_UART1_ADDR, 8); port.irq = UART1_INT; - port.uartclk = clks->uart1; + port.uartclk = clocks.uart1; port.line = 1; if (early_serial_setup(&port) != 0) { @@ -240,41 +276,7 @@ static void __init ocotea_setup_arch(void) { - unsigned char *addr; - unsigned long long mac64; - struct ocp_def *def; - struct ocp_func_emac_data *emacdata; - int i; - struct ibm44x_clocks clocks; - - /* - * Note: Current rev. board only operates in Group 4a - * mode, so we always set EMAC0-1 for SMII and EMAC2-3 - * for RGMII (though these could run in RTBI just the same). - * - * The FPGA reg 3 information isn't even suitable for - * determining the phy_mode, so if the board becomes - * usable in !4a, it will be necessary to parse an environment - * variable from the firmware or similar to properly configure - * the phy_map/phy_mode. - */ - /* Set phy_map, phy_mode, and mac_addr for each EMAC */ - addr = ioremap64(OCOTEA_MAC_BASE, OCOTEA_MAC_SIZE); - for (i=0; i<4; i++) { - mac64 = simple_strtoull(addr+OCOTEA_MAC_OFFSET*i, 0, 16); - def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i); - emacdata = def->additions; - if (i < 2) { - emacdata->phy_map = 0x00000001; /* Skip 0x00 */ - emacdata->phy_mode = PHY_MODE_SMII; - } - else { - emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */ - emacdata->phy_mode = PHY_MODE_RGMII; - } - memcpy(emacdata->mac_addr, (char *)&mac64+2, 6); - } - iounmap(addr); + ocotea_set_emacdata(); ibm440gx_tah_enable(); @@ -319,173 +321,33 @@ ROOT_DEV = Root_HDA1; #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - ocotea_early_serial_map(&clocks); + ocotea_early_serial_map(); /* Identify the system */ printk("IBM Ocotea port (MontaVista Software, Inc. )\n"); } -static void -ocotea_restart(char *cmd) -{ - local_irq_disable(); - abort(); -} - -static void -ocotea_power_off(void) -{ - local_irq_disable(); - for(;;); -} - -static void -ocotea_halt(void) -{ - local_irq_disable(); - for(;;); -} - -/* - * Read the 440GX memory controller to get size of system memory. - */ -static unsigned long __init -ocotea_find_end_of_memory(void) -{ - u32 i, bank_config; - u32 mem_size = 0; - - for (i=0; i<4; i++) - { - switch (i) - { - case 0: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR); - break; - case 1: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR); - break; - case 2: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR); - break; - case 3: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR); - break; - } - - bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); - - if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE)) - continue; - switch (SDRAM_CONFIG_BANK_SIZE(bank_config)) - { - case SDRAM_CONFIG_SIZE_8M: - mem_size += PPC44x_MEM_SIZE_8M; - break; - case SDRAM_CONFIG_SIZE_16M: - mem_size += PPC44x_MEM_SIZE_16M; - break; - case SDRAM_CONFIG_SIZE_32M: - mem_size += PPC44x_MEM_SIZE_32M; - break; - case SDRAM_CONFIG_SIZE_64M: - mem_size += PPC44x_MEM_SIZE_64M; - break; - case SDRAM_CONFIG_SIZE_128M: - mem_size += PPC44x_MEM_SIZE_128M; - break; - case SDRAM_CONFIG_SIZE_256M: - mem_size += PPC44x_MEM_SIZE_256M; - break; - case SDRAM_CONFIG_SIZE_512M: - mem_size += PPC44x_MEM_SIZE_512M; - break; - } - } - return mem_size; -} - -static void __init -ocotea_init_irq(void) -{ - int i; - - ppc4xx_pic_init(); - - for (i = 0; i < NR_IRQS; i++) - irq_desc[i].handler = ppc4xx_pic; -} - -#ifdef CONFIG_SERIAL_TEXT_DEBUG -#include -#include -#include -struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in */ -}; - -static void -ocotea_progress(char *s, unsigned short hex) -{ - volatile char c; - volatile unsigned long com_port; - u16 shift; - - com_port = (unsigned long)rs_table[0].iomem_base; - shift = rs_table[0].iomem_reg_shift; - - while ((c = *s++) != 0) { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = c; - - } - - /* Send LF/CR to pretty up output */ - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\r'; - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\n'; -} -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - -#if 0 -static void __init -ocotea_map_io(void) -{ - io_block_mapping(0xe0000000, 0x0000000140000000, - 0x00001000, _PAGE_IO); -} -#endif - void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - parse_bootinfo((struct bi_record *) (r3 + KERNELBASE)); + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) + __res = *(bd_t *)(r3 + KERNELBASE); /* Disable L2-Cache due to hardware issues */ ibm440gx_l2c_disable(); + ibm44x_platform_init(); + ppc_md.setup_arch = ocotea_setup_arch; ppc_md.show_cpuinfo = ocotea_show_cpuinfo; - ppc_md.init_IRQ = ocotea_init_irq; ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ - ppc_md.find_end_of_memory = ocotea_find_end_of_memory; - - ppc_md.restart = ocotea_restart; - ppc_md.power_off = ocotea_power_off; - ppc_md.halt = ocotea_halt; - ppc_md.calibrate_decr = ocotea_calibrate_decr; ppc_md.time_init = todc_time_init; ppc_md.set_rtc_time = todc_set_rtc_time; @@ -494,9 +356,6 @@ ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_SERIAL_TEXT_DEBUG - ppc_md.progress = ocotea_progress; -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ #ifdef CONFIG_KGDB ppc_md.early_serial_map = ocotea_early_serial_map; #endif diff -Nru a/arch/ppc/platforms/4xx/ocotea.h b/arch/ppc/platforms/4xx/ocotea.h --- a/arch/ppc/platforms/4xx/ocotea.h 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc/platforms/4xx/ocotea.h 2004-10-18 14:56:29 -07:00 @@ -24,13 +24,14 @@ /* F/W TLB mapping used in bootloader glue to reset EMAC */ #define PPC44x_EMAC0_MR0 0xE0000800 -/* Location of MAC addresses in firmware */ -#define OCOTEA_MAC_BASE (OCOTEA_SMALL_FLASH_HIGH+0xb0500) -#define OCOTEA_MAC_SIZE 0x200 -#define OCOTEA_MAC_OFFSET 0x100 +/* Location of MAC addresses in PIBS image */ +#define OCOTEA_PIBS_FLASH 0xfff00000 +#define OCOTEA_PIBS_MAC_BASE (OCOTEA_PIBS_FLASH+0xb0500) +#define OCOTEA_PIBS_MAC_SIZE 0x200 +#define OCOTEA_PIBS_MAC_OFFSET 0x100 -/* Default clock rate */ -#define OCOTEA_SYSCLK 25000000 +/* External timer clock frequency */ +#define OCOTEA_TMR_CLK 25000000 /* RTC/NVRAM location */ #define OCOTEA_RTC_ADDR 0x0000000148000000ULL diff -Nru a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c --- a/arch/ppc/platforms/85xx/mpc8540_ads.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c 2004-10-18 14:56:28 -07:00 @@ -120,10 +120,6 @@ mpc85xx_setup_hose(); #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - #ifdef CONFIG_SERIAL_8250 mpc85xx_early_serial_map(); #endif diff -Nru a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c 2004-10-18 14:57:03 -07:00 @@ -307,7 +307,7 @@ { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; -#if CONFIG_85xx_PCI2 +#ifdef CONFIG_85xx_PCI2 /* With the current code we know PCI2 will be bus 2, however this may * not be guarnteed */ if (bus == 2 && PCI_SLOT(devfn) == 0) @@ -356,10 +356,6 @@ #ifdef CONFIG_PCI /* setup PCI host bridges */ mpc85xx_setup_hose(); -#endif - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; #endif #ifdef CONFIG_SERIAL_8250 diff -Nru a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c --- a/arch/ppc/platforms/85xx/sbc8560.c 2004-10-18 14:56:19 -07:00 +++ b/arch/ppc/platforms/85xx/sbc8560.c 2004-10-18 14:56:19 -07:00 @@ -144,9 +144,6 @@ /* setup PCI host bridges */ mpc85xx_setup_hose(); #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif #ifdef CONFIG_SERIAL_8250 sbc8560_early_serial_map(); #endif diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile --- a/arch/ppc/platforms/Makefile 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc/platforms/Makefile 2004-10-18 14:57:05 -07:00 @@ -21,23 +21,21 @@ obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o -obj-$(CONFIG_EST8260) += est8260_setup.o -obj-$(CONFIG_PQ2ADS) += pq2ads_setup.o +obj-$(CONFIG_PQ2ADS) += pq2ads.o obj-$(CONFIG_TQM8260) += tqm8260_setup.o obj-$(CONFIG_EV64260) += ev64260_setup.o obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o obj-$(CONFIG_K2) += k2.o -obj-$(CONFIG_LOPEC) += lopec_setup.o lopec_pci.o +obj-$(CONFIG_LOPEC) += lopec.o obj-$(CONFIG_MCPN765) += mcpn765.o obj-$(CONFIG_MENF1) += menf1_setup.o menf1_pci.o -obj-$(CONFIG_MVME5100) += mvme5100_setup.o mvme5100_pci.o +obj-$(CONFIG_MVME5100) += mvme5100.o obj-$(CONFIG_PAL4) += pal4_setup.o pal4_pci.o obj-$(CONFIG_PCORE) += pcore.o obj-$(CONFIG_POWERPMC250) += powerpmc250.o obj-$(CONFIG_PPLUS) += pplus.o obj-$(CONFIG_PRPMC750) += prpmc750.o obj-$(CONFIG_PRPMC800) += prpmc800.o -obj-$(CONFIG_RPX8260) += rpx8260.o obj-$(CONFIG_SANDPOINT) += sandpoint.o obj-$(CONFIG_SBC82xx) += sbc82xx.o obj-$(CONFIG_SPRUCE) += spruce.o diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c --- a/arch/ppc/platforms/chrp_setup.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc/platforms/chrp_setup.c 2004-10-18 14:56:50 -07:00 @@ -250,13 +250,6 @@ */ sio_init(); - /* - * Setup the console operations - */ -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - /* Get the event scan rate for the rtas so we know how * often it expects a heartbeat. -- Cort */ @@ -382,7 +375,7 @@ { struct device_node *np; int i; - unsigned long chrp_int_ack; + unsigned long chrp_int_ack = 0; unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; diff -Nru a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c --- a/arch/ppc/platforms/chrp_smp.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc/platforms/chrp_smp.c 2004-10-18 14:56:28 -07:00 @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/platforms/est8260.h b/arch/ppc/platforms/est8260.h --- a/arch/ppc/platforms/est8260.h 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/platforms/est8260.h 2004-10-18 14:56:49 -07:00 @@ -10,6 +10,9 @@ #define BOOTROM_RESTART_ADDR ((uint)0xff000104) +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "EST Corporation" +#define CPUINFO_MACHINE "SBC8260 PowerPC" /* A Board Information structure that is given to a program when * prom starts it up. diff -Nru a/arch/ppc/platforms/est8260_setup.c b/arch/ppc/platforms/est8260_setup.c --- a/arch/ppc/platforms/est8260_setup.c 2004-10-18 14:55:54 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,65 +0,0 @@ -/* - * arch/ppc/platforms/est8260_setup.c - * - * EST8260 platform support - * - * Author: Allen Curtis - * Derived from: m8260_setup.c by Dan Malek, MVista - * - * Copyright 2002 Ones and Zeros, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include - -#include -#include - -static void (*callback_setup_arch)(void); - -extern unsigned char __res[sizeof(bd_t)]; - -extern void m8260_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); - -static int -est8260_show_cpuinfo(struct seq_file *m) -{ - bd_t *binfo = (bd_t *)__res; - - seq_printf(m, "vendor\t\t: EST Corporation\n" - "machine\t\t: SBC8260 PowerPC\n" - "\n" - "mem size\t\t: 0x%08x\n" - "console baud\t\t: %d\n" - "\n", - binfo->bi_memsize, - binfo->bi_baudrate); - return 0; -} - -static void __init -est8260_setup_arch(void) -{ - printk("EST SBC8260 Port\n"); - callback_setup_arch(); -} - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* Generic 8260 platform initialization */ - m8260_init(r3, r4, r5, r6, r7); - - /* Anything special for this platform */ - ppc_md.show_cpuinfo = est8260_show_cpuinfo; - - callback_setup_arch = ppc_md.setup_arch; - ppc_md.setup_arch = est8260_setup_arch; -} diff -Nru a/arch/ppc/platforms/k2.c b/arch/ppc/platforms/k2.c --- a/arch/ppc/platforms/k2.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/platforms/k2.c 2004-10-18 14:55:54 -07:00 @@ -464,10 +464,6 @@ ROOT_DEV = Root_HDC1; #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - /* Identify the system */ printk(KERN_INFO "System Identification: SBS K2 - PowerPC 750 @ " "%d Mhz\n", k2_get_cpu_speed() / 1000000); diff -Nru a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c --- a/arch/ppc/platforms/lite5200.c 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc/platforms/lite5200.c 2004-10-18 14:55:53 -07:00 @@ -36,6 +36,8 @@ #include +extern int powersave_nap; + /* Board data given by U-Boot */ bd_t __res; EXPORT_SYMBOL(__res); /* For modules */ @@ -64,25 +66,55 @@ .vendor = OCP_VENDOR_INVALID } }; - + /* ======================================================================== */ /* Platform specific code */ /* ======================================================================== */ static int -icecube_show_cpuinfo(struct seq_file *m) +lite5200_show_cpuinfo(struct seq_file *m) { seq_printf(m, "machine\t\t: Freescale LITE5200\n"); return 0; } static void __init -icecube_setup_arch(void) +lite5200_setup_cpu(void) { + struct mpc52xx_intr *intr; + + u32 intr_ctrl; + + /* Map zones */ + intr = (struct mpc52xx_intr *) + ioremap(MPC52xx_INTR,sizeof(struct mpc52xx_intr)); + + if (!intr) { + printk("lite5200.c: Error while mapping INTR during lite5200_setup_cpu\n"); + goto unmap_regs; + } + + /* IRQ[0-3] setup : IRQ0 - Level Active Low */ + /* IRQ[1-3] - Level Active High */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= ~0x00ff0000; + intr_ctrl |= 0x00c00000; + out_be32(&intr->ctrl, intr_ctrl); + + /* Unmap reg zone */ +unmap_regs: + if (intr) iounmap(intr); +} +static void __init +lite5200_setup_arch(void) +{ /* Add board OCP definitions */ mpc52xx_add_board_devices(board_ocp); + + /* CPU & Port mux setup */ + lite5200_setup_cpu(); } void __init @@ -110,7 +142,7 @@ initrd_end = r5 + KERNELBASE; } #endif - + /* Load the command line */ if (r6) { *(char *)(r7+KERNELBASE) = 0; @@ -120,14 +152,17 @@ /* BAT setup */ mpc52xx_set_bat(); - + /* No ISA bus AFAIK */ isa_io_base = 0; isa_mem_base = 0; + /* Powersave */ + powersave_nap = 1; /* We allow this platform to NAP */ + /* Setup the ppc_md struct */ - ppc_md.setup_arch = icecube_setup_arch; - ppc_md.show_cpuinfo = icecube_show_cpuinfo; + ppc_md.setup_arch = lite5200_setup_arch; + ppc_md.show_cpuinfo = lite5200_show_cpuinfo; ppc_md.show_percpuinfo = NULL; ppc_md.init_IRQ = mpc52xx_init_irq; ppc_md.get_irq = mpc52xx_get_irq; @@ -138,12 +173,12 @@ ppc_md.restart = mpc52xx_restart; ppc_md.power_off = mpc52xx_power_off; ppc_md.halt = mpc52xx_halt; - - /* No time keeper on the IceCube */ + + /* No time keeper on the LITE5200 */ ppc_md.time_init = NULL; ppc_md.get_rtc_time = NULL; ppc_md.set_rtc_time = NULL; - + ppc_md.calibrate_decr = mpc52xx_calibrate_decr; #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = mpc52xx_progress; diff -Nru a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/platforms/lopec.c 2004-10-18 14:56:32 -07:00 @@ -0,0 +1,410 @@ +/* + * arch/ppc/platforms/lopec.c + * + * Setup routines for the Motorola LoPEC. + * + * Author: Dan Cox + * Maintainer: Tom Rini + * + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Define all of the IRQ senses and polarities. Taken from the + * LoPEC Programmer's Reference Guide. + */ +static u_char lopec_openpic_initsenses[16] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 5 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 6 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 7 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 8 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 9 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 10 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 11 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 12 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 13 */ + (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* IRQ 14 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* IRQ 15 */ +}; + +static inline int __init +lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + int irq; + static char pci_irq_table[][4] = { + {16, 0, 0, 0}, /* ID 11 - Winbond */ + {22, 0, 0, 0}, /* ID 12 - SCSI */ + {0, 0, 0, 0}, /* ID 13 - nothing */ + {17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */ + {27, 0, 0, 0}, /* ID 15 - USB */ + {23, 0, 0, 0}, /* ID 16 - PMC slot 1 */ + {24, 0, 0, 0}, /* ID 17 - PMC slot 2 */ + {25, 0, 0, 0}, /* ID 18 - PCI slot */ + {0, 0, 0, 0}, /* ID 19 - nothing */ + {0, 0, 0, 0}, /* ID 20 - nothing */ + {0, 0, 0, 0}, /* ID 21 - nothing */ + {0, 0, 0, 0}, /* ID 22 - nothing */ + {0, 0, 0, 0}, /* ID 23 - nothing */ + {0, 0, 0, 0}, /* ID 24 - PMC slot 1b */ + {0, 0, 0, 0}, /* ID 25 - nothing */ + {0, 0, 0, 0} /* ID 26 - PMC Slot 2b */ + }; + const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4; + + irq = PCI_IRQ_TABLE_LOOKUP; + if (!irq) + return 0; + + return irq; +} + +static void __init +lopec_setup_winbond_83553(struct pci_controller *hose) +{ + int devfn; + + devfn = PCI_DEVFN(11,0); + + /* IDE interrupt routing (primary 14, secondary 15) */ + early_write_config_byte(hose, 0, devfn, 0x43, 0xef); + /* PCI interrupt routing */ + early_write_config_word(hose, 0, devfn, 0x44, 0x0000); + + /* ISA-PCI address decoder */ + early_write_config_byte(hose, 0, devfn, 0x48, 0xf0); + + /* RTC, kb, not used in PPC */ + early_write_config_byte(hose, 0, devfn, 0x4d, 0x00); + early_write_config_byte(hose, 0, devfn, 0x4e, 0x04); + devfn = PCI_DEVFN(11, 1); + early_write_config_byte(hose, 0, devfn, 0x09, 0x8f); + early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011); +} + +static void __init +lopec_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + if (mpc10x_bridge_init(hose, MPC10X_MEM_MAP_B, MPC10X_MEM_MAP_B, + MPC10X_MAPB_EUMB_BASE) == 0) { + + hose->mem_resources[0].end = 0xffffffff; + lopec_setup_winbond_83553(hose); + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = lopec_map_irq; + } +} + +static int +lopec_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "machine\t\t: Motorola LoPEC\n"); + return 0; +} + +static u32 +lopec_irq_canonicalize(u32 irq) +{ + if (irq == 2) + return 9; + else + return irq; +} + +static void +lopec_restart(char *cmd) +{ +#define LOPEC_SYSSTAT1 0xffe00000 + /* force a hard reset, if possible */ + unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1); + reg |= 0x80; + *((unsigned char *) LOPEC_SYSSTAT1) = reg; + + local_irq_disable(); + while(1); +#undef LOPEC_SYSSTAT1 +} + +static void +lopec_halt(void) +{ + local_irq_disable(); + while(1); +} + +static void +lopec_power_off(void) +{ + lopec_halt(); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +int lopec_ide_ports_known = 0; +static unsigned long lopec_ide_regbase[MAX_HWIFS]; +static unsigned long lopec_ide_ctl_regbase[MAX_HWIFS]; +static unsigned long lopec_idedma_regbase; + +static void +lopec_ide_probe(void) +{ + struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, + NULL); + lopec_ide_ports_known = 1; + + if (dev) { + lopec_ide_regbase[0] = dev->resource[0].start; + lopec_ide_regbase[1] = dev->resource[2].start; + lopec_ide_ctl_regbase[0] = dev->resource[1].start; + lopec_ide_ctl_regbase[1] = dev->resource[3].start; + lopec_idedma_regbase = dev->resource[4].start; + } +} + +static int +lopec_ide_default_irq(unsigned long base) +{ + if (lopec_ide_ports_known == 0) + lopec_ide_probe(); + + if (base == lopec_ide_regbase[0]) + return 14; + else if (base == lopec_ide_regbase[1]) + return 15; + else + return 0; +} + +static unsigned long +lopec_ide_default_io_base(int index) +{ + if (lopec_ide_ports_known == 0) + lopec_ide_probe(); + return lopec_ide_regbase[index]; +} + +static void __init +lopec_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data, + unsigned long ctl, int *irq) +{ + unsigned long reg = data; + uint alt_status_base; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) + hw->io_ports[i] = reg++; + + if (data == lopec_ide_regbase[0]) { + alt_status_base = lopec_ide_ctl_regbase[0] + 2; + hw->irq = 14; + } else if (data == lopec_ide_regbase[1]) { + alt_status_base = lopec_ide_ctl_regbase[1] + 2; + hw->irq = 15; + } else { + alt_status_base = 0; + hw->irq = 0; + } + + if (ctl) + hw->io_ports[IDE_CONTROL_OFFSET] = ctl; + else + hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base; + + if (irq != NULL) + *irq = hw->irq; + +} +#endif /* BLK_DEV_IDE */ + +static void __init +lopec_init_IRQ(void) +{ + int i; + + /* + * Provide the open_pic code with the correct table of interrupts. + */ + OpenPIC_InitSenses = lopec_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses); + + mpc10x_set_openpic(); + + /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + &i8259_irq); + + /* Map i8259 interrupts */ + for(i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + /* + * The EPIC allows for a read in the range of 0xFEF00000 -> + * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. + */ + i8259_init(0xfef00000); +} + +static int __init +lopec_request_io(void) +{ + outb(0x00, 0x4d0); + outb(0xc0, 0x4d1); + + request_region(0x00, 0x20, "dma1"); + request_region(0x20, 0x20, "pic1"); + request_region(0x40, 0x20, "timer"); + request_region(0x80, 0x10, "dma page reg"); + request_region(0xa0, 0x20, "pic2"); + request_region(0xc0, 0x20, "dma2"); + + return 0; +} + +device_initcall(lopec_request_io); + +static void __init +lopec_map_io(void) +{ + io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); + io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO); +} + +/* + * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1. + */ +static __inline__ void +lopec_set_bat(void) +{ + mb(); + mtspr(DBAT1U, 0xf8000ffe); + mtspr(DBAT1L, 0xf800002a); + mb(); +} + +TODC_ALLOC(); + +static void __init +lopec_setup_arch(void) +{ + + TODC_INIT(TODC_TYPE_MK48T37, 0, 0, + ioremap(0xffe80000, 0x8000), 8); + + loops_per_jiffy = 100000000/HZ; + + lopec_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#elif defined(CONFIG_ROOT_NFS) + ROOT_DEV = Root_NFS; +#elif defined(CONFIG_BLK_DEV_IDEDISK) + ROOT_DEV = Root_HDA1; +#else + ROOT_DEV = Root_SDA1; +#endif + +#ifdef CONFIG_PPCBUG_NVRAM + /* Read in NVRAM data */ + init_prep_nvram(); + + /* if no bootargs, look in NVRAM */ + if ( cmd_line[0] == '\0' ) { + char *bootargs; + bootargs = prep_nvram_get_var("bootargs"); + if (bootargs != NULL) { + strcpy(cmd_line, bootargs); + /* again.. */ + strcpy(saved_command_line, cmd_line); + } + } +#endif +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + lopec_set_bat(); + + isa_io_base = MPC10X_MAPB_ISA_IO_BASE; + isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; + pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = lopec_setup_arch; + ppc_md.show_cpuinfo = lopec_show_cpuinfo; + ppc_md.irq_canonicalize = lopec_irq_canonicalize; + ppc_md.init_IRQ = lopec_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = lopec_restart; + ppc_md.power_off = lopec_power_off; + ppc_md.halt = lopec_halt; + + ppc_md.setup_io_mappings = lopec_map_io; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.default_irq = lopec_ide_default_irq; + ppc_ide_md.default_io_base = lopec_ide_default_io_base; + ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports; +#endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif +} diff -Nru a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/platforms/lopec.h 2004-10-18 14:57:03 -07:00 @@ -0,0 +1,39 @@ +/* + * include/asm-ppc/lopec_serial.h + * + * Definitions for Motorola LoPEC board. + * + * Author: Dan Cox + * danc@mvista.com (or, alternately, source@mvista.com) + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __H_LOPEC_SERIAL +#define __H_LOPEC_SERIAL + +#define RS_TABLE_SIZE 3 + +#define BASE_BAUD (1843200 / 16) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#endif + +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, 0xffe10000, 29, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe10000, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, 0xffe11000, 20, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe11000, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, 0xffe12000, 21, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe12000, \ + io_type: SERIAL_IO_MEM } + +#endif diff -Nru a/arch/ppc/platforms/lopec_pci.c b/arch/ppc/platforms/lopec_pci.c --- a/arch/ppc/platforms/lopec_pci.c 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,99 +0,0 @@ -/* - * arch/ppc/platforms/lopec_pci.c - * - * PCI setup routines for the Motorola LoPEC. - * - * Author: Dan Cox - * danc@mvista.com (or, alternately, source@mvista.com) - * - * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include -#include - -#include -#include -#include - -static inline int __init -lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) -{ - int irq; - static char pci_irq_table[][4] = { - {16, 0, 0, 0}, /* ID 11 - Winbond */ - {22, 0, 0, 0}, /* ID 12 - SCSI */ - {0, 0, 0, 0}, /* ID 13 - nothing */ - {17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */ - {27, 0, 0, 0}, /* ID 15 - USB */ - {23, 0, 0, 0}, /* ID 16 - PMC slot 1 */ - {24, 0, 0, 0}, /* ID 17 - PMC slot 2 */ - {25, 0, 0, 0}, /* ID 18 - PCI slot */ - {0, 0, 0, 0}, /* ID 19 - nothing */ - {0, 0, 0, 0}, /* ID 20 - nothing */ - {0, 0, 0, 0}, /* ID 21 - nothing */ - {0, 0, 0, 0}, /* ID 22 - nothing */ - {0, 0, 0, 0}, /* ID 23 - nothing */ - {0, 0, 0, 0}, /* ID 24 - PMC slot 1b */ - {0, 0, 0, 0}, /* ID 25 - nothing */ - {0, 0, 0, 0} /* ID 26 - PMC Slot 2b */ - }; - const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4; - - irq = PCI_IRQ_TABLE_LOOKUP; - if (!irq) - return 0; - - return irq; -} - -void __init -lopec_setup_winbond_83553(struct pci_controller *hose) -{ - int devfn; - - devfn = PCI_DEVFN(11,0); - - /* IDE interrupt routing (primary 14, secondary 15) */ - early_write_config_byte(hose, 0, devfn, 0x43, 0xef); - /* PCI interrupt routing */ - early_write_config_word(hose, 0, devfn, 0x44, 0x0000); - - /* ISA-PCI address decoder */ - early_write_config_byte(hose, 0, devfn, 0x48, 0xf0); - - /* RTC, kb, not used in PPC */ - early_write_config_byte(hose, 0, devfn, 0x4d, 0x00); - early_write_config_byte(hose, 0, devfn, 0x4e, 0x04); - devfn = PCI_DEVFN(11, 1); - early_write_config_byte(hose, 0, devfn, 0x09, 0x8f); - early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011); -} - -void __init -lopec_find_bridges(void) -{ - struct pci_controller *hose; - - hose = pcibios_alloc_controller(); - if (!hose) - return; - - hose->first_busno = 0; - hose->last_busno = 0xff; - - if (mpc10x_bridge_init(hose, - MPC10X_MEM_MAP_B, - MPC10X_MEM_MAP_B, - MPC10X_MAPB_EUMB_BASE) == 0) { - - hose->mem_resources[0].end = 0xffffffff; - lopec_setup_winbond_83553(hose); - hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); - ppc_md.pci_swizzle = common_swizzle; - ppc_md.pci_map_irq = lopec_map_irq; - } -} diff -Nru a/arch/ppc/platforms/lopec_serial.h b/arch/ppc/platforms/lopec_serial.h --- a/arch/ppc/platforms/lopec_serial.h 2004-10-18 14:57:03 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,39 +0,0 @@ -/* - * include/asm-ppc/lopec_serial.h - * - * Definitions for Motorola LoPEC board. - * - * Author: Dan Cox - * danc@mvista.com (or, alternately, source@mvista.com) - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __H_LOPEC_SERIAL -#define __H_LOPEC_SERIAL - -#define RS_TABLE_SIZE 3 - -#define BASE_BAUD (1843200 / 16) - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#endif - -#define SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, 0xffe10000, 29, STD_COM_FLAGS, \ - iomem_base: (u8 *) 0xffe10000, \ - io_type: SERIAL_IO_MEM }, \ - { 0, BASE_BAUD, 0xffe11000, 20, STD_COM_FLAGS, \ - iomem_base: (u8 *) 0xffe11000, \ - io_type: SERIAL_IO_MEM }, \ - { 0, BASE_BAUD, 0xffe12000, 21, STD_COM_FLAGS, \ - iomem_base: (u8 *) 0xffe12000, \ - io_type: SERIAL_IO_MEM } - -#endif diff -Nru a/arch/ppc/platforms/lopec_setup.c b/arch/ppc/platforms/lopec_setup.c --- a/arch/ppc/platforms/lopec_setup.c 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,378 +0,0 @@ -/* - * arch/ppc/platforms/lopec_setup.c - * - * Setup routines for the Motorola LoPEC. - * - * Author: Dan Cox - * danc@mvista.com - * - * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -extern void lopec_find_bridges(void); - -/* - * Define all of the IRQ senses and polarities. Taken from the - * LoPEC Programmer's Reference Guide. - */ -static u_char lopec_openpic_initsenses[16] __initdata = { - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 0 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 1 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 2 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 3 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 4 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 5 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 6 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 7 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 8 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 9 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 10 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 11 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 12 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 13 */ - (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* IRQ 14 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* IRQ 15 */ -}; - -static int -lopec_show_cpuinfo(struct seq_file *m) -{ - seq_printf(m, "machine\t\t: Motorola LoPEC\n"); - return 0; -} - -static u32 -lopec_irq_canonicalize(u32 irq) -{ - if (irq == 2) - return 9; - else - return irq; -} - -static void -lopec_restart(char *cmd) -{ -#define LOPEC_SYSSTAT1 0xffe00000 - /* force a hard reset, if possible */ - unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1); - reg |= 0x80; - *((unsigned char *) LOPEC_SYSSTAT1) = reg; - - local_irq_disable(); - while(1); -#undef LOPEC_SYSSTAT1 -} - -static void -lopec_halt(void) -{ - local_irq_disable(); - while(1); -} - -static void -lopec_power_off(void) -{ - lopec_halt(); -} - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -int lopec_ide_ports_known = 0; -static unsigned long lopec_ide_regbase[MAX_HWIFS]; -static unsigned long lopec_ide_ctl_regbase[MAX_HWIFS]; -static unsigned long lopec_idedma_regbase; - -static void -lopec_ide_probe(void) -{ - struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_WINBOND, - PCI_DEVICE_ID_WINBOND_82C105, - NULL); - lopec_ide_ports_known = 1; - - if (dev) { - lopec_ide_regbase[0] = dev->resource[0].start; - lopec_ide_regbase[1] = dev->resource[2].start; - lopec_ide_ctl_regbase[0] = dev->resource[1].start; - lopec_ide_ctl_regbase[1] = dev->resource[3].start; - lopec_idedma_regbase = dev->resource[4].start; - } -} - -static int -lopec_ide_default_irq(unsigned long base) -{ - if (lopec_ide_ports_known == 0) - lopec_ide_probe(); - - if (base == lopec_ide_regbase[0]) - return 14; - else if (base == lopec_ide_regbase[1]) - return 15; - else - return 0; -} - -static unsigned long -lopec_ide_default_io_base(int index) -{ - if (lopec_ide_ports_known == 0) - lopec_ide_probe(); - return lopec_ide_regbase[index]; -} - -static void __init -lopec_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data, - unsigned long ctl, int *irq) -{ - unsigned long reg = data; - uint alt_status_base; - int i; - - for(i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - hw->io_ports[i] = reg++; - - if (data == lopec_ide_regbase[0]) { - alt_status_base = lopec_ide_ctl_regbase[0] + 2; - hw->irq = 14; - } - else if (data == lopec_ide_regbase[1]) { - alt_status_base = lopec_ide_ctl_regbase[1] + 2; - hw->irq = 15; - } - else { - alt_status_base = 0; - hw->irq = 0; - } - - if (ctl) - hw->io_ports[IDE_CONTROL_OFFSET] = ctl; - else - hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base; - - if (irq != NULL) - *irq = hw->irq; - -} -#endif /* BLK_DEV_IDE */ - -static void __init -lopec_init_IRQ(void) -{ - int i; - - /* - * Provide the open_pic code with the correct table of interrupts. - */ - OpenPIC_InitSenses = lopec_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses); - - mpc10x_set_openpic(); - - /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ - openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", - &i8259_irq); - - /* Map i8259 interrupts */ - for(i = 0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - - /* - * The EPIC allows for a read in the range of 0xFEF00000 -> - * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. - */ - i8259_init(0xfef00000); -} - -static int __init -lopec_request_io(void) -{ - outb(0x00, 0x4d0); - outb(0xc0, 0x4d1); - - request_region(0x00, 0x20, "dma1"); - request_region(0x20, 0x20, "pic1"); - request_region(0x40, 0x20, "timer"); - request_region(0x80, 0x10, "dma page reg"); - request_region(0xa0, 0x20, "pic2"); - request_region(0xc0, 0x20, "dma2"); - - return 0; -} - -device_initcall(lopec_request_io); - -static void __init -lopec_map_io(void) -{ - io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); - io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO); -} - -static void __init -lopec_set_bat(void) -{ - unsigned long batu, batl; - - __asm__ __volatile__( - "lis %0,0xf800\n \ - ori %1,%0,0x002a\n \ - ori %0,%0,0x0ffe\n \ - mtspr 0x21e,%0\n \ - mtspr 0x21f,%1\n \ - isync\n \ - sync " - : "=r" (batu), "=r" (batl)); -} - -#ifdef CONFIG_SERIAL_TEXT_DEBUG -#include -#include -#include -#include - -static struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in */ -}; - -volatile unsigned char *com_port; -volatile unsigned char *com_port_lsr; - -static void -serial_writechar(char c) -{ - while ((*com_port_lsr & UART_LSR_THRE) == 0) - ; - *com_port = c; -} - -void -lopec_progress(char *s, unsigned short hex) -{ - volatile char c; - - com_port = (volatile unsigned char *) rs_table[0].port; - com_port_lsr = com_port + UART_LSR; - - while ((c = *s++) != 0) - serial_writechar(c); - - /* Most messages don't have a newline in them */ - serial_writechar('\n'); - serial_writechar('\r'); -} -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - -TODC_ALLOC(); - -static void __init -lopec_setup_arch(void) -{ - - TODC_INIT(TODC_TYPE_MK48T37, 0, 0, - ioremap(0xffe80000, 0x8000), 8); - - loops_per_jiffy = 100000000/HZ; - - lopec_find_bridges(); - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#elif defined(CONFIG_ROOT_NFS) - ROOT_DEV = Root_NFS; -#elif defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ROOT_DEV = Root_HDA1; -#else - ROOT_DEV = Root_SDA1; -#endif - -#ifdef CONFIG_VT - conswitchp = &dummy_con; -#endif -#ifdef CONFIG_PPCBUG_NVRAM - /* Read in NVRAM data */ - init_prep_nvram(); - - /* if no bootargs, look in NVRAM */ - if ( cmd_line[0] == '\0' ) { - char *bootargs; - bootargs = prep_nvram_get_var("bootargs"); - if (bootargs != NULL) { - strcpy(cmd_line, bootargs); - /* again.. */ - strcpy(saved_command_line, cmd_line); - } - } -#endif -} - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - parse_bootinfo(find_bootinfo()); - lopec_set_bat(); - - isa_io_base = MPC10X_MAPB_ISA_IO_BASE; - isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; - pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; - ISA_DMA_THRESHOLD = 0x00ffffff; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; - - ppc_md.setup_arch = lopec_setup_arch; - ppc_md.show_cpuinfo = lopec_show_cpuinfo; - ppc_md.irq_canonicalize = lopec_irq_canonicalize; - ppc_md.init_IRQ = lopec_init_IRQ; - ppc_md.get_irq = openpic_get_irq; - - ppc_md.restart = lopec_restart; - ppc_md.power_off = lopec_power_off; - ppc_md.halt = lopec_halt; - - ppc_md.setup_io_mappings = lopec_map_io; - - ppc_md.time_init = todc_time_init; - ppc_md.set_rtc_time = todc_set_rtc_time; - ppc_md.get_rtc_time = todc_get_rtc_time; - ppc_md.calibrate_decr = todc_calibrate_decr; - - ppc_md.nvram_read_val = todc_direct_read_val; - ppc_md.nvram_write_val = todc_direct_write_val; - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ppc_ide_md.default_irq = lopec_ide_default_irq; - ppc_ide_md.default_io_base = lopec_ide_default_io_base; - ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports; -#endif -#ifdef CONFIG_SERIAL_TEXT_DEBUG - ppc_md.progress = lopec_progress; -#endif -} diff -Nru a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c --- a/arch/ppc/platforms/mcpn765.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc/platforms/mcpn765.c 2004-10-18 14:56:48 -07:00 @@ -58,8 +58,6 @@ #include #include "mcpn765.h" -#include "mcpn765_serial.h" - static u_char mcpn765_openpic_initsenses[] __initdata = { (IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE),/* 16: i8259 cascade */ @@ -322,10 +320,6 @@ ROOT_DEV = Root_NFS; #else ROOT_DEV = Root_SDA2; -#endif - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; #endif if ( ppc_md.progress ) diff -Nru a/arch/ppc/platforms/mcpn765.h b/arch/ppc/platforms/mcpn765.h --- a/arch/ppc/platforms/mcpn765.h 2004-10-18 14:56:21 -07:00 +++ b/arch/ppc/platforms/mcpn765.h 2004-10-18 14:56:21 -07:00 @@ -6,7 +6,7 @@ * Author: Mark A. Greer * mgreer@mvista.com * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. @@ -25,6 +25,7 @@ #ifndef __PPC_PLATFORMS_MCPN765_H #define __PPC_PLATFORMS_MCPN765_H +#include /* PCI Memory space mapping info */ #define MCPN765_PCI_MEM_SIZE 0x40000000U @@ -65,13 +66,56 @@ #define MCPN765_BOARD_EXT_FEATURE_REG 0xfef880f0U #define MCPN765_BOARD_LAST_RESET_REG 0xfef880f8U -/* UART base addresses are defined in */ +/* Defines for UART */ + +/* Define the UART base addresses */ +#define MCPN765_SERIAL_1 0xfef88000 +#define MCPN765_SERIAL_2 0xfef88200 +#define MCPN765_SERIAL_3 0xfef88400 +#define MCPN765_SERIAL_4 0xfef88600 + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 4 +#endif + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD ( 1843200 / 16 ) +#define UART_CLK 1843200 + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#endif + +/* All UART IRQ's are wire-OR'd to IRQ 17 */ +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\ + iomem_base: (u8 *)MCPN765_SERIAL_1, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\ + iomem_base: (u8 *)MCPN765_SERIAL_2, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\ + iomem_base: (u8 *)MCPN765_SERIAL_3, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\ + iomem_base: (u8 *)MCPN765_SERIAL_4, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS /* Define the NVRAM/RTC address strobe & data registers */ #define MCPN765_PHYS_NVRAM_AS0 0xfef880c8U #define MCPN765_PHYS_NVRAM_AS1 0xfef880d0U #define MCPN765_PHYS_NVRAM_DATA 0xfef880d8U - extern void mcpn765_find_bridges(void); diff -Nru a/arch/ppc/platforms/mcpn765_serial.h b/arch/ppc/platforms/mcpn765_serial.h --- a/arch/ppc/platforms/mcpn765_serial.h 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,64 +0,0 @@ -/* - * include/asm-ppc/mcpn765_serial.h - * - * Definitions for Motorola MCG MCPN765 cPCI board support - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __ASMPPC_MCPN765_SERIAL_H -#define __ASMPPC_MCPN765_SERIAL_H - -#include - -/* Define the UART base addresses */ -#define MCPN765_SERIAL_1 0xfef88000 -#define MCPN765_SERIAL_2 0xfef88200 -#define MCPN765_SERIAL_3 0xfef88400 -#define MCPN765_SERIAL_4 0xfef88600 - -#ifdef CONFIG_SERIAL_MANY_PORTS -#define RS_TABLE_SIZE 64 -#else -#define RS_TABLE_SIZE 4 -#endif - -/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ -#define BASE_BAUD ( 1843200 / 16 ) -#define UART_CLK 1843200 - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#endif - -/* All UART IRQ's are wire-OR'd to IRQ 17 */ -#define STD_SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\ - iomem_base: (u8 *)MCPN765_SERIAL_1, \ - iomem_reg_shift: 4, \ - io_type: SERIAL_IO_MEM }, \ - { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\ - iomem_base: (u8 *)MCPN765_SERIAL_2, \ - iomem_reg_shift: 4, \ - io_type: SERIAL_IO_MEM }, \ - { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\ - iomem_base: (u8 *)MCPN765_SERIAL_3, \ - iomem_reg_shift: 4, \ - io_type: SERIAL_IO_MEM }, \ - { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\ - iomem_base: (u8 *)MCPN765_SERIAL_4, \ - iomem_reg_shift: 4, \ - io_type: SERIAL_IO_MEM }, - -#define SERIAL_PORT_DFNS \ - STD_SERIAL_PORT_DFNS - -#endif /* __ASMPPC_MCPN765_SERIAL_H */ diff -Nru a/arch/ppc/platforms/mpc5200.c b/arch/ppc/platforms/mpc5200.c --- a/arch/ppc/platforms/mpc5200.c 2004-10-18 14:56:17 -07:00 +++ b/arch/ppc/platforms/mpc5200.c 2004-10-18 14:56:17 -07:00 @@ -16,6 +16,12 @@ #include #include + +struct ocp_fs_i2c_data mpc5200_i2c_def = { + .flags = FS_I2C_CLOCK_5200, +}; + + /* Here is the core_ocp struct. * With all the devices common to all board. Even if port multiplexing is * not setup for them (if the user don't want them, just don't select the @@ -23,6 +29,24 @@ * board specific file. */ struct ocp_def core_ocp[] = { + { + .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = MPC52xx_I2C1, + .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C1 - Buggy */ + .pm = OCP_CPM_NA, + .additions = &mpc5200_i2c_def, + }, + { + .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_IIC, + .index = 1, + .paddr = MPC52xx_I2C2, + .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C2 - Buggy */ + .pm = OCP_CPM_NA, + .additions = &mpc5200_i2c_def, + }, { /* Terminating entry */ .vendor = OCP_VENDOR_INVALID } diff -Nru a/arch/ppc/platforms/mvme5100.c b/arch/ppc/platforms/mvme5100.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/platforms/mvme5100.c 2004-10-18 14:56:28 -07:00 @@ -0,0 +1,349 @@ +/* + * arch/ppc/platforms/mvme5100.c + * + * Board setup routines for the Motorola MVME5100. + * + * Author: Matt Porter + * + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static u_char mvme5100_openpic_initsenses[16] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* i8259 cascade */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* TL16C550 UART 1,2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet1 front panel or P2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Hawk Watchdog 1,2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* DS1621 thermal alarm */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT0# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT1# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT2# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT3# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTA#, PMC2 INTB# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTB#, PMC2 INTC# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTC#, PMC2 INTD# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTD#, PMC2 INTA# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet 2 (front panel) */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Abort Switch */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* RTC Alarm */ +}; + +static inline int +mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + int irq; + + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 0, 0, 0, 0 }, /* IDSEL 11 - Winbond */ + { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ + { 21, 22, 23, 24 }, /* IDSEL 13 - Universe II */ + { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 1 */ + { 0, 0, 0, 0 }, /* IDSEL 15 - unused */ + { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */ + { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */ + { 0, 0, 0, 0 }, /* IDSEL 18 - unused */ + { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 2 */ + { 0, 0, 0, 0 }, /* IDSEL 20 - PMCSPAN */ + }; + + const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4; + irq = PCI_IRQ_TABLE_LOOKUP; + /* If lookup is zero, always return 0 */ + if (!irq) + return 0; + else +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + /* If IPMC761 present, return table value */ + return irq; +#else + /* If IPMC761 not present, we don't have an i8259 so adjust */ + return (irq - NUM_8259_INTERRUPTS); +#endif +} + +static void +mvme5100_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + + if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) && + (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK)) + for (i=0; iresource[i].start = 0; + dev->resource[i].end = 0; + } +} + +static void __init +mvme5100_setup_bridge(void) +{ + struct pci_controller* hose; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, MVME5100_PCI_LOWER_IO, + MVME5100_PCI_UPPER_IO, IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], MVME5100_PCI_LOWER_MEM, + MVME5100_PCI_UPPER_MEM, IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = MVME5100_PCI_LOWER_IO; + hose->io_space.end = MVME5100_PCI_UPPER_IO; + hose->mem_space.start = MVME5100_PCI_LOWER_MEM; + hose->mem_space.end = MVME5100_PCI_UPPER_MEM; + hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE; + + /* Use indirect method of Hawk */ + setup_indirect_pci(hose, MVME5100_PCI_CONFIG_ADDR, + MVME5100_PCI_CONFIG_DATA); + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = mvme5100_map_irq; +} + +static void __init +mvme5100_setup_arch(void) +{ + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: enter", 0); + + loops_per_jiffy = 50000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: find_bridges", 0); + + /* Setup PCI host bridge */ + mvme5100_setup_bridge(); + + /* Find and map our OpenPIC */ + hawk_mpic_init(MVME5100_PCI_MEM_OFFSET); + OpenPIC_InitSenses = mvme5100_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses); + + printk("MVME5100 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: exit", 0); + + return; +} + +static void __init +mvme5100_init2(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + request_region(0x00,0x20,"dma1"); + request_region(0x20,0x20,"pic1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xa0,0x20,"pic2"); + request_region(0xc0,0x20,"dma2"); +#endif + return; +} + +/* + * Interrupt setup and service. + * Have MPIC on HAWK and cascaded 8259s on Winbond cascaded to MPIC. + */ +static void __init +mvme5100_init_IRQ(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + int i; +#endif + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: enter", 0); + + openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000); +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + openpic_init(NUM_8259_INTERRUPTS); + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + &i8259_irq); + + /* Map i8259 interrupts. */ + for (i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(NULL); +#else + openpic_init(0); +#endif + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: exit", 0); + + return; +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +mvme5100_set_bat(void) +{ + mb(); + mtspr(DBAT1U, 0xf0001ffe); + mtspr(DBAT1L, 0xf000002a); + mb(); +} + +static unsigned long __init +mvme5100_find_end_of_memory(void) +{ + return hawk_get_mem_size(MVME5100_HAWK_SMC_BASE); +} + +static void __init +mvme5100_map_io(void) +{ + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); + ioremap_base = 0xfe000000; +} + +static void +mvme5100_reset_board(void) +{ + local_irq_disable(); + + /* Set exception prefix high - to the firmware */ + _nmask_and_or_msr(0, MSR_IP); + + out_8((u_char *)MVME5100_BOARD_MODRST_REG, 0x01); + + return; +} + +static void +mvme5100_restart(char *cmd) +{ + volatile ulong i = 10000000; + + mvme5100_reset_board(); + + while (i-- > 0); + panic("restart failed\n"); +} + +static void +mvme5100_halt(void) +{ + local_irq_disable(); + while (1); +} + +static void +mvme5100_power_off(void) +{ + mvme5100_halt(); +} + +static int +mvme5100_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Motorola\n"); + seq_printf(m, "machine\t\t: MVME5100\n"); + + return 0; +} + +TODC_ALLOC(); + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + mvme5100_set_bat(); + + isa_io_base = MVME5100_ISA_IO_BASE; + isa_mem_base = MVME5100_ISA_MEM_BASE; + pci_dram_offset = MVME5100_PCI_DRAM_OFFSET; + + ppc_md.setup_arch = mvme5100_setup_arch; + ppc_md.show_cpuinfo = mvme5100_show_cpuinfo; + ppc_md.init_IRQ = mvme5100_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = mvme5100_init2; + + ppc_md.restart = mvme5100_restart; + ppc_md.power_off = mvme5100_power_off; + ppc_md.halt = mvme5100_halt; + + ppc_md.find_end_of_memory = mvme5100_find_end_of_memory; + ppc_md.setup_io_mappings = mvme5100_map_io; + + TODC_INIT(TODC_TYPE_MK48T37, MVME5100_NVRAM_AS0, MVME5100_NVRAM_AS1, + MVME5100_NVRAM_DATA, 8); + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_m48txx_read_val; + ppc_md.nvram_write_val = todc_m48txx_write_val; +} diff -Nru a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h --- a/arch/ppc/platforms/mvme5100.h 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/platforms/mvme5100.h 2004-10-18 14:56:49 -07:00 @@ -63,10 +63,29 @@ #define MVME5100_SERIAL_IRQ 1 #endif -#define MVME5100_WINBOND_DEVFN 0x58 -#define MVME5100_WINBOND_VIDDID 0x056510ad +#define RS_TABLE_SIZE 4 -extern void mvme5100_setup_bridge(void); +#define BASE_BAUD ( MVME5100_BASE_BAUD / 16 ) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +/* All UART IRQ's are wire-OR'd to one MPIC IRQ */ +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, MVME5100_SERIAL_1, \ + MVME5100_SERIAL_IRQ, \ + STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (unsigned char *)MVME5100_SERIAL_1, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MVME5100_SERIAL_2, \ + MVME5100_SERIAL_IRQ, \ + STD_COM_FLAGS, /* ttyS1 */ \ + iomem_base: (unsigned char *)MVME5100_SERIAL_2, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS #endif /* __ASM_MVME5100_H__ */ #endif /* __KERNEL__ */ diff -Nru a/arch/ppc/platforms/mvme5100_pci.c b/arch/ppc/platforms/mvme5100_pci.c --- a/arch/ppc/platforms/mvme5100_pci.c 2004-10-18 14:55:54 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,121 +0,0 @@ -/* - * arch/ppc/platforms/mvme5100_pci.c - * - * PCI setup routines for the Motorola MVME5100. - * - * Author: Matt Porter - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -static inline int -mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) -{ - int irq; - - static char pci_irq_table[][4] = - /* - * PCI IDSEL/INTPIN->INTLINE - * A B C D - */ - { - { 0, 0, 0, 0 }, /* IDSEL 11 - Winbond */ - { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ - { 21, 22, 23, 24 }, /* IDSEL 13 - Universe II */ - { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 1 */ - { 0, 0, 0, 0 }, /* IDSEL 15 - unused */ - { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */ - { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */ - { 0, 0, 0, 0 }, /* IDSEL 18 - unused */ - { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 2 */ - { 0, 0, 0, 0 }, /* IDSEL 20 - PMCSPAN */ - }; - - const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4; - irq = PCI_IRQ_TABLE_LOOKUP; - /* If lookup is zero, always return 0 */ - if (!irq) - return 0; - else -#ifdef CONFIG_MVME5100_IPMC761_PRESENT - /* If IPMC761 present, return table value */ - return irq; -#else - /* If IPMC761 not present, we don't have an i8259 so adjust */ - return (irq - NUM_8259_INTERRUPTS); -#endif -} - -static void -mvme5100_pcibios_fixup_resources(struct pci_dev *dev) -{ - int i; - - if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) && - (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK)) - for (i=0; iresource[i].start = 0; - dev->resource[i].end = 0; - } -} - -void __init -mvme5100_setup_bridge(void) -{ - struct pci_controller* hose; - - hose = pcibios_alloc_controller(); - - if (!hose) - return; - - hose->first_busno = 0; - hose->last_busno = 0xff; - hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET; - - pci_init_resource(&hose->io_resource, - MVME5100_PCI_LOWER_IO, - MVME5100_PCI_UPPER_IO, - IORESOURCE_IO, - "PCI host bridge"); - - pci_init_resource(&hose->mem_resources[0], - MVME5100_PCI_LOWER_MEM, - MVME5100_PCI_UPPER_MEM, - IORESOURCE_MEM, - "PCI host bridge"); - - hose->io_space.start = MVME5100_PCI_LOWER_IO; - hose->io_space.end = MVME5100_PCI_UPPER_IO; - hose->mem_space.start = MVME5100_PCI_LOWER_MEM; - hose->mem_space.end = MVME5100_PCI_UPPER_MEM; - hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE; - - /* Use indirect method of Hawk */ - setup_indirect_pci(hose, - MVME5100_PCI_CONFIG_ADDR, - MVME5100_PCI_CONFIG_DATA); - - hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); - - ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources; - ppc_md.pci_swizzle = common_swizzle; - ppc_md.pci_map_irq = mvme5100_map_irq; -} diff -Nru a/arch/ppc/platforms/mvme5100_serial.h b/arch/ppc/platforms/mvme5100_serial.h --- a/arch/ppc/platforms/mvme5100_serial.h 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,54 +0,0 @@ -/* - * include/asm-ppc/mvme5100_serial.h - * - * Definitions for Motorola MVME5100 support - * - * Author: Matt Porter - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifdef __KERNEL__ -#ifndef __ASM_MVME5100_SERIAL_H__ -#define __ASM_MVME5100_SERIAL_H__ - -#include -#include - -#ifdef CONFIG_SERIAL_MANY_PORTS -#define RS_TABLE_SIZE 64 -#else -#define RS_TABLE_SIZE 4 -#endif - -#define BASE_BAUD ( MVME5100_BASE_BAUD / 16 ) - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#endif - -/* All UART IRQ's are wire-OR'd to one MPIC IRQ */ -#define STD_SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, MVME5100_SERIAL_1, \ - MVME5100_SERIAL_IRQ, \ - STD_COM_FLAGS, /* ttyS0 */ \ - iomem_base: (unsigned char *)MVME5100_SERIAL_1, \ - iomem_reg_shift: 4, \ - io_type: SERIAL_IO_MEM }, \ - { 0, BASE_BAUD, MVME5100_SERIAL_2, \ - MVME5100_SERIAL_IRQ, \ - STD_COM_FLAGS, /* ttyS1 */ \ - iomem_base: (unsigned char *)MVME5100_SERIAL_2, \ - iomem_reg_shift: 4, \ - io_type: SERIAL_IO_MEM }, - -#define SERIAL_PORT_DFNS \ - STD_SERIAL_PORT_DFNS - -#endif /* __ASM_MVME5100_SERIAL_H__ */ -#endif /* __KERNEL__ */ diff -Nru a/arch/ppc/platforms/mvme5100_setup.c b/arch/ppc/platforms/mvme5100_setup.c --- a/arch/ppc/platforms/mvme5100_setup.c 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,284 +0,0 @@ -/* - * arch/ppc/platforms/mvme5100_setup.c - * - * Board setup routines for the Motorola MVME5100. - * - * Author: Matt Porter - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern char cmd_line[]; - -static u_char mvme5100_openpic_initsenses[] __initdata = { - 0, /* 16: i8259 cascade (active high) */ - 1, /* 17: TL16C550 UART 1,2 */ - 1, /* 18: Enet 1 (front panel or P2) */ - 1, /* 19: Hawk Watchdog 1,2 */ - 1, /* 20: DS1621 thermal alarm */ - 1, /* 21: Universe II LINT0# */ - 1, /* 22: Universe II LINT1# */ - 1, /* 23: Universe II LINT2# */ - 1, /* 24: Universe II LINT3# */ - 1, /* 25: PMC1 INTA#, PMC2 INTB# */ - 1, /* 26: PMC1 INTB#, PMC2 INTC# */ - 1, /* 27: PMC1 INTC#, PMC2 INTD# */ - 1, /* 28: PMC1 INTD#, PMC2 INTA# */ - 1, /* 29: Enet 2 (front panel) */ - 1, /* 30: Abort Switch */ - 1, /* 31: RTC Alarm */ -}; - -static void __init -mvme5100_setup_arch(void) -{ - if ( ppc_md.progress ) - ppc_md.progress("mvme5100_setup_arch: enter", 0); - - loops_per_jiffy = 50000000 / HZ; - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_SDA2; -#endif - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - if ( ppc_md.progress ) - ppc_md.progress("mvme5100_setup_arch: find_bridges", 0); - - /* Setup PCI host bridge */ - mvme5100_setup_bridge(); - - /* Find and map our OpenPIC */ - pplus_mpic_init(MVME5100_PCI_MEM_OFFSET); - OpenPIC_InitSenses = mvme5100_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses); - - printk("MVME5100 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); - - if ( ppc_md.progress ) - ppc_md.progress("mvme5100_setup_arch: exit", 0); - - return; -} - -static void __init -mvme5100_init2(void) -{ -#ifdef CONFIG_MVME5100_IPMC761_PRESENT - request_region(0x00,0x20,"dma1"); - request_region(0x20,0x20,"pic1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xa0,0x20,"pic2"); - request_region(0xc0,0x20,"dma2"); -#endif - return; -} - -/* - * Interrupt setup and service. - * Have MPIC on HAWK and cascaded 8259s on Winbond cascaded to MPIC. - */ -static void __init -mvme5100_init_IRQ(void) -{ -#ifdef CONFIG_MVME5100_IPMC761_PRESENT - int i; -#endif - - if ( ppc_md.progress ) - ppc_md.progress("init_irq: enter", 0); - -#ifdef CONFIG_MVME5100_IPMC761_PRESENT - openpic_init(1, NUM_8259_INTERRUPTS, NULL, -1); - openpic_hookup_cascade(NUM_8259_INTERRUPTS,"82c59 cascade",&i8259_irq); - - for(i=0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - - i8259_init(NULL); -#else - openpic_init(1, 0, NULL, -1); -#endif - - if ( ppc_md.progress ) - ppc_md.progress("init_irq: exit", 0); - - return; -} - -/* - * Set BAT 3 to map 0xf0000000 to end of physical memory space. - */ -static __inline__ void -mvme5100_set_bat(void) -{ - unsigned long bat3u, bat3l; - static int mapping_set = 0; - - if (!mapping_set) { - - __asm__ __volatile__( - " lis %0,0xf000\n \ - ori %1,%0,0x002a\n \ - ori %0,%0,0x1ffe\n \ - mtspr 0x21e,%0\n \ - mtspr 0x21f,%1\n \ - isync\n \ - sync " - : "=r" (bat3u), "=r" (bat3l)); - - mapping_set = 1; - } - - return; -} - -static unsigned long __init -mvme5100_find_end_of_memory(void) -{ - mvme5100_set_bat(); - return pplus_get_mem_size(MVME5100_HAWK_SMC_BASE); -} - -static void __init -mvme5100_map_io(void) -{ - io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); - ioremap_base = 0xfe000000; -} - -static void -mvme5100_reset_board(void) -{ - local_irq_disable(); - - /* Set exception prefix high - to the firmware */ - _nmask_and_or_msr(0, MSR_IP); - - out_8((u_char *)MVME5100_BOARD_MODRST_REG, 0x01); - - return; -} - -static void -mvme5100_restart(char *cmd) -{ - volatile ulong i = 10000000; - - mvme5100_reset_board(); - - while (i-- > 0); - panic("restart failed\n"); -} - -static void -mvme5100_halt(void) -{ - local_irq_disable(); - while (1); -} - -static void -mvme5100_power_off(void) -{ - mvme5100_halt(); -} - -static int -mvme5100_show_cpuinfo(struct seq_file *m) -{ - seq_printf(m, "vendor\t\t: Motorola\n"); - seq_printf(m, "machine\t\t: MVME5100\n"); - - return 0; -} - -TODC_ALLOC(); - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - parse_bootinfo(find_bootinfo()); - - isa_io_base = MVME5100_ISA_IO_BASE; - isa_mem_base = MVME5100_ISA_MEM_BASE; - pci_dram_offset = MVME5100_PCI_DRAM_OFFSET; - - ppc_md.setup_arch = mvme5100_setup_arch; - ppc_md.show_cpuinfo = mvme5100_show_cpuinfo; - ppc_md.init_IRQ = mvme5100_init_IRQ; - ppc_md.get_irq = openpic_get_irq; - ppc_md.init = mvme5100_init2; - - ppc_md.restart = mvme5100_restart; - ppc_md.power_off = mvme5100_power_off; - ppc_md.halt = mvme5100_halt; - - ppc_md.find_end_of_memory = mvme5100_find_end_of_memory; - ppc_md.setup_io_mappings = mvme5100_map_io; - - TODC_INIT(TODC_TYPE_MK48T37, - MVME5100_NVRAM_AS0, - MVME5100_NVRAM_AS1, - MVME5100_NVRAM_DATA, - 8); - - ppc_md.time_init = todc_time_init; - ppc_md.set_rtc_time = todc_set_rtc_time; - ppc_md.get_rtc_time = todc_get_rtc_time; - ppc_md.calibrate_decr = todc_calibrate_decr; - - ppc_md.nvram_read_val = todc_m48txx_read_val; - ppc_md.nvram_write_val = todc_m48txx_write_val; - - ppc_md.progress = NULL; -} diff -Nru a/arch/ppc/platforms/pcore.c b/arch/ppc/platforms/pcore.c --- a/arch/ppc/platforms/pcore.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/platforms/pcore.c 2004-10-18 14:55:54 -07:00 @@ -228,10 +228,6 @@ ROOT_DEV = Root_SDA2; #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - printk(KERN_INFO "Force PowerCore "); if (board_type == PCORE_TYPE_6750) printk("6750\n"); diff -Nru a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c --- a/arch/ppc/platforms/pmac_cpufreq.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc/platforms/pmac_cpufreq.c 2004-10-18 14:56:33 -07:00 @@ -24,10 +24,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -301,7 +301,6 @@ static int __pmac do_set_cpu_speed(int speed_mode) { struct cpufreq_freqs freqs; - int rc; freqs.old = cur_freq; freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; @@ -315,7 +314,7 @@ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; - return rc; + return 0; } static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy) @@ -498,7 +497,7 @@ * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz) * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) - * - iBook2 500 (PMU based, 400Mhz & 500Mhz) + * - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz) * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) * - Recent MacRISC3 laptops * - iBook G4s and PowerBook G4s with 7447A CPUs @@ -533,11 +532,8 @@ machine_is_compatible("PowerBook3,5") || machine_is_compatible("MacRISC3")) { pmac_cpufreq_init_MacRISC3(cpunode); - /* Else check for iBook2 500 */ + /* Else check for iBook2 500/600 */ } else if (machine_is_compatible("PowerBook4,1")) { - /* We only know about 500Mhz model */ - if (cur_freq < 450000 || cur_freq > 550000) - goto out; hi_freq = cur_freq; low_freq = 400000; set_speed_proc = pmu_set_cpu_speed; diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c --- a/arch/ppc/platforms/pmac_feature.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/platforms/pmac_feature.c 2004-10-18 14:57:03 -07:00 @@ -2665,7 +2665,7 @@ struct device_node *p = of_get_parent(ui2c); if (p && !strcmp(p->name, "uni-n")) break; - ui2c = of_find_node_by_type(np, "i2c"); + ui2c = of_find_node_by_type(ui2c, "i2c"); } if (ui2c == NULL) break; diff -Nru a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c --- a/arch/ppc/platforms/pmac_pci.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/platforms/pmac_pci.c 2004-10-18 14:56:32 -07:00 @@ -50,6 +50,7 @@ #endif /* CONFIG_POWER4 */ extern u8 pci_cache_line_size; +extern int pcibios_assign_bus_offset; struct pci_dev *k2_skiplist[2]; @@ -315,6 +316,10 @@ unsigned int addr; int i; + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + /* * When a device in K2 is powered down, we die on config * cycle accesses. Fix that here. @@ -362,6 +367,9 @@ unsigned int addr; int i; + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; /* * When a device in K2 is powered down, we die on config * cycle accesses. Fix that here. @@ -565,6 +573,14 @@ init_p2pbridge(); fixup_nec_usb2(); + + /* We are still having some issues with the Xserve G4, enabling + * some offset between bus number and domains for now when we + * assign all busses should help for now + */ + if (pci_assign_all_busses) + pcibios_assign_bus_offset = 0x10; + #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 @@ -707,7 +723,7 @@ * properties or figuring out the U3 address space decoding logic and * then read its configuration register (if any). */ - hose->io_base_phys = 0xf4000000 + 0x00400000; + hose->io_base_phys = 0xf4000000; 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; @@ -1034,6 +1050,8 @@ } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus); + void pmac_pci_fixup_pciata(struct pci_dev* dev) { u8 progif = 0; @@ -1074,6 +1092,8 @@ printk(KERN_ERR "Rewrite of PROGIF failed !\n"); } } +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata); + /* * Disable second function on K2-SATA, it's broken @@ -1104,3 +1124,4 @@ } } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata); diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c --- a/arch/ppc/platforms/pmac_setup.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc/platforms/pmac_setup.c 2004-10-18 14:56:33 -07:00 @@ -318,9 +318,6 @@ #ifdef CONFIG_NVRAM pmac_nvram_init(); #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) ROOT_DEV = Root_RAM0; diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c --- a/arch/ppc/platforms/pmac_smp.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/platforms/pmac_smp.c 2004-10-18 14:56:32 -07:00 @@ -32,13 +32,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c --- a/arch/ppc/platforms/pmac_time.c 2004-10-18 14:56:27 -07:00 +++ b/arch/ppc/platforms/pmac_time.c 2004-10-18 14:56:27 -07:00 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h --- a/arch/ppc/platforms/powerpmc250.h 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc/platforms/powerpmc250.h 2004-10-18 14:56:48 -07:00 @@ -7,7 +7,7 @@ * * Borrowed heavily from prpmc750.h by Matt Porter * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. @@ -16,8 +16,6 @@ #ifndef __ASMPPC_POWERPMC250_H #define __ASMPPC_POWERPMC250_H -#include - #define POWERPMC250_PCI_CONFIG_ADDR 0x80000cf8 #define POWERPMC250_PCI_CONFIG_DATA 0x80000cfc @@ -36,5 +34,19 @@ #define POWERPMC250_BASE_BAUD 12288000 #define POWERPMC250_SERIAL 0xff000000 #define POWERPMC250_SERIAL_IRQ 20 + +/* UART Defines. */ +#define RS_TABLE_SIZE 1 + +#define BASE_BAUD (POWERPMC250_BASE_BAUD / 16) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, POWERPMC250_SERIAL, POWERPMC250_SERIAL_IRQ, \ + STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (u8 *)POWERPMC250_SERIAL, \ + iomem_reg_shift: 0, \ + io_type: SERIAL_IO_MEM } #endif /* __ASMPPC_POWERPMC250_H */ diff -Nru a/arch/ppc/platforms/powerpmc250_serial.h b/arch/ppc/platforms/powerpmc250_serial.h --- a/arch/ppc/platforms/powerpmc250_serial.h 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,40 +0,0 @@ -/* - * include/asm-ppc/platforms/powerpmc250_serial.h - * - * Motorola PrPMC750 serial support - * - * Author: Troy Benjegerdes - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifdef __KERNEL__ -#ifndef __ASMPPC_POWERPMC250_SERIAL_H -#define __ASMPPC_POWERPMC250_SERIAL_H - -#include -#include - -#define RS_TABLE_SIZE 1 - -#define BASE_BAUD (POWERPMC250_BASE_BAUD / 16) - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) -#endif - -#define SERIAL_PORT_DFNS \ -{ 0, BASE_BAUD, POWERPMC250_SERIAL, POWERPMC250_SERIAL_IRQ, STD_COM_FLAGS, /* ttyS0 */\ - iomem_base: (u8 *)POWERPMC250_SERIAL, \ - iomem_reg_shift: 0, \ - io_type: SERIAL_IO_MEM } - -#endif -#endif /* __KERNEL__ */ diff -Nru a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c --- a/arch/ppc/platforms/pplus.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/platforms/pplus.c 2004-10-18 14:57:04 -07:00 @@ -583,8 +583,6 @@ vgacon_remap_base = (unsigned long)ioremap(PPLUS_ISA_MEM_BASE, 0x08000000); conswitchp = &vga_con; -#elif defined(CONFIG_DUMMY_CONSOLE) - conswitchp = &dummy_con; #endif #ifdef CONFIG_PPCBUG_NVRAM /* Read in NVRAM data */ diff -Nru a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/platforms/pq2ads.c 2004-10-18 14:57:05 -07:00 @@ -0,0 +1,26 @@ +/* + * arch/ppc/platforms/pq2ads.c + * + * PQ2ADS platform support + * + * Author: Kumar Gala + * Derived from: est8260_setup.c by Allen Curtis + * + * Copyright 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include + +#include + +void __init +m82xx_board_init(void) +{ + /* Enable the 2nd UART port */ + *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2; +} diff -Nru a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h --- a/arch/ppc/platforms/pq2ads.h 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/platforms/pq2ads.h 2004-10-18 14:56:32 -07:00 @@ -23,6 +23,10 @@ #define BOOTROM_RESTART_ADDR ((uint)0xff000104) +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "Motorola" +#define CPUINFO_MACHINE "PQ2 ADS PowerPC" + /* The ADS8260 has 16, 32-bit wide control/status registers, accessed * only on word boundaries. * Not all are used (yet), or are interesting to us (yet). diff -Nru a/arch/ppc/platforms/pq2ads_setup.c b/arch/ppc/platforms/pq2ads_setup.c --- a/arch/ppc/platforms/pq2ads_setup.c 2004-10-18 14:57:05 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,66 +0,0 @@ -/* - * arch/ppc/platforms/pq2ads_setup.c - * - * PQ2ADS platform support - * - * Author: Kumar Gala - * Derived from: est8260_setup.c by Allen Curtis - * - * Copyright 2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include - -#include -#include - -static void (*callback_setup_arch)(void); - -extern unsigned char __res[sizeof(bd_t)]; - -extern void m8260_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); - -static int -pq2ads_show_cpuinfo(struct seq_file *m) -{ - bd_t *binfo = (bd_t *)__res; - - seq_printf(m, "vendor\t\t: Motorola\n" - "machine\t\t: PQ2 ADS PowerPC\n" - "\n" - "mem size\t\t: 0x%08lx\n" - "console baud\t\t: %ld\n" - "\n", - binfo->bi_memsize, - binfo->bi_baudrate); - return 0; -} - -static void __init -pq2ads_setup_arch(void) -{ - printk("PQ2 ADS Port\n"); - callback_setup_arch(); - *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2; -} - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* Generic 8260 platform initialization */ - m8260_init(r3, r4, r5, r6, r7); - - /* Anything special for this platform */ - ppc_md.show_cpuinfo = pq2ads_show_cpuinfo; - - callback_setup_arch = ppc_md.setup_arch; - ppc_md.setup_arch = pq2ads_setup_arch; -} diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c --- a/arch/ppc/platforms/prep_pci.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/platforms/prep_pci.c 2004-10-18 14:57:04 -07:00 @@ -836,52 +836,59 @@ void __init ibm_prep_init(void) { -#ifdef CONFIG_PREP_RESIDUAL - u32 addr, real_addr, len; - PPC_DEVICE *mpic; - PnP_TAG_PACKET *pkt; - - /* Use the PReP residual data to determine if an OpenPIC is - * present. If so, get the large vendor packet which will - * tell us the base address and length in memory. - * If we are successful, ioremap the memory area and set - * OpenPIC_Addr (this indicates that the OpenPIC was found). - */ - mpic = residual_find_device(-1, NULL, SystemPeripheral, - ProgrammableInterruptController, MPIC, 0); - if (!mpic) - return; + if (have_residual_data) { + u32 addr, real_addr, len, offset; + PPC_DEVICE *mpic; + PnP_TAG_PACKET *pkt; + + /* Use the PReP residual data to determine if an OpenPIC is + * present. If so, get the large vendor packet which will + * tell us the base address and length in memory. + * If we are successful, ioremap the memory area and set + * OpenPIC_Addr (this indicates that the OpenPIC was found). + */ + mpic = residual_find_device(-1, NULL, SystemPeripheral, + ProgrammableInterruptController, MPIC, 0); + if (!mpic) + return; - pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + - mpic->AllocatedOffset, 9, 0); + pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + + mpic->AllocatedOffset, 9, 0); - if (!pkt) - return; + if (!pkt) + return; #define p pkt->L4_Pack.L4_Data.L4_PPCPack - if (!((p.PPCData[0] == 2) && (p.PPCData[1] == 32))) - return; /* not a 32-bit memory address */ - - real_addr = ld_le32((unsigned int *) (p.PPCData + 4)); - if (real_addr == 0xffffffff) - return; - - /* Adjust address to be as seen by CPU */ - addr = real_addr + PREP_ISA_MEM_BASE; + if (p.PPCData[1] == 32) { + switch (p.PPCData[0]) { + case 1: offset = PREP_ISA_IO_BASE; break; + case 2: offset = PREP_ISA_MEM_BASE; break; + default: return; /* Not I/O or memory?? */ + } + } + else + return; /* Not a 32-bit address */ - len = ld_le32((unsigned int *) (p.PPCData + 12)); - if (!len) - return; + real_addr = ld_le32((unsigned int *) (p.PPCData + 4)); + if (real_addr == 0xffffffff) + return; + + /* Adjust address to be as seen by CPU */ + addr = real_addr + offset; + + len = ld_le32((unsigned int *) (p.PPCData + 12)); + if (!len) + return; #undef p - OpenPIC_Addr = ioremap(addr, len); - ppc_md.get_irq = openpic_get_irq; + OpenPIC_Addr = ioremap(addr, len); + ppc_md.get_irq = openpic_get_irq; - OpenPIC_InitSenses = prep_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses); + OpenPIC_InitSenses = prep_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses); - printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x " - "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr); -#endif + printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x " + "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr); + } } static void __init @@ -901,6 +908,17 @@ } void __init +prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + if (have_residual_data) { + Motherboard_map_name = res->VitalProductData.PrintableModel; + Motherboard_map = NULL; + Motherboard_routes = NULL; + residual_irq_mask(irq_edge_mask_lo, irq_edge_mask_hi); + } +} + +void __init prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi) { Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)"; @@ -1011,21 +1029,31 @@ } } else if ( _prep_type == _PREP_IBM ) { unsigned char irq_edge_mask_lo, irq_edge_mask_hi; + unsigned short irq_edge_mask; + int i; setup_ibm_pci(&irq_edge_mask_lo, &irq_edge_mask_hi); outb(inb(0x04d0)|irq_edge_mask_lo, 0x4d0); /* primary 8259 */ outb(inb(0x04d1)|irq_edge_mask_hi, 0x4d1); /* cascaded 8259 */ + + irq_edge_mask = (irq_edge_mask_hi << 8) | irq_edge_mask_lo; + for (i = 0; i < 16; ++i, irq_edge_mask >>= 1) + if (irq_edge_mask & 1) + irq_desc[i].status |= IRQ_LEVEL; } else { printk("No known machine pci routing!\n"); return; } /* Set up mapping from slots */ - for (i = 1; i <= 4; i++) - ibc_pirq[i-1] = Motherboard_routes[i]; - /* Enable PCI interrupts */ - *ibc_pcicon |= 0x20; + if (Motherboard_routes) { + for (i = 1; i <= 4; i++) + ibc_pirq[i-1] = Motherboard_routes[i]; + + /* Enable PCI interrupts */ + *ibc_pcicon |= 0x20; + } } void __init @@ -1171,38 +1199,52 @@ prep_pcibios_fixup(void) { struct pci_dev *dev = NULL; + int irq; + int have_openpic = (OpenPIC_Addr != NULL); prep_route_pci_interrupts(); printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name); - if (OpenPIC_Addr) { - /* PCI interrupts are controlled by the OpenPIC */ - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (dev->bus->number == 0) { - dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } else { - if (Motherboard_non0 != NULL) - Motherboard_non0(dev); - } - } - - /* Setup the Winbond or Via PIB */ - prep_pib_init(); - - return; - } - dev = NULL; + /* Iterate through all the PCI devices, setting the IRQ */ while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* - * Use our old hard-coded kludge to figure out what - * irq this device uses. This is necessary on things - * without residual data. -- Cort + * If we have residual data, then this is easy: query the + * residual data for the IRQ line allocated to the device. + * This works the same whether we have an OpenPic or not. + */ + if (have_residual_data) { + irq = residual_pcidev_irq(dev); + dev->irq = have_openpic ? openpic_to_irq(irq) : irq; + } + /* + * If we don't have residual data, then we need to use + * tables to determine the IRQ. The table organisation + * is different depending on whether there is an OpenPIC + * or not. The tables are only used for bus 0, so check + * this first. */ - unsigned char d = PCI_SLOT(dev->devfn); - dev->irq = Motherboard_routes[Motherboard_map[d]]; + else if (dev->bus->number == 0) { + irq = Motherboard_map[PCI_SLOT(dev->devfn)]; + dev->irq = have_openpic ? openpic_to_irq(irq) + : Motherboard_routes[irq]; + } + /* + * Finally, if we don't have residual data and the bus is + * non-zero, use the callback (if provided) + */ + else { + if (Motherboard_non0 != NULL) + Motherboard_non0(dev); + + continue; + } + + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); } + + /* Setup the Winbond or Via PIB */ + prep_pib_init(); } static void __init @@ -1262,14 +1304,15 @@ PREP_ISA_IO_BASE + 0xcfc); printk("PReP architecture\n"); -#ifdef CONFIG_PREP_RESIDUAL - { + + if (have_residual_data) { PPC_DEVICE *hostbridge; hostbridge = residual_find_device(PROCESSORDEVICE, NULL, BridgeController, PCIBridge, -1, 0); if (hostbridge && - hostbridge->DeviceId.Interface == PCIBridgeIndirect) { + ((hostbridge->DeviceId.Interface == PCIBridgeIndirect) || + (hostbridge->DeviceId.Interface == PCIBridgeRS6K))) { PnP_TAG_PACKET * pkt; pkt = PnP_find_large_vendor_packet( res->DevicePnPHeap+hostbridge->AllocatedOffset, @@ -1284,7 +1327,6 @@ setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc); } } -#endif /* CONFIG_PREP_RESIDUAL */ ppc_md.pcibios_fixup = prep_pcibios_fixup; ppc_md.pcibios_after_init = prep_pcibios_after_init; diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c --- a/arch/ppc/platforms/prep_setup.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc/platforms/prep_setup.c 2004-10-18 14:56:50 -07:00 @@ -79,6 +79,7 @@ int _prep_type; +extern void prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); extern void prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); extern void prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); extern void prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); @@ -193,9 +194,8 @@ seq_printf(m, "bad"); seq_printf(m, "\n"); -#ifdef CONFIG_PREP_RESIDUAL /* print info about SIMMs */ - if (res->ResidualLength != 0) { + if (have_residual_data) { int i; seq_printf(m, "simms\t\t: "); for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) { @@ -207,7 +207,13 @@ } seq_printf(m, "\n"); } -#endif +} + +static int __prep +prep_gen_cpuinfo(struct seq_file *m) +{ + prep_ibm_cpuinfo(m); + return 0; } static int __prep @@ -431,9 +437,8 @@ } no_l2: -#ifdef CONFIG_PREP_RESIDUAL /* print info about SIMMs */ - if (res->ResidualLength != 0) { + if (have_residual_data) { int i; seq_printf(m, "simms\t\t: "); for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) { @@ -445,18 +450,11 @@ } seq_printf(m, "\n"); } -#endif return 0; } static void __prep -prep_tiger1_progress(char *msg, unsigned short code) -{ - outw(code, PREP_IBM_DISP); -} - -static void __prep prep_restart(char *cmd) { #define PREP_SP92 0x92 /* Special Port 92 */ @@ -561,14 +559,12 @@ { /* PREP's without residual data will give incorrect values here */ seq_printf(m, "clock\t\t: "); -#ifdef CONFIG_PREP_RESIDUAL - if (res->ResidualLength) + if (have_residual_data) seq_printf(m, "%ldMHz\n", (res->VitalProductData.ProcessorHz > 1024) ? res->VitalProductData.ProcessorHz / 1000000 : res->VitalProductData.ProcessorHz); else -#endif /* CONFIG_PREP_RESIDUAL */ seq_printf(m, "???\n"); return 0; @@ -598,9 +594,10 @@ * Get the needed resource informations from residual data. * */ -#ifdef CONFIG_PREP_RESIDUAL - audiodevice = residual_find_device(~0, NULL, MultimediaController, - AudioController, -1, 0); + if (have_residual_data) + audiodevice = residual_find_device(~0, NULL, + MultimediaController, AudioController, -1, 0); + if (audiodevice != NULL) { PnP_TAG_PACKET *pkt; @@ -613,7 +610,6 @@ if (pkt != NULL) ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask); } -#endif /* * These are the PReP specs' defaults for the cs4231. We use these @@ -649,13 +645,14 @@ static void __init prep_init_vesa(void) { -#if defined(CONFIG_PREP_RESIDUAL) && \ - (defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA_16_MODULE) || \ +#if (defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA_16_MODULE) || \ defined(CONFIG_FB_VESA)) - PPC_DEVICE *vgadev; + PPC_DEVICE *vgadev = NULL; + + if (have_residual_data) + vgadev = residual_find_device(~0, NULL, DisplayController, + SVGAController, -1, 0); - vgadev = residual_find_device(~0, NULL, DisplayController, SVGAController, - -1, 0); if (vgadev != NULL) { PnP_TAG_PACKET *pkt; @@ -680,7 +677,112 @@ } } } -#endif /* CONFIG_PREP_RESIDUAL */ +#endif +} + +/* + * Set DBAT 2 to access 0x80000000 so early progress messages will work + */ +static __inline__ void +prep_set_bat(void) +{ + /* wait for all outstanding memory access to complete */ + mb(); + + /* setup DBATs */ + mtspr(DBAT2U, 0x80001ffe); + mtspr(DBAT2L, 0x8000002a); + + /* wait for updates */ + mb(); +} + +/* + * IBM 3-digit status LED + */ +static unsigned int ibm_statusled_base __prepdata; + +static void __prep +ibm_statusled_progress(char *s, unsigned short hex); + +static int __prep +ibm_statusled_panic(struct notifier_block *dummy1, unsigned long dummy2, + void * dummy3) +{ + ibm_statusled_progress(NULL, 0x505); /* SOS */ + return NOTIFY_DONE; +} + +static struct notifier_block ibm_statusled_block __prepdata = { + ibm_statusled_panic, + NULL, + INT_MAX /* try to do it first */ +}; + +static void __prep +ibm_statusled_progress(char *s, unsigned short hex) +{ + static int notifier_installed; + /* + * Progress uses 4 digits and we have only 3. So, we map 0xffff to + * 0xfff for display switch off. Out of range values are mapped to + * 0xeff, as I'm told 0xf00 and above are reserved for hardware codes. + * Install the panic notifier when the display is first switched off. + */ + if (hex == 0xffff) { + hex = 0xfff; + if (!notifier_installed) { + ++notifier_installed; + notifier_chain_register(&panic_notifier_list, + &ibm_statusled_block); + } + } + else + if (hex > 0xfff) + hex = 0xeff; + + mb(); + outw(hex, ibm_statusled_base); +} + +static void __init +ibm_statusled_init(void) +{ + /* + * The IBM 3-digit LED display is specified in the residual data + * as an operator panel device, type "System Status LED". Find + * that device and determine its address. We validate all the + * other parameters on the off-chance another, similar device + * exists. + */ + if (have_residual_data) { + PPC_DEVICE *led; + PnP_TAG_PACKET *pkt; + + led = residual_find_device(~0, NULL, SystemPeripheral, + OperatorPanel, SystemStatusLED, 0); + if (!led) + return; + + pkt = PnP_find_packet((unsigned char *) + &res->DevicePnPHeap[led->AllocatedOffset], S8_Packet, 0); + if (!pkt) + return; + + if (pkt->S8_Pack.IOInfo != ISAAddr16bit) + return; + if (*(unsigned short *)pkt->S8_Pack.RangeMin != + *(unsigned short *)pkt->S8_Pack.RangeMax) + return; + if (pkt->S8_Pack.IOAlign != 2) + return; + if (pkt->S8_Pack.IONum != 2) + return; + + ibm_statusled_base = ld_le16((unsigned short *) + (pkt->S8_Pack.RangeMin)); + ppc_md.progress = ibm_statusled_progress; + } } static void __init @@ -706,7 +808,7 @@ { case _PREP_IBM: reg = inb(PREP_IBM_PLANAR); - printk(KERN_INFO "IBM planar ID: %08x", reg); + printk(KERN_INFO "IBM planar ID: %02x", reg); switch (reg) { case PREP_IBM_SANDALFOOT: prep_gen_enable_l2(); @@ -721,7 +823,16 @@ ppc_md.show_cpuinfo = prep_thinkpad_cpuinfo; break; default: - printk(" -- unknown! Assuming Carolina"); + if (have_residual_data) { + prep_gen_enable_l2(); + setup_ibm_pci = prep_residual_setup_pci; + ppc_md.power_off = prep_halt; + ppc_md.show_cpuinfo = prep_gen_cpuinfo; + break; + } + else + printk(" - unknown! Assuming Carolina"); + /* fall through */ case PREP_IBM_CAROLINA_IDE_0: case PREP_IBM_CAROLINA_IDE_1: case PREP_IBM_CAROLINA_IDE_2: @@ -745,7 +856,6 @@ setup_ibm_pci = prep_tiger1_setup_pci; ppc_md.power_off = prep_sig750_poweroff; ppc_md.show_cpuinfo = prep_tiger1_cpuinfo; - ppc_md.progress = prep_tiger1_progress; break; } printk("\n"); @@ -808,8 +918,6 @@ /* vgacon.c needs to know where we mapped IO memory in io_block_mapping() */ vgacon_remap_base = 0xf0000000; conswitchp = &vga_con; -#elif defined(CONFIG_DUMMY_CONSOLE) - conswitchp = &dummy_con; #endif } @@ -821,18 +929,19 @@ static void __init prep_calibrate_decr(void) { -#ifdef CONFIG_PREP_RESIDUAL - unsigned long freq, divisor = 4; + if (have_residual_data) { + unsigned long freq, divisor = 4; - if ( res->VitalProductData.ProcessorBusHz ) { - freq = res->VitalProductData.ProcessorBusHz; - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - (freq/divisor)/1000000, - (freq/divisor)%1000000); - tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); - tb_ticks_per_jiffy = freq / HZ / divisor; - } else -#endif + if ( res->VitalProductData.ProcessorBusHz ) { + freq = res->VitalProductData.ProcessorBusHz; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + (freq/divisor)/1000000, + (freq/divisor)%1000000); + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); + tb_ticks_per_jiffy = freq / HZ / divisor; + } + } + else todc_calibrate_decr(); } @@ -863,6 +972,12 @@ } for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) irq_desc[i].handler = &i8259_pic; + + if (have_residual_data) { + i8259_init(residual_isapic_addr()); + return; + } + /* If we have a Raven PCI bridge or a Hawk PCI bridge / Memory * controller, we poll (as they have a different int-ack address). */ early_read_config_dword(NULL, 0, 0, PCI_VENDOR_ID, &pci_viddid); @@ -1000,17 +1115,26 @@ DMA_MODE_WRITE = 0x48; /* figure out what kind of prep workstation we are */ -#ifdef CONFIG_PREP_RESIDUAL - if ( res->ResidualLength != 0 ) { + if (have_residual_data) { if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) _prep_type = _PREP_IBM; else _prep_type = _PREP_Motorola; - } else /* assume motorola if no residual (netboot?) */ -#endif - { + } + else { + /* assume motorola if no residual (netboot?) */ _prep_type = _PREP_Motorola; } + +#ifdef CONFIG_PREP_PRESIDUAL + /* Switch off all residual data processing if the user requests it */ + if (strstr(cmd_line, "noresidual") != NULL) + res = NULL; +#endif + + /* Initialise progress early to get maximum benefit */ + prep_set_bat(); + ibm_statusled_init(); ppc_md.setup_arch = prep_setup_arch; ppc_md.show_percpuinfo = prep_show_percpuinfo; diff -Nru a/arch/ppc/platforms/prpmc750.c b/arch/ppc/platforms/prpmc750.c --- a/arch/ppc/platforms/prpmc750.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/platforms/prpmc750.c 2004-10-18 14:57:03 -07:00 @@ -193,10 +193,6 @@ ROOT_DEV = Root_SDA2; #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - OpenPIC_InitSenses = prpmc750_openpic_initsenses; OpenPIC_NumInitSenses = sizeof(prpmc750_openpic_initsenses); diff -Nru a/arch/ppc/platforms/prpmc750.h b/arch/ppc/platforms/prpmc750.h --- a/arch/ppc/platforms/prpmc750.h 2004-10-18 14:56:27 -07:00 +++ b/arch/ppc/platforms/prpmc750.h 2004-10-18 14:56:27 -07:00 @@ -5,20 +5,16 @@ * * Author: Matt Porter * - * Copyright 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. */ #ifdef __KERNEL__ #ifndef __ASM_PRPMC750_H__ #define __ASM_PRPMC750_H__ -#include - /* * Due to limiations imposed by legacy hardware (primaryily IDE controllers), * the PrPMC750 carrier board operates using a PReP address map. @@ -80,6 +76,20 @@ #define PRPMC750_TBEN_REG 0xfef880c0 #define PRPMC750_TBEN_MASK 0x01 + +/* UART Defines. */ +#define RS_TABLE_SIZE 4 + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD (PRPMC750_BASE_BAUD / 16) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, PRPMC750_SERIAL_0, 1, STD_COM_FLAGS, \ + iomem_base: (unsigned char *)PRPMC750_SERIAL_0, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM } /* ttyS0 */ #endif /* __ASM_PRPMC750_H__ */ #endif /* __KERNEL__ */ diff -Nru a/arch/ppc/platforms/prpmc750_serial.h b/arch/ppc/platforms/prpmc750_serial.h --- a/arch/ppc/platforms/prpmc750_serial.h 2004-10-18 14:56:20 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,43 +0,0 @@ -/* - * include/asm-ppc/platforms/prpmc750_serial.h - * - * Motorola PrPMC750 serial support - * - * Author: Matt Porter - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifdef __KERNEL__ -#ifndef __ASM_PRPMC750_SERIAL_H__ -#define __ASM_PRPMC750_SERIAL_H__ - -#include -#include - -#define RS_TABLE_SIZE 4 - -/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ -#define BASE_BAUD (PRPMC750_BASE_BAUD / 16) - -#ifndef SERIAL_MAGIC_KEY -#define kernel_debugger ppc_kernel_debug -#endif - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#endif - -#define SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, PRPMC750_SERIAL_0, 1, STD_COM_FLAGS, \ - iomem_base: (unsigned char *)PRPMC750_SERIAL_0, \ - iomem_reg_shift: 4, \ - io_type: SERIAL_IO_MEM } /* ttyS0 */ - -#endif /* __ASM_PRPMC750_SERIAL_H__ */ -#endif /* __KERNEL__ */ diff -Nru a/arch/ppc/platforms/prpmc800.c b/arch/ppc/platforms/prpmc800.c --- a/arch/ppc/platforms/prpmc800.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc/platforms/prpmc800.c 2004-10-18 14:56:48 -07:00 @@ -309,10 +309,6 @@ ROOT_DEV = Root_SDA2; #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - printk(KERN_INFO "Port by MontaVista Software, Inc. " "(source@mvista.com)\n"); } diff -Nru a/arch/ppc/platforms/prpmc800.h b/arch/ppc/platforms/prpmc800.h --- a/arch/ppc/platforms/prpmc800.h 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/platforms/prpmc800.h 2004-10-18 14:56:49 -07:00 @@ -5,12 +5,10 @@ * * Author: Dale Farnsworth * - * Copyright 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. */ /* * From Processor to PCI: @@ -62,5 +60,23 @@ */ #define PRPMC800_INT_IRQ 16 #define PRPMC800_INT_PRI 15 + +/* UART Defines. */ +#define RS_TABLE_SIZE 4 + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD (PRPMC800_BASE_BAUD / 16) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +/* UARTS are at IRQ 16 */ +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, PRPMC800_SERIAL_1, 16, STD_COM_FLAGS, /* ttyS0 */\ + iomem_base: (unsigned char *)PRPMC800_SERIAL_1, \ + iomem_reg_shift: 0, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS #endif /* __ASMPPC_PRPMC800_H */ diff -Nru a/arch/ppc/platforms/prpmc800_serial.h b/arch/ppc/platforms/prpmc800_serial.h --- a/arch/ppc/platforms/prpmc800_serial.h 2004-10-18 14:56:50 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,49 +0,0 @@ -/* - * arch/ppc/platforms/prpmc800_serial.h - * - * Definitions for Motorola MCG PRPMC800 cPCI board support - * - * Author: Dale Farnsworth dale.farnsworth@mvista.com - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __ASMPPC_PRPMC800_SERIAL_H -#define __ASMPPC_PRPMC800_SERIAL_H - -#include -#include - -#ifdef CONFIG_SERIAL_MANY_PORTS -#define RS_TABLE_SIZE 64 -#else -#define RS_TABLE_SIZE 4 -#endif - -/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ -#define BASE_BAUD (PRPMC800_BASE_BAUD / 16) - -#ifndef SERIAL_MAGIC_KEY -#define kernel_debugger ppc_kernel_debug -#endif - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#endif - -/* UARTS are at IRQ 16 */ -#define STD_SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, PRPMC800_SERIAL_1, 16, STD_COM_FLAGS, /* ttyS0 */\ - iomem_base: (unsigned char *)PRPMC800_SERIAL_1, \ - iomem_reg_shift: 0, \ - io_type: SERIAL_IO_MEM }, - -#define SERIAL_PORT_DFNS \ - STD_SERIAL_PORT_DFNS - -#endif /* __ASMPPC_PRPMC800_SERIAL_H */ diff -Nru a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c --- a/arch/ppc/platforms/residual.c 2004-10-18 14:56:17 -07:00 +++ b/arch/ppc/platforms/residual.c 2004-10-18 14:56:17 -07:00 @@ -504,7 +504,7 @@ #define did dev->DeviceId /* make sure we have residual data first */ - if ( res->ResidualLength == 0 ) + if (!have_residual_data) return; printk("Residual: %ld devices\n", res->ActualNumDevices); @@ -639,7 +639,7 @@ #define did dev->DeviceId /* make sure we have residual data first */ - if ( res->ResidualLength == 0 ) + if (!have_residual_data) return; printk("Residual: %ld devices\n", res->ActualNumDevices); for ( i = 0; @@ -790,7 +790,7 @@ int n) { int i; - if ( !res->ResidualLength ) return NULL; + if (!have_residual_data) return NULL; for (i=0; iActualNumDevices; i++) { #define Dev res->Devices[i].DeviceId if ( (Dev.BusId&BusMask) && @@ -813,7 +813,7 @@ int n) { int i; - if ( !res->ResidualLength ) return NULL; + if (!have_residual_data) return NULL; for (i=0; iActualNumDevices; i++) { #define Dev res->Devices[i].DeviceId if ( (Dev.BusId&BusMask) && @@ -827,6 +827,129 @@ return NULL; } +static int __init +residual_scan_pcibridge(PnP_TAG_PACKET * pkt, struct pci_dev *dev) +{ + int irq = -1; + +#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData + if (dev->bus->number == data[16]) { + int i, size; + + size = 3 + ld_le16((u_short *) (&pkt->L4_Pack.Count0)); + for (i = 20; i < size - 4; i += 12) { + unsigned char pin; + int line_irq; + + if (dev->devfn != data[i + 1]) + continue; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + line_irq = ld_le16((unsigned short *) + (&data[i + 4 + 2 * (pin - 1)])); + irq = (line_irq == 0xffff) ? 0 + : line_irq & 0x7fff; + } else + irq = 0; + + break; + } + } +#undef data + + return irq; +} + +int __init +residual_pcidev_irq(struct pci_dev *dev) +{ + int i = 0; + int irq = -1; + PPC_DEVICE *bridge; + + while ((bridge = residual_find_device + (-1, NULL, BridgeController, PCIBridge, -1, i++))) { + + PnP_TAG_PACKET *pkt; + if (bridge->AllocatedOffset) { + pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + + bridge->AllocatedOffset, 3, 0); + if (!pkt) + continue; + + irq = residual_scan_pcibridge(pkt, dev); + if (irq != -1) + break; + } + } + + return (irq < 0) ? 0 : irq; +} + +void __init residual_irq_mask(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + PPC_DEVICE *dev; + int i = 0; + unsigned short irq_mask = 0x000; /* default to edge */ + + while ((dev = residual_find_device(-1, NULL, -1, -1, -1, i++))) { + PnP_TAG_PACKET *pkt; + unsigned short mask; + int size; + int offset = dev->AllocatedOffset; + + if (!offset) + continue; + + pkt = PnP_find_packet(res->DevicePnPHeap + offset, + IRQFormat, 0); + if (!pkt) + continue; + + size = tag_small_count(pkt->S1_Pack.Tag) + 1; + mask = ld_le16((unsigned short *)pkt->S4_Pack.IRQMask); + if (size > 3 && (pkt->S4_Pack.IRQInfo & 0x0c)) + irq_mask |= mask; + } + + *irq_edge_mask_lo = irq_mask & 0xff; + *irq_edge_mask_hi = irq_mask >> 8; +} + +unsigned int __init residual_isapic_addr(void) +{ + PPC_DEVICE *isapic; + PnP_TAG_PACKET *pkt; + unsigned int addr; + + isapic = residual_find_device(~0, NULL, SystemPeripheral, + ProgrammableInterruptController, + ISA_PIC, 0); + if (!isapic) + goto unknown; + + pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + + isapic->AllocatedOffset, 9, 0); + if (!pkt) + goto unknown; + +#define p pkt->L4_Pack.L4_Data.L4_PPCPack + /* Must be 32-bit system address */ + if (!((p.PPCData[0] == 3) && (p.PPCData[1] == 32))) + goto unknown; + + /* It doesn't seem to work where length != 1 (what can I say? :-/ ) */ + if (ld_le32((unsigned int *)(p.PPCData + 12)) != 1) + goto unknown; + + addr = ld_le32((unsigned int *) (p.PPCData + 4)); +#undef p + return addr; +unknown: + return 0; +} + PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, unsigned packet_tag, int n) @@ -901,7 +1024,7 @@ int __init proc_prep_residual_init(void) { - if (res->ResidualLength) + if (have_residual_data) create_proc_read_entry("residual", S_IRUGO, NULL, proc_prep_residual_read, NULL); return 0; diff -Nru a/arch/ppc/platforms/rpx8260.c b/arch/ppc/platforms/rpx8260.c --- a/arch/ppc/platforms/rpx8260.c 2004-10-18 14:56:31 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,65 +0,0 @@ -/* - * arch/ppc/platforms/rpx8260.c - * - * RPC EP8260 platform support - * - * Author: Dan Malek - * Derived from: pq2ads_setup.c by Kumar - * - * Copyright 2004 Embedded Edge, LLC - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include - -#include -#include - -static void (*callback_setup_arch)(void); - -extern unsigned char __res[sizeof(bd_t)]; - -extern void m8260_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); - -static int -ep8260_show_cpuinfo(struct seq_file *m) -{ - bd_t *binfo = (bd_t *)__res; - - seq_printf(m, "vendor\t\t: RPC\n" - "machine\t\t: EP8260 PPC\n" - "\n" - "mem size\t\t: 0x%08x\n" - "console baud\t\t: %d\n" - "\n", - binfo->bi_memsize, - binfo->bi_baudrate); - return 0; -} - -static void __init -ep8260_setup_arch(void) -{ - printk("RPC EP8260 Port\n"); - callback_setup_arch(); -} - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* Generic 8260 platform initialization */ - m8260_init(r3, r4, r5, r6, r7); - - /* Anything special for this platform */ - ppc_md.show_cpuinfo = ep8260_show_cpuinfo; - - callback_setup_arch = ppc_md.setup_arch; - ppc_md.setup_arch = ep8260_setup_arch; -} diff -Nru a/arch/ppc/platforms/rpx8260.h b/arch/ppc/platforms/rpx8260.h --- a/arch/ppc/platforms/rpx8260.h 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/platforms/rpx8260.h 2004-10-18 14:56:32 -07:00 @@ -70,5 +70,12 @@ #define PHY_INTERRUPT SIU_INT_IRQ7 +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "Embedded Planet" +#define CPUINFO_MACHINE "EP8260 PowerPC" + +/* Warm reset vector. */ +#define BOOTROM_RESTART_ADDR ((uint)0xfff00104) + #endif /* __ASM_PLATFORMS_RPX8260_H__ */ #endif /* __KERNEL__ */ diff -Nru a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c --- a/arch/ppc/platforms/sandpoint.c 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc/platforms/sandpoint.c 2004-10-18 14:57:05 -07:00 @@ -303,10 +303,6 @@ /* Lookup PCI host bridges */ sandpoint_find_bridges(); -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n"); printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); diff -Nru a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c --- a/arch/ppc/platforms/sbc82xx.c 2004-10-18 14:56:20 -07:00 +++ b/arch/ppc/platforms/sbc82xx.c 2004-10-18 14:56:20 -07:00 @@ -16,10 +16,11 @@ */ #include -#include #include #include #include +#include +#include #include #include @@ -28,39 +29,12 @@ #include #include -static void (*callback_setup_arch)(void); static void (*callback_init_IRQ)(void); extern unsigned char __res[sizeof(bd_t)]; -extern void m8260_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); - extern void (*late_time_init)(void); -static int -sbc82xx_show_cpuinfo(struct seq_file *m) -{ - bd_t *binfo = (bd_t *)__res; - - seq_printf(m, "vendor\t\t: Wind River\n" - "machine\t\t: SBC PowerQUICC II\n" - "\n" - "mem size\t\t: 0x%08lx\n" - "console baud\t\t: %ld\n" - "\n", - binfo->bi_memsize, - binfo->bi_baudrate); - return 0; -} - -static void __init -sbc82xx_setup_arch(void) -{ - printk("SBC PowerQUICC II Port\n"); - callback_setup_arch(); -} - #ifdef CONFIG_GEN_RTC TODC_ALLOC(); @@ -236,26 +210,36 @@ return PCI_IRQ_TABLE_LOOKUP; } +static void __devinit quirk_sbc8260_cardbus(struct pci_dev *pdev) +{ + uint32_t ctrl; + if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(17, 0)) + return; + + printk(KERN_INFO "Setting up CardBus controller\n"); + + /* Set P2CCLK bit in System Control Register */ + pci_read_config_dword(pdev, 0x80, &ctrl); + ctrl |= (1<<27); + pci_write_config_dword(pdev, 0x80, ctrl); + + /* Set MFUNC up for PCI IRQ routing via INTA and INTB, and LEDs. */ + pci_write_config_dword(pdev, 0x8c, 0x00c01d22); + +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, quirk_sbc8260_cardbus); void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +m82xx_board_init(void) { - /* Generic 8260 platform initialization */ - m8260_init(r3, r4, r5, r6, r7); - /* u-boot may be using one of the FCC Ethernet devices. Use the MAC address to the SCC. */ __res[offsetof(bd_t, bi_enetaddr[5])] &= ~3; /* Anything special for this platform */ - ppc_md.show_cpuinfo = sbc82xx_show_cpuinfo; - - callback_setup_arch = ppc_md.setup_arch; callback_init_IRQ = ppc_md.init_IRQ; - ppc_md.setup_arch = sbc82xx_setup_arch; ppc_md.init_IRQ = sbc82xx_init_IRQ; ppc_md.pci_map_irq = sbc82xx_pci_map_irq; #ifdef CONFIG_GEN_RTC diff -Nru a/arch/ppc/platforms/sbc82xx.h b/arch/ppc/platforms/sbc82xx.h --- a/arch/ppc/platforms/sbc82xx.h 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/platforms/sbc82xx.h 2004-10-18 14:57:04 -07:00 @@ -18,6 +18,10 @@ #define SBC82xx_MACADDR_NVRAM_FCC2 0x220000d5 /* JP7A */ #define SBC82xx_MACADDR_NVRAM_FCC3 0x220000db /* JP7B */ +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "Wind River" +#define CPUINFO_MACHINE "SBC PowerQUICC II" + #define BOOTROM_RESTART_ADDR ((uint)0x40000104) #define SBC82xx_PC_IRQA (NR_SIU_INTS+0) diff -Nru a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c --- a/arch/ppc/platforms/spruce.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc/platforms/spruce.c 2004-10-18 14:55:55 -07:00 @@ -228,11 +228,6 @@ ROOT_DEV = Root_SDA1; #endif -#ifdef CONFIG_VT - conswitchp = &dummy_con; -#endif - - /* Identify the system */ printk(KERN_INFO "System Identification: IBM Spruce\n"); printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); diff -Nru a/arch/ppc/platforms/tqm8260.h b/arch/ppc/platforms/tqm8260.h --- a/arch/ppc/platforms/tqm8260.h 2004-10-18 14:56:31 -07:00 +++ b/arch/ppc/platforms/tqm8260.h 2004-10-18 14:56:31 -07:00 @@ -14,6 +14,10 @@ #define CPM_MAP_ADDR ((uint)0xFFF00000) #define PHY_INTERRUPT 25 +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "IN2 Systems" +#define CPUINFO_MACHINE "TQM8260 PowerPC" + #define BOOTROM_RESTART_ADDR ((uint)0x40000104) #endif /* __TQM8260_PLATFORM */ diff -Nru a/arch/ppc/platforms/tqm8260_setup.c b/arch/ppc/platforms/tqm8260_setup.c --- a/arch/ppc/platforms/tqm8260_setup.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc/platforms/tqm8260_setup.c 2004-10-18 14:56:28 -07:00 @@ -14,33 +14,12 @@ * option) any later version. */ -#include -#include +#include #include #include #include -static void (*callback_setup_arch)(void); - -extern unsigned char __res[sizeof(bd_t)]; - -extern void m8260_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); - -static int -tqm8260_show_cpuinfo(struct seq_file *m) -{ - bd_t *binfo = (bd_t *)__res; - - seq_printf(m, "vendor\t\t: IN2 Systems\n" - "machine\t\t: TQM8260 PowerPC\n" - "mem size\t\t: 0x%08x\n" - "\n", - binfo->bi_memsize); - return 0; -} - static int tqm8260_set_rtc_time(unsigned long time) { @@ -56,24 +35,10 @@ return ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt; } -static void __init -tqm8260_setup_arch(void) -{ - printk("IN2 Systems TQM8260 port\n"); - callback_setup_arch(); -} - void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +m82xx_board_init(void) { - /* Generic 8260 platform initialization */ - m8260_init(r3, r4, r5, r6, r7); - /* Anything special for this platform */ - ppc_md.show_cpuinfo = tqm8260_show_cpuinfo; ppc_md.set_rtc_time = tqm8260_set_rtc_time; ppc_md.get_rtc_time = tqm8260_get_rtc_time; - - callback_setup_arch = ppc_md.setup_arch; - ppc_md.setup_arch = tqm8260_setup_arch; +} diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile --- a/arch/ppc/syslib/Makefile 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc/syslib/Makefile 2004-10-18 14:55:54 -07:00 @@ -5,6 +5,8 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC +wdt-mpc8xx-$(CONFIG_8xx_WDT) += m8xx_wdt.o + obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o obj-$(CONFIG_PPC_OCP) += ocp.o obj-$(CONFIG_IBM_OCP) += ibm_ocp.o @@ -22,7 +24,7 @@ obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o ppc405_pci.o endif endif -obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o +obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.o i8259.o endif diff -Nru a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c --- a/arch/ppc/syslib/cpm2_pic.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/syslib/cpm2_pic.c 2004-10-18 14:56:32 -07:00 @@ -1,12 +1,3 @@ -#include -#include -#include -#include -#include -#include -#include -#include "cpm2_pic.h" - /* The CPM2 internal interrupt controller. It is usually * the only interrupt controller. * There are two 32-bit registers (high/low) for up to 64 @@ -18,6 +9,18 @@ * We create two tables, indexed by vector number, to indicate * which register to use and which bit in the register to use. */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "cpm2_pic.h" + static u_char irq_to_siureg[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -123,9 +126,5 @@ if (irq == 0) return(-1); -#if 0 - irq += ppc8260_pic.irq_offset; -#endif return irq; } - diff -Nru a/arch/ppc/syslib/cpm2_pic.h b/arch/ppc/syslib/cpm2_pic.h --- a/arch/ppc/syslib/cpm2_pic.h 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/syslib/cpm2_pic.h 2004-10-18 14:57:04 -07:00 @@ -1,13 +1,7 @@ #ifndef _PPC_KERNEL_CPM2_H #define _PPC_KERNEL_CPM2_H -#include - extern struct hw_interrupt_type cpm2_pic; - -void cpm2_pic_init(void); -void cpm2_do_IRQ(struct pt_regs *regs, - int cpu); -int cpm2_get_irq(struct pt_regs *regs); +extern int cpm2_get_irq(struct pt_regs *regs); #endif /* _PPC_KERNEL_CPM2_H */ diff -Nru a/arch/ppc/syslib/hawk_common.c b/arch/ppc/syslib/hawk_common.c --- a/arch/ppc/syslib/hawk_common.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/syslib/hawk_common.c 2004-10-18 14:56:32 -07:00 @@ -285,3 +285,35 @@ return total; } + +int __init +hawk_mpic_init(unsigned int pci_mem_offset) +{ + unsigned short devid; + unsigned int pci_membase; + + /* Check the first PCI device to see if it is a Raven or Hawk. */ + early_read_config_word(0, 0, 0, PCI_DEVICE_ID, &devid); + + switch (devid) { + case PCI_DEVICE_ID_MOTOROLA_RAVEN: + case PCI_DEVICE_ID_MOTOROLA_HAWK: + break; + default: + OpenPIC_Addr = NULL; + return 1; + } + + /* Read the memory base register. */ + early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); + + if (pci_membase == 0) { + OpenPIC_Addr = NULL; + return 1; + } + + /* Map the MPIC registers to virtual memory. */ + OpenPIC_Addr = ioremap(pci_membase + pci_mem_offset, 0x22000); + + return 0; +} diff -Nru a/arch/ppc/syslib/ibm44x_common.c b/arch/ppc/syslib/ibm44x_common.c --- a/arch/ppc/syslib/ibm44x_common.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc/syslib/ibm44x_common.c 2004-10-18 14:56:29 -07:00 @@ -6,6 +6,9 @@ * Matt Porter * Copyright 2002-2003 MontaVista Software Inc. * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -14,8 +17,14 @@ */ #include #include +#include + +#include #include #include +#include +#include +#include phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size) { @@ -35,3 +44,159 @@ return (page_4gb | addr); }; + +void __init ibm44x_calibrate_decr(unsigned int freq) +{ + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + /* Clear any pending timer interrupts */ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + + /* Enable decrementer interrupt */ + mtspr(SPRN_TCR, TCR_DIE); +} + +extern void abort(void); + +static void ibm44x_restart(char *cmd) +{ + local_irq_disable(); + abort(); +} + +static void ibm44x_power_off(void) +{ + local_irq_disable(); + for(;;); +} + +static void ibm44x_halt(void) +{ + local_irq_disable(); + for(;;); +} + +/* + * Read the 44x memory controller to get size of system memory. + */ +static unsigned long __init ibm44x_find_end_of_memory(void) +{ + u32 i, bank_config; + u32 mem_size = 0; + + for (i=0; i<4; i++) + { + switch (i) + { + case 0: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR); + break; + case 1: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR); + break; + case 2: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR); + break; + case 3: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR); + break; + } + + bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); + + if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE)) + continue; + switch (SDRAM_CONFIG_BANK_SIZE(bank_config)) + { + case SDRAM_CONFIG_SIZE_8M: + mem_size += PPC44x_MEM_SIZE_8M; + break; + case SDRAM_CONFIG_SIZE_16M: + mem_size += PPC44x_MEM_SIZE_16M; + break; + case SDRAM_CONFIG_SIZE_32M: + mem_size += PPC44x_MEM_SIZE_32M; + break; + case SDRAM_CONFIG_SIZE_64M: + mem_size += PPC44x_MEM_SIZE_64M; + break; + case SDRAM_CONFIG_SIZE_128M: + mem_size += PPC44x_MEM_SIZE_128M; + break; + case SDRAM_CONFIG_SIZE_256M: + mem_size += PPC44x_MEM_SIZE_256M; + break; + case SDRAM_CONFIG_SIZE_512M: + mem_size += PPC44x_MEM_SIZE_512M; + break; + } + } + return mem_size; +} + +static void __init ibm44x_init_irq(void) +{ + int i; + + ppc4xx_pic_init(); + + for (i = 0; i < NR_IRQS; i++) + irq_desc[i].handler = ppc4xx_pic; +} + +#ifdef CONFIG_SERIAL_TEXT_DEBUG +#include +#include +#include + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in */ +}; + +static void ibm44x_progress(char *s, unsigned short hex) +{ + volatile char c; + volatile unsigned long com_port; + u16 shift; + + com_port = (unsigned long)rs_table[0].iomem_base; + shift = rs_table[0].iomem_reg_shift; + + while ((c = *s++) != 0) { + while ((*((volatile unsigned char *)com_port + + (UART_LSR << shift)) & UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = c; + + } + + /* Send LF/CR to pretty up output */ + while ((*((volatile unsigned char *)com_port + + (UART_LSR << shift)) & UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = '\r'; + while ((*((volatile unsigned char *)com_port + + (UART_LSR << shift)) & UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = '\n'; +} +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ + +void __init ibm44x_platform_init(void) +{ + ppc_md.init_IRQ = ibm44x_init_irq; + ppc_md.find_end_of_memory = ibm44x_find_end_of_memory; + ppc_md.restart = ibm44x_restart; + ppc_md.power_off = ibm44x_power_off; + ppc_md.halt = ibm44x_halt; + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = ibm44x_progress; +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +} + diff -Nru a/arch/ppc/syslib/ibm44x_common.h b/arch/ppc/syslib/ibm44x_common.h --- a/arch/ppc/syslib/ibm44x_common.h 2004-10-18 14:56:18 -07:00 +++ b/arch/ppc/syslib/ibm44x_common.h 2004-10-18 14:56:18 -07:00 @@ -4,7 +4,7 @@ * PPC44x system library * * Eugene Surovegin or - * Copyright (c) 2003 Zultys Technologies + * Copyright (c) 2003, 2004 Zultys Technologies * * 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 @@ -30,6 +30,12 @@ unsigned int uart0; unsigned int uart1; }; + +/* common 44x platform init */ +void ibm44x_platform_init(void) __init; + +/* initialize decrementer and tick-related variables */ +void ibm44x_calibrate_decr(unsigned int freq) __init; #endif /* __ASSEMBLY__ */ #endif /* __PPC_SYSLIB_IBM44x_COMMON_H */ diff -Nru a/arch/ppc/syslib/m8260_pci.h b/arch/ppc/syslib/m8260_pci.h --- a/arch/ppc/syslib/m8260_pci.h 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/syslib/m8260_pci.h 2004-10-18 14:57:03 -07:00 @@ -66,6 +66,7 @@ #endif #ifdef CONFIG_8260_PCI9 +struct pci_controller; extern void setup_m8260_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data); #else diff -Nru a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c --- a/arch/ppc/syslib/m8260_setup.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc/syslib/m8260_setup.c 2004-10-18 14:56:32 -07:00 @@ -1,5 +1,5 @@ /* - * arch/ppc/kernel/setup.c + * arch/ppc/syslib/m8260_setup.c * * Copyright (C) 1995 Linus Torvalds * Adapted from 'alpha' version by Gary Thomas @@ -8,36 +8,20 @@ * Further modified for generic 8xx and 8260 by Dan. */ -/* - * bootup setup stuff.. - */ - #include -#include #include #include #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include #include +#include #include -#include #include #include -#include #include #include #include @@ -46,10 +30,6 @@ #include "cpm2_pic.h" -static int m8260_set_rtc_time(unsigned long time); -static unsigned long m8260_get_rtc_time(void); -static void m8260_calibrate_decr(void); - unsigned char __res[sizeof(bd_t)]; extern void cpm2_reset(void); @@ -59,8 +39,10 @@ static void __init m8260_setup_arch(void) { - /* Reset the Communication Processor Module. - */ + /* Print out Vendor and Machine info. */ + printk(KERN_INFO "%s %s port\n", CPUINFO_VENDOR, CPUINFO_MACHINE); + + /* Reset the Communication Processor Module. */ cpm2_reset(); #ifdef CONFIG_8260_PCI9 /* Initialise IDMA for PCI erratum workaround */ @@ -69,6 +51,10 @@ #ifdef CONFIG_PCI_8260 m8260_find_bridges(); #endif +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; +#endif } /* The decrementer counts at the system (internal) clock frequency @@ -77,7 +63,7 @@ static void __init m8260_calibrate_decr(void) { - bd_t *binfo = (bd_t *)__res; + bd_t *binfo = (bd_t *)__res; int freq, divisor; freq = binfo->bi_busfreq; @@ -145,18 +131,22 @@ } static int -m8260_show_percpuinfo(struct seq_file *m, int i) +m8260_show_cpuinfo(struct seq_file *m) { - bd_t *bp; - - bp = (bd_t *)__res; + bd_t *bp = (bd_t *)__res; - seq_printf(m, "core clock\t: %ld MHz\n" - "CPM clock\t: %ld MHz\n" - "bus clock\t: %ld MHz\n", - bp->bi_intfreq / 1000000, - bp->bi_cpmfreq / 1000000, - bp->bi_busfreq / 1000000); + seq_printf(m, "vendor\t\t: %s\n" + "machine\t\t: %s\n" + "\n" + "mem size\t\t: 0x%08x\n" + "console baud\t\t: %d\n" + "\n" + "core clock\t: %u MHz\n" + "CPM clock\t: %u MHz\n" + "bus clock\t: %u MHz\n", + CPUINFO_VENDOR, CPUINFO_MACHINE, bp->bi_memsize, + bp->bi_baudrate, bp->bi_intfreq / 1000000, + bp->bi_cpmfreq / 1000000, bp->bi_busfreq / 1000000); return 0; } @@ -170,7 +160,6 @@ m8260_init_IRQ(void) { int i; - void cpm_interrupt_init(void); for ( i = 0 ; i < NR_SIU_INTS ; i++ ) irq_desc[i].handler = &cpm2_pic; @@ -190,10 +179,7 @@ static unsigned long __init m8260_find_end_of_memory(void) { - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; + bd_t *binfo = (bd_t *)__res; return binfo->bi_memsize; } @@ -216,6 +202,12 @@ io_block_mapping(IO_VIRT_ADDR, IO_PHYS_ADDR, 0x10000000, _PAGE_IO); } +/* Place-holder for board-specific init */ +void __attribute__ ((weak)) __init +m82xx_board_init(void) +{ +} + /* Inputs: * r3 - Optional pointer to a board information structure. * r4 - Optional pointer to the physical starting address of the init RAM @@ -228,7 +220,7 @@ * command-line parameters. */ void __init -m8260_init(unsigned long r3, unsigned long r4, unsigned long r5, +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { parse_bootinfo(find_bootinfo()); @@ -249,18 +241,18 @@ strcpy(cmd_line, (char *)(r6+KERNELBASE)); } + /* Call back for board-specific settings. */ + m82xx_board_init(); + ppc_md.setup_arch = m8260_setup_arch; - ppc_md.show_percpuinfo = m8260_show_percpuinfo; - ppc_md.irq_canonicalize = NULL; + ppc_md.show_cpuinfo = m8260_show_cpuinfo; ppc_md.init_IRQ = m8260_init_IRQ; ppc_md.get_irq = cpm2_get_irq; - ppc_md.init = NULL; ppc_md.restart = m8260_restart; ppc_md.power_off = m8260_power_off; ppc_md.halt = m8260_halt; - ppc_md.time_init = NULL; ppc_md.set_rtc_time = m8260_set_rtc_time; ppc_md.get_rtc_time = m8260_get_rtc_time; ppc_md.calibrate_decr = m8260_calibrate_decr; diff -Nru a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c --- a/arch/ppc/syslib/m8xx_setup.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc/syslib/m8xx_setup.c 2004-10-18 14:56:29 -07:00 @@ -60,6 +60,11 @@ extern void m8xx_cpm_reset(uint); extern void rpxfb_alloc_pages(void); +void __attribute__ ((weak)) +board_init(void) +{ +} + void __init m8xx_setup_arch(void) { @@ -102,6 +107,7 @@ } #endif #endif + board_init(); } void diff -Nru a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/m8xx_wdt.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,99 @@ +/* + * m8xx_wdt.c - MPC8xx watchdog driver + * + * Author: Florian Schirmer + * + * 2002 (c) Florian Schirmer This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include + +static int wdt_timeout; + +void m8xx_wdt_reset(void) +{ + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + + imap->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */ + imap->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */ +} + +static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + + m8xx_wdt_reset(); + + imap->im_sit.sit_piscr |= PISCR_PS; /* clear irq */ + + return IRQ_HANDLED; +} + +void __init m8xx_wdt_handler_install(bd_t * binfo) +{ + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + u32 pitc; + u32 sypcr; + u32 pitrtclk; + + sypcr = imap->im_siu_conf.sc_sypcr; + + if (!(sypcr & 0x04)) { + printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n", + sypcr); + return; + } + + m8xx_wdt_reset(); + + printk(KERN_NOTICE + "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n", + (sypcr >> 16), sypcr & 0x01); + + wdt_timeout = (sypcr >> 16) & 0xFFFF; + + if (!wdt_timeout) + wdt_timeout = 0xFFFF; + + if (sypcr & 0x01) + wdt_timeout *= 2048; + + /* + * Fire trigger if half of the wdt ticked down + */ + + if (imap->im_sit.sit_rtcsc & RTCSC_38K) + pitrtclk = 9600; + else + pitrtclk = 8192; + + if ((wdt_timeout) > (UINT_MAX / pitrtclk)) + pitc = wdt_timeout / binfo->bi_intfreq * pitrtclk / 2; + else + pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2; + + imap->im_sit.sit_pitc = pitc << 16; + imap->im_sit.sit_piscr = + (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE; + + if (request_irq(PIT_INTERRUPT, m8xx_wdt_interrupt, 0, "watchdog", NULL)) + panic("m8xx_wdt: could not allocate watchdog irq!"); + + printk(KERN_NOTICE + "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc); + + wdt_timeout /= binfo->bi_intfreq; +} + +int m8xx_wdt_get_timeout(void) +{ + return wdt_timeout; +} diff -Nru a/arch/ppc/syslib/m8xx_wdt.h b/arch/ppc/syslib/m8xx_wdt.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/m8xx_wdt.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,16 @@ +/* + * Author: Florian Schirmer + * + * 2002 (c) Florian Schirmer This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef _PPC_SYSLIB_M8XX_WDT_H +#define _PPC_SYSLIB_M8XX_WDT_H + +extern void m8xx_wdt_handler_install(bd_t * binfo); +extern int m8xx_wdt_get_timeout(void); +extern void m8xx_wdt_reset(void); + +#endif /* _PPC_SYSLIB_M8XX_WDT_H */ diff -Nru a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c --- a/arch/ppc/syslib/mpc52xx_pic.c 2004-10-18 14:57:21 -07:00 +++ b/arch/ppc/syslib/mpc52xx_pic.c 2004-10-18 14:57:21 -07:00 @@ -114,7 +114,7 @@ /* * Only some irqs are reset here, others in interrupting hardware. */ - + switch (irq) { case MPC52xx_IRQ0: val = in_be32(&intr->ctrl); @@ -180,13 +180,14 @@ mpc52xx_init_irq(void) { int i; + u32 intr_ctrl; /* Remap the necessary zones */ intr = (struct mpc52xx_intr *) ioremap(MPC52xx_INTR, sizeof(struct mpc52xx_intr)); sdma = (struct mpc52xx_sdma *) ioremap(MPC52xx_SDMA, sizeof(struct mpc52xx_sdma)); - + if ((intr==NULL) || (sdma==NULL)) panic("Can't ioremap PIC/SDMA register for init_irq !"); @@ -195,12 +196,13 @@ out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ - out_be32(&intr->ctrl, - 0x0f000000 | /* clear IRQ 0-3 */ - 0x00c00000 | /* IRQ0: level-sensitive, active low */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ 0x00001000 | /* MEE master external enable */ 0x00000000 | /* 0 means disable IRQ 0-3 */ - 0x00000001); /* CEb route critical normally */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); /* Zero a bunch of the priority settings. */ out_be32(&intr->per_pri1, 0); @@ -213,6 +215,14 @@ for (i = 0; i < NR_IRQS; i++) { irq_desc[i].handler = &mpc52xx_ic; irq_desc[i].status = IRQ_LEVEL; + } + + #define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i=0 ; i<4 ; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl,i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; } } diff -Nru a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c --- a/arch/ppc/syslib/mpc52xx_setup.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc/syslib/mpc52xx_setup.c 2004-10-18 14:56:49 -07:00 @@ -1,5 +1,5 @@ /* - * arch/ppc/syslib/mpc52xx_common.c + * arch/ppc/syslib/mpc52xx_setup.c * * Common code for the boards based on Freescale MPC52xx embedded CPU. * @@ -23,6 +23,7 @@ #include #include #include +#include #include extern bd_t __res; @@ -38,9 +39,9 @@ mpc52xx_restart(char *cmd) { struct mpc52xx_gpt* gpt0 = (struct mpc52xx_gpt*) MPC52xx_GPTx(0); - + local_irq_disable(); - + /* Turn on the watchdog and wait for it to expire. It effectively does a reset */ if (gpt0 != NULL) { @@ -99,24 +100,28 @@ #error "mpc52xx PSC for console not selected" #endif +static void +mpc52xx_psc_putc(struct mpc52xx_psc * psc, unsigned char c) +{ + while (!(in_be16(&psc->mpc52xx_psc_status) & + MPC52xx_PSC_SR_TXRDY)); + out_8(&psc->mpc52xx_psc_buffer_8, c); +} + void mpc52xx_progress(char *s, unsigned short hex) { struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE; char c; - /* Don't we need to disable serial interrupts ? */ - while ((c = *s++) != 0) { - if (c == '\n') { - while (!(in_be16(&psc->mpc52xx_psc_status) & - MPC52xx_PSC_SR_TXRDY)) ; - out_8(&psc->mpc52xx_psc_buffer_8, '\r'); - } - while (!(in_be16(&psc->mpc52xx_psc_status) & - MPC52xx_PSC_SR_TXRDY)) ; - out_8(&psc->mpc52xx_psc_buffer_8, c); + if (c == '\n') + mpc52xx_psc_putc(psc, '\r'); + mpc52xx_psc_putc(psc, c); } + + mpc52xx_psc_putc(psc, '\r'); + mpc52xx_psc_putc(psc, '\n'); } #endif /* CONFIG_SERIAL_TEXT_DEBUG */ @@ -137,7 +142,7 @@ /* Temp BAT2 mapping active when this is called ! */ mmap_ctl = (struct mpc52xx_mmap_ctl*) MPC52xx_MMAP_CTL; - + sdram_config_0 = in_be32(&mmap_ctl->sdram0); sdram_config_1 = in_be32(&mmap_ctl->sdram1); @@ -147,10 +152,8 @@ if (((sdram_config_1 & 0x1f) >= 0x13) && ((sdram_config_1 & 0xfff00000) == ramsize)) ramsize += 1 << ((sdram_config_1 & 0xf) + 17); - - iounmap(mmap_ctl); } - + return ramsize; } @@ -167,7 +170,7 @@ /* Get RTC & Clock manager modules */ struct mpc52xx_rtc *rtc; struct mpc52xx_cdm *cdm; - + rtc = (struct mpc52xx_rtc*) ioremap(MPC52xx_RTC, sizeof(struct mpc52xx_rtc)); cdm = (struct mpc52xx_cdm*) @@ -206,7 +209,7 @@ __res.bi_intfreq = cpufreq; __res.bi_ipbfreq = ipbfreq; __res.bi_pcifreq = pcifreq; - + /* Release mapping */ iounmap((void*)rtc); iounmap((void*)cdm); diff -Nru a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c --- a/arch/ppc/syslib/open_pic.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc/syslib/open_pic.c 2004-10-18 14:56:33 -07:00 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include "open_pic_defs.h" @@ -412,7 +412,7 @@ /* Initialize the spurious interrupt */ if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd); - openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); openpic_disable_8259_pass_through(); #ifdef CONFIG_EPIC_SERIAL_MODE openpic_eicr_set_clk(7); /* Slowest value until we know better */ @@ -865,7 +865,7 @@ irq = cirq; openpic_eoi(); } - } else if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) + } else if (irq == OPENPIC_VEC_SPURIOUS) irq = -1; return irq; } @@ -988,9 +988,9 @@ /* OpenPIC sometimes seem to need some time to be fully back up... */ do { - openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); } while(openpic_readfield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK) - != (OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)); + != OPENPIC_VEC_SPURIOUS); openpic_disable_8259_pass_through(); diff -Nru a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c --- a/arch/ppc/syslib/open_pic2.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc/syslib/open_pic2.c 2004-10-18 14:56:28 -07:00 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include "open_pic_defs.h" diff -Nru a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c --- a/arch/ppc/syslib/ppc4xx_pic.c 2004-10-18 14:55:46 -07:00 +++ b/arch/ppc/syslib/ppc4xx_pic.c 2004-10-18 14:55:46 -07:00 @@ -256,7 +256,7 @@ ppc4xx_uic_end(unsigned int irq) { int bit, word; - unsigned int tr_bits; + unsigned int tr_bits = 0; bit = irq & 0x1f; word = irq >> 5; diff -Nru a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c --- a/arch/ppc/syslib/ppc4xx_setup.c 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc/syslib/ppc4xx_setup.c 2004-10-18 14:55:53 -07:00 @@ -61,10 +61,6 @@ #ifdef CONFIG_PCI ppc4xx_find_bridges(); #endif - -#if defined(CONFIG_FB) - conswitchp = &dummy_con; -#endif } /* diff -Nru a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c --- a/arch/ppc/syslib/ppc85xx_setup.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc/syslib/ppc85xx_setup.c 2004-10-18 14:57:03 -07:00 @@ -277,7 +277,7 @@ hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO; hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO; hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE; -#if CONFIG_85xx_PCI2 +#ifdef CONFIG_85xx_PCI2 isa_io_base = (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE, MPC85XX_PCI1_IO_SIZE + @@ -304,7 +304,7 @@ hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); -#if CONFIG_85xx_PCI2 +#ifdef CONFIG_85xx_PCI2 hose_b = pcibios_alloc_controller(); if (!hose_b) diff -Nru a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c --- a/arch/ppc/syslib/prom_init.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc/syslib/prom_init.c 2004-10-18 14:57:04 -07:00 @@ -115,11 +115,11 @@ ihandle prom_chosen __initdata; ihandle prom_stdout __initdata; -char *prom_display_paths[FB_MAX] __initdata; -phandle prom_display_nodes[FB_MAX] __initdata; -unsigned int prom_num_displays __initdata; -char *of_stdout_device __initdata; +static char *prom_display_paths[FB_MAX] __initdata; +static phandle prom_display_nodes[FB_MAX] __initdata; +static unsigned int prom_num_displays __initdata; static ihandle prom_disp_node __initdata; +char *of_stdout_device __initdata; unsigned int rtas_data; /* physical pointer */ unsigned int rtas_entry; /* physical pointer */ @@ -403,6 +403,7 @@ for (j=0; jcontrol_a); @@ -361,7 +361,7 @@ todc_set_rtc_time(unsigned long nowtime) { struct rtc_time tm; - u_char save_control, save_freq_select; + u_char save_control, save_freq_select = 0; spin_lock(&rtc_lock); to_tm(nowtime, &tm); @@ -416,7 +416,7 @@ */ static unsigned char __init todc_read_timereg(int addr) { - unsigned char save_control, val; + unsigned char save_control = 0, val; switch (todc_info->rtc_type) { case TODC_TYPE_DS1557: diff -Nru a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig --- a/arch/ppc64/Kconfig 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/Kconfig 2004-10-18 14:56:32 -07:00 @@ -1,4 +1,4 @@ -# +# # For a description of the syntax of this configuration file, # see Documentation/kbuild/kconfig-language.txt. # @@ -58,16 +58,28 @@ choice prompt "Platform Type" - default PPC_PSERIES + default PPC_MULTIPLATFORM config PPC_ISERIES - bool "iSeries" + bool "IBM Legacy iSeries" -config PPC_PSERIES - bool "pSeries / PowerMac G5" +config PPC_MULTIPLATFORM + bool "Generic" endchoice +config PPC_PSERIES + depends on PPC_MULTIPLATFORM + bool " IBM pSeries & new iSeries" + default y + +config PPC_PMAC + depends on PPC_MULTIPLATFORM + bool " Apple G5 based machines" + default y + select ADB_PMU + select U3_DART + config PPC bool default y @@ -77,7 +89,7 @@ default y config PPC_OF - depends on PPC_PSERIES + depends on PPC_MULTIPLATFORM bool default y @@ -85,14 +97,9 @@ # exception vectors for it config ALTIVEC bool "Support for VMX (Altivec) vector unit" - depends on PPC_PSERIES + depends on PPC_MULTIPLATFORM default y -config PPC_PMAC - depends on PPC_PSERIES - bool "Apple PowerMac G5 support" - select ADB_PMU - config PPC_SPLPAR depends on PPC_PSERIES bool "Support for shared-processor logical partitions" @@ -103,16 +110,10 @@ processors, that is, which share physical processors between two or more partitions. -config PMAC_DART - bool "Enable DART/IOMMU on PowerMac (allow >2G of RAM)" - depends on PPC_PMAC - depends on EXPERIMENTAL +config U3_DART + bool + depends on PPC_MULTIPLATFORM default n - help - Enabling DART makes it possible to boot a PowerMac G5 with more - than 2GB of memory. Note that the code is very new and untested - at this time, so it has to be considered experimental. Enabling - this might result in data loss. config PPC_PMAC64 bool @@ -163,7 +164,7 @@ config IRQ_ALL_CPUS bool "Distribute interrupts on all CPUs by default" - depends on SMP && PPC_PSERIES + depends on SMP && PPC_MULTIPLATFORM help This option gives the kernel permission to distribute IRQs across multiple CPUs. Saying N here will route all IRQs to the first @@ -214,7 +215,7 @@ config PPC_RTAS bool "Proc interface to RTAS" - depends on !PPC_ISERIES + depends on PPC_PSERIES config RTAS_FLASH tristate "Firmware flash interface" @@ -226,8 +227,9 @@ config LPARCFG tristate "LPAR Configuration Data" + depends on PPC_PSERIES || PPC_ISERIES help - Provide system capacity information via human readable + Provide system capacity information via human readable = pairs through a /proc/ppc64/lparcfg interface. endmenu @@ -272,7 +274,7 @@ config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" - depends on SMP && HOTPLUG && EXPERIMENTAL + depends on SMP && HOTPLUG && EXPERIMENTAL && PPC_PSERIES ---help--- Say Y here to be able to turn CPUs off and on. @@ -343,102 +345,10 @@ source "arch/ppc64/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_STACKOVERFLOW - bool "Check for stack overflows" - depends on DEBUG_KERNEL - -config DEBUG_STACK_USAGE - bool "Stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUGGER - bool "Enable debugger hooks" - depends on DEBUG_KERNEL - help - Include in-kernel hooks for kernel debuggers. Unless you are - intending to debug the kernel, say N here. - -config XMON - bool "Include xmon kernel debugger" - depends on DEBUGGER - help - Include in-kernel hooks for the xmon kernel monitor/debugger. - Unless you are intending to debug the kernel, say N here. - -config XMON_DEFAULT - bool "Enable xmon by default" - depends on XMON - -config PPCDBG - bool "Include PPCDBG realtime debugging" - depends on DEBUG_KERNEL - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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 IRQSTACKS - bool "Use separate kernel stacks when processing interrupts" - help - If you say Y here the kernel will use separate kernel stacks - for handling hard and soft interrupts. This can help avoid - overflowing the process kernel stacks. - -config SPINLINE - bool "Inline spinlock code at each call site" - depends on SMP && !PPC_SPLPAR && !PPC_ISERIES - help - Say Y if you want to have the code for acquiring spinlocks - and rwlocks inlined at each call site. This makes the kernel - somewhat bigger, but can be useful when profiling the kernel. - - If in doubt, say N. - -endmenu +source "arch/ppc64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/Kconfig.debug 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,59 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL + +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config DEBUGGER + bool "Enable debugger hooks" + depends on DEBUG_KERNEL + help + Include in-kernel hooks for kernel debuggers. Unless you are + intending to debug the kernel, say N here. + +config XMON + bool "Include xmon kernel debugger" + depends on DEBUGGER + help + Include in-kernel hooks for the xmon kernel monitor/debugger. + Unless you are intending to debug the kernel, say N here. + +config XMON_DEFAULT + bool "Enable xmon by default" + depends on XMON + +config PPCDBG + bool "Include PPCDBG realtime debugging" + depends on DEBUG_KERNEL + +config IRQSTACKS + bool "Use separate kernel stacks when processing interrupts" + help + If you say Y here the kernel will use separate kernel stacks + for handling hard and soft interrupts. This can help avoid + overflowing the process kernel stacks. + +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on DEBUG_KERNEL && PROC_FS + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. + +endmenu diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile --- a/arch/ppc64/Makefile 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc64/Makefile 2004-10-18 14:55:55 -07:00 @@ -15,29 +15,34 @@ KERNELLOAD := 0xc000000000000000 -HAS_BIARCH := $(shell if $(CC) -m64 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi;) +HAS_BIARCH := $(call cc-option-yn, -m64) ifeq ($(HAS_BIARCH),y) AS := $(AS) -a64 LD := $(LD) -m elf64ppc CC := $(CC) -m64 endif -CHECK := $(CHECK) -m64 -D__powerpc__=1 +new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi) + +ifeq ($(new_nm),y) +NM := $(NM) --synthetic +endif + +CHECKFLAGS += -m64 -D__powerpc__ LDFLAGS := -m elf64ppc LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD) -CFLAGS += -msoft-float -pipe -Wno-uninitialized -mminimal-toc \ - -mtraceback=none +CFLAGS += -msoft-float -pipe -mminimal-toc -mtraceback=none ifeq ($(CONFIG_POWER4_ONLY),y) - CFLAGS += $(call check_gcc,-mcpu=power4,) + CFLAGS += $(call cc-option,-mcpu=power4) else - CFLAGS += $(call check_gcc,-mtune=power4,) + CFLAGS += $(call cc-option,-mtune=power4) endif # Enable unit-at-a-time mode when possible. It shrinks the # kernel considerably. -CFLAGS += $(call check_gcc,-funit-at-a-time,) +CFLAGS += $(call cc-option,-funit-at-a-time) head-y := arch/ppc64/kernel/head.o diff -Nru a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile --- a/arch/ppc64/boot/Makefile 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc64/boot/Makefile 2004-10-18 14:56:50 -07:00 @@ -25,11 +25,11 @@ BOOTCC := $(CROSS32_COMPILE)gcc HOSTCC := gcc -BOOTCFLAGS := $(HOSTCFLAGS) -Iinclude -fno-builtin +BOOTCFLAGS := $(HOSTCFLAGS) $(LINUXINCLUDE) -fno-builtin BOOTAS := $(CROSS32_COMPILE)as BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional BOOTLD := $(CROSS32_COMPILE)ld -BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(obj)/zImage.lds +BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds BOOTOBJCOPY := $(CROSS32_COMPILE)objcopy OBJCOPYFLAGS := contents,alloc,load,readonly,data @@ -51,36 +51,31 @@ #----------------------------------------------------------- # ELF sections within the zImage bootloader/wrapper #----------------------------------------------------------- -required := vmlinux .config System.map +required := vmlinux.strip initrd := initrd obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section))) src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section))) gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section))) -host-progs := piggy addnote addSystemMap addRamDisk +hostprogs-y := piggy addnote addRamDisk targets += zImage zImage.initrd imagesize.c \ $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \ - vmlinux.sm vmlinux.initrd vmlinux.sminitrd -extra-y := sysmap.o initrd.o - -quiet_cmd_sysmap = SYSMAP $@ - cmd_sysmap = $(obj)/addSystemMap System.map $< $@ -$(obj)/vmlinux.sm: vmlinux $(obj)/addSystemMap System.map FORCE - $(call if_changed,sysmap) + vmlinux.initrd +extra-y := initrd.o quiet_cmd_ramdisk = RAMDISK $@ - cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz System.map $< $@ -$(obj)/vmlinux.initrd: vmlinux $(obj)/addRamDisk $(obj)/ramdisk.image.gz System.map FORCE - $(call if_changed,ramdisk) + cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@ -$(obj)/vmlinux.sminitrd: $(obj)/vmlinux.sm $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE - $(call if_changed,ramdisk) +quiet_cmd_stripvm = STRIP $@ + cmd_stripvm = $(STRIP) -s $< -o $@ -$(obj)/sysmap.o: System.map $(obj)/piggyback FORCE - $(call if_changed,piggy) +vmlinux.strip: vmlinux FORCE + $(call if_changed,stripvm) +$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE + $(call if_changed,ramdisk) addsection = $(BOOTOBJCOPY) $(1) \ --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(patsubst %.o,%.gz, $(1)) \ @@ -113,9 +108,9 @@ $(obj)/zImage.initrd: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(obj)/addnote FORCE $(call if_changed,addnote) -$(obj)/imagesize.c: vmlinux +$(obj)/imagesize.c: vmlinux.strip @echo Generating $@ - ls -l vmlinux | \ + ls -l vmlinux.strip | \ awk '{printf "/* generated -- do not edit! */\n" \ "unsigned long vmlinux_filesize = %d;\n", $$5}' > $(obj)/imagesize.c $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \ @@ -123,6 +118,6 @@ >> $(obj)/imagesize.c install: $(CONFIGURE) $(obj)/$(BOOTIMAGE) - sh -x $(src)/install.sh "$(KERNELRELEASE)" "$(obj)/$(BOOTIMAGE)" "$(TOPDIR)/System.map" "$(INSTALL_PATH)" + sh -x $(src)/install.sh "$(KERNELRELEASE)" "$(obj)/$(BOOTIMAGE)" "$(INSTALL_PATH)" -clean-files := $(patsubst $(obj)/%,%, $(obj-boot)) +clean-files := $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip) diff -Nru a/arch/ppc64/boot/addSystemMap.c b/arch/ppc64/boot/addSystemMap.c --- a/arch/ppc64/boot/addSystemMap.c 2004-10-18 14:56:29 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,248 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void xlate( char * inb, char * trb, unsigned len ) -{ - unsigned i; - for ( i=0; i> 4; - char c2 = c & 0xf; - if ( c1 > 9 ) - c1 = c1 + 'A' - 10; - else - c1 = c1 + '0'; - if ( c2 > 9 ) - c2 = c2 + 'A' - 10; - else - c2 = c2 + '0'; - *trb++ = c1; - *trb++ = c2; - } - *trb = 0; -} - -#define ElfHeaderSize (64 * 1024) -#define ElfPages (ElfHeaderSize / 4096) - -void get4k( /*istream *inf*/FILE *file, char *buf ) -{ - unsigned j; - unsigned num = fread(buf, 1, 4096, file); - for ( j=num; j<4096; ++j ) - buf[j] = 0; -} - -void put4k( /*ostream *outf*/FILE *file, char *buf ) -{ - fwrite(buf, 1, 4096, file); -} - -int main(int argc, char **argv) -{ - char inbuf[4096]; - FILE *sysmap = NULL; - char* ptr_end = NULL; - FILE *inputVmlinux = NULL; - FILE *outputVmlinux = NULL; - long i = 0; - unsigned long sysmapFileLen = 0; - unsigned long sysmapLen = 0; - unsigned long roundR = 0; - unsigned long kernelLen = 0; - unsigned long actualKernelLen = 0; - unsigned long round = 0; - unsigned long roundedKernelLen = 0; - unsigned long sysmapStartOffs = 0; - unsigned long sysmapPages = 0; - unsigned long roundedKernelPages = 0; - long padPages = 0; - if ( argc < 2 ) - { - fprintf(stderr, "Name of System Map file missing.\n"); - exit(1); - } - - if ( argc < 3 ) - { - fprintf(stderr, "Name of vmlinux file missing.\n"); - exit(1); - } - - if ( argc < 4 ) - { - fprintf(stderr, "Name of vmlinux output file missing.\n"); - exit(1); - } - - sysmap = fopen(argv[1], "r"); - if ( ! sysmap ) - { - fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[1]); - exit(1); - } - inputVmlinux = fopen(argv[2], "r"); - if ( ! inputVmlinux ) - { - fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[2]); - exit(1); - } - outputVmlinux = fopen(argv[3], "w"); - if ( ! outputVmlinux ) - { - fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[3]); - exit(1); - } - - - - fseek(inputVmlinux, 0, SEEK_END); - kernelLen = ftell(inputVmlinux); - fseek(inputVmlinux, 0, SEEK_SET); - printf("kernel file size = %ld\n", kernelLen); - if ( kernelLen == 0 ) - { - fprintf(stderr, "You must have a linux kernel specified as argv[2]\n"); - exit(1); - } - - - actualKernelLen = kernelLen - ElfHeaderSize; - - printf("actual kernel length (minus ELF header) = %ld/%lxx \n", actualKernelLen, actualKernelLen); - - round = actualKernelLen % 4096; - roundedKernelLen = actualKernelLen; - if ( round ) - roundedKernelLen += (4096 - round); - - printf("Kernel length rounded up to a 4k multiple = %ld/%lxx \n", roundedKernelLen, roundedKernelLen); - roundedKernelPages = roundedKernelLen / 4096; - printf("Kernel pages to copy = %ld/%lxx\n", roundedKernelPages, roundedKernelPages); - - - - /* Sysmap file */ - fseek(sysmap, 0, SEEK_END); - sysmapFileLen = ftell(sysmap); - fseek(sysmap, 0, SEEK_SET); - printf("%s file size = %ld\n", argv[1], sysmapFileLen); - - sysmapLen = sysmapFileLen; - - roundR = 4096 - (sysmapLen % 4096); - if (roundR) - { - printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR); - sysmapLen += roundR; - } - printf("Rounded System Map size is %ld\n", sysmapLen); - - /* Process the Sysmap file to determine the true end of the kernel */ - sysmapPages = sysmapLen / 4096; - printf("System map pages to copy = %ld\n", sysmapPages); - /* read the whole file line by line, expect that it doesn't fail */ - while ( fgets(inbuf, 4096, sysmap) ) ; - /* search for _end in the last page of the system map */ - ptr_end = strstr(inbuf, " _end"); - if (!ptr_end) - { - fprintf(stderr, "Unable to find _end in the sysmap file \n"); - fprintf(stderr, "inbuf: \n"); - fprintf(stderr, "%s \n", inbuf); - exit(1); - } - printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10); - sysmapStartOffs = (unsigned int)strtol(ptr_end-10, NULL, 16); - /* calc how many pages we need to insert between the vmlinux and the start of the sysmap */ - padPages = sysmapStartOffs/4096 - roundedKernelPages; - - /* Check and see if the vmlinux is larger than _end in System.map */ - if (padPages < 0) - { /* vmlinux is larger than _end - adjust the offset to start the embedded system map */ - sysmapStartOffs = roundedKernelLen; - printf("vmlinux is larger than _end indicates it needs to be - sysmapStartOffs = %lx \n", sysmapStartOffs); - padPages = 0; - printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages); - } - else - { /* _end is larger than vmlinux - use the sysmapStartOffs we calculated from the system map */ - printf("vmlinux is smaller than _end indicates is needed - sysmapStartOffs = %lx \n", sysmapStartOffs); - printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages); - } - - - - - /* Copy 64K ELF header */ - for (i=0; i<(ElfPages); ++i) - { - get4k( inputVmlinux, inbuf ); - put4k( outputVmlinux, inbuf ); - } - - - /* Copy the vmlinux (as full pages). */ - fseek(inputVmlinux, ElfHeaderSize, SEEK_SET); - for ( i=0; i 0 ) { - sysmap.addr = (RAM_END - sysmap.size) & ~0xFFF; - claim(sysmap.addr, RAM_END - sysmap.addr, 0); - printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", - sysmap.addr, (unsigned long)_sysmap_start, sysmap.size); - memcpy((void *)sysmap.addr, (void *)_sysmap_start, sysmap.size); + /* + * Now we try to claim some memory for the kernel itself + * our "vmlinux_memsize" is the memory footprint in RAM, _HOWEVER_, what + * our Makefile stuffs in is an image containing all sort of junk including + * an ELF header. We need to do some calculations here to find the right + * size... In practice we add 1Mb, that is enough, but we should really + * consider fixing the Makefile to put a _raw_ kernel in there ! + */ + vmlinux_memsize += 0x100000; + printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux_memsize); + vmlinux.addr = try_claim(vmlinux_memsize); + if (vmlinux.addr == 0) { + printf("Can't allocate memory for kernel image !\n\r"); + exit(); } -#endif + vmlinuz.addr = (unsigned long)_vmlinux_start; + vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); + vmlinux.size = PAGE_ALIGN(vmlinux_filesize); + vmlinux.memsize = vmlinux_memsize; + /* + * Now we try to claim memory for the initrd (and copy it there) + */ initrd.size = (unsigned long)(_initrd_end - _initrd_start); initrd.memsize = initrd.size; if ( initrd.size > 0 ) { - initrd.addr = (RAM_END - initrd.size) & ~0xFFF; - a1 = a2 = 0; - claim(initrd.addr, RAM_END - initrd.addr, 0); + printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size); + initrd.addr = try_claim(initrd.size); + if (initrd.addr == 0) { + printf("Can't allocate memory for initial ramdisk !\n\r"); + exit(); + } + a1 = initrd.addr; + a2 = initrd.size; printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", initrd.addr, (unsigned long)_initrd_start, initrd.size); - memcpy((void *)initrd.addr, (void *)_initrd_start, initrd.size); + memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size); + printf("initrd head: 0x%lx\n", *((u32 *)initrd.addr)); } - vmlinuz.addr = (unsigned long)_vmlinux_start; - vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); - vmlinux.addr = (unsigned long)(void *)-1; - vmlinux.size = PAGE_ALIGN(vmlinux_filesize); - vmlinux.memsize = vmlinux_memsize; - - claim_size = vmlinux.memsize /* PPPBBB: + fudge for bi_recs */; - for(claim_addr = PROG_START; - claim_addr <= PROG_START * 8; - claim_addr += 0x100000) { -#ifdef DEBUG - printf(" trying: 0x%08lx\n\r", claim_addr); -#endif - vmlinux.addr = (unsigned long)claim(claim_addr, claim_size, 0); - if ((void *)vmlinux.addr != (void *)-1) break; - } - if ((void *)vmlinux.addr == (void *)-1) { - printf("claim error, can't allocate kernel memory\n\r"); - exit(); - } - - /* PPPBBB: should kernel always be gziped? */ + /* Eventually gunzip the kernel */ if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { + int len; avail_ram = scratch; begin_avail = avail_high = avail_ram; end_avail = scratch + sizeof(scratch); printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...", vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size); + len = vmlinuz.size; gunzip((void *)vmlinux.addr, vmlinux.size, - (unsigned char *)vmlinuz.addr, (int *)&vmlinuz.size); - printf("done %lu bytes\n\r", vmlinuz.size); - printf("%u bytes of heap consumed, max in use %u\n\r", + (unsigned char *)vmlinuz.addr, &len); + printf("done 0x%lx bytes\n\r", len); + printf("0x%x bytes of heap consumed, max in use 0x%\n\r", (unsigned)(avail_high - begin_avail), heap_max); } else { memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size); @@ -192,7 +202,8 @@ flush_cache((void *)vmlinux.addr, vmlinux.memsize); - bi_recs = make_bi_recs(vmlinux.addr + vmlinux.memsize); + if (a1) + printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr)); kernel_entry = (kernel_entry_t)vmlinux.addr; #ifdef DEBUG @@ -203,63 +214,14 @@ " prom = 0x%lx,\n\r" " bi_recs = 0x%lx,\n\r", (unsigned long)kernel_entry, a1, a2, - (unsigned long)prom, (unsigned long)bi_recs); + (unsigned long)prom, NULL); #endif - kernel_entry( a1, a2, prom, bi_recs ); + kernel_entry( a1, a2, prom, NULL ); printf("Error: Linux kernel returned to zImage bootloader!\n\r"); exit(); -} - -static struct bi_record * -make_bi_recs(unsigned long addr) -{ - struct bi_record *bi_recs; - struct bi_record *rec; - - bi_recs = rec = bi_rec_init(addr); - - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_FIRST; - /* rec->data[0] = ...; # Written below before return */ - /* rec->data[1] = ...; # Written below before return */ - - rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1); - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "chrpboot"); - - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_MACHTYPE; - rec->data[0] = PLATFORM_PSERIES; - rec->data[1] = 1; - - if ( initrd.size > 0 ) { - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_INITRD; - rec->data[0] = initrd.addr; - rec->data[1] = initrd.size; - } - - if ( sysmap.size > 0 ) { - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)sysmap.addr; - rec->data[1] = (unsigned long)sysmap.size; - } - - rec = bi_rec_alloc(rec, 1); - rec->tag = BI_LAST; - rec->data[0] = (bi_rec_field)bi_recs; - - /* Save the _end_ address of the bi_rec's in the first bi_rec - * data field for easy access by the kernel. - */ - bi_recs->data[0] = (bi_rec_field)rec; - bi_recs->data[1] = (bi_rec_field)rec + rec->size - (bi_rec_field)bi_recs; - - return bi_recs; } struct memchunk { diff -Nru a/arch/ppc64/boot/zImage.lds b/arch/ppc64/boot/zImage.lds --- a/arch/ppc64/boot/zImage.lds 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc64/boot/zImage.lds 2004-10-18 14:55:54 -07:00 @@ -61,18 +61,8 @@ . = ALIGN(4096); _vmlinux_start = .; - .kernel:vmlinux : { *(.kernel:vmlinux) } + .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) } _vmlinux_end = .; - - . = ALIGN(4096); - _dotconfig_start = .; - .kernel:.config : { *(.kernel:.config) } - _dotconfig_end = .; - - . = ALIGN(4096); - _sysmap_start = .; - .kernel:System.map : { *(.kernel:System.map) } - _sysmap_end = .; . = ALIGN(4096); _initrd_start = .; diff -Nru a/arch/ppc64/configs/g5_defconfig b/arch/ppc64/configs/g5_defconfig --- a/arch/ppc64/configs/g5_defconfig 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc64/configs/g5_defconfig 2004-10-18 14:55:54 -07:00 @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3 +# Thu Oct 7 15:18:38 2004 # CONFIG_64BIT=y CONFIG_MMU=y @@ -16,11 +18,11 @@ # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set @@ -32,6 +34,8 @@ # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -39,6 +43,8 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -50,18 +56,20 @@ # CONFIG_MODVERSIONS is not set # CONFIG_KMOD is not set CONFIG_STOP_MACHINE=y +CONFIG_SYSVIPC_COMPAT=y # # Platform support # # CONFIG_PPC_ISERIES is not set -CONFIG_PPC_PSERIES=y +CONFIG_PPC_MULTIPLATFORM=y +# CONFIG_PPC_PSERIES is not set +CONFIG_PPC_PMAC=y CONFIG_PPC=y CONFIG_PPC64=y CONFIG_PPC_OF=y CONFIG_ALTIVEC=y -CONFIG_PPC_PMAC=y -CONFIG_PMAC_DART=y +CONFIG_U3_DART=y CONFIG_PPC_PMAC64=y CONFIG_BOOTX_TEXT=y CONFIG_POWER4_ONLY=y @@ -69,8 +77,8 @@ CONFIG_SMP=y CONFIG_IRQ_ALL_CPUS=y CONFIG_NR_CPUS=2 -# CONFIG_HMT is not set -# CONFIG_DISCONTIGMEM is not set +# CONFIG_SCHED_SMT is not set +# CONFIG_PREEMPT is not set # CONFIG_PPC_RTAS is not set # CONFIG_LPARCFG is not set @@ -104,6 +112,8 @@ # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set @@ -132,7 +142,8 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_CARMEL is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_INITRD=y @@ -146,9 +157,9 @@ # # Please see Documentation/ide.txt for help/info on IDE drives # +# CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDETAPE=y CONFIG_BLK_DEV_IDEFLOPPY=y @@ -170,7 +181,6 @@ # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set @@ -196,6 +206,7 @@ CONFIG_BLK_DEV_IDEDMA_PMAC=y # CONFIG_BLK_DEV_IDE_PMAC_BLINK is not set CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -221,7 +232,6 @@ # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -235,23 +245,25 @@ # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y CONFIG_SCSI_SATA_SVW=y # CONFIG_SCSI_ATA_PIIX is not set +# CONFIG_SCSI_SATA_NV is not set # CONFIG_SCSI_SATA_PROMISE is not set +# CONFIG_SCSI_SATA_SX4 is not set # CONFIG_SCSI_SATA_SIL is not set # CONFIG_SCSI_SATA_SIS is not set # CONFIG_SCSI_SATA_VIA is not set # CONFIG_SCSI_SATA_VITESSE is not set # CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set @@ -264,6 +276,7 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set @@ -277,7 +290,6 @@ # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_MESH is not set # CONFIG_SCSI_MAC53C94 is not set # @@ -288,11 +300,15 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=y # CONFIG_MD_RAID6 is not set # CONFIG_MD_MULTIPATH is not set CONFIG_BLK_DEV_DM=y # CONFIG_DM_CRYPT is not set +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_ZERO is not set # # Fusion MPT device support @@ -332,6 +348,7 @@ # # I2O device support # +# CONFIG_I2O is not set # # Macintosh device drivers @@ -340,7 +357,6 @@ CONFIG_ADB_PMU=y # CONFIG_PMAC_PBOOK is not set # CONFIG_PMAC_BACKLIGHT is not set -# CONFIG_MAC_SERIAL is not set # CONFIG_INPUT_ADBHID is not set CONFIG_THERM_PM72=y @@ -369,14 +385,13 @@ CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m +CONFIG_INET_TUNNEL=y # # IP: Virtual Server Configuration # # CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -384,6 +399,8 @@ # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=y +# CONFIG_IP_NF_CT_ACCT is not set +# CONFIG_IP_NF_CT_PROTO_SCTP is not set # CONFIG_IP_NF_FTP is not set # CONFIG_IP_NF_IRC is not set # CONFIG_IP_NF_TFTP is not set @@ -408,8 +425,15 @@ CONFIG_IP_NF_MATCH_STATE=y CONFIG_IP_NF_MATCH_CONNTRACK=y CONFIG_IP_NF_MATCH_OWNER=y +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set +# CONFIG_IP_NF_MATCH_SCTP is not set +# CONFIG_IP_NF_MATCH_COMMENT is not set CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_IP_NF_TARGET_ULOG=y +CONFIG_IP_NF_TARGET_TCPMSS=y CONFIG_IP_NF_NAT=y CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y @@ -424,9 +448,7 @@ CONFIG_IP_NF_TARGET_DSCP=y CONFIG_IP_NF_TARGET_MARK=y CONFIG_IP_NF_TARGET_CLASSIFY=y -CONFIG_IP_NF_TARGET_LOG=y -CONFIG_IP_NF_TARGET_ULOG=y -CONFIG_IP_NF_TARGET_TCPMSS=y +# CONFIG_IP_NF_RAW is not set CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y @@ -438,7 +460,9 @@ # # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set CONFIG_LLC=y # CONFIG_LLC2 is not set # CONFIG_IPX is not set @@ -454,30 +478,33 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m # # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=m -CONFIG_BONDING=m -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y CONFIG_MII=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -# CONFIG_OAKNET is not set # CONFIG_HAPPYMEAL is not set CONFIG_SUNGEM=y # CONFIG_NET_VENDOR_3COM is not set @@ -509,57 +536,38 @@ # # CONFIG_IXGB is not set # CONFIG_S2IO is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_IBMVETH is not set -CONFIG_PPP=m -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_FILTER is not set -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set # # Token Ring devices # CONFIG_TR=y CONFIG_IBMOL=y -# CONFIG_IBMLS is not set # CONFIG_3C359 is not set # CONFIG_TMS380TR is not set -# CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set # -# IrDA (infrared) support +# Wireless LAN (non-hamradio) # -# CONFIG_IRDA is not set +# CONFIG_NET_RADIO is not set # -# Bluetooth support +# Wan interfaces # -# CONFIG_BT is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # ISDN subsystem @@ -598,6 +606,7 @@ # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set # # Input Device Drivers @@ -636,8 +645,6 @@ CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -CONFIG_HVC_CONSOLE=y -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -673,6 +680,7 @@ # CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set # # I2C Hardware Bus support @@ -697,23 +705,29 @@ # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set # # Hardware Sensors Chip support # # CONFIG_I2C_SENSOR is not set # CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ASB100 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set # CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set @@ -725,12 +739,18 @@ # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set # +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# # Misc devices # @@ -748,6 +768,8 @@ # Graphics support # CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y @@ -755,10 +777,12 @@ # CONFIG_FB_PLATINUM is not set # CONFIG_FB_VALKYRIE is not set # CONFIG_FB_CT65550 is not set +# CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set -# CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_RIVA=y +# CONFIG_FB_RIVA_I2C is not set +# CONFIG_FB_RIVA_DEBUG is not set # CONFIG_FB_MATROX is not set # CONFIG_FB_RADEON_OLD is not set CONFIG_FB_RADEON=y @@ -778,10 +802,8 @@ # 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 @@ -811,6 +833,7 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -829,6 +852,7 @@ CONFIG_USB_PRINTER=y CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set CONFIG_USB_STORAGE_DATAFAB=y CONFIG_USB_STORAGE_FREECOM=y CONFIG_USB_STORAGE_ISD200=y @@ -853,6 +877,7 @@ # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set @@ -959,6 +984,7 @@ # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set # CONFIG_USB_TEST is not set # @@ -997,6 +1023,7 @@ # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -1004,6 +1031,8 @@ CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -1016,8 +1045,8 @@ CONFIG_DEVPTS_FS_XATTR=y # CONFIG_DEVPTS_FS_SECURITY is not set CONFIG_TMPFS=y -# CONFIG_HUGETLBFS is not set -# CONFIG_HUGETLB_PAGE is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y # @@ -1030,7 +1059,7 @@ # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set +CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set @@ -1054,11 +1083,14 @@ CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_POSIX 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 # @@ -1076,7 +1108,6 @@ # 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 @@ -1110,6 +1141,7 @@ # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -1135,13 +1167,16 @@ # Kernel hacking # CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_STACKOVERFLOW is not set # CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_SLAB is not set -CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUGGER is not set # CONFIG_PPCDBG is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_IRQSTACKS=y +# CONFIG_SCHEDSTATS is not set # # Security options @@ -1159,6 +1194,7 @@ CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m +# CONFIG_CRYPTO_WP512 is not set CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m @@ -1166,14 +1202,19 @@ CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +# CONFIG_CRYPTO_TEA is not set CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_KHAZAD is not set CONFIG_CRYPTO_DEFLATE=m CONFIG_CRYPTO_MICHAEL_MIC=m +# CONFIG_CRYPTO_CRC32C is not set CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_CRC_CCITT=m CONFIG_CRC32=y -CONFIG_ZLIB_INFLATE=m +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/ppc64/configs/iSeries_defconfig b/arch/ppc64/configs/iSeries_defconfig --- a/arch/ppc64/configs/iSeries_defconfig 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc64/configs/iSeries_defconfig 2004-10-18 14:57:05 -07:00 @@ -16,17 +16,17 @@ # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_POSIX_MQUEUE is not set +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y CONFIG_LOG_BUF_SHIFT=17 CONFIG_HOTPLUG=y CONFIG_IKCONFIG=y @@ -34,6 +34,7 @@ # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -41,6 +42,8 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -62,10 +65,11 @@ CONFIG_PPC=y CONFIG_PPC64=y # CONFIG_POWER4_ONLY is not set -# CONFIG_IOMMU_VMERGE is not set +CONFIG_IOMMU_VMERGE=y CONFIG_SMP=y CONFIG_NR_CPUS=32 # CONFIG_SCHED_SMT is not set +# CONFIG_PREEMPT is not set CONFIG_MSCHUNKS=y CONFIG_LPARCFG=y @@ -97,6 +101,8 @@ # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set @@ -125,7 +131,7 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_CARMEL is not set +# CONFIG_BLK_DEV_SX8 is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -168,22 +174,23 @@ # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY 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 # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set +CONFIG_SCSI_IBMVSCSI=m # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set @@ -209,11 +216,15 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m CONFIG_MD_RAID5=y -CONFIG_MD_RAID6=y -# CONFIG_MD_MULTIPATH is not set +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m # # Fusion MPT device support @@ -259,6 +270,7 @@ CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m +CONFIG_INET_TUNNEL=y # # IP: Virtual Server Configuration @@ -324,7 +336,13 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_COMPAT_IPFWADM=m -# CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_REALM=m +# CONFIG_IP_NF_CT_ACCT is not set +CONFIG_IP_NF_MATCH_SCTP=m +CONFIG_IP_NF_CT_PROTO_SCTP=m CONFIG_XFRM=y CONFIG_XFRM_USER=m @@ -351,6 +369,7 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +CONFIG_NET_CLS_ROUTE=y # # Network testing @@ -379,7 +398,6 @@ # CONFIG_NET_ETHERNET=y CONFIG_MII=y -# CONFIG_OAKNET is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set @@ -408,18 +426,32 @@ # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set # -# Gigabit Ethernet (1000/10000 Mbit) +# Ethernet (1000 Mbit) # -# CONFIG_NET_GIGE is not set +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set # # Token Ring devices # CONFIG_TR=y CONFIG_IBMOL=y -# CONFIG_IBMLS is not set # CONFIG_3C359 is not set # CONFIG_TMS380TR is not set @@ -508,10 +540,11 @@ # # Non-8250 serial port support # +CONFIG_SERIAL_CORE=m +CONFIG_SERIAL_ICOM=m CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -542,6 +575,11 @@ # CONFIG_I2C is not set # +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# # Misc devices # @@ -592,8 +630,10 @@ CONFIG_REISERFS_FS=y # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set -# CONFIG_REISERFS_FS_XATTR is not set -CONFIG_JFS_FS=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +# CONFIG_REISERFS_FS_SECURITY is not set +CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set @@ -616,6 +656,7 @@ # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -623,6 +664,8 @@ CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -663,19 +706,22 @@ CONFIG_NFS_V3=y CONFIG_NFS_V4=y # CONFIG_NFS_DIRECTIO is not set -CONFIG_NFSD=y +CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=y +CONFIG_EXPORTFS=m CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y CONFIG_RPCSEC_GSS_KRB5=y +CONFIG_RPCSEC_GSS_SPKM3=m # CONFIG_SMB_FS is not set CONFIG_CIFS=m # CONFIG_CIFS_STATS is not set +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -691,7 +737,7 @@ # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -714,7 +760,8 @@ # 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 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -748,14 +795,16 @@ # Kernel hacking # CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y -# CONFIG_DEBUG_SLAB is not set -CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUGGER is not set # CONFIG_PPCDBG is not set -# CONFIG_DEBUG_INFO is not set # CONFIG_IRQSTACKS is not set +# CONFIG_SCHEDSTATS is not set # # Security options @@ -773,6 +822,7 @@ CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WHIRLPOOL=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m @@ -780,16 +830,19 @@ CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_DEFLATE=m -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_CRC_CCITT=m CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set +CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/ppc64/configs/pSeries_defconfig b/arch/ppc64/configs/pSeries_defconfig --- a/arch/ppc64/configs/pSeries_defconfig 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc64/configs/pSeries_defconfig 2004-10-18 14:57:03 -07:00 @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Thu Sep 23 16:45:05 2004 # CONFIG_64BIT=y CONFIG_MMU=y @@ -16,27 +18,35 @@ # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y CONFIG_LOG_BUF_SHIFT=17 CONFIG_HOTPLUG=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -48,25 +58,31 @@ # CONFIG_MODVERSIONS is not set # CONFIG_KMOD is not set CONFIG_STOP_MACHINE=y +CONFIG_SYSVIPC_COMPAT=y # # Platform support # # CONFIG_PPC_ISERIES is not set +CONFIG_PPC_MULTIPLATFORM=y CONFIG_PPC_PSERIES=y +# CONFIG_PPC_PMAC is not set CONFIG_PPC=y CONFIG_PPC64=y CONFIG_PPC_OF=y CONFIG_ALTIVEC=y -# CONFIG_PPC_PMAC is not set +CONFIG_PPC_SPLPAR=y # CONFIG_BOOTX_TEXT is not set # CONFIG_POWER4_ONLY is not set -# CONFIG_IOMMU_VMERGE is not set +CONFIG_IOMMU_VMERGE=y CONFIG_SMP=y CONFIG_IRQ_ALL_CPUS=y -CONFIG_NR_CPUS=32 +CONFIG_NR_CPUS=128 # CONFIG_HMT is not set -# CONFIG_DISCONTIGMEM is not set +CONFIG_DISCONTIGMEM=y +CONFIG_NUMA=y +CONFIG_SCHED_SMT=y +# CONFIG_PREEMPT is not set CONFIG_PPC_RTAS=y CONFIG_RTAS_FLASH=m CONFIG_SCANLOG=m @@ -81,6 +97,7 @@ # CONFIG_BINFMT_MISC is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG_CPU=y # # PCMCIA/CardBus support @@ -107,7 +124,9 @@ # # Generic Driver Options # -CONFIG_FW_LOADER=m +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set # @@ -127,7 +146,7 @@ # # Block devices # -CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_FD=m # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -135,7 +154,8 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_CARMEL is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -149,9 +169,9 @@ # # Please see Documentation/ide.txt for help/info on IDE drives # +# CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -173,7 +193,6 @@ # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set CONFIG_BLK_DEV_AMD74XX=y @@ -194,6 +213,7 @@ # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -219,7 +239,6 @@ # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -233,28 +252,32 @@ # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY 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 # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set +CONFIG_SCSI_IBMVSCSI=m # 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_IPR=y +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set @@ -277,11 +300,15 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m CONFIG_MD_RAID5=y -CONFIG_MD_RAID6=y -# CONFIG_MD_MULTIPATH is not set +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m # # Fusion MPT device support @@ -296,6 +323,7 @@ # # I2O device support # +# CONFIG_I2O is not set # # Macintosh device drivers @@ -322,19 +350,17 @@ # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set -CONFIG_INET_ECN=y CONFIG_SYN_COOKIES=y CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m +CONFIG_INET_TUNNEL=y # # IP: Virtual Server Configuration # # CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -342,6 +368,8 @@ # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=m +# CONFIG_IP_NF_CT_ACCT is not set +CONFIG_IP_NF_CT_PROTO_SCTP=m CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m CONFIG_IP_NF_TFTP=m @@ -366,8 +394,14 @@ CONFIG_IP_NF_MATCH_STATE=m CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_REALM=m +CONFIG_IP_NF_MATCH_SCTP=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_NAT=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m @@ -386,9 +420,8 @@ CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_CLASSIFY=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_NOTRACK=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m @@ -400,10 +433,11 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set CONFIG_LLC=y # CONFIG_LLC2 is not set # CONFIG_IPX is not set @@ -419,28 +453,35 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +CONFIG_NET_CLS_ROUTE=y # # Network testing # # CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +CONFIG_NETPOLL_RX=y +CONFIG_NETPOLL_TRAP=y +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m # # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=m -CONFIG_BONDING=m -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y CONFIG_MII=y -# CONFIG_OAKNET is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set CONFIG_NET_VENDOR_3COM=y @@ -452,6 +493,7 @@ # # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set +CONFIG_IBMVETH=m CONFIG_NET_PCI=y CONFIG_PCNET32=y # CONFIG_AMD8111_ETH is not set @@ -471,6 +513,7 @@ # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set # # Ethernet (1000 Mbit) @@ -484,7 +527,6 @@ # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set CONFIG_TIGON3=y @@ -493,59 +535,40 @@ # CONFIG_IXGB=m # CONFIG_IXGB_NAPI is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -CONFIG_IBMVETH=m -CONFIG_PPP=m -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_FILTER is not set -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set # # Token Ring devices # CONFIG_TR=y CONFIG_IBMOL=y -# CONFIG_IBMLS is not set # CONFIG_3C359 is not set # CONFIG_TMS380TR is not set -# CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set -CONFIG_NETCONSOLE=y # -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support +# Wireless LAN (non-hamradio) # -# CONFIG_IRDA is not set +# CONFIG_NET_RADIO is not set # -# Bluetooth support +# Wan interfaces # -# CONFIG_BT is not set -CONFIG_NETPOLL=y -CONFIG_NETPOLL_RX=y -CONFIG_NETPOLL_TRAP=y -CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=y # # ISDN subsystem @@ -584,6 +607,7 @@ # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set # # Input Device Drivers @@ -591,15 +615,17 @@ CONFIG_INPUT_KEYBOARD=y CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TOUCHSCREEN is not set CONFIG_INPUT_MISC=y -CONFIG_INPUT_PCSPKR=y +# CONFIG_INPUT_PCSPKR is not set # CONFIG_INPUT_UINPUT is not set # @@ -624,16 +650,12 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_PMACZILOG is not set +CONFIG_SERIAL_ICOM=m CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 CONFIG_HVC_CONSOLE=y - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set +CONFIG_HVCS=m # # IPMI @@ -656,7 +678,7 @@ # CONFIG_AGP is not set # CONFIG_DRM is not set CONFIG_RAW_DRIVER=y -CONFIG_MAX_RAW_DEVS=256 +CONFIG_MAX_RAW_DEVS=1024 # # I2C support @@ -669,11 +691,13 @@ # CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set # # I2C Hardware Bus support # # CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set # CONFIG_I2C_ALI15X3 is not set # CONFIG_I2C_AMD756 is not set # CONFIG_I2C_AMD8111 is not set @@ -691,30 +715,52 @@ # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set # -# I2C Hardware Sensors Chip support +# Hardware Sensors Chip support # # CONFIG_I2C_SENSOR is not set # CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set # CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set # +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# # Misc devices # @@ -732,12 +778,14 @@ # Graphics support # CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=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_CT65550 is not set +# CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set -# CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set # CONFIG_FB_RIVA is not set CONFIG_FB_MATROX=y @@ -765,10 +813,8 @@ # 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 @@ -798,11 +844,14 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers # CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set CONFIG_USB_OHCI_HCD=y # CONFIG_USB_UHCI_HCD is not set @@ -814,6 +863,7 @@ # CONFIG_USB_PRINTER is not set CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set @@ -834,7 +884,10 @@ # CONFIG_USB_WACOM is not set # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set # CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set # # USB Imaging devices @@ -881,6 +934,8 @@ # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set # CONFIG_USB_TEST is not set # @@ -905,7 +960,10 @@ CONFIG_REISERFS_FS=y # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set -CONFIG_JFS_FS=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +# CONFIG_REISERFS_FS_SECURITY is not set +CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set @@ -928,6 +986,7 @@ # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -935,6 +994,8 @@ CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -942,6 +1003,7 @@ # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS_XATTR=y # CONFIG_DEVPTS_FS_SECURITY is not set @@ -974,18 +1036,22 @@ CONFIG_NFS_V3=y CONFIG_NFS_V4=y # CONFIG_NFS_DIRECTIO is not set -CONFIG_NFSD=y +CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=y +CONFIG_EXPORTFS=m CONFIG_SUNRPC=y -CONFIG_SUNRPC_GSS=m -CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +CONFIG_RPCSEC_GSS_SPKM3=m # CONFIG_SMB_FS is not set CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -1001,7 +1067,7 @@ # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -1024,7 +1090,8 @@ # 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 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -1049,15 +1116,18 @@ # Kernel hacking # CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y -# CONFIG_DEBUG_SLAB is not set -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUGGER=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y # CONFIG_PPCDBG is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_IRQSTACKS=y +# CONFIG_SCHEDSTATS is not set # # Security options @@ -1071,24 +1141,31 @@ CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_WHIRLPOOL=m +CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_CRC_CCITT=m CONFIG_CRC32=y +CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/ppc64/kernel/ItLpQueue.c b/arch/ppc64/kernel/ItLpQueue.c --- a/arch/ppc64/kernel/ItLpQueue.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc64/kernel/ItLpQueue.c 2004-10-18 14:55:55 -07:00 @@ -25,7 +25,7 @@ __asm__ __volatile__("\n\ 1: lwarx %0,0,%2 \n\ - cmpi 0,%0,0 \n\ + cmpwi 0,%0,0 \n\ li %0,0 \n\ bne- 2f \n\ addi %0,%0,1 \n\ diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile --- a/arch/ppc64/kernel/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc64/kernel/Makefile 2004-10-18 14:57:04 -07:00 @@ -3,11 +3,11 @@ # EXTRA_CFLAGS += -mno-minimal-toc -extra-y := head.o vmlinux.lds.s +extra-y := head.o vmlinux.lds obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \ - align.o semaphore.o bitops.o stab.o pacaData.o \ + align.o semaphore.o bitops.o pacaData.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ @@ -17,9 +17,9 @@ pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_pci_reset.o \ iSeries_IoMmTable.o -pci-obj-$(CONFIG_PPC_PSERIES) += pci_dn.o pci_dma_direct.o +pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_dma_direct.o -obj-$(CONFIG_PCI) += pci.o pci_iommu.o $(pci-obj-y) +obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ iSeries_VpdInfo.o XmPciLpEvent.o \ @@ -28,10 +28,11 @@ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o open_pic.o i8259.o prom_init.o prom.o + obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ - eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \ - open_pic.o xics.o pSeries_htab.o rtas.o \ - chrp_setup.o i8259.o prom.o pSeries_iommu.o + eeh.o pSeries_nvram.o rtasd.o ras.o \ + xics.o rtas.o pSeries_setup.o pSeries_iommu.o obj-$(CONFIG_PROC_FS) += proc_ppc64.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o @@ -48,7 +49,7 @@ obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ pmac_time.o pmac_nvram.o pmac_low_i2c.o \ open_pic_u3.o -obj-$(CONFIG_PMAC_DART) += pmac_iommu.o +obj-$(CONFIG_U3_DART) += u3_iommu.o ifdef CONFIG_SMP obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c --- a/arch/ppc64/kernel/asm-offsets.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/kernel/asm-offsets.c 2004-10-18 14:56:33 -07:00 @@ -22,18 +22,17 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include #include #include -#include #include #include @@ -58,6 +57,7 @@ DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); DEFINE(KSP, offsetof(struct thread_struct, ksp)); + DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); #ifdef CONFIG_ALTIVEC DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); @@ -93,16 +93,10 @@ DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); - DEFINE(PACASLBR3, offsetof(struct paca_struct, slb_r3)); #ifdef CONFIG_HUGETLB_PAGE DEFINE(PACAHTLBSEGS, offsetof(struct paca_struct, context.htlb_segs)); #endif /* CONFIG_HUGETLB_PAGE */ DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); - DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled)); - DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len)); - DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift)); - DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer)); - DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext)); DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); @@ -113,15 +107,10 @@ DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt)); - DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr)); - DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending)); - DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags)); - DEFINE(PROMENTRY, offsetof(struct prom_t, entry)); /* RTAS */ DEFINE(RTASBASE, offsetof(struct rtas_t, base)); DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); - DEFINE(RTASSIZE, offsetof(struct rtas_t, size)); /* Interrupt register frame */ DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); @@ -148,10 +137,6 @@ DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); - DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); - DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); - DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); - DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); /* * Note: these symbols include _ because they overlap with special * register names diff -Nru a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c --- a/arch/ppc64/kernel/btext.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/btext.c 2004-10-18 14:56:49 -07:00 @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -36,6 +36,11 @@ static int g_max_loc_X; static int g_max_loc_Y; +static int dispDeviceRowBytes; +static int dispDeviceDepth; +static int dispDeviceRect[4]; +static unsigned char *dispDeviceBase, *logicalDisplayBase; + unsigned long disp_BAT[2] __initdata = {0, 0}; #define cmapsz (16*256) @@ -45,30 +50,6 @@ int boot_text_mapped; int force_printk_to_btext = 0; -boot_infos_t disp_bi; - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -void __init btext_setup_display(int width, int height, int depth, int pitch, - unsigned long address) -{ - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = width / 8; - RELOC(g_max_loc_Y) = height / 16; - bi->logicalDisplayBase = (unsigned char *)address; - bi->dispDeviceBase = (unsigned char *)address; - bi->dispDeviceRowBytes = pitch; - bi->dispDeviceDepth = depth; - bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; - RELOC(boot_text_mapped) = 1; -} /* Here's a small text engine to use during early boot * or for debugging purposes @@ -84,34 +65,84 @@ void map_boot_text(void) { unsigned long base, offset, size; - boot_infos_t *bi = &disp_bi; unsigned char *vbase; /* By default, we are no longer mapped */ boot_text_mapped = 0; - if (bi->dispDeviceBase == 0) + if (dispDeviceBase == 0) return; - base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL; - offset = ((unsigned long) bi->dispDeviceBase) - base; - size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset - + bi->dispDeviceRect[0]; + base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL; + offset = ((unsigned long) dispDeviceBase) - base; + size = dispDeviceRowBytes * dispDeviceRect[3] + offset + + dispDeviceRect[0]; vbase = __ioremap(base, size, _PAGE_NO_CACHE); if (vbase == 0) return; - bi->logicalDisplayBase = vbase + offset; + logicalDisplayBase = vbase + offset; boot_text_mapped = 1; } +int btext_initialize(struct device_node *np) +{ + unsigned int width, height, depth, pitch; + unsigned long address = 0; + u32 *prop; + + prop = (u32 *)get_property(np, "width", NULL); + if (prop == NULL) + return -EINVAL; + width = *prop; + prop = (u32 *)get_property(np, "height", NULL); + if (prop == NULL) + return -EINVAL; + height = *prop; + prop = (u32 *)get_property(np, "depth", NULL); + if (prop == NULL) + return -EINVAL; + depth = *prop; + pitch = width * ((depth + 7) / 8); + prop = (u32 *)get_property(np, "linebytes", NULL); + if (prop) + pitch = *prop; + if (pitch == 1) + pitch = 0x1000; + prop = (u32 *)get_property(np, "address", NULL); + if (prop) + address = *prop; + + /* FIXME: Add support for PCI reg properties */ + + if (address == 0) + return -EINVAL; + + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; + logicalDisplayBase = (unsigned char *)address; + dispDeviceBase = (unsigned char *)address; + dispDeviceRowBytes = pitch; + dispDeviceDepth = depth; + dispDeviceRect[0] = dispDeviceRect[1] = 0; + dispDeviceRect[2] = width; + dispDeviceRect[3] = height; + + map_boot_text(); + + return 0; +} + + /* Calc the base address of a given point (x,y) */ -static unsigned char * calc_base(boot_infos_t *bi, int x, int y) +static unsigned char * calc_base(int x, int y) { unsigned char *base; - base = bi->logicalDisplayBase; + base = logicalDisplayBase; if (base == 0) - base = bi->dispDeviceBase; - base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3); - base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes; + base = dispDeviceBase; + base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3); + base += (y + dispDeviceRect[1]) * dispDeviceRowBytes; return base; } @@ -119,24 +150,22 @@ void btext_update_display(unsigned long phys, int width, int height, int depth, int pitch) { - boot_infos_t *bi = &disp_bi; - - if (bi->dispDeviceBase == 0) + if (dispDeviceBase == 0) return; /* check it's the same frame buffer (within 256MB) */ - if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000) + if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000) return; - bi->dispDeviceBase = (__u8 *) phys; - bi->dispDeviceRect[0] = 0; - bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; - bi->dispDeviceDepth = depth; - bi->dispDeviceRowBytes = pitch; + dispDeviceBase = (__u8 *) phys; + dispDeviceRect[0] = 0; + dispDeviceRect[1] = 0; + dispDeviceRect[2] = width; + dispDeviceRect[3] = height; + dispDeviceDepth = depth; + dispDeviceRowBytes = pitch; if (boot_text_mapped) { - iounmap(bi->logicalDisplayBase); + iounmap(logicalDisplayBase); boot_text_mapped = 0; } map_boot_text(); @@ -148,108 +177,101 @@ void btext_clearscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); - unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * - (bi->dispDeviceDepth >> 3)) >> 3; + unsigned long *base = (unsigned long *)calc_base(0, 0); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 3; int i,j; - for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) + for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) { unsigned long *ptr = base; for(j=width; j; --j) *(ptr++) = 0; - base += (bi->dispDeviceRowBytes >> 3); + base += (dispDeviceRowBytes >> 3); } } #ifndef NO_SCROLL static void scrollscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - unsigned long *src = (unsigned long *)calc_base(bi,0,16); - unsigned long *dst = (unsigned long *)calc_base(bi,0,0); - unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * - (bi->dispDeviceDepth >> 3)) >> 3; + unsigned long *src = (unsigned long *)calc_base(0,16); + unsigned long *dst = (unsigned long *)calc_base(0,0); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 3; int i,j; - for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) + for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) { unsigned long *src_ptr = src; unsigned long *dst_ptr = dst; for(j=width; j; --j) *(dst_ptr++) = *(src_ptr++); - src += (bi->dispDeviceRowBytes >> 3); - dst += (bi->dispDeviceRowBytes >> 3); + src += (dispDeviceRowBytes >> 3); + dst += (dispDeviceRowBytes >> 3); } for (i=0; i<16; i++) { unsigned long *dst_ptr = dst; for(j=width; j; --j) *(dst_ptr++) = 0; - dst += (bi->dispDeviceRowBytes >> 3); + dst += (dispDeviceRowBytes >> 3); } } #endif /* ndef NO_SCROLL */ void btext_drawchar(char c) { - unsigned long offset = reloc_offset(); int cline = 0; #ifdef NO_SCROLL int x; #endif - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; switch (c) { case '\b': - if (RELOC(g_loc_X) > 0) - --RELOC(g_loc_X); + if (g_loc_X > 0) + --g_loc_X; break; case '\t': - RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8; + g_loc_X = (g_loc_X & -8) + 8; break; case '\r': - RELOC(g_loc_X) = 0; + g_loc_X = 0; break; case '\n': - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + g_loc_X = 0; + g_loc_Y++; cline = 1; break; default: - draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + draw_byte(c, g_loc_X++, g_loc_Y); } - if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) { - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + if (g_loc_X >= g_max_loc_X) { + g_loc_X = 0; + g_loc_Y++; cline = 1; } #ifndef NO_SCROLL - while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) { + while (g_loc_Y >= g_max_loc_Y) { scrollscreen(); - RELOC(g_loc_Y)--; + g_loc_Y--; } #else /* wrap around from bottom to top of screen so we don't waste time scrolling each line. -- paulus. */ - if (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) - RELOC(g_loc_Y) = 0; + if (g_loc_Y >= g_max_loc_Y) + g_loc_Y = 0; if (cline) { - for (x = 0; x < RELOC(g_max_loc_X); ++x) - draw_byte(' ', x, RELOC(g_loc_Y)); + for (x = 0; x < g_max_loc_X; ++x) + draw_byte(' ', x, g_loc_Y); } #endif } void btext_drawstring(const char *c) { - unsigned long offset = reloc_offset(); - - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; while (*c) btext_drawchar(*c++); @@ -257,10 +279,9 @@ void btext_drawhex(unsigned long v) { - unsigned long offset = reloc_offset(); - char *hex_table = RELOC("0123456789abcdef"); + char *hex_table = "0123456789abcdef"; - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]); btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]); @@ -283,14 +304,11 @@ static void draw_byte(unsigned char c, long locX, long locY) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - unsigned char *base = calc_base(bi, locX << 3, locY << 4); - unsigned char *font = PTRRELOC(&vga_font[((unsigned int)c) * 16]); - int rb = bi->dispDeviceRowBytes; + unsigned char *base = calc_base(locX << 3, locY << 4); + unsigned char *font = &vga_font[((unsigned int)c) * 16]; + int rb = dispDeviceRowBytes; -#if 0 - switch(bi->dispDeviceDepth) { + switch(dispDeviceDepth) { case 24: case 32: draw_byte_32(font, (unsigned int *)base, rb); @@ -303,17 +321,6 @@ draw_byte_8(font, (unsigned int *)base, rb); break; } -#else - if(bi->dispDeviceDepth == 24 || - bi->dispDeviceDepth == 32) { - draw_byte_32(font, (unsigned int *)base, rb); - } else if(bi->dispDeviceDepth == 15 || - bi->dispDeviceDepth == 16) { - draw_byte_16(font, (unsigned int *)base, rb); - } else if(bi->dispDeviceDepth == 8) { - draw_byte_8(font, (unsigned int *)base, rb); - } -#endif } static unsigned int expand_bits_8[16] = { @@ -369,8 +376,7 @@ int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned int *eb = PTRRELOC((int *)expand_bits_16); + unsigned int *eb = (int *)expand_bits_16; for (l = 0; l < 16; ++l) { @@ -388,8 +394,7 @@ int l, bits; int fg = 0x0F0F0F0FUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned int *eb = PTRRELOC((int *)expand_bits_8); + unsigned int *eb = (int *)expand_bits_8; for (l = 0; l < 16; ++l) { diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c --- a/arch/ppc64/kernel/chrp_setup.c 2004-10-18 14:55:55 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,464 +0,0 @@ -/* - * linux/arch/ppc/kernel/setup.c - * - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * Modified by PPC64 Team, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * bootup setup stuff.. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "i8259.h" -#include "open_pic.h" -#include -#include -#include - -void chrp_progress(char *, unsigned short); - -extern void pSeries_init_openpic(void); - -extern void find_and_init_phbs(void); -extern void pSeries_final_fixup(void); - -extern void pSeries_get_boot_time(struct rtc_time *rtc_time); -extern void pSeries_get_rtc_time(struct rtc_time *rtc_time); -extern int pSeries_set_rtc_time(struct rtc_time *rtc_time); -void pSeries_calibrate_decr(void); -void fwnmi_init(void); -extern void SystemReset_FWNMI(void), MachineCheck_FWNMI(void); /* from head.S */ -int fwnmi_active; /* TRUE if an FWNMI handler is present */ - -dev_t boot_dev; -unsigned long virtPython0Facilities = 0; // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address. - -extern unsigned long loops_per_jiffy; - -extern unsigned long ppc_proc_freq; -extern unsigned long ppc_tb_freq; - -void chrp_get_cpuinfo(struct seq_file *m) -{ - struct device_node *root; - const char *model = ""; - - root = of_find_node_by_path("/"); - if (root) - model = get_property(root, "model", NULL); - seq_printf(m, "machine\t\t: CHRP %s\n", model); - of_node_put(root); -} - -#define I8042_DATA_REG 0x60 - -void __init chrp_request_regions(void) -{ - struct device_node *i8042; - - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); - - /* - * Some machines have an unterminated i8042 so check the device - * tree and reserve the region if it does not appear. Later on - * the i8042 code will try and reserve this region and fail. - */ - if (!(i8042 = of_find_node_by_type(NULL, "8042"))) - request_region(I8042_DATA_REG, 16, "reserved (no i8042)"); - of_node_put(i8042); -} - -void __init -chrp_setup_arch(void) -{ - struct device_node *root; - unsigned int *opprop; - - /* openpic global configuration register (64-bit format). */ - /* openpic Interrupt Source Unit pointer (64-bit format). */ - /* python0 facility area (mmio) (64-bit format) REAL address. */ - - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/sda2\n"); - ROOT_DEV = Root_SDA2; - } - - printk("Boot arguments: %s\n", cmd_line); - - fwnmi_init(); - -#ifndef CONFIG_PPC_ISERIES - /* Find and initialize PCI host bridges */ - /* iSeries needs to be done much later. */ - eeh_init(); - find_and_init_phbs(); -#endif - - /* Find the Open PIC if present */ - root = of_find_node_by_path("/"); - opprop = (unsigned int *) get_property(root, - "platform-open-pic", NULL); - if (opprop != 0) { - int n = prom_n_addr_cells(root); - unsigned long openpic; - - for (openpic = 0; n > 0; --n) - openpic = (openpic << 32) + *opprop++; - printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic); - OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE); - } - of_node_put(root); - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - -#ifdef CONFIG_PPC_PSERIES - pSeries_nvram_init(); -#endif -} - -void __init -chrp_init2(void) -{ - /* Manually leave the kernel version on the panel. */ - ppc_md.progress("Linux ppc64\n", 0); - ppc_md.progress(UTS_RELEASE, 0); -} - -/* Initialize firmware assisted non-maskable interrupts if - * the firmware supports this feature. - * - */ -void __init fwnmi_init(void) -{ - int ret; - int ibm_nmi_register = rtas_token("ibm,nmi-register"); - if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE) - return; - ret = rtas_call(ibm_nmi_register, 2, 1, NULL, - __pa((unsigned long)SystemReset_FWNMI), - __pa((unsigned long)MachineCheck_FWNMI)); - if (ret == 0) - fwnmi_active = 1; -} - -/* Early initialization. Relocation is on but do not reference unbolted pages */ -void __init pSeries_init_early(void) -{ - void *comport; - - hpte_init_pSeries(); - - if (ppc64_iommu_off) - pci_dma_init_direct(); - else - tce_init_pSeries(); - -#ifdef CONFIG_SMP - smp_init_pSeries(); -#endif - - /* Map the uart for udbg. */ - comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE); - udbg_init_uart(comport); - - ppc_md.udbg_putc = udbg_putc; - ppc_md.udbg_getc = udbg_getc; - ppc_md.udbg_getc_poll = udbg_getc_poll; -} - -void __init -chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - struct device_node * dn; - char * hypertas; - unsigned int len; - - ppc_md.setup_arch = chrp_setup_arch; - ppc_md.get_cpuinfo = chrp_get_cpuinfo; - if (naca->interrupt_controller == IC_OPEN_PIC) { - ppc_md.init_IRQ = pSeries_init_openpic; - ppc_md.get_irq = openpic_get_irq; - } else { - ppc_md.init_IRQ = xics_init_IRQ; - ppc_md.get_irq = xics_get_irq; - } - - ppc_md.log_error = pSeries_log_error; - - ppc_md.init = chrp_init2; - - ppc_md.pcibios_fixup = pSeries_final_fixup; - - ppc_md.restart = rtas_restart; - ppc_md.power_off = rtas_power_off; - ppc_md.halt = rtas_halt; - ppc_md.panic = rtas_os_term; - - ppc_md.get_boot_time = pSeries_get_boot_time; - ppc_md.get_rtc_time = pSeries_get_rtc_time; - ppc_md.set_rtc_time = pSeries_set_rtc_time; - ppc_md.calibrate_decr = pSeries_calibrate_decr; - - ppc_md.progress = chrp_progress; - - /* Build up the firmware_features bitmask field - * using contents of device-tree/ibm,hypertas-functions. - * Ultimately this functionality may be moved into prom.c prom_init(). - */ - cur_cpu_spec->firmware_features = 0; - dn = of_find_node_by_path("/rtas"); - if (dn == NULL) { - printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n"); - goto no_rtas; - } - - hypertas = get_property(dn, "ibm,hypertas-functions", &len); - if (hypertas) { - while (len > 0){ - int i, hypertas_len; - /* check value against table of strings */ - for(i=0; i < FIRMWARE_MAX_FEATURES ;i++) { - if ((firmware_features_table[i].name) && - (strcmp(firmware_features_table[i].name,hypertas))==0) { - /* we have a match */ - cur_cpu_spec->firmware_features |= - (firmware_features_table[i].val); - break; - } - } - hypertas_len = strlen(hypertas); - len -= hypertas_len +1; - hypertas+= hypertas_len +1; - } - } - - of_node_put(dn); - no_rtas: - printk(KERN_INFO "firmware_features = 0x%lx\n", - cur_cpu_spec->firmware_features); -} - -void chrp_progress(char *s, unsigned short hex) -{ - struct device_node *root; - int width, *p; - char *os; - static int display_character, set_indicator; - static int max_width; - static spinlock_t progress_lock = SPIN_LOCK_UNLOCKED; - static int pending_newline = 0; /* did last write end with unprinted newline? */ - - if (!rtas.base) - return; - - if (max_width == 0) { - if ((root = find_path_device("/rtas")) && - (p = (unsigned int *)get_property(root, - "ibm,display-line-length", - NULL))) - max_width = *p; - else - max_width = 0x10; - display_character = rtas_token("display-character"); - set_indicator = rtas_token("set-indicator"); - } - - if (display_character == RTAS_UNKNOWN_SERVICE) { - /* use hex display if available */ - if (set_indicator != RTAS_UNKNOWN_SERVICE) - rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); - return; - } - - spin_lock(&progress_lock); - - /* - * Last write ended with newline, but we didn't print it since - * it would just clear the bottom line of output. Print it now - * instead. - * - * If no newline is pending, print a CR to start output at the - * beginning of the line. - */ - if (pending_newline) { - rtas_call(display_character, 1, 1, NULL, '\r'); - rtas_call(display_character, 1, 1, NULL, '\n'); - pending_newline = 0; - } else { - rtas_call(display_character, 1, 1, NULL, '\r'); - } - - width = max_width; - os = s; - while (*os) { - if (*os == '\n' || *os == '\r') { - /* Blank to end of line. */ - while (width-- > 0) - rtas_call(display_character, 1, 1, NULL, ' '); - - /* If newline is the last character, save it - * until next call to avoid bumping up the - * display output. - */ - if (*os == '\n' && !os[1]) { - pending_newline = 1; - spin_unlock(&progress_lock); - return; - } - - /* RTAS wants CR-LF, not just LF */ - - if (*os == '\n') { - rtas_call(display_character, 1, 1, NULL, '\r'); - rtas_call(display_character, 1, 1, NULL, '\n'); - } else { - /* CR might be used to re-draw a line, so we'll - * leave it alone and not add LF. - */ - rtas_call(display_character, 1, 1, NULL, *os); - } - - width = max_width; - } else { - width--; - rtas_call(display_character, 1, 1, NULL, *os); - } - - os++; - - /* if we overwrite the screen length */ - if (width <= 0) - while ((*os != 0) && (*os != '\n') && (*os != '\r')) - os++; - } - - /* Blank to end of line. */ - while (width-- > 0) - rtas_call(display_character, 1, 1, NULL, ' '); - - spin_unlock(&progress_lock); -} - -extern void setup_default_decr(void); - -/* Some sane defaults: 125 MHz timebase, 1GHz processor */ -#define DEFAULT_TB_FREQ 125000000UL -#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) - -void __init pSeries_calibrate_decr(void) -{ - struct device_node *cpu; - struct div_result divres; - unsigned int *fp; - int node_found; - - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - cpu = of_find_node_by_type(NULL, "cpu"); - - ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */ - node_found = 0; - if (cpu != 0) { - fp = (unsigned int *)get_property(cpu, "timebase-frequency", - NULL); - if (fp != 0) { - node_found = 1; - ppc_tb_freq = *fp; - } - } - if (!node_found) - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - - ppc_proc_freq = DEFAULT_PROC_FREQ; - node_found = 0; - if (cpu != 0) { - fp = (unsigned int *)get_property(cpu, "clock-frequency", - NULL); - if (fp != 0) { - node_found = 1; - ppc_proc_freq = *fp; - } - } - if (!node_found) - printk(KERN_ERR "WARNING: Estimating processor frequency " - "(not found)\n"); - - of_node_put(cpu); - - printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", - ppc_tb_freq/1000000, ppc_tb_freq%1000000); - printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", - ppc_proc_freq/1000000, ppc_proc_freq%1000000); - - tb_ticks_per_jiffy = ppc_tb_freq / HZ; - tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; - tb_ticks_per_usec = ppc_tb_freq / 1000000; - tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); - div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); - tb_to_xs = divres.result_low; - - setup_default_decr(); -} diff -Nru a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c --- a/arch/ppc64/kernel/eeh.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/kernel/eeh.c 2004-10-18 14:56:33 -07:00 @@ -48,9 +48,6 @@ static int ibm_slot_error_detail; static int eeh_subsystem_enabled; -#define EEH_MAX_OPTS 4096 -static char *eeh_opts; -static int eeh_opts_last; /* Buffer for reporting slot-error-detail rtas calls */ static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; @@ -62,10 +59,6 @@ static DEFINE_PER_CPU(unsigned long, false_positives); static DEFINE_PER_CPU(unsigned long, ignored_failures); -static int eeh_check_opts_config(struct device_node *dn, int class_code, - int vendor_id, int device_id, - int default_state); - /** * The pci address cache subsystem. This subsystem places * PCI device address resources into a red-black tree, sorted @@ -209,6 +202,7 @@ { struct device_node *dn; int i; + int inserted = 0; dn = pci_device_to_OF_node(dev); if (!dn) { @@ -242,7 +236,12 @@ if (start == 0 || ~start == 0 || end == 0 || ~end == 0) continue; pci_addr_cache_insert(dev, start, end, flags); + inserted = 1; } + + /* If there was nothing to add, the cache has no reference... */ + if (!inserted) + pci_dev_put(dev); } /** @@ -265,6 +264,7 @@ static inline void __pci_addr_cache_remove_device(struct pci_dev *dev) { struct rb_node *n; + int removed = 0; restart: n = rb_first(&pci_io_addr_cache_root.rb_root); @@ -274,6 +274,7 @@ if (piar->pcidev == dev) { rb_erase(n, &pci_io_addr_cache_root.rb_root); + removed = 1; kfree(piar); goto restart; } @@ -281,7 +282,8 @@ } /* The cache no longer holds its reference to this device... */ - pci_dev_put(dev); + if (removed) + pci_dev_put(dev); } /** @@ -333,47 +335,38 @@ /** * eeh_token_to_phys - convert EEH address token to phys address - * @token i/o token, should be address in the form 0xA.... - * - * Converts EEH address tokens into physical addresses. Note that - * ths routine does *not* convert I/O BAR addresses (which start - * with 0xE...) to phys addresses! + * @token i/o token, should be address in the form 0xE.... */ -static unsigned long eeh_token_to_phys(unsigned long token) +static inline unsigned long eeh_token_to_phys(unsigned long token) { pte_t *ptep; - unsigned long pa, vaddr; + unsigned long pa; - if (REGION_ID(token) == EEH_REGION_ID) - vaddr = IO_TOKEN_TO_ADDR(token); - else + ptep = find_linux_pte(ioremap_mm.pgd, token); + if (!ptep) return token; - - ptep = find_linux_pte(ioremap_mm.pgd, vaddr); pa = pte_pfn(*ptep) << PAGE_SHIFT; - return pa | (vaddr & (PAGE_SIZE-1)); + return pa | (token & (PAGE_SIZE-1)); } /** - * eeh_check_failure - check if all 1's data is due to EEH slot freeze - * @token i/o token, should be address in the form 0xA.... - * @val value, should be all 1's (XXX why do we need this arg??) + * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze + * @dn device node + * @dev pci device, if known * - * Check for an eeh failure at the given token address. - * The given value has been read and it should be 1's (0xff, 0xffff or - * 0xffffffff). + * Check for an EEH failure for the given device node. Call this + * routine if the result of a read was all 0xff's and you want to + * find out if this is due to an EEH slot freeze event. This routine + * will query firmware for the EEH status. * - * Probe to determine if an error actually occurred. If not return val. - * Otherwise panic. + * Returns 0 if there has not been an EEH error; otherwise returns + * an error code. * - * Note this routine might be called in an interrupt context ... + * It is safe to call this routine in an interrupt context. */ -unsigned long eeh_check_failure(void *token, unsigned long val) +int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) { - unsigned long addr; - struct pci_dev *dev; - struct device_node *dn; int ret; int rets[2]; unsigned long flags; @@ -381,30 +374,19 @@ __get_cpu_var(total_mmio_ffs)++; if (!eeh_subsystem_enabled) - return val; + return 0; - /* Finding the phys addr + pci device; this is pretty quick. */ - addr = eeh_token_to_phys((unsigned long)token); - dev = pci_get_device_by_addr(addr); - if (!dev) - return val; - - dn = pci_device_to_OF_node(dev); - if (!dn) { - pci_dev_put(dev); - return val; - } + if (!dn) + return 0; /* Access to IO BARs might get this far and still not want checking. */ if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK) { - pci_dev_put(dev); - return val; + return 0; } if (!dn->eeh_config_addr) { - pci_dev_put(dev); - return val; + return 0; } /* @@ -418,7 +400,7 @@ dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid)); - if (ret == 0 && rets[1] == 1 && rets[0] >= 2) { + if (ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4)) { int log_event; spin_lock_irqsave(&slot_errbuf_lock, flags); @@ -430,7 +412,7 @@ BUID_LO(dn->phb->buid), NULL, 0, virt_to_phys(slot_errbuf), eeh_error_buf_size, - 2 /* Permanent Error */); + 1 /* Temporary Error */); if (log_event == 0) log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, @@ -438,6 +420,10 @@ spin_unlock_irqrestore(&slot_errbuf_lock, flags); + printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n", + rets[0], dn->name, dn->full_name); + WARN_ON(1); + /* * XXX We should create a separate sysctl for this. * @@ -446,26 +432,57 @@ * can use it here. */ if (panic_on_oops) { - panic("EEH: MMIO failure (%d) on device:%s %s\n", - rets[0], pci_name(dev), pci_pretty_name(dev)); + panic("EEH: MMIO failure (%d) on device: %s %s\n", + rets[0], dn->name, dn->full_name); } else { __get_cpu_var(ignored_failures)++; - printk(KERN_INFO "EEH: MMIO failure (%d) on device:%s %s\n", - rets[0], pci_name(dev), pci_pretty_name(dev)); } } else { __get_cpu_var(false_positives)++; } + return 0; +} + +EXPORT_SYMBOL(eeh_dn_check_failure); + +/** + * eeh_check_failure - check if all 1's data is due to EEH slot freeze + * @token i/o token, should be address in the form 0xA.... + * @val value, should be all 1's (XXX why do we need this arg??) + * + * Check for an eeh failure at the given token address. + * Check for an EEH failure at the given token address. Call this + * routine if the result of a read was all 0xff's and you want to + * find out if this is due to an EEH slot freeze event. This routine + * will query firmware for the EEH status. + * + * Note this routine is safe to call in an interrupt context. + */ +unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) +{ + unsigned long addr; + struct pci_dev *dev; + struct device_node *dn; + + /* Finding the phys addr + pci device; this is pretty quick. */ + addr = eeh_token_to_phys((unsigned long __force) token); + dev = pci_get_device_by_addr(addr); + if (!dev) + return val; + + dn = pci_device_to_OF_node(dev); + eeh_dn_check_failure (dn, dev); + pci_dev_put(dev); return val; } + EXPORT_SYMBOL(eeh_check_failure); struct eeh_early_enable_info { unsigned int buid_hi; unsigned int buid_lo; - int force_off; }; /* Enable eeh for the given device node. */ @@ -507,18 +524,8 @@ if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY) enable = 0; - if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id, - enable)) { - if (enable) { - printk(KERN_WARNING "EEH: %s user requested to run " - "without EEH checking.\n", dn->full_name); - enable = 0; - } - } - - if (!enable || info->force_off) { + if (!enable) dn->eeh_mode |= EEH_MODE_NOCHECK; - } /* Ok... see if this device supports EEH. Some do, some don't, * and the only way to find out is to check each and every one. */ @@ -572,15 +579,12 @@ { struct device_node *phb, *np; struct eeh_early_enable_info info; - char *eeh_force_off = strstr(saved_command_line, "eeh-force-off"); init_pci_config_tokens(); np = of_find_node_by_path("/rtas"); - if (np == NULL) { - printk(KERN_WARNING "EEH: RTAS not found !\n"); + if (np == NULL) return; - } ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); @@ -600,13 +604,6 @@ eeh_error_buf_size = RTAS_ERROR_LOG_MAX; } - info.force_off = 0; - if (eeh_force_off) { - printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error " - "Handling is user disabled\n"); - info.force_off = 1; - } - /* Enable EEH for all adapters. Note that eeh requires buid's */ for (phb = of_find_node_by_name(NULL, "pci"); phb; phb = of_find_node_by_name(phb, "pci")) { @@ -621,11 +618,10 @@ traverse_pci_devices(phb, early_enable_eeh, &info); } - if (eeh_subsystem_enabled) { + if (eeh_subsystem_enabled) printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n"); - } else { - printk(KERN_WARNING "EEH: disabled PCI Enhanced I/O Error Handling\n"); - } + else + printk(KERN_WARNING "EEH: No capable adapters found\n"); } /** @@ -701,39 +697,6 @@ } EXPORT_SYMBOL(eeh_remove_device); -/* - * If EEH is implemented, find the PCI device using given phys addr - * and check to see if eeh failure checking is disabled. - * Remap the addr (trivially) to the EEH region if EEH checking enabled. - * For addresses not known to PCI the vaddr is simply returned unchanged. - */ -void *eeh_ioremap(unsigned long addr, void *vaddr) -{ - struct pci_dev *dev; - struct device_node *dn; - - if (!eeh_subsystem_enabled) - return vaddr; - - dev = pci_get_device_by_addr(addr); - if (!dev) - return vaddr; - - dn = pci_device_to_OF_node(dev); - if (!dn) { - pci_dev_put(dev); - return vaddr; - } - - if (dn->eeh_mode & EEH_MODE_NOCHECK) { - pci_dev_put(dev); - return vaddr; - } - - pci_dev_put(dev); - return (void *)IO_ADDR_TO_TOKEN(vaddr); -} - static int proc_eeh_show(struct seq_file *m, void *v) { unsigned int cpu; @@ -784,129 +747,3 @@ return 0; } __initcall(eeh_init_proc); - -/* - * Test if "dev" should be configured on or off. - * This processes the options literally from left to right. - * This lets the user specify stupid combinations of options, - * but at least the result should be very predictable. - */ -static int eeh_check_opts_config(struct device_node *dn, - int class_code, int vendor_id, int device_id, - int default_state) -{ - char devname[32], classname[32]; - char *strs[8], *s; - int nstrs, i; - int ret = default_state; - - /* Build list of strings to match */ - nstrs = 0; - s = (char *)get_property(dn, "ibm,loc-code", NULL); - if (s) - strs[nstrs++] = s; - sprintf(devname, "dev%04x:%04x", vendor_id, device_id); - strs[nstrs++] = devname; - sprintf(classname, "class%04x", class_code); - strs[nstrs++] = classname; - strs[nstrs++] = ""; /* yes, this matches the empty string */ - - /* - * Now see if any string matches the eeh_opts list. - * The eeh_opts list entries start with + or -. - */ - for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); - s += strlen(s)+1) { - for (i = 0; i < nstrs; i++) { - if (strcasecmp(strs[i], s+1) == 0) { - ret = (strs[i][0] == '+') ? 1 : 0; - } - } - } - return ret; -} - -/* - * Handle kernel eeh-on & eeh-off cmd line options for eeh. - * - * We support: - * eeh-off=loc1,loc2,loc3... - * - * and this option can be repeated so - * eeh-off=loc1,loc2 eeh-off=loc3 - * is the same as eeh-off=loc1,loc2,loc3 - * - * loc is an IBM location code that can be found in a manual or - * via openfirmware (or the Hardware Management Console). - * - * We also support these additional "loc" values: - * - * dev#:# vendor:device id in hex (e.g. dev1022:2000) - * class# class id in hex (e.g. class0200) - * - * If no location code is specified all devices are assumed - * so eeh-off means eeh by default is off. - */ - -/* - * This is implemented as a null separated list of strings. - * Each string looks like this: "+X" or "-X" - * where X is a loc code, vendor:device, class (as shown above) - * or empty which is used to indicate all. - * - * We interpret this option string list so that it will literally - * behave left-to-right even if some combinations don't make sense. - */ -static int __init eeh_parm(char *str, int state) -{ - char *s, *cur, *curend; - - if (!eeh_opts) { - eeh_opts = alloc_bootmem(EEH_MAX_OPTS); - eeh_opts[eeh_opts_last++] = '+'; /* default */ - eeh_opts[eeh_opts_last++] = '\0'; - } - if (*str == '\0') { - eeh_opts[eeh_opts_last++] = state ? '+' : '-'; - eeh_opts[eeh_opts_last++] = '\0'; - return 1; - } - if (*str == '=') - str++; - for (s = str; s && *s != '\0'; s = curend) { - cur = s; - /* ignore empties. Don't treat as "all-on" or "all-off" */ - while (*cur == ',') - cur++; - curend = strchr(cur, ','); - if (!curend) - curend = cur + strlen(cur); - if (*cur) { - int curlen = curend-cur; - if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) { - printk(KERN_WARNING "EEH: sorry...too many " - "eeh cmd line options\n"); - return 1; - } - eeh_opts[eeh_opts_last++] = state ? '+' : '-'; - strncpy(eeh_opts+eeh_opts_last, cur, curlen); - eeh_opts_last += curlen; - eeh_opts[eeh_opts_last++] = '\0'; - } - } - - return 1; -} - -static int __init eehoff_parm(char *str) -{ - return eeh_parm(str, 0); -} - -static int __init eehon_parm(char *str) -{ - return eeh_parm(str, 1); -} - -__setup("eeh-off", eehoff_parm); -__setup("eeh-on", eehon_parm); diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S --- a/arch/ppc64/kernel/entry.S 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc64/kernel/entry.S 2004-10-18 14:55:54 -07:00 @@ -122,7 +122,7 @@ andi. r11,r10,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace syscall_dotrace_cont: - cmpli 0,r0,NR_syscalls + cmpldi 0,r0,NR_syscalls bge- syscall_enosys system_call: /* label this so stack traces look sane */ @@ -204,7 +204,7 @@ syscall_error: lbz r11,TI_SC_NOERR(r12) - cmpi 0,r11,0 + cmpwi 0,r11,0 bne- syscall_error_cont neg r3,r3 oris r5,r5,0x1000 /* Set SO bit in CR */ @@ -393,9 +393,17 @@ cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ cror eq,4*cr1+eq,eq beq 2f /* if yes, don't slbie it */ - oris r6,r6,0x0800 /* set C (class) bit */ - slbie r6 - slbie r6 /* Workaround POWER5 < DD2.1 issue */ + oris r0,r6,0x0800 /* set C (class) bit */ + + /* Bolt in the new stack SLB entry */ + ld r7,KSP_VSID(r4) /* Get new stack's VSID */ + oris r6,r6,(SLB_ESID_V)@h + ori r6,r6,(SLB_NUM_BOLTED-1)@l + slbie r0 + slbie r0 /* Workaround POWER5 < DD2.1 issue */ + slbmte r7,r6 + isync + 2: END_FTR_SECTION_IFSET(CPU_FTR_SLB) clrrdi r7,r8,THREAD_SHIFT /* base of new stack */ @@ -738,6 +746,10 @@ mtlr r0 blr /* return to caller */ +#endif /* CONFIG_PPC_PSERIES */ + +#ifdef CONFIG_PPC_MULTIPLATFORM + _GLOBAL(enter_prom) mflr r0 std r0,16(r1) @@ -769,11 +781,8 @@ std r11,_MSR(r1) /* Get the PROM entrypoint */ - bl .reloc_offset - LOADADDR(r12,prom) - sub r12,r12,r3 - ld r12,PROMENTRY(r12) - mtlr r12 + ld r0,GPR4(r1) + mtlr r0 /* Switch MSR to 32 bits mode */ @@ -826,4 +835,4 @@ mtlr r0 blr -#endif /* defined(CONFIG_PPC_PSERIES) */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S --- a/arch/ppc64/kernel/head.S 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/kernel/head.S 2004-10-18 14:56:32 -07:00 @@ -83,13 +83,14 @@ .text .globl _stext _stext: -#ifdef CONFIG_PPC_PSERIES -_STATIC(__start) +#ifdef CONFIG_PPC_MULTIPLATFORM +_GLOBAL(__start) /* NOP this out unconditionally */ BEGIN_FTR_SECTION - b .__start_initialization_pSeries + b .__start_initialization_multiplatform END_FTR_SECTION(0, 1) -#endif +#endif /* CONFIG_PPC_MULTIPLATFORM */ + /* Catch branch to 0 in real mode */ trap #ifdef CONFIG_PPC_ISERIES @@ -117,7 +118,8 @@ .globl embedded_sysmap_end embedded_sysmap_end: .llong 0 -#else + +#else /* CONFIG_PPC_ISERIES */ /* Secondary processors spin on this value until it goes to 1. */ .globl __secondary_hold_spinloop @@ -199,6 +201,7 @@ #define EX_R12 24 #define EX_R13 32 #define EX_SRR0 40 +#define EX_R3 40 /* SLB miss saves R3, but not SRR0 */ #define EX_DAR 48 #define EX_LR 48 /* SLB miss saves LR, but not DAR */ #define EX_DSISR 56 @@ -322,36 +325,11 @@ HMT_MEDIUM; \ mtspr SPRG1,r13; /* save r13 */ \ EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ - lbz r10,PACAPROFENABLED(r13); \ - cmpwi r10,0; \ - bne- label##_Iseries_profile; \ -label##_Iseries_prof_ret: \ lbz r10,PACAPROCENABLED(r13); \ cmpwi 0,r10,0; \ beq- label##_Iseries_masked; \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common; \ -label##_Iseries_profile: \ - ld r12,PACALPPACA+LPPACASRR1(r13); \ - andi. r12,r12,MSR_PR; /* Test if in kernel */ \ - bne label##_Iseries_prof_ret; \ - ld r11,PACALPPACA+LPPACASRR0(r13); \ - ld r12,PACAPROFSTEXT(r13); /* _stext */ \ - subf r11,r12,r11; /* offset into kernel */ \ - lwz r12,PACAPROFSHIFT(r13); \ - srd r11,r11,r12; \ - lwz r12,PACAPROFLEN(r13); /* profile table length - 1 */ \ - cmpd r11,r12; /* off end? */ \ - ble 1f; \ - mr r11,r12; /* force into last entry */ \ -1: sldi r11,r11,2; /* convert to offset */ \ - ld r12,PACAPROFBUFFER(r13);/* profile buffer */ \ - add r12,r12,r11; \ -2: lwarx r11,0,r12; /* atomically increment */ \ - addi r11,r11,1; \ - stwcx. r11,0,r12; \ - bne- 2b; \ - b label##_Iseries_prof_ret #ifdef DO_SOFT_DISABLE #define DISABLE_INTS \ @@ -446,21 +424,13 @@ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - std r3,PACASLBR3(r13) + std r3,PACA_EXSLB+EX_R3(r13) mfspr r9,SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - clrrdi r12,r13,32 /* get high part of &label */ - mfmsr r10 - mfspr r11,SRR0 /* save SRR0 */ - ori r12,r12,(.do_slb_miss)@l - ori r10,r10,MSR_IR|MSR_DR /* DON'T set RI for SLB miss */ - mtspr SRR0,r12 mfspr r12,SRR1 /* and SRR1 */ - mtspr SRR1,r10 mfspr r3,DAR - rfid - b . /* prevent speculative execution */ + b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x400, InstructionAccess) @@ -474,21 +444,13 @@ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - std r3,PACASLBR3(r13) + std r3,PACA_EXSLB+EX_R3(r13) mfspr r9,SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - clrrdi r12,r13,32 /* get high part of &label */ - mfmsr r10 - mfspr r11,SRR0 /* save SRR0 */ - ori r12,r12,(.do_slb_miss)@l - ori r10,r10,MSR_IR|MSR_DR /* DON'T set RI for SLB miss */ - mtspr SRR0,r12 mfspr r12,SRR1 /* and SRR1 */ - mtspr SRR1,r10 - mr r3,r11 /* SRR0 is faulting address */ - rfid - b . /* prevent speculative execution */ + mfspr r3,SRR0 /* SRR0 is faulting address */ + b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x500, HardwareInterrupt) STD_EXCEPTION_PSERIES(0x600, Alignment) @@ -580,7 +542,7 @@ * VSID generation algorithm. See include/asm/mmu_context.h. */ - .llong 1 /* # ESIDs to be mapped by hypervisor */ + .llong 2 /* # ESIDs to be mapped by hypervisor */ .llong 1 /* # memory ranges to be mapped by hypervisor */ .llong STAB0_PAGE /* Page # of segment table within load area */ .llong 0 /* Reserved */ @@ -588,11 +550,15 @@ .llong 0 /* Reserved */ .llong 0 /* Reserved */ .llong 0 /* Reserved */ - .llong 0x0c00000000 /* ESID to map (Kernel at EA = 0xC000000000000000) */ - .llong 0x06a99b4b14 /* VSID to map (Kernel at VA = 0x6a99b4b140000000) */ + .llong (KERNELBASE>>SID_SHIFT) + .llong 0x408f92c94 /* KERNELBASE VSID */ + /* We have to list the bolted VMALLOC segment here, too, so that it + * will be restored on shared processor switch */ + .llong (VMALLOCBASE>>SID_SHIFT) + .llong 0xf09b89af5 /* VMALLOCBASE VSID */ .llong 8192 /* # pages to map (32 MB) */ .llong 0 /* Offset from start of loadarea to start of map */ - .llong 0x0006a99b4b140000 /* VPN of first page to map */ + .llong 0x408f92c940000 /* VPN of first page to map */ . = 0x6100 @@ -630,8 +596,7 @@ DataAccessSLB_Iseries: mtspr SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - std r3,PACASLBR3(r13) - ld r11,PACALPPACA+LPPACASRR0(r13) + std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) mfspr r3,DAR b .do_slb_miss @@ -642,10 +607,9 @@ InstructionAccessSLB_Iseries: mtspr SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - std r3,PACASLBR3(r13) - ld r11,PACALPPACA+LPPACASRR0(r13) + std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) - mr r3,r11 + ld r3,PACALPPACA+LPPACASRR0(r13) b .do_slb_miss MASKABLE_EXCEPTION_ISERIES(0x500, HardwareInterrupt) @@ -1033,6 +997,9 @@ * interrupts if necessary. */ beq .ret_from_except_lite + /* For a hash failure, we don't bother re-enabling interrupts */ + ble- 12f + /* * hash_page couldn't handle it, set soft interrupt enable back * to what it was before the trap. Note that .local_irq_restore @@ -1043,6 +1010,8 @@ b 11f #else beq fast_exception_return /* Return from exception on success */ + ble- 12f /* Failure return from hash_page */ + /* fall through */ #endif @@ -1062,6 +1031,15 @@ bl .bad_page_fault b .ret_from_except +/* We have a page fault that hash_page could handle but HV refused + * the PTE insertion + */ +12: bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + lwz r4,_DAR(r1) + bl .low_hash_fault + b .ret_from_except + /* here we have a segment miss */ _GLOBAL(do_ste_alloc) bl .ste_allocate /* try to insert stab entry */ @@ -1088,18 +1066,9 @@ rldimi r10,r11,7,52 /* r10 = first ste of the group */ /* Calculate VSID */ - /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */ - rldic r11,r11,15,36 - ori r11,r11,0xc - - /* VSID_RANDOMIZER */ - li r9,9 - sldi r9,r9,32 - oris r9,r9,58231 - ori r9,r9,39831 - - mulld r9,r11,r9 - rldic r9,r9,12,16 /* r9 = vsid << 12 */ + /* This is a kernel address, so protovsid = ESID */ + ASM_VSID_SCRAMBLE(r11, r9) + rldic r9,r11,12,16 /* r9 = vsid << 12 */ /* Search the primary group for a free entry */ 1: ld r11,0(r10) /* Test valid bit of the current ste */ @@ -1176,7 +1145,6 @@ mflr r10 stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */ std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ bl .slb_allocate /* handle it */ @@ -1184,9 +1152,11 @@ /* All done -- return from exception. */ ld r10,PACA_EXSLB+EX_LR(r13) - ld r3,PACASLBR3(r13) + ld r3,PACA_EXSLB+EX_R3(r13) lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ - ld r11,PACA_EXSLB+EX_SRR0(r13) /* get saved SRR0 */ +#ifdef CONFIG_PPC_ISERIES + ld r11,PACALPPACA+LPPACASRR0(r13) /* get SRR0 value */ +#endif /* CONFIG_PPC_ISERIES */ mtlr r10 @@ -1199,8 +1169,10 @@ mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ .machine pop +#ifdef CONFIG_PPC_ISERIES mtspr SRR0,r11 mtspr SRR1,r12 +#endif /* CONFIG_PPC_ISERIES */ ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) ld r11,PACA_EXSLB+EX_R11(r13) @@ -1253,12 +1225,10 @@ #endif b 1b /* Loop until told to go */ #ifdef CONFIG_PPC_ISERIES -_GLOBAL(__start_initialization_iSeries) +_STATIC(__start_initialization_iSeries) /* Clear out the BSS */ LOADADDR(r11,__bss_stop) - LOADADDR(r8,__bss_start) - sub r11,r11,r8 /* bss size */ addi r11,r11,7 /* round up to an even double word */ rldicl. r11,r11,61,3 /* shift right by 3 */ @@ -1295,32 +1265,73 @@ ld r6,PACA(r4) /* Get the base paca pointer */ ld r4,PACASTABVIRT(r6) - bl .iSeries_fixup_klimit + bl .iSeries_early_setup /* relocation is on at this point */ b .start_here_common -#endif +#endif /* CONFIG_PPC_ISERIES */ -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM -_STATIC(mmu_off) +_STATIC(__mmu_off) mfmsr r3 andi. r0,r3,MSR_IR|MSR_DR beqlr andc r3,r3,r0 - mtspr SRR0,r4 - mtspr SRR1,r3 + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 sync rfid b . /* prevent speculative execution */ -_GLOBAL(__start_initialization_pSeries) - mr r31,r3 /* save parameters */ + + +/* + * Here is our main kernel entry point. We support currently 2 kind of entries + * depending on the value of r5. + * + * r5 != NULL -> OF entry, we go to prom_init, "legacy" parameter content + * in r3...r7 + * + * r5 == NULL -> kexec style entry. r3 is a physical pointer to the + * DT block, r4 is a physical pointer to the kernel itself + * + */ +_GLOBAL(__start_initialization_multiplatform) + /* + * Are we booted from a PROM Of-type client-interface ? + */ + cmpldi cr0,r5,0 + bne .__boot_from_prom /* yes -> prom */ + + /* Save parameters */ + mr r31,r3 + mr r30,r4 + + /* Make sure we are running in 64 bits mode */ + bl .enable_64b_mode + + /* Setup some critical 970 SPRs before switching MMU off */ + bl .__970_cpu_preinit + + /* cpu # */ + li r24,0 + + /* Switch off MMU if not already */ + LOADADDR(r4, .__after_prom_start - KERNELBASE) + add r4,r4,r30 + bl .__mmu_off + b .__after_prom_start + +_STATIC(__boot_from_prom) + /* Save parameters */ + mr r31,r3 mr r30,r4 mr r29,r5 mr r28,r6 mr r27,r7 + /* Make sure we are running in 64 bits mode */ bl .enable_64b_mode /* put a relocation offset into r3 */ @@ -1333,7 +1344,7 @@ /* Relocate the TOC from a virt addr to a real addr */ sub r2,r2,r3 - /* Save parameters */ + /* Restore parameters */ mr r3,r31 mr r4,r30 mr r5,r29 @@ -1342,17 +1353,8 @@ /* Do all of the interaction with OF client interface */ bl .prom_init - mr r23,r3 /* Save phys address we are running at */ - - /* Setup some critical 970 SPRs before switching MMU off */ - bl .__970_cpu_preinit - - li r24,0 /* cpu # */ - - /* Switch off MMU if not already */ - LOADADDR(r4, .__after_prom_start - KERNELBASE) - add r4,r4,r23 - bl .mmu_off + /* We never return */ + trap /* * At this point, r3 contains the physical address we are running at, @@ -1378,7 +1380,7 @@ li r3,0 /* target addr */ - // XXX FIXME: Use phys returned by OF (r23) + // XXX FIXME: Use phys returned by OF (r30) sub r4,r27,r26 /* source addr */ /* current address of _start */ /* i.e. where we are running */ @@ -1403,8 +1405,9 @@ ld r5,0(r5) /* get the value of klimit */ sub r5,r5,r27 bl .copy_and_flush /* copy the rest */ - b .start_here_pSeries -#endif + b .start_here_multiplatform + +#endif /* CONFIG_PPC_MULTIPLATFORM */ /* * Copy routine used to copy the kernel to start at physical address 0 @@ -1609,6 +1612,7 @@ li r10,THREAD_VSCR stw r4,THREAD_USED_VR(r5) lvx vr0,r10,r5 + mtvscr vr0 REST_32VRS(0,r4,r5) #ifndef CONFIG_SMP /* Update last_task_used_math to 'current' */ @@ -1823,15 +1827,33 @@ isync blr -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM /* * This is where the main kernel code starts. */ -_STATIC(start_here_pSeries) +_STATIC(start_here_multiplatform) /* get a new offset, now that the kernel has moved. */ bl .reloc_offset mr r26,r3 + /* Clear out the BSS. It may have been done in prom_init, + * already but that's irrelevant since prom_init will soon + * be detached from the kernel completely. Besides, we need + * to clear it now for kexec-style entry. + */ + LOADADDR(r11,__bss_stop) + LOADADDR(r8,__bss_start) + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + mfmsr r6 ori r6,r6,MSR_RI mtmsrd r6 /* RI on */ @@ -1904,8 +1926,11 @@ mr r5,r26 bl .identify_cpu - /* Get the pointer to the segment table which is used by */ - /* stab_initialize */ + /* Setup a valid physical PACA pointer in SPRG3 for early_setup + * note that boot_cpuid can always be 0 nowadays since there is + * nowhere it can be initialized differently before we reach this + * code + */ LOADADDR(r27, boot_cpuid) sub r27,r27,r26 lwz r27,0(r27) @@ -1914,12 +1939,18 @@ mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ sub r13,r13,r26 /* convert to physical addr */ - mtspr SPRG3,r13 /* PPPBBB: Temp... -Peter */ - ld r3,PACASTABREAL(r13) - ori r4,r3,1 /* turn on valid bit */ + /* Do very early kernel initializations, including initial hash table, + * stab and slb setup before we turn on relocation. */ + + /* Restore parameters passed from prom_init/kexec */ + mr r3,r31 + bl .early_setup + /* set the ASR */ + ld r3,PACASTABREAL(r13) + ori r4,r3,1 /* turn on valid bit */ li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ cmpldi r3,PLATFORM_PSERIES_LPAR @@ -1938,13 +1969,7 @@ 98: /* !(rpa hypervisor) || !(star) */ mtasr r4 /* set the stab location */ 99: - mfspr r6,SPRG3 - ld r3,PACASTABREAL(r6) /* restore r3 for stab_initialize */ - - /* Initialize an initial memory mapping and turn on relocation. */ - bl .stab_initialize - bl .htab_initialize - + /* Set SDR1 (hash table pointer) */ li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ /* Test if bit 0 is set (LPAR bit) */ @@ -1961,7 +1986,7 @@ mtspr SRR1,r4 rfid b . /* prevent speculative execution */ -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ /* This is where all platforms converge execution */ _STATIC(start_here_common) @@ -2008,13 +2033,6 @@ /* Load the TOC */ ld r2,PACATOC(r13) std r1,PACAKSAVE(r13) - - /* Restore the parms passed in from the bootloader. */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 bl .setup_system diff -Nru a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c --- a/arch/ppc64/kernel/hvconsole.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/kernel/hvconsole.c 2004-10-18 14:56:32 -07:00 @@ -1,6 +1,10 @@ /* * hvconsole.c * Copyright (C) 2004 Hollis Blanchard, IBM Corporation + * Copyright (C) 2004 IBM Corporation + * + * Additional Author(s): + * Ryan S. Arnold * * LPAR console support. * @@ -22,14 +26,22 @@ #include #include #include -#include #include +#include -int hvc_get_chars(int index, char *buf, int count) +/** + * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper + * @vtermno: The vtermno or unit_address of the adapter from which to fetch the + * data. + * @buf: The character buffer into which to put the character data fetched from + * firmware. + * @count: not used? + */ +int hvc_get_chars(uint32_t vtermno, char *buf, int count) { unsigned long got; - if (plpar_hcall(H_GET_TERM_CHAR, index, 0, 0, 0, &got, + if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got, (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { /* * Work around a HV bug where it gives us a null @@ -53,40 +65,56 @@ EXPORT_SYMBOL(hvc_get_chars); -int hvc_put_chars(int index, const char *buf, int count) +/** + * hvc_put_chars: send characters to firmware for denoted vterm adapter + * @vtermno: The vtermno or unit_address of the adapter from which the data + * originated. + * @buf: The character buffer that contains the character data to send to + * firmware. + * @count: Send this number of characters. + */ +int hvc_put_chars(uint32_t vtermno, 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], + ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], lbuf[1]); if (ret == H_Success) return count; if (ret == H_Busy) return 0; - return -1; + return -EIO; } EXPORT_SYMBOL(hvc_put_chars); -/* return the number of client vterms present */ -/* XXX this requires an interface change to handle multiple discontiguous - * vterms */ -int hvc_count(int *start_termno) +/* + * We hope/assume that the first vty found corresponds to the first console + * device. + */ +int hvc_find_vtys(void) { 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", NULL); - - if (termno && start_termno) - *start_termno = *termno; - num_found = 1; - of_node_put(vty); + for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; + vty = of_find_node_by_name(vty, "vty")) { + uint32_t *vtermno; + + /* We have statically defined space for only a certain number of + * console adapters. */ + if (num_found >= MAX_NR_HVC_CONSOLES) + break; + + vtermno = (uint32_t *)get_property(vty, "reg", NULL); + if (!vtermno) + continue; + + if (device_is_compatible(vty, "hvterm1")) { + hvc_instantiate(*vtermno, num_found); + ++num_found; + } } return num_found; diff -Nru a/arch/ppc64/kernel/hvcserver.c b/arch/ppc64/kernel/hvcserver.c --- a/arch/ppc64/kernel/hvcserver.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/kernel/hvcserver.c 2004-10-18 14:56:33 -07:00 @@ -61,14 +61,21 @@ } } +/** + * hvcs_free_partner_info - free pi allocated by hvcs_get_partner_info + * @head: list_head pointer for an allocated list of partner info structs to + * free. + * + * This function is used to free the partner info list that was returned by + * calling hvcs_get_partner_info(). + */ int hvcs_free_partner_info(struct list_head *head) { struct hvcs_partner_info *pi; struct list_head *element; - if (!head) { + if (!head) return -EINVAL; - } while (!list_empty(head)) { element = head->next; @@ -82,7 +89,7 @@ EXPORT_SYMBOL(hvcs_free_partner_info); /* Helper function for hvcs_get_partner_info */ -int hvcs_next_partner(unsigned int unit_address, +int hvcs_next_partner(uint32_t unit_address, unsigned long last_p_partition_ID, unsigned long last_p_unit_address, unsigned long *pi_buff) @@ -94,25 +101,37 @@ return hvcs_convert(retval); } -/* - * The unit_address parameter is the unit address of the vty-server vdevice - * in whose partner information the caller is interested. This function - * uses a pointer to a list_head instance in which to store the partner info. +/** + * hvcs_get_partner_info - Get all of the partner info for a vty-server adapter + * @unit_address: The unit_address of the vty-server adapter for which this + * function is fetching partner info. + * @head: An initialized list_head pointer to an empty list to use to return the + * list of partner info fetched from the hypervisor to the caller. + * @pi_buff: A page sized buffer pre-allocated prior to calling this function + * that is to be used to be used by firmware as an iterator to keep track + * of the partner info retrieval. + * * This function returns non-zero on success, or if there is no partner info. * + * The pi_buff is pre-allocated prior to calling this function because this + * function may be called with a spin_lock held and kmalloc of a page is not + * recommended as GFP_ATOMIC. + * + * The first long of this buffer is used to store a partner unit address. The + * second long is used to store a partner partition ID and starting at + * pi_buff[2] is the 79 character Converged Location Code (diff size than the + * unsigned longs, hence the casting mumbo jumbo you see later). + * * Invocation of this function should always be followed by an invocation of * hvcs_free_partner_info() using a pointer to the SAME list head instance - * that was used to store the partner_info list. + * that was passed as a parameter to this function. */ -int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head, +int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head, unsigned long *pi_buff) { /* - * This is a page sized buffer to be passed to hvcall per invocation. - * NOTE: the first long returned is unit_address. The second long - * returned is the partition ID and starting with pi_buff[2] are - * HVCS_CLC_LENGTH characters, which are diff size than the unsigned - * long, hence the casting mumbojumbo you see later. + * Dealt with as longs because of the hcall interface even though the + * values are uint32_t. */ unsigned long last_p_partition_ID; unsigned long last_p_unit_address; @@ -122,15 +141,12 @@ memset(pi_buff, 0x00, PAGE_SIZE); /* invalid parameters */ - if (!head) + if (!head || !pi_buff) return -EINVAL; last_p_partition_ID = last_p_unit_address = ~0UL; INIT_LIST_HEAD(head); - if (!pi_buff) - return -ENOMEM; - do { retval = hvcs_next_partner(unit_address, last_p_partition_ID, last_p_unit_address, pi_buff); @@ -183,21 +199,29 @@ } EXPORT_SYMBOL(hvcs_get_partner_info); -/* +/** + * hvcs_register_connection - establish a connection between this vty-server and + * a vty. + * @unit_address: The unit address of the vty-server adapter that is to be + * establish a connection. + * @p_partition_ID: The partition ID of the vty adapter that is to be connected. + * @p_unit_address: The unit address of the vty adapter to which the vty-server + * is to be connected. + * * If this function is called once and -EINVAL is returned it may * indicate that the partner info needs to be refreshed for the * target unit address at which point the caller must invoke * hvcs_get_partner_info() and then call this function again. If, * for a second time, -EINVAL is returned then it indicates that * there is probably already a partner connection registered to a - * different vty-server@ vdevice. It is also possible that a second + * different vty-server adapter. It is also possible that a second * -EINVAL may indicate that one of the parms is not valid, for - * instance if the link was removed between the vty-server@ vdevice - * and the vty@ vdevice that you are trying to open. Don't shoot the + * instance if the link was removed between the vty-server adapter + * and the vty adapter that you are trying to open. Don't shoot the * messenger. Firmware implemented it this way. */ -int hvcs_register_connection( unsigned int unit_address, - unsigned int p_partition_ID, unsigned int p_unit_address) +int hvcs_register_connection( uint32_t unit_address, + uint32_t p_partition_ID, uint32_t p_unit_address) { long retval; retval = plpar_hcall_norets(H_REGISTER_VTERM, unit_address, @@ -206,11 +230,17 @@ } EXPORT_SYMBOL(hvcs_register_connection); -/* - * If -EBUSY is returned continue to call this function - * until 0 is returned. +/** + * hvcs_free_connection - free the connection between a vty-server and vty + * @unit_address: The unit address of the vty-server that is to have its + * connection severed. + * + * This function is used to free the partner connection between a vty-server + * adapter and a vty adapter. + * + * If -EBUSY is returned continue to call this function until 0 is returned. */ -int hvcs_free_connection(unsigned int unit_address) +int hvcs_free_connection(uint32_t unit_address) { long retval; retval = plpar_hcall_norets(H_FREE_VTERM, unit_address); diff -Nru a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c --- a/arch/ppc64/kernel/iSeries_htab.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc64/kernel/iSeries_htab.c 2004-10-18 14:56:29 -07:00 @@ -233,4 +233,6 @@ ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; ppc_md.hpte_insert = iSeries_hpte_insert; ppc_md.hpte_remove = iSeries_hpte_remove; + + htab_finish_init(); } diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c --- a/arch/ppc64/kernel/iSeries_pci.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc64/kernel/iSeries_pci.c 2004-10-18 14:57:04 -07:00 @@ -419,46 +419,39 @@ * I/0 Memory copy MUST use mmio commands on iSeries * To do; For performance, include the hv call directly */ -void *iSeries_memset_io(void *dest, char c, size_t Count) +void iSeries_memset_io(volatile void __iomem *dest, char c, size_t Count) { u8 ByteValue = c; long NumberOfBytes = Count; - char *IoBuffer = dest; while (NumberOfBytes > 0) { - iSeries_Write_Byte(ByteValue, (void *)IoBuffer); - ++IoBuffer; + iSeries_Write_Byte(ByteValue, dest++); -- NumberOfBytes; } - return dest; } EXPORT_SYMBOL(iSeries_memset_io); -void *iSeries_memcpy_toio(void *dest, void *source, size_t count) +void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t count) { - char *dst = dest; char *src = source; long NumberOfBytes = count; while (NumberOfBytes > 0) { - iSeries_Write_Byte(*src++, (void *)dst++); + iSeries_Write_Byte(*src++, dest++); -- NumberOfBytes; } - return dest; } EXPORT_SYMBOL(iSeries_memcpy_toio); -void *iSeries_memcpy_fromio(void *dest, void *source, size_t count) +void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *src, size_t count) { char *dst = dest; - char *src = source; long NumberOfBytes = count; while (NumberOfBytes > 0) { - *dst++ = iSeries_Read_Byte((void *)src++); + *dst++ = iSeries_Read_Byte(src++); -- NumberOfBytes; } - return dest; } EXPORT_SYMBOL(iSeries_memcpy_fromio); @@ -612,17 +605,19 @@ * Note: Make sure the passed variable end up on the stack to avoid * the exposure of being device global. */ -static inline struct iSeries_Device_Node *xlateIoMmAddress(void *IoAddress, +static inline struct iSeries_Device_Node *xlateIoMmAddress(const volatile void __iomem *IoAddress, u64 *dsaptr, u64 *BarOffsetPtr) { + unsigned long OrigIoAddr; unsigned long BaseIoAddr; unsigned long TableIndex; struct iSeries_Device_Node *DevNode; - if (((unsigned long)IoAddress < iSeries_Base_Io_Memory) || - ((unsigned long)IoAddress >= iSeries_Max_Io_Memory)) + OrigIoAddr = (unsigned long __force)IoAddress; + if ((OrigIoAddr < iSeries_Base_Io_Memory) || + (OrigIoAddr >= iSeries_Max_Io_Memory)) return NULL; - BaseIoAddr = (unsigned long)IoAddress - iSeries_Base_Io_Memory; + BaseIoAddr = OrigIoAddr - iSeries_Base_Io_Memory; TableIndex = BaseIoAddr / iSeries_IoMmTable_Entry_Size; DevNode = iSeries_IoMmTable[TableIndex]; @@ -644,7 +639,7 @@ * iSeries_Read_Word = Read Word (16 bit) * iSeries_Read_Long = Read Long (32 bit) */ -u8 iSeries_Read_Byte(void *IoAddress) +u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -673,7 +668,7 @@ } EXPORT_SYMBOL(iSeries_Read_Byte); -u16 iSeries_Read_Word(void *IoAddress) +u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -703,7 +698,7 @@ } EXPORT_SYMBOL(iSeries_Read_Word); -u32 iSeries_Read_Long(void *IoAddress) +u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -740,7 +735,7 @@ * iSeries_Write_Word = Write Word(16 bit) * iSeries_Write_Long = Write Long(32 bit) */ -void iSeries_Write_Byte(u8 data, void *IoAddress) +void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -767,7 +762,7 @@ } EXPORT_SYMBOL(iSeries_Write_Byte); -void iSeries_Write_Word(u16 data, void *IoAddress) +void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -794,7 +789,7 @@ } EXPORT_SYMBOL(iSeries_Write_Word); -void iSeries_Write_Long(u32 data, void *IoAddress) +void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -820,7 +815,3 @@ } while (CheckReturnCode("WWL", DevNode, rc) != 0); } EXPORT_SYMBOL(iSeries_Write_Long); - -void pcibios_name_device(struct pci_dev *dev) -{ -} diff -Nru a/arch/ppc64/kernel/iSeries_pci_reset.c b/arch/ppc64/kernel/iSeries_pci_reset.c --- a/arch/ppc64/kernel/iSeries_pci_reset.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/iSeries_pci_reset.c 2004-10-18 14:56:49 -07:00 @@ -65,7 +65,8 @@ AssertDelay = (5 * HZ) / 10; else AssertDelay = (AssertTime * HZ) / 10; - if (WaitDelay == 0) + + if (DelayTime == 0) WaitDelay = (30 * HZ) / 10; else WaitDelay = (DelayTime * HZ) / 10; diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c --- a/arch/ppc64/kernel/iSeries_setup.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/iSeries_setup.c 2004-10-18 14:56:49 -07:00 @@ -16,6 +16,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -36,6 +38,7 @@ #include #include #include +#include #include #include "iSeries_setup.h" @@ -53,18 +56,21 @@ #include #include +extern void hvlog(char *fmt, ...); + +#ifdef DEBUG +#define DBG(fmt...) hvlog(fmt) +#else +#define DBG(fmt...) +#endif + /* Function Prototypes */ -extern void abort(void); extern void ppcdbg_initialize(void); -extern void iSeries_pcibios_init(void); extern void tce_init_iSeries(void); static void build_iSeries_Memory_Map(void); static void setup_iSeries_cache_sizes(void); static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr); -extern void build_valid_hpte(unsigned long vsid, unsigned long ea, unsigned long pa, - pte_t *ptep, unsigned hpteflags, unsigned bolted); -static void iSeries_setup_dprofile(void); extern void iSeries_setup_arch(void); extern void iSeries_pci_final_fixup(void); @@ -77,16 +83,8 @@ static unsigned long tbFreqMhz; static unsigned long tbFreqMhzHundreths; -unsigned long dprof_shift; -unsigned long dprof_len; -unsigned int *dprof_buffer; - int piranha_simulator; -int boot_cpuid; - -extern char _end[]; - extern int rd_size; /* Defined in drivers/block/rd.c */ extern unsigned long klimit; extern unsigned long embedded_sysmap_start; @@ -285,8 +283,28 @@ return mem_blocks; } -void __init iSeries_init_early(void) +static void __init iSeries_parse_cmdline(void) +{ + char *p, *q; + + /* copy the command line parameter from the primary VSP */ + HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, + HvLpDma_Direction_RemoteToLocal); + + p = cmd_line; + q = cmd_line + 255; + while(p < q) { + if (!*p || *p == '\n') + break; + ++p; + } + *p = 0; +} + +/*static*/ void __init iSeries_init_early(void) { + DBG(" -> iSeries_init_early()\n"); + ppcdbg_initialize(); #if defined(CONFIG_BLK_DEV_INITRD) @@ -310,25 +328,20 @@ iSeries_recal_tb = get_tb(); iSeries_recal_titan = HvCallXm_loadTod(); - ppc_md.setup_arch = iSeries_setup_arch; - ppc_md.get_cpuinfo = iSeries_get_cpuinfo; - ppc_md.init_IRQ = iSeries_init_IRQ; - ppc_md.get_irq = iSeries_get_irq; - ppc_md.init = NULL; - - ppc_md.pcibios_fixup = iSeries_pci_final_fixup; - - ppc_md.restart = iSeries_restart; - ppc_md.power_off = iSeries_power_off; - ppc_md.halt = iSeries_halt; - - ppc_md.get_boot_time = iSeries_get_boot_time; - ppc_md.set_rtc_time = iSeries_set_rtc_time; - ppc_md.get_rtc_time = iSeries_get_rtc_time; - ppc_md.calibrate_decr = iSeries_calibrate_decr; - ppc_md.progress = iSeries_progress; + /* + * Cache sizes must be initialized before hpte_init_iSeries is called + * as the later need them for flush_icache_range() + */ + setup_iSeries_cache_sizes(); + /* + * Initialize the hash table management pointers + */ hpte_init_iSeries(); + + /* + * Initialize the DMA/TCE management + */ tce_init_iSeries(); /* @@ -336,63 +349,36 @@ * AS/400 absolute addresses */ build_iSeries_Memory_Map(); - setup_iSeries_cache_sizes(); + /* Initialize machine-dependency vectors */ #ifdef CONFIG_SMP smp_init_iSeries(); #endif if (itLpNaca.xPirEnvironMode == 0) piranha_simulator = 1; -} - -void __init iSeries_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - char *p, *q; /* Associate Lp Event Queue 0 with processor 0 */ HvCallEvent_setLpEventQueueInterruptProc(0, 0); - /* copy the command line parameter from the primary VSP */ - HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, - HvLpDma_Direction_RemoteToLocal); + mf_init(); + mf_initialized = 1; + mb(); - p = cmd_line; - q = cmd_line + 255; - while( p < q ) { - if (!*p || *p == '\n') - break; - ++p; - } - *p = 0; + /* If we were passed an initrd, set the ROOT_DEV properly if the values + * look sensible. If not, clear initrd reference. + */ +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && + initrd_end > initrd_start) + ROOT_DEV = Root_RAM0; + else + initrd_start = initrd_end = 0; +#endif /* CONFIG_BLK_DEV_INITRD */ - if (strstr(cmd_line, "dprofile=")) { - for (q = cmd_line; (p = strstr(q, "dprofile=")) != 0; ) { - unsigned long size, new_klimit; - - q = p + 9; - if ((p > cmd_line) && (p[-1] != ' ')) - continue; - dprof_shift = simple_strtoul(q, &q, 0); - dprof_len = (unsigned long)_etext - - (unsigned long)_stext; - dprof_len >>= dprof_shift; - size = ((dprof_len * sizeof(unsigned int)) + - (PAGE_SIZE-1)) & PAGE_MASK; - dprof_buffer = (unsigned int *)((klimit + - (PAGE_SIZE-1)) & PAGE_MASK); - new_klimit = ((unsigned long)dprof_buffer) + size; - lmb_reserve(__pa(klimit), (new_klimit-klimit)); - klimit = new_klimit; - memset(dprof_buffer, 0, size); - } - } - iSeries_setup_dprofile(); + iSeries_parse_cmdline(); - mf_init(); - mf_initialized = 1; - mb(); + DBG(" <- iSeries_init_early()\n"); } /* @@ -816,7 +802,7 @@ } } -void iSeries_fixup_klimit(void) +static void __init iSeries_fixup_klimit(void) { /* * Change klimit to take into account any ram disk @@ -837,22 +823,6 @@ } } -static void iSeries_setup_dprofile(void) -{ - if (dprof_buffer) { - unsigned i; - - for (i = 0; i < NR_CPUS; ++i) { - paca[i].prof_shift = dprof_shift; - paca[i].prof_len = dprof_len - 1; - paca[i].prof_buffer = dprof_buffer; - paca[i].prof_stext = (unsigned *)_stext; - mb(); - paca[i].prof_enabled = 1; - } - } -} - int __init iSeries_src_init(void) { /* clear the progress line */ @@ -861,3 +831,27 @@ } late_initcall(iSeries_src_init); + +void __init iSeries_early_setup(void) +{ + iSeries_fixup_klimit(); + + ppc_md.setup_arch = iSeries_setup_arch; + ppc_md.get_cpuinfo = iSeries_get_cpuinfo; + ppc_md.init_IRQ = iSeries_init_IRQ; + ppc_md.get_irq = iSeries_get_irq; + ppc_md.init_early = iSeries_init_early, + + ppc_md.pcibios_fixup = iSeries_pci_final_fixup; + + ppc_md.restart = iSeries_restart; + ppc_md.power_off = iSeries_power_off; + ppc_md.halt = iSeries_halt; + + ppc_md.get_boot_time = iSeries_get_boot_time; + ppc_md.set_rtc_time = iSeries_set_rtc_time; + ppc_md.get_rtc_time = iSeries_get_rtc_time; + ppc_md.calibrate_decr = iSeries_calibrate_decr; + ppc_md.progress = iSeries_progress; +} + diff -Nru a/arch/ppc64/kernel/iSeries_setup.h b/arch/ppc64/kernel/iSeries_setup.h --- a/arch/ppc64/kernel/iSeries_setup.h 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/iSeries_setup.h 2004-10-18 14:56:49 -07:00 @@ -19,10 +19,6 @@ #ifndef __ISERIES_SETUP_H__ #define __ISERIES_SETUP_H__ -extern void iSeries_init_early(void); -extern void iSeries_init(unsigned long r3, unsigned long ird_start, - unsigned long ird_end, unsigned long cline_start, - unsigned long cline_end); extern void iSeries_setup_arch(void); extern void iSeries_setup_residual(struct seq_file *m, int cpu_id); extern void iSeries_get_cpuinfo(struct seq_file *m); diff -Nru a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c --- a/arch/ppc64/kernel/idle.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/idle.c 2004-10-18 14:56:49 -07:00 @@ -16,40 +16,29 @@ */ #include -#include #include #include -#include #include -#include -#include -#include -#include -#include #include +#include +#include -#include -#include #include -#include #include #include -#include #include #include -#include #include #include +#include -extern long cede_processor(void); -extern long poll_pending(void); extern void power4_idle(void); -int (*idle_loop)(void); +static int (*idle_loop)(void); #ifdef CONFIG_PPC_ISERIES -unsigned long maxYieldTime = 0; -unsigned long minYieldTime = 0xffffffffffffffffUL; +static unsigned long maxYieldTime = 0; +static unsigned long minYieldTime = 0xffffffffffffffffUL; static void yield_shared_processor(void) { @@ -80,7 +69,7 @@ process_iSeries_events(); } -int iSeries_idle(void) +static int iSeries_idle(void) { struct paca_struct *lpaca; long oldval; @@ -91,13 +80,10 @@ CTRL = mfspr(CTRLF); CTRL &= ~RUNLATCH; mtspr(CTRLT, CTRL); -#if 0 - init_idle(); -#endif lpaca = get_paca(); - for (;;) { + while (1) { if (lpaca->lppaca.xSharedProc) { if (ItLpQueue_isLpIntPending(lpaca->lpqueue_ptr)) process_iSeries_events(); @@ -125,13 +111,16 @@ schedule(); } + return 0; } -#endif -int default_idle(void) +#else + +static int default_idle(void) { long oldval; + unsigned int cpu = smp_processor_id(); while (1) { oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); @@ -139,9 +128,14 @@ if (!oldval) { set_thread_flag(TIF_POLLING_NRFLAG); - while (!need_resched()) { + while (!need_resched() && !cpu_is_offline(cpu)) { barrier(); + /* + * Go into low thread priority and possibly + * low power mode. + */ HMT_low(); + HMT_very_low(); } HMT_medium(); @@ -151,8 +145,7 @@ } schedule(); - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); } @@ -169,12 +162,15 @@ struct paca_struct *lpaca = get_paca(), *ppaca; unsigned long start_snooze; unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); + unsigned int cpu = smp_processor_id(); - ppaca = &paca[smp_processor_id() ^ 1]; + ppaca = &paca[cpu ^ 1]; while (1) { - /* Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. */ + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ lpaca->lppaca.xIdle = 1; oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); @@ -182,42 +178,32 @@ set_thread_flag(TIF_POLLING_NRFLAG); start_snooze = __get_tb() + *smt_snooze_delay * tb_ticks_per_usec; - while (!need_resched()) { - /* need_resched could be 1 or 0 at this - * point. If it is 0, set it to 0, so - * an IPI/Prod is sent. If it is 1, keep - * it that way & schedule work. + while (!need_resched() && !cpu_is_offline(cpu)) { + /* + * Go into low thread priority and possibly + * low power mode. */ + HMT_low(); + HMT_very_low(); + if (*smt_snooze_delay == 0 || - __get_tb() < start_snooze) { - HMT_low(); /* Low thread priority */ + __get_tb() < start_snooze) continue; - } - HMT_very_low(); /* Low power mode */ + HMT_medium(); - /* If the SMT mode is system controlled & the - * partner thread is doing work, switch into - * ST mode. - */ - if((naca->smt_state == SMT_DYNAMIC) && - (!(ppaca->lppaca.xIdle))) { - /* Indicate we are no longer polling for - * work, and then clear need_resched. If - * need_resched was 1, set it back to 1 - * and schedule work + if (!(ppaca->lppaca.xIdle)) { + local_irq_disable(); + + /* + * We are about to sleep the thread + * and so wont be polling any + * more. */ clear_thread_flag(TIF_POLLING_NRFLAG); - oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - if(oldval == 1) { - set_need_resched(); - break; - } - /* DRENG: Go HMT_medium here ? */ - local_irq_disable(); - - /* SMT dynamic mode. Cede will result + /* + * SMT dynamic mode. Cede will result * in this thread going dormant, if the * partner thread is still doing work. * Thread wakes up if partner goes idle, @@ -225,15 +211,21 @@ * occurs. Returning from the cede * enables external interrupts. */ - cede_processor(); + if (!need_resched()) + cede_processor(); + else + local_irq_enable(); } else { - /* Give the HV an opportunity at the + /* + * Give the HV an opportunity at the * processor, since we are not doing * any work. */ poll_pending(); } } + + clear_thread_flag(TIF_POLLING_NRFLAG); } else { set_need_resched(); } @@ -241,57 +233,60 @@ HMT_medium(); lpaca->lppaca.xIdle = 0; schedule(); - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); } return 0; } -int shared_idle(void) +static int shared_idle(void) { struct paca_struct *lpaca = get_paca(); + unsigned int cpu = smp_processor_id(); while (1) { - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) - cpu_die(); - - /* Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. */ + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ lpaca->lppaca.xIdle = 1; - if (!need_resched()) { - local_irq_disable(); - - /* + while (!need_resched() && !cpu_is_offline(cpu)) { + local_irq_disable(); + + /* * Yield the processor to the hypervisor. We return if * an external interrupt occurs (which are driven prior * to returning here) or if a prod occurs from another - * processor. When returning here, external interrupts + * processor. When returning here, external interrupts * are enabled. + * + * Check need_resched() again with interrupts disabled + * to avoid a race. */ - cede_processor(); + if (!need_resched()) + cede_processor(); + else + local_irq_enable(); } HMT_medium(); lpaca->lppaca.xIdle = 0; schedule(); + if (cpu_is_offline(smp_processor_id()) && + system_state == SYSTEM_RUNNING) + cpu_die(); } return 0; } -#endif -int cpu_idle(void) -{ - idle_loop(); - return 0; -} +#endif /* CONFIG_PPC_PSERIES */ -int native_idle(void) +static int native_idle(void) { while(1) { + /* check CPU type here */ if (!need_resched()) power4_idle(); if (need_resched()) @@ -300,33 +295,80 @@ return 0; } +#endif /* CONFIG_PPC_ISERIES */ + +int cpu_idle(void) +{ + idle_loop(); + return 0; +} + +int powersave_nap; + +#ifdef CONFIG_SYSCTL +/* + * Register the sysctl to set/clear powersave_nap. + */ +static ctl_table powersave_nap_ctl_table[]={ + { + .ctl_name = KERN_PPC_POWERSAVE_NAP, + .procname = "powersave-nap", + .data = &powersave_nap, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { 0, }, +}; +static ctl_table powersave_nap_sysctl_root[] = { + { 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, }, + { 0,}, +}; + +static int __init +register_powersave_nap_sysctl(void) +{ + register_sysctl_table(powersave_nap_sysctl_root, 0); + + return 0; +} +__initcall(register_powersave_nap_sysctl); +#endif + int idle_setup(void) { + /* + * Move that junk to each platform specific file, eventually define + * a pSeries_idle for shared processor stuff + */ #ifdef CONFIG_PPC_ISERIES idle_loop = iSeries_idle; + return 1; #else + idle_loop = default_idle; +#endif +#ifdef CONFIG_PPC_PSERIES if (systemcfg->platform & PLATFORM_PSERIES) { if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { if (get_paca()->lppaca.xSharedProc) { - printk("idle = shared_idle\n"); + printk(KERN_INFO "Using shared processor idle loop\n"); idle_loop = shared_idle; } else { - printk("idle = dedicated_idle\n"); + printk(KERN_INFO "Using dedicated idle loop\n"); idle_loop = dedicated_idle; } } else { - printk("idle = default_idle\n"); + printk(KERN_INFO "Using default idle loop\n"); idle_loop = default_idle; } - } else if (systemcfg->platform == PLATFORM_POWERMAC) { - printk("idle = native_idle\n"); + } +#endif /* CONFIG_PPC_PSERIES */ +#ifdef CONFIG_PPC_PMAC + if (systemcfg->platform == PLATFORM_POWERMAC) { + printk(KERN_INFO "Using native/NAP idle loop\n"); idle_loop = native_idle; - } else { - printk("idle_setup: unknown platform, use default_idle\n"); - idle_loop = default_idle; } -#endif +#endif /* CONFIG_PPC_PMAC */ return 1; } - diff -Nru a/arch/ppc64/kernel/idle_power4.S b/arch/ppc64/kernel/idle_power4.S --- a/arch/ppc64/kernel/idle_power4.S 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/kernel/idle_power4.S 2004-10-18 14:56:32 -07:00 @@ -46,7 +46,7 @@ /* Now check if user or arch enabled NAP mode */ LOADBASE(r3,powersave_nap) lwz r4,powersave_nap@l(r3) - cmpi 0,r4,0 + cmpwi 0,r4,0 beqlr /* Clear MSR:EE */ diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c --- a/arch/ppc64/kernel/ioctl32.c 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc64/kernel/ioctl32.c 2004-10-18 14:57:05 -07:00 @@ -22,9 +22,7 @@ #define INCLUDES #include "compat_ioctl.c" -#include #include -#include #define CODE #include "compat_ioctl.c" diff -Nru a/arch/ppc64/kernel/iomap.c b/arch/ppc64/kernel/iomap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/kernel/iomap.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +/* + * Here comes the ppc64 implementation of the IOMAP + * interfaces. + */ +unsigned int fastcall ioread8(void __iomem *addr) +{ + return readb(addr); +} +unsigned int fastcall ioread16(void __iomem *addr) +{ + return readw(addr); +} +unsigned int fastcall ioread32(void __iomem *addr) +{ + return readl(addr); +} +EXPORT_SYMBOL(ioread8); +EXPORT_SYMBOL(ioread16); +EXPORT_SYMBOL(ioread32); + +void fastcall iowrite8(u8 val, void __iomem *addr) +{ + writeb(val, addr); +} +void fastcall iowrite16(u16 val, void __iomem *addr) +{ + writew(val, addr); +} +void fastcall iowrite32(u32 val, void __iomem *addr) +{ + writel(val, addr); +} +EXPORT_SYMBOL(iowrite8); +EXPORT_SYMBOL(iowrite16); +EXPORT_SYMBOL(iowrite32); + +/* + * These are the "repeat read/write" functions. Note the + * non-CPU byte order. We do things in "IO byteorder" + * here. + * + * FIXME! We could make these do EEH handling if we really + * wanted. Not clear if we do. + */ +void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) +{ + _insb((u8 __force *) addr, dst, count); +} +void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) +{ + _insw_ns((u16 __force *) addr, dst, count); +} +void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) +{ + _insl_ns((u32 __force *) addr, dst, count); +} +EXPORT_SYMBOL(ioread8_rep); +EXPORT_SYMBOL(ioread16_rep); +EXPORT_SYMBOL(ioread32_rep); + +void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) +{ + _outsb((u8 __force *) addr, src, count); +} +void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) +{ + _outsw_ns((u16 __force *) addr, src, count); +} +void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) +{ + _outsl_ns((u32 __force *) addr, src, count); +} +EXPORT_SYMBOL(iowrite8_rep); +EXPORT_SYMBOL(iowrite16_rep); +EXPORT_SYMBOL(iowrite32_rep); + +void __iomem *ioport_map(unsigned long port, unsigned int len) +{ + if (!_IO_IS_VALID(port)) + return NULL; + return (void __iomem *) (port+pci_io_base); +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len) + return NULL; + if (max && len > max) + len = max; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) + return (void __iomem *) start; + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); diff -Nru a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c --- a/arch/ppc64/kernel/iommu.c 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc64/kernel/iommu.c 2004-10-18 14:55:53 -07:00 @@ -229,7 +229,7 @@ struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - dma_addr_t dma_next, dma_addr; + dma_addr_t dma_next = 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart; int outcount; diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c --- a/arch/ppc64/kernel/irq.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc64/kernel/irq.c 2004-10-18 14:56:29 -07:00 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -362,14 +363,16 @@ int handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) { int status = 0; - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -586,13 +589,13 @@ irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: is there less than 4KB free? */ + /* Debugging check for stack overflow: is there less than 2KB free? */ { long sp; sp = __get_SP() & (THREAD_SIZE-1); - if (unlikely(sp < (sizeof(struct thread_info) + 4096))) { + if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { printk("do_IRQ: stack overflow: %ld\n", sp - sizeof(struct thread_info)); dump_stack(); @@ -629,13 +632,13 @@ irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: is there less than 4KB free? */ + /* Debugging check for stack overflow: is there less than 2KB free? */ { long sp; sp = __get_SP() & (THREAD_SIZE-1); - if (unlikely(sp < (sizeof(struct thread_info) + 4096))) { + if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { printk("do_IRQ: stack overflow: %ld\n", sp - sizeof(struct thread_info)); dump_stack(); @@ -674,6 +677,8 @@ return 0; } +EXPORT_SYMBOL(probe_irq_mask); + void __init init_IRQ(void) { static int once = 0; @@ -757,44 +762,6 @@ return ret; } -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - -#ifdef CONFIG_PPC_ISERIES - { - unsigned i; - for (i=0; inlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. @@ -977,7 +933,7 @@ struct thread_info *tp; int i; - for (i = 0; i < NR_CPUS; i++) { + for_each_cpu(i) { memset((void *)softirq_ctx[i], 0, THREAD_SIZE); tp = softirq_ctx[i]; tp->cpu = i; diff -Nru a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c --- a/arch/ppc64/kernel/lmb.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/kernel/lmb.c 2004-10-18 14:56:33 -07:00 @@ -20,7 +20,44 @@ #include #include -struct lmb lmb __initdata; +struct lmb lmb; + +#undef DEBUG + +void lmb_dump_all(void) +{ +#ifdef DEBUG + unsigned long i; + struct lmb *_lmb = &lmb; + + udbg_printf("lmb_dump_all:\n"); + udbg_printf(" memory.cnt = 0x%lx\n", + _lmb->memory.cnt); + udbg_printf(" memory.size = 0x%lx\n", + _lmb->memory.size); + for (i=0; i < _lmb->memory.cnt ;i++) { + udbg_printf(" memory.region[0x%x].base = 0x%lx\n", + i, _lmb->memory.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + _lmb->memory.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + _lmb->memory.region[i].size); + } + + udbg_printf("\n reserved.cnt = 0x%lx\n", + _lmb->reserved.cnt); + udbg_printf(" reserved.size = 0x%lx\n", + _lmb->reserved.size); + for (i=0; i < _lmb->reserved.cnt ;i++) { + udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", + i, _lmb->reserved.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + _lmb->reserved.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + _lmb->reserved.region[i].size); + } +#endif /* DEBUG */ +} static unsigned long __init lmb_addrs_overlap(unsigned long base1, unsigned long size1, @@ -71,8 +108,7 @@ void __init lmb_init(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; /* Create a dummy zero size LMB which will get coalesced away later. * This simplifies the lmb_add() code below... @@ -94,8 +130,7 @@ unsigned long i; unsigned long mem_size = 0; unsigned long size_mask = 0; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; #ifdef CONFIG_MSCHUNKS unsigned long physbase = 0; #endif @@ -178,8 +213,7 @@ long __init lmb_add(unsigned long base, unsigned long size) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_rgn = &(_lmb->memory); /* On pSeries LPAR systems, the first LMB is our RMO region. */ @@ -193,8 +227,7 @@ long __init lmb_reserve(unsigned long base, unsigned long size) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_rgn = &(_lmb->reserved); return lmb_add_region(_rgn, base, size); @@ -227,8 +260,7 @@ { long i, j; unsigned long base = 0; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); struct lmb_region *_rsv = &(_lmb->reserved); @@ -263,8 +295,7 @@ unsigned long __init lmb_phys_mem_size(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; #ifdef CONFIG_MSCHUNKS return _lmb->memory.size; #else @@ -282,8 +313,7 @@ unsigned long __init lmb_end_of_DRAM(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); int idx = _mem->cnt - 1; @@ -300,8 +330,7 @@ lmb_abs_to_phys(unsigned long aa) { unsigned long i, pa = aa; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); for (i=0; i < _mem->cnt; i++) { diff -Nru a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c --- a/arch/ppc64/kernel/lparcfg.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc64/kernel/lparcfg.c 2004-10-18 14:55:55 -07:00 @@ -34,31 +34,37 @@ #include #include -#define MODULE_VERS "1.3" +#define MODULE_VERS "1.4" #define MODULE_NAME "lparcfg" /* #define LPARCFG_DEBUG */ /* find a better place for this function... */ -void log_plpar_hcall_return(unsigned long rc,char * tag) +void log_plpar_hcall_return(unsigned long rc, char *tag) { - if (rc ==0 ) /* success, return */ + if (rc == 0) /* success, return */ return; /* check for null tag ? */ if (rc == H_Hardware) - printk(KERN_INFO "plpar-hcall (%s) failed with hardware fault\n",tag); + printk(KERN_INFO + "plpar-hcall (%s) failed with hardware fault\n", tag); else if (rc == H_Function) - printk(KERN_INFO "plpar-hcall (%s) failed; function not allowed\n",tag); + printk(KERN_INFO + "plpar-hcall (%s) failed; function not allowed\n", tag); else if (rc == H_Authority) - printk(KERN_INFO "plpar-hcall (%s) failed; not authorized to this function\n",tag); + printk(KERN_INFO + "plpar-hcall (%s) failed; not authorized to this function\n", + tag); else if (rc == H_Parameter) - printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",tag); + printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n", + tag); else - printk(KERN_INFO "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",tag,rc); + printk(KERN_INFO + "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n", + tag, rc); } - static struct proc_dir_entry *proc_ppc64_lparcfg; #define LPARCFG_BUFF_SIZE 4096 @@ -78,59 +84,60 @@ shared = (int)(lpaca->lppaca_ptr->xSharedProc); seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n", - e2a(xItExtVpdPanel.mfgID[2]), - e2a(xItExtVpdPanel.mfgID[3]), - e2a(xItExtVpdPanel.systemSerial[1]), - e2a(xItExtVpdPanel.systemSerial[2]), - e2a(xItExtVpdPanel.systemSerial[3]), - e2a(xItExtVpdPanel.systemSerial[4]), - e2a(xItExtVpdPanel.systemSerial[5])); + e2a(xItExtVpdPanel.mfgID[2]), + e2a(xItExtVpdPanel.mfgID[3]), + e2a(xItExtVpdPanel.systemSerial[1]), + e2a(xItExtVpdPanel.systemSerial[2]), + e2a(xItExtVpdPanel.systemSerial[3]), + e2a(xItExtVpdPanel.systemSerial[4]), + e2a(xItExtVpdPanel.systemSerial[5])); seq_printf(m, "system_type=%c%c%c%c\n", - e2a(xItExtVpdPanel.machineType[0]), - e2a(xItExtVpdPanel.machineType[1]), - e2a(xItExtVpdPanel.machineType[2]), - e2a(xItExtVpdPanel.machineType[3])); + e2a(xItExtVpdPanel.machineType[0]), + e2a(xItExtVpdPanel.machineType[1]), + e2a(xItExtVpdPanel.machineType[2]), + e2a(xItExtVpdPanel.machineType[3])); - lp_index = HvLpConfig_getLpIndex(); + lp_index = HvLpConfig_getLpIndex(); seq_printf(m, "partition_id=%d\n", (int)lp_index); seq_printf(m, "system_active_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); + (int)HvLpConfig_getSystemPhysicalProcessors()); seq_printf(m, "system_potential_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); + (int)HvLpConfig_getSystemPhysicalProcessors()); - processors = (int)HvLpConfig_getPhysicalProcessors(); + processors = (int)HvLpConfig_getPhysicalProcessors(); seq_printf(m, "partition_active_processors=%d\n", processors); - max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); + max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); seq_printf(m, "partition_potential_processors=%d\n", max_processors); - if(shared) { - entitled_capacity = HvLpConfig_getSharedProcUnits(); - max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); + if (shared) { + entitled_capacity = HvLpConfig_getSharedProcUnits(); + max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); } else { - entitled_capacity = processors * 100; - max_entitled_capacity = max_processors * 100; + entitled_capacity = processors * 100; + max_entitled_capacity = max_processors * 100; } seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity); seq_printf(m, "partition_max_entitled_capacity=%d\n", - max_entitled_capacity); + max_entitled_capacity); - if(shared) { - pool_id = HvLpConfig_getSharedPoolIndex(); + if (shared) { + pool_id = HvLpConfig_getSharedPoolIndex(); seq_printf(m, "pool=%d\n", (int)pool_id); seq_printf(m, "pool_capacity=%d\n", - (int)(HvLpConfig_getNumProcsInSharedPool(pool_id)*100)); + (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) * + 100)); } seq_printf(m, "shared_processor_mode=%d\n", shared); return 0; } -#endif /* CONFIG_PPC_ISERIES */ +#endif /* CONFIG_PPC_ISERIES */ #ifdef CONFIG_PPC_PSERIES /* @@ -158,11 +165,13 @@ * XXXX - Processors active on platform. */ static unsigned int h_get_ppp(unsigned long *entitled, - unsigned long *unallocated, unsigned long *aggregation, - unsigned long *resource) + unsigned long *unallocated, + unsigned long *aggregation, + unsigned long *resource) { unsigned long rc; - rc = plpar_hcall_4out(H_GET_PPP,0,0,0,0,entitled,unallocated,aggregation,resource); + rc = plpar_hcall_4out(H_GET_PPP, 0, 0, 0, 0, entitled, unallocated, + aggregation, resource); log_plpar_hcall_return(rc, "H_GET_PPP"); @@ -185,7 +194,7 @@ */ static unsigned long get_purr() { - unsigned long sum_purr=0; + unsigned long sum_purr = 0; return sum_purr; } @@ -202,7 +211,7 @@ { int call_status; - char * local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); + char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!local_buffer) { printk(KERN_ERR "%s %s kmalloc failure at line %d \n", __FILE__, __FUNCTION__, __LINE__); @@ -219,22 +228,23 @@ spin_unlock(&rtas_data_buf_lock); if (call_status != 0) { - printk(KERN_INFO "%s %s Error calling get-system-parameter (0x%x)\n", + printk(KERN_INFO + "%s %s Error calling get-system-parameter (0x%x)\n", __FILE__, __FUNCTION__, call_status); } else { int splpar_strlen; int idx, w_idx; - char * workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); + char *workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!workbuffer) { - printk(KERN_ERR "%s %s kmalloc failure at line %d \n",__FILE__,__FUNCTION__,__LINE__); + printk(KERN_ERR "%s %s kmalloc failure at line %d \n", + __FILE__, __FUNCTION__, __LINE__); return; } - #ifdef LPARCFG_DEBUG printk(KERN_INFO "success calling get-system-parameter \n"); #endif splpar_strlen = local_buffer[0] * 16 + local_buffer[1]; - local_buffer += 2; /* step over strlen value */ + local_buffer += 2; /* step over strlen value */ memset(workbuffer, 0, SPLPAR_MAXLENGTH); w_idx = 0; @@ -253,13 +263,15 @@ w_idx = 0; } else if (local_buffer[idx] == '=') { /* code here to replace workbuffer contents - with different keyword strings */ - if (0 == strcmp(workbuffer,"MaxEntCap")) { - strcpy(workbuffer, "partition_max_entitled_capacity"); + with different keyword strings */ + if (0 == strcmp(workbuffer, "MaxEntCap")) { + strcpy(workbuffer, + "partition_max_entitled_capacity"); w_idx = strlen(workbuffer); } - if (0 == strcmp(workbuffer,"MaxPlatProcs")) { - strcpy(workbuffer, "system_potential_processors"); + if (0 == strcmp(workbuffer, "MaxPlatProcs")) { + strcpy(workbuffer, + "system_potential_processors"); w_idx = strlen(workbuffer); } } @@ -283,7 +295,7 @@ while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) { #ifdef LPARCFG_DEBUG - printk(KERN_ERR "cpus_dn %p \n",cpus_dn); + printk(KERN_ERR "cpus_dn %p \n", cpus_dn); #endif count++; } @@ -292,7 +304,8 @@ static int lparcfg_data(struct seq_file *m, void *v) { - int system_active_processors; + int partition_potential_processors; + int partition_active_processors; struct device_node *rootdn; const char *model = ""; const char *system_id = ""; @@ -305,12 +318,11 @@ model = get_property(rootdn, "model", NULL); system_id = get_property(rootdn, "system-id", NULL); lp_index_ptr = (unsigned int *) - get_property(rootdn, "ibm,partition-no", NULL); + get_property(rootdn, "ibm,partition-no", NULL); if (lp_index_ptr) lp_index = *lp_index_ptr; } - seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); seq_printf(m, "serial_number=%s\n", system_id); @@ -323,11 +335,13 @@ lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL); if (lrdrp == NULL) { - system_active_processors = systemcfg->processorCount; + partition_potential_processors = systemcfg->processorCount; } else { - system_active_processors = *(lrdrp + 4); + partition_potential_processors = *(lrdrp + 4); } + partition_active_processors = lparcfg_count_active_processors(); + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { unsigned long h_entitled, h_unallocated; unsigned long h_aggregation, h_resource; @@ -342,71 +356,69 @@ seq_printf(m, "R6=0x%lx\n", h_aggregation); seq_printf(m, "R7=0x%lx\n", h_resource); - h_pic(&pool_idle_time, &pool_procs); - purr = get_purr(); /* this call handles the ibm,get-system-parameter contents */ parse_system_parameter_string(m); - seq_printf(m, "partition_entitled_capacity=%ld\n", - h_entitled); - - seq_printf(m, "pool=%ld\n", - (h_aggregation >> 0*8) & 0xffff); + seq_printf(m, "partition_entitled_capacity=%ld\n", h_entitled); - seq_printf(m, "group=%ld\n", - (h_aggregation >> 2*8) & 0xffff); + seq_printf(m, "group=%ld\n", (h_aggregation >> 2 * 8) & 0xffff); seq_printf(m, "system_active_processors=%ld\n", - (h_resource >> 0*8) & 0xffff); + (h_resource >> 0 * 8) & 0xffff); + + /* pool related entries are apropriate for shared configs */ + if (paca[0].lppaca.xSharedProc) { - seq_printf(m, "pool_capacity=%ld\n", - (h_resource >> 2*8) & 0xffff); + h_pic(&pool_idle_time, &pool_procs); + + seq_printf(m, "pool=%ld\n", + (h_aggregation >> 0 * 8) & 0xffff); + + /* report pool_capacity in percentage */ + seq_printf(m, "pool_capacity=%ld\n", + ((h_resource >> 2 * 8) & 0xffff) * 100); + + seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time); + + seq_printf(m, "pool_num_procs=%ld\n", pool_procs); + } seq_printf(m, "unallocated_capacity_weight=%ld\n", - (h_resource >> 4*8) & 0xFF); + (h_resource >> 4 * 8) & 0xFF); seq_printf(m, "capacity_weight=%ld\n", - (h_resource >> 5*8) & 0xFF); - - seq_printf(m, "capped=%ld\n", - (h_resource >> 6*8) & 0x01); + (h_resource >> 5 * 8) & 0xFF); - seq_printf(m, "unallocated_capacity=%ld\n", - h_unallocated); + seq_printf(m, "capped=%ld\n", (h_resource >> 6 * 8) & 0x01); - seq_printf(m, "pool_idle_time=%ld\n", - pool_idle_time); + seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated); - seq_printf(m, "pool_num_procs=%ld\n", - pool_procs); + seq_printf(m, "purr=%ld\n", purr); - seq_printf(m, "purr=%ld\n", - purr); + } else { /* non SPLPAR case */ - } else /* non SPLPAR case */ { seq_printf(m, "system_active_processors=%d\n", - system_active_processors); + partition_potential_processors); seq_printf(m, "system_potential_processors=%d\n", - system_active_processors); + partition_potential_processors); seq_printf(m, "partition_max_entitled_capacity=%d\n", - 100*system_active_processors); + partition_potential_processors * 100); seq_printf(m, "partition_entitled_capacity=%d\n", - system_active_processors*100); + partition_active_processors * 100); } seq_printf(m, "partition_active_processors=%d\n", - (int) lparcfg_count_active_processors()); + partition_active_processors); seq_printf(m, "partition_potential_processors=%d\n", - system_active_processors); + partition_potential_processors); - seq_printf(m, "shared_processor_mode=%d\n", - paca[0].lppaca.xSharedProc); + seq_printf(m, "shared_processor_mode=%d\n", paca[0].lppaca.xSharedProc); return 0; } @@ -421,14 +433,15 @@ * This function should be invoked only on systems with * FW_FEATURE_SPLPAR. */ -static ssize_t lparcfg_write(struct file *file, const char __user *buf, size_t count, loff_t *off) +static ssize_t lparcfg_write(struct file *file, const char __user * buf, + size_t count, loff_t * off) { char *kbuf; char *tmp; u64 new_entitled, *new_entitled_ptr = &new_entitled; u8 new_weight, *new_weight_ptr = &new_weight; - unsigned long current_entitled; /* parameters for h_get_ppp */ + unsigned long current_entitled; /* parameters for h_get_ppp */ unsigned long dummy; unsigned long resource; u8 current_weight; @@ -453,13 +466,13 @@ if (!strcmp(kbuf, "partition_entitled_capacity")) { char *endp; - *new_entitled_ptr = (u64)simple_strtoul(tmp, &endp, 10); + *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10); if (endp == tmp) goto out; new_weight_ptr = ¤t_weight; } else if (!strcmp(kbuf, "capacity_weight")) { char *endp; - *new_weight_ptr = (u8)simple_strtoul(tmp, &endp, 10); + *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10); if (endp == tmp) goto out; new_entitled_ptr = ¤t_entitled; @@ -473,7 +486,7 @@ goto out; } - current_weight = (resource>>5*8)&0xFF; + current_weight = (resource >> 5 * 8) & 0xFF; pr_debug("%s: current_entitled = %lu, current_weight = %lu\n", __FUNCTION__, current_entitled, current_weight); @@ -498,23 +511,23 @@ retval = -EIO; } -out: + out: kfree(kbuf); return retval; } -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_PSERIES */ -static int lparcfg_open(struct inode * inode, struct file * file) +static int lparcfg_open(struct inode *inode, struct file *file) { - return single_open(file,lparcfg_data,NULL); + return single_open(file, lparcfg_data, NULL); } struct file_operations lparcfg_fops = { - owner: THIS_MODULE, - read: seq_read, - open: lparcfg_open, - release: single_release, + owner:THIS_MODULE, + read:seq_read, + open:lparcfg_open, + release:single_release, }; int __init lparcfg_init(void) @@ -533,7 +546,8 @@ ent->proc_fops = &lparcfg_fops; ent->data = kmalloc(LPARCFG_BUFF_SIZE, GFP_KERNEL); if (!ent->data) { - printk(KERN_ERR "Failed to allocate buffer for lparcfg\n"); + printk(KERN_ERR + "Failed to allocate buffer for lparcfg\n"); remove_proc_entry("lparcfg", ent->parent); return -ENOMEM; } @@ -550,7 +564,7 @@ { if (proc_ppc64_lparcfg) { if (proc_ppc64_lparcfg->data) { - kfree(proc_ppc64_lparcfg->data); + kfree(proc_ppc64_lparcfg->data); } remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent); } diff -Nru a/arch/ppc64/kernel/mf_proc.c b/arch/ppc64/kernel/mf_proc.c --- a/arch/ppc64/kernel/mf_proc.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc64/kernel/mf_proc.c 2004-10-18 14:56:29 -07:00 @@ -167,22 +167,29 @@ return count; } -static int proc_mf_change_vmlinux(struct file *file, const char *buffer, - unsigned long count, void *data) +static ssize_t proc_mf_change_vmlinux(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) { + struct inode * inode = file->f_dentry->d_inode; + struct proc_dir_entry * dp = PDE(inode); int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - rc = mf_setVmlinuxChunk(buffer, count, file->f_pos, (u64)data); + rc = mf_setVmlinuxChunk(buf, count, *ppos, (u64)dp->data); if (rc < 0) return rc; - file->f_pos += count; + *ppos += count; return count; } +static struct file_operations proc_vmlinux_operations = { + .write = proc_mf_change_vmlinux, +}; + static int __init mf_proc_init(void) { struct proc_dir_entry *mf_proc_root; @@ -218,20 +225,7 @@ return 1; ent->nlink = 1; ent->data = (void *)(long)i; -#if 0 - if (i == 3) { - /* - * if we had a 'D' vmlinux entry, it would only - * be readable. - */ - ent->read_proc = proc_mf_dump_vmlinux; - ent->write_proc = NULL; - } else -#endif - { - ent->write_proc = proc_mf_change_vmlinux; - ent->read_proc = NULL; - } + ent->proc_fops = &proc_vmlinux_operations; } ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S --- a/arch/ppc64/kernel/misc.S 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc64/kernel/misc.S 2004-10-18 14:56:50 -07:00 @@ -127,6 +127,47 @@ blr #endif /* CONFIG_IRQSTACKS */ + /* + * To be called by C code which needs to do some operations with MMU + * disabled. Note that interrupts have to be disabled by the caller + * prior to calling us. The code called _MUST_ be in the RMO of course + * and part of the linear mapping as we don't attempt to translate the + * stack pointer at all. The function is called with the stack switched + * to this CPU emergency stack + * + * prototype is void *call_with_mmu_off(void *func, void *data); + * + * the called function is expected to be of the form + * + * void *called(void *data); + */ +_GLOBAL(call_with_mmu_off) + mflr r0 /* get link, save it on stackframe */ + std r0,16(r1) + mr r1,r5 /* save old stack ptr */ + ld r1,PACAEMERGSP(r13) /* get emerg. stack */ + subi r1,r1,STACK_FRAME_OVERHEAD + std r0,16(r1) /* save link on emerg. stack */ + std r5,0(r1) /* save old stack ptr in backchain */ + ld r3,0(r3) /* get to real function ptr (assume same TOC) */ + bl 2f /* we need LR to return, continue at label 2 */ + + ld r0,16(r1) /* we return here from the call, get LR and */ + ld r1,0(r1) /* .. old stack ptr */ + mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ + mfmsr r4 + ori r4,r4,MSR_IR|MSR_DR + mtspr SPRN_SRR1,r4 + rfid + +2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ + mr r3,r4 /* get parameter */ + mfmsr r0 + ori r0,r0,MSR_IR|MSR_DR + xori r0,r0,MSR_IR|MSR_DR + mtspr SPRN_SRR1,r0 + rfid + /* * Flush instruction cache. */ @@ -454,23 +495,6 @@ sync blr -_GLOBAL(abs) - cmpi 0,r3,0 - bge 10f - neg r3,r3 -10: blr - -_GLOBAL(_get_PVR) - mfspr r3,PVR - blr - -_GLOBAL(_get_PIR) - mfspr r3,PIR - blr - -_GLOBAL(_get_HID0) - mfspr r3,HID0 - blr _GLOBAL(cvt_fd) lfd 0,0(r5) /* load up fpscr value */ @@ -567,6 +591,69 @@ isync b 1b +#ifdef CONFIG_PPC_PMAC +/* + * Do an IO access in real mode + */ +_GLOBAL(real_readb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + mfspr r6,SPRN_HID4 + rldicl r5,r6,32,0 + ori r5,r5,0x100 + rldicl r5,r5,32,0 + sync + mtspr SPRN_HID4,r5 + isync + slbia + isync + lbz r3,0(r3) + sync + mtspr SPRN_HID4,r6 + isync + slbia + isync + mtmsrd r7 + sync + isync + blr + + /* + * Do an IO access in real mode + */ +_GLOBAL(real_writeb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + mfspr r6,SPRN_HID4 + rldicl r5,r6,32,0 + ori r5,r5,0x100 + rldicl r5,r5,32,0 + sync + mtspr SPRN_HID4,r5 + isync + slbia + isync + stb r3,0(r4) + sync + mtspr SPRN_HID4,r6 + isync + slbia + isync + mtmsrd r7 + sync + isync + blr +#endif /* CONFIG_PPC_PMAC */ /* * Create a kernel thread @@ -583,7 +670,7 @@ li r4,0 /* new sp (unused) */ li r0,__NR_clone sc - cmpi 0,r3,0 /* parent or child? */ + cmpdi 0,r3,0 /* parent or child? */ bne 1f /* return if parent */ li r0,0 stdu r0,-STACK_FRAME_OVERHEAD(r1) @@ -600,7 +687,7 @@ ld r30,-16(r1) blr -#ifdef CONFIG_PPC_ISERIES /* hack hack hack */ +#ifndef CONFIG_PPC_PSERIES /* hack hack hack */ #define ppc_rtas sys_ni_syscall #endif @@ -866,9 +953,9 @@ .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ .llong .sys_ni_syscall /* 257 reserved for vserver */ .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .sys_ni_syscall /* 259 reserved for new sys_mbind */ - .llong .sys_ni_syscall /* 260 reserved for new sys_get_mempolicy */ - .llong .sys_ni_syscall /* 261 reserved for new sys_set_mempolicy */ + .llong .compat_mbind + .llong .compat_get_mempolicy /* 260 */ + .llong .compat_set_mempolicy .llong .compat_sys_mq_open .llong .sys_mq_unlink .llong .compat_sys_mq_timedsend @@ -1138,9 +1225,9 @@ .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ .llong .sys_ni_syscall /* 257 reserved for vserver */ .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .sys_ni_syscall /* 259 reserved for new sys_mbind */ - .llong .sys_ni_syscall /* 260 reserved for new sys_get_mempolicy */ - .llong .sys_ni_syscall /* 261 reserved for new sys_set_mempolicy */ + .llong .sys_mbind + .llong .sys_get_mempolicy /* 260 */ + .llong .sys_set_mempolicy .llong .sys_mq_open .llong .sys_mq_unlink .llong .sys_mq_timedsend diff -Nru a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c --- a/arch/ppc64/kernel/nvram.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc64/kernel/nvram.c 2004-10-18 14:55:54 -07:00 @@ -340,7 +340,7 @@ struct list_head * p; struct nvram_partition * part; struct nvram_partition * new_part = NULL; - struct nvram_partition * free_part; + struct nvram_partition * free_part = NULL; int seq_init[2] = { 0, 0 }; loff_t tmp_index; long size = 0; @@ -603,6 +603,7 @@ } +#ifdef CONFIG_PPC_PSERIES /* nvram_write_error_log * @@ -727,6 +728,7 @@ return 0; } +#endif /* CONFIG_PPC_PSERIES */ module_init(nvram_init); module_exit(nvram_cleanup); diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c --- a/arch/ppc64/kernel/open_pic.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/kernel/open_pic.c 2004-10-18 14:56:33 -07:00 @@ -362,7 +362,6 @@ find_ISUs(); /* Initialize timer interrupts */ - ppc64_boot_msg(0x21, "OpenPic Timer"); for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { /* Disabled, Priority 0 */ openpic_inittimer(i, 0, openpic_vec_timer+i); @@ -372,7 +371,6 @@ #ifdef CONFIG_SMP /* Initialize IPI interrupts */ - ppc64_boot_msg(0x22, "OpenPic IPI"); openpic_test_broken_IPI(); for (i = 0; i < OPENPIC_NUM_IPI; i++) { /* Disabled, Priority 10..13 */ @@ -384,8 +382,6 @@ #endif /* Initialize external interrupts */ - ppc64_boot_msg(0x23, "OpenPic Ext"); - openpic_set_priority(0xf); /* SIOint (8259 cascade) is special */ @@ -420,7 +416,6 @@ irq_desc[i].handler = &open_pic; /* Initialize the spurious interrupt */ - ppc64_boot_msg(0x24, "OpenPic Spurious"); openpic_set_spurious(openpic_vec_spurious); openpic_set_priority(0); diff -Nru a/arch/ppc64/kernel/open_pic_u3.c b/arch/ppc64/kernel/open_pic_u3.c --- a/arch/ppc64/kernel/open_pic_u3.c 2004-10-18 14:55:46 -07:00 +++ b/arch/ppc64/kernel/open_pic_u3.c 2004-10-18 14:55:46 -07:00 @@ -344,5 +344,5 @@ openpic2_set_priority(0); openpic2_disable_8259_pass_through(); - ppc64_boot_msg(0x25, "OpenPic2 Done"); + ppc64_boot_msg(0x25, "OpenPic U3 Done"); } diff -Nru a/arch/ppc64/kernel/pSeries_htab.c b/arch/ppc64/kernel/pSeries_htab.c --- a/arch/ppc64/kernel/pSeries_htab.c 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,408 +0,0 @@ -/* - * pSeries hashtable management. - * - * SMP scalability work: - * Copyright (C) 2001 Anton Blanchard , IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define HPTE_LOCK_BIT 3 - -static inline void pSeries_lock_hpte(HPTE *hptep) -{ - unsigned long *word = &hptep->dw0.dword0; - - while (1) { - if (!test_and_set_bit(HPTE_LOCK_BIT, word)) - break; - while(test_bit(HPTE_LOCK_BIT, word)) - cpu_relax(); - } -} - -static inline void pSeries_unlock_hpte(HPTE *hptep) -{ - unsigned long *word = &hptep->dw0.dword0; - - asm volatile("lwsync":::"memory"); - clear_bit(HPTE_LOCK_BIT, word); -} - -static spinlock_t pSeries_tlbie_lock = SPIN_LOCK_UNLOCKED; - -long pSeries_hpte_insert(unsigned long hpte_group, unsigned long va, - unsigned long prpn, int secondary, - unsigned long hpteflags, int bolted, int large) -{ - unsigned long arpn = physRpn_to_absRpn(prpn); - HPTE *hptep = htab_data.htab + hpte_group; - Hpte_dword0 dw0; - HPTE lhpte; - int i; - - for (i = 0; i < HPTES_PER_GROUP; i++) { - dw0 = hptep->dw0.dw0; - - if (!dw0.v) { - /* retry with lock held */ - pSeries_lock_hpte(hptep); - dw0 = hptep->dw0.dw0; - if (!dw0.v) - break; - pSeries_unlock_hpte(hptep); - } - - hptep++; - } - - if (i == HPTES_PER_GROUP) - return -1; - - lhpte.dw1.dword1 = 0; - lhpte.dw1.dw1.rpn = arpn; - lhpte.dw1.flags.flags = hpteflags; - - lhpte.dw0.dword0 = 0; - lhpte.dw0.dw0.avpn = va >> 23; - lhpte.dw0.dw0.h = secondary; - lhpte.dw0.dw0.bolted = bolted; - lhpte.dw0.dw0.v = 1; - - if (large) { - lhpte.dw0.dw0.l = 1; - lhpte.dw0.dw0.avpn &= ~0x1UL; - } - - hptep->dw1.dword1 = lhpte.dw1.dword1; - - /* Guarantee the second dword is visible before the valid bit */ - __asm__ __volatile__ ("eieio" : : : "memory"); - - /* - * Now set the first dword including the valid bit - * NOTE: this also unlocks the hpte - */ - hptep->dw0.dword0 = lhpte.dw0.dword0; - - __asm__ __volatile__ ("ptesync" : : : "memory"); - - return i | (secondary << 3); -} - -static long pSeries_hpte_remove(unsigned long hpte_group) -{ - HPTE *hptep; - Hpte_dword0 dw0; - int i; - int slot_offset; - - /* pick a random entry to start at */ - slot_offset = mftb() & 0x7; - - for (i = 0; i < HPTES_PER_GROUP; i++) { - hptep = htab_data.htab + hpte_group + slot_offset; - dw0 = hptep->dw0.dw0; - - if (dw0.v && !dw0.bolted) { - /* retry with lock held */ - pSeries_lock_hpte(hptep); - dw0 = hptep->dw0.dw0; - if (dw0.v && !dw0.bolted) - break; - pSeries_unlock_hpte(hptep); - } - - slot_offset++; - slot_offset &= 0x7; - } - - if (i == HPTES_PER_GROUP) - return -1; - - /* Invalidate the hpte. NOTE: this also unlocks it */ - hptep->dw0.dword0 = 0; - - return i; -} - -static inline void set_pp_bit(unsigned long pp, HPTE *addr) -{ - unsigned long old; - unsigned long *p = &addr->dw1.dword1; - - __asm__ __volatile__( - "1: ldarx %0,0,%3\n\ - rldimi %0,%2,0,61\n\ - stdcx. %0,0,%3\n\ - bne 1b" - : "=&r" (old), "=m" (*p) - : "r" (pp), "r" (p), "m" (*p) - : "cc"); -} - -/* - * Only works on small pages. Yes its ugly to have to check each slot in - * the group but we only use this during bootup. - */ -static long pSeries_hpte_find(unsigned long vpn) -{ - HPTE *hptep; - unsigned long hash; - unsigned long i, j; - long slot; - Hpte_dword0 dw0; - - hash = hpt_hash(vpn, 0); - - for (j = 0; j < 2; j++) { - slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; - for (i = 0; i < HPTES_PER_GROUP; i++) { - hptep = htab_data.htab + slot; - dw0 = hptep->dw0.dw0; - - if ((dw0.avpn == (vpn >> 11)) && dw0.v && - (dw0.h == j)) { - /* HPTE matches */ - if (j) - slot = -slot; - return slot; - } - ++slot; - } - hash = ~hash; - } - - return -1; -} - -static long pSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int large, int local) -{ - HPTE *hptep = htab_data.htab + slot; - Hpte_dword0 dw0; - unsigned long avpn = va >> 23; - int ret = 0; - - if (large) - avpn &= ~0x1UL; - - pSeries_lock_hpte(hptep); - - dw0 = hptep->dw0.dw0; - - /* Even if we miss, we need to invalidate the TLB */ - if ((dw0.avpn != avpn) || !dw0.v) { - pSeries_unlock_hpte(hptep); - ret = -1; - } else { - set_pp_bit(newpp, hptep); - pSeries_unlock_hpte(hptep); - } - - /* Ensure it is out of the tlb too */ - if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { - tlbiel(va); - } else { - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_lock(&pSeries_tlbie_lock); - tlbie(va, large); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_unlock(&pSeries_tlbie_lock); - } - - return ret; -} - -/* - * Update the page protection bits. Intended to be used to create - * guard pages for kernel data structures on pages which are bolted - * in the HPT. Assumes pages being operated on will not be stolen. - * Does not work on large pages. - * - * No need to lock here because we should be the only user. - */ -static void pSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea) -{ - unsigned long vsid, va, vpn, flags; - long slot; - HPTE *hptep; - - vsid = get_kernel_vsid(ea); - va = (vsid << 28) | (ea & 0x0fffffff); - vpn = va >> PAGE_SHIFT; - - slot = pSeries_hpte_find(vpn); - if (slot == -1) - panic("could not find page to bolt\n"); - hptep = htab_data.htab + slot; - - set_pp_bit(newpp, hptep); - - /* Ensure it is out of the tlb too */ - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_lock_irqsave(&pSeries_tlbie_lock, flags); - tlbie(va, 0); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_unlock_irqrestore(&pSeries_tlbie_lock, flags); -} - -static void pSeries_hpte_invalidate(unsigned long slot, unsigned long va, - int large, int local) -{ - HPTE *hptep = htab_data.htab + slot; - Hpte_dword0 dw0; - unsigned long avpn = va >> 23; - unsigned long flags; - - if (large) - avpn &= ~0x1UL; - - local_irq_save(flags); - pSeries_lock_hpte(hptep); - - dw0 = hptep->dw0.dw0; - - /* Even if we miss, we need to invalidate the TLB */ - if ((dw0.avpn != avpn) || !dw0.v) { - pSeries_unlock_hpte(hptep); - } else { - /* Invalidate the hpte. NOTE: this also unlocks it */ - hptep->dw0.dword0 = 0; - } - - /* Invalidate the tlb */ - if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { - tlbiel(va); - } else { - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_lock(&pSeries_tlbie_lock); - tlbie(va, large); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_unlock(&pSeries_tlbie_lock); - } - local_irq_restore(flags); -} - -static void pSeries_flush_hash_range(unsigned long context, - unsigned long number, int local) -{ - unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn; - int i, j; - HPTE *hptep; - Hpte_dword0 dw0; - struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - - /* XXX fix for large ptes */ - unsigned long large = 0; - - local_irq_save(flags); - - j = 0; - for (i = 0; i < number; i++) { - if ((batch->addr[i] >= USER_START) && - (batch->addr[i] <= USER_END)) - vsid = get_vsid(context, batch->addr[i]); - else - vsid = get_kernel_vsid(batch->addr[i]); - - va = (vsid << 28) | (batch->addr[i] & 0x0fffffff); - batch->vaddr[j] = va; - if (large) - vpn = va >> LARGE_PAGE_SHIFT; - else - vpn = va >> PAGE_SHIFT; - hash = hpt_hash(vpn, large); - secondary = (pte_val(batch->pte[i]) & _PAGE_SECONDARY) >> 15; - if (secondary) - hash = ~hash; - slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; - slot += (pte_val(batch->pte[i]) & _PAGE_GROUP_IX) >> 12; - - hptep = htab_data.htab + slot; - - avpn = va >> 23; - if (large) - avpn &= ~0x1UL; - - pSeries_lock_hpte(hptep); - - dw0 = hptep->dw0.dw0; - - /* Even if we miss, we need to invalidate the TLB */ - if ((dw0.avpn != avpn) || !dw0.v) { - pSeries_unlock_hpte(hptep); - } else { - /* Invalidate the hpte. NOTE: this also unlocks it */ - hptep->dw0.dword0 = 0; - } - - j++; - } - - if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { - asm volatile("ptesync":::"memory"); - - for (i = 0; i < j; i++) - __tlbiel(batch->vaddr[i]); - - asm volatile("ptesync":::"memory"); - } else { - /* XXX double check that it is safe to take this late */ - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_lock(&pSeries_tlbie_lock); - - asm volatile("ptesync":::"memory"); - - for (i = 0; i < j; i++) - __tlbie(batch->vaddr[i], 0); - - asm volatile("eieio; tlbsync; ptesync":::"memory"); - - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) - spin_unlock(&pSeries_tlbie_lock); - } - - local_irq_restore(flags); -} - -void hpte_init_pSeries(void) -{ - struct device_node *root; - const char *model; - - ppc_md.hpte_invalidate = pSeries_hpte_invalidate; - ppc_md.hpte_updatepp = pSeries_hpte_updatepp; - ppc_md.hpte_updateboltedpp = pSeries_hpte_updateboltedpp; - ppc_md.hpte_insert = pSeries_hpte_insert; - ppc_md.hpte_remove = pSeries_hpte_remove; - - /* Disable TLB batching on nighthawk */ - root = of_find_node_by_path("/"); - if (root) { - model = get_property(root, "model", NULL); - if (!strcmp(model, "CHRP IBM,9076-N81")) { - of_node_put(root); - return; - } - of_node_put(root); - } - - ppc_md.flush_hash_range = pSeries_flush_hash_range; -} diff -Nru a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c --- a/arch/ppc64/kernel/pSeries_iommu.c 2004-10-18 14:56:17 -07:00 +++ b/arch/ppc64/kernel/pSeries_iommu.c 2004-10-18 14:56:17 -07:00 @@ -42,6 +42,7 @@ #include #include #include +#include #include "pci.h" @@ -88,9 +89,153 @@ } +static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, + long npages, unsigned long uaddr, + enum dma_data_direction direction) +{ + u64 rc; + union tce_entry tce; + + tce.te_word = 0; + tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; + tce.te_rdwr = 1; + if (direction != DMA_TO_DEVICE) + tce.te_pciwr = 1; + + while (npages--) { + rc = plpar_tce_put((u64)tbl->it_index, + (u64)tcenum << 12, + tce.te_word ); + + if (rc && printk_ratelimit()) { + printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\ttcenum = 0x%lx\n", (u64)tcenum); + printk("\ttce val = 0x%lx\n", tce.te_word ); + show_stack(current, (unsigned long *)__get_SP()); + } + + tcenum++; + tce.te_rpn++; + } +} + +DEFINE_PER_CPU(void *, tce_page) = NULL; + +static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, + long npages, unsigned long uaddr, + enum dma_data_direction direction) +{ + u64 rc; + union tce_entry tce, *tcep; + long l, limit; + + if (npages == 1) + return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, + direction); + + tcep = __get_cpu_var(tce_page); + + /* This is safe to do since interrupts are off when we're called + * from iommu_alloc{,_sg}() + */ + if (!tcep) { + tcep = (void *)__get_free_page(GFP_ATOMIC); + /* If allocation fails, fall back to the loop implementation */ + if (!tcep) + return tce_build_pSeriesLP(tbl, tcenum, npages, + uaddr, direction); + __get_cpu_var(tce_page) = tcep; + } + + tce.te_word = 0; + tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; + tce.te_rdwr = 1; + if (direction != DMA_TO_DEVICE) + tce.te_pciwr = 1; + + /* We can map max one pageful of TCEs at a time */ + do { + /* + * Set up the page with TCE data, looping through and setting + * the values. + */ + limit = min_t(long, npages, PAGE_SIZE/sizeof(union tce_entry)); + + for (l = 0; l < limit; l++) { + tcep[l] = tce; + tce.te_rpn++; + } + + rc = plpar_tce_put_indirect((u64)tbl->it_index, + (u64)tcenum << 12, + (u64)virt_to_abs(tcep), + limit); + + npages -= limit; + tcenum += limit; + } while (npages > 0 && !rc); + + if (rc && printk_ratelimit()) { + printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\tnpages = 0x%lx\n", (u64)npages); + printk("\ttce[0] val = 0x%lx\n", tcep[0].te_word); + show_stack(current, (unsigned long *)__get_SP()); + } +} + +static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) +{ + u64 rc; + union tce_entry tce; + + tce.te_word = 0; + + while (npages--) { + rc = plpar_tce_put((u64)tbl->it_index, + (u64)tcenum << 12, + tce.te_word); + + if (rc && printk_ratelimit()) { + printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\ttcenum = 0x%lx\n", (u64)tcenum); + printk("\ttce val = 0x%lx\n", tce.te_word ); + show_stack(current, (unsigned long *)__get_SP()); + } + + tcenum++; + } +} + + +static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) +{ + u64 rc; + union tce_entry tce; + + tce.te_word = 0; + + rc = plpar_tce_stuff((u64)tbl->it_index, + (u64)tcenum << 12, + tce.te_word, + npages); + + if (rc && printk_ratelimit()) { + printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); + printk("\trc = %ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\tnpages = 0x%lx\n", (u64)npages); + printk("\ttce val = 0x%lx\n", tce.te_word ); + show_stack(current, (unsigned long *)__get_SP()); + } +} + + static void iommu_buses_init(void) { - struct pci_controller* phb; + struct pci_controller *phb, *tmp; struct device_node *dn, *first_dn; int num_slots, num_slots_ilog2; int first_phb = 1; @@ -106,10 +251,10 @@ else tcetable_ilog2 = 22; - /* XXX Should we be using pci_root_buses instead? -ojn + /* XXX Should we be using pci_root_buses instead? -ojn */ - for (phb=hose_head; phb; phb=phb->next) { + list_for_each_entry_safe(phb, tmp, &hose_list, list_node) { first_dn = ((struct device_node *)phb->arch_data)->child; /* Carve 2GB into the largest dma_window_size possible */ @@ -166,24 +311,25 @@ struct device_node *dn, struct iommu_table *tbl) { - phandle node; - unsigned long i; - struct of_tce_table *oft; - - node = ((struct device_node *)(phb->arch_data))->node; - - oft = NULL; - - for (i=0; of_tce_table[i].node; i++) - if(of_tce_table[i].node == node) { - oft = &of_tce_table[i]; - break; - } - - if (!oft) - panic("PCI_DMA: iommu_table_setparms: Can't find phb named '%s' in of_tce_table\n", dn->full_name); - - memset((void *)oft->base, 0, oft->size); + struct device_node *node; + unsigned long *basep; + unsigned int *sizep; + + node = (struct device_node *)phb->arch_data; + + if (get_property(node, "linux,has-tce-table", NULL) == NULL) { + printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has no tce table !\n", + dn->full_name); + return; + } + basep = (unsigned long *)get_property(node, "linux,tce-base", NULL); + sizep = (unsigned int *)get_property(node, "linux,tce-size", NULL); + if (basep == NULL || sizep == NULL) { + printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has missing tce" + " entries !\n", dn->full_name); + return; + } + memset((void *)(*basep), 0, *sizep); tbl->it_busno = phb->bus->number; @@ -207,10 +353,11 @@ if (phb->dma_window_base_cur > (1 << 19)) panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); - tbl->it_base = oft->base; + tbl->it_base = *basep; tbl->it_index = 0; tbl->it_entrysize = sizeof(union tce_entry); tbl->it_blocksize = 16; + tbl->it_type = TCE_PCI; } /* @@ -246,6 +393,7 @@ tbl->it_index = dma_window[0]; tbl->it_entrysize = sizeof(union tce_entry); tbl->it_blocksize = 16; + tbl->it_type = TCE_PCI; } @@ -293,8 +441,16 @@ /* These are called very early. */ void tce_init_pSeries(void) { - ppc_md.tce_build = tce_build_pSeries; - ppc_md.tce_free = tce_free_pSeries; + if (!(systemcfg->platform & PLATFORM_LPAR)) { + ppc_md.tce_build = tce_build_pSeries; + ppc_md.tce_free = tce_free_pSeries; + } else if (cur_cpu_spec->firmware_features & FW_FEATURE_MULTITCE) { + ppc_md.tce_build = tce_buildmulti_pSeriesLP; + ppc_md.tce_free = tce_freemulti_pSeriesLP; + } else { + ppc_md.tce_build = tce_build_pSeriesLP; + ppc_md.tce_free = tce_free_pSeriesLP; + } pci_iommu_init(); } diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c --- a/arch/ppc64/kernel/pSeries_lpar.c 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc64/kernel/pSeries_lpar.c 2004-10-18 14:57:05 -07:00 @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define DEBUG + #include #include #include @@ -34,10 +36,16 @@ #include #include #include -#include #include #include #include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif /* in pSeries_hvCall.S */ EXPORT_SYMBOL(plpar_hcall); @@ -45,146 +53,9 @@ EXPORT_SYMBOL(plpar_hcall_norets); EXPORT_SYMBOL(plpar_hcall_8arg_2ret); -long poll_pending(void) -{ - unsigned long dummy; - return plpar_hcall(H_POLL_PENDING, 0, 0, 0, 0, - &dummy, &dummy, &dummy); -} - -long prod_processor(void) -{ - plpar_hcall_norets(H_PROD); - return(0); -} - -long cede_processor(void) -{ - plpar_hcall_norets(H_CEDE); - return(0); -} - -long register_vpa(unsigned long flags, unsigned long proc, unsigned long vpa) -{ - plpar_hcall_norets(H_REGISTER_VPA, flags, proc, vpa); - return(0); -} - -long plpar_pte_remove(unsigned long flags, - unsigned long ptex, - unsigned long avpn, - unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) -{ - unsigned long dummy; - return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0, - old_pteh_ret, old_ptel_ret, &dummy); -} - -long plpar_pte_read(unsigned long flags, - unsigned long ptex, - unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) -{ - unsigned long dummy; - return plpar_hcall(H_READ, flags, ptex, 0, 0, - old_pteh_ret, old_ptel_ret, &dummy); -} - -long plpar_pte_protect(unsigned long flags, - unsigned long ptex, - unsigned long avpn) -{ - return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn); -} - -long plpar_tce_get(unsigned long liobn, - unsigned long ioba, - unsigned long *tce_ret) -{ - unsigned long dummy; - return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0, - tce_ret, &dummy, &dummy); -} +extern void fw_feature_init(void); +extern void pSeries_find_serial_port(void); -long plpar_tce_put(unsigned long liobn, - unsigned long ioba, - unsigned long tceval) -{ - return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval); -} - -long plpar_get_term_char(unsigned long termno, - unsigned long *len_ret, - char *buf_ret) -{ - unsigned long *lbuf = (unsigned long *)buf_ret; /* ToDo: alignment? */ - return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0, - len_ret, lbuf+0, lbuf+1); -} - -long plpar_put_term_char(unsigned long termno, - unsigned long len, - const char *buffer) -{ - unsigned long *lbuf = (unsigned long *)buffer; /* ToDo: alignment? */ - return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0], - lbuf[1]); -} - -static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, - long npages, unsigned long uaddr, - enum dma_data_direction direction) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; - tce.te_rdwr = 1; - if (direction != DMA_TO_DEVICE) - tce.te_pciwr = 1; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - - if (rc && printk_ratelimit()) { - printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - tce.te_rpn++; - } -} - -static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - - if (rc && printk_ratelimit()) { - printk("tce_free_pSeriesLP: plpar_tce_put failed\n"); - printk("\trc = %ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - } -} int vtermno; /* virtual terminal# for udbg */ @@ -249,8 +120,19 @@ } } +/* call this from early_init() for a working debug console on + * vterm capable LPAR machines + */ +void udbg_init_debug_lpar(void) +{ + vtermno = 0; + ppc_md.udbg_putc = udbg_putcLP; + ppc_md.udbg_getc = udbg_getcLP; + ppc_md.udbg_getc_poll = udbg_getc_pollLP; +} + /* returns 0 if couldn't find or use /chosen/stdout as console */ -static int find_udbg_vterm(void) +int find_udbg_vterm(void) { struct device_node *stdout_node; u32 *termno; @@ -258,15 +140,14 @@ int found = 0; /* find the boot console from /chosen/stdout */ - if (!of_stdout_device) { - printk(KERN_WARNING "couldn't get path from /chosen/stdout!\n"); - return found; - } - stdout_node = of_find_node_by_path(of_stdout_device); - if (!stdout_node) { - printk(KERN_WARNING "couldn't find node from /chosen/stdout\n"); - return found; - } + if (!of_chosen) + return 0; + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) + return 0; + stdout_node = of_find_node_by_path(name); + if (!stdout_node) + return 0; /* now we have the stdout node; figure out what type of device it is. */ name = (char *)get_property(stdout_node, "name", NULL); @@ -288,15 +169,17 @@ } else { /* XXX implement udbg_putcLP_vtty for hvterm-protocol1 case */ printk(KERN_WARNING "%s doesn't speak hvterm1; " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } } else if (strncmp(name, "serial", 6)) { /* XXX fix ISA serial console */ printk(KERN_WARNING "serial stdout on LPAR ('%s')! " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } else { printk(KERN_WARNING "don't know how to print to stdout '%s'\n", - of_stdout_device); + stdout_node->full_name); } out: @@ -304,35 +187,6 @@ return found; } -void pSeries_lpar_mm_init(void); - -/* This is called early in setup.c. - * Use it to setup page table ppc_md stuff as well as udbg. - */ -void pSeriesLP_init_early(void) -{ - pSeries_lpar_mm_init(); - - tce_init_pSeries(); - - ppc_md.tce_build = tce_build_pSeriesLP; - ppc_md.tce_free = tce_free_pSeriesLP; - - pci_iommu_init(); - -#ifdef CONFIG_SMP - smp_init_pSeries(); -#endif - - /* The keyboard is not useful in the LPAR environment. - * Leave all the ppc_md keyboard interfaces NULL. - */ - - if (0 == find_udbg_vterm()) { - printk(KERN_WARNING - "can't use stdout; can't print early debug messages.\n"); - } -} long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long prpn, @@ -377,7 +231,7 @@ lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, lhpte.dw0.dword0, lhpte.dw1.dword1, &slot, &dummy0, &dummy1); - if (lpar_rc == H_PTEG_Full) + if (unlikely(lpar_rc == H_PTEG_Full)) return -1; /* @@ -385,7 +239,7 @@ * will fail. However we must catch the failure in hash_page * or we will loop forever, so return -2 in this case. */ - if (lpar_rc != H_Success) + if (unlikely(lpar_rc != H_Success)) return -2; /* Because of iSeries, we have to pass down the secondary @@ -415,9 +269,7 @@ if (lpar_rc == H_Success) return i; - if (lpar_rc != H_Not_Found) - panic("Bad return code from pte remove rc = %lx\n", - lpar_rc); + BUG_ON(lpar_rc != H_Not_Found); slot_offset++; slot_offset &= 0x7; @@ -426,6 +278,18 @@ return -1; } +static void pSeries_lpar_hptab_clear(void) +{ + unsigned long size_bytes = 1UL << naca->pftSize; + unsigned long hpte_count = size_bytes >> 4; + unsigned long dummy1, dummy2; + int i; + + /* TODO: Use bulk call */ + for (i = 0; i < hpte_count; i++) + plpar_pte_remove(0, i, 0, &dummy1, &dummy2); +} + /* * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and * the low 3 bits of flags happen to line up. So no transform is needed. @@ -447,8 +311,7 @@ if (lpar_rc == H_Not_Found) return -1; - if (lpar_rc != H_Success) - panic("bad return code from pte protect rc = %lx\n", lpar_rc); + BUG_ON(lpar_rc != H_Success); return 0; } @@ -464,11 +327,10 @@ /* Do not need RPN to logical page translation */ /* No cross CEC PFT access */ flags = 0; - + lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1); - if (lpar_rc != H_Success) - panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc); + BUG_ON(lpar_rc != H_Success); return dword0; } @@ -519,15 +381,12 @@ vpn = va >> PAGE_SHIFT; slot = pSeries_lpar_hpte_find(vpn); - if (slot == -1) - panic("updateboltedpp: Could not find page to bolt\n"); + BUG_ON(slot == -1); flags = newpp & 3; lpar_rc = plpar_pte_protect(flags, slot, 0); - if (lpar_rc != H_Success) - panic("Bad return code from pte bolted protect rc = %lx\n", - lpar_rc); + BUG_ON(lpar_rc != H_Success); } static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, @@ -546,8 +405,7 @@ if (lpar_rc == H_Not_Found) return; - if (lpar_rc != H_Success) - panic("Bad return code from invalidate rc = %lx\n", lpar_rc); + BUG_ON(lpar_rc != H_Success); } /* @@ -560,18 +418,19 @@ int i; unsigned long flags; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); for (i = 0; i < number; i++) flush_hash_page(context, batch->addr[i], batch->pte[i], local); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); } -void pSeries_lpar_mm_init(void) +void hpte_init_lpar(void) { ppc_md.hpte_invalidate = pSeries_lpar_hpte_invalidate; ppc_md.hpte_updatepp = pSeries_lpar_hpte_updatepp; @@ -579,4 +438,7 @@ ppc_md.hpte_insert = pSeries_lpar_hpte_insert; ppc_md.hpte_remove = pSeries_lpar_hpte_remove; ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; + ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; + + htab_finish_init(); } diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c --- a/arch/ppc64/kernel/pSeries_pci.c 2004-10-18 14:57:18 -07:00 +++ b/arch/ppc64/kernel/pSeries_pci.c 2004-10-18 14:57:18 -07:00 @@ -45,12 +45,6 @@ #include "open_pic.h" #include "pci.h" -/* legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch - devices we don't have access to. */ -unsigned long io_page_mask; - -EXPORT_SYMBOL(io_page_mask); - /* RTAS tokens */ static int read_pci_config; static int write_pci_config; @@ -68,7 +62,9 @@ int ret; if (!dn) - return -2; + return PCIBIOS_DEVICE_NOT_FOUND; + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = (dn->busno << 16) | (dn->devfn << 8) | where; buid = dn->phb->buid; @@ -79,7 +75,15 @@ ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); } *val = returnval; - return ret; + + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (returnval == EEH_IO_ERROR_VALUE(size) + && eeh_dn_check_failure (dn, NULL)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; } static int rtas_pci_read_config(struct pci_bus *bus, @@ -106,7 +110,9 @@ int ret; if (!dn) - return -2; + return PCIBIOS_DEVICE_NOT_FOUND; + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = (dn->busno << 16) | (dn->devfn << 8) | where; buid = dn->phb->buid; @@ -115,7 +121,11 @@ } else { ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); } - return ret; + + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; } static int rtas_pci_write_config(struct pci_bus *bus, @@ -141,189 +151,6 @@ rtas_pci_write_config }; -/****************************************************************** - * pci_read_irq_line - * - * Reads the Interrupt Pin to determine if interrupt is use by card. - * If the interrupt is used, then gets the interrupt line from the - * openfirmware and sets it in the pci_dev and pci_config line. - * - ******************************************************************/ -int pci_read_irq_line(struct pci_dev *pci_dev) -{ - u8 intpin; - struct device_node *node; - - pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin); - - if (intpin == 0) { - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n", pci_name(pci_dev)); - return 0; - } - - node = pci_device_to_OF_node(pci_dev); - if (node == NULL) { - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n", - pci_name(pci_dev)); - return -1; - } - if (node->n_intrs == 0) { - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n", pci_name(pci_dev)); - return -1; - } - pci_dev->irq = node->intrs[0].line; - - if (s7a_workaround) { - if (pci_dev->irq > 16) - pci_dev->irq -= 3; - } - - pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); - - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n", - pci_name(pci_dev), pci_dev->irq); - return 0; -} -EXPORT_SYMBOL(pci_read_irq_line); - -#define ISA_SPACE_MASK 0x1 -#define ISA_SPACE_IO 0x1 - -static void pci_process_ISA_OF_ranges(struct device_node *isa_node, - unsigned long phb_io_base_phys, - void * phb_io_base_virt) -{ - struct isa_range *range; - unsigned long pci_addr; - unsigned int isa_addr; - unsigned int size; - int rlen = 0; - - range = (struct isa_range *) get_property(isa_node, "ranges", &rlen); - if (rlen < sizeof(struct isa_range)) { - printk(KERN_ERR "unexpected isa range size: %s\n", - __FUNCTION__); - return; - } - - /* From "ISA Binding to 1275" - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 1: an ISA address - * cells 2 - 4: a PCI address - * (size depending on dev->n_addr_cells) - * cell 5: the size of the range - */ - if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) { - isa_addr = range->isa_addr.a_lo; - pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | - range->pci_addr.a_lo; - - /* Assume these are both zero */ - if ((pci_addr != 0) || (isa_addr != 0)) { - printk(KERN_ERR "unexpected isa to pci mapping: %s\n", - __FUNCTION__); - return; - } - - size = PAGE_ALIGN(range->size); - - __ioremap_explicit(phb_io_base_phys, - (unsigned long) phb_io_base_virt, - size, _PAGE_NO_CACHE); - } -} - -static void __init pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, - int primary) -{ - unsigned int *ranges; - unsigned long size; - int rlen = 0; - int memno = 0; - struct resource *res; - int np, na = prom_n_addr_cells(dev); - unsigned long pci_addr, cpu_phys_addr; - struct device_node *isa_dn; - - np = na + 5; - - /* From "PCI Binding to 1275" - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 2: a PCI address - * cells 3 or 3+4: a CPU physical address - * (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) { - res = NULL; - pci_addr = (unsigned long)ranges[1] << 32 | ranges[2]; - - cpu_phys_addr = ranges[3]; - if (na == 2) - cpu_phys_addr = cpu_phys_addr << 32 | ranges[4]; - - size = (unsigned long)ranges[na+3] << 32 | ranges[na+4]; - - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - hose->io_base_phys = cpu_phys_addr; - hose->io_base_virt = reserve_phb_iospace(size); - PPCDBG(PPCDBG_PHBINIT, - "phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", - hose->global_number, hose->io_base_phys, - (unsigned long) hose->io_base_virt); - - if (primary) { - pci_io_base = (unsigned long)hose->io_base_virt; - isa_dn = of_find_node_by_type(NULL, "isa"); - if (isa_dn) { - isa_io_base = pci_io_base; - pci_process_ISA_OF_ranges(isa_dn, - hose->io_base_phys, - hose->io_base_virt); - of_node_put(isa_dn); - /* Allow all IO */ - io_page_mask = -1; - } - } - - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = pci_addr; - res->start += (unsigned long)hose->io_base_virt - - pci_io_base; - break; - case 2: /* memory space */ - memno = 0; - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - - if (memno == 0) - hose->pci_mem_offset = cpu_phys_addr - pci_addr; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = cpu_phys_addr; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += np; - } -} - static void python_countermeasures(unsigned long addr) { void *chip_regs; @@ -481,7 +308,7 @@ struct pci_controller *phb; unsigned int root_size_cells = 0; unsigned int index; - unsigned int *opprop; + unsigned int *opprop = NULL; struct device_node *root = of_find_node_by_path("/"); if (naca->interrupt_controller == IC_OPEN_PIC) { @@ -519,9 +346,9 @@ return 0; } +#if 0 void pcibios_name_device(struct pci_dev *dev) { -#if 0 struct device_node *dn; /* @@ -541,98 +368,9 @@ } } } -#endif } - -void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus) -{ - /* Update device resources. */ - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; - unsigned long start, end, mask; - - start = dev->resource[i].start += offset; - end = dev->resource[i].end += offset; - - /* Need to allow IO access to pages that are in the - ISA range */ - if (start < MAX_ISA_PORT) { - if (end > MAX_ISA_PORT) - end = MAX_ISA_PORT; - - start >>= PAGE_SHIFT; - end >>= PAGE_SHIFT; - - /* get the range of pages for the map */ - mask = ((1 << (end+1))-1) ^ ((1 << start)-1); - io_page_mask |= mask; - } - } - else if (dev->resource[i].flags & IORESOURCE_MEM) { - dev->resource[i].start += hose->pci_mem_offset; - dev->resource[i].end += hose->pci_mem_offset; - } - } -} -EXPORT_SYMBOL(pcibios_fixup_device_resources); - -void __devinit pcibios_fixup_bus(struct pci_bus *bus) -{ - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); - struct list_head *ln; - - /* XXX or bus->parent? */ - struct pci_dev *dev = bus->self; - struct resource *res; - int i; - - if (!dev) { - /* Root bus. */ - - hose->bus = bus; - bus->resource[0] = res = &hose->io_resource; - if (!res->flags) - BUG(); /* No I/O resource for this PHB? */ - - if (request_resource(&ioport_resource, res)) - printk(KERN_ERR "Failed to request IO on " - "PCI domain %d\n", pci_domain_nr(bus)); - - - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - if (!res->flags && i == 0) - BUG(); /* No memory resource for this PHB? */ - bus->resource[i+1] = res; - if (res->flags && request_resource(&iomem_resource, res)) - printk(KERN_ERR "Failed to request MEM on " - "PCI domain %d\n", - pci_domain_nr(bus)); - } - } else if (pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - /* This is a subordinate bridge */ - - pci_read_bridge_bases(bus); - pcibios_fixup_device_resources(dev, bus); - } - - /* XXX Need to check why Alpha doesnt do this - Anton */ - if (!pci_probe_only) - return; - - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *dev = pci_dev_b(ln); - if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) - pcibios_fixup_device_resources(dev, bus); - } -} -EXPORT_SYMBOL(pcibios_fixup_bus); +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); +#endif static void check_s7a(void) { @@ -728,13 +466,34 @@ static void phbs_fixup_io(void) { - struct pci_controller *hose; + struct pci_controller *hose, *tmp; - for (hose=hose_head;hose;hose=hose->next) + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) remap_bus_range(hose->bus); } -extern void chrp_request_regions(void); +static void __init pSeries_request_regions(void) +{ + struct device_node *i8042; + + request_region(0x20,0x20,"pic1"); + request_region(0xa0,0x20,"pic2"); + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); + +#define I8042_DATA_REG 0x60 + + /* + * Some machines have an unterminated i8042 so check the device + * tree and reserve the region if it does not appear. Later on + * the i8042 code will try and reserve this region and fail. + */ + if (!(i8042 = of_find_node_by_type(NULL, "8042"))) + request_region(I8042_DATA_REG, 16, "reserved (no i8042)"); + of_node_put(i8042); +} void __init pSeries_final_fixup(void) { @@ -742,58 +501,23 @@ check_s7a(); - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_irq_line(dev); + if (s7a_workaround) { + if (dev->irq > 16) { + dev->irq -= 3; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + } + } phbs_fixup_io(); - chrp_request_regions(); + pSeries_request_regions(); pci_fix_bus_sysdata(); - if (!ppc64_iommu_off) - iommu_setup_pSeries(); -} -/*********************************************************************** - * pci_find_hose_for_OF_device - * - * This function finds the PHB that matching device_node in the - * OpenFirmware by scanning all the pci_controllers. - * - ***********************************************************************/ -struct pci_controller* -pci_find_hose_for_OF_device(struct device_node *node) -{ - while (node) { - struct pci_controller *hose; - for (hose=hose_head;hose;hose=hose->next) - if (hose->arch_data == node) - return hose; - node=node->parent; - } - 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; + if (!of_chosen || !get_property(of_chosen, "linux,iommu-off", NULL)) + iommu_setup_pSeries(); - return 0; + pci_addr_cache_build(); } + diff -Nru a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/kernel/pSeries_setup.c 2004-10-18 14:55:55 -07:00 @@ -0,0 +1,579 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified by PPC64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * bootup setup stuff.. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i8259.h" +#include "open_pic.h" +#include +#include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +extern void pSeries_init_openpic(void); + +extern void find_and_init_phbs(void); +extern void pSeries_final_fixup(void); + +extern void pSeries_get_boot_time(struct rtc_time *rtc_time); +extern void pSeries_get_rtc_time(struct rtc_time *rtc_time); +extern int pSeries_set_rtc_time(struct rtc_time *rtc_time); +extern void find_udbg_vterm(void); +extern void SystemReset_FWNMI(void), MachineCheck_FWNMI(void); /* from head.S */ +int fwnmi_active; /* TRUE if an FWNMI handler is present */ + +unsigned long virtPython0Facilities = 0; // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address. + +extern unsigned long loops_per_jiffy; + +extern unsigned long ppc_proc_freq; +extern unsigned long ppc_tb_freq; + +void pSeries_get_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + const char *model = ""; + + root = of_find_node_by_path("/"); + if (root) + model = get_property(root, "model", NULL); + seq_printf(m, "machine\t\t: CHRP %s\n", model); + of_node_put(root); +} + +/* Initialize firmware assisted non-maskable interrupts if + * the firmware supports this feature. + * + */ +static void __init fwnmi_init(void) +{ + int ret; + int ibm_nmi_register = rtas_token("ibm,nmi-register"); + if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE) + return; + ret = rtas_call(ibm_nmi_register, 2, 1, NULL, + __pa((unsigned long)SystemReset_FWNMI), + __pa((unsigned long)MachineCheck_FWNMI)); + if (ret == 0) + fwnmi_active = 1; +} + +static void __init pSeries_setup_arch(void) +{ + struct device_node *root; + unsigned int *opprop; + + /* Fixup ppc_md depending on the type of interrupt controller */ + if (naca->interrupt_controller == IC_OPEN_PIC) { + ppc_md.init_IRQ = pSeries_init_openpic; + ppc_md.get_irq = openpic_get_irq; + } else { + ppc_md.init_IRQ = xics_init_IRQ; + ppc_md.get_irq = xics_get_irq; + } + +#ifdef CONFIG_SMP + smp_init_pSeries(); +#endif + /* openpic global configuration register (64-bit format). */ + /* openpic Interrupt Source Unit pointer (64-bit format). */ + /* python0 facility area (mmio) (64-bit format) REAL address. */ + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + if (ROOT_DEV == 0) { + printk("No ramdisk, default root is /dev/sda2\n"); + ROOT_DEV = Root_SDA2; + } + + fwnmi_init(); + + /* Find and initialize PCI host bridges */ + /* iSeries needs to be done much later. */ + eeh_init(); + find_and_init_phbs(); + + /* Find the Open PIC if present */ + root = of_find_node_by_path("/"); + opprop = (unsigned int *) get_property(root, + "platform-open-pic", NULL); + if (opprop != 0) { + int n = prom_n_addr_cells(root); + unsigned long openpic; + + for (openpic = 0; n > 0; --n) + openpic = (openpic << 32) + *opprop++; + printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic); + OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE); + } + of_node_put(root); + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + + pSeries_nvram_init(); +} + +static int __init pSeries_init_panel(void) +{ + /* Manually leave the kernel version on the panel. */ + ppc_md.progress("Linux ppc64\n", 0); + ppc_md.progress(UTS_RELEASE, 0); + + return 0; +} +arch_initcall(pSeries_init_panel); + + + +void __init pSeries_find_serial_port(void) +{ + struct device_node *np; + unsigned long encode_phys_size = 32; + u32 *sizeprop; + + struct isa_reg_property { + u32 space; + u32 address; + u32 size; + }; + struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; + }; + + DBG(" -> pSeries_find_serial_port()\n"); + + naca->serialPortAddr = 0; + + np = of_find_node_by_path("/"); + if (!np) + return; + sizeprop = (u32 *)get_property(np, "#size-cells", NULL); + if (sizeprop != NULL) + encode_phys_size = (*sizeprop) << 5; + + for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { + struct device_node *isa, *pci; + struct isa_reg_property *reg; + union pci_range *rangesp; + char *typep; + + typep = (char *)get_property(np, "ibm,aix-loc", NULL); + if ((typep == NULL) || (typep && strcmp(typep, "S1"))) + continue; + + reg = (struct isa_reg_property *)get_property(np, "reg", NULL); + + isa = of_get_parent(np); + if (!isa) { + DBG("no isa parent found\n"); + break; + } + pci = of_get_parent(isa); + if (!pci) { + DBG("no pci parent found\n"); + break; + } + + rangesp = (union pci_range *)get_property(pci, "ranges", NULL); + + if ( encode_phys_size == 32 ) + naca->serialPortAddr = rangesp->pci32.phys+reg->address; + else { + naca->serialPortAddr = + ((((unsigned long)rangesp->pci64.phys_hi) << 32) + | + (rangesp->pci64.phys_lo)) + reg->address; + } + break; + } + + DBG(" <- pSeries_find_serial_port()\n"); +} + + +/* Build up the firmware_features bitmask field + * using contents of device-tree/ibm,hypertas-functions. + * Ultimately this functionality may be moved into prom.c prom_init(). + */ +void __init fw_feature_init(void) +{ + struct device_node * dn; + char * hypertas; + unsigned int len; + + DBG(" -> fw_feature_init()\n"); + + cur_cpu_spec->firmware_features = 0; + dn = of_find_node_by_path("/rtas"); + if (dn == NULL) { + printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n"); + goto no_rtas; + } + + hypertas = get_property(dn, "ibm,hypertas-functions", &len); + if (hypertas) { + while (len > 0){ + int i, hypertas_len; + /* check value against table of strings */ + for(i=0; i < FIRMWARE_MAX_FEATURES ;i++) { + if ((firmware_features_table[i].name) && + (strcmp(firmware_features_table[i].name,hypertas))==0) { + /* we have a match */ + cur_cpu_spec->firmware_features |= + (firmware_features_table[i].val); + break; + } + } + hypertas_len = strlen(hypertas); + len -= hypertas_len +1; + hypertas+= hypertas_len +1; + } + } + + of_node_put(dn); + no_rtas: + printk(KERN_INFO "firmware_features = 0x%lx\n", + cur_cpu_spec->firmware_features); + + DBG(" <- fw_feature_init()\n"); +} + + +static void __init pSeries_discover_pic(void) +{ + struct device_node *np; + char *typep; + + /* + * Setup interrupt mapping options that are needed for finish_device_tree + * to properly parse the OF interrupt tree & do the virtual irq mapping + */ + __irq_offset_value = NUM_ISA_INTERRUPTS; + naca->interrupt_controller = IC_INVALID; + for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { + typep = (char *)get_property(np, "compatible", NULL); + if (strstr(typep, "open-pic")) + naca->interrupt_controller = IC_OPEN_PIC; + else if (strstr(typep, "ppc-xicp")) + naca->interrupt_controller = IC_PPC_XIC; + else + printk("initialize_naca: failed to recognize" + " interrupt-controller\n"); + break; + } +} + +/* + * Early initialization. Relocation is on but do not reference unbolted pages + */ +static void __init pSeries_init_early(void) +{ + void *comport; + int iommu_off = 0; + + DBG(" -> pSeries_init_early()\n"); + + fw_feature_init(); + + if (systemcfg->platform & PLATFORM_LPAR) + hpte_init_lpar(); + else { + hpte_init_native(); + iommu_off = (of_chosen && + get_property(of_chosen, "linux,iommu-off", NULL)); + } + + pSeries_find_serial_port(); + + if (systemcfg->platform & PLATFORM_LPAR) + find_udbg_vterm(); + else if (naca->serialPortAddr) { + /* Map the uart for udbg. */ + comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE); + udbg_init_uart(comport); + + ppc_md.udbg_putc = udbg_putc; + ppc_md.udbg_getc = udbg_getc; + ppc_md.udbg_getc_poll = udbg_getc_poll; + DBG("Hello World !\n"); + } + + + if (iommu_off) + pci_dma_init_direct(); + else + tce_init_pSeries(); + + pSeries_discover_pic(); + + DBG(" <- pSeries_init_early()\n"); +} + + +static void pSeries_progress(char *s, unsigned short hex) +{ + struct device_node *root; + int width, *p; + char *os; + static int display_character, set_indicator; + static int max_width; + static spinlock_t progress_lock = SPIN_LOCK_UNLOCKED; + static int pending_newline = 0; /* did last write end with unprinted newline? */ + + if (!rtas.base) + return; + + if (max_width == 0) { + if ((root = find_path_device("/rtas")) && + (p = (unsigned int *)get_property(root, + "ibm,display-line-length", + NULL))) + max_width = *p; + else + max_width = 0x10; + display_character = rtas_token("display-character"); + set_indicator = rtas_token("set-indicator"); + } + + if (display_character == RTAS_UNKNOWN_SERVICE) { + /* use hex display if available */ + if (set_indicator != RTAS_UNKNOWN_SERVICE) + rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); + return; + } + + spin_lock(&progress_lock); + + /* + * Last write ended with newline, but we didn't print it since + * it would just clear the bottom line of output. Print it now + * instead. + * + * If no newline is pending, print a CR to start output at the + * beginning of the line. + */ + if (pending_newline) { + rtas_call(display_character, 1, 1, NULL, '\r'); + rtas_call(display_character, 1, 1, NULL, '\n'); + pending_newline = 0; + } else { + rtas_call(display_character, 1, 1, NULL, '\r'); + } + + width = max_width; + os = s; + while (*os) { + if (*os == '\n' || *os == '\r') { + /* Blank to end of line. */ + while (width-- > 0) + rtas_call(display_character, 1, 1, NULL, ' '); + + /* If newline is the last character, save it + * until next call to avoid bumping up the + * display output. + */ + if (*os == '\n' && !os[1]) { + pending_newline = 1; + spin_unlock(&progress_lock); + return; + } + + /* RTAS wants CR-LF, not just LF */ + + if (*os == '\n') { + rtas_call(display_character, 1, 1, NULL, '\r'); + rtas_call(display_character, 1, 1, NULL, '\n'); + } else { + /* CR might be used to re-draw a line, so we'll + * leave it alone and not add LF. + */ + rtas_call(display_character, 1, 1, NULL, *os); + } + + width = max_width; + } else { + width--; + rtas_call(display_character, 1, 1, NULL, *os); + } + + os++; + + /* if we overwrite the screen length */ + if (width <= 0) + while ((*os != 0) && (*os != '\n') && (*os != '\r')) + os++; + } + + /* Blank to end of line. */ + while (width-- > 0) + rtas_call(display_character, 1, 1, NULL, ' '); + + spin_unlock(&progress_lock); +} + +extern void setup_default_decr(void); + +/* Some sane defaults: 125 MHz timebase, 1GHz processor */ +#define DEFAULT_TB_FREQ 125000000UL +#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) + +static void __init pSeries_calibrate_decr(void) +{ + struct device_node *cpu; + struct div_result divres; + unsigned int *fp; + int node_found; + + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + cpu = of_find_node_by_type(NULL, "cpu"); + + ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */ + node_found = 0; + if (cpu != 0) { + fp = (unsigned int *)get_property(cpu, "timebase-frequency", + NULL); + if (fp != 0) { + node_found = 1; + ppc_tb_freq = *fp; + } + } + if (!node_found) + printk(KERN_ERR "WARNING: Estimating decrementer frequency " + "(not found)\n"); + + ppc_proc_freq = DEFAULT_PROC_FREQ; + node_found = 0; + if (cpu != 0) { + fp = (unsigned int *)get_property(cpu, "clock-frequency", + NULL); + if (fp != 0) { + node_found = 1; + ppc_proc_freq = *fp; + } + } + if (!node_found) + printk(KERN_ERR "WARNING: Estimating processor frequency " + "(not found)\n"); + + of_node_put(cpu); + + printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", + ppc_tb_freq/1000000, ppc_tb_freq%1000000); + printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", + ppc_proc_freq/1000000, ppc_proc_freq%1000000); + + tb_ticks_per_jiffy = ppc_tb_freq / HZ; + tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; + tb_ticks_per_usec = ppc_tb_freq / 1000000; + tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); + div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); + tb_to_xs = divres.result_low; + + setup_default_decr(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +extern struct machdep_calls pSeries_md; + +static int __init pSeries_probe(int platform) +{ + if (platform != PLATFORM_PSERIES && + platform != PLATFORM_PSERIES_LPAR) + return 0; + + /* if we have some ppc_md fixups for LPAR to do, do + * it here ... + */ + + return 1; +} + +struct machdep_calls __initdata pSeries_md = { + .probe = pSeries_probe, + .setup_arch = pSeries_setup_arch, + .init_early = pSeries_init_early, + .get_cpuinfo = pSeries_get_cpuinfo, + .log_error = pSeries_log_error, + .pcibios_fixup = pSeries_final_fixup, + .restart = rtas_restart, + .power_off = rtas_power_off, + .halt = rtas_halt, + .panic = rtas_os_term, + .get_boot_time = pSeries_get_boot_time, + .get_rtc_time = pSeries_get_rtc_time, + .set_rtc_time = pSeries_set_rtc_time, + .calibrate_decr = pSeries_calibrate_decr, + .progress = pSeries_progress, +}; diff -Nru a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c --- a/arch/ppc64/kernel/pacaData.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/pacaData.c 2004-10-18 14:56:49 -07:00 @@ -27,13 +27,6 @@ * field correctly */ extern unsigned long __toc_start; -/* Stack space used when we detect a bad kernel stack pointer, and - * early in SMP boots before relocation is enabled. - * - * ABI requires stack to be 128-byte aligned - */ -char emergency_stack[PAGE_SIZE * NR_CPUS] __attribute__((aligned(128))); - /* The Paca is an array with one entry per processor. Each contains an * ItLpPaca, which contains the information shared between the * hypervisor and Linux. Each also contains an ItLpRegSave area which @@ -44,18 +37,27 @@ * processors. The processor VPD array needs one entry per physical * processor (not thread). */ -#define PACAINITDATA(number,start,lpq,asrr,asrv) \ -{ \ +#ifdef CONFIG_PPC_ISERIES +#define EXTRA_INITS(number, lpq) \ .lppaca_ptr = &paca[number].lppaca, \ + .lpqueue_ptr = (lpq), /* &xItLpQueue, */ \ .reg_save_ptr = &paca[number].reg_save, \ + .reg_save = { \ + .xDesc = 0xd397d9e2, /* "LpRS" */ \ + .xSize = sizeof(struct ItLpRegSave) \ + }, +#else +#define EXTRA_INITS(number, lpq) +#endif + +#define PACAINITDATA(number,start,lpq,asrr,asrv) \ +{ \ .lock_token = 0x8000, \ .paca_index = (number), /* Paca Index */ \ - .lpqueue_ptr = (lpq), /* &xItLpQueue, */ \ .default_decr = 0x00ff0000, /* Initial Decr */ \ .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ .stab_real = (asrr), /* Real pointer to segment table */ \ .stab_addr = (asrv), /* Virt pointer to segment table */ \ - .emergency_sp = &emergency_stack[((number)+1) * PAGE_SIZE], \ .cpu_start = (start), /* Processor start */ \ .lppaca = { \ .xDesc = 0xd397d781, /* "LpPa" */ \ @@ -66,13 +68,10 @@ .xEndOfQuantum = 0xfffffffffffffffful, \ .xSLBCount = 64, \ }, \ - .reg_save = { \ - .xDesc = 0xd397d9e2, /* "LpRS" */ \ - .xSize = sizeof(struct ItLpRegSave) \ - }, \ + EXTRA_INITS((number), (lpq)) \ } -struct paca_struct paca[] __page_aligned = { +struct paca_struct paca[] = { #ifdef CONFIG_PPC_ISERIES PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR), #else diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c --- a/arch/ppc64/kernel/pci.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc64/kernel/pci.c 2004-10-18 14:56:50 -07:00 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,13 @@ unsigned long pci_probe_only = 1; unsigned long pci_assign_all_buses = 0; +/* legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch + devices we don't have access to. */ +unsigned long io_page_mask; + +EXPORT_SYMBOL(io_page_mask); + + unsigned int pcibios_assign_all_busses(void) { return pci_assign_all_buses; @@ -55,16 +63,9 @@ unsigned long isa_io_base; /* NULL if no ISA bus */ unsigned long pci_io_base; -void pcibios_name_device(struct pci_dev* dev); -void pcibios_final_fixup(void); -static void fixup_broken_pcnet32(struct pci_dev* dev); -static void fixup_windbond_82c105(struct pci_dev* dev); -extern void fixup_k2_sata(struct pci_dev* dev); - void iSeries_pcibios_init(void); -struct pci_controller *hose_head; -struct pci_controller **hose_tail = &hose_head; +LIST_HEAD(hose_list); struct pci_dma_ops pci_dma_ops; EXPORT_SYMBOL(pci_dma_ops); @@ -74,20 +75,6 @@ /* Cached ISA bridge dev. */ struct pci_dev *ppc64_isabridge_dev = NULL; -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, - fixup_broken_pcnet32 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, - fixup_windbond_82c105 }, - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, - pcibios_name_device }, -#ifdef CONFIG_PPC_PMAC - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, 0x0240, - fixup_k2_sata }, -#endif - { 0 } -}; - static void fixup_broken_pcnet32(struct pci_dev* dev) { if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { @@ -96,6 +83,7 @@ pci_name_device(dev); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); static void fixup_windbond_82c105(struct pci_dev* dev) { @@ -118,6 +106,7 @@ dev->resource[i].flags &= ~IORESOURCE_IO; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105); void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, @@ -239,9 +228,9 @@ memcpy(hose->what,model,7); hose->type = controller_type; hose->global_number = global_phb_number++; - - *hose_tail = hose; - hose_tail = &hose->next; + + list_add_tail(&hose->list_node, &hose_list); + return hose; } @@ -281,18 +270,17 @@ static int __init pcibios_init(void) { - struct pci_controller *hose; + struct pci_controller *hose, *tmp; struct pci_bus *bus; #ifdef CONFIG_PPC_ISERIES iSeries_pcibios_init(); #endif - //ppc64_boot_msg(0x40, "PCI Probe"); printk("PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ - for (hose = hose_head; hose; hose = hose->next) { + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { hose->last_busno = 0xff; bus = pci_scan_bus(hose->first_busno, hose->ops, hose->arch_data); @@ -308,7 +296,7 @@ pci_assign_unassigned_resources() is able to work correctly with [partially] allocated PCI tree. */ pci_assign_unassigned_resources(); -#endif +#endif /* !CONFIG_PPC_ISERIES */ /* Call machine dependent final fixup */ if (ppc_md.pcibios_fixup) @@ -320,11 +308,6 @@ printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); printk("PCI: Probing PCI hardware done\n"); - //ppc64_boot_msg(0x41, "PCI Done"); - -#ifdef CONFIG_PPC_PSERIES - pci_addr_cache_build(); -#endif return 0; } @@ -524,7 +507,7 @@ return ret; } -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM static ssize_t pci_show_devspec(struct device *dev, char *buf) { struct pci_dev *pdev; @@ -537,11 +520,329 @@ return sprintf(buf, "%s", np->full_name); } static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ void pcibios_add_platform_entries(struct pci_dev *pdev) { -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM device_create_file(&pdev->dev, &dev_attr_devspec); -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ +} + +#ifdef CONFIG_PPC_MULTIPLATFORM + +#define ISA_SPACE_MASK 0x1 +#define ISA_SPACE_IO 0x1 + +static void pci_process_ISA_OF_ranges(struct device_node *isa_node, + unsigned long phb_io_base_phys, + void * phb_io_base_virt) +{ + struct isa_range *range; + unsigned long pci_addr; + unsigned int isa_addr; + unsigned int size; + int rlen = 0; + + range = (struct isa_range *) get_property(isa_node, "ranges", &rlen); + if (rlen < sizeof(struct isa_range)) { + printk(KERN_ERR "unexpected isa range size: %s\n", + __FUNCTION__); + return; + } + + /* From "ISA Binding to 1275" + * The ranges property is laid out as an array of elements, + * each of which comprises: + * cells 0 - 1: an ISA address + * cells 2 - 4: a PCI address + * (size depending on dev->n_addr_cells) + * cell 5: the size of the range + */ + if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) { + isa_addr = range->isa_addr.a_lo; + pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | + range->pci_addr.a_lo; + + /* Assume these are both zero */ + if ((pci_addr != 0) || (isa_addr != 0)) { + printk(KERN_ERR "unexpected isa to pci mapping: %s\n", + __FUNCTION__); + return; + } + + size = PAGE_ALIGN(range->size); + + __ioremap_explicit(phb_io_base_phys, + (unsigned long) phb_io_base_virt, + size, _PAGE_NO_CACHE); + } +} + +void __init pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) +{ + unsigned int *ranges; + unsigned long size; + int rlen = 0; + int memno = 0; + struct resource *res; + int np, na = prom_n_addr_cells(dev); + unsigned long pci_addr, cpu_phys_addr; + struct device_node *isa_dn; + + np = na + 5; + + /* From "PCI Binding to 1275" + * The ranges property is laid out as an array of elements, + * each of which comprises: + * cells 0 - 2: a PCI address + * cells 3 or 3+4: a CPU physical address + * (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) { + res = NULL; + pci_addr = (unsigned long)ranges[1] << 32 | ranges[2]; + + cpu_phys_addr = ranges[3]; + if (na == 2) + cpu_phys_addr = cpu_phys_addr << 32 | ranges[4]; + + size = (unsigned long)ranges[na+3] << 32 | ranges[na+4]; + + switch (ranges[0] >> 24) { + case 1: /* I/O space */ + hose->io_base_phys = cpu_phys_addr; + hose->io_base_virt = reserve_phb_iospace(size); + PPCDBG(PPCDBG_PHBINIT, + "phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", + hose->global_number, hose->io_base_phys, + (unsigned long) hose->io_base_virt); + + if (primary) { + pci_io_base = (unsigned long)hose->io_base_virt; + isa_dn = of_find_node_by_type(NULL, "isa"); + if (isa_dn) { + isa_io_base = pci_io_base; + pci_process_ISA_OF_ranges(isa_dn, + hose->io_base_phys, + hose->io_base_virt); + of_node_put(isa_dn); + /* Allow all IO */ + io_page_mask = -1; + } + } + + res = &hose->io_resource; + res->flags = IORESOURCE_IO; + res->start = pci_addr; + res->start += (unsigned long)hose->io_base_virt - + pci_io_base; + break; + case 2: /* memory space */ + memno = 0; + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + + if (memno == 0) + hose->pci_mem_offset = cpu_phys_addr - pci_addr; + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = cpu_phys_addr; + } + break; + } + if (res != NULL) { + res->name = dev->full_name; + res->end = res->start + size - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + ranges += np; + } +} + +/*********************************************************************** + * pci_find_hose_for_OF_device + * + * This function finds the PHB that matching device_node in the + * OpenFirmware by scanning all the pci_controllers. + * + ***********************************************************************/ +struct pci_controller* pci_find_hose_for_OF_device(struct device_node *node) +{ + while (node) { + struct pci_controller *hose, *tmp; + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + if (hose->arch_data == node) + return hose; + node=node->parent; + } + 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; +} + + +void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, + struct pci_bus *bus) +{ + /* Update device resources. */ + struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (dev->resource[i].flags & IORESOURCE_IO) { + unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; + unsigned long start, end, mask; + + start = dev->resource[i].start += offset; + end = dev->resource[i].end += offset; + + /* Need to allow IO access to pages that are in the + ISA range */ + if (start < MAX_ISA_PORT) { + if (end > MAX_ISA_PORT) + end = MAX_ISA_PORT; + + start >>= PAGE_SHIFT; + end >>= PAGE_SHIFT; + + /* get the range of pages for the map */ + mask = ((1 << (end+1))-1) ^ ((1 << start)-1); + io_page_mask |= mask; + } + } + else if (dev->resource[i].flags & IORESOURCE_MEM) { + dev->resource[i].start += hose->pci_mem_offset; + dev->resource[i].end += hose->pci_mem_offset; + } + } } +EXPORT_SYMBOL(pcibios_fixup_device_resources); + +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct list_head *ln; + + /* XXX or bus->parent? */ + struct pci_dev *dev = bus->self; + struct resource *res; + int i; + + if (!dev) { + /* Root bus. */ + + hose->bus = bus; + bus->resource[0] = res = &hose->io_resource; + if (!res->flags) + BUG(); /* No I/O resource for this PHB? */ + + if (request_resource(&ioport_resource, res)) + printk(KERN_ERR "Failed to request IO on " + "PCI domain %d\n", pci_domain_nr(bus)); + + + for (i = 0; i < 3; ++i) { + res = &hose->mem_resources[i]; + if (!res->flags && i == 0) + BUG(); /* No memory resource for this PHB? */ + bus->resource[i+1] = res; + if (res->flags && request_resource(&iomem_resource, res)) + printk(KERN_ERR "Failed to request MEM on " + "PCI domain %d\n", + pci_domain_nr(bus)); + } + } else if (pci_probe_only && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + /* This is a subordinate bridge */ + + pci_read_bridge_bases(bus); + pcibios_fixup_device_resources(dev, bus); + } + + /* XXX Need to check why Alpha doesnt do this - Anton */ + if (!pci_probe_only) + return; + + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { + struct pci_dev *dev = pci_dev_b(ln); + if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + pcibios_fixup_device_resources(dev, bus); + } +} +EXPORT_SYMBOL(pcibios_fixup_bus); + +/****************************************************************** + * pci_read_irq_line + * + * Reads the Interrupt Pin to determine if interrupt is use by card. + * If the interrupt is used, then gets the interrupt line from the + * openfirmware and sets it in the pci_dev and pci_config line. + * + ******************************************************************/ +int pci_read_irq_line(struct pci_dev *pci_dev) +{ + u8 intpin; + struct device_node *node; + + pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin); + + if (intpin == 0) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n", + pci_name(pci_dev)); + return 0; + } + + node = pci_device_to_OF_node(pci_dev); + if (node == NULL) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n", + pci_name(pci_dev)); + return -1; + } + if (node->n_intrs == 0) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n", + pci_name(pci_dev)); + return -1; + } + pci_dev->irq = node->intrs[0].line; + + pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); + + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n", + pci_name(pci_dev), pci_dev->irq); + return 0; +} +EXPORT_SYMBOL(pci_read_irq_line); + +#endif /* CONFIG_PPC_MULTIPLATFORM */ diff -Nru a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h --- a/arch/ppc64/kernel/pci.h 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc64/kernel/pci.h 2004-10-18 14:55:53 -07:00 @@ -17,9 +17,7 @@ extern struct pci_controller* pci_alloc_pci_controller(enum phb_types controller_type); extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node); -extern struct pci_controller* hose_head; -extern struct pci_controller** hose_tail; - +extern struct list_head hose_list; extern int global_phb_number; /******************************************************************* diff -Nru a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c --- a/arch/ppc64/kernel/pci_dn.c 2004-10-18 14:57:05 -07:00 +++ b/arch/ppc64/kernel/pci_dn.c 2004-10-18 14:57:05 -07:00 @@ -129,10 +129,10 @@ */ static void *traverse_all_pci_devices(traverse_func pre) { - struct pci_controller *phb; + struct pci_controller *phb, *tmp; void *ret; - for (phb = hose_head; phb; phb = phb->next) + list_for_each_entry_safe(phb, tmp, &hose_list, list_node) if ((ret = traverse_pci_devices(phb->arch_data, pre, phb)) != NULL) return ret; diff -Nru a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c --- a/arch/ppc64/kernel/pci_iommu.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc64/kernel/pci_iommu.c 2004-10-18 14:56:48 -07:00 @@ -54,9 +54,9 @@ return ISERIES_DEVNODE(dev)->iommu_table; #endif /* CONFIG_PPC_ISERIES */ -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM return PCI_GET_DN(dev)->iommu_table; -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ } diff -Nru a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c --- a/arch/ppc64/kernel/pmac_feature.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/pmac_feature.c 2004-10-18 14:56:49 -07:00 @@ -44,9 +44,9 @@ #undef DEBUG_FEATURE #ifdef DEBUG_FEATURE -#define DBG(fmt,...) printk(KERN_DEBUG fmt) +#define DBG(fmt...) printk(KERN_DEBUG fmt) #else -#define DBG(fmt,...) +#define DBG(fmt...) #endif /* @@ -343,6 +343,10 @@ PMAC_TYPE_POWERMAC_G5, g5_features, 0, }, + { "PowerMac7,3", "PowerMac G5", + PMAC_TYPE_POWERMAC_G5, g5_features, + 0, + }, { "RackMac3,1", "XServe G5", PMAC_TYPE_POWERMAC_G5, g5_features, 0, @@ -611,7 +615,7 @@ device_initcall(pmac_feature_late_init); - +#if 0 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 }; @@ -625,6 +629,7 @@ name, freqs[freq], bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); } +#endif void __init pmac_check_ht_link(void) { diff -Nru a/arch/ppc64/kernel/pmac_iommu.c b/arch/ppc64/kernel/pmac_iommu.c --- a/arch/ppc64/kernel/pmac_iommu.c 2004-10-18 14:57:04 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,305 +0,0 @@ -/* - * arch/ppc64/kernel/pmac_iommu.c - * - * Copyright (C) 2004 Olof Johansson , IBM Corporation - * - * Based on pSeries_iommu.c: - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * Copyright (C) 2004 Olof Johansson , IBM Corporation - * - * Dynamic DMA mapping support, PowerMac G5 (DART)-specific parts. - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pci.h" - - -/* physical base of DART registers */ -#define DART_BASE 0xf8033000UL - -/* Offset from base to control register */ -#define DARTCNTL 0 -/* Offset from base to exception register */ -#define DARTEXCP 0x10 -/* Offset from base to TLB tag registers */ -#define DARTTAG 0x1000 - - -/* Control Register fields */ - -/* base address of table (pfn) */ -#define DARTCNTL_BASE_MASK 0xfffff -#define DARTCNTL_BASE_SHIFT 12 - -#define DARTCNTL_FLUSHTLB 0x400 -#define DARTCNTL_ENABLE 0x200 - -/* size of table in pages */ -#define DARTCNTL_SIZE_MASK 0x1ff -#define DARTCNTL_SIZE_SHIFT 0 - -/* DART table fields */ -#define DARTMAP_VALID 0x80000000 -#define DARTMAP_RPNMASK 0x00ffffff - -/* Physical base address and size of the DART table */ -unsigned long dart_tablebase; -unsigned long dart_tablesize; - -/* Virtual base address of the DART table */ -static u32 *dart_vbase; - -/* Mapped base address for the dart */ -static unsigned int *dart; - -/* Dummy val that entries are set to when unused */ -static unsigned int dart_emptyval; - -static struct iommu_table iommu_table_pmac; -static int dart_dirty; - -#define DBG(...) - -static inline void dart_tlb_invalidate_all(void) -{ - unsigned long l = 0; - unsigned int reg; - unsigned long limit; - - DBG("dart: flush\n"); - - /* To invalidate the DART, set the DARTCNTL_FLUSHTLB bit in the - * control register and wait for it to clear. - * - * Gotcha: Sometimes, the DART won't detect that the bit gets - * set. If so, clear it and set it again. - */ - - limit = 0; - -retry: - reg = in_be32((unsigned int *)dart+DARTCNTL); - reg |= DARTCNTL_FLUSHTLB; - out_be32((unsigned int *)dart+DARTCNTL, reg); - - l = 0; - while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) && - l < (1L<it_base) + index; - - /* On pmac, all memory is contigous, so we can move this - * out of the loop. - */ - while (npages--) { - rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; - - *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); - - rpn++; - uaddr += PAGE_SIZE; - } - - dart_dirty = 1; -} - - -static void dart_free_pmac(struct iommu_table *tbl, long index, long npages) -{ - unsigned int *dp; - - /* We don't worry about flushing the TLB cache. The only drawback of - * not doing it is that we won't catch buggy device drivers doing - * bad DMAs, but then no 32-bit architecture ever does either. - */ - - DBG("dart: free at: %lx, %lx\n", index, npages); - - dp = ((unsigned int *)tbl->it_base) + index; - - while (npages--) - *(dp++) = dart_emptyval; -} - - -static int dart_init(struct device_node *dart_node) -{ - unsigned int regword; - unsigned int i; - unsigned long tmp; - struct page *p; - - if (dart_tablebase == 0 || dart_tablesize == 0) { - printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n"); - return -ENODEV; - } - - /* Make sure nothing from the DART range remains in the CPU cache - * from a previous mapping that existed before the kernel took - * over - */ - flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize); - - /* Allocate a spare page to map all invalid DART pages. We need to do - * that to work around what looks like a problem with the HT bridge - * prefetching into invalid pages and corrupting data - */ - tmp = __get_free_pages(GFP_ATOMIC, 1); - if (tmp == 0) - panic("U3-DART: Cannot allocate spare page !"); - dart_emptyval = DARTMAP_VALID | - ((virt_to_abs(tmp) >> PAGE_SHIFT) & DARTMAP_RPNMASK); - - /* Map in DART registers. FIXME: Use device node to get base address */ - dart = ioremap(DART_BASE, 0x7000); - if (dart == NULL) - panic("U3-DART: Cannot map registers !"); - - /* Set initial control register contents: table base, - * table size and enable bit - */ - regword = DARTCNTL_ENABLE | - ((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | - (((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK) - << DARTCNTL_SIZE_SHIFT); - p = virt_to_page(dart_tablebase); - dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); - - /* Fill initial table */ - for (i = 0; i < dart_tablesize/4; i++) - dart_vbase[i] = dart_emptyval; - - /* Initialize DART with table base and enable it. */ - out_be32((unsigned int *)dart, regword); - - /* Invalidate DART to get rid of possible stale TLBs */ - dart_tlb_invalidate_all(); - - iommu_table_pmac.it_busno = 0; - - /* Units of tce entries */ - iommu_table_pmac.it_offset = 0; - - /* Set the tce table size - measured in pages */ - iommu_table_pmac.it_size = dart_tablesize >> PAGE_SHIFT; - - /* Initialize the common IOMMU code */ - iommu_table_pmac.it_base = (unsigned long)dart_vbase; - iommu_table_pmac.it_index = 0; - iommu_table_pmac.it_blocksize = 1; - iommu_table_pmac.it_entrysize = sizeof(u32); - iommu_init_table(&iommu_table_pmac); - - /* Reserve the last page of the DART to avoid possible prefetch - * past the DART mapped area - */ - set_bit(iommu_table_pmac.it_mapsize - 1, iommu_table_pmac.it_map); - - printk(KERN_INFO "U3-DART IOMMU initialized\n"); - - return 0; -} - - -void iommu_setup_pmac(void) -{ - struct pci_dev *dev = NULL; - struct device_node *dn; - - /* Find the DART in the device-tree */ - dn = of_find_compatible_node(NULL, "dart", "u3-dart"); - if (dn == NULL) - return; - - /* Setup low level TCE operations for the core IOMMU code */ - ppc_md.tce_build = dart_build_pmac; - ppc_md.tce_free = dart_free_pmac; - ppc_md.tce_flush = dart_flush; - - /* Initialize the DART HW */ - if (dart_init(dn)) - return; - - /* Setup pci_dma ops */ - pci_iommu_init(); - - /* We only have one iommu table on the mac for now, which makes - * things simple. Setup all PCI devices to point to this table - */ - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - /* We must use pci_device_to_OF_node() to make sure that - * we get the real "final" pointer to the device in the - * pci_dev sysdata and not the temporary PHB one - */ - struct device_node *dn = pci_device_to_OF_node(dev); - if (dn) - dn->iommu_table = &iommu_table_pmac; - } -} - - - - diff -Nru a/arch/ppc64/kernel/pmac_low_i2c.c b/arch/ppc64/kernel/pmac_low_i2c.c --- a/arch/ppc64/kernel/pmac_low_i2c.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc64/kernel/pmac_low_i2c.c 2004-10-18 14:56:28 -07:00 @@ -50,7 +50,7 @@ struct device_node *np; /* OF device node */ struct semaphore mutex; /* Access mutex for use by i2c-keywest */ low_i2c_func_t func; /* Access function */ - int is_open : 1; /* Poor man's access control */ + unsigned is_open : 1; /* Poor man's access control */ int mode; /* Current mode */ int channel; /* Current channel */ int num_channels; /* Number of channels */ diff -Nru a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c --- a/arch/ppc64/kernel/pmac_pci.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc64/kernel/pmac_pci.c 2004-10-18 14:56:48 -07:00 @@ -271,7 +271,7 @@ int offset, int len, u32 *val) { struct pci_controller *hose; - struct device_node *busdn; + struct device_node *busdn, *dn; unsigned long addr; if (bus->self) @@ -284,6 +284,16 @@ if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; + /* We only allow config cycles to devices that are in OF device-tree + * as we are apparently having some weird things going on with some + * revs of K2 on recent G5s + */ + for (dn = busdn->child; dn; dn = dn->sibling) + if (dn->devfn == devfn) + break; + if (dn == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -419,7 +429,7 @@ * 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_phys = 0xf4000000; hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; hose->io_resource.name = np->full_name; @@ -664,17 +674,15 @@ pci_fix_bus_sysdata(); -#ifdef CONFIG_PMAC_DART - iommu_setup_pmac(); -#endif /* CONFIG_PMAC_DART */ + iommu_setup_u3(); } static void __init pmac_fixup_phb_resources(void) { - struct pci_controller *hose; + struct pci_controller *hose, *tmp; - for (hose = hose_head; hose; hose = hose->next) { + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; hose->io_resource.start += offset; hose->io_resource.end += offset; @@ -746,6 +754,9 @@ * the exception of U3/AGP (hook into pci_set_mwi) */ pci_cache_line_size = 16; /* 64 bytes */ + + /* Allow all IO */ + io_page_mask = -1; } /* @@ -777,3 +788,4 @@ } } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata); diff -Nru a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c --- a/arch/ppc64/kernel/pmac_setup.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc64/kernel/pmac_setup.c 2004-10-18 14:55:55 -07:00 @@ -23,6 +23,8 @@ * bootup setup stuff.. */ +#undef DEBUG + #include #include #include @@ -63,7 +65,6 @@ #include #include #include -#include #include #include #include @@ -73,6 +74,13 @@ #include "pmac.h" +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + + static int current_root_goodness = -1; #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ @@ -81,10 +89,6 @@ extern void udbg_init_scc(struct device_node *np); -#ifdef CONFIG_BOOTX_TEXT -void pmac_progress(char *s, unsigned short hex); -#endif - void __pmac pmac_show_cpuinfo(struct seq_file *m) { struct device_node *np; @@ -134,28 +138,20 @@ void __init pmac_setup_arch(void) { - struct device_node *cpu; - int *fp; - unsigned long pvr; - - pvr = PVR_VER(mfspr(PVR)); - - /* Set loops_per_jiffy to a half-way reasonable value, - for use until calibrate_delay gets called. */ - cpu = find_type_devices("cpu"); - if (cpu != 0) { - fp = (int *) get_property(cpu, "clock-frequency", NULL); - if (fp != 0) { - if (pvr == 4 || pvr >= 8) - /* 604, G3, G4 etc. */ - loops_per_jiffy = *fp / HZ; - else - /* 601, 603, etc. */ - loops_per_jiffy = *fp / (2*HZ); - } else - loops_per_jiffy = 50000000 / HZ; + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + /* Probe motherboard chipset */ + pmac_feature_init(); +#if 0 + /* Lock-enable the SCC channel used for debug */ + if (sccdbg) { + np = of_find_node_by_name(NULL, "escc"); + if (np) + pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, + PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); } - +#endif /* We can NAP */ powersave_nap = 1; @@ -183,67 +179,13 @@ #endif } -extern char *bootpath; -extern char *bootdevice; -void *boot_host; -int boot_target; -int boot_part; -extern dev_t boot_dev; - #ifdef CONFIG_SCSI -void __init note_scsi_host(struct device_node *node, void *host) +void note_scsi_host(struct device_node *node, void *host) { - int l; - char *p; - - l = strlen(node->full_name); - if (bootpath != NULL && bootdevice != NULL - && strncmp(node->full_name, bootdevice, l) == 0 - && (bootdevice[l] == '/' || bootdevice[l] == 0)) { - boot_host = host; - /* - * There's a bug in OF 1.0.5. (Why am I not surprised.) - * If you pass a path like scsi/sd@1:0 to canon, it returns - * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 - * That is, the scsi target number doesn't get preserved. - * So we pick the target number out of bootpath and use that. - */ - p = strstr(bootpath, "/sd@"); - if (p != NULL) { - p += 4; - boot_target = simple_strtoul(p, NULL, 10); - p = strchr(p, ':'); - if (p != NULL) - boot_part = simple_strtoul(p + 1, NULL, 10); - } - } + /* Obsolete */ } #endif -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -static dev_t __init find_ide_boot(void) -{ - char *p; - int n; - dev_t __init pmac_find_ide_boot(char *bootdevice, int n); - - if (bootdevice == NULL) - return 0; - p = strrchr(bootdevice, '/'); - if (p == NULL) - return 0; - n = p - bootdevice; - - return pmac_find_ide_boot(bootdevice, n); -} -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ - -void __init find_boot_device(void) -{ -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - boot_dev = find_ide_boot(); -#endif -} static int initializing = 1; @@ -258,7 +200,7 @@ /* can't be __init - can be called whenever a disk is first accessed */ void __pmac note_bootable_part(dev_t dev, int part, int goodness) { - static int found_boot = 0; + extern dev_t boot_dev; char *p; if (!initializing) @@ -270,10 +212,6 @@ if (p != NULL && (p == saved_command_line || p[-1] == ' ')) return; - if (!found_boot) { - find_boot_device(); - found_boot = 1; - } if (!boot_dev || dev == boot_dev) { ROOT_DEV = dev + part; boot_dev = 0; @@ -313,21 +251,73 @@ } #endif /* CONFIG_BOOTX_TEXT */ +static void __init init_boot_display(void) +{ + char *name; + struct device_node *np = NULL; + int rc = -ENODEV; + + printk("trying to initialize btext ...\n"); + + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name != NULL) { + np = of_find_node_by_path(name); + if (np != NULL) { + if (strcmp(np->type, "display") != 0) { + printk("boot stdout isn't a display !\n"); + of_node_put(np); + np = NULL; + } + } + } + if (np) + rc = btext_initialize(np); + if (rc == 0) + return; + + for (np = NULL; (np = of_find_node_by_type(np, "display"));) { + if (get_property(np, "linux,opened", NULL)) { + printk("trying %s ...\n", np->full_name); + rc = btext_initialize(np); + printk("result: %d\n", rc); + } + if (rc == 0) + return; + } +} + /* * Early initialization. - * Relocation is on but do not reference unbolted pages - * Also, device-tree hasn't been "finished", so don't muck with - * it too much */ void __init pmac_init_early(void) { - hpte_init_pSeries(); + DBG(" -> pmac_init_early\n"); + + /* Initialize hash table, from now on, we can take hash faults + * and call ioremap + */ + hpte_init_native(); + /* Init SCC */ + if (strstr(cmd_line, "sccdbg")) { + sccdbg = 1; + udbg_init_scc(NULL); + } + + else { #ifdef CONFIG_BOOTX_TEXT - ppc_md.udbg_putc = btext_putc; - ppc_md.udbg_getc = dummy_getc; - ppc_md.udbg_getc_poll = dummy_getc_poll; + init_boot_display(); + + ppc_md.udbg_putc = btext_putc; + ppc_md.udbg_getc = dummy_getc; + ppc_md.udbg_getc_poll = dummy_getc_poll; #endif /* CONFIG_BOOTX_TEXT */ + } + + /* Setup interrupt mapping options */ + naca->interrupt_controller = IC_OPEN_PIC; + + DBG(" <- pmac_init_early\n"); } extern void* OpenPIC_Addr; @@ -417,60 +407,19 @@ core_initcall(pmac_irq_cascade_init); -void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* Probe motherboard chipset */ - pmac_feature_init(); - - /* Init SCC */ - if (strstr(cmd_line, "sccdbg")) { - sccdbg = 1; - udbg_init_scc(NULL); - } - - /* Fill up the machine description */ - ppc_md.setup_arch = pmac_setup_arch; - ppc_md.get_cpuinfo = pmac_show_cpuinfo; - - ppc_md.init_IRQ = pmac_init_IRQ; - ppc_md.get_irq = openpic_get_irq; - - ppc_md.pcibios_fixup = pmac_pcibios_fixup; - - ppc_md.restart = pmac_restart; - ppc_md.power_off = pmac_power_off; - ppc_md.halt = pmac_halt; - - ppc_md.get_boot_time = pmac_get_boot_time; - ppc_md.set_rtc_time = pmac_set_rtc_time; - ppc_md.get_rtc_time = pmac_get_rtc_time; - ppc_md.calibrate_decr = pmac_calibrate_decr; - - ppc_md.feature_call = pmac_do_feature_call; - - -#ifdef CONFIG_BOOTX_TEXT - ppc_md.progress = pmac_progress; -#endif /* CONFIG_BOOTX_TEXT */ - - if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); - -} - -#ifdef CONFIG_BOOTX_TEXT -void __init pmac_progress(char *s, unsigned short hex) +static void __init pmac_progress(char *s, unsigned short hex) { if (sccdbg) { udbg_puts(s); - udbg_putc('\n'); + udbg_puts("\n"); } +#ifdef CONFIG_BOOTX_TEXT else if (boot_text_mapped) { btext_drawstring(s); - btext_drawchar('\n'); + btext_drawstring("\n"); } -} #endif /* CONFIG_BOOTX_TEXT */ +} static int __init pmac_declare_of_platform_devices(void) { @@ -489,3 +438,41 @@ } device_initcall(pmac_declare_of_platform_devices); + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init pmac_probe(int platform) +{ + if (platform != PLATFORM_POWERMAC) + return 0; + + /* + * On U3, the DART (iommu) must be allocated now since it + * has an impact on htab_initialize (due to the large page it + * occupies having to be broken up so the DART itself is not + * part of the cacheable linar mapping + */ + alloc_u3_dart_table(); + + return 1; +} + +struct machdep_calls __initdata pmac_md = { + .probe = pmac_probe, + .setup_arch = pmac_setup_arch, + .init_early = pmac_init_early, + .get_cpuinfo = pmac_show_cpuinfo, + .init_IRQ = pmac_init_IRQ, + .get_irq = openpic_get_irq, + .pcibios_fixup = pmac_pcibios_fixup, + .restart = pmac_restart, + .power_off = pmac_power_off, + .halt = pmac_halt, + .get_boot_time = pmac_get_boot_time, + .set_rtc_time = pmac_set_rtc_time, + .get_rtc_time = pmac_get_rtc_time, + .calibrate_decr = pmac_calibrate_decr, + .feature_call = pmac_do_feature_call, + .progress = pmac_progress, +}; diff -Nru a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c --- a/arch/ppc64/kernel/pmac_smp.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc64/kernel/pmac_smp.c 2004-10-18 14:55:54 -07:00 @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c --- a/arch/ppc64/kernel/pmac_time.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc64/kernel/pmac_time.c 2004-10-18 14:56:48 -07:00 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c --- a/arch/ppc64/kernel/ppc_ksyms.c 2004-10-18 14:56:17 -07:00 +++ b/arch/ppc64/kernel/ppc_ksyms.c 2004-10-18 14:56:17 -07:00 @@ -119,7 +119,6 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(flush_instruction_cache); -EXPORT_SYMBOL(_get_PVR); EXPORT_SYMBOL(giveup_fpu); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(giveup_altivec); @@ -137,7 +136,7 @@ EXPORT_SYMBOL(ppc_md); -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -148,12 +147,12 @@ EXPORT_SYMBOL(get_property); #endif -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memchr); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(irq_desc); diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c --- a/arch/ppc64/kernel/process.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/kernel/process.c 2004-10-18 14:56:33 -07:00 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -147,7 +147,6 @@ */ void flush_altivec_to_thread(struct task_struct *tsk) { -#ifdef CONFIG_ALTIVEC if (tsk->thread.regs) { preempt_disable(); if (tsk->thread.regs->msr & MSR_VEC) { @@ -158,7 +157,6 @@ } preempt_enable(); } -#endif } int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) @@ -356,6 +354,16 @@ kregs = (struct pt_regs *) sp; sp -= STACK_FRAME_OVERHEAD; p->thread.ksp = sp; + if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) { + unsigned long sp_vsid = get_kernel_vsid(sp); + + sp_vsid <<= SLB_VSID_SHIFT; + sp_vsid |= SLB_VSID_KERNEL; + if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + sp_vsid |= SLB_VSID_L; + + p->thread.ksp_vsid = sp_vsid; + } /* * The PPC64 ABI makes use of a TOC to contain function @@ -387,11 +395,22 @@ /* Check whether the e_entry function descriptor entries * need to be relocated before we can use them. */ - if ( load_addr != 0 ) { + if (load_addr != 0) { entry += load_addr; toc += load_addr; } + /* + * If we exec out of a kernel thread then thread.regs will not be + * set. Do it now. + */ + if (!current->thread.regs) { + unsigned long childregs = (unsigned long)current->thread_info + + THREAD_SIZE; + childregs -= sizeof(struct pt_regs); + current->thread.regs = (struct pt_regs *)childregs; + } + regs->nip = entry; regs->gpr[1] = sp; regs->gpr[2] = toc; @@ -458,7 +477,7 @@ } } - return do_fork(clone_flags & ~CLONE_IDLETASK, p2, regs, 0, + return do_fork(clone_flags, p2, regs, 0, (int __user *)parent_tidptr, (int __user *)child_tidptr); } diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c --- a/arch/ppc64/kernel/prom.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc64/kernel/prom.c 2004-10-18 14:56:48 -07:00 @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG_PROM +#undef DEBUG #include #include @@ -54,1806 +54,58 @@ #include #include "open_pic.h" -#ifdef CONFIG_LOGO_LINUX_CLUT224 -#include -extern const struct linux_logo logo_linux_clut224; -#endif - -/* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This value does need to be big enough to - * ensure that we don't lose things like the interrupt-map property - * on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) - -/* - * prom_init() is called very early on, before the kernel text - * and data have been mapped to KERNELBASE. At this point the code - * is running at whatever address it has been loaded at, so - * references to extern and static variables must be relocated - * explicitly. The procedure reloc_offset() returns the address - * we're currently running at minus the address we were linked at. - * (Note that strings count as static variables.) - * - * Because OF may have mapped I/O devices into the area starting at - * KERNELBASE, particularly on CHRP machines, we can't safely call - * OF once the kernel has been mapped to KERNELBASE. Therefore all - * OF calls should be done within prom_init(), and prom_init() - * and all routines called within it must be careful to relocate - * references as necessary. - * - * Note that the bss is cleared *after* prom_init runs, so we have - * to make sure that any static or extern variables it accesses - * are put in the data segment. - */ - - -#define PROM_BUG() do { \ - prom_printf("kernel BUG at %s line 0x%x!\n", \ - RELOC(__FILE__), __LINE__); \ - __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ -} while (0) - -#ifdef DEBUG_PROM -#define prom_debug(x...) prom_printf(x) +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) #else -#define prom_debug(x...) +#define DBG(fmt...) #endif - struct pci_reg_property { struct pci_address addr; u32 size_hi; u32 size_lo; }; - struct isa_reg_property { u32 space; u32 address; u32 size; }; -struct pci_intr_map { - struct pci_address addr; - u32 dunno; - phandle int_ctrler; - u32 intr; -}; - typedef unsigned long interpret_func(struct device_node *, unsigned long, int, int, int); -#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ -#define FB_MAX 8 -#endif - -/* prom structure */ -struct prom_t prom; - -char *prom_display_paths[FB_MAX] __initdata = { NULL, }; -phandle prom_display_nodes[FB_MAX] __initdata; -unsigned int prom_num_displays = 0; -char *of_stdout_device = NULL; - -static int iommu_force_on; -int ppc64_iommu_off; - extern struct rtas_t rtas; -extern unsigned long klimit; extern struct lmb lmb; +extern unsigned long klimit; -#define MAX_PHB (32 * 6) /* 32 drawers * 6 PHBs/drawer */ -struct of_tce_table of_tce_table[MAX_PHB + 1]; +static int __initdata dt_root_addr_cells; +static int __initdata dt_root_size_cells; +static int __initdata iommu_is_off; +int __initdata iommu_force_on; +typedef u32 cell_t; -char *bootpath = NULL; -char *bootdevice = NULL; +#if 0 +static struct boot_param_header *initial_boot_params __initdata; +#else +struct boot_param_header *initial_boot_params; +#endif -int boot_cpuid = 0; -#define MAX_CPU_THREADS 2 +static struct device_node *allnodes = NULL; -struct device_node *allnodes = NULL; /* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. */ static rwlock_t devtree_lock = RW_LOCK_UNLOCKED; -extern unsigned long reloc_offset(void); - -extern void enter_prom(struct prom_args *args); -extern void copy_and_flush(unsigned long dest, unsigned long src, - unsigned long size, unsigned long offset); - -unsigned long dev_tree_size; -unsigned long _get_PIR(void); - -#ifdef CONFIG_HMT -struct { - unsigned int pir; - unsigned int threadid; -} hmt_thread_data[NR_CPUS]; -#endif /* CONFIG_HMT */ - -char testString[] = "LINUX\n"; - -/* - * This are used in calls to call_prom. The 4th and following - * arguments to call_prom should be 32-bit values. 64 bit values - * are truncated to 32 bits (and fortunately don't get interpreted - * as two arguments). - */ -#define ADDR(x) (u32) ((unsigned long)(x) - offset) - -/* This is the one and *ONLY* place where we actually call open - * firmware from, since we need to make sure we're running in 32b - * mode when we do. We switch back to 64b mode upon return. - */ - -#define PROM_ERROR (-1) - -static int __init call_prom(const char *service, int nargs, int nret, ...) -{ - int i; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - va_list list; - - _prom->args.service = ADDR(service); - _prom->args.nargs = nargs; - _prom->args.nret = nret; - _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); - - va_start(list, nret); - for (i=0; i < nargs; i++) - _prom->args.args[i] = va_arg(list, prom_arg_t); - va_end(list); - - for (i=0; i < nret ;i++) - _prom->args.rets[i] = 0; - - enter_prom(&_prom->args); - - return (nret > 0)? _prom->args.rets[0]: 0; -} - - -static void __init prom_print(const char *msg) -{ - const char *p, *q; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - if (_prom->stdout == 0) - return; - - for (p = msg; *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - ++q; - call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); - } -} - - -static void __init prom_print_hex(unsigned long val) -{ - unsigned long offset = reloc_offset(); - int i, nibbles = sizeof(val)*2; - char buf[sizeof(val)*2+1]; - struct prom_t *_prom = PTRRELOC(&prom); - - for (i = nibbles-1; i >= 0; i--) { - buf[i] = (val & 0xf) + '0'; - if (buf[i] > '9') - buf[i] += ('a'-'0'-10); - val >>= 4; - } - buf[nibbles] = '\0'; - call_prom("write", 3, 1, _prom->stdout, buf, nibbles); -} - - -static void __init prom_printf(const char *format, ...) -{ - unsigned long offset = reloc_offset(); - const char *p, *q, *s; - va_list args; - unsigned long v; - struct prom_t *_prom = PTRRELOC(&prom); - - va_start(args, format); - for (p = PTRRELOC(format); *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - if (*q == '\n') { - ++q; - call_prom("write", 3, 1, _prom->stdout, - ADDR("\r\n"), 2); - continue; - } - ++q; - if (*q == 0) - break; - switch (*q) { - case 's': - ++q; - s = va_arg(args, const char *); - prom_print(s); - break; - case 'x': - ++q; - v = va_arg(args, unsigned long); - prom_print_hex(v); - break; - } - } -} - - -static void __init __attribute__((noreturn)) prom_panic(const char *reason) -{ - unsigned long offset = reloc_offset(); - - prom_print(PTRRELOC(reason)); - /* ToDo: should put up an SRC here */ - call_prom("exit", 0, 0); - - for (;;) /* should never get here */ - ; -} - - -static int __init prom_next_node(phandle *nodep) -{ - phandle node; - - if ((node = *nodep) != 0 - && (*nodep = call_prom("child", 1, 1, node)) != 0) - return 1; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - for (;;) { - if ((node = call_prom("parent", 1, 1, node)) == 0) - return 0; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - } -} - -static int __init prom_getprop(phandle node, const char *pname, - void *value, size_t valuelen) -{ - unsigned long offset = reloc_offset(); - - return call_prom("getprop", 4, 1, node, ADDR(pname), - (u32)(unsigned long) value, (u32) valuelen); -} - -static void __init prom_initialize_naca(void) -{ - phandle node; - char type[64]; - unsigned long num_cpus = 0; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct naca_struct *_naca = RELOC(naca); - struct systemcfg *_systemcfg = RELOC(systemcfg); - - /* NOTE: _naca->debug_switch is already initialized. */ - prom_debug("prom_initialize_naca: start...\n"); - - _naca->pftSize = 0; /* ilog2 of htab size. computed below. */ - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - - if (!strcmp(type, RELOC("cpu"))) { - num_cpus += 1; - - /* We're assuming *all* of the CPUs have the same - * d-cache and i-cache sizes... -Peter - */ - if ( num_cpus == 1 ) { - u32 size, lsize; - const char *dc, *ic; - - if (_systemcfg->platform == PLATFORM_POWERMAC){ - dc = "d-cache-block-size"; - ic = "i-cache-block-size"; - } else { - dc = "d-cache-line-size"; - ic = "i-cache-line-size"; - } - - prom_getprop(node, "d-cache-size", - &size, sizeof(size)); - - prom_getprop(node, dc, &lsize, sizeof(lsize)); - - _systemcfg->dCacheL1Size = size; - _systemcfg->dCacheL1LineSize = lsize; - _naca->dCacheL1LogLineSize = __ilog2(lsize); - _naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize; - - prom_getprop(node, "i-cache-size", - &size, sizeof(size)); - - prom_getprop(node, ic, &lsize, sizeof(lsize)); - - _systemcfg->iCacheL1Size = size; - _systemcfg->iCacheL1LineSize = lsize; - _naca->iCacheL1LogLineSize = __ilog2(lsize); - _naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize; - - if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) { - u32 pft_size[2]; - prom_getprop(node, "ibm,pft-size", - &pft_size, sizeof(pft_size)); - /* pft_size[0] is the NUMA CEC cookie */ - _naca->pftSize = pft_size[1]; - } - } - } else if (!strcmp(type, RELOC("serial"))) { - phandle isa, pci; - struct isa_reg_property reg; - union pci_range ranges; - - if (_systemcfg->platform == PLATFORM_POWERMAC) - continue; - type[0] = 0; - prom_getprop(node, "ibm,aix-loc", type, sizeof(type)); - - if (strcmp(type, RELOC("S1"))) - continue; - - prom_getprop(node, "reg", ®, sizeof(reg)); - - isa = call_prom("parent", 1, 1, node); - if (!isa) - PROM_BUG(); - pci = call_prom("parent", 1, 1, isa); - if (!pci) - PROM_BUG(); - - prom_getprop(pci, "ranges", &ranges, sizeof(ranges)); - - if ( _prom->encode_phys_size == 32 ) - _naca->serialPortAddr = ranges.pci32.phys+reg.address; - else { - _naca->serialPortAddr = - ((((unsigned long)ranges.pci64.phys_hi) << 32) | - (ranges.pci64.phys_lo)) + reg.address; - } - } - } - - if (_systemcfg->platform == PLATFORM_POWERMAC) - _naca->interrupt_controller = IC_OPEN_PIC; - else { - _naca->interrupt_controller = IC_INVALID; - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "name", type, sizeof(type)); - if (strcmp(type, RELOC("interrupt-controller"))) - continue; - prom_getprop(node, "compatible", type, sizeof(type)); - if (strstr(type, RELOC("open-pic"))) - _naca->interrupt_controller = IC_OPEN_PIC; - else if (strstr(type, RELOC("ppc-xicp"))) - _naca->interrupt_controller = IC_PPC_XIC; - else - prom_printf("prom: failed to recognize" - " interrupt-controller\n"); - break; - } - } - - if (_naca->interrupt_controller == IC_INVALID) { - prom_printf("prom: failed to find interrupt-controller\n"); - PROM_BUG(); - } - - /* We gotta have at least 1 cpu... */ - if ( (_systemcfg->processorCount = num_cpus) < 1 ) - PROM_BUG(); - - _systemcfg->physicalMemorySize = lmb_phys_mem_size(); - - if (_systemcfg->platform == PLATFORM_PSERIES || - _systemcfg->platform == PLATFORM_POWERMAC) { - unsigned long rnd_mem_size, pteg_count; - - /* round mem_size up to next power of 2 */ - rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize); - if (rnd_mem_size < _systemcfg->physicalMemorySize) - rnd_mem_size <<= 1; - - /* # pages / 2 */ - pteg_count = (rnd_mem_size >> (12 + 1)); - - _naca->pftSize = __ilog2(pteg_count << 7); - } - - if (_naca->pftSize == 0) { - prom_printf("prom: failed to compute pftSize!\n"); - PROM_BUG(); - } - - /* Add an eye catcher and the systemcfg layout version number */ - strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64")); - _systemcfg->version.major = SYSTEMCFG_MAJOR; - _systemcfg->version.minor = SYSTEMCFG_MINOR; - _systemcfg->processor = _get_PVR(); - - prom_debug("systemcfg->processorCount = 0x%x\n", - _systemcfg->processorCount); - prom_debug("systemcfg->physicalMemorySize = 0x%x\n", - _systemcfg->physicalMemorySize); - prom_debug("naca->pftSize = 0x%x\n", - _naca->pftSize); - prom_debug("systemcfg->dCacheL1LineSize = 0x%x\n", - _systemcfg->dCacheL1LineSize); - prom_debug("systemcfg->iCacheL1LineSize = 0x%x\n", - _systemcfg->iCacheL1LineSize); - prom_debug("naca->serialPortAddr = 0x%x\n", - _naca->serialPortAddr); - prom_debug("naca->interrupt_controller = 0x%x\n", - _naca->interrupt_controller); - prom_debug("systemcfg->platform = 0x%x\n", - _systemcfg->platform); - prom_debug("prom_initialize_naca: end...\n"); -} - - -static void __init early_cmdline_parse(void) -{ - unsigned long offset = reloc_offset(); - char *opt; -#ifndef CONFIG_PMAC_DART - struct systemcfg *_systemcfg = RELOC(systemcfg); -#endif - - opt = strstr(RELOC(cmd_line), RELOC("iommu=")); - if (opt) { - prom_printf("opt is:%s\n", opt); - opt += 6; - while (*opt && *opt == ' ') - opt++; - if (!strncmp(opt, RELOC("off"), 3)) - RELOC(ppc64_iommu_off) = 1; - else if (!strncmp(opt, RELOC("force"), 5)) - RELOC(iommu_force_on) = 1; - } - -#ifndef CONFIG_PMAC_DART - if (_systemcfg->platform == PLATFORM_POWERMAC) { - RELOC(ppc64_iommu_off) = 1; - prom_printf("DART disabled on PowerMac !\n"); - } -#endif -} - -#ifdef DEBUG_PROM -void prom_dump_lmb(void) -{ - unsigned long i; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); - - prom_printf("\nprom_dump_lmb:\n"); - prom_printf(" memory.cnt = 0x%x\n", - _lmb->memory.cnt); - prom_printf(" memory.size = 0x%x\n", - _lmb->memory.size); - for (i=0; i < _lmb->memory.cnt ;i++) { - prom_printf(" memory.region[0x%x].base = 0x%x\n", - i, _lmb->memory.region[i].base); - prom_printf(" .physbase = 0x%x\n", - _lmb->memory.region[i].physbase); - prom_printf(" .size = 0x%x\n", - _lmb->memory.region[i].size); - } - - prom_printf("\n reserved.cnt = 0x%x\n", - _lmb->reserved.cnt); - prom_printf(" reserved.size = 0x%x\n", - _lmb->reserved.size); - for (i=0; i < _lmb->reserved.cnt ;i++) { - prom_printf(" reserved.region[0x%x\n].base = 0x%x\n", - i, _lmb->reserved.region[i].base); - prom_printf(" .physbase = 0x%x\n", - _lmb->reserved.region[i].physbase); - prom_printf(" .size = 0x%x\n", - _lmb->reserved.region[i].size); - } -} -#endif /* DEBUG_PROM */ - -static void __init prom_initialize_lmb(void) -{ - phandle node; - char type[64]; - unsigned long i, offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct systemcfg *_systemcfg = RELOC(systemcfg); - union lmb_reg_property reg; - unsigned long lmb_base, lmb_size; - unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8; - - lmb_init(); - - /* XXX Quick HACK. Proper fix is to drop those structures and properly use - * #address-cells. PowerMac has #size-cell set to 1 and #address-cells to 2 - */ - if (_systemcfg->platform == PLATFORM_POWERMAC) - bytes_per_reg = 12; - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - - if (strcmp(type, RELOC("memory"))) - continue; - - num_regs = prom_getprop(node, "reg", ®, sizeof(reg)) - / bytes_per_reg; - - for (i=0; i < num_regs ;i++) { - if (_systemcfg->platform == PLATFORM_POWERMAC) { - lmb_base = ((unsigned long)reg.addrPM[i].address_hi) << 32; - lmb_base |= (unsigned long)reg.addrPM[i].address_lo; - lmb_size = reg.addrPM[i].size; - } else if (_prom->encode_phys_size == 32) { - lmb_base = reg.addr32[i].address; - lmb_size = reg.addr32[i].size; - } else { - lmb_base = reg.addr64[i].address; - lmb_size = reg.addr64[i].size; - } - - /* We limit memory to 2GB if the IOMMU is off */ - if (RELOC(ppc64_iommu_off)) { - if (lmb_base >= 0x80000000UL) - continue; - - if ((lmb_base + lmb_size) > 0x80000000UL) - lmb_size = 0x80000000UL - lmb_base; - } - - if (lmb_add(lmb_base, lmb_size) < 0) - prom_printf("Too many LMB's, discarding this one...\n"); - } - - } - - lmb_analyze(); -#ifdef DEBUG_PROM - prom_dump_lmb(); -#endif /* DEBUG_PROM */ -} - -static void __init -prom_instantiate_rtas(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct rtas_t *_rtas = PTRRELOC(&rtas); - struct systemcfg *_systemcfg = RELOC(systemcfg); - ihandle prom_rtas; - u32 getprop_rval; - char hypertas_funcs[4]; - - prom_debug("prom_instantiate_rtas: start...\n"); - - prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (prom_rtas != (ihandle) -1) { - unsigned long x; - x = prom_getprop(prom_rtas, "ibm,hypertas-functions", - hypertas_funcs, sizeof(hypertas_funcs)); - - if (x != PROM_ERROR) { - prom_printf("Hypertas detected, assuming LPAR !\n"); - _systemcfg->platform = PLATFORM_PSERIES_LPAR; - } - - prom_getprop(prom_rtas, "rtas-size", - &getprop_rval, sizeof(getprop_rval)); - _rtas->size = getprop_rval; - prom_printf("instantiating rtas"); - if (_rtas->size != 0) { - unsigned long rtas_region = RTAS_INSTANTIATE_MAX; - - /* Grab some space within the first RTAS_INSTANTIATE_MAX bytes - * of physical memory (or within the RMO region) because RTAS - * runs in 32-bit mode and relocate off. - */ - if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) { - struct lmb *_lmb = PTRRELOC(&lmb); - rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX); - } - - _rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region); - - prom_printf(" at 0x%x", _rtas->base); - - prom_rtas = call_prom("open", 1, 1, ADDR("/rtas")); - prom_printf("..."); - - if (call_prom("call-method", 3, 2, - ADDR("instantiate-rtas"), - prom_rtas, - _rtas->base) != PROM_ERROR) { - _rtas->entry = (long)_prom->args.rets[1]; - } - RELOC(rtas_rmo_buf) - = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, - rtas_region); - } - - if (_rtas->entry <= 0) { - prom_printf(" failed\n"); - } else { - prom_printf(" done\n"); - } - - prom_debug("rtas->base = 0x%x\n", _rtas->base); - prom_debug("rtas->entry = 0x%x\n", _rtas->entry); - prom_debug("rtas->size = 0x%x\n", _rtas->size); - } - prom_debug("prom_instantiate_rtas: end...\n"); -} - - -#ifdef CONFIG_PMAC_DART -static void __init prom_initialize_dart_table(void) -{ - unsigned long offset = reloc_offset(); - extern unsigned long dart_tablebase; - extern unsigned long dart_tablesize; - - /* Only reserve DART space if machine has more than 2GB of RAM - * or if requested with iommu=on on cmdline. - */ - if (lmb_end_of_DRAM() <= 0x80000000ull && !RELOC(iommu_force_on)) - return; - - /* 512 pages (2MB) is max DART tablesize. */ - RELOC(dart_tablesize) = 1UL << 21; - /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we - * will blow up an entire large page anyway in the kernel mapping - */ - RELOC(dart_tablebase) = (unsigned long) - abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); - - prom_printf("Dart at: %x\n", RELOC(dart_tablebase)); -} -#endif /* CONFIG_PMAC_DART */ - -static void __init prom_initialize_tce_table(void) -{ - phandle node; - ihandle phb_node; - unsigned long offset = reloc_offset(); - char compatible[64], path[64], type[64], model[64]; - unsigned long i, table = 0; - unsigned long base, vbase, align; - unsigned int minalign, minsize; - struct of_tce_table *prom_tce_table = RELOC(of_tce_table); - unsigned long tce_entry, *tce_entryp; - - if (RELOC(ppc64_iommu_off)) - return; - - prom_debug("starting prom_initialize_tce_table\n"); - - /* Search all nodes looking for PHBs. */ - for (node = 0; prom_next_node(&node); ) { - if (table == MAX_PHB) { - prom_printf("WARNING: PCI host bridge ignored, " - "need to increase MAX_PHB\n"); - continue; - } - - compatible[0] = 0; - type[0] = 0; - model[0] = 0; - prom_getprop(node, "compatible", - compatible, sizeof(compatible)); - prom_getprop(node, "device_type", type, sizeof(type)); - prom_getprop(node, "model", model, sizeof(model)); - - /* Keep the old logic in tack to avoid regression. */ - if (compatible[0] != 0) { - if ((strstr(compatible, RELOC("python")) == NULL) && - (strstr(compatible, RELOC("Speedwagon")) == NULL) && - (strstr(compatible, RELOC("Winnipeg")) == NULL)) - continue; - } else if (model[0] != 0) { - if ((strstr(model, RELOC("ython")) == NULL) && - (strstr(model, RELOC("peedwagon")) == NULL) && - (strstr(model, RELOC("innipeg")) == NULL)) - continue; - } - - if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) { - continue; - } - - if (prom_getprop(node, "tce-table-minalign", &minalign, - sizeof(minalign)) == PROM_ERROR) { - minalign = 0; - } - - if (prom_getprop(node, "tce-table-minsize", &minsize, - sizeof(minsize)) == PROM_ERROR) { - minsize = 4UL << 20; - } - - /* - * Even though we read what OF wants, we just set the table - * size to 4 MB. This is enough to map 2GB of PCI DMA space. - * By doing this, we avoid the pitfalls of trying to DMA to - * MMIO space and the DMA alias hole. - * - * On POWER4, firmware sets the TCE region by assuming - * each TCE table is 8MB. Using this memory for anything - * else will impact performance, so we always allocate 8MB. - * Anton - */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) - minsize = 8UL << 20; - else - minsize = 4UL << 20; - - /* Align to the greater of the align or size */ - align = max(minalign, minsize); - - /* Carve out storage for the TCE table. */ - base = lmb_alloc(minsize, align); - - if ( !base ) { - prom_panic("ERROR, cannot find space for TCE table.\n"); - } - - vbase = (unsigned long)abs_to_virt(base); - - /* Save away the TCE table attributes for later use. */ - prom_tce_table[table].node = node; - prom_tce_table[table].base = vbase; - prom_tce_table[table].size = minsize; - - prom_debug("TCE table: 0x%x\n", table); - prom_debug("\tnode = 0x%x\n", node); - prom_debug("\tbase = 0x%x\n", vbase); - prom_debug("\tsize = 0x%x\n", minsize); - - /* Initialize the table to have a one-to-one mapping - * over the allocated size. - */ - tce_entryp = (unsigned long *)base; - for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { - tce_entry = (i << PAGE_SHIFT); - tce_entry |= 0x3; - *tce_entryp = tce_entry; - } - - /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - /* Call OF to setup the TCE hardware */ - if (call_prom("package-to-path", 3, 1, node, - path, sizeof(path)-1) == PROM_ERROR) { - prom_printf("package-to-path failed\n"); - } else { - prom_printf("opening PHB %s", path); - } - - phb_node = call_prom("open", 1, 1, path); - if ( (long)phb_node <= 0) { - prom_printf("... failed\n"); - } else { - prom_printf("... done\n"); - } - call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), - phb_node, -1, minsize, - (u32) base, (u32) (base >> 32)); - call_prom("close", 1, 0, phb_node); - - table++; - } - - /* Flag the first invalid entry */ - prom_tce_table[table].node = 0; - prom_debug("ending prom_initialize_tce_table\n"); -} - -/* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of low memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. The holding pattern - * checks that address until its cpu # is there, when it is that - * cpu jumps to __secondary_start(). smp_boot_cpus() takes care - * of setting those values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * Fixup comment... DRENG / PPPBBB - Peter - * - * -- Cort - */ -static void __init prom_hold_cpus(unsigned long mem) -{ - unsigned long i; - unsigned int reg; - phandle node; - unsigned long offset = reloc_offset(); - char type[64], *path; - int cpuid = 0; - unsigned int interrupt_server[MAX_CPU_THREADS]; - unsigned int cpu_threads, hw_cpu_num; - int propsize; - extern void __secondary_hold(void); - extern unsigned long __secondary_hold_spinloop; - extern unsigned long __secondary_hold_acknowledge; - unsigned long *spinloop - = (void *)virt_to_abs(&__secondary_hold_spinloop); - unsigned long *acknowledge - = (void *)virt_to_abs(&__secondary_hold_acknowledge); - unsigned long secondary_hold - = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); - struct systemcfg *_systemcfg = RELOC(systemcfg); - struct paca_struct *lpaca = PTRRELOC(&paca[0]); - struct prom_t *_prom = PTRRELOC(&prom); -#ifdef CONFIG_SMP - struct naca_struct *_naca = RELOC(naca); -#endif - - /* On pmac, we just fill out the various global bitmasks and - * arrays indicating our CPUs are here, they are actually started - * later on from pmac_smp - */ - if (_systemcfg->platform == PLATFORM_POWERMAC) { - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - reg = -1; - prom_getprop(node, "reg", ®, sizeof(reg)); - lpaca[cpuid].hw_cpu_id = reg; - -#ifdef CONFIG_SMP - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_possible_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); - if (reg == 0) - cpu_set(cpuid, RELOC(cpu_online_map)); -#endif /* CONFIG_SMP */ - cpuid++; - } - return; - } - - /* Initially, we must have one active CPU. */ - _systemcfg->processorCount = 1; - - prom_debug("prom_hold_cpus: start...\n"); - prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); - prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); - prom_debug(" 1) acknowledge = 0x%x\n", - (unsigned long)acknowledge); - prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); - prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); - - /* Set the common spinloop variable, so all of the secondary cpus - * will block when they are awakened from their OF spinloop. - * This must occur for both SMP and non SMP kernels, since OF will - * be trashed when we move the kernel. - */ - *spinloop = 0; - -#ifdef CONFIG_HMT - for (i=0; i < NR_CPUS; i++) { - RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; - } -#endif - /* look for cpus */ - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - - /* Skip non-configured cpus. */ - prom_getprop(node, "status", type, sizeof(type)); - if (strcmp(type, RELOC("okay")) != 0) - continue; - - reg = -1; - prom_getprop(node, "reg", ®, sizeof(reg)); - - path = (char *) mem; - memset(path, 0, 256); - if (call_prom("package-to-path", 3, 1, - node, path, 255) == PROM_ERROR) - continue; - - prom_debug("\ncpuid = 0x%x\n", cpuid); - prom_debug("cpu hw idx = 0x%x\n", reg); - lpaca[cpuid].hw_cpu_id = reg; - - /* Init the acknowledge var which will be reset by - * the secondary cpu when it awakens from its OF - * spinloop. - */ - *acknowledge = (unsigned long)-1; - - propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", - &interrupt_server, - sizeof(interrupt_server)); - if (propsize < 0) { - /* no property. old hardware has no SMT */ - cpu_threads = 1; - interrupt_server[0] = reg; /* fake it with phys id */ - } else { - /* We have a threaded processor */ - cpu_threads = propsize / sizeof(u32); - if (cpu_threads > MAX_CPU_THREADS) { - prom_printf("SMT: too many threads!\n" - "SMT: found %x, max is %x\n", - cpu_threads, MAX_CPU_THREADS); - cpu_threads = 1; /* ToDo: panic? */ - } - } - - hw_cpu_num = interrupt_server[0]; - if (hw_cpu_num != _prom->cpu) { - /* Primary Thread of non-boot cpu */ - prom_printf("%x : starting cpu %s... ", cpuid, path); - call_prom("start-cpu", 3, 0, node, - secondary_hold, cpuid); - - for ( i = 0 ; (i < 100000000) && - (*acknowledge == ((unsigned long)-1)); i++ ) ; - - if (*acknowledge == cpuid) { - prom_printf("... done\n"); - /* We have to get every CPU out of OF, - * even if we never start it. */ - if (cpuid >= NR_CPUS) - goto next; -#ifdef CONFIG_SMP - /* Set the number of active processors. */ - _systemcfg->processorCount++; - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_possible_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); -#endif - } else { - prom_printf("... failed: %x\n", *acknowledge); - } - } -#ifdef CONFIG_SMP - else { - prom_printf("%x : booting cpu %s\n", cpuid, path); - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_possible_map)); - cpu_set(cpuid, RELOC(cpu_online_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); - } -#endif -next: -#ifdef CONFIG_SMP - /* Init paca for secondary threads. They start later. */ - for (i=1; i < cpu_threads; i++) { - cpuid++; - if (cpuid >= NR_CPUS) - continue; - lpaca[cpuid].hw_cpu_id = interrupt_server[i]; - prom_printf("%x : preparing thread ... ", - interrupt_server[i]); - if (_naca->smt_state) { - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); - prom_printf("available\n"); - } else { - prom_printf("not available\n"); - } - } -#endif - cpuid++; - } -#ifdef CONFIG_HMT - /* Only enable HMT on processors that provide support. */ - if (__is_processor(PV_PULSAR) || - __is_processor(PV_ICESTAR) || - __is_processor(PV_SSTAR)) { - prom_printf(" starting secondary threads\n"); - - for (i = 0; i < NR_CPUS; i += 2) { - if (!cpu_online(i)) - continue; - - if (i == 0) { - unsigned long pir = _get_PIR(); - if (__is_processor(PV_PULSAR)) { - RELOC(hmt_thread_data)[i].pir = - pir & 0x1f; - } else { - RELOC(hmt_thread_data)[i].pir = - pir & 0x3ff; - } - } -/* cpu_set(i+1, cpu_online_map); */ - cpu_set(i+1, RELOC(cpu_possible_map)); - } - _systemcfg->processorCount *= 2; - } else { - prom_printf("Processor is not HMT capable\n"); - } -#endif - - if (cpuid > NR_CPUS) - prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) - ") exceeded: ignoring extras\n"); - - prom_debug("prom_hold_cpus: end...\n"); -} - -static void __init smt_setup(void) -{ - char *p, *q; - char my_smt_enabled = SMT_DYNAMIC; - ihandle prom_options = 0; - char option[9]; - unsigned long offset = reloc_offset(); - struct naca_struct *_naca = RELOC(naca); - char found = 0; - - if (strstr(RELOC(cmd_line), RELOC("smt-enabled="))) { - for (q = RELOC(cmd_line); (p = strstr(q, RELOC("smt-enabled="))) != 0; ) { - q = p + 12; - if (p > RELOC(cmd_line) && p[-1] != ' ') - continue; - found = 1; - if (q[0] == 'o' && q[1] == 'f' && - q[2] == 'f' && (q[3] == ' ' || q[3] == '\0')) { - my_smt_enabled = SMT_OFF; - } else if (q[0]=='o' && q[1] == 'n' && - (q[2] == ' ' || q[2] == '\0')) { - my_smt_enabled = SMT_ON; - } else { - my_smt_enabled = SMT_DYNAMIC; - } - } - } - if (!found) { - prom_options = call_prom("finddevice", 1, 1, ADDR("/options")); - if (prom_options != (ihandle) -1) { - prom_getprop(prom_options, "ibm,smt-enabled", - option, sizeof(option)); - if (option[0] != 0) { - found = 1; - if (!strcmp(option, RELOC("off"))) - my_smt_enabled = SMT_OFF; - else if (!strcmp(option, RELOC("on"))) - my_smt_enabled = SMT_ON; - else - my_smt_enabled = SMT_DYNAMIC; - } - } - } - - if (!found ) - my_smt_enabled = SMT_DYNAMIC; /* default to on */ - - _naca->smt_state = my_smt_enabled; -} - - -#ifdef CONFIG_BOOTX_TEXT - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -static void __init setup_disp_fake_bi(ihandle dp) -{ - int width = 640, height = 480, depth = 8, pitch; - unsigned address; - struct pci_reg_property addrs[8]; - int i, naddrs; - char name[64]; - unsigned long offset = reloc_offset(); - - memset(name, 0, sizeof(name)); - prom_getprop(dp, "name", name, sizeof(name)); - name[sizeof(name)-1] = 0; - prom_printf("Initializing fake screen: %s\n", name); - - prom_getprop(dp, "width", &width, sizeof(width)); - prom_getprop(dp, "height", &height, sizeof(height)); - prom_getprop(dp, "depth", &depth, sizeof(depth)); - pitch = width * ((depth + 7) / 8); - prom_getprop(dp, "linebytes", &pitch, sizeof(pitch)); - if (pitch == 1) - pitch = 0x1000; /* for strange IBM display */ - address = 0; - - prom_printf("width %x height %x depth %x linebytes %x\n", - width, height, depth, depth); - - prom_getprop(dp, "address", &address, sizeof(address)); - if (address == 0) { - /* look for an assigned address with a size of >= 1MB */ - naddrs = prom_getprop(dp, "assigned-addresses", - addrs, sizeof(addrs)); - naddrs /= sizeof(struct pci_reg_property); - for (i = 0; i < naddrs; ++i) { - if (addrs[i].size_lo >= (1 << 20)) { - address = addrs[i].addr.a_lo; - /* use the BE aperture if possible */ - if (addrs[i].size_lo >= (16 << 20)) - address += (8 << 20); - break; - } - } - if (address == 0) { - prom_printf("Failed to get address of frame buffer\n"); - return; - } - } - btext_setup_display(width, height, depth, pitch, address); - prom_printf("Addr of fb: %x\n", address); - RELOC(boot_text_mapped) = 0; -} -#endif /* CONFIG_BOOTX_TEXT */ - -static void __init prom_init_client_services(unsigned long pp) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - /* Get a handle to the prom entry point before anything else */ - _prom->entry = pp; - - /* Init default value for phys size */ - _prom->encode_phys_size = 32; - - /* get a handle for the stdout device */ - _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if ((long)_prom->chosen <= 0) - prom_panic("cannot find chosen"); /* msg won't be printed :( */ - - /* get device tree root */ - _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if ((long)_prom->root <= 0) - prom_panic("cannot find device tree root"); /* msg won't be printed :( */ -} - -static void __init prom_init_stdout(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - u32 val; - - if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) - prom_panic("cannot find stdout"); - - _prom->stdout = val; -} - -static int __init prom_find_machine_type(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char compat[256]; - int len, i = 0; - - len = prom_getprop(_prom->root, "compatible", - compat, sizeof(compat)-1); - if (len > 0) { - compat[len] = 0; - while (i < len) { - char *p = &compat[i]; - int sl = strlen(p); - if (sl == 0) - break; - if (strstr(p, RELOC("Power Macintosh")) || - strstr(p, RELOC("MacRISC4"))) - return PLATFORM_POWERMAC; - i += sl + 1; - } - } - /* Default to pSeries */ - return PLATFORM_PSERIES; -} - -static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) -{ - unsigned long offset = reloc_offset(); - - return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); -} - -/* - * 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 - * later. However, OF will probably fall over if we do that - * we've taken over the MMU. - * So we check whether we will need to open the display, - * and if so, open it now. - */ -static unsigned long __init check_display(unsigned long mem) -{ - phandle node; - ihandle ih; - int i, j; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char type[16], *path; - static unsigned char default_colors[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0xaa, - 0x00, 0xaa, 0x00, - 0x00, 0xaa, 0xaa, - 0xaa, 0x00, 0x00, - 0xaa, 0x00, 0xaa, - 0xaa, 0xaa, 0x00, - 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, - 0x55, 0x55, 0xff, - 0x55, 0xff, 0x55, - 0x55, 0xff, 0xff, - 0xff, 0x55, 0x55, - 0xff, 0x55, 0xff, - 0xff, 0xff, 0x55, - 0xff, 0xff, 0xff - }; - const unsigned char *clut; - - _prom->disp_node = 0; - - prom_printf("Looking for displays\n"); - if (RELOC(of_stdout_device) != 0) - prom_printf("OF stdout is : %s\n", - PTRRELOC(RELOC(of_stdout_device))); - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("display")) != 0) - continue; - /* It seems OF doesn't null-terminate the path :-( */ - path = (char *) mem; - memset(path, 0, 256); - - /* - * leave some room at the end of the path for appending extra - * arguments - */ - if (call_prom("package-to-path", 3, 1, node, path, 250) < 0) - continue; - prom_printf("found display : %s\n", path); - - /* - * If this display is the device that OF is using for stdout, - * move it to the front of the list. - */ - mem += strlen(path) + 1; - i = RELOC(prom_num_displays); - RELOC(prom_num_displays) = i + 1; - if (RELOC(of_stdout_device) != 0 && i > 0 - && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { - for (; i > 0; --i) { - RELOC(prom_display_paths[i]) - = RELOC(prom_display_paths[i-1]); - RELOC(prom_display_nodes[i]) - = RELOC(prom_display_nodes[i-1]); - } - _prom->disp_node = node; - } - RELOC(prom_display_paths[i]) = PTRUNRELOC(path); - RELOC(prom_display_nodes[i]) = node; - if (_prom->disp_node == 0) - _prom->disp_node = node; - if (RELOC(prom_num_displays) >= FB_MAX) - break; - } - prom_printf("Opening displays...\n"); - for (j = RELOC(prom_num_displays) - 1; j >= 0; j--) { - path = PTRRELOC(RELOC(prom_display_paths[j])); - prom_printf("opening display : %s", path); - ih = call_prom("open", 1, 1, path); - if (ih == (ihandle)0 || ih == (ihandle)-1) { - prom_printf("... failed\n"); - continue; - } - - prom_printf("... done\n"); - - /* Setup a useable color table when the appropriate - * method is available. Should update this to set-colors */ - clut = RELOC(default_colors); - for (i = 0; i < 32; i++, clut += 3) - if (prom_set_color(ih, i, clut[0], clut[1], - clut[2]) != 0) - break; - -#ifdef CONFIG_LOGO_LINUX_CLUT224 - clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); - for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) - if (prom_set_color(ih, i + 32, clut[0], clut[1], - clut[2]) != 0) - break; -#endif /* CONFIG_LOGO_LINUX_CLUT224 */ - } - - return DOUBLEWORD_ALIGN(mem); -} - -/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ -static void __init *__make_room(unsigned long *mem_start, unsigned long *mem_end, - unsigned long needed, unsigned long align) -{ - void *ret; - - *mem_start = ALIGN(*mem_start, align); - if (*mem_start + needed > *mem_end) { -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long offset = reloc_offset(); - /* FIXME: Apple OF doesn't map unclaimed mem. If this - * ever happened on G5, we'd need to fix. */ - unsigned long initrd_len; - - if (*mem_end != RELOC(initrd_start)) - prom_panic("No memory for copy_device_tree"); - - prom_printf("Huge device_tree: moving initrd\n"); - /* Move by 4M. */ - initrd_len = RELOC(initrd_end) - RELOC(initrd_start); - *mem_end = RELOC(initrd_start) + 4 * 1024 * 1024; - memmove((void *)*mem_end, (void *)RELOC(initrd_start), - initrd_len); - RELOC(initrd_start) = *mem_end; - RELOC(initrd_end) = RELOC(initrd_start) + initrd_len; -#else - prom_panic("No memory for copy_device_tree"); -#endif - } - - ret = (void *)*mem_start; - *mem_start += needed; - - return ret; -} - -#define make_room(startp, endp, type) \ - __make_room(startp, endp, sizeof(type), __alignof__(type)) - -static void __init -inspect_node(phandle node, struct device_node *dad, - unsigned long *mem_start, unsigned long *mem_end, - struct device_node ***allnextpp) -{ - int l; - phandle child; - struct device_node *np; - struct property *pp, **prev_propp; - char *prev_name, *namep; - unsigned char *valp; - unsigned long offset = reloc_offset(); - phandle ibm_phandle; - - np = make_room(mem_start, mem_end, struct device_node); - memset(np, 0, sizeof(*np)); - - np->node = node; - **allnextpp = PTRUNRELOC(np); - *allnextpp = &np->allnext; - if (dad != 0) { - np->parent = PTRUNRELOC(dad); - /* we temporarily use the `next' field as `last_child'. */ - if (dad->next == 0) - dad->child = PTRUNRELOC(np); - else - dad->next->sibling = PTRUNRELOC(np); - dad->next = np; - } - - /* get and store all properties */ - prev_propp = &np->properties; - prev_name = RELOC(""); - for (;;) { - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, char[32]); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { - /* No more nodes: unwind alloc */ - *mem_start = (unsigned long)namep; - break; - } - /* Trim off some if we can */ - *mem_start = DOUBLEWORD_ALIGN((unsigned long)namep - + strlen(namep) + 1); - pp = make_room(mem_start, mem_end, struct property); - pp->name = PTRUNRELOC(namep); - prev_name = namep; - - pp->length = call_prom("getproplen", 2, 1, node, namep); - if (pp->length < 0) - continue; - if (pp->length > MAX_PROPERTY_LENGTH) { - char path[128]; - - prom_printf("WARNING: ignoring large property "); - /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - if (call_prom("package-to-path", 3, 1, node, - path, sizeof(path)-1) > 0) - prom_printf("[%s] ", path); - prom_printf("%s length 0x%x\n", namep, pp->length); - continue; - } - valp = __make_room(mem_start, mem_end, pp->length, 1); - pp->value = PTRUNRELOC(valp); - call_prom("getprop", 4, 1, node, namep, valp, pp->length); - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - } - - /* Add a "linux,phandle" property. */ - namep = make_room(mem_start, mem_end, char[16]); - strcpy(namep, RELOC("linux,phandle")); - pp = make_room(mem_start, mem_end, struct property); - pp->name = PTRUNRELOC(namep); - pp->length = sizeof(phandle); - valp = make_room(mem_start, mem_end, phandle); - pp->value = PTRUNRELOC(valp); - *(phandle *)valp = node; - *prev_propp = PTRUNRELOC(pp); - pp->next = NULL; - - /* Set np->linux_phandle to the value of the ibm,phandle property - if it exists, otherwise to the phandle for this node. */ - np->linux_phandle = node; - if (prom_getprop(node, "ibm,phandle", - &ibm_phandle, sizeof(ibm_phandle)) > 0) - np->linux_phandle = ibm_phandle; - - /* get the node's full name */ - namep = (char *)*mem_start; - l = call_prom("package-to-path", 3, 1, node, - namep, *mem_end - *mem_start); - if (l >= 0) { - /* Didn't fit? Get more room. */ - if (l+1 > *mem_end - *mem_start) { - namep = __make_room(mem_start, mem_end, l+1, 1); - call_prom("package-to-path", 3, 1, node, namep, l); - } - np->full_name = PTRUNRELOC(namep); - namep[l] = '\0'; - *mem_start = DOUBLEWORD_ALIGN(*mem_start + l + 1); - } - - /* do all our children */ - child = call_prom("child", 1, 1, node); - while (child != (phandle)0) { - inspect_node(child, np, mem_start, mem_end, - allnextpp); - child = call_prom("peer", 1, 1, child); - } -} - -/* - * Make a copy of the device tree from the PROM. - */ -static unsigned long __init -copy_device_tree(unsigned long mem_start) -{ - phandle root; - struct device_node **allnextp; - unsigned long offset = reloc_offset(); - unsigned long mem_end; - - /* We pass mem_end-mem_start to OF: keep it well under 32-bit */ - mem_end = mem_start + 1024*1024*1024; -#ifdef CONFIG_BLK_DEV_INITRD - if (RELOC(initrd_start) && RELOC(initrd_start) > mem_start) - mem_end = RELOC(initrd_start); -#endif /* CONFIG_BLK_DEV_INITRD */ - - root = call_prom("peer", 1, 1, (phandle)0); - if (root == (phandle)0) { - prom_panic("couldn't get device tree root\n"); - } - allnextp = &RELOC(allnodes); - inspect_node(root, NULL, &mem_start, &mem_end, &allnextp); - *allnextp = NULL; - return mem_start; -} - -/* Verify bi_recs are good */ -static struct bi_record * __init prom_bi_rec_verify(struct bi_record *bi_recs) -{ - struct bi_record *first, *last; - - prom_debug("birec_verify: r6=0x%x\n", (unsigned long)bi_recs); - if (bi_recs != NULL) - prom_debug(" tag=0x%x\n", bi_recs->tag); - - if ( bi_recs == NULL || bi_recs->tag != BI_FIRST ) - return NULL; - - last = (struct bi_record *)(long)bi_recs->data[0]; - - prom_debug(" last=0x%x\n", (unsigned long)last); - if (last != NULL) - prom_debug(" last_tag=0x%x\n", last->tag); - - if ( last == NULL || last->tag != BI_LAST ) - return NULL; - - first = (struct bi_record *)(long)last->data[0]; - prom_debug(" first=0x%x\n", (unsigned long)first); - - if ( first == NULL || first != bi_recs ) - return NULL; - - return bi_recs; -} - -static void __init prom_bi_rec_reserve(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct bi_record *rec; - - if ( _prom->bi_recs != NULL) { - - for ( rec=_prom->bi_recs; - rec->tag != BI_LAST; - rec=bi_rec_next(rec) ) { - prom_debug("bi: 0x%x\n", rec->tag); - switch (rec->tag) { -#ifdef CONFIG_BLK_DEV_INITRD - case BI_INITRD: - RELOC(initrd_start) = (unsigned long)(rec->data[0]); - RELOC(initrd_end) = RELOC(initrd_start) + rec->data[1]; - break; -#endif /* CONFIG_BLK_DEV_INITRD */ - } - } - /* The next use of this field will be after relocation - * is enabled, so convert this physical address into a - * virtual address. - */ - _prom->bi_recs = PTRUNRELOC(_prom->bi_recs); - } -} - -/* - * We enter here early on, when the Open Firmware prom is still - * handling exceptions and the MMU hash table for us. - */ - -unsigned long __init -prom_init(unsigned long r3, unsigned long r4, unsigned long pp, - unsigned long r6, unsigned long r7) -{ - unsigned long mem; - ihandle prom_cpu; - phandle cpu_pkg; - unsigned long offset = reloc_offset(); - long l; - char *p, *d; - unsigned long phys; - u32 getprop_rval; - struct systemcfg *_systemcfg; - struct paca_struct *lpaca = PTRRELOC(&paca[0]); - struct prom_t *_prom = PTRRELOC(&prom); - - /* First zero the BSS -- use memset, some arches don't have - * caches on yet */ - memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); - - /* Setup systemcfg and NACA pointers now */ - RELOC(systemcfg) = _systemcfg = (struct systemcfg *)(SYSTEMCFG_VIRT_ADDR - offset); - RELOC(naca) = (struct naca_struct *)(NACA_VIRT_ADDR - offset); - - /* Init interface to Open Firmware and pickup bi-recs */ - prom_init_client_services(pp); - - /* Init prom stdout device */ - prom_init_stdout(); - - prom_debug("klimit=0x%x\n", RELOC(klimit)); - prom_debug("offset=0x%x\n", offset); - prom_debug("->mem=0x%x\n", RELOC(klimit) - offset); - - /* check out if we have bi_recs */ - _prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6); - if ( _prom->bi_recs != NULL ) { - RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + - _prom->bi_recs->data[1]); - prom_debug("bi_recs=0x%x\n", (unsigned long)_prom->bi_recs); - prom_debug("new mem=0x%x\n", RELOC(klimit) - offset); - } - - /* If we don't have birec's or didn't find them, check for an initrd - * using the "yaboot" way - */ -#ifdef CONFIG_BLK_DEV_INITRD - if ( _prom->bi_recs == NULL && r3 && r4 && r4 != 0xdeadbeef) { - RELOC(initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; - RELOC(initrd_end) = RELOC(initrd_start) + r4; - RELOC(initrd_below_start_ok) = 1; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Default machine type. */ - _systemcfg->platform = prom_find_machine_type(); - - /* On pSeries, copy the CPU hold code */ - if (_systemcfg->platform == PLATFORM_PSERIES) - copy_and_flush(0, KERNELBASE - offset, 0x100, 0); - - /* Start storing things at klimit */ - mem = RELOC(klimit) - offset; - - /* Get the full OF pathname of the stdout device */ - p = (char *) mem; - memset(p, 0, 256); - call_prom("instance-to-path", 3, 1, _prom->stdout, p, 255); - RELOC(of_stdout_device) = PTRUNRELOC(p); - mem += strlen(p) + 1; - - getprop_rval = 1; - prom_getprop(_prom->root, "#size-cells", - &getprop_rval, sizeof(getprop_rval)); - _prom->encode_phys_size = (getprop_rval == 1) ? 32 : 64; - - /* Determine which cpu is actually running right _now_ */ - if (prom_getprop(_prom->chosen, "cpu", - &prom_cpu, sizeof(prom_cpu)) <= 0) - prom_panic("cannot find boot cpu"); - - cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); - prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); - _prom->cpu = getprop_rval; - lpaca[0].hw_cpu_id = _prom->cpu; - - RELOC(boot_cpuid) = 0; - - prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); - - /* Get the boot device and translate it to a full OF pathname. */ - p = (char *) mem; - l = prom_getprop(_prom->chosen, "bootpath", p, 1<<20); - if (l > 0) { - p[l] = 0; /* should already be null-terminated */ - RELOC(bootpath) = PTRUNRELOC(p); - mem += l + 1; - d = (char *) mem; - *d = 0; - call_prom("canon", 3, 1, p, d, 1<<20); - RELOC(bootdevice) = PTRUNRELOC(d); - mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1); - } - - RELOC(cmd_line[0]) = 0; - if ((long)_prom->chosen > 0) { - prom_getprop(_prom->chosen, "bootargs", p, sizeof(cmd_line)); - if (p != NULL && p[0] != 0) - strlcpy(RELOC(cmd_line), p, sizeof(cmd_line)); - } - - early_cmdline_parse(); - - prom_initialize_lmb(); - - prom_bi_rec_reserve(); - - mem = check_display(mem); - - if (_systemcfg->platform != PLATFORM_POWERMAC) - prom_instantiate_rtas(); - - /* Initialize some system info into the Naca early... */ - prom_initialize_naca(); - - smt_setup(); - - /* If we are on an SMP machine, then we *MUST* do the - * following, regardless of whether we have an SMP - * kernel or not. - */ - prom_hold_cpus(mem); - - prom_debug("after basic inits, mem=0x%x\n", mem); -#ifdef CONFIG_BLK_DEV_INITRD - prom_debug("initrd_start=0x%x\n", RELOC(initrd_start)); - prom_debug("initrd_end=0x%x\n", RELOC(initrd_end)); -#endif /* CONFIG_BLK_DEV_INITRD */ - prom_debug("copying OF device tree...\n"); - - mem = copy_device_tree(mem); - - RELOC(klimit) = mem + offset; - - prom_debug("new klimit is\n"); - prom_debug("klimit=0x%x\n", RELOC(klimit)); - prom_debug(" ->mem=0x%x\n", mem); - - lmb_reserve(0, __pa(RELOC(klimit))); - -#ifdef CONFIG_BLK_DEV_INITRD - if (RELOC(initrd_start)) { - unsigned long initrd_len; - initrd_len = RELOC(initrd_end) - RELOC(initrd_start); - - /* Move initrd if it's where we're going to copy kernel. */ - if (RELOC(initrd_start) < __pa(RELOC(klimit))) { - memmove((void *)mem, (void *)RELOC(initrd_start), - initrd_len); - RELOC(initrd_start) = mem; - RELOC(initrd_end) = mem + initrd_len; - } - - lmb_reserve(RELOC(initrd_start), initrd_len); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - if (_systemcfg->platform == PLATFORM_PSERIES) - prom_initialize_tce_table(); - -#ifdef CONFIG_PMAC_DART - if (_systemcfg->platform == PLATFORM_POWERMAC) - prom_initialize_dart_table(); -#endif - -#ifdef CONFIG_BOOTX_TEXT - if (_prom->disp_node) { - prom_printf("Setting up bi display...\n"); - setup_disp_fake_bi(_prom->disp_node); - } -#endif /* CONFIG_BOOTX_TEXT */ - - prom_printf("Calling quiesce ...\n"); - call_prom("quiesce", 0, 0); - phys = KERNELBASE - offset; - -#ifdef CONFIG_BLK_DEV_INITRD - /* If we had an initrd, we convert its address to virtual */ - if (RELOC(initrd_start)) { - RELOC(initrd_start) = (unsigned long)__va(RELOC(initrd_start)); - RELOC(initrd_end) = (unsigned long)__va(RELOC(initrd_end)); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - prom_printf("returning from prom_init\n"); - return phys; -} +/* export that to outside world */ +struct device_node *of_chosen; /* * Find the device_node with a given phandle. */ -static struct device_node * __devinit -find_phandle(phandle ph) +static struct device_node * find_phandle(phandle ph) { struct device_node *np; @@ -1866,8 +118,7 @@ /* * Find the interrupt parent of a node. */ -static struct device_node * __devinit -intr_parent(struct device_node *p) +static struct device_node * __devinit intr_parent(struct device_node *p) { phandle *parp; @@ -1908,14 +159,14 @@ * Map an interrupt from a device up to the platform interrupt * descriptor. */ -static int __devinit -map_interrupt(unsigned int **irq, struct device_node **ictrler, - struct device_node *np, unsigned int *ints, int nintrc) +static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler, + struct device_node *np, unsigned int *ints, + int nintrc) { struct device_node *p, *ipar; unsigned int *imap, *imask, *ip; int i, imaplen, match; - int newintrc, newaddrc; + int newintrc = 0, newaddrc = 0; unsigned int *reg; int naddrc; @@ -2004,9 +255,9 @@ return nintrc; } -static unsigned long __init -finish_node_interrupts(struct device_node *np, unsigned long mem_start, - int measure_only) +static unsigned long __init finish_node_interrupts(struct device_node *np, + unsigned long mem_start, + int measure_only) { unsigned int *ints; int intlen, intrcells, intrcount; @@ -2067,9 +318,10 @@ return mem_start; } -static unsigned long __init -interpret_pci_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_pci_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct address_range *adr; struct pci_reg_property *pci_addrs; @@ -2095,9 +347,10 @@ return mem_start; } -static unsigned long __init -interpret_dbdma_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_dbdma_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct reg_property32 *rp; struct address_range *adr; @@ -2135,9 +388,10 @@ return mem_start; } -static unsigned long __init -interpret_macio_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_macio_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct reg_property32 *rp; struct address_range *adr; @@ -2175,9 +429,10 @@ return mem_start; } -static unsigned long __init -interpret_isa_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_isa_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct isa_reg_property *rp; struct address_range *adr; @@ -2203,9 +458,10 @@ return mem_start; } -static unsigned long __init -interpret_root_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_root_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct address_range *adr; int i, l; @@ -2233,21 +489,15 @@ return mem_start; } -static unsigned long __init -finish_node(struct device_node *np, unsigned long mem_start, - interpret_func *ifunc, int naddrc, int nsizec, int measure_only) +static unsigned long __init finish_node(struct device_node *np, + unsigned long mem_start, + interpret_func *ifunc, + int naddrc, int nsizec, + int measure_only) { struct device_node *child; int *ip; - np->name = get_property(np, "name", NULL); - np->type = get_property(np, "device_type", NULL); - - if (!np->name) - np->name = ""; - if (!np->type) - np->type = ""; - /* get the device addresses and interrupts */ if (ifunc != NULL) mem_start = ifunc(np, mem_start, naddrc, nsizec, measure_only); @@ -2298,24 +548,516 @@ /** * finish_device_tree is called once things are running normally * (i.e. with text and data mapped to the address they were linked at). - * It traverses the device tree and fills in the name, type, - * {n_}addrs and {n_}intrs fields of each node. + * It traverses the device tree and fills in some of the additional, + * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt + * mapping is also initialized at this point. */ -void __init -finish_device_tree(void) +void __init finish_device_tree(void) { - unsigned long mem = klimit; + unsigned long mem, size; + DBG(" -> finish_device_tree\n"); + + if (naca->interrupt_controller == IC_INVALID) { + DBG("failed to configure interrupt controller type\n"); + panic("failed to configure interrupt controller type\n"); + } + + /* Initialize virtual IRQ map */ virt_irq_init(); - dev_tree_size = finish_node(allnodes, 0, NULL, 0, 0, 1); - mem = (long)abs_to_virt(lmb_alloc(dev_tree_size, - __alignof__(struct device_node))); - if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + dev_tree_size) + /* Finish device-tree (pre-parsing some properties etc...) */ + size = finish_node(allnodes, 0, NULL, 0, 0, 1); + mem = (unsigned long)abs_to_virt(lmb_alloc(size, 128)); + if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + size) BUG(); - rtas.dev = of_find_node_by_name(NULL, "rtas"); + + DBG(" <- finish_device_tree\n"); +} + +#ifdef DEBUG +#define printk udbg_printf +#endif + +static inline char *find_flat_dt_string(u32 offset) +{ + return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings + + offset; +} + +/** + * This function is used to scan the flattened device-tree, it is + * used to extract the memory informations at boot before we can + * unflatten the tree + */ +static int __init scan_flat_dt(int (*it)(unsigned long node, + const char *full_path, void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + int rc = 0; + + do { + u32 tag = *((u32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = *((u32 *)p); + p += 8; + p = _ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = _ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + printk(KERN_WARNING "Invalid tag %x scanning flattened" + " device tree !\n", tag); + return -EINVAL; + } + pathp = (char *)p; + p = _ALIGN(p + strlen(pathp) + 1, 4); + rc = it(p, pathp, data); + if (rc != 0) + break; + } while(1); + + return rc; } +/** + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +static void* __init get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = *((u32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag != OF_DT_PROP) + return NULL; + + sz = *((u32 *)p); + noff = *((u32 *)(p + 4)); + p += 8; + p = _ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = find_flat_dt_string(noff); + if (nstr == NULL) { + printk(KERN_WARNING "Can't find property index name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = _ALIGN(p, 4); + } while(1); +} + +static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = _ALIGN(*mem, align); + res = (void *)*mem; + *mem += size; + + return res; +} + +static unsigned long __init unflatten_dt_node(unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp) +{ + struct device_node *np; + struct property *pp, **prev_pp = NULL; + char *pathp; + u32 tag; + unsigned int l; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_BEGIN_NODE) { + printk("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + pathp = (char *)*p; + l = strlen(pathp) + 1; + *p = _ALIGN(*p + l, 4); + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, + __alignof__(struct device_node)); + if (allnextpp) { + memset(np, 0, sizeof(*np)); + np->full_name = ((char*)np) + sizeof(struct device_node); + memcpy(np->full_name, pathp, l); + prev_pp = &np->properties; + **allnextpp = np; + *allnextpp = &np->allnext; + if (dad != NULL) { + np->parent = dad; + /* we temporarily use the `next' field as `last_child'. */ + if (dad->next == 0) + dad->child = np; + else + dad->next->sibling = np; + dad->next = np; + } + } + while(1) { + u32 sz, noff; + char *pname; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_PROP) + break; + *p += 4; + sz = *((u32 *)(*p)); + noff = *((u32 *)((*p) + 4)); + *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); + + pname = find_flat_dt_string(noff); + if (pname == NULL) { + printk("Can't find property name in list !\n"); + break; + } + l = strlen(pname) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property), + __alignof__(struct property)); + if (allnextpp) { + if (strcmp(pname, "linux,phandle") == 0) { + np->node = *((u32 *)*p); + if (np->linux_phandle == 0) + np->linux_phandle = np->node; + } + if (strcmp(pname, "ibm,phandle") == 0) + np->linux_phandle = *((u32 *)*p); + pp->name = pname; + pp->length = sz; + pp->value = (void *)*p; + *prev_pp = pp; + prev_pp = &pp->next; + } + *p = _ALIGN((*p) + sz, 4); + } + if (allnextpp) { + *prev_pp = NULL; + np->name = get_property(np, "name", NULL); + np->type = get_property(np, "device_type", NULL); + + if (!np->name) + np->name = ""; + if (!np->type) + np->type = ""; + } + while (tag == OF_DT_BEGIN_NODE) { + mem = unflatten_dt_node(mem, p, np, allnextpp); + tag = *((u32 *)(*p)); + } + if (tag != OF_DT_END_NODE) { + printk("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + return mem; +} + + +/** + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used (this used to be done by finish_device_tree) + */ +void __init unflatten_device_tree(void) +{ + unsigned long start, mem, size; + struct device_node **allnextp = &allnodes; + char *p; + int l = 0; + + DBG(" -> unflatten_device_tree()\n"); + + /* First pass, scan for size */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + size = unflatten_dt_node(0, &start, NULL, NULL); + + DBG(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = (unsigned long)abs_to_virt(lmb_alloc(size, + __alignof__(struct device_node))); + DBG(" unflattening...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + unflatten_dt_node(mem, &start, NULL, &allnextp); + if (*((u32 *)start) != OF_DT_END) + printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); + *allnextp = NULL; + + /* Get pointer to OF "/chosen" node for use everywhere */ + of_chosen = of_find_node_by_path("/chosen"); + + /* Retreive command line */ + if (of_chosen != NULL) { + p = (char *)get_property(of_chosen, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE)); + } +#ifdef CONFIG_CMDLINE + if (l == 0) /* dbl check */ + strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif /* CONFIG_CMDLINE */ + + DBG("Command line is: %s\n", cmd_line); + + DBG(" <- unflatten_device_tree()\n"); +} + + +static int __init early_init_dt_scan_cpus(unsigned long node, + const char *full_path, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + + /* We are scanning "cpu" nodes only */ + if (type == NULL || strcmp(type, "cpu") != 0) + return 0; + + /* On LPAR, look for the first ibm,pft-size property for the hash table size + */ + if (systemcfg->platform == PLATFORM_PSERIES_LPAR && naca->pftSize == 0) { + u32 *pft_size; + pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL); + if (pft_size != NULL) { + /* pft_size[0] is the NUMA CEC cookie */ + naca->pftSize = pft_size[1]; + } + } + + /* Check if it's the boot-cpu, set it's hw index in paca now */ + if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { + u32 *prop = get_flat_dt_prop(node, "reg", NULL); + paca[0].hw_cpu_id = prop == NULL ? 0 : *prop; + } + + return 0; +} + +static int __init early_init_dt_scan_chosen(unsigned long node, + const char *full_path, void *data) +{ + u32 *prop; + + if (strcmp(full_path, "/chosen") != 0) + return 0; + + /* get platform type */ + prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL); + if (prop == NULL) + return 0; + systemcfg->platform = *prop; + + /* check if iommu is forced on or off */ + if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) + iommu_is_off = 1; + if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL) + iommu_force_on = 1; + +#ifdef CONFIG_PPC_PSERIES + /* To help early debugging via the front panel, we retreive a minimal + * set of RTAS infos now if available + */ + { + u64 *basep, *entryp; + + basep = (u64*)get_flat_dt_prop(node, "linux,rtas-base", NULL); + entryp = (u64*)get_flat_dt_prop(node, "linux,rtas-entry", NULL); + prop = (u32*)get_flat_dt_prop(node, "linux,rtas-size", NULL); + if (basep && entryp && prop) { + rtas.base = *basep; + rtas.entry = *entryp; + rtas.size = *prop; + } + } +#endif /* CONFIG_PPC_PSERIES */ + + /* break now */ + return 1; +} + +static int __init early_init_dt_scan_root(unsigned long node, + const char *full_path, void *data) +{ + u32 *prop; + + if (strcmp(full_path, "/") != 0) + return 0; + + prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); + dt_root_size_cells = (prop == NULL) ? 1 : *prop; + + prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); + dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + + /* break now */ + return 1; +} + +static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r = 0; + + /* Ignore more than 2 cells */ + while (s > 2) { + p++; + s--; + } + while (s) { + r <<= 32; + r |= *(p++); + s--; + } + + *cellp = p; + return r; +} + + +static int __init early_init_dt_scan_memory(unsigned long node, + const char *full_path, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + cell_t *reg, *endp; + unsigned long l; + + /* We are scanning "memory" nodes only */ + if (type == NULL || strcmp(type, "memory") != 0) + return 0; + + reg = (cell_t *)get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(cell_t)); + + DBG("memory scan node %s ...\n", full_path); + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + unsigned long base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + if (size == 0) + continue; + DBG(" - %lx , %lx\n", base, size); + if (iommu_is_off) { + if (base >= 0x80000000ul) + continue; + if ((base + size) > 0x80000000ul) + size = 0x80000000ul - base; + } + lmb_add(base, size); + } + return 0; +} + +static void __init early_reserve_mem(void) +{ + u64 base, size; + u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) + + initial_boot_params->off_mem_rsvmap); + while (1) { + base = *(reserve_map++); + size = *(reserve_map++); + if (size == 0) + break; + DBG("reserving: %lx -> %lx\n", base, size); + lmb_reserve(base, size); + } + +#if 0 + DBG("memory reserved, lmbs :\n"); + lmb_dump_all(); +#endif +} + +void __init early_init_devtree(void *params) +{ + DBG(" -> early_init_devtree()\n"); + + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* By default, hash size is not set */ + naca->pftSize = 0; + + /* Retreive various informations from the /chosen node of the + * device-tree, including the platform type, initrd location and + * size, TCE reserve, and more ... + */ + scan_flat_dt(early_init_dt_scan_chosen, NULL); + + /* Scan memory nodes and rebuild LMBs */ + lmb_init(); + scan_flat_dt(early_init_dt_scan_root, NULL); + scan_flat_dt(early_init_dt_scan_memory, NULL); + lmb_analyze(); + systemcfg->physicalMemorySize = lmb_phys_mem_size(); + + DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize); + + /* Reserve LMB regions used by kernel, initrd, dt, etc... */ + early_reserve_mem(); + + DBG("Scanning CPUs ...\n"); + + /* Retreive hash table size from flattened tree */ + scan_flat_dt(early_init_dt_scan_cpus, NULL); + + /* If hash size wasn't obtained above, we calculate it now based on + * the total RAM size + */ + if (naca->pftSize == 0) { + unsigned long rnd_mem_size, pteg_count; + + /* round mem_size up to next power of 2 */ + rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); + if (rnd_mem_size < systemcfg->physicalMemorySize) + rnd_mem_size <<= 1; + + /* # pages / 2 */ + pteg_count = (rnd_mem_size >> (12 + 1)); + + naca->pftSize = __ilog2(pteg_count << 7); + } + + DBG("Hash pftSize: %x\n", (int)naca->pftSize); + DBG(" <- early_init_devtree()\n"); +} + +#undef printk + int prom_n_addr_cells(struct device_node* np) { @@ -2628,6 +1370,28 @@ EXPORT_SYMBOL(of_find_node_by_path); /** + * of_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + read_lock(&devtree_lock); + for (np = allnodes; np != 0; np = np->allnext) + if (np->linux_phandle == handle) + break; + if (np) + of_node_get(np); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_phandle); + +/** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration * of_node_put() will be called on it @@ -2886,6 +1650,7 @@ return 0; } + /* * Fix up the uninitialized fields in a new device node: * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields @@ -2971,12 +1736,14 @@ /* fixing up iommu_table */ +#ifdef CONFIG_PPC_PSERIES if (strcmp(node->name, "pci") == 0 && get_property(node, "ibm,dma-window", NULL)) { node->bussubno = node->busno; iommu_devnode_init(node); } else node->iommu_table = parent->iommu_table; +#endif /* CONFIG_PPC_PSERIES */ out: of_node_put(parent); @@ -3163,3 +1930,13 @@ } } #endif + + + + + + + + + + diff -Nru a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/kernel/prom_init.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,1714 @@ +/* + * + * + * Procedures for interfacing to Open Firmware. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG_PROM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "open_pic.h" + +#ifdef CONFIG_LOGO_LINUX_CLUT224 +#include +extern const struct linux_logo logo_linux_clut224; +#endif + +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This value does need to be big enough to + * ensure that we don't lose things like the interrupt-map property + * on a PCI-PCI bridge. + */ +#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) + +/* + * Eventually bump that one up + */ +#define DEVTREE_CHUNK_SIZE 0x100000 + +/* + * This is the size of the local memory reserve map that gets copied + * into the boot params passed to the kernel. That size is totally + * flexible as the kernel just reads the list until it encounters an + * entry with size 0, so it can be changed without breaking binary + * compatibility + */ +#define MEM_RESERVE_MAP_SIZE 8 + +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at, so + * references to extern and static variables must be relocated + * explicitly. The procedure reloc_offset() returns the address + * we're currently running at minus the address we were linked at. + * (Note that strings count as static variables.) + * + * Because OF may have mapped I/O devices into the area starting at + * KERNELBASE, particularly on CHRP machines, we can't safely call + * OF once the kernel has been mapped to KERNELBASE. Therefore all + * OF calls should be done within prom_init(), and prom_init() + * and all routines called within it must be careful to relocate + * references as necessary. + * + * Note that the bss is cleared *after* prom_init runs, so we have + * to make sure that any static or extern variables it accesses + * are put in the data segment. + */ + + +#define PROM_BUG() do { \ + prom_printf("kernel BUG at %s line 0x%x!\n", \ + RELOC(__FILE__), __LINE__); \ + __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ +} while (0) + +#ifdef DEBUG_PROM +#define prom_debug(x...) prom_printf(x) +#else +#define prom_debug(x...) +#endif + + +typedef u32 prom_arg_t; + +struct prom_args { + u32 service; + u32 nargs; + u32 nret; + prom_arg_t args[10]; + prom_arg_t *rets; /* Pointer to return values in args[16]. */ +}; + +struct prom_t { + unsigned long entry; + ihandle root; + ihandle chosen; + int cpu; + ihandle stdout; + ihandle disp_node; + struct prom_args args; + unsigned long version; + unsigned long root_size_cells; + unsigned long root_addr_cells; +}; + +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; + +struct mem_map_entry { + u64 base; + u64 size; +}; + +typedef u32 cell_t; + +extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); + +extern unsigned long reloc_offset(void); +extern void enter_prom(struct prom_args *args, unsigned long entry); +extern void copy_and_flush(unsigned long dest, unsigned long src, + unsigned long size, unsigned long offset); + +extern unsigned long klimit; + +//int global_width = 640, global_height = 480, global_depth = 8, global_pitch; +//unsigned global_address; +/* prom structure */ +static struct prom_t __initdata prom; + +#define PROM_SCRATCH_SIZE 256 + +static char __initdata of_stdout_device[256]; +static char __initdata prom_scratch[PROM_SCRATCH_SIZE]; + +static unsigned long __initdata dt_header_start; +static unsigned long __initdata dt_struct_start, dt_struct_end; +static unsigned long __initdata dt_string_start, dt_string_end; + +static unsigned long __initdata prom_initrd_start, prom_initrd_end; + +static int __initdata iommu_force_on; +static int __initdata ppc64_iommu_off; +static int __initdata of_platform; + +static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; + +static unsigned long __initdata alloc_top; +static unsigned long __initdata alloc_top_high; +static unsigned long __initdata alloc_bottom; +static unsigned long __initdata rmo_top; +static unsigned long __initdata ram_top; + +static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; +static int __initdata mem_reserve_cnt; + +static cell_t __initdata regbuf[1024]; + + +#define MAX_CPU_THREADS 2 + +/* TO GO */ +#ifdef CONFIG_HMT +struct { + unsigned int pir; + unsigned int threadid; +} hmt_thread_data[NR_CPUS]; +#endif /* CONFIG_HMT */ + +/* + * This are used in calls to call_prom. The 4th and following + * arguments to call_prom should be 32-bit values. 64 bit values + * are truncated to 32 bits (and fortunately don't get interpreted + * as two arguments). + */ +#define ADDR(x) (u32) ((unsigned long)(x) - offset) + +/* This is the one and *ONLY* place where we actually call open + * firmware from, since we need to make sure we're running in 32b + * mode when we do. We switch back to 64b mode upon return. + */ + +#define PROM_ERROR (-1) + +static int __init call_prom(const char *service, int nargs, int nret, ...) +{ + int i; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + va_list list; + + _prom->args.service = ADDR(service); + _prom->args.nargs = nargs; + _prom->args.nret = nret; + _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); + + va_start(list, nret); + for (i=0; i < nargs; i++) + _prom->args.args[i] = va_arg(list, prom_arg_t); + va_end(list); + + for (i=0; i < nret ;i++) + _prom->args.rets[i] = 0; + + enter_prom(&_prom->args, _prom->entry); + + return (nret > 0) ? _prom->args.rets[0] : 0; +} + + +static unsigned int __init prom_claim(unsigned long virt, unsigned long size, + unsigned long align) +{ + return (unsigned int)call_prom("claim", 3, 1, + (prom_arg_t)virt, (prom_arg_t)size, + (prom_arg_t)align); +} + +static void __init prom_print(const char *msg) +{ + const char *p, *q; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + if (_prom->stdout == 0) + return; + + for (p = msg; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + ++q; + call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); + } +} + + +static void __init prom_print_hex(unsigned long val) +{ + unsigned long offset = reloc_offset(); + int i, nibbles = sizeof(val)*2; + char buf[sizeof(val)*2+1]; + struct prom_t *_prom = PTRRELOC(&prom); + + for (i = nibbles-1; i >= 0; i--) { + buf[i] = (val & 0xf) + '0'; + if (buf[i] > '9') + buf[i] += ('a'-'0'-10); + val >>= 4; + } + buf[nibbles] = '\0'; + call_prom("write", 3, 1, _prom->stdout, buf, nibbles); +} + + +static void __init prom_printf(const char *format, ...) +{ + unsigned long offset = reloc_offset(); + const char *p, *q, *s; + va_list args; + unsigned long v; + struct prom_t *_prom = PTRRELOC(&prom); + + va_start(args, format); + for (p = PTRRELOC(format); *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + if (*q == '\n') { + ++q; + call_prom("write", 3, 1, _prom->stdout, + ADDR("\r\n"), 2); + continue; + } + ++q; + if (*q == 0) + break; + switch (*q) { + case 's': + ++q; + s = va_arg(args, const char *); + prom_print(s); + break; + case 'x': + ++q; + v = va_arg(args, unsigned long); + prom_print_hex(v); + break; + } + } +} + + +static void __init __attribute__((noreturn)) prom_panic(const char *reason) +{ + unsigned long offset = reloc_offset(); + + prom_print(PTRRELOC(reason)); + /* ToDo: should put up an SRC here */ + call_prom("exit", 0, 0); + + for (;;) /* should never get here */ + ; +} + + +static int __init prom_next_node(phandle *nodep) +{ + phandle node; + + if ((node = *nodep) != 0 + && (*nodep = call_prom("child", 1, 1, node)) != 0) + return 1; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + for (;;) { + if ((node = call_prom("parent", 1, 1, node)) == 0) + return 0; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + } +} + +static int __init prom_getprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + unsigned long offset = reloc_offset(); + + return call_prom("getprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + +static int __init prom_getproplen(phandle node, const char *pname) +{ + unsigned long offset = reloc_offset(); + + return call_prom("getproplen", 2, 1, node, ADDR(pname)); +} + +static int __init prom_setprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + unsigned long offset = reloc_offset(); + + return call_prom("setprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + + +/* + * Early parsing of the command line passed to the kernel, used for + * the options that affect the iommu + */ +static void __init early_cmdline_parse(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char *opt, *p; + int l = 0; + + RELOC(prom_cmd_line[0]) = 0; + p = RELOC(prom_cmd_line); + if ((long)_prom->chosen > 0) + l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1); +#ifdef CONFIG_CMDLINE + if (l == 0) /* dbl check */ + strlcpy(RELOC(prom_cmd_line), + RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line)); +#endif /* CONFIG_CMDLINE */ + prom_printf("command line: %s\n", RELOC(prom_cmd_line)); + + opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); + if (opt) { + prom_printf("iommu opt is: %s\n", opt); + opt += 6; + while (*opt && *opt == ' ') + opt++; + if (!strncmp(opt, RELOC("off"), 3)) + RELOC(ppc64_iommu_off) = 1; + else if (!strncmp(opt, RELOC("force"), 5)) + RELOC(iommu_force_on) = 1; + } +} + +/* + * Memory allocation strategy... our layout is normally: + * + * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd + * might end up beeing before the kernel though. We assume this won't override + * the final kernel at 0, we have no provision to handle that in this version, + * but it should hopefully never happen. + * + * alloc_top is set to the top of RMO, eventually shrink down if the TCEs overlap + * alloc_bottom is set to the top of kernel/initrd + * + * from there, allocations are done that way : rtas is allocated topmost, and + * the device-tree is allocated from the bottom. We try to grow the device-tree + * allocation as we progress. If we can't, then we fail, we don't currently have + * a facility to restart elsewhere, but that shouldn't be necessary neither + * + * Note that calls to reserve_mem have to be done explicitely, memory allocated + * with either alloc_up or alloc_down isn't automatically reserved. + */ + + +/* + * Allocates memory in the RMO upward from the kernel/initrd + * + * When align is 0, this is a special case, it means to allocate in place + * at the current location of alloc_bottom or fail (that is basically + * extending the previous allocation). Used for the device-tree flattening + */ +static unsigned long __init alloc_up(unsigned long size, unsigned long align) +{ + unsigned long offset = reloc_offset(); + unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); + unsigned long addr = 0; + + prom_debug("alloc_up(%x, %x)\n", size, align); + if (RELOC(ram_top) == 0) + prom_panic("alloc_up() called with mem not initialized\n"); + + if (align) + base = _ALIGN_UP(RELOC(alloc_bottom), align); + else + base = RELOC(alloc_bottom); + + for(; (base + size) <= RELOC(alloc_top); + base = _ALIGN_UP(base + 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if ((int)addr != PROM_ERROR) + break; + addr = 0; + if (align == 0) + break; + } + if (addr == 0) + return 0; + RELOC(alloc_bottom) = addr; + + prom_debug(" -> %x\n", addr); + prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); + prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); + prom_debug(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Allocates memory downard, either from top of RMO, or if highmem + * is set, from the top of RAM. Note that this one doesn't handle + * failures. In does claim memory if highmem is not set. + */ +static unsigned long __init alloc_down(unsigned long size, unsigned long align, + int highmem) +{ + unsigned long offset = reloc_offset(); + unsigned long base, addr = 0; + + prom_debug("alloc_down(%x, %x, %s)\n", size, align, + highmem ? RELOC("(high)") : RELOC("(low)")); + if (RELOC(ram_top) == 0) + prom_panic("alloc_down() called with mem not initialized\n"); + + if (highmem) { + /* Carve out storage for the TCE table. */ + addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align); + if (addr <= RELOC(alloc_bottom)) + return 0; + else { + /* Will we bump into the RMO ? If yes, check out that we + * didn't overlap existing allocations there, if we did, + * we are dead, we must be the first in town ! + */ + if (addr < RELOC(rmo_top)) { + /* Good, we are first */ + if (RELOC(alloc_top) == RELOC(rmo_top)) + RELOC(alloc_top) = RELOC(rmo_top) = addr; + else + return 0; + } + RELOC(alloc_top_high) = addr; + } + goto bail; + } + + base = _ALIGN_DOWN(RELOC(alloc_top) - size, align); + for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if ((int)addr != PROM_ERROR) + break; + addr = 0; + } + if (addr == 0) + return 0; + RELOC(alloc_top) = addr; + + bail: + prom_debug(" -> %x\n", addr); + prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); + prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); + prom_debug(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Parse a "reg" cell + */ +static unsigned long __init prom_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r = 0; + + /* Ignore more than 2 cells */ + while (s > 2) { + p++; + s--; + } + while (s) { + r <<= 32; + r |= *(p++); + s--; + } + + *cellp = p; + return r; +} + +/* + * Very dumb function for adding to the memory reserve list, but + * we don't need anything smarter at this point + * + * XXX Eventually check for collisions. They should NEVER happen + * if problems seem to show up, it would be a good start to track + * them down. + */ +static void reserve_mem(unsigned long base, unsigned long size) +{ + unsigned long offset = reloc_offset(); + unsigned long top = base + size; + unsigned long cnt = RELOC(mem_reserve_cnt); + + if (size == 0) + return; + + /* We need to always keep one empty entry so that we + * have our terminator with "size" set to 0 since we are + * dumb and just copy this entire array to the boot params + */ + base = _ALIGN_DOWN(base, PAGE_SIZE); + top = _ALIGN_UP(top, PAGE_SIZE); + size = top - base; + + if (cnt >= (MEM_RESERVE_MAP_SIZE - 1)) + prom_panic("Memory reserve map exhausted !\n"); + RELOC(mem_reserve_map)[cnt].base = base; + RELOC(mem_reserve_map)[cnt].size = size; + RELOC(mem_reserve_cnt) = cnt + 1; +} + +/* + * Initialize memory allocation mecanism, parse "memory" nodes and + * obtain that way the top of memory and RMO to setup out local allocator + */ +static void __init prom_init_mem(void) +{ + phandle node; + char *path, type[64]; + unsigned int plen; + cell_t *p, *endp; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + /* + * We iterate the memory nodes to find + * 1) top of RMO (first node) + * 2) top of memory + */ + prom_debug("root_addr_cells: %x\n", (long)_prom->root_addr_cells); + prom_debug("root_size_cells: %x\n", (long)_prom->root_size_cells); + + prom_debug("scanning memory:\n"); + path = RELOC(prom_scratch); + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + + if (strcmp(type, RELOC("memory"))) + continue; + + plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); + if (plen > sizeof(regbuf)) { + prom_printf("memory node too large for buffer !\n"); + plen = sizeof(regbuf); + } + p = RELOC(regbuf); + endp = p + (plen / sizeof(cell_t)); + +#ifdef DEBUG_PROM + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + prom_debug(" node %s :\n", path); +#endif /* DEBUG_PROM */ + + while ((endp - p) >= (_prom->root_addr_cells + _prom->root_size_cells)) { + unsigned long base, size; + + base = prom_next_cell(_prom->root_addr_cells, &p); + size = prom_next_cell(_prom->root_size_cells, &p); + + if (size == 0) + continue; + prom_debug(" %x %x\n", base, size); + if (base == 0) + RELOC(rmo_top) = size; + if ((base + size) > RELOC(ram_top)) + RELOC(ram_top) = base + size; + } + } + + /* Setup our top/bottom alloc points, that is top of RMO or top of + * segment 0 when running non-LPAR + */ + if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR ) + RELOC(alloc_top) = RELOC(rmo_top); + else + RELOC(alloc_top) = min(0x40000000ul, RELOC(ram_top)); + RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000); + RELOC(alloc_top_high) = RELOC(ram_top); + + /* Check if we have an initrd after the kernel, if we do move our bottom + * point to after it + */ + if (RELOC(prom_initrd_start)) { + if ((RELOC(prom_initrd_start) + RELOC(prom_initrd_end)) + > RELOC(alloc_bottom)) + RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end)); + } + + prom_printf("memory layout at init:\n"); + prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); + prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); + prom_printf(" ram_top : %x\n", RELOC(ram_top)); +} + + +/* + * Allocate room for and instanciate RTAS + */ +static void __init prom_instantiate_rtas(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + phandle prom_rtas; + u64 base, entry = 0; + u32 size; + + prom_debug("prom_instantiate_rtas: start...\n"); + + prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); + if (prom_rtas != (phandle) -1) { + prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); + if (size != 0) { + base = alloc_down(size, PAGE_SIZE, 0); + if (base == 0) { + prom_printf("RTAS allocation failed !\n"); + return; + } + prom_printf("instantiating rtas at 0x%x", base); + + prom_rtas = call_prom("open", 1, 1, ADDR("/rtas")); + prom_printf("..."); + + if (call_prom("call-method", 3, 2, + ADDR("instantiate-rtas"), + prom_rtas, base) != PROM_ERROR) { + entry = (long)_prom->args.rets[1]; + } + if (entry == 0) { + prom_printf(" failed\n"); + return; + } + prom_printf(" done\n"); + + reserve_mem(base, size); + } + + prom_setprop(_prom->chosen, "linux,rtas-base", &base, sizeof(base)); + prom_setprop(_prom->chosen, "linux,rtas-entry", &entry, sizeof(entry)); + prom_setprop(_prom->chosen, "linux,rtas-size", &size, sizeof(size)); + + prom_debug("rtas base = 0x%x\n", base); + prom_debug("rtas entry = 0x%x\n", entry); + prom_debug("rtas size = 0x%x\n", (long)size); + } + prom_debug("prom_instantiate_rtas: end...\n"); +} + + +/* + * Allocate room for and initialize TCE tables + */ +static void __init prom_initialize_tce_table(void) +{ + phandle node; + ihandle phb_node; + unsigned long offset = reloc_offset(); + char compatible[64], type[64], model[64]; + char *path = RELOC(prom_scratch); + u64 base, vbase, align; + u32 minalign, minsize; + u64 tce_entry, *tce_entryp; + u64 local_alloc_top, local_alloc_bottom; + u64 i; + + if (RELOC(ppc64_iommu_off)) + return; + + prom_debug("starting prom_initialize_tce_table\n"); + + /* Cache current top of allocs so we reserve a single block */ + local_alloc_top = RELOC(alloc_top_high); + local_alloc_bottom = local_alloc_top; + + /* Search all nodes looking for PHBs. */ + for (node = 0; prom_next_node(&node); ) { + compatible[0] = 0; + type[0] = 0; + model[0] = 0; + prom_getprop(node, "compatible", + compatible, sizeof(compatible)); + prom_getprop(node, "device_type", type, sizeof(type)); + prom_getprop(node, "model", model, sizeof(model)); + + if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) + continue; + + /* Keep the old logic in tack to avoid regression. */ + if (compatible[0] != 0) { + if ((strstr(compatible, RELOC("python")) == NULL) && + (strstr(compatible, RELOC("Speedwagon")) == NULL) && + (strstr(compatible, RELOC("Winnipeg")) == NULL)) + continue; + } else if (model[0] != 0) { + if ((strstr(model, RELOC("ython")) == NULL) && + (strstr(model, RELOC("peedwagon")) == NULL) && + (strstr(model, RELOC("innipeg")) == NULL)) + continue; + } + + if (prom_getprop(node, "tce-table-minalign", &minalign, + sizeof(minalign)) == PROM_ERROR) + minalign = 0; + if (prom_getprop(node, "tce-table-minsize", &minsize, + sizeof(minsize)) == PROM_ERROR) + minsize = 4UL << 20; + + /* + * Even though we read what OF wants, we just set the table + * size to 4 MB. This is enough to map 2GB of PCI DMA space. + * By doing this, we avoid the pitfalls of trying to DMA to + * MMIO space and the DMA alias hole. + * + * On POWER4, firmware sets the TCE region by assuming + * each TCE table is 8MB. Using this memory for anything + * else will impact performance, so we always allocate 8MB. + * Anton + */ + if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) + minsize = 8UL << 20; + else + minsize = 4UL << 20; + + /* Align to the greater of the align or size */ + align = max(minalign, minsize); + base = alloc_down(minsize, align, 1); + if (base == 0) + prom_panic("ERROR, cannot find space for TCE table.\n"); + if (base < local_alloc_bottom) + local_alloc_bottom = base; + + vbase = (unsigned long)abs_to_virt(base); + + /* Save away the TCE table attributes for later use. */ + prom_setprop(node, "linux,tce-base", &vbase, sizeof(vbase)); + prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); + prom_setprop(node, "linux,has-tce-table", NULL, 0); + + /* It seems OF doesn't null-terminate the path :-( */ + memset(path, 0, sizeof(path)); + /* Call OF to setup the TCE hardware */ + if (call_prom("package-to-path", 3, 1, node, + path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) { + prom_printf("package-to-path failed\n"); + } + + prom_debug("TCE table: %s\n", path); + prom_debug("\tnode = 0x%x\n", node); + prom_debug("\tbase = 0x%x\n", vbase); + prom_debug("\tsize = 0x%x\n", minsize); + + /* Initialize the table to have a one-to-one mapping + * over the allocated size. + */ + tce_entryp = (unsigned long *)base; + for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { + tce_entry = (i << PAGE_SHIFT); + tce_entry |= 0x3; + *tce_entryp = tce_entry; + } + + prom_printf("opening PHB %s", path); + phb_node = call_prom("open", 1, 1, path); + if ( (long)phb_node <= 0) + prom_printf("... failed\n"); + else + prom_printf("... done\n"); + + call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), + phb_node, -1, minsize, + (u32) base, (u32) (base >> 32)); + call_prom("close", 1, 0, phb_node); + } + + reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); + + /* Flag the first invalid entry */ + prom_debug("ending prom_initialize_tce_table\n"); +} + +/* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of low memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. The holding pattern + * checks that address until its cpu # is there, when it is that + * cpu jumps to __secondary_start(). smp_boot_cpus() takes care + * of setting those values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * Fixup comment... DRENG / PPPBBB - Peter + * + * -- Cort + */ +static void __init prom_hold_cpus(void) +{ + unsigned long i; + unsigned int reg; + phandle node; + unsigned long offset = reloc_offset(); + char type[64]; + int cpuid = 0; + unsigned int interrupt_server[MAX_CPU_THREADS]; + unsigned int cpu_threads, hw_cpu_num; + int propsize; + extern void __secondary_hold(void); + extern unsigned long __secondary_hold_spinloop; + extern unsigned long __secondary_hold_acknowledge; + unsigned long *spinloop + = (void *)virt_to_abs(&__secondary_hold_spinloop); + unsigned long *acknowledge + = (void *)virt_to_abs(&__secondary_hold_acknowledge); + unsigned long secondary_hold + = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); + struct prom_t *_prom = PTRRELOC(&prom); + + prom_debug("prom_hold_cpus: start...\n"); + prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); + prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); + prom_debug(" 1) acknowledge = 0x%x\n", + (unsigned long)acknowledge); + prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); + prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); + + /* Set the common spinloop variable, so all of the secondary cpus + * will block when they are awakened from their OF spinloop. + * This must occur for both SMP and non SMP kernels, since OF will + * be trashed when we move the kernel. + */ + *spinloop = 0; + +#ifdef CONFIG_HMT + for (i=0; i < NR_CPUS; i++) { + RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; + } +#endif + /* look for cpus */ + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + + /* Skip non-configured cpus. */ + prom_getprop(node, "status", type, sizeof(type)); + if (strcmp(type, RELOC("okay")) != 0) + continue; + + reg = -1; + prom_getprop(node, "reg", ®, sizeof(reg)); + + prom_debug("\ncpuid = 0x%x\n", cpuid); + prom_debug("cpu hw idx = 0x%x\n", reg); + + /* Init the acknowledge var which will be reset by + * the secondary cpu when it awakens from its OF + * spinloop. + */ + *acknowledge = (unsigned long)-1; + + propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", + &interrupt_server, + sizeof(interrupt_server)); + if (propsize < 0) { + /* no property. old hardware has no SMT */ + cpu_threads = 1; + interrupt_server[0] = reg; /* fake it with phys id */ + } else { + /* We have a threaded processor */ + cpu_threads = propsize / sizeof(u32); + if (cpu_threads > MAX_CPU_THREADS) { + prom_printf("SMT: too many threads!\n" + "SMT: found %x, max is %x\n", + cpu_threads, MAX_CPU_THREADS); + cpu_threads = 1; /* ToDo: panic? */ + } + } + + hw_cpu_num = interrupt_server[0]; + if (hw_cpu_num != _prom->cpu) { + /* Primary Thread of non-boot cpu */ + prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); + call_prom("start-cpu", 3, 0, node, + secondary_hold, cpuid); + + for ( i = 0 ; (i < 100000000) && + (*acknowledge == ((unsigned long)-1)); i++ ) ; + + if (*acknowledge == cpuid) { + prom_printf("done\n"); + /* We have to get every CPU out of OF, + * even if we never start it. */ + if (cpuid >= NR_CPUS) + goto next; + } else { + prom_printf("failed: %x\n", *acknowledge); + } + } +#ifdef CONFIG_SMP + else + prom_printf("%x : boot cpu %x\n", cpuid, reg); +#endif +next: +#ifdef CONFIG_SMP + /* Init paca for secondary threads. They start later. */ + for (i=1; i < cpu_threads; i++) { + cpuid++; + if (cpuid >= NR_CPUS) + continue; + } +#endif /* CONFIG_SMP */ + cpuid++; + } +#ifdef CONFIG_HMT + /* Only enable HMT on processors that provide support. */ + if (__is_processor(PV_PULSAR) || + __is_processor(PV_ICESTAR) || + __is_processor(PV_SSTAR)) { + prom_printf(" starting secondary threads\n"); + + for (i = 0; i < NR_CPUS; i += 2) { + if (!cpu_online(i)) + continue; + + if (i == 0) { + unsigned long pir = mfspr(SPRN_PIR); + if (__is_processor(PV_PULSAR)) { + RELOC(hmt_thread_data)[i].pir = + pir & 0x1f; + } else { + RELOC(hmt_thread_data)[i].pir = + pir & 0x3ff; + } + } + } + } else { + prom_printf("Processor is not HMT capable\n"); + } +#endif + + if (cpuid > NR_CPUS) + prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) + ") exceeded: ignoring extras\n"); + + prom_debug("prom_hold_cpus: end...\n"); +} + + +static void __init prom_init_client_services(unsigned long pp) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + /* Get a handle to the prom entry point before anything else */ + _prom->entry = pp; + + /* Init default value for phys size */ + _prom->root_size_cells = 1; + _prom->root_addr_cells = 2; + + /* get a handle for the stdout device */ + _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); + if ((long)_prom->chosen <= 0) + prom_panic("cannot find chosen"); /* msg won't be printed :( */ + + /* get device tree root */ + _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); + if ((long)_prom->root <= 0) + prom_panic("cannot find device tree root"); /* msg won't be printed :( */ +} + +static void __init prom_init_stdout(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char *path = RELOC(of_stdout_device); + char type[16]; + u32 val; + + if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) + prom_panic("cannot find stdout"); + + _prom->stdout = val; + + /* Get the full OF pathname of the stdout device */ + memset(path, 0, 256); + call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); + val = call_prom("instance-to-package", 1, 1, _prom->stdout); + prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); + prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); + prom_setprop(_prom->chosen, "linux,stdout-path", + RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); + + /* If it's a display, note it */ + memset(type, 0, sizeof(type)); + prom_getprop(val, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) == 0) { + _prom->disp_node = val; + prom_setprop(val, "linux,boot-display", NULL, 0); + } +} + +static int __init prom_find_machine_type(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char compat[256]; + int len, i = 0; + phandle rtas; + + len = prom_getprop(_prom->root, "compatible", + compat, sizeof(compat)-1); + if (len > 0) { + compat[len] = 0; + while (i < len) { + char *p = &compat[i]; + int sl = strlen(p); + if (sl == 0) + break; + if (strstr(p, RELOC("Power Macintosh")) || + strstr(p, RELOC("MacRISC4"))) + return PLATFORM_POWERMAC; + i += sl + 1; + } + } + /* Default to pSeries. We need to know if we are running LPAR */ + rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); + if (rtas != (phandle) -1) { + unsigned long x; + x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (x != PROM_ERROR) { + prom_printf("Hypertas detected, assuming LPAR !\n"); + return PLATFORM_PSERIES_LPAR; + } + } + return PLATFORM_PSERIES; +} + +static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + unsigned long offset = reloc_offset(); + + return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); +} + +/* + * 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 + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. + * So we check whether we will need to open the display, + * and if so, open it now. + */ +static unsigned long __init prom_check_displays(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char type[16], *path; + phandle node; + ihandle ih; + int i; + + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + const unsigned char *clut; + + prom_printf("Looking for displays\n"); + for (node = 0; prom_next_node(&node); ) { + memset(type, 0, sizeof(type)); + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) != 0) + continue; + + /* It seems OF doesn't null-terminate the path :-( */ + path = RELOC(prom_scratch); + memset(path, 0, PROM_SCRATCH_SIZE); + + /* + * leave some room at the end of the path for appending extra + * arguments + */ + if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) + continue; + prom_printf("found display : %s, opening ... ", path); + + ih = call_prom("open", 1, 1, path); + if (ih == (ihandle)0 || ih == (ihandle)-1) { + prom_printf("failed\n"); + continue; + } + + /* Success */ + prom_printf("done\n"); + prom_setprop(node, "linux,opened", NULL, 0); + + /* + * stdout wasn't a display node, pick the first we can find + * for btext + */ + if (_prom->disp_node == 0) + _prom->disp_node = node; + + /* Setup a useable color table when the appropriate + * method is available. Should update this to set-colors */ + clut = RELOC(default_colors); + for (i = 0; i < 32; i++, clut += 3) + if (prom_set_color(ih, i, clut[0], clut[1], + clut[2]) != 0) + break; + +#ifdef CONFIG_LOGO_LINUX_CLUT224 + clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); + for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) + if (prom_set_color(ih, i + 32, clut[0], clut[1], + clut[2]) != 0) + break; +#endif /* CONFIG_LOGO_LINUX_CLUT224 */ + } +} + + +/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ +static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, + unsigned long needed, unsigned long align) +{ + unsigned long offset = reloc_offset(); + void *ret; + + *mem_start = _ALIGN(*mem_start, align); + while ((*mem_start + needed) > *mem_end) { + unsigned long room, chunk; + + prom_debug("Chunk exhausted, claiming more at %x...\n", + RELOC(alloc_bottom)); + room = RELOC(alloc_top) - RELOC(alloc_bottom); + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + if (room < PAGE_SIZE) + prom_panic("No memory for flatten_device_tree (no room)"); + chunk = alloc_up(room, 0); + if (chunk == 0) + prom_panic("No memory for flatten_device_tree (claim failed)"); + *mem_end = RELOC(alloc_top); + } + + ret = (void *)*mem_start; + *mem_start += needed; + + return ret; +} + +#define dt_push_token(token, mem_start, mem_end) \ + do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0) + +static unsigned long __init dt_find_string(char *str) +{ + unsigned long offset = reloc_offset(); + char *s, *os; + + s = os = (char *)RELOC(dt_string_start); + s += 4; + while (s < (char *)RELOC(dt_string_end)) { + if (strcmp(s, str) == 0) + return s - os; + s += strlen(s) + 1; + } + return 0; +} + +static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, + unsigned long *mem_end) +{ + unsigned long offset = reloc_offset(); + char *prev_name, *namep, *sstart; + unsigned long soff; + phandle child; + + sstart = (char *)RELOC(dt_string_start); + + /* get and store all property names */ + prev_name = RELOC(""); + for (;;) { + + /* 32 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, 32, 1); + if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { + /* No more nodes: unwind alloc */ + *mem_start = (unsigned long)namep; + break; + } + soff = dt_find_string(namep); + if (soff != 0) { + *mem_start = (unsigned long)namep; + namep = sstart + soff; + } else { + /* Trim off some if we can */ + *mem_start = (unsigned long)namep + strlen(namep) + 1; + RELOC(dt_string_end) = *mem_start; + } + prev_name = namep; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (phandle)0) { + scan_dt_build_strings(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } +} + +static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, + unsigned long *mem_end) +{ + int l, align; + phandle child; + char *namep, *prev_name, *sstart; + unsigned long soff; + unsigned char *valp; + unsigned long offset = reloc_offset(); + char pname[32]; + char *path; + + path = RELOC(prom_scratch); + + dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); + + /* get the node's full name */ + namep = (char *)*mem_start; + l = call_prom("package-to-path", 3, 1, node, + namep, *mem_end - *mem_start); + if (l >= 0) { + /* Didn't fit? Get more room. */ + if (l+1 > *mem_end - *mem_start) { + namep = make_room(mem_start, mem_end, l+1, 1); + call_prom("package-to-path", 3, 1, node, namep, l); + } + namep[l] = '\0'; + *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); + } + + /* get it again for debugging */ + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + + /* get and store all properties */ + prev_name = RELOC(""); + sstart = (char *)RELOC(dt_string_start); + for (;;) { + if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) + break; + + /* find string offset */ + soff = dt_find_string(pname); + if (soff == 0) { + prom_printf("WARNING: Can't find string index for <%s>, node %s\n", + pname, path); + break; + } + prev_name = sstart + soff; + + /* get length */ + l = call_prom("getproplen", 2, 1, node, pname); + + /* sanity checks */ + if (l < 0) + continue; + if (l > MAX_PROPERTY_LENGTH) { + prom_printf("WARNING: ignoring large property "); + /* It seems OF doesn't null-terminate the path :-( */ + prom_printf("[%s] ", path); + prom_printf("%s length 0x%x\n", pname, l); + continue; + } + + /* push property head */ + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(l, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + + /* push property content */ + align = (l >= 8) ? 8 : 4; + valp = make_room(mem_start, mem_end, l, align); + call_prom("getprop", 4, 1, node, pname, valp, l); + *mem_start = _ALIGN(*mem_start, 4); + } + + /* Add a "linux,phandle" property. */ + soff = dt_find_string(RELOC("linux,phandle")); + if (soff == 0) + prom_printf("WARNING: Can't find string index for " + " node %s\n", path); + else { + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(4, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + valp = make_room(mem_start, mem_end, 4, 4); + *(u32 *)valp = node; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (phandle)0) { + scan_dt_build_struct(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } + + dt_push_token(OF_DT_END_NODE, mem_start, mem_end); +} + +static void __init flatten_device_tree(void) +{ + phandle root; + unsigned long offset = reloc_offset(); + unsigned long mem_start, mem_end, room; + struct boot_param_header *hdr; + char *namep; + u64 *rsvmap; + + /* + * Check how much room we have between alloc top & bottom (+/- a + * few pages), crop to 4Mb, as this is our "chuck" size + */ + room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); + + /* Now try to claim that */ + mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); + if (mem_start == 0) + prom_panic("Can't allocate initial device-tree chunk\n"); + mem_end = RELOC(alloc_top); + + /* Get root of tree */ + root = call_prom("peer", 1, 1, (phandle)0); + if (root == (phandle)0) + prom_panic ("couldn't get device tree root\n"); + + /* Build header and make room for mem rsv map */ + mem_start = _ALIGN(mem_start, 4); + hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); + RELOC(dt_header_start) = (unsigned long)hdr; + rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); + + /* Start of strings */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_string_start) = mem_start; + mem_start += 4; /* hole */ + + /* Add "linux,phandle" in there, we'll need it */ + namep = make_room(&mem_start, &mem_end, 16, 1); + strcpy(namep, RELOC("linux,phandle")); + mem_start = (unsigned long)namep + strlen(namep) + 1; + RELOC(dt_string_end) = mem_start; + + /* Build string array */ + prom_printf("Building dt strings...\n"); + scan_dt_build_strings(root, &mem_start, &mem_end); + + /* Build structure */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_struct_start) = mem_start; + prom_printf("Building dt structure...\n"); + scan_dt_build_struct(root, &mem_start, &mem_end); + dt_push_token(OF_DT_END, &mem_start, &mem_end); + RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); + + /* Finish header */ + hdr->magic = OF_DT_HEADER; + hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); + hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); + hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); + hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); + hdr->version = OF_DT_VERSION; + hdr->last_comp_version = 1; + + /* Reserve the whole thing and copy the reserve map in, we + * also bump mem_reserve_cnt to cause further reservations to + * fail since it's too late. + */ + reserve_mem(RELOC(dt_header_start), hdr->totalsize); + memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map)); + +#ifdef DEBUG_PROM + { + int i; + prom_printf("reserved memory map:\n"); + for (i = 0; i < RELOC(mem_reserve_cnt); i++) + prom_printf(" %x - %x\n", RELOC(mem_reserve_map)[i].base, + RELOC(mem_reserve_map)[i].size); + } +#endif + RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; + + prom_printf("Device tree strings 0x%x -> 0x%x\n", + RELOC(dt_string_start), RELOC(dt_string_end)); + prom_printf("Device tree struct 0x%x -> 0x%x\n", + RELOC(dt_struct_start), RELOC(dt_struct_end)); + + } + +static void __init prom_find_boot_cpu(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + u32 getprop_rval; + ihandle prom_cpu; + phandle cpu_pkg; + + if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) + prom_panic("cannot find boot cpu"); + + cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); + + prom_setprop(cpu_pkg, "linux,boot-cpu", NULL, 0); + prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); + _prom->cpu = getprop_rval; + + prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); +} + +static void __init prom_check_initrd(unsigned long r3, unsigned long r4) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + if ( r3 && r4 && r4 != 0xdeadbeef) { + u64 val; + + RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; + RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; + + val = (u64)RELOC(prom_initrd_start); + prom_setprop(_prom->chosen, "linux,initrd-start", &val, sizeof(val)); + val = (u64)RELOC(prom_initrd_end); + prom_setprop(_prom->chosen, "linux,initrd-end", &val, sizeof(val)); + + reserve_mem(RELOC(prom_initrd_start), + RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); + + prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); + prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +/* + * We enter here early on, when the Open Firmware prom is still + * handling exceptions and the MMU hash table for us. + */ + +unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp, + unsigned long r6, unsigned long r7) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + unsigned long phys = KERNELBASE - offset; + u32 getprop_rval; + + /* + * First zero the BSS + */ + memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); + + /* + * Init interface to Open Firmware, get some node references, + * like /chosen + */ + prom_init_client_services(pp); + + /* + * Init prom stdout device + */ + prom_init_stdout(); + prom_debug("klimit=0x%x\n", RELOC(klimit)); + prom_debug("offset=0x%x\n", offset); + + /* + * Reserve kernel in reserve map + */ + reserve_mem(0, __pa(RELOC(klimit))); + + /* + * Check for an initrd + */ + prom_check_initrd(r3, r4); + + /* + * Get default machine type. At this point, we do not differenciate + * between pSeries SMP and pSeries LPAR + */ + RELOC(of_platform) = prom_find_machine_type(); + getprop_rval = RELOC(of_platform); + prom_setprop(_prom->chosen, "linux,platform", + &getprop_rval, sizeof(getprop_rval)); + + /* + * On pSeries, copy the CPU hold code + */ + if (RELOC(of_platform) & PLATFORM_PSERIES) + copy_and_flush(0, KERNELBASE - offset, 0x100, 0); + + /* + * Get memory cells format + */ + getprop_rval = 1; + prom_getprop(_prom->root, "#size-cells", + &getprop_rval, sizeof(getprop_rval)); + _prom->root_size_cells = getprop_rval; + getprop_rval = 2; + prom_getprop(_prom->root, "#address-cells", + &getprop_rval, sizeof(getprop_rval)); + _prom->root_addr_cells = getprop_rval; + + /* + * Do early parsing of command line + */ + early_cmdline_parse(); + + /* + * Initialize memory management within prom_init + */ + prom_init_mem(); + + /* + * Determine which cpu is actually running right _now_ + */ + prom_find_boot_cpu(); + + /* + * Initialize display devices + */ + prom_check_displays(); + + /* + * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else + * that uses the allocator, we need to make sure we get the top of memory + * available for us here... + */ + if (RELOC(of_platform) == PLATFORM_PSERIES) + prom_initialize_tce_table(); + + /* + * On non-powermacs, try to instantiate RTAS and puts all CPUs + * in spin-loops. PowerMacs don't have a working RTAS and use + * a different way to spin CPUs + */ + if (RELOC(of_platform) != PLATFORM_POWERMAC) { + prom_instantiate_rtas(); + prom_hold_cpus(); + } + + /* + * Fill in some infos for use by the kernel later on + */ + if (RELOC(ppc64_iommu_off)) + prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); + if (RELOC(iommu_force_on)) + prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); + + /* + * Now finally create the flattened device-tree + */ + prom_printf("copying OF device tree ...\n"); + flatten_device_tree(); + + /* + * Call OF "quiesce" method to shut down pending DMA's from + * devices etc... + */ + prom_printf("Calling quiesce ...\n"); + call_prom("quiesce", 0, 0); + + /* + * And finally, call the kernel passing it the flattened device + * tree and NULL as r5, thus triggering the new entry point which + * is common to us and kexec + */ + prom_printf("returning from prom_init\n"); + prom_debug("->dt_header_start=0x%x\n", RELOC(dt_header_start)); + prom_debug("->phys=0x%x\n", phys); + + __start(RELOC(dt_header_start), phys, 0); + + return 0; +} + diff -Nru a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c --- a/arch/ppc64/kernel/ras.c 2004-10-18 14:56:27 -07:00 +++ b/arch/ppc64/kernel/ras.c 2004-10-18 14:56:28 -07:00 @@ -161,7 +161,8 @@ RAS_VECTOR_OFFSET, virt_irq_to_real(irq_offset_down(irq)), RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, - critical, __pa(&ras_log_buf), RTAS_ERROR_LOG_MAX); + critical, __pa(&ras_log_buf), + rtas_get_error_log_max()); udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n", *((unsigned long *)&ras_log_buf), status, state); @@ -196,11 +197,12 @@ RAS_VECTOR_OFFSET, virt_irq_to_real(irq_offset_down(irq)), RTAS_INTERNAL_ERROR, 1 /*Time Critical */, - __pa(&ras_log_buf), RTAS_ERROR_LOG_MAX); + __pa(&ras_log_buf), + rtas_get_error_log_max()); rtas_elog = (struct rtas_error_log *)ras_log_buf; - if ((status == 0) && (rtas_elog->severity >= SEVERITY_ERROR_SYNC)) + if ((status == 0) && (rtas_elog->severity >= RTAS_SEVERITY_ERROR_SYNC)) fatal = 1; else fatal = 0; diff -Nru a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c --- a/arch/ppc64/kernel/rtas-proc.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc64/kernel/rtas-proc.c 2004-10-18 14:56:29 -07:00 @@ -580,7 +580,7 @@ } break; case THERMAL_SENSOR: - seq_printf(m, "Temp. (°C/°F):\t"); + seq_printf(m, "Temp. (C/F):\t"); temperature = 1; break; case LID_STATUS: diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c --- a/arch/ppc64/kernel/rtas.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc64/kernel/rtas.c 2004-10-18 14:55:55 -07:00 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -37,17 +36,22 @@ .lock = SPIN_LOCK_UNLOCKED }; +EXPORT_SYMBOL(rtas); + char rtas_err_buf[RTAS_ERROR_LOG_MAX]; spinlock_t rtas_data_buf_lock = SPIN_LOCK_UNLOCKED; char rtas_data_buf[RTAS_DATA_BUF_SIZE]__page_aligned; +unsigned long rtas_rmo_buf; void -call_rtas_display_status(char c) +call_rtas_display_status(unsigned char c) { struct rtas_args *args = &rtas.args; unsigned long s; + if (!rtas.base) + return; spin_lock_irqsave(&rtas.lock, s); args->token = 10; @@ -61,6 +65,31 @@ spin_unlock_irqrestore(&rtas.lock, s); } +void +call_rtas_display_status_delay(unsigned char c) +{ + static int pending_newline = 0; /* did last write end with unprinted newline? */ + static int width = 16; + + if (c == '\n') { + while (width-- > 0) + call_rtas_display_status(' '); + width = 16; + udelay(500000); + pending_newline = 1; + } else { + if (pending_newline) { + call_rtas_display_status('\r'); + call_rtas_display_status('\n'); + } + pending_newline = 0; + if (width--) { + call_rtas_display_status(c); + udelay(10000); + } + } +} + int rtas_token(const char *service) { @@ -73,7 +102,6 @@ return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; } - /** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, @@ -84,28 +112,32 @@ __fetch_rtas_last_error(void) { struct rtas_args err_args, save_args; + u32 bufsz; + + bufsz = rtas_token ("rtas-error-log-max"); + if ((bufsz == RTAS_UNKNOWN_SERVICE) || + (bufsz > RTAS_ERROR_LOG_MAX)) { + printk (KERN_WARNING "RTAS: bad log buffer size %d\n", bufsz); + bufsz = RTAS_ERROR_LOG_MAX; + } err_args.token = rtas_token("rtas-last-error"); err_args.nargs = 2; err_args.nret = 1; - err_args.rets = (rtas_arg_t *)&(err_args.args[2]); err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); - err_args.args[1] = RTAS_ERROR_LOG_MAX; + err_args.args[1] = bufsz; err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; - PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", - __pa(&err_args)); enter_rtas(__pa(&rtas.args)); - PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); err_args = rtas.args; rtas.args = save_args; - return err_args.rets[0]; + return err_args.args[2]; } int rtas_call(int token, int nargs, int nret, int *outputs, ...) @@ -165,9 +197,12 @@ /* Log the error in the unlikely case that there was one. */ if (unlikely(logit)) { - buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); - if (buff_copy) { - memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); + buff_copy = rtas_err_buf; + if (mem_init_done) { + buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); + if (buff_copy) + memcpy(buff_copy, rtas_err_buf, + RTAS_ERROR_LOG_MAX); } } @@ -176,7 +211,8 @@ if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); - kfree(buff_copy); + if (mem_init_done) + kfree(buff_copy); } return ret; } @@ -417,7 +453,6 @@ } while (status == RTAS_BUSY); } -unsigned long rtas_rmo_buf = 0; asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { @@ -508,6 +543,73 @@ } #endif /* CONFIG_HOTPLUG_CPU */ +/* + * Return the firmware-specified size of the error log buffer + * for all rtas calls that require an error buffer argument. + * This includes 'check-exception' and 'rtas-last-error'. + */ +int rtas_get_error_log_max(void) +{ + static int rtas_error_log_max; + if (rtas_error_log_max) + return rtas_error_log_max; + + rtas_error_log_max = rtas_token ("rtas-error-log-max"); + if ((rtas_error_log_max == RTAS_UNKNOWN_SERVICE) || + (rtas_error_log_max > RTAS_ERROR_LOG_MAX)) { + printk (KERN_WARNING "RTAS: bad log buffer size %d\n", rtas_error_log_max); + rtas_error_log_max = RTAS_ERROR_LOG_MAX; + } + return rtas_error_log_max; +} + +/* + * Call early during boot, before mem init or bootmem, to retreive the RTAS + * informations from the device-tree and allocate the RMO buffer for userland + * accesses. + */ +void __init rtas_initialize(void) +{ + /* Get RTAS dev node and fill up our "rtas" structure with infos + * about it. + */ + rtas.dev = of_find_node_by_name(NULL, "rtas"); + if (rtas.dev) { + u64 *basep, *entryp; + u32 *sizep; + + basep = (u64 *)get_property(of_chosen, "linux,rtas-base", NULL); + sizep = (u32 *)get_property(of_chosen, "linux,rtas-size", NULL); + if (basep != NULL && sizep != NULL) { + rtas.base = *basep; + rtas.size = *sizep; + entryp = (u64 *)get_property(of_chosen, "linux,rtas-entry", NULL); + if (entryp == NULL) /* Ugh */ + rtas.entry = rtas.base; + else + rtas.entry = *entryp; + } else + rtas.dev = NULL; + } + /* If RTAS was found, allocate the RMO buffer for it and look for + * the stop-self token if any + */ + if (rtas.dev) { + unsigned long rtas_region = RTAS_INSTANTIATE_MAX; + if (systemcfg->platform == PLATFORM_PSERIES_LPAR) + rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); + + rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, + rtas_region); + +#ifdef CONFIG_HOTPLUG_CPU + rtas_stop_self_args.token = rtas_token("stop-self"); +#endif /* CONFIG_HOTPLUG_CPU */ + } + +} + + EXPORT_SYMBOL(rtas_firmware_flash_list); EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); @@ -518,3 +620,4 @@ EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); EXPORT_SYMBOL(rtas_set_indicator); +EXPORT_SYMBOL(rtas_get_error_log_max); diff -Nru a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c --- a/arch/ppc64/kernel/rtasd.c 2004-10-18 14:56:28 -07:00 +++ b/arch/ppc64/kernel/rtasd.c 2004-10-18 14:56:28 -07:00 @@ -46,6 +46,8 @@ static unsigned int rtas_error_log_max; static unsigned int rtas_error_log_buffer_max; +static int full_rtas_msgs = 0; + extern volatile int no_more_logging; volatile int error_log_cnt = 0; @@ -57,6 +59,37 @@ */ static unsigned char logdata[RTAS_ERROR_LOG_MAX]; +static int get_eventscan_parms(void); + +static char *rtas_type[] = { + "Unknown", "Retry", "TCE Error", "Internal Device Failure", + "Timeout", "Data Parity", "Address Parity", "Cache Parity", + "Address Invalid", "ECC Uncorrected", "ECC Corrupted", +}; + +static char *rtas_event_type(int type) +{ + if ((type > 0) && (type < 11)) + return rtas_type[type]; + + switch (type) { + case RTAS_TYPE_EPOW: + return "EPOW"; + case RTAS_TYPE_PLATFORM: + return "Platform Error"; + case RTAS_TYPE_IO: + return "I/O Event"; + case RTAS_TYPE_INFO: + return "Platform Information Event"; + case RTAS_TYPE_DEALLOC: + return "Resource Deallocation Event"; + case RTAS_TYPE_DUMP: + return "Dump Notification Event"; + } + + return rtas_type[0]; +} + /* To see this info, grep RTAS /var/log/messages and each entry * will be collected together with obvious begin/end. * There will be a unique identifier on the begin and end lines. @@ -73,38 +106,48 @@ static void printk_log_rtas(char *buf, int len) { - int i,j,n; + int i,j,n = 0; int perline = 16; char buffer[64]; char * str = "RTAS event"; - printk(RTAS_DEBUG "%d -------- %s begin --------\n", error_log_cnt, str); + if (full_rtas_msgs) { + printk(RTAS_DEBUG "%d -------- %s begin --------\n", + error_log_cnt, str); + + /* + * Print perline bytes on each line, each line will start + * with RTAS and a changing number, so syslogd will + * print lines that are otherwise the same. Separate every + * 4 bytes with a space. + */ + for (i = 0; i < len; i++) { + j = i % perline; + if (j == 0) { + memset(buffer, 0, sizeof(buffer)); + n = sprintf(buffer, "RTAS %d:", i/perline); + } - /* - * Print perline bytes on each line, each line will start - * with RTAS and a changing number, so syslogd will - * print lines that are otherwise the same. Separate every - * 4 bytes with a space. - */ - for (i=0; i < len; i++) { - j = i % perline; - if (j == 0) { - memset(buffer, 0, sizeof(buffer)); - n = sprintf(buffer, "RTAS %d:", i/perline); - } + if ((i % 4) == 0) + n += sprintf(buffer+n, " "); - if ((i % 4) == 0) - n += sprintf(buffer+n, " "); + n += sprintf(buffer+n, "%02x", (unsigned char)buf[i]); - n += sprintf(buffer+n, "%02x", (unsigned char)buf[i]); - - if (j == (perline-1)) + if (j == (perline-1)) + printk(KERN_DEBUG "%s\n", buffer); + } + if ((i % perline) != 0) printk(KERN_DEBUG "%s\n", buffer); - } - if ((i % perline) != 0) - printk(KERN_DEBUG "%s\n", buffer); - printk(RTAS_DEBUG "%d -------- %s end ----------\n", error_log_cnt, str); + printk(RTAS_DEBUG "%d -------- %s end ----------\n", + error_log_cnt, str); + } else { + struct rtas_error_log *errlog = (struct rtas_error_log *)buf; + + printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", + error_log_cnt, rtas_event_type(errlog->type), + errlog->severity); + } } static int log_rtas_len(char * buf) @@ -121,6 +164,9 @@ len += err->extended_log_length; } + if (rtas_error_log_max == 0) { + get_eventscan_parms(); + } if (len > rtas_error_log_max) len = rtas_error_log_max; @@ -148,7 +194,6 @@ int len = 0; DEBUG("logging event\n"); - if (buf == NULL) return; @@ -171,6 +216,14 @@ if (!no_more_logging && !(err_type & ERR_FLAG_BOOT)) nvram_write_error_log(buf, len, err_type); + /* + * rtas errors can occur during boot, and we do want to capture + * those somewhere, even if nvram isn't ready (why not?), and even + * if rtasd isn't ready. Put them into the boot log, at least. + */ + if ((err_type & ERR_TYPE_MASK) == ERR_TYPE_RTAS_LOG) + printk_log_rtas(buf, len); + /* Check to see if we need to or have stopped logging */ if (fatal || no_more_logging) { no_more_logging = 1; @@ -181,9 +234,6 @@ /* call type specific method for error */ switch (err_type & ERR_TYPE_MASK) { case ERR_TYPE_RTAS_LOG: - /* put into syslog and error_log file */ - printk_log_rtas(buf, len); - offset = rtas_error_log_buffer_max * ((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK); @@ -291,15 +341,18 @@ { int error; - error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, - SURVEILLANCE_TOKEN, 0, timeout); + error = rtas_set_indicator(SURVEILLANCE_TOKEN, 0, timeout); - if (error) { - printk(KERN_ERR "rtasd: could not enable surveillance\n"); - return -1; + if (error == 0) + return 0; + + if (error == RTAS_NO_SUCH_INDICATOR) { + printk(KERN_INFO "rtasd: surveillance not supported\n"); + return 0; } - return 0; + printk(KERN_ERR "rtasd: could not update surveillance\n"); + return -1; } static int get_eventscan_parms(void) @@ -318,21 +371,8 @@ rtas_event_scan_rate = *ip; DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); - ip = (int *)get_property(node, "rtas-error-log-max", NULL); - if (ip == NULL) { - printk(KERN_ERR "rtasd: no rtas-error-log-max\n"); - of_node_put(node); - return -1; - } - rtas_error_log_max = *ip; - DEBUG("rtas-error-log-max %d\n", rtas_error_log_max); - - if (rtas_error_log_max > RTAS_ERROR_LOG_MAX) { - printk(KERN_ERR "rtasd: truncated error log from %d to %d bytes\n", rtas_error_log_max, RTAS_ERROR_LOG_MAX); - rtas_error_log_max = RTAS_ERROR_LOG_MAX; - } - /* Make room for the sequence number */ + rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); of_node_put(node); @@ -473,5 +513,15 @@ return 1; } +static int __init rtasmsgs_setup(char *str) +{ + if (strcmp(str, "on") == 0) + full_rtas_msgs = 1; + else if (strcmp(str, "off") == 0) + full_rtas_msgs = 0; + + return 1; +} __initcall(rtas_init); __setup("surveillance=", surveillance_setup); +__setup("rtasmsgs=", rtasmsgs_setup); diff -Nru a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c --- a/arch/ppc64/kernel/rtc.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/kernel/rtc.c 2004-10-18 14:56:32 -07:00 @@ -34,8 +34,8 @@ #include #include #include +#include -#include #include #include #include diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c --- a/arch/ppc64/kernel/setup.c 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc64/kernel/setup.c 2004-10-18 14:56:29 -07:00 @@ -10,6 +10,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -27,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -47,60 +50,79 @@ #include #include #include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* + * Here are some early debugging facilities. You can enable one + * but your kernel will not boot on anything else if you do so + */ + +/* This one is for use on LPAR machines that support an HVC console + * on vterm 0 + */ +extern void udbg_init_debug_lpar(void); +/* This one is for use on Apple G5 machines + */ +extern void udbg_init_pmac_realmode(void); +/* That's RTAS panel debug */ +extern void call_rtas_display_status_delay(unsigned char c); + +#define EARLY_DEBUG_INIT() do {} while(0) + +#if 0 +#define EARLY_DEBUG_INIT() udbg_init_debug_lpar() +#define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() +#define EARLY_DEBUG_INIT() \ + do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0) +#endif -extern unsigned long klimit; /* extern void *stab; */ extern HTAB htab_data; -extern unsigned long loops_per_jiffy; - -int have_of = 1; +extern unsigned long klimit; -extern void chrp_init(unsigned long r3, - unsigned long r4, - unsigned long r5, - unsigned long r6, - unsigned long r7); - -extern void pmac_init(unsigned long r3, - unsigned long r4, - unsigned long r5, - unsigned long r6, - unsigned long r7); - -extern void iSeries_init( void ); -extern void iSeries_init_early( void ); -extern void pSeries_init_early( void ); -extern void pSeriesLP_init_early(void); -extern void pmac_init_early(void); -extern void mm_init_ppc64( void ); -extern void pseries_secondary_smp_init(unsigned long); +extern void mm_init_ppc64(void); extern int idle_setup(void); -extern void vpa_init(int cpu); +extern void stab_initialize(unsigned long stab); +extern void htab_initialize(void); +extern void early_init_devtree(void *flat_dt); +extern void unflatten_device_tree(void); unsigned long decr_overclock = 1; unsigned long decr_overclock_proc0 = 1; unsigned long decr_overclock_set = 0; unsigned long decr_overclock_proc0_set = 0; -int powersave_nap; +int have_of = 1; +int boot_cpuid = 0; +dev_t boot_dev; -unsigned char aux_device_present; +/* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. + */ +int dcache_bsize; +int icache_bsize; +int ucache_bsize; -void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7); -int parse_bootinfo(void); +/* The main machine-dep calls structure + */ +struct machdep_calls ppc_md; #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; #endif /* CONFIG_MAGIC_SYSRQ */ -struct machdep_calls ppc_md; static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); - static struct notifier_block ppc64_panic_block = { - notifier_call: ppc64_panic_event, - priority: INT_MIN /* may not return; must be done last */ + .notifier_call = ppc64_panic_event, + .priority = INT_MIN /* may not return; must be done last */ }; /* @@ -112,42 +134,32 @@ * these processors use on existing boards. -- Dan */ struct screen_info screen_info = { - 0, 25, /* orig-x, orig-y */ - 0, /* unused */ - 0, /* orig-video-page */ - 0, /* orig-video-mode */ - 80, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ - 25, /* orig-video-lines */ - 1, /* orig-video-isVGA */ - 16 /* orig-video-points */ + .orig_x = 0, + .orig_y = 25, + .orig_video_cols = 80, + .orig_video_lines = 25, + .orig_video_isVGA = 1, + .orig_video_points = 16 }; /* - * These are used in binfmt_elf.c to put aux entries on the stack - * for each elf executable being started. - */ -int dcache_bsize; -int icache_bsize; -int ucache_bsize; - -/* * Initialize the PPCDBG state. Called before relocation has been enabled. */ -void ppcdbg_initialize(void) { - unsigned long offset = reloc_offset(); - struct naca_struct *_naca = RELOC(naca); - - _naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; +void __init ppcdbg_initialize(void) +{ + naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ + /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; } +/* + * Early boot console based on udbg + */ static struct console udbg_console = { .name = "udbg", .write = udbg_console_write, .flags = CON_PRINTBUFFER, .index = -1, }; - static int early_console_initialized; void __init disable_early_printk(void) @@ -158,111 +170,457 @@ early_console_initialized = 0; } -/* - * Do some initial setup of the system. The parameters are those which - * were passed in from the bootloader. +#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) + +static int smt_enabled_cmdline; + +/* Look for ibm,smt-enabled OF option */ +static void check_smt_enabled(void) +{ + struct device_node *dn; + char *smt_option; + + /* Allow the command line to overrule the OF option */ + if (smt_enabled_cmdline) + return; + + dn = of_find_node_by_path("/options"); + + if (dn) { + smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); + + if (smt_option) { + if (!strcmp(smt_option, "on")) + smt_enabled_at_boot = 1; + else if (!strcmp(smt_option, "off")) + smt_enabled_at_boot = 0; + } + } +} + +/* Look for smt-enabled= cmdline option */ +static int __init early_smt_enabled(char *p) +{ + smt_enabled_cmdline = 1; + + if (!p) + return 0; + + if (!strcmp(p, "on") || !strcmp(p, "1")) + smt_enabled_at_boot = 1; + else if (!strcmp(p, "off") || !strcmp(p, "0")) + smt_enabled_at_boot = 0; + + return 0; +} +early_param("smt-enabled", early_smt_enabled); + +/** + * setup_cpu_maps - initialize the following cpu maps: + * cpu_possible_map + * cpu_present_map + * cpu_sibling_map + * + * Having the possible map set up early allows us to restrict allocations + * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. + * + * We do not initialize the online map here; cpus set their own bits in + * cpu_online_map as they come up. + * + * This function is valid only for Open Firmware systems. finish_device_tree + * must be called before using this. + * + * While we're here, we may as well set the "physical" cpu ids in the paca. */ -void setup_system(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +static void __init setup_cpu_maps(void) { -#if defined(CONFIG_SMP) && defined(CONFIG_PPC_PSERIES) - int ret, i; -#endif + struct device_node *dn = NULL; + int cpu = 0; -#ifdef CONFIG_XMON_DEFAULT - xmon_init(); -#endif + check_smt_enabled(); -#ifdef CONFIG_PPC_ISERIES - /* pSeries systems are identified in prom.c via OF. */ - if ( itLpNaca.xLparInstalled == 1 ) - systemcfg->platform = PLATFORM_ISERIES_LPAR; -#endif - - switch (systemcfg->platform) { -#ifdef CONFIG_PPC_ISERIES - case PLATFORM_ISERIES_LPAR: - iSeries_init_early(); - break; -#endif + while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { + u32 *intserv; + int j, len = sizeof(u32), nthreads; + + intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", + &len); + if (!intserv) + intserv = (u32 *)get_property(dn, "reg", NULL); + + nthreads = len / sizeof(u32); + + for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { + /* + * Only spin up secondary threads if SMT is enabled. + * We must leave space in the logical map for the + * threads. + */ + if (j == 0 || smt_enabled_at_boot) { + cpu_set(cpu, cpu_present_map); + set_hard_smp_processor_id(cpu, intserv[j]); + } + cpu_set(cpu, cpu_possible_map); + cpu++; + } + } + /* + * On pSeries LPAR, we need to know how many cpus + * could possibly be added to this partition. + */ + if (systemcfg->platform == PLATFORM_PSERIES_LPAR && + (dn = of_find_node_by_path("/rtas"))) { + int num_addr_cell, num_size_cell, maxcpus; + unsigned int *ireg; + + num_addr_cell = prom_n_addr_cells(dn); + num_size_cell = prom_n_size_cells(dn); + + ireg = (unsigned int *) + get_property(dn, "ibm,lrdr-capacity", NULL); + + if (!ireg) + goto out; + + maxcpus = ireg[num_addr_cell + num_size_cell]; + + /* Double maxcpus for processors which have SMT capability */ + if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + maxcpus *= 2; + + if (maxcpus > NR_CPUS) { + printk(KERN_WARNING + "Partition configured for %d cpus, " + "operating system maximum is %d.\n", + maxcpus, NR_CPUS); + maxcpus = NR_CPUS; + } else + printk(KERN_INFO "Partition configured for %d cpus.\n", + maxcpus); + + for (cpu = 0; cpu < maxcpus; cpu++) + cpu_set(cpu, cpu_possible_map); + out: + of_node_put(dn); + } + + /* + * Do the sibling map; assume only two threads per processor. + */ + for_each_cpu(cpu) { + cpu_set(cpu, cpu_sibling_map[cpu]); + if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); + } + + systemcfg->processorCount = num_present_cpus(); +} +#endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ + + +#ifdef CONFIG_PPC_MULTIPLATFORM + +extern struct machdep_calls pSeries_md; +extern struct machdep_calls pmac_md; + +/* Ultimately, stuff them in an elf section like initcalls... */ +static struct machdep_calls __initdata *machines[] = { #ifdef CONFIG_PPC_PSERIES - case PLATFORM_PSERIES: - pSeries_init_early(); - parse_bootinfo(); - break; - - case PLATFORM_PSERIES_LPAR: - pSeriesLP_init_early(); - parse_bootinfo(); - break; + &pSeries_md, #endif /* CONFIG_PPC_PSERIES */ #ifdef CONFIG_PPC_PMAC - case PLATFORM_POWERMAC: - pmac_init_early(); - parse_bootinfo(); + &pmac_md, #endif /* CONFIG_PPC_PMAC */ + NULL +}; + +/* + * Early initialization entry point. This is called by head.S + * with MMU translation disabled. We rely on the "feature" of + * the CPU that ignores the top 2 bits of the address in real + * mode so we can access kernel globals normally provided we + * only toy with things in the RMO region. From here, we do + * some early parsing of the device-tree to setup out LMB + * data structures, and allocate & initialize the hash table + * and segment tables so we can start running with translation + * enabled. + * + * It is this function which will call the probe() callback of + * the various platform types and copy the matching one to the + * global ppc_md structure. Your platform can eventually do + * some very early initializations from the probe() routine, but + * this is not recommended, be very careful as, for example, the + * device-tree is not accessible via normal means at this point. + */ + +void __init early_setup(unsigned long dt_ptr) +{ + struct paca_struct *lpaca = get_paca(); + static struct machdep_calls **mach; + + /* + * Enable early debugging if any specified (see top of + * this file) + */ + EARLY_DEBUG_INIT(); + + DBG(" -> early_setup()\n"); + + /* + * Fill the default DBG level in naca (do we want to keep + * that old mecanism around forever ?) + */ + ppcdbg_initialize(); + + /* + * Do early initializations using the flattened device + * tree, like retreiving the physical memory map or + * calculating/retreiving the hash table size + */ + early_init_devtree(__va(dt_ptr)); + + /* + * Iterate all ppc_md structures until we find the proper + * one for the current machine type + */ + DBG("Probing machine type for platform %x...\n", + systemcfg->platform); + + for (mach = machines; *mach; mach++) { + if ((*mach)->probe(systemcfg->platform)) + break; + } + /* What can we do if we didn't find ? */ + if (*mach == NULL) { + DBG("No suitable machine found !\n"); + for (;;); + } + ppc_md = **mach; + + /* our udbg callbacks got overriden by the above, let's put them + * back in. Ultimately, I want those things to be split from the + * main ppc_md + */ + EARLY_DEBUG_INIT(); + + DBG("Found, Initializing memory management...\n"); + + /* + * Initialize stab / SLB management + */ + stab_initialize(lpaca->stab_real); + + /* + * Initialize the MMU Hash table and create the linear mapping + * of memory + */ + htab_initialize(); + + DBG(" <- early_setup()\n"); +} + + +/* + * Initialize some remaining members of the naca and systemcfg structures + * (at least until we get rid of them completely). This is mostly some + * cache informations about the CPU that will be used by cache flush + * routines and/or provided to userland + */ +static void __init initialize_naca(void) +{ + struct device_node *np; + unsigned long num_cpus = 0; + + DBG(" -> initialize_naca()\n"); + + for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { + num_cpus += 1; + + /* We're assuming *all* of the CPUs have the same + * d-cache and i-cache sizes... -Peter + */ + + if ( num_cpus == 1 ) { + u32 *sizep, *lsizep; + u32 size, lsize; + const char *dc, *ic; + + /* Then read cache informations */ + if (systemcfg->platform == PLATFORM_POWERMAC) { + dc = "d-cache-block-size"; + ic = "i-cache-block-size"; + } else { + dc = "d-cache-line-size"; + ic = "i-cache-line-size"; + } + + size = 0; + lsize = cur_cpu_spec->dcache_bsize; + sizep = (u32 *)get_property(np, "d-cache-size", NULL); + if (sizep != NULL) + size = *sizep; + lsizep = (u32 *) get_property(np, dc, NULL); + if (lsizep != NULL) + lsize = *lsizep; + + if (sizep == 0 || lsizep == 0) + DBG("Argh, can't find dcache properties ! " + "sizep: %p, lsizep: %p\n", sizep, lsizep); + + systemcfg->dCacheL1Size = size; + systemcfg->dCacheL1LineSize = lsize; + naca->dCacheL1LogLineSize = __ilog2(lsize); + naca->dCacheL1LinesPerPage = PAGE_SIZE/(lsize); + + size = 0; + lsize = cur_cpu_spec->icache_bsize; + sizep = (u32 *)get_property(np, "i-cache-size", NULL); + if (sizep != NULL) + size = *sizep; + lsizep = (u32 *)get_property(np, ic, NULL); + if (lsizep != NULL) + lsize = *lsizep; + if (sizep == 0 || lsizep == 0) + DBG("Argh, can't find icache properties ! " + "sizep: %p, lsizep: %p\n", sizep, lsizep); + + systemcfg->iCacheL1Size = size; + systemcfg->iCacheL1LineSize = lsize; + naca->iCacheL1LogLineSize = __ilog2(lsize); + naca->iCacheL1LinesPerPage = PAGE_SIZE/(lsize); + + } + } + + /* Add an eye catcher and the systemcfg layout version number */ + strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); + systemcfg->version.major = SYSTEMCFG_MAJOR; + systemcfg->version.minor = SYSTEMCFG_MINOR; + systemcfg->processor = mfspr(SPRN_PVR); + + DBG(" <- initialize_naca()\n"); +} + +static void __init check_for_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + u64 *prop; + + DBG(" -> check_for_initrd()\n"); + + prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL); + if (prop != NULL) { + initrd_start = (unsigned long)__va(*prop); + prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL); + if (prop != NULL) { + initrd_end = (unsigned long)__va(*prop); + initrd_below_start_ok = 1; + } else + initrd_start = 0; } /* If we were passed an initrd, set the ROOT_DEV properly if the values * look sensible. If not, clear initrd reference. */ -#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && initrd_end > initrd_start) ROOT_DEV = Root_RAM0; else initrd_start = initrd_end = 0; + + if (initrd_start) + printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); + + DBG(" <- check_for_initrd()\n"); #endif /* CONFIG_BLK_DEV_INITRD */ +} -#ifdef CONFIG_BOOTX_TEXT - map_boot_text(); - if (systemcfg->platform == PLATFORM_POWERMAC) { - early_console_initialized = 1; - register_console(&udbg_console); - } -#endif /* CONFIG_BOOTX_TEXT */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ -#ifdef CONFIG_PPC_PSERIES - if (systemcfg->platform & PLATFORM_PSERIES) { - early_console_initialized = 1; - register_console(&udbg_console); - __irq_offset_value = NUM_ISA_INTERRUPTS; - finish_device_tree(); - chrp_init(r3, r4, r5, r6, r7); +/* + * Do some initial setup of the system. The parameters are those which + * were passed in from the bootloader. + */ +void __init setup_system(void) +{ + DBG(" -> setup_system()\n"); -#ifdef CONFIG_SMP - /* Start secondary threads on SMT systems */ - for (i = 0; i < NR_CPUS; i++) { - if (cpu_available(i) && !cpu_possible(i)) { - printk("%16.16x : starting thread\n", i); - rtas_call(rtas_token("start-cpu"), 3, 1, &ret, - get_hard_smp_processor_id(i), - (u32)*((unsigned long *)pseries_secondary_smp_init), - i); - cpu_set(i, cpu_possible_map); - systemcfg->processorCount++; - } - } -#endif /* CONFIG_SMP */ - } +#ifdef CONFIG_PPC_ISERIES + /* pSeries systems are identified in prom.c via OF. */ + if (itLpNaca.xLparInstalled == 1) + systemcfg->platform = PLATFORM_ISERIES_LPAR; + + ppc_md.init_early(); +#else /* CONFIG_PPC_ISERIES */ + + /* + * Unflatten the device-tree passed by prom_init or kexec + */ + unflatten_device_tree(); + + /* + * Fill the naca & systemcfg structures with informations + * retreived from the device-tree. Need to be called before + * finish_device_tree() since the later requires some of the + * informations filled up here to properly parse the interrupt + * tree. + * It also sets up the cache line sizes which allows to call + * routines like flush_icache_range (used by the hash init + * later on). + */ + initialize_naca(); + +#ifdef CONFIG_PPC_PSERIES + /* + * Initialize RTAS if available + */ + rtas_initialize(); #endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_PPC_PMAC - if (systemcfg->platform == PLATFORM_POWERMAC) { - finish_device_tree(); - pmac_init(r3, r4, r5, r6, r7); - } -#endif /* CONFIG_PPC_PMAC */ + /* + * Check if we have an initrd provided via the device-tree + */ + check_for_initrd(); + + /* + * Do some platform specific early initializations, that includes + * setting up the hash table pointers. It also sets up some interrupt-mapping + * related options that will be used by finish_device_tree() + */ + ppc_md.init_early(); + + /* + * "Finish" the device-tree, that is do the actual parsing of + * some of the properties like the interrupt map + */ + finish_device_tree(); + + /* + * Initialize xmon + */ +#ifdef CONFIG_XMON_DEFAULT + xmon_init(); +#endif + /* + * Register early console + */ + early_console_initialized = 1; + register_console(&udbg_console); -#if defined(CONFIG_HOTPLUG_CPU) && !defined(CONFIG_PPC_PMAC) - rtas_stop_self_args.token = rtas_token("stop-self"); -#endif /* CONFIG_HOTPLUG_CPU && !CONFIG_PPC_PMAC */ +#endif /* !CONFIG_PPC_ISERIES */ - /* Finish initializing the hash table (do the dynamic - * patching for the fast-path hashtable.S code) + /* Save unparsed command line copy for /proc/cmdline */ + strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); + + parse_early_param(); + +#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) + /* + * iSeries has already initialized the cpu maps at this point. */ - htab_finish_init(); + setup_cpu_maps(); +#endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ printk("Starting Linux PPC64 %s\n", UTS_RELEASE); @@ -282,28 +640,10 @@ mm_init_ppc64(); -#if defined(CONFIG_SMP) && defined(CONFIG_PPC_PSERIES) - if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { - vpa_init(boot_cpuid); - } -#endif - - /* Select the correct idle loop for the platform. */ - idle_setup(); - - switch (systemcfg->platform) { -#ifdef CONFIG_PPC_ISERIES - case PLATFORM_ISERIES_LPAR: - iSeries_init(); - break; -#endif - default: - /* The following relies on the device tree being */ - /* fully configured. */ - parse_cmd_line(r3, r4, r5, r6, r7); - } + DBG(" <- setup_system()\n"); } + void machine_restart(char *cmd) { if (ppc_md.nvram_sync) @@ -373,7 +713,7 @@ #ifdef CONFIG_SMP pvr = per_cpu(pvr, cpu_id); #else - pvr = _get_PVR(); + pvr = mfspr(SPRN_PVR); #endif maj = (pvr >> 8) & 0xFF; min = pvr & 0xFF; @@ -425,74 +765,75 @@ .show = show_cpuinfo, }; -/* - * Fetch the cmd_line from open firmware. - */ -void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - cmd_line[0] = 0; +#if 0 /* XXX not currently used */ +unsigned long memory_limit; -#ifdef CONFIG_CMDLINE - strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); -#endif /* CONFIG_CMDLINE */ - -#ifdef CONFIG_PPC_PSERIES - { - struct device_node *chosen; +static int __init early_parsemem(char *p) +{ + if (!p) + return 0; - chosen = of_find_node_by_name(NULL, "chosen"); - if (chosen != NULL) { - char *p; - p = get_property(chosen, "bootargs", NULL); - if (p != NULL && p[0] != 0) - strlcpy(cmd_line, p, sizeof(cmd_line)); - of_node_put(chosen); - } - } -#endif + memory_limit = memparse(p, &p); - /* Look for mem= option on command line */ - if (strstr(cmd_line, "mem=")) { - char *p, *q; - unsigned long maxmem = 0; - extern unsigned long __max_memory; - - for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { - q = p + 4; - if (p > cmd_line && p[-1] != ' ') - continue; - maxmem = simple_strtoul(q, &q, 0); - if (*q == 'k' || *q == 'K') { - maxmem <<= 10; - ++q; - } else if (*q == 'm' || *q == 'M') { - maxmem <<= 20; - ++q; - } - } - __max_memory = maxmem; - } + return 0; } +early_param("mem", early_parsemem); +#endif -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM static int __init set_preferred_console(void) { struct device_node *prom_stdout; char *name; - int offset; + int offset = 0; +#if 0 + phandle *stdout_ph; +#endif + DBG(" -> set_preferred_console()\n"); /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) + if (strstr(saved_command_line, "console=")) { + DBG(" console was specified !\n"); return -EBUSY; + } - prom_stdout = find_path_device(of_stdout_device); - if (!prom_stdout) + if (!of_chosen) { + DBG(" of_chosen is NULL !\n"); return -ENODEV; + } + /* We are getting a weird phandle from OF ... */ +#if 0 + stdout_ph = (phandle *)get_property(of_chosen, "linux,stdout-package", NULL); + if (stdout_ph == NULL) { + DBG(" no linux,stdout-package !\n"); + return -ENODEV; + } + prom_stdout = of_find_node_by_phandle(*stdout_ph); + if (!prom_stdout) { + DBG(" can't find stdout package for phandle 0x%x !\n", *stdout_ph); + return -ENODEV; + } +#endif + /* ... So use the full path instead */ +#if 1 + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) { + DBG(" no linux,stdout-path !\n"); + return -ENODEV; + } + prom_stdout = of_find_node_by_path(name); + if (!prom_stdout) { + DBG(" can't find stdout package %s !\n", name); + return -ENODEV; + } +#endif + DBG("stdout is %s\n", prom_stdout->full_name); name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) - return -ENODEV; + if (!name) { + DBG(" stdout package has no name !\n"); + goto not_found; + } if (strcmp(name, "serial") == 0) { int i; @@ -513,76 +854,69 @@ break; default: /* We dont recognise the serial port */ - return -ENODEV; + goto not_found; } } - } else if (strcmp(name, "vty") == 0) - /* pSeries LPAR virtual console */ - return add_preferred_console("hvc", 0, NULL); + } +#ifdef CONFIG_PPC_PSERIES + else if (strcmp(name, "vty") == 0) { + u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); + char *compat = (char *)get_property(prom_stdout, "compatible", NULL); + + if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { + /* Host Virtual Serial Interface */ + int offset; + switch (reg[0]) { + case 0x30000000: + offset = 0; + break; + case 0x30000001: + offset = 1; + break; + default: + goto not_found; + } + of_node_put(prom_stdout); + DBG("Found hvsi console at offset %d\n", offset); + return add_preferred_console("hvsi", offset, NULL); + } else { + /* pSeries LPAR virtual console */ + of_node_put(prom_stdout); + DBG("Found hvc console\n"); + return add_preferred_console("hvc", 0, NULL); + } + } +#endif /* CONFIG_PPC_PSERIES */ else if (strcmp(name, "ch-a") == 0) offset = 0; else if (strcmp(name, "ch-b") == 0) offset = 1; else - return -ENODEV; + goto not_found; + of_node_put(prom_stdout); + + DBG("Found serial console at ttyS%d\n", offset); return add_preferred_console("ttyS", offset, NULL); + not_found: + DBG("No preferred console found !\n"); + of_node_put(prom_stdout); + return -ENODEV; } console_initcall(set_preferred_console); - -int parse_bootinfo(void) -{ - struct bi_record *rec; - - rec = prom.bi_recs; - - if ( rec == NULL || rec->tag != BI_FIRST ) - return -1; - - for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) { - switch (rec->tag) { - case BI_CMD_LINE: - strlcpy(cmd_line, (void *)rec->data, sizeof(cmd_line)); - break; - } - } - - return 0; -} -#endif - -int __init ppc_init(void) -{ - /* clear the progress line */ - ppc_md.progress(" ", 0xffff); - - if (ppc_md.init != NULL) { - ppc_md.init(); - } - return 0; -} - -arch_initcall(ppc_init); - -void __init ppc64_calibrate_delay(void) -{ - loops_per_jiffy = tb_ticks_per_jiffy; - - printk("Calibrating delay loop... %lu.%02lu BogoMips\n", - loops_per_jiffy/(500000/HZ), - loops_per_jiffy/(5000/HZ) % 100); -} - -extern void (*calibrate_delay)(void); +#endif /* CONFIG_PPC_MULTIPLATFORM */ #ifdef CONFIG_IRQSTACKS static void __init irqstack_early_init(void) { - int i; + unsigned int i; - /* interrupt stacks must be under 256MB, we cannot afford to take SLB misses on them */ - for (i = 0; i < NR_CPUS; i++) { + /* + * interrupt stacks must be under 256MB, we cannot afford to take + * SLB misses on them. + */ + for_each_cpu(i) { softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, THREAD_SIZE, 0x10000000)); hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, @@ -594,6 +928,31 @@ #endif /* + * Stack space used when we detect a bad kernel stack pointer, and + * early in SMP boots before relocation is enabled. + */ +static void __init emergency_stack_init(void) +{ + unsigned long limit; + unsigned int i; + + /* + * Emergency stacks must be under 256MB, we cannot afford to take + * SLB misses on them. The ABI also requires them to be 128-byte + * aligned. + * + * Since we use these as temporary stacks during secondary CPU + * bringup, we need to get at them in real mode. This means they + * must also be within the RMO region. + */ + limit = min(0x10000000UL, lmb.rmo_size); + + for_each_cpu(i) + paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, + limit)) + PAGE_SIZE; +} + +/* * Called into from start_kernel, after lock_kernel has been called. * Initializes bootmem, which is unsed to manage page allocation until * mem_init is called. @@ -603,17 +962,9 @@ extern int panic_timeout; extern void do_init_bootmem(void); - calibrate_delay = ppc64_calibrate_delay; - ppc64_boot_msg(0x12, "Setup Arch"); -#ifdef CONFIG_XMON - if (strstr(cmd_line, "xmon")) { - /* ensure xmon is enabled */ - xmon_init(); - debugger(0); - } -#endif /* CONFIG_XMON */ + *cmdline_p = cmd_line; /* * Set cache line size based on type of cpu as a default. @@ -634,21 +985,22 @@ init_mm.end_data = (unsigned long) _edata; init_mm.brk = klimit; - /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); - *cmdline_p = cmd_line; - irqstack_early_init(); + emergency_stack_init(); /* set up the bootmem stuff with available memory */ do_init_bootmem(); + /* Select the correct idle loop for the platform. */ + idle_setup(); + ppc_md.setup_arch(); paging_init(); ppc64_boot_msg(0x15, "Setup Done"); } + /* ToDo: do something useful if ppc_md is not yet setup. */ #define PPC64_LINUX_FUNCTION 0x0f000000 #define PPC64_IPL_MESSAGE 0xc0000000 @@ -753,3 +1105,16 @@ __setup("spread_lpevents=", set_spread_lpevents ); __setup("decr_overclock_proc0=", set_decr_overclock_proc0 ); __setup("decr_overclock=", set_decr_overclock ); + +#ifdef CONFIG_XMON +static int __init early_xmon(char *p) +{ + /* ensure xmon is enabled */ + xmon_init(); + debugger(0); + + return 0; +} +early_param("xmon", early_xmon); +#endif + diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c --- a/arch/ppc64/kernel/signal.c 2004-10-18 14:55:53 -07:00 +++ b/arch/ppc64/kernel/signal.c 2004-10-18 14:55:53 -07:00 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -127,7 +126,7 @@ * v_regs pointer or not */ #ifdef CONFIG_ALTIVEC - elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve) & ~0xful); + elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve + 15) & ~0xful); #endif long err = 0; @@ -178,7 +177,7 @@ elf_vrreg_t __user *v_regs; #endif unsigned long err = 0; - unsigned long save_r13; + unsigned long save_r13 = 0; elf_greg_t *gregs = (elf_greg_t *)regs; int i; @@ -371,7 +370,8 @@ printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n", regs, uc, &uc->uc_mcontext); #endif - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); + return 0; } static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, @@ -446,7 +446,7 @@ printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - do_exit(SIGSEGV); + force_sigsegv(signr, current); } @@ -459,17 +459,13 @@ /* Set up Signal Frame */ setup_rt_frame(sig, ka, info, oldset, regs); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } - return; } static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) @@ -512,6 +508,7 @@ { siginfo_t info; int signr; + struct k_sigaction ka; /* * If the current thread is 32 bit - invoke the @@ -523,14 +520,12 @@ if (!oldset) oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - struct k_sigaction *ka = ¤t->sighand->action[signr-1]; - /* Whee! Actually deliver the signal. */ if (TRAP(regs) == 0x0C00) - syscall_restart(regs, ka); - handle_signal(signr, ka, &info, oldset, regs); + syscall_restart(regs, &ka); + handle_signal(signr, &ka, &info, oldset, regs); return 1; } diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c --- a/arch/ppc64/kernel/signal32.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc64/kernel/signal32.c 2004-10-18 14:57:03 -07:00 @@ -189,7 +189,7 @@ elf_greg_t64 *gregs = (elf_greg_t64 *)regs; int i; long err = 0; - unsigned int save_r2; + unsigned int save_r2 = 0; #ifdef CONFIG_ALTIVEC unsigned long msr; #endif @@ -472,10 +472,14 @@ &d->si_addr); break; case __SI_POLL >> 16: - case __SI_TIMER >> 16: err |= __put_user(s->si_band, &d->si_band); err |= __put_user(s->si_fd, &d->si_fd); break; + case __SI_TIMER >> 16: + err |= __put_user(s->si_tid, &d->si_tid); + err |= __put_user(s->si_overrun, &d->si_overrun); + err |= __put_user(s->si_int, &d->si_int); + break; case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __put_user(s->si_int, &d->si_int); @@ -699,9 +703,7 @@ printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig) @@ -864,9 +866,7 @@ printk("badframe in handle_signal, regs=%p frame=%x newsp=%x\n", regs, frame, *newspp); #endif - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* @@ -928,18 +928,16 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; - struct k_sigaction *ka; unsigned int frame, newsp; int signr, ret; + struct k_sigaction ka; if (!oldset) oldset = ¤t->blocked; newsp = frame = 0; - signr = get_signal_to_deliver(&info, regs, NULL); - - ka = (signr == 0)? NULL: ¤t->sighand->action[signr-1]; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (TRAP(regs) == 0x0C00 /* System Call! */ && regs->ccr & 0x10000000 /* error signalled */ @@ -950,7 +948,7 @@ if (signr > 0 && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK || (ret == ERESTARTSYS - && !(ka->sa.sa_flags & SA_RESTART)))) { + && !(ka.sa.sa_flags & SA_RESTART)))) { /* make the system call return an EINTR error */ regs->result = -EINTR; regs->gpr[3] = EINTR; @@ -969,7 +967,7 @@ if (signr == 0) return 0; /* no signals delivered */ - if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size + if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size && (!on_sig_stack(regs->gpr[1]))) newsp = (current->sas_ss_sp + current->sas_ss_size); else @@ -977,17 +975,15 @@ newsp &= ~0xfUL; /* Whee! Actually deliver the signal. */ - if (ka->sa.sa_flags & SA_SIGINFO) - handle_rt_signal32(signr, ka, &info, oldset, regs, newsp); + if (ka.sa.sa_flags & SA_SIGINFO) + handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); else - handle_signal32(signr, ka, &info, oldset, regs, newsp); - - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; + handle_signal32(signr, &ka, &info, oldset, regs, newsp); - if (!(ka->sa.sa_flags & SA_NODEFER)) { + if (!(ka.sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, + &ka.sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c --- a/arch/ppc64/kernel/smp.c 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/smp.c 2004-10-18 14:56:49 -07:00 @@ -15,6 +15,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -53,14 +54,20 @@ #include #include #include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif int smp_threads_ready; unsigned long cache_decay_ticks; cpumask_t cpu_possible_map = CPU_MASK_NONE; cpumask_t cpu_online_map = CPU_MASK_NONE; -cpumask_t cpu_available_map = CPU_MASK_NONE; -cpumask_t cpu_present_at_boot = CPU_MASK_NONE; +cpumask_t cpu_sibling_map[NR_CPUS] = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_possible_map); @@ -76,9 +83,13 @@ extern long register_vpa(unsigned long flags, unsigned long proc, unsigned long vpa); +int smt_enabled_at_boot = 1; + /* Low level assembly function used to backup CPU 0 state */ extern void __save_cpu_setup(void); +extern void pseries_secondary_smp_init(unsigned long); + #ifdef CONFIG_PPC_ISERIES static unsigned long iSeries_smp_message[NR_CPUS]; @@ -124,9 +135,8 @@ np = 0; for (i=0; i < NR_CPUS; ++i) { if (paca[i].lppaca.xDynProcStatus < 2) { - cpu_set(i, cpu_available_map); cpu_set(i, cpu_possible_map); - cpu_set(i, cpu_present_at_boot); + cpu_set(i, cpu_present_map); ++np; } } @@ -183,7 +193,7 @@ } #endif -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM void smp_openpic_message_pass(int target, int msg) { /* make sure we're sending something that translates to an IPI */ @@ -224,7 +234,10 @@ do_openpic_setup_cpu(); } -#ifdef CONFIG_HOTPLUG_CPU +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +#ifdef CONFIG_PPC_PSERIES + /* Get state of physical CPU. * Return codes: * 0 - The processor is in the RTAS stopped state @@ -233,13 +246,15 @@ * -1 - Hardware Error * -2 - Hardware Busy, Try again later. */ -static int query_cpu_stopped(unsigned int pcpu) +int query_cpu_stopped(unsigned int pcpu) { int cpu_status; int status, qcss_tok; + DBG(" -> query_cpu_stopped(%d)\n", pcpu); qcss_tok = rtas_token("query-cpu-stopped-state"); - BUG_ON(qcss_tok == RTAS_UNKNOWN_SERVICE); + if (qcss_tok == RTAS_UNKNOWN_SERVICE) + return -1; status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu); if (status != 0) { printk(KERN_ERR @@ -247,9 +262,13 @@ return status; } + DBG(" <- query_cpu_stopped(), status: %d\n", cpu_status); + return cpu_status; } +#ifdef CONFIG_HOTPLUG_CPU + int __cpu_disable(void) { /* FIXME: go put this in a header somewhere */ @@ -272,13 +291,12 @@ int cpu_status; unsigned int pcpu = get_hard_smp_processor_id(cpu); - for (tries = 0; tries < 5; tries++) { + for (tries = 0; tries < 25; tries++) { cpu_status = query_cpu_stopped(pcpu); - - if (cpu_status == 0) + if (cpu_status == 0 || cpu_status == -1) break; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(HZ/5); } if (cpu_status != 0) { printk("Querying DEAD? cpu %i (%i) shows %i\n", @@ -372,13 +390,13 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) { int status; - extern void (*pseries_secondary_smp_init)(unsigned int cpu); - unsigned long start_here = __pa(pseries_secondary_smp_init); + unsigned long start_here = __pa((u32)*((unsigned long *) + pseries_secondary_smp_init)); unsigned int pcpu; /* At boot time the cpus are already spinning in hold * loops, so nothing to do. */ - if (system_state == SYSTEM_BOOTING) + if (system_state < SYSTEM_RUNNING) return 1; pcpu = find_physical_cpu_to_start(get_hard_smp_processor_id(lcpu)); @@ -401,56 +419,11 @@ } return 1; } - -static inline void look_for_more_cpus(void) -{ - int num_addr_cell, num_size_cell, len, i, maxcpus; - struct device_node *np; - unsigned int *ireg; - - /* Find the property which will tell us about how many CPUs - * we're allowed to have. */ - if ((np = find_path_device("/rtas")) == NULL) { - printk(KERN_ERR "Could not find /rtas in device tree!"); - return; - } - num_addr_cell = prom_n_addr_cells(np); - num_size_cell = prom_n_size_cells(np); - - ireg = (unsigned int *)get_property(np, "ibm,lrdr-capacity", &len); - if (ireg == NULL) { - /* FIXME: make sure not marked as lrdr_capable() */ - return; - } - - maxcpus = ireg[num_addr_cell + num_size_cell]; - - /* Double maxcpus for processors which have SMT capability */ - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) - maxcpus *= 2; - - - if (maxcpus > NR_CPUS) { - printk(KERN_WARNING - "Partition configured for %d cpus, " - "operating system maximum is %d.\n", maxcpus, NR_CPUS); - maxcpus = NR_CPUS; - } else - printk(KERN_INFO "Partition configured for %d cpus.\n", - maxcpus); - - /* Make those cpus (which might appear later) possible too. */ - for (i = 0; i < maxcpus; i++) - cpu_set(i, cpu_possible_map); -} #else /* ... CONFIG_HOTPLUG_CPU */ static inline int __devinit smp_startup_cpu(unsigned int lcpu) { return 1; } -static inline void look_for_more_cpus(void) -{ -} #endif /* CONFIG_HOTPLUG_CPU */ static void smp_pSeries_kick_cpu(int nr) @@ -485,13 +458,13 @@ } #ifdef CONFIG_PPC_PSERIES -void vpa_init(int cpu) +static void vpa_init(int cpu) { - unsigned long flags; + unsigned long flags, pcpu = get_hard_smp_processor_id(cpu); /* Register the Virtual Processor Area (VPA) */ flags = 1UL << (63 - 18); - register_vpa(flags, cpu, __pa((unsigned long)&(paca[cpu].lppaca))); + register_vpa(flags, pcpu, __pa((unsigned long)&(paca[cpu].lppaca))); } static inline void smp_xics_do_message(int cpu, int msg) @@ -576,26 +549,47 @@ /* This is called very early */ void __init smp_init_pSeries(void) { + int ret, i; + + DBG(" -> smp_init_pSeries()\n"); if (naca->interrupt_controller == IC_OPEN_PIC) smp_ops = &pSeries_openpic_smp_ops; else smp_ops = &pSeries_xics_smp_ops; + /* Start secondary threads on SMT systems; primary threads + * are already in the running state. + */ + for_each_present_cpu(i) { + if (query_cpu_stopped(get_hard_smp_processor_id(i)) == 0) { + printk("%16.16x : starting thread\n", i); + DBG("%16.16x : starting thread\n", i); + rtas_call(rtas_token("start-cpu"), 3, 1, &ret, + get_hard_smp_processor_id(i), + __pa((u32)*((unsigned long *) + pseries_secondary_smp_init)), + i); + } + } + + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) + vpa_init(boot_cpuid); + /* Non-lpar has additional take/give timebase */ if (systemcfg->platform == PLATFORM_PSERIES) { smp_ops->give_timebase = pSeries_give_timebase; smp_ops->take_timebase = pSeries_take_timebase; } + + + DBG(" <- smp_init_pSeries()\n"); } -#endif +#endif /* CONFIG_PPC_PSERIES */ void smp_local_timer_interrupt(struct pt_regs * regs) { - if (!--(get_paca()->prof_counter)) { - update_process_times(user_mode(regs)); - (get_paca()->prof_counter)=get_paca()->prof_multiplier; - } + update_process_times(user_mode(regs)); } void smp_message_recv(int msg, struct pt_regs *regs) @@ -751,6 +745,8 @@ return ret; } +EXPORT_SYMBOL(smp_call_function); + void smp_call_function_interrupt(void) { void (*func) (void *info); @@ -794,26 +790,17 @@ static void __devinit smp_store_cpu_info(int id) { - per_cpu(pvr, id) = _get_PVR(); + per_cpu(pvr, id) = mfspr(SPRN_PVR); } static void __init smp_create_idle(unsigned int cpu) { - struct pt_regs regs; struct task_struct *p; /* create a process for the processor */ - /* only regs.msr is actually used, and 0 is OK for it */ - memset(®s, 0, sizeof(struct pt_regs)); - p = copy_process(CLONE_VM | CLONE_IDLETASK, - 0, ®s, 0, NULL, NULL); + p = fork_idle(cpu); if (IS_ERR(p)) panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - - wake_up_forked_process(p); - init_idle(p, cpu); - unhash_process(p); - paca[cpu].__current = p; current_set[cpu] = p->thread_info; } @@ -831,8 +818,6 @@ /* Fixup boot cpu */ smp_store_cpu_info(boot_cpuid); cpu_callin_map[boot_cpuid] = 1; - paca[boot_cpuid].prof_counter = 1; - paca[boot_cpuid].prof_multiplier = 1; #ifndef CONFIG_PPC_ISERIES paca[boot_cpuid].next_jiffy_update_tb = tb_last_stamp = get_tb(); @@ -843,8 +828,7 @@ * number of msecs off until someone does a settimeofday() */ do_gtod.tb_orig_stamp = tb_last_stamp; - - look_for_more_cpus(); + systemcfg->tb_orig_stamp = tb_last_stamp; #endif max_cpus = smp_ops->probe(); @@ -863,7 +847,6 @@ { BUG_ON(smp_processor_id() != boot_cpuid); - /* cpu_possible is set up in prom.c */ cpu_set(boot_cpuid, cpu_online_map); paca[boot_cpuid].__current = current; @@ -875,11 +858,9 @@ int c; /* At boot, don't bother with non-present cpus -JSCHOPP */ - if (system_state == SYSTEM_BOOTING && !cpu_present_at_boot(cpu)) + if (system_state < SYSTEM_RUNNING && !cpu_present(cpu)) return -ENOENT; - paca[cpu].prof_counter = 1; - paca[cpu].prof_multiplier = 1; paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock; if (!(cur_cpu_spec->cpu_features & CPU_FTR_SLB)) { @@ -909,7 +890,7 @@ * use this value that I found through experimentation. * -- Cort */ - if (system_state == SYSTEM_BOOTING) + if (system_state < SYSTEM_RUNNING) for (c = 5000; c && !cpu_callin_map[cpu]; c--) udelay(100); #ifdef CONFIG_HOTPLUG_CPU @@ -1004,219 +985,12 @@ smp_threads_ready = 1; set_cpus_allowed(current, old_mask); -} - -#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, cpu_domains); -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 = NULL, *last = NULL; - - /* Set up domains */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, 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); - cpumask_t my_cpumask = cpumask_of_cpu(i); - cpumask_t sibling_cpumask = cpumask_of_cpu(i ^ 0x1); - - *cpu_domain = SD_SIBLING_INIT; - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) - cpus_or(cpu_domain->span, my_cpumask, sibling_cpumask); - else - cpu_domain->span = my_cpumask; - cpu_domain->parent = phys_domain; - cpu_domain->groups = &sched_group_cpus[i]; - - *phys_domain = SD_CPU_INIT; - phys_domain->span = nodemask; - phys_domain->parent = node_domain; - phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)]; - - *node_domain = SD_NODE_INIT; - node_domain->span = cpu_possible_map; - node_domain->groups = &sched_group_nodes[node]; - } - - /* Set up CPU (sibling) groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - int j; - first = last = 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); - cpu->cpu_power = SCHED_LOAD_SCALE; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - } - - for (i = 0; i < MAX_NUMNODES; i++) { - int j; - cpumask_t nodemask; - struct sched_group *node = &sched_group_nodes[i]; - cpumask_t node_cpumask = node_to_cpumask(i); - cpus_and(nodemask, node_cpumask, cpu_possible_map); - - if (cpus_empty(nodemask)) - continue; - - first = last = NULL; - /* Set up physical groups */ - for_each_cpu_mask(j, nodemask) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, j); - struct sched_group *cpu = &sched_group_phys[j]; - - if (j != first_cpu(cpu_domain->span)) - continue; - - cpu->cpumask = cpu_domain->span; - /* - * Make each extra sibling increase power by 10% of - * the basic CPU. This is very arbitrary. - */ - cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10; - node->cpu_power += cpu->cpu_power; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - } - - /* Set up nodes */ - first = last = NULL; - for (i = 0; i < MAX_NUMNODES; i++) { - struct sched_group *cpu = &sched_group_nodes[i]; - cpumask_t nodemask; - cpumask_t node_cpumask = node_to_cpumask(i); - cpus_and(nodemask, node_cpumask, cpu_possible_map); - - if (cpus_empty(nodemask)) - continue; - - cpu->cpumask = nodemask; - /* ->cpu_power already setup */ - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - - mb(); - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - cpu_attach_domain(cpu_domain, i); - } -} -#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, cpu_domains); -static DEFINE_PER_CPU(struct sched_domain, phys_domains); -__init void arch_init_sched_domains(void) -{ - int i; - struct sched_group *first = NULL, *last = NULL; - - /* Set up domains */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - struct sched_domain *phys_domain = &per_cpu(phys_domains, i); - cpumask_t my_cpumask = cpumask_of_cpu(i); - cpumask_t sibling_cpumask = cpumask_of_cpu(i ^ 0x1); - - *cpu_domain = SD_SIBLING_INIT; - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) - cpus_or(cpu_domain->span, my_cpumask, sibling_cpumask); - else - cpu_domain->span = my_cpumask; - cpu_domain->parent = phys_domain; - cpu_domain->groups = &sched_group_cpus[i]; - - *phys_domain = SD_CPU_INIT; - phys_domain->span = cpu_possible_map; - phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)]; - } - - /* Set up CPU (sibling) groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - int j; - first = last = 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); - cpu->cpu_power = SCHED_LOAD_SCALE; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - } - - first = last = NULL; - /* Set up physical groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - struct sched_group *cpu = &sched_group_phys[i]; - - if (i != first_cpu(cpu_domain->span)) - continue; - - cpu->cpumask = cpu_domain->span; - /* See SMT+NUMA setup for comment */ - cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - - mb(); - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - cpu_attach_domain(cpu_domain, i); - } + /* + * We know at boot the maximum number of cpus we can add to + * a partition and set cpu_possible_map accordingly. cpu_present_map + * needs to match for the hotplug code to allow us to hot add + * any offline cpus. + */ + cpu_present_map = cpu_possible_map; } -#endif /* CONFIG_NUMA */ -#endif /* CONFIG_SCHED_SMT */ diff -Nru a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c --- a/arch/ppc64/kernel/stab.c 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,281 +0,0 @@ -/* - * PowerPC64 Segment Translation Support. - * - * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com - * Copyright (c) 2001 Dave Engebretsen - * - * Copyright (C) 2002 Anton Blanchard , IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -static int make_ste(unsigned long stab, unsigned long esid, - unsigned long vsid); - -void slb_initialize(void); - -/* - * Build an entry for the base kernel segment and put it into - * the segment table or SLB. All other segment table or SLB - * entries are faulted in. - */ -void stab_initialize(unsigned long stab) -{ - unsigned long vsid = get_kernel_vsid(KERNELBASE); - - if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) { - slb_initialize(); - } else { - asm volatile("isync; slbia; isync":::"memory"); - make_ste(stab, GET_ESID(KERNELBASE), vsid); - - /* Order update */ - asm volatile("sync":::"memory"); - } -} - -/* Both the segment table and SLB code uses the following cache */ -#define NR_STAB_CACHE_ENTRIES 8 -DEFINE_PER_CPU(long, stab_cache_ptr); -DEFINE_PER_CPU(long, stab_cache[NR_STAB_CACHE_ENTRIES]); - -/* - * Segment table stuff - */ - -/* - * Create a segment table entry for the given esid/vsid pair. - */ -static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) -{ - unsigned long entry, group, old_esid, castout_entry, i; - unsigned int global_entry; - STE *ste, *castout_ste; - unsigned long kernel_segment = (REGION_ID(esid << SID_SHIFT) != - USER_REGION_ID); - - /* Search the primary group first. */ - global_entry = (esid & 0x1f) << 3; - ste = (STE *)(stab | ((esid & 0x1f) << 7)); - - /* Find an empty entry, if one exists. */ - for (group = 0; group < 2; group++) { - for (entry = 0; entry < 8; entry++, ste++) { - if (!(ste->dw0.dw0.v)) { - ste->dw0.dword0 = 0; - ste->dw1.dword1 = 0; - ste->dw1.dw1.vsid = vsid; - ste->dw0.dw0.esid = esid; - ste->dw0.dw0.kp = 1; - if (!kernel_segment) - ste->dw0.dw0.ks = 1; - asm volatile("eieio":::"memory"); - ste->dw0.dw0.v = 1; - return (global_entry | entry); - } - } - /* Now search the secondary group. */ - global_entry = ((~esid) & 0x1f) << 3; - ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); - } - - /* - * Could not find empty entry, pick one with a round robin selection. - * Search all entries in the two groups. - */ - castout_entry = get_paca()->stab_rr; - for (i = 0; i < 16; i++) { - if (castout_entry < 8) { - global_entry = (esid & 0x1f) << 3; - ste = (STE *)(stab | ((esid & 0x1f) << 7)); - castout_ste = ste + castout_entry; - } else { - global_entry = ((~esid) & 0x1f) << 3; - ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); - castout_ste = ste + (castout_entry - 8); - } - - /* Dont cast out the first kernel segment */ - if (castout_ste->dw0.dw0.esid != GET_ESID(KERNELBASE)) - break; - - castout_entry = (castout_entry + 1) & 0xf; - } - - get_paca()->stab_rr = (castout_entry + 1) & 0xf; - - /* Modify the old entry to the new value. */ - - /* Force previous translations to complete. DRENG */ - asm volatile("isync" : : : "memory"); - - castout_ste->dw0.dw0.v = 0; - asm volatile("sync" : : : "memory"); /* Order update */ - - castout_ste->dw0.dword0 = 0; - castout_ste->dw1.dword1 = 0; - castout_ste->dw1.dw1.vsid = vsid; - old_esid = castout_ste->dw0.dw0.esid; - castout_ste->dw0.dw0.esid = esid; - castout_ste->dw0.dw0.kp = 1; - if (!kernel_segment) - castout_ste->dw0.dw0.ks = 1; - asm volatile("eieio" : : : "memory"); /* Order update */ - castout_ste->dw0.dw0.v = 1; - asm volatile("slbie %0" : : "r" (old_esid << SID_SHIFT)); - /* Ensure completion of slbie */ - asm volatile("sync" : : : "memory"); - - return (global_entry | (castout_entry & 0x7)); -} - -static inline void __ste_allocate(unsigned long esid, unsigned long vsid) -{ - unsigned char stab_entry; - unsigned long offset; - int region_id = REGION_ID(esid << SID_SHIFT); - - stab_entry = make_ste(get_paca()->stab_addr, esid, vsid); - - if (region_id != USER_REGION_ID) - return; - - offset = __get_cpu_var(stab_cache_ptr); - if (offset < NR_STAB_CACHE_ENTRIES) - __get_cpu_var(stab_cache[offset++]) = stab_entry; - else - offset = NR_STAB_CACHE_ENTRIES+1; - __get_cpu_var(stab_cache_ptr) = offset; -} - -/* - * Allocate a segment table entry for the given ea. - */ -int ste_allocate(unsigned long ea) -{ - unsigned long vsid, esid; - mm_context_t context; - - /* Check for invalid effective addresses. */ - if (!IS_VALID_EA(ea)) - return 1; - - /* Kernel or user address? */ - if (REGION_ID(ea) >= KERNEL_REGION_ID) { - vsid = get_kernel_vsid(ea); - context = KERNEL_CONTEXT(ea); - } else { - if (!current->mm) - return 1; - - context = current->mm->context; - vsid = get_vsid(context.id, ea); - } - - esid = GET_ESID(ea); - __ste_allocate(esid, vsid); - /* Order update */ - asm volatile("sync":::"memory"); - - return 0; -} - -/* - * preload some userspace segments into the segment table. - */ -static void preload_stab(struct task_struct *tsk, struct mm_struct *mm) -{ - unsigned long pc = KSTK_EIP(tsk); - unsigned long stack = KSTK_ESP(tsk); - unsigned long unmapped_base; - unsigned long pc_esid = GET_ESID(pc); - unsigned long stack_esid = GET_ESID(stack); - unsigned long unmapped_base_esid; - unsigned long vsid; - - if (test_tsk_thread_flag(tsk, TIF_32BIT)) - unmapped_base = TASK_UNMAPPED_BASE_USER32; - else - unmapped_base = TASK_UNMAPPED_BASE_USER64; - - unmapped_base_esid = GET_ESID(unmapped_base); - - if (!IS_VALID_EA(pc) || (REGION_ID(pc) >= KERNEL_REGION_ID)) - return; - vsid = get_vsid(mm->context.id, pc); - __ste_allocate(pc_esid, vsid); - - if (pc_esid == stack_esid) - return; - - if (!IS_VALID_EA(stack) || (REGION_ID(stack) >= KERNEL_REGION_ID)) - return; - vsid = get_vsid(mm->context.id, stack); - __ste_allocate(stack_esid, vsid); - - if (pc_esid == unmapped_base_esid || stack_esid == unmapped_base_esid) - return; - - if (!IS_VALID_EA(unmapped_base) || - (REGION_ID(unmapped_base) >= KERNEL_REGION_ID)) - return; - vsid = get_vsid(mm->context.id, unmapped_base); - __ste_allocate(unmapped_base_esid, vsid); - - /* Order update */ - asm volatile("sync" : : : "memory"); -} - -/* Flush all user entries from the segment table of the current processor. */ -void flush_stab(struct task_struct *tsk, struct mm_struct *mm) -{ - STE *stab = (STE *) get_paca()->stab_addr; - STE *ste; - unsigned long offset = __get_cpu_var(stab_cache_ptr); - - /* Force previous translations to complete. DRENG */ - asm volatile("isync" : : : "memory"); - - if (offset <= NR_STAB_CACHE_ENTRIES) { - int i; - - for (i = 0; i < offset; i++) { - ste = stab + __get_cpu_var(stab_cache[i]); - ste->dw0.dw0.v = 0; - } - } else { - unsigned long entry; - - /* Invalidate all entries. */ - ste = stab; - - /* Never flush the first entry. */ - ste += 1; - for (entry = 1; - entry < (PAGE_SIZE / sizeof(STE)); - entry++, ste++) { - unsigned long ea; - ea = ste->dw0.dw0.esid << SID_SHIFT; - if (ea < KERNELBASE) { - ste->dw0.dw0.v = 0; - } - } - } - - asm volatile("sync; slbia; sync":::"memory"); - - __get_cpu_var(stab_cache_ptr) = 0; - - preload_stab(tsk, mm); -} diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c --- a/arch/ppc64/kernel/sys_ppc32.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc64/kernel/sys_ppc32.c 2004-10-18 14:56:48 -07:00 @@ -72,7 +72,6 @@ #include #include #include -#include #include #include "pci.h" @@ -634,8 +633,24 @@ void start_thread32(struct pt_regs* regs, unsigned long nip, unsigned long sp) { set_fs(USER_DS); - memset(regs->gpr, 0, sizeof(regs->gpr)); - memset(®s->ctr, 0, 4 * sizeof(regs->ctr)); + + /* + * If we exec out of a kernel thread then thread.regs will not be + * set. Do it now. + */ + if (!current->thread.regs) { + unsigned long childregs = (unsigned long)current->thread_info + + THREAD_SIZE; + childregs -= sizeof(struct pt_regs); + current->thread.regs = (struct pt_regs *)childregs; + } + + /* + * ELF_PLAT_INIT already clears all registers but it also sets r2. + * So just clear r2 here. + */ + regs->gpr[2] = 0; + regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER32; @@ -700,7 +715,7 @@ (unsigned long) dfn, (unsigned long) off, (unsigned long) len, - (unsigned char __user *)AA(ubuf)); + compat_ptr(ubuf)); } asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) @@ -709,7 +724,7 @@ (unsigned long) dfn, (unsigned long) off, (unsigned long) len, - (unsigned char __user *)AA(ubuf)); + compat_ptr(ubuf)); } #define IOBASE_BRIDGE_NUMBER 0 @@ -1095,7 +1110,7 @@ u32 __unused[4]; }; -extern asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) +asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) { struct __sysctl_args32 tmp; int error; @@ -1114,19 +1129,20 @@ glibc's __sysctl uses rw memory for the structure anyway. */ oldlenp = (size_t __user *)addr; - if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) || + if (get_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)) || put_user(oldlen, oldlenp)) return -EFAULT; } lock_kernel(); - error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval), - oldlenp, (void __user *)A(tmp.newval), tmp.newlen); + error = do_sysctl(compat_ptr(tmp.name), tmp.nlen, + compat_ptr(tmp.oldval), oldlenp, + compat_ptr(tmp.newval), tmp.newlen); unlock_kernel(); if (oldlenp) { if (!error) { if (get_user(oldlen, oldlenp) || - put_user(oldlen, (u32 __user *)A(tmp.oldlenp))) + put_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp))) error = -EFAULT; } copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); diff -Nru a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c --- a/arch/ppc64/kernel/sysfs.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc64/kernel/sysfs.c 2004-10-18 14:55:55 -07:00 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,14 @@ /* PMC stuff */ +#ifdef CONFIG_PPC_ISERIES +void ppc64_enable_pmcs(void) +{ + /* XXX Implement for iseries */ +} +#endif + +#ifdef CONFIG_PPC_MULTIPLATFORM /* * Enabling PMCs will slow partition context switch times so we only do * it the first time we write to the PMCs. @@ -103,18 +112,14 @@ static DEFINE_PER_CPU(char, pmcs_enabled); -#ifdef CONFIG_PPC_ISERIES -void ppc64_enable_pmcs(void) -{ - /* XXX Implement for iseries */ -} -#else void ppc64_enable_pmcs(void) { unsigned long hid0; +#ifdef CONFIG_PPC_PSERIES unsigned long set, reset; int ret; unsigned int ctrl; +#endif /* CONFIG_PPC_PSERIES */ /* Only need to enable them once */ if (__get_cpu_var(pmcs_enabled)) @@ -123,37 +128,42 @@ __get_cpu_var(pmcs_enabled) = 1; switch (systemcfg->platform) { - case PLATFORM_PSERIES: - hid0 = mfspr(HID0); - hid0 |= 1UL << (63 - 20); - - /* POWER4 requires the following sequence */ - asm volatile( - "sync\n" - "mtspr %1, %0\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): - "memory"); - break; - - case PLATFORM_PSERIES_LPAR: - set = 1UL << 63; - reset = 0; - ret = plpar_hcall_norets(H_PERFMON, set, reset); - if (ret) - printk(KERN_ERR "H_PERFMON call returned %d", - ret); - break; + case PLATFORM_PSERIES: + case PLATFORM_POWERMAC: + hid0 = mfspr(HID0); + hid0 |= 1UL << (63 - 20); + + /* POWER4 requires the following sequence */ + asm volatile( + "sync\n" + "mtspr %1, %0\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): + "memory"); + break; + +#ifdef CONFIG_PPC_PSERIES + case PLATFORM_PSERIES_LPAR: + set = 1UL << 63; + reset = 0; + ret = plpar_hcall_norets(H_PERFMON, set, reset); + if (ret) + printk(KERN_ERR "H_PERFMON call on cpu %u " + "returned %d\n", + smp_processor_id(), ret); + break; +#endif /* CONFIG_PPC_PSERIES */ - default: - break; + default: + break; } +#ifdef CONFIG_PPC_PSERIES /* instruct hypervisor to maintain PMCs */ if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { char *ptr = (char *)&paca[smp_processor_id()].lppaca; @@ -169,8 +179,11 @@ ctrl |= RUNLATCH; mtspr(CTRLT, ctrl); } +#endif /* CONFIG_PPC_PSERIES */ } -#endif +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +EXPORT_SYMBOL(ppc64_enable_pmcs); /* XXX convert to rusty's on_one_cpu */ static unsigned long run_on_cpu(unsigned long cpu, diff -Nru a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c --- a/arch/ppc64/kernel/time.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc64/kernel/time.c 2004-10-18 14:57:03 -07:00 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -83,7 +84,7 @@ #define XSEC_PER_SEC (1024*1024) unsigned long tb_ticks_per_jiffy; -unsigned long tb_ticks_per_usec; +unsigned long tb_ticks_per_usec = 100; /* sane default */ unsigned long tb_ticks_per_sec; unsigned long next_xtime_sync_tb; unsigned long xtime_sync_interval; @@ -101,50 +102,12 @@ extern unsigned long lpevent_count; extern int smp_tb_synchronized; +extern struct timezone sys_tz; + void ppc_adjtimex(void); static unsigned adjusting_time = 0; -/* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ -static inline void ppc64_do_profile(struct pt_regs *regs) -{ - unsigned long nip; - extern unsigned long prof_cpu_mask; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - nip = instruction_pointer(regs); - - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!((1<>= prof_shift; - /* - * Don't ignore out-of-bounds EIP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (nip > prof_len-1) - nip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[nip]); -} - static __inline__ void timer_check_rtc(void) { /* @@ -195,6 +158,19 @@ } } +#ifdef CONFIG_SMP +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (in_lock_functions(pc)) + return regs->link; + + return pc; +} +EXPORT_SYMBOL(profile_pc); +#endif + #ifdef CONFIG_PPC_ISERIES /* @@ -233,6 +209,8 @@ do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; tb_to_xs = divres.result_low; do_gtod.varp->tb_to_xs = tb_to_xs; + systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; + systemcfg->tb_to_xs = tb_to_xs; } else { printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" @@ -273,7 +251,7 @@ irq_enter(); #ifndef CONFIG_PPC_ISERIES - ppc64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #endif lpaca->lppaca.xIntDword.xFields.xDecrInt = 0; @@ -281,8 +259,20 @@ while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) { #ifdef CONFIG_SMP - smp_local_timer_interrupt(regs); + /* + * We cannot disable the decrementer, so in the period + * between this cpu's being marked offline in cpu_online_map + * and calling stop-self, it is taking timer interrupts. + * Avoid calling into the scheduler rebalancing code if this + * is the case. + */ + if (!cpu_is_offline(cpu)) + smp_local_timer_interrupt(regs); #endif + /* + * No need to check whether cpu is offline here; boot_cpuid + * should have been fixed up by now. + */ if (cpu == boot_cpuid) { write_seqlock(&xtime_lock); tb_last_stamp = lpaca->next_jiffy_update_tb; @@ -408,6 +398,7 @@ new_xsec += new_sec * XSEC_PER_SEC; if ( new_xsec > delta_xsec ) { do_gtod.varp->stamp_xsec = new_xsec - delta_xsec; + systemcfg->stamp_xsec = new_xsec - delta_xsec; } else { /* This is only for the case where the user is setting the time @@ -416,8 +407,13 @@ * the time to Jan 5, 1970 */ do_gtod.varp->stamp_xsec = new_xsec; do_gtod.tb_orig_stamp = tb_last_stamp; + systemcfg->stamp_xsec = new_xsec; + systemcfg->tb_orig_stamp = tb_last_stamp; } + systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; + systemcfg->tz_dsttime = sys_tz.tz_dsttime; + write_sequnlock_irqrestore(&xtime_lock, flags); clock_was_set(); return 0; @@ -520,6 +516,11 @@ do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; do_gtod.varp->tb_to_xs = tb_to_xs; do_gtod.tb_to_us = tb_to_us; + systemcfg->tb_orig_stamp = tb_last_stamp; + systemcfg->tb_update_count = 0; + systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; + systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; + systemcfg->tb_to_xs = tb_to_xs; xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8); next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval; @@ -654,6 +655,22 @@ mb(); do_gtod.varp = temp_varp; do_gtod.var_idx = temp_idx; + + /* + * tb_update_count is used to allow the problem state gettimeofday code + * to assure itself that it sees a consistent view of the tb_to_xs and + * stamp_xsec variables. It reads the tb_update_count, then reads + * tb_to_xs and stamp_xsec and then reads tb_update_count again. If + * the two values of tb_update_count match and are even then the + * tb_to_xs and stamp_xsec values are consistent. If not, then it + * loops back and reads them again until this criteria is met. + */ + ++(systemcfg->tb_update_count); + wmb(); + systemcfg->tb_to_xs = new_tb_to_xs; + systemcfg->stamp_xsec = new_stamp_xsec; + wmb(); + ++(systemcfg->tb_update_count); write_sequnlock_irqrestore( &xtime_lock, flags ); diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c --- a/arch/ppc64/kernel/traps.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/kernel/traps.c 2004-10-18 14:56:32 -07:00 @@ -134,14 +134,20 @@ } static void -_exception(int signr, siginfo_t *info, struct pt_regs *regs) +_exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { + siginfo_t info; + if (!user_mode(regs)) { if (die("Exception in kernel mode", regs, signr)) return; } - force_sig_info(signr, info, current); + memset(&info, 0, sizeof(info)); + info.si_signo = signr; + info.si_code = code; + info.si_addr = (void __user *) addr; + force_sig_info(signr, &info, current); } #ifdef CONFIG_PPC_PSERIES @@ -213,27 +219,21 @@ */ static int recover_mce(struct pt_regs *regs, struct rtas_error_log err) { - siginfo_t info; - - if (err.disposition == DISP_FULLY_RECOVERED) { + if (err.disposition == RTAS_DISP_FULLY_RECOVERED) { /* Platform corrected itself */ return 1; } else if ((regs->msr & MSR_RI) && user_mode(regs) && - err.severity == SEVERITY_ERROR_SYNC && - err.disposition == DISP_NOT_RECOVERED && - err.target == TARGET_MEMORY && - err.type == TYPE_ECC_UNCORR && + err.severity == RTAS_SEVERITY_ERROR_SYNC && + err.disposition == RTAS_DISP_NOT_RECOVERED && + err.target == RTAS_TARGET_MEMORY && + err.type == RTAS_TYPE_ECC_UNCORR && !(current->pid == 0 || current->pid == 1)) { /* Kill off a user process with an ECC error */ - info.si_signo = SIGBUS; - info.si_errno = 0; - /* XXX something better for ECC error? */ - info.si_code = BUS_ADRERR; - info.si_addr = (void __user *)regs->nip; printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n", current->pid); - _exception(SIGBUS, &info, regs); + /* XXX something better for ECC error? */ + _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); return 1; } return 0; @@ -278,35 +278,46 @@ void UnknownException(struct pt_regs *regs) { - siginfo_t info; - printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", regs->nip, regs->msr, regs->trap); - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = 0; - info.si_addr = NULL; - _exception(SIGTRAP, &info, regs); + _exception(SIGTRAP, regs, 0, 0); } void InstructionBreakpointException(struct pt_regs *regs) { - siginfo_t info; - if (debugger_iabr_match(regs)) return; - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; - info.si_addr = (void __user *)regs->nip; - _exception(SIGTRAP, &info, regs); + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); +} + +void +SingleStepException(struct pt_regs *regs) +{ + regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ + + if (debugger_sstep(regs)) + return; + + _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); +} + +/* + * After we have successfully emulated an instruction, we have to + * check if the instruction was being single-stepped, and if so, + * pretend we got a single-step exception. This was pointed out + * by Kumar Gala. -- paulus + */ +static inline void emulate_single_step(struct pt_regs *regs) +{ + if (regs->msr & MSR_SE) + SingleStepException(regs); } static void parse_fpe(struct pt_regs *regs) { - siginfo_t info; + int code = 0; unsigned long fpscr; flush_fp_to_thread(current); @@ -315,31 +326,84 @@ /* Invalid operation */ if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) - info.si_code = FPE_FLTINV; + code = FPE_FLTINV; /* Overflow */ else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX)) - info.si_code = FPE_FLTOVF; + code = FPE_FLTOVF; /* Underflow */ else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX)) - info.si_code = FPE_FLTUND; + code = FPE_FLTUND; /* Divide by zero */ else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX)) - info.si_code = FPE_FLTDIV; + code = FPE_FLTDIV; /* Inexact result */ else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX)) - info.si_code = FPE_FLTRES; + code = FPE_FLTRES; + + _exception(SIGFPE, regs, code, regs->nip); +} + +/* + * Illegal instruction emulation support. Return non-zero if we can't + * emulate, or -EFAULT if the associated memory access caused an access + * fault. Return zero on success. + */ + +#define INST_DCBA 0x7c0005ec +#define INST_DCBA_MASK 0x7c0007fe + +#define INST_MCRXR 0x7c000400 +#define INST_MCRXR_MASK 0x7c0007fe + +static int emulate_instruction(struct pt_regs *regs) +{ + unsigned int instword; + + if (!user_mode(regs)) + return -EINVAL; + + CHECK_FULL_REGS(regs); - else - info.si_code = 0; + if (get_user(instword, (unsigned int __user *)(regs->nip))) + return -EFAULT; - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_addr = (void __user *)regs->nip; - _exception(SIGFPE, &info, regs); + /* Emulating the dcba insn is just a no-op. */ + if ((instword & INST_DCBA_MASK) == INST_DCBA) { + static int warned; + + if (!warned) { + printk(KERN_WARNING + "process %d (%s) uses obsolete 'dcba' insn\n", + current->pid, current->comm); + warned = 1; + } + return 0; + } + + /* Emulate the mcrxr insn. */ + if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { + static int warned; + unsigned int shift; + + if (!warned) { + printk(KERN_WARNING + "process %d (%s) uses obsolete 'mcrxr' insn\n", + current->pid, current->comm); + warned = 1; + } + + shift = (instword >> 21) & 0x1c; + regs->ccr &= ~(0xf0000000 >> shift); + regs->ccr |= (regs->xer & 0xf0000000) >> shift; + regs->xer &= ~0xf0000000; + return 0; + } + + return -EINVAL; } /* @@ -395,20 +459,14 @@ void ProgramCheckException(struct pt_regs *regs) { - siginfo_t info; - if (regs->msr & 0x100000) { /* IEEE FP exception */ - parse_fpe(regs); + } else if (regs->msr & 0x40000) { /* Privileged instruction */ + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_PRVOPC; - info.si_addr = (void __user *)regs->nip; - _exception(SIGILL, &info, regs); } else if (regs->msr & 0x20000) { /* trap exception */ @@ -419,19 +477,24 @@ regs->nip += 4; return; } - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; - info.si_addr = (void __user *)regs->nip; - _exception(SIGTRAP, &info, regs); + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); + } else { - /* Illegal instruction */ + /* Illegal instruction; try to emulate it. */ + switch (emulate_instruction(regs)) { + case 0: + regs->nip += 4; + emulate_single_step(regs); + break; - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLTRP; - info.si_addr = (void __user *)regs->nip; - _exception(SIGILL, &info, regs); + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + break; + + default: + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + break; + } } } @@ -448,13 +511,7 @@ if (user_mode(regs)) { /* A user program has executed an altivec instruction, but this kernel doesn't support altivec. */ - siginfo_t info; - - memset(&info, 0, sizeof(info)); - info.si_signo = SIGILL; - info.si_code = ILL_ILLOPC; - info.si_addr = (void *) regs->nip; - _exception(SIGILL, &info, regs); + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); return; } #endif @@ -463,41 +520,22 @@ die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); } -void -SingleStepException(struct pt_regs *regs) -{ - siginfo_t info; - - regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ - - if (debugger_sstep(regs)) - return; - - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_TRACE; - info.si_addr = (void __user *)regs->nip; - _exception(SIGTRAP, &info, regs); -} - -/* - * After we have successfully emulated an instruction, we have to - * check if the instruction was being single-stepped, and if so, - * pretend we got a single-step exception. This was pointed out - * by Kumar Gala. -- paulus - */ -static inline void emulate_single_step(struct pt_regs *regs) -{ - if (regs->msr & MSR_SE) - SingleStepException(regs); -} +/* Ensure exceptions are disabled */ +#define MMCR0_PMXE (1UL << (31 - 5)) +#define MMCR0_PMAO (1UL << (31 - 24)) static void dummy_perf(struct pt_regs *regs) { + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + + mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO); + mtspr(SPRN_MMCR0, mmcr0); } void (*perf_irq)(struct pt_regs *) = dummy_perf; +EXPORT_SYMBOL(perf_irq); + void PerformanceMonitorException(struct pt_regs *regs) { @@ -508,7 +546,6 @@ AlignmentException(struct pt_regs *regs) { int fixed; - siginfo_t info; fixed = fix_alignment(regs); @@ -521,11 +558,7 @@ /* Operand address was bad */ if (fixed == -EFAULT) { if (user_mode(regs)) { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *)regs->dar; - force_sig_info(SIGSEGV, &info, current); + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->dar); } else { /* Search exception table */ bad_page_fault(regs, regs->dar, SIGSEGV); @@ -534,11 +567,7 @@ return; } - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRALN; - info.si_addr = (void __user *)regs->nip; - _exception(SIGBUS, &info, regs); + _exception(SIGBUS, regs, BUS_ADRALN, regs->nip); } #ifdef CONFIG_ALTIVEC diff -Nru a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/kernel/u3_iommu.c 2004-10-18 14:57:04 -07:00 @@ -0,0 +1,321 @@ +/* + * arch/ppc64/kernel/u3_iommu.c + * + * Copyright (C) 2004 Olof Johansson , IBM Corporation + * + * Based on pSeries_iommu.c: + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation + * Copyright (C) 2004 Olof Johansson , IBM Corporation + * + * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +extern int iommu_force_on; + +/* physical base of DART registers */ +#define DART_BASE 0xf8033000UL + +/* Offset from base to control register */ +#define DARTCNTL 0 +/* Offset from base to exception register */ +#define DARTEXCP 0x10 +/* Offset from base to TLB tag registers */ +#define DARTTAG 0x1000 + + +/* Control Register fields */ + +/* base address of table (pfn) */ +#define DARTCNTL_BASE_MASK 0xfffff +#define DARTCNTL_BASE_SHIFT 12 + +#define DARTCNTL_FLUSHTLB 0x400 +#define DARTCNTL_ENABLE 0x200 + +/* size of table in pages */ +#define DARTCNTL_SIZE_MASK 0x1ff +#define DARTCNTL_SIZE_SHIFT 0 + +/* DART table fields */ +#define DARTMAP_VALID 0x80000000 +#define DARTMAP_RPNMASK 0x00ffffff + +/* Physical base address and size of the DART table */ +unsigned long dart_tablebase; /* exported to htab_initialize */ +static unsigned long dart_tablesize; + +/* Virtual base address of the DART table */ +static u32 *dart_vbase; + +/* Mapped base address for the dart */ +static unsigned int *dart; + +/* Dummy val that entries are set to when unused */ +static unsigned int dart_emptyval; + +static struct iommu_table iommu_table_u3; +static int dart_dirty; + +#define DBG(...) + +static inline void dart_tlb_invalidate_all(void) +{ + unsigned long l = 0; + unsigned int reg; + unsigned long limit; + + DBG("dart: flush\n"); + + /* To invalidate the DART, set the DARTCNTL_FLUSHTLB bit in the + * control register and wait for it to clear. + * + * Gotcha: Sometimes, the DART won't detect that the bit gets + * set. If so, clear it and set it again. + */ + + limit = 0; + +retry: + reg = in_be32((unsigned int *)dart+DARTCNTL); + reg |= DARTCNTL_FLUSHTLB; + out_be32((unsigned int *)dart+DARTCNTL, reg); + + l = 0; + while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) && + l < (1L<it_base) + index; + + /* On U3, all memory is contigous, so we can move this + * out of the loop. + */ + while (npages--) { + rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; + + *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); + + rpn++; + uaddr += PAGE_SIZE; + } + + dart_dirty = 1; +} + + +static void dart_free(struct iommu_table *tbl, long index, long npages) +{ + unsigned int *dp; + + /* We don't worry about flushing the TLB cache. The only drawback of + * not doing it is that we won't catch buggy device drivers doing + * bad DMAs, but then no 32-bit architecture ever does either. + */ + + DBG("dart: free at: %lx, %lx\n", index, npages); + + dp = ((unsigned int *)tbl->it_base) + index; + + while (npages--) + *(dp++) = dart_emptyval; +} + + +static int dart_init(struct device_node *dart_node) +{ + unsigned int regword; + unsigned int i; + unsigned long tmp; + struct page *p; + + if (dart_tablebase == 0 || dart_tablesize == 0) { + printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n"); + return -ENODEV; + } + + /* Make sure nothing from the DART range remains in the CPU cache + * from a previous mapping that existed before the kernel took + * over + */ + flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize); + + /* Allocate a spare page to map all invalid DART pages. We need to do + * that to work around what looks like a problem with the HT bridge + * prefetching into invalid pages and corrupting data + */ + tmp = __get_free_pages(GFP_ATOMIC, 1); + if (tmp == 0) + panic("U3-DART: Cannot allocate spare page !"); + dart_emptyval = DARTMAP_VALID | + ((virt_to_abs(tmp) >> PAGE_SHIFT) & DARTMAP_RPNMASK); + + /* Map in DART registers. FIXME: Use device node to get base address */ + dart = ioremap(DART_BASE, 0x7000); + if (dart == NULL) + panic("U3-DART: Cannot map registers !"); + + /* Set initial control register contents: table base, + * table size and enable bit + */ + regword = DARTCNTL_ENABLE | + ((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | + (((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK) + << DARTCNTL_SIZE_SHIFT); + p = virt_to_page(dart_tablebase); + dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); + + /* Fill initial table */ + for (i = 0; i < dart_tablesize/4; i++) + dart_vbase[i] = dart_emptyval; + + /* Initialize DART with table base and enable it. */ + out_be32((unsigned int *)dart, regword); + + /* Invalidate DART to get rid of possible stale TLBs */ + dart_tlb_invalidate_all(); + + iommu_table_u3.it_busno = 0; + + /* Units of tce entries */ + iommu_table_u3.it_offset = 0; + + /* Set the tce table size - measured in pages */ + iommu_table_u3.it_size = dart_tablesize >> PAGE_SHIFT; + + /* Initialize the common IOMMU code */ + iommu_table_u3.it_base = (unsigned long)dart_vbase; + iommu_table_u3.it_index = 0; + iommu_table_u3.it_blocksize = 1; + iommu_table_u3.it_entrysize = sizeof(u32); + iommu_init_table(&iommu_table_u3); + + /* Reserve the last page of the DART to avoid possible prefetch + * past the DART mapped area + */ + set_bit(iommu_table_u3.it_mapsize - 1, iommu_table_u3.it_map); + + printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n"); + + return 0; +} + +void iommu_setup_u3(void) +{ + struct pci_dev *dev = NULL; + struct device_node *dn; + + /* Find the DART in the device-tree */ + dn = of_find_compatible_node(NULL, "dart", "u3-dart"); + if (dn == NULL) + return; + + /* Setup low level TCE operations for the core IOMMU code */ + ppc_md.tce_build = dart_build; + ppc_md.tce_free = dart_free; + ppc_md.tce_flush = dart_flush; + + /* Initialize the DART HW */ + if (dart_init(dn)) + return; + + /* Setup pci_dma ops */ + pci_iommu_init(); + + /* We only have one iommu table on the mac for now, which makes + * things simple. Setup all PCI devices to point to this table + */ + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + /* We must use pci_device_to_OF_node() to make sure that + * we get the real "final" pointer to the device in the + * pci_dev sysdata and not the temporary PHB one + */ + struct device_node *dn = pci_device_to_OF_node(dev); + if (dn) + dn->iommu_table = &iommu_table_u3; + } +} + +void __init alloc_u3_dart_table(void) +{ + /* Only reserve DART space if machine has more than 2GB of RAM + * or if requested with iommu=on on cmdline. + */ + if (lmb_end_of_DRAM() <= 0x80000000ull && !iommu_force_on) + return; + + /* 512 pages (2MB) is max DART tablesize. */ + dart_tablesize = 1UL << 21; + /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we + * will blow up an entire large page anyway in the kernel mapping + */ + dart_tablebase = (unsigned long) + abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); + + printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase); +} diff -Nru a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c --- a/arch/ppc64/kernel/udbg.c 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc64/kernel/udbg.c 2004-10-18 14:55:54 -07:00 @@ -84,23 +84,38 @@ void udbg_init_scc(struct device_node *np) { + u32 *reg; unsigned long addr; int i, x; if (np == NULL) np = of_find_node_by_name(NULL, "escc"); - if (np == NULL) + if (np == NULL || np->parent == NULL) + return; + + udbg_printf("found SCC...\n"); + /* Get address within mac-io ASIC */ + reg = (u32 *)get_property(np, "reg", NULL); + if (reg == NULL) + return; + addr = reg[0]; + udbg_printf("local addr: %lx\n", addr); + /* Get address of mac-io PCI itself */ + reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); + if (reg == NULL) return; - - /* Lock-enable the SCC channel */ - pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); + addr += reg[2]; + udbg_printf("final addr: %lx\n", addr); /* Setup for 57600 8N1 */ - addr = np->addrs[0].address + 0x20; + addr += 0x20; sccc = (volatile u8 *) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; sccc += addr & ~PAGE_MASK; sccd = sccc + 0x10; + udbg_printf("ioremap result sccc: %p\n", sccc); + mb(); + for (i = 20000; i != 0; --i) x = *sccc; eieio(); *sccc = 9; eieio(); /* reset A or B side */ @@ -119,6 +134,30 @@ #endif /* CONFIG_PPC_PMAC */ +#if CONFIG_PPC_PMAC +extern u8 real_readb(volatile u8 *addr); +extern void real_writeb(u8 data, volatile u8 *addr); + +static void udbg_real_putc(unsigned char c) +{ + while ((real_readb(sccc) & SCC_TXRDY) == 0) + ; + real_writeb(c, sccd); + if (c == '\n') + udbg_real_putc('\r'); +} + +void udbg_init_pmac_realmode(void) +{ + sccc = (volatile u8 *)0x80013020ul; + sccd = (volatile u8 *)0x80013030ul; + + ppc_md.udbg_putc = udbg_real_putc; + ppc_md.udbg_getc = NULL; + ppc_md.udbg_getc_poll = NULL; +} +#endif /* CONFIG_PPC_PMAC */ + void udbg_putc(unsigned char c) { if (udbg_comport) { @@ -191,9 +230,12 @@ while ((c = *s++) != '\0') ppc_md.udbg_putc(c); } - } else { + } +#if 0 + else { printk("%s", s); } +#endif } int udbg_write(const char *s, int n) @@ -218,7 +260,7 @@ char c, *p = buf; int i; - if (!ppc_md.udbg_putc) + if (!ppc_md.udbg_getc) return 0; for (i = 0; i < buflen; ++i) { diff -Nru a/arch/ppc64/kernel/vector.S b/arch/ppc64/kernel/vector.S --- a/arch/ppc64/kernel/vector.S 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/kernel/vector.S 2004-10-18 14:56:32 -07:00 @@ -89,7 +89,7 @@ 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fmadds fr0,fr0,fr1,fr2 + fmadds fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b @@ -109,7 +109,7 @@ 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fnmsubs fr0,fr0,fr1,fr2 + fnmsubs fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b diff -Nru a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c --- a/arch/ppc64/kernel/vio.c 2004-10-18 14:56:27 -07:00 +++ b/arch/ppc64/kernel/vio.c 2004-10-18 14:56:27 -07:00 @@ -225,6 +225,10 @@ struct vio_dev *viodev; int i; + /* there is only one of each of these */ + vio_register_device_iseries("viocons", 0); + vio_register_device_iseries("vscsi", 0); + vlan_map = HvLpConfig_getVirtualLanIndexMap(); for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { if ((vlan_map & (0x8000 >> i)) == 0) diff -Nru a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c --- a/arch/ppc64/kernel/viopath.c 2004-10-18 14:55:55 -07:00 +++ b/arch/ppc64/kernel/viopath.c 2004-10-18 14:55:55 -07:00 @@ -38,8 +38,8 @@ #include #include #include +#include -#include #include #include #include diff -Nru a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S --- a/arch/ppc64/kernel/vmlinux.lds.S 2004-10-18 14:56:49 -07:00 +++ b/arch/ppc64/kernel/vmlinux.lds.S 2004-10-18 14:56:49 -07:00 @@ -14,6 +14,7 @@ .text : { *(.text .text.*) SCHED_TEXT + LOCK_TEXT *(.fixup) . = ALIGN(4096); _etext = .; @@ -61,12 +62,6 @@ __setup_end = .; } - __param : { - __start___param = .; - *(__param) - __stop___param = .; - } - .initcall.init : { __initcall_start = .; *(.initcall1.init) @@ -122,8 +117,11 @@ .data : { *(.data .data.rel* .toc1) - *(.opd) *(.branch_lt) + } + + .opd : { + *(.opd) } .got : { diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c --- a/arch/ppc64/kernel/xics.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/kernel/xics.c 2004-10-18 14:56:32 -07:00 @@ -536,7 +536,7 @@ #ifdef CONFIG_SMP for_each_cpu(i) { /* FIXME: Do this dynamically! --RR */ - if (!cpu_present_at_boot(i)) + if (!cpu_present(i)) continue; xics_per_cpu[i] = __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, (ulong)inodes[get_hard_smp_processor_id(i)].size, diff -Nru a/arch/ppc64/lib/checksum.S b/arch/ppc64/lib/checksum.S --- a/arch/ppc64/lib/checksum.S 2004-10-18 14:56:29 -07:00 +++ b/arch/ppc64/lib/checksum.S 2004-10-18 14:56:29 -07:00 @@ -92,19 +92,19 @@ adde r5,r5,r6 bdnz 2b andi. r4,r4,7 /* compute bytes left to sum after doublewords */ -3: cmpi 0,r4,4 /* is at least a full word left? */ +3: cmpwi 0,r4,4 /* is at least a full word left? */ blt 4f lwz r6,8(r3) /* sum this word */ addi r3,r3,4 subi r4,r4,4 adde r5,r5,r6 -4: cmpi 0,r4,2 /* is at least a halfword left? */ +4: cmpwi 0,r4,2 /* is at least a halfword left? */ blt+ 5f lhz r6,8(r3) /* sum this halfword */ addi r3,r3,2 subi r4,r4,2 adde r5,r5,r6 -5: cmpi 0,r4,1 /* is at least a byte left? */ +5: cmpwi 0,r4,1 /* is at least a byte left? */ bne+ 6f lbz r6,8(r3) /* sum this byte */ slwi r6,r6,8 /* this byte is assumed to be the upper byte of a halfword */ @@ -150,7 +150,7 @@ adde r0,r0,r6 bdnz 82b andi. r5,r5,3 -3: cmpi 0,r5,2 +3: cmpwi 0,r5,2 blt+ 4f 83: lhz r6,4(r3) addi r3,r3,2 @@ -158,7 +158,7 @@ 93: sth r6,4(r4) addi r4,r4,2 adde r0,r0,r6 -4: cmpi 0,r5,1 +4: cmpwi 0,r5,1 bne+ 5f 84: lbz r6,4(r3) 94: stb r6,4(r4) @@ -198,7 +198,7 @@ bdnz 97b .globl src_error src_error: - cmpi 0,r7,0 + cmpdi 0,r7,0 beq 1f li r6,-EFAULT stw r6,0(r7) @@ -207,7 +207,7 @@ .globl dst_error dst_error: - cmpi 0,r8,0 + cmpdi 0,r8,0 beq 1f li r6,-EFAULT stw r6,0(r8) diff -Nru a/arch/ppc64/lib/locks.c b/arch/ppc64/lib/locks.c --- a/arch/ppc64/lib/locks.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/lib/locks.c 2004-10-18 14:56:33 -07:00 @@ -20,28 +20,9 @@ #include #include -#ifndef CONFIG_SPINLINE - -/* - * On a system with shared processors (that is, where a physical - * processor is multiplexed between several virtual processors), - * there is no point spinning on a lock if the holder of the lock - * isn't currently scheduled on a physical processor. Instead - * we detect this situation and ask the hypervisor to give the - * rest of our timeslice to the lock holder. - * - * So that we can tell which virtual processor is holding a lock, - * we put 0x80000000 | smp_processor_id() in the lock when it is - * held. Conveniently, we have a word in the paca that holds this - * value. - */ - /* waiting for a spinlock... */ #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) -/* We only yield to the hypervisor if we are in shared processor mode */ -#define SHARED_PROCESSOR (get_paca()->lppaca.xSharedProc) - void __spin_yield(spinlock_t *lock) { unsigned int lock_value, holder_cpu, yield_count; @@ -63,100 +44,16 @@ HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, ((u64)holder_cpu << 32) | yield_count); #else - plpar_hcall_norets(H_CONFER, holder_cpu, yield_count); + plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), + yield_count); #endif } -#else /* SPLPAR || ISERIES */ -#define __spin_yield(x) barrier() -#define SHARED_PROCESSOR 0 -#endif - -/* - * This returns the old value in the lock, so we succeeded - * in getting the lock if the return value is 0. - */ -static __inline__ unsigned long __spin_trylock(spinlock_t *lock) -{ - unsigned long tmp, tmp2; - - __asm__ __volatile__( -" lwz %1,%3(13) # __spin_trylock\n\ -1: lwarx %0,0,%2\n\ - cmpwi 0,%0,0\n\ - bne- 2f\n\ - stwcx. %1,0,%2\n\ - bne- 1b\n\ - isync\n\ -2:" : "=&r" (tmp), "=&r" (tmp2) - : "r" (&lock->lock), "i" (offsetof(struct paca_struct, lock_token)) - : "cr0", "memory"); - - return tmp; -} - -int _raw_spin_trylock(spinlock_t *lock) -{ - return __spin_trylock(lock) == 0; -} - -EXPORT_SYMBOL(_raw_spin_trylock); - -void _raw_spin_lock(spinlock_t *lock) -{ - while (1) { - if (likely(__spin_trylock(lock) == 0)) - break; - do { - HMT_low(); - if (SHARED_PROCESSOR) - __spin_yield(lock); - } while (likely(lock->lock != 0)); - HMT_medium(); - } -} - -EXPORT_SYMBOL(_raw_spin_lock); - -void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags) -{ - unsigned long flags_dis; - - while (1) { - if (likely(__spin_trylock(lock) == 0)) - break; - local_save_flags(flags_dis); - local_irq_restore(flags); - do { - HMT_low(); - if (SHARED_PROCESSOR) - __spin_yield(lock); - } while (likely(lock->lock != 0)); - HMT_medium(); - local_irq_restore(flags_dis); - } -} - -EXPORT_SYMBOL(_raw_spin_lock_flags); - -void spin_unlock_wait(spinlock_t *lock) -{ - while (lock->lock) { - HMT_low(); - if (SHARED_PROCESSOR) - __spin_yield(lock); - } - HMT_medium(); -} - -EXPORT_SYMBOL(spin_unlock_wait); - /* * Waiting for a read lock or a write lock on a rwlock... * This turns out to be the same for read and write locks, since * we only know the holder if it is write-locked. */ -#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) void __rw_yield(rwlock_t *rw) { int lock_value; @@ -179,121 +76,20 @@ HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, ((u64)holder_cpu << 32) | yield_count); #else - plpar_hcall_norets(H_CONFER, holder_cpu, yield_count); + plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), + yield_count); #endif } - -#else /* SPLPAR || ISERIES */ -#define __rw_yield(x) barrier() #endif -/* - * This returns the old value in the lock + 1, - * so we got a read lock if the return value is > 0. - */ -static __inline__ long __read_trylock(rwlock_t *rw) -{ - long tmp; - - __asm__ __volatile__( -"1: lwarx %0,0,%1 # read_trylock\n\ - extsw %0,%0\n\ - addic. %0,%0,1\n\ - ble- 2f\n\ - stwcx. %0,0,%1\n\ - bne- 1b\n\ - isync\n\ -2:" : "=&r" (tmp) - : "r" (&rw->lock) - : "cr0", "xer", "memory"); - - return tmp; -} - -int _raw_read_trylock(rwlock_t *rw) -{ - return __read_trylock(rw) > 0; -} - -EXPORT_SYMBOL(_raw_read_trylock); - -void _raw_read_lock(rwlock_t *rw) -{ - while (1) { - if (likely(__read_trylock(rw) > 0)) - break; - do { - HMT_low(); - if (SHARED_PROCESSOR) - __rw_yield(rw); - } while (likely(rw->lock < 0)); - HMT_medium(); - } -} - -EXPORT_SYMBOL(_raw_read_lock); - -void _raw_read_unlock(rwlock_t *rw) -{ - long tmp; - - __asm__ __volatile__( - "eieio # read_unlock\n\ -1: lwarx %0,0,%1\n\ - addic %0,%0,-1\n\ - stwcx. %0,0,%1\n\ - bne- 1b" - : "=&r"(tmp) - : "r"(&rw->lock) - : "cr0", "memory"); -} - -EXPORT_SYMBOL(_raw_read_unlock); - -/* - * This returns the old value in the lock, - * so we got the write lock if the return value is 0. - */ -static __inline__ long __write_trylock(rwlock_t *rw) -{ - long tmp, tmp2; - - __asm__ __volatile__( -" lwz %1,%3(13) # write_trylock\n\ -1: lwarx %0,0,%2\n\ - cmpwi 0,%0,0\n\ - bne- 2f\n\ - stwcx. %1,0,%2\n\ - bne- 1b\n\ - isync\n\ -2:" : "=&r" (tmp), "=&r" (tmp2) - : "r" (&rw->lock), "i" (offsetof(struct paca_struct, lock_token)) - : "cr0", "memory"); - - return tmp; -} - -int _raw_write_trylock(rwlock_t *rw) -{ - return __write_trylock(rw) == 0; -} - -EXPORT_SYMBOL(_raw_write_trylock); - -void _raw_write_lock(rwlock_t *rw) +void spin_unlock_wait(spinlock_t *lock) { - while (1) { - if (likely(__write_trylock(rw) == 0)) - break; - do { - HMT_low(); - if (SHARED_PROCESSOR) - __rw_yield(rw); - } while (likely(rw->lock != 0)); - HMT_medium(); + while (lock->lock) { + HMT_low(); + if (SHARED_PROCESSOR) + __spin_yield(lock); } + HMT_medium(); } -EXPORT_SYMBOL(_raw_write_lock); - -#endif /* CONFIG_SPINLINE */ +EXPORT_SYMBOL(spin_unlock_wait); diff -Nru a/arch/ppc64/mm/Makefile b/arch/ppc64/mm/Makefile --- a/arch/ppc64/mm/Makefile 2004-10-18 14:55:54 -07:00 +++ b/arch/ppc64/mm/Makefile 2004-10-18 14:55:54 -07:00 @@ -4,6 +4,8 @@ EXTRA_CFLAGS += -mno-minimal-toc -obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o tlb.o slb_low.o slb.o +obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o tlb.o \ + slb_low.o slb.o stab.o mmap.o obj-$(CONFIG_DISCONTIGMEM) += numa.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += hash_native.o diff -Nru a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S --- a/arch/ppc64/mm/hash_low.S 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc64/mm/hash_low.S 2004-10-18 14:56:50 -07:00 @@ -172,9 +172,9 @@ li r9,0 _GLOBAL(htab_call_hpte_insert1) bl . /* Will be patched by htab_finish_init() */ - cmpi 0,r3,0 + cmpdi 0,r3,0 bge htab_pte_insert_ok /* Insertion successful */ - cmpi 0,r3,-2 /* Critical failure */ + cmpdi 0,r3,-2 /* Critical failure */ beq- htab_pte_insert_failure /* Now try secondary slot */ @@ -194,9 +194,9 @@ li r9,0 _GLOBAL(htab_call_hpte_insert2) bl . /* Will be patched by htab_finish_init() */ - cmpi 0,r3,0 + cmpdi 0,r3,0 bge+ htab_pte_insert_ok /* Insertion successful */ - cmpi 0,r3,-2 /* Critical failure */ + cmpdi 0,r3,-2 /* Critical failure */ beq- htab_pte_insert_failure /* Both are full, we need to evict something */ @@ -263,7 +263,7 @@ /* if we failed because typically the HPTE wasn't really here * we try an insertion. */ - cmpi 0,r3,-1 + cmpdi 0,r3,-1 beq- htab_insert_pte /* Clear the BUSY bit and Write out the PTE */ @@ -278,6 +278,10 @@ b bail htab_pte_insert_failure: - b .htab_insert_failure + /* Bail out restoring old PTE */ + ld r6,STK_PARM(r6)(r1) + std r31,0(r6) + li r3,-1 + b bail diff -Nru a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/mm/hash_native.c 2004-10-18 14:56:28 -07:00 @@ -0,0 +1,419 @@ +/* + * native hashtable management. + * + * SMP scalability work: + * Copyright (C) 2001 Anton Blanchard , IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HPTE_LOCK_BIT 3 + +static spinlock_t native_tlbie_lock = SPIN_LOCK_UNLOCKED; + +static inline void native_lock_hpte(HPTE *hptep) +{ + unsigned long *word = &hptep->dw0.dword0; + + while (1) { + if (!test_and_set_bit(HPTE_LOCK_BIT, word)) + break; + while(test_bit(HPTE_LOCK_BIT, word)) + cpu_relax(); + } +} + +static inline void native_unlock_hpte(HPTE *hptep) +{ + unsigned long *word = &hptep->dw0.dword0; + + asm volatile("lwsync":::"memory"); + clear_bit(HPTE_LOCK_BIT, word); +} + +long native_hpte_insert(unsigned long hpte_group, unsigned long va, + unsigned long prpn, int secondary, + unsigned long hpteflags, int bolted, int large) +{ + unsigned long arpn = physRpn_to_absRpn(prpn); + HPTE *hptep = htab_data.htab + hpte_group; + Hpte_dword0 dw0; + HPTE lhpte; + int i; + + for (i = 0; i < HPTES_PER_GROUP; i++) { + dw0 = hptep->dw0.dw0; + + if (!dw0.v) { + /* retry with lock held */ + native_lock_hpte(hptep); + dw0 = hptep->dw0.dw0; + if (!dw0.v) + break; + native_unlock_hpte(hptep); + } + + hptep++; + } + + if (i == HPTES_PER_GROUP) + return -1; + + lhpte.dw1.dword1 = 0; + lhpte.dw1.dw1.rpn = arpn; + lhpte.dw1.flags.flags = hpteflags; + + lhpte.dw0.dword0 = 0; + lhpte.dw0.dw0.avpn = va >> 23; + lhpte.dw0.dw0.h = secondary; + lhpte.dw0.dw0.bolted = bolted; + lhpte.dw0.dw0.v = 1; + + if (large) { + lhpte.dw0.dw0.l = 1; + lhpte.dw0.dw0.avpn &= ~0x1UL; + } + + hptep->dw1.dword1 = lhpte.dw1.dword1; + + /* Guarantee the second dword is visible before the valid bit */ + __asm__ __volatile__ ("eieio" : : : "memory"); + + /* + * Now set the first dword including the valid bit + * NOTE: this also unlocks the hpte + */ + hptep->dw0.dword0 = lhpte.dw0.dword0; + + __asm__ __volatile__ ("ptesync" : : : "memory"); + + return i | (secondary << 3); +} + +static long native_hpte_remove(unsigned long hpte_group) +{ + HPTE *hptep; + Hpte_dword0 dw0; + int i; + int slot_offset; + + /* pick a random entry to start at */ + slot_offset = mftb() & 0x7; + + for (i = 0; i < HPTES_PER_GROUP; i++) { + hptep = htab_data.htab + hpte_group + slot_offset; + dw0 = hptep->dw0.dw0; + + if (dw0.v && !dw0.bolted) { + /* retry with lock held */ + native_lock_hpte(hptep); + dw0 = hptep->dw0.dw0; + if (dw0.v && !dw0.bolted) + break; + native_unlock_hpte(hptep); + } + + slot_offset++; + slot_offset &= 0x7; + } + + if (i == HPTES_PER_GROUP) + return -1; + + /* Invalidate the hpte. NOTE: this also unlocks it */ + hptep->dw0.dword0 = 0; + + return i; +} + +static inline void set_pp_bit(unsigned long pp, HPTE *addr) +{ + unsigned long old; + unsigned long *p = &addr->dw1.dword1; + + __asm__ __volatile__( + "1: ldarx %0,0,%3\n\ + rldimi %0,%2,0,61\n\ + stdcx. %0,0,%3\n\ + bne 1b" + : "=&r" (old), "=m" (*p) + : "r" (pp), "r" (p), "m" (*p) + : "cc"); +} + +/* + * Only works on small pages. Yes its ugly to have to check each slot in + * the group but we only use this during bootup. + */ +static long native_hpte_find(unsigned long vpn) +{ + HPTE *hptep; + unsigned long hash; + unsigned long i, j; + long slot; + Hpte_dword0 dw0; + + hash = hpt_hash(vpn, 0); + + for (j = 0; j < 2; j++) { + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + for (i = 0; i < HPTES_PER_GROUP; i++) { + hptep = htab_data.htab + slot; + dw0 = hptep->dw0.dw0; + + if ((dw0.avpn == (vpn >> 11)) && dw0.v && + (dw0.h == j)) { + /* HPTE matches */ + if (j) + slot = -slot; + return slot; + } + ++slot; + } + hash = ~hash; + } + + return -1; +} + +static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, + unsigned long va, int large, int local) +{ + HPTE *hptep = htab_data.htab + slot; + Hpte_dword0 dw0; + unsigned long avpn = va >> 23; + int ret = 0; + + if (large) + avpn &= ~0x1UL; + + native_lock_hpte(hptep); + + dw0 = hptep->dw0.dw0; + + /* Even if we miss, we need to invalidate the TLB */ + if ((dw0.avpn != avpn) || !dw0.v) { + native_unlock_hpte(hptep); + ret = -1; + } else { + set_pp_bit(newpp, hptep); + native_unlock_hpte(hptep); + } + + /* Ensure it is out of the tlb too */ + if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + tlbiel(va); + } else { + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (lock_tlbie) + spin_lock(&native_tlbie_lock); + tlbie(va, large); + if (lock_tlbie) + spin_unlock(&native_tlbie_lock); + } + + return ret; +} + +/* + * Update the page protection bits. Intended to be used to create + * guard pages for kernel data structures on pages which are bolted + * in the HPT. Assumes pages being operated on will not be stolen. + * Does not work on large pages. + * + * No need to lock here because we should be the only user. + */ +static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea) +{ + unsigned long vsid, va, vpn, flags; + long slot; + HPTE *hptep; + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + vsid = get_kernel_vsid(ea); + va = (vsid << 28) | (ea & 0x0fffffff); + vpn = va >> PAGE_SHIFT; + + slot = native_hpte_find(vpn); + if (slot == -1) + panic("could not find page to bolt\n"); + hptep = htab_data.htab + slot; + + set_pp_bit(newpp, hptep); + + /* Ensure it is out of the tlb too */ + if (lock_tlbie) + spin_lock_irqsave(&native_tlbie_lock, flags); + tlbie(va, 0); + if (lock_tlbie) + spin_unlock_irqrestore(&native_tlbie_lock, flags); +} + +static void native_hpte_invalidate(unsigned long slot, unsigned long va, + int large, int local) +{ + HPTE *hptep = htab_data.htab + slot; + Hpte_dword0 dw0; + unsigned long avpn = va >> 23; + unsigned long flags; + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (large) + avpn &= ~0x1UL; + + local_irq_save(flags); + native_lock_hpte(hptep); + + dw0 = hptep->dw0.dw0; + + /* Even if we miss, we need to invalidate the TLB */ + if ((dw0.avpn != avpn) || !dw0.v) { + native_unlock_hpte(hptep); + } else { + /* Invalidate the hpte. NOTE: this also unlocks it */ + hptep->dw0.dword0 = 0; + } + + /* Invalidate the tlb */ + if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + tlbiel(va); + } else { + if (lock_tlbie) + spin_lock(&native_tlbie_lock); + tlbie(va, large); + if (lock_tlbie) + spin_unlock(&native_tlbie_lock); + } + local_irq_restore(flags); +} + +static void native_flush_hash_range(unsigned long context, + unsigned long number, int local) +{ + unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn; + int i, j; + HPTE *hptep; + Hpte_dword0 dw0; + struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + + /* XXX fix for large ptes */ + unsigned long large = 0; + + local_irq_save(flags); + + j = 0; + for (i = 0; i < number; i++) { + if ((batch->addr[i] >= USER_START) && + (batch->addr[i] <= USER_END)) + vsid = get_vsid(context, batch->addr[i]); + else + vsid = get_kernel_vsid(batch->addr[i]); + + va = (vsid << 28) | (batch->addr[i] & 0x0fffffff); + batch->vaddr[j] = va; + if (large) + vpn = va >> HPAGE_SHIFT; + else + vpn = va >> PAGE_SHIFT; + hash = hpt_hash(vpn, large); + secondary = (pte_val(batch->pte[i]) & _PAGE_SECONDARY) >> 15; + if (secondary) + hash = ~hash; + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + slot += (pte_val(batch->pte[i]) & _PAGE_GROUP_IX) >> 12; + + hptep = htab_data.htab + slot; + + avpn = va >> 23; + if (large) + avpn &= ~0x1UL; + + native_lock_hpte(hptep); + + dw0 = hptep->dw0.dw0; + + /* Even if we miss, we need to invalidate the TLB */ + if ((dw0.avpn != avpn) || !dw0.v) { + native_unlock_hpte(hptep); + } else { + /* Invalidate the hpte. NOTE: this also unlocks it */ + hptep->dw0.dword0 = 0; + } + + j++; + } + + if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + asm volatile("ptesync":::"memory"); + + for (i = 0; i < j; i++) + __tlbiel(batch->vaddr[i]); + + asm volatile("ptesync":::"memory"); + } else { + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (lock_tlbie) + spin_lock(&native_tlbie_lock); + + asm volatile("ptesync":::"memory"); + + for (i = 0; i < j; i++) + __tlbie(batch->vaddr[i], 0); + + asm volatile("eieio; tlbsync; ptesync":::"memory"); + + if (lock_tlbie) + spin_unlock(&native_tlbie_lock); + } + + local_irq_restore(flags); +} + +void hpte_init_native(void) +{ +#ifdef CONFIG_PPC_PSERIES + struct device_node *root; + const char *model; +#endif /* CONFIG_PPC_PSERIES */ + + ppc_md.hpte_invalidate = native_hpte_invalidate; + ppc_md.hpte_updatepp = native_hpte_updatepp; + ppc_md.hpte_updateboltedpp = native_hpte_updateboltedpp; + ppc_md.hpte_insert = native_hpte_insert; + ppc_md.hpte_remove = native_hpte_remove; + +#ifdef CONFIG_PPC_PSERIES + /* Disable TLB batching on nighthawk */ + root = of_find_node_by_path("/"); + if (root) { + model = get_property(root, "model", NULL); + if (!strcmp(model, "CHRP IBM,9076-N81")) { + of_node_put(root); + goto bail; + } + of_node_put(root); + } +#endif /* CONFIG_PPC_PSERIES */ + + ppc_md.flush_hash_range = native_flush_hash_range; + bail: + htab_finish_init(); +} diff -Nru a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c --- a/arch/ppc64/mm/hash_utils.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/mm/hash_utils.c 2004-10-18 14:56:33 -07:00 @@ -18,6 +18,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -28,6 +30,7 @@ #include #include #include +#include #include #include @@ -50,6 +53,12 @@ #include #include +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + /* * Note: pte --> Linux PTE * HPTE --> PowerPC Hashed Page Table Entry @@ -62,9 +71,9 @@ * */ -#ifdef CONFIG_PMAC_DART +#ifdef CONFIG_U3_DART extern unsigned long dart_tablebase; -#endif /* CONFIG_PMAC_DART */ +#endif /* CONFIG_U3_DART */ HTAB htab_data = {NULL, 0, 0, 0, 0}; @@ -80,7 +89,7 @@ ; } -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM static inline void create_pte_mapping(unsigned long start, unsigned long end, unsigned long mode, int large) { @@ -99,7 +108,7 @@ int ret; if (large) - vpn = va >> LARGE_PAGE_SHIFT; + vpn = va >> HPAGE_SHIFT; else vpn = va >> PAGE_SHIFT; @@ -107,12 +116,14 @@ hpteg = ((hash & htab_data.htab_hash_mask)*HPTES_PER_GROUP); - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) +#ifdef CONFIG_PPC_PSERIES + if (systemcfg->platform & PLATFORM_LPAR) ret = pSeries_lpar_hpte_insert(hpteg, va, virt_to_abs(addr) >> PAGE_SHIFT, 0, mode, 1, large); else - ret = pSeries_hpte_insert(hpteg, va, +#endif /* CONFIG_PPC_PSERIES */ + ret = native_hpte_insert(hpteg, va, virt_to_abs(addr) >> PAGE_SHIFT, 0, mode, 1, large); @@ -130,6 +141,8 @@ unsigned long mode_rw; int i, use_largepages = 0; + DBG(" -> htab_initialize()\n"); + /* * Calculate the required size of the htab. We want the number of * PTEGs to equal one half the number of real pages. @@ -146,12 +159,19 @@ htab_data.htab_num_ptegs = pteg_count; htab_data.htab_hash_mask = pteg_count - 1; - if (systemcfg->platform == PLATFORM_PSERIES || - systemcfg->platform == PLATFORM_POWERMAC) { + if (systemcfg->platform & PLATFORM_LPAR) { + /* Using a hypervisor which owns the htab */ + htab_data.htab = NULL; + _SDR1 = 0; + } else { /* Find storage for the HPT. Must be contiguous in * the absolute address space. */ table = lmb_alloc(htab_size_bytes, htab_size_bytes); + + DBG("Hash table allocated at %lx, size: %lx\n", table, + htab_size_bytes); + if ( !table ) { ppc64_terminate_msg(0x20, "hpt space"); loop_forever(); @@ -163,10 +183,6 @@ /* Initialize the HPT with no entries */ memset((void *)table, 0, htab_size_bytes); - } else { - /* Using a hypervisor which owns the htab */ - htab_data.htab = NULL; - _SDR1 = 0; } mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; @@ -178,14 +194,16 @@ if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) use_largepages = 1; - /* add all physical memory to the bootmem map */ + /* create bolted the linear mapping in the hash table */ for (i=0; i < lmb.memory.cnt; i++) { unsigned long base, size; base = lmb.memory.region[i].physbase + KERNELBASE; size = lmb.memory.region[i].size; -#ifdef CONFIG_PMAC_DART + DBG("creating mapping for region: %lx : %lx\n", base, size); + +#ifdef CONFIG_U3_DART /* Do not map the DART space. Fortunately, it will be aligned * in such a way that it will not cross two lmb regions and will * fit within a single 16Mb page. @@ -193,6 +211,8 @@ * only use 2Mb of that space. We will use more of it later for * AGP GART. We have to use a full 16Mb large page. */ + DBG("DART base: %lx\n", dart_tablebase); + if (dart_tablebase != 0 && dart_tablebase >= base && dart_tablebase < (base + size)) { if (base != dart_tablebase) @@ -203,13 +223,14 @@ mode_rw, use_largepages); continue; } -#endif /* CONFIG_PMAC_DART */ +#endif /* CONFIG_U3_DART */ create_pte_mapping(base, base + size, mode_rw, use_largepages); } + DBG(" <- htab_initialize()\n"); } #undef KB #undef MB -#endif +#endif /* CONFIG_PPC_MULTIPLATFORM */ /* * Called by asm hashtable.S for doing lazy icache flush @@ -236,14 +257,11 @@ return pp; } -/* - * Called by asm hashtable.S in case of critical insert failure +/* Result code is: + * 0 - handled + * 1 - normal page fault + * -1 - critical hash insertion error */ -void htab_insert_failure(void) -{ - panic("hash_page: pte_insert failed\n"); -} - int hash_page(unsigned long ea, unsigned long access, unsigned long trap) { void *pgdir; @@ -255,24 +273,24 @@ int local = 0; cpumask_t tmp; - /* Check for invalid addresses. */ - if (!IS_VALID_EA(ea)) - return 1; - switch (REGION_ID(ea)) { case USER_REGION_ID: user_region = 1; mm = current->mm; - if (mm == NULL) + if ((ea > USER_END) || (! mm)) return 1; vsid = get_vsid(mm->context.id, ea); break; case IO_REGION_ID: + if (ea > IMALLOC_END) + return 1; mm = &ioremap_mm; vsid = get_kernel_vsid(ea); break; case VMALLOC_REGION_ID: + if (ea > VMALLOC_END) + return 1; mm = &init_mm; vsid = get_kernel_vsid(ea); break; @@ -334,7 +352,7 @@ va = (vsid << 28) | (ea & 0x0fffffff); if (large) - vpn = va >> LARGE_PAGE_SHIFT; + vpn = va >> HPAGE_SHIFT; else vpn = va >> PAGE_SHIFT; hash = hpt_hash(vpn, large); @@ -369,6 +387,25 @@ *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc)); flush_icache_range((unsigned long)insn_addr, 4+ (unsigned long)insn_addr); +} + +/* + * low_hash_fault is called when we the low level hash code failed + * to instert a PTE due to an hypervisor error + */ +void low_hash_fault(struct pt_regs *regs, unsigned long address) +{ + if (user_mode(regs)) { + siginfo_t info; + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info(SIGBUS, &info, current); + return; + } + bad_page_fault(regs, address, SIGBUS); } void __init htab_finish_init(void) diff -Nru a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c --- a/arch/ppc64/mm/hugetlbpage.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/mm/hugetlbpage.c 2004-10-18 14:56:32 -07:00 @@ -527,6 +527,108 @@ return -ENOMEM; } +/* + * This mmap-allocator allocates new areas top-down from below the + * stack's low limit (the base): + * + * Because we have an exclusive hugepage region which lies within the + * normal user address space, we have to take special measures to make + * non-huge mmap()s evade the hugepage reserved regions. + */ +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma, *prev_vma; + struct mm_struct *mm = current->mm; + unsigned long base = mm->mmap_base, addr = addr0; + int first_time = 1; + + /* requested length too big for entire address space */ + if (len > TASK_SIZE) + return -ENOMEM; + + /* dont allow allocations above current base */ + if (mm->free_area_cache > base) + mm->free_area_cache = base; + + /* requesting a specific address */ + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start) + && !is_hugepage_only_range(addr,len)) + return addr; + } + +try_again: + /* make sure it can fit in the remaining address space */ + if (mm->free_area_cache < len) + goto fail; + + /* either no address requested or cant fit in requested address hole */ + addr = (mm->free_area_cache - len) & PAGE_MASK; + do { +hugepage_recheck: + if (touches_hugepage_low_range(addr, len)) { + addr = (addr & ((~0) << SID_SHIFT)) - len; + goto hugepage_recheck; + } else if (touches_hugepage_high_range(addr, len)) { + addr = TASK_HPAGE_BASE - len; + } + + /* + * Lookup failure means no vma is above this address, + * i.e. return with success: + */ + if (!(vma = find_vma_prev(mm, addr, &prev_vma))) + return addr; + + /* + * new region fits between prev_vma->vm_end and + * vma->vm_start, use it: + */ + if (addr+len <= vma->vm_start && + (!prev_vma || (addr >= prev_vma->vm_end))) + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr); + else + /* pull free_area_cache down to the first hole */ + if (mm->free_area_cache == vma->vm_end) + mm->free_area_cache = vma->vm_start; + + /* try just below the current vma->vm_start */ + addr = vma->vm_start-len; + } while (len <= vma->vm_start); + +fail: + /* + * if hint left us with no space for the requested + * mapping then try again: + */ + if (first_time) { + mm->free_area_cache = base; + first_time = 0; + goto try_again; + } + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + mm->free_area_cache = TASK_UNMAPPED_BASE; + addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); + /* + * Restore the topdown base: + */ + mm->free_area_cache = base; + + return addr; +} + static unsigned long htlb_get_low_area(unsigned long len, u16 segmask) { unsigned long addr = 0; @@ -751,7 +853,7 @@ vsid = get_vsid(context.id, ea); va = (vsid << 28) | (ea & 0x0fffffff); - vpn = va >> LARGE_PAGE_SHIFT; + vpn = va >> HPAGE_SHIFT; hash = hpt_hash(vpn, 1); if (hugepte_val(pte) & _HUGEPAGE_SECONDARY) hash = ~hash; diff -Nru a/arch/ppc64/mm/imalloc.c b/arch/ppc64/mm/imalloc.c --- a/arch/ppc64/mm/imalloc.c 2004-10-18 14:56:27 -07:00 +++ b/arch/ppc64/mm/imalloc.c 2004-10-18 14:56:27 -07:00 @@ -37,33 +37,51 @@ return 0; } +/* Return whether the region described by v_addr and size is a subset + * of the region described by parent + */ +static inline int im_region_is_subset(unsigned long v_addr, unsigned long size, + struct vm_struct *parent) +{ + return (int) (v_addr >= (unsigned long) parent->addr && + v_addr < (unsigned long) parent->addr + parent->size && + size < parent->size); +} + +/* Return whether the region described by v_addr and size is a superset + * of the region described by child + */ +static int im_region_is_superset(unsigned long v_addr, unsigned long size, + struct vm_struct *child) +{ + struct vm_struct parent; + + parent.addr = (void *) v_addr; + parent.size = size; + + return im_region_is_subset((unsigned long) child->addr, child->size, + &parent); +} + /* Return whether the region described by v_addr and size overlaps - * the region described by vm. Overlapping regions meet the + * the region described by vm. Overlapping regions meet the * following conditions: * 1) The regions share some part of the address space * 2) The regions aren't identical - * 3) The first region is not a subset of the second + * 3) Neither region is a subset of the other */ -static inline int im_region_overlaps(unsigned long v_addr, unsigned long size, +static int im_region_overlaps(unsigned long v_addr, unsigned long size, struct vm_struct *vm) { + if (im_region_is_superset(v_addr, size, vm)) + return 0; + return (v_addr + size > (unsigned long) vm->addr + vm->size && v_addr < (unsigned long) vm->addr + vm->size) || (v_addr < (unsigned long) vm->addr && v_addr + size > (unsigned long) vm->addr); } -/* Return whether the region described by v_addr and size is a subset - * of the region described by vm - */ -static inline int im_region_is_subset(unsigned long v_addr, unsigned long size, - struct vm_struct *vm) -{ - return (int) (v_addr >= (unsigned long) vm->addr && - v_addr < (unsigned long) vm->addr + vm->size && - size < vm->size); -} - /* Determine imalloc status of region described by v_addr and size. * Can return one of the following: * IM_REGION_UNUSED - Entire region is unallocated in imalloc space. @@ -73,28 +91,37 @@ * IM_REGION_EXISTS - Exact region already allocated in imalloc space. * vm will be assigned to a ptr to the existing imlist * member. - * IM_REGION_OVERLAPS - A portion of the region is already allocated in - * imalloc space. + * IM_REGION_OVERLAPS - Region overlaps an allocated region in imalloc space. + * IM_REGION_SUPERSET - Region is a superset of a region that is already + * allocated in imalloc space. */ -static int im_region_status(unsigned long v_addr, unsigned long size, +static int im_region_status(unsigned long v_addr, unsigned long size, struct vm_struct **vm) { struct vm_struct *tmp; - for (tmp = imlist; tmp; tmp = tmp->next) - if (v_addr < (unsigned long) tmp->addr + tmp->size) + for (tmp = imlist; tmp; tmp = tmp->next) + if (v_addr < (unsigned long) tmp->addr + tmp->size) break; - + if (tmp) { if (im_region_overlaps(v_addr, size, tmp)) return IM_REGION_OVERLAP; *vm = tmp; - if (im_region_is_subset(v_addr, size, tmp)) + if (im_region_is_subset(v_addr, size, tmp)) { + /* Return with tmp pointing to superset */ return IM_REGION_SUBSET; - else if (v_addr == (unsigned long) tmp->addr && - size == tmp->size) + } + if (im_region_is_superset(v_addr, size, tmp)) { + /* Return with tmp pointing to first subset */ + return IM_REGION_SUPERSET; + } + else if (v_addr == (unsigned long) tmp->addr && + size == tmp->size) { + /* Return with tmp pointing to exact region */ return IM_REGION_EXISTS; + } } *vm = NULL; @@ -208,6 +235,10 @@ tmp = split_im_region(req_addr, size, tmp); break; case IM_REGION_EXISTS: + /* Return requested region */ + break; + case IM_REGION_SUPERSET: + /* Return first existing subset of requested region */ break; default: printk(KERN_ERR "%s() unexpected imalloc region status\n", diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c --- a/arch/ppc64/mm/init.c 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/mm/init.c 2004-10-18 14:56:33 -07:00 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -62,8 +63,6 @@ #include #include - -struct mmu_context_queue_t mmu_context_queue; int mem_init_done; unsigned long ioremap_bot = IMALLOC_BASE; static unsigned long phbs_io_bot = PHBS_IO_BASE; @@ -85,7 +84,6 @@ /* info on what we think the IO hole is */ unsigned long io_hole_start; unsigned long io_hole_size; -unsigned long top_of_ram; void show_mem(void) { @@ -118,18 +116,18 @@ #ifdef CONFIG_PPC_ISERIES -void *ioremap(unsigned long addr, unsigned long size) +void __iomem *ioremap(unsigned long addr, unsigned long size) { - return (void *)addr; + return (void __iomem *)addr; } -extern void *__ioremap(unsigned long addr, unsigned long size, +extern void __iomem *__ioremap(unsigned long addr, unsigned long size, unsigned long flags) { - return (void *)addr; + return (void __iomem *)addr; } -void iounmap(void *addr) +void iounmap(volatile void __iomem *addr) { return; } @@ -183,7 +181,7 @@ } -static void * __ioremap_com(unsigned long addr, unsigned long pa, +static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa, unsigned long ea, unsigned long size, unsigned long flags) { @@ -198,20 +196,17 @@ map_io_page(ea+i, pa+i, flags); } - return (void *) (ea + (addr & ~PAGE_MASK)); + return (void __iomem *) (ea + (addr & ~PAGE_MASK)); } -void * +void __iomem * ioremap(unsigned long addr, unsigned long size) { - void *ret = __ioremap(addr, size, _PAGE_NO_CACHE); - if(mem_init_done) - return eeh_ioremap(addr, ret); /* may remap the addr */ - return ret; + return __ioremap(addr, size, _PAGE_NO_CACHE); } -void * +void __iomem * __ioremap(unsigned long addr, unsigned long size, unsigned long flags) { unsigned long pa, ea; @@ -354,19 +349,18 @@ * * XXX what about calls before mem_init_done (ie python_countermeasures()) */ -void iounmap(void *addr) +void iounmap(volatile void __iomem *token) { unsigned long address, start, end, size; struct mm_struct *mm; pgd_t *dir; + void *addr; if (!mem_init_done) { return; } - /* addr could be in EEH or IO region, map it to IO region regardless. - */ - addr = (void *) (IO_TOKEN_TO_ADDR(addr) & PAGE_MASK); + addr = (void *) ((unsigned long __force) token & PAGE_MASK); if ((size = im_free(addr)) == 0) { return; @@ -392,27 +386,55 @@ return; } -int iounmap_explicit(void *addr, unsigned long size) +static int iounmap_subset_regions(unsigned long addr, unsigned long size) { struct vm_struct *area; + + /* Check whether subsets of this region exist */ + area = im_get_area(addr, size, IM_REGION_SUPERSET); + if (area == NULL) + return 1; + + while (area) { + iounmap((void __iomem *) area->addr); + area = im_get_area(addr, size, + IM_REGION_SUPERSET); + } + + return 0; +} + +int iounmap_explicit(volatile void __iomem *start, unsigned long size) +{ + struct vm_struct *area; + unsigned long addr; + int rc; - /* addr could be in EEH or IO region, map it to IO region regardless. - */ - addr = (void *) (IO_TOKEN_TO_ADDR(addr) & PAGE_MASK); + addr = (unsigned long __force) start & PAGE_MASK; /* Verify that the region either exists or is a subset of an existing * region. In the latter case, split the parent region to create * the exact region */ - area = im_get_area((unsigned long) addr, size, + area = im_get_area(addr, size, IM_REGION_EXISTS | IM_REGION_SUBSET); if (area == NULL) { - printk(KERN_ERR "%s() cannot unmap nonexistent range 0x%lx\n", - __FUNCTION__, (unsigned long) addr); - return 1; + /* Determine whether subset regions exist. If so, unmap */ + rc = iounmap_subset_regions(addr, size); + if (rc) { + printk(KERN_ERR + "%s() cannot unmap nonexistent range 0x%lx\n", + __FUNCTION__, addr); + return 1; + } + } else { + iounmap((void __iomem *) area->addr); } - + /* + * FIXME! This can't be right: iounmap(area->addr); + * Maybe it should be "iounmap(area);" + */ return 0; } @@ -447,41 +469,81 @@ } #endif +static spinlock_t mmu_context_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_IDR(mmu_context_idr); + +int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + int index; + int err; + +again: + if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&mmu_context_lock); + err = idr_get_new(&mmu_context_idr, NULL, &index); + spin_unlock(&mmu_context_lock); + + if (err == -EAGAIN) + goto again; + else if (err) + return err; + + if (index > MAX_CONTEXT) { + idr_remove(&mmu_context_idr, index); + return -ENOMEM; + } + + mm->context.id = index; + + return 0; +} + +void destroy_context(struct mm_struct *mm) +{ + spin_lock(&mmu_context_lock); + idr_remove(&mmu_context_idr, mm->context.id); + spin_unlock(&mmu_context_lock); + + mm->context.id = NO_CONTEXT; +} + +static int __init mmu_context_init(void) +{ + int index; + + /* Reserve the first (invalid) context*/ + idr_pre_get(&mmu_context_idr, GFP_KERNEL); + idr_get_new(&mmu_context_idr, NULL, &index); + BUG_ON(0 != index); + + return 0; +} +arch_initcall(mmu_context_init); + /* * Do very early mm setup. */ void __init mm_init_ppc64(void) { +#ifndef CONFIG_PPC_ISERIES unsigned long i; +#endif ppc64_boot_msg(0x100, "MM Init"); - /* Reserve all contexts < FIRST_USER_CONTEXT for kernel use. - * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT) - * are stored on a stack/queue for easy allocation and deallocation. - */ - mmu_context_queue.lock = SPIN_LOCK_UNLOCKED; - mmu_context_queue.head = 0; - mmu_context_queue.tail = NUM_USER_CONTEXT-1; - mmu_context_queue.size = NUM_USER_CONTEXT; - for (i = 0; i < NUM_USER_CONTEXT; i++) - mmu_context_queue.elements[i] = i + FIRST_USER_CONTEXT; - /* This is the story of the IO hole... please, keep seated, * unfortunately, we are out of oxygen masks at the moment. * So we need some rough way to tell where your big IO hole * is. On pmac, it's between 2G and 4G, on POWER3, it's around * that area as well, on POWER4 we don't have one, etc... - * We need that to implement something approx. decent for - * page_is_ram() so that /dev/mem doesn't map cacheable IO space - * when XFree resquest some IO regions witout using O_SYNC, we - * also need that as a "hint" when sizing the TCE table on POWER3 + * We need that as a "hint" when sizing the TCE table on POWER3 * So far, the simplest way that seem work well enough for us it * to just assume that the first discontinuity in our physical * RAM layout is the IO hole. That may not be correct in the future * (and isn't on iSeries but then we don't care ;) */ - top_of_ram = lmb_end_of_DRAM(); #ifndef CONFIG_PPC_ISERIES for (i = 1; i < lmb.memory.cnt; i++) { @@ -504,22 +566,32 @@ ppc64_boot_msg(0x100, "MM Init Done"); } - /* * This is called by /dev/mem to know if a given address has to * be mapped non-cacheable or not */ -int page_is_ram(unsigned long physaddr) +int page_is_ram(unsigned long pfn) { -#ifdef CONFIG_PPC_ISERIES - return 1; + int i; + unsigned long paddr = (pfn << PAGE_SHIFT); + + for (i=0; i < lmb.memory.cnt; i++) { + unsigned long base; + +#ifdef CONFIG_MSCHUNKS + base = lmb.memory.region[i].physbase; +#else + base = lmb.memory.region[i].base; #endif - if (physaddr >= top_of_ram) - return 0; - return io_hole_start == 0 || physaddr < io_hole_start || - physaddr >= (io_hole_start + io_hole_size); -} + if ((paddr >= base) && + (paddr < (base + lmb.memory.region[i].size))) { + return 1; + } + } + return 0; +} +EXPORT_SYMBOL(page_is_ram); /* * Initialize the bootmem system and give it all the memory we @@ -573,6 +645,7 @@ unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; unsigned long total_ram = lmb_phys_mem_size(); + unsigned long top_of_ram = lmb_end_of_DRAM(); printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", top_of_ram, total_ram); @@ -587,7 +660,7 @@ zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT; - free_area_init_node(0, &contig_page_data, NULL, zones_size, + free_area_init_node(0, &contig_page_data, zones_size, __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); mem_map = contig_page_data.node_mem_map; } @@ -622,59 +695,53 @@ void __init mem_init(void) { -#ifndef CONFIG_DISCONTIGMEM - unsigned long addr; +#ifdef CONFIG_DISCONTIGMEM + int nid; #endif - int codepages = 0; - int datapages = 0; - int initpages = 0; + pg_data_t *pgdat; + unsigned long i; + struct page *page; + unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; num_physpages = max_low_pfn; /* RAM is assumed contiguous */ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); #ifdef CONFIG_DISCONTIGMEM -{ - int nid; - for (nid = 0; nid < numnodes; nid++) { - if (node_data[nid].node_spanned_pages != 0) { + if (NODE_DATA(nid)->node_spanned_pages != 0) { printk("freeing bootmem node %x\n", nid); totalram_pages += free_all_bootmem_node(NODE_DATA(nid)); } } - - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", - (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), - codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), - initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM())); -} #else max_mapnr = num_physpages; - totalram_pages += free_all_bootmem(); +#endif - for (addr = KERNELBASE; addr < (unsigned long)__va(lmb_end_of_DRAM()); - addr += PAGE_SIZE) { - if (!PageReserved(virt_to_page(addr))) - continue; - if (addr < (unsigned long)_etext) - codepages++; - - else if (addr >= (unsigned long)__init_begin - && addr < (unsigned long)__init_end) - initpages++; - else if (addr < klimit) - datapages++; + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { + page = pgdat->node_mem_map + i; + if (PageReserved(page)) + reservedpages++; + } } - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", - (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), - codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), - initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM())); -#endif + codesize = (unsigned long)&_etext - (unsigned long)&_stext; + initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; + datasize = (unsigned long)&_edata - (unsigned long)&__init_end; + bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; + + printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " + "%luk reserved, %luk data, %luk bss, %luk init)\n", + (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + bsssize >> 10, + initsize >> 10); + mem_init_done = 1; #ifdef CONFIG_PPC_ISERIES diff -Nru a/arch/ppc64/mm/mmap.c b/arch/ppc64/mm/mmap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/mm/mmap.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,86 @@ +/* + * linux/arch/ppc64/mm/mmap.c + * + * flexible mmap layout support + * + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Started by Ingo Molnar + */ + +#include +#include + +/* + * Top of mmap area (just below the process stack). + * + * Leave an at least ~128 MB hole. + */ +#define MIN_GAP (128*1024*1024) +#define MAX_GAP (TASK_SIZE/6*5) + +static inline unsigned long mmap_base(void) +{ + unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur; + + if (gap < MIN_GAP) + gap = MIN_GAP; + else if (gap > MAX_GAP) + gap = MAX_GAP; + + return TASK_SIZE - (gap & PAGE_MASK); +} + +static inline int mmap_is_legacy(void) +{ + /* + * Force standard allocation for 64 bit programs. + */ + if (!test_thread_flag(TIF_32BIT)) + return 1; + + if (current->personality & ADDR_COMPAT_LAYOUT) + return 1; + + if (current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) + return 1; + + return sysctl_legacy_va_layout; +} + +/* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: + */ +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + /* + * Fall back to the standard layout if the personality + * bit is set, or if the expected stack growth is unlimited: + */ + if (mmap_is_legacy()) { + mm->mmap_base = TASK_UNMAPPED_BASE; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; + } else { + mm->mmap_base = mmap_base(); + mm->get_unmapped_area = arch_get_unmapped_area_topdown; + mm->unmap_area = arch_unmap_area_topdown; + } +} diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c --- a/arch/ppc64/mm/numa.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc64/mm/numa.c 2004-10-18 14:56:48 -07:00 @@ -18,11 +18,10 @@ #include #include -#if 1 -#define dbg(args...) printk(KERN_INFO args) -#else -#define dbg(args...) -#endif +static int numa_enabled = 1; + +static int numa_debug; +#define dbg(args...) if (numa_debug) { printk(KERN_INFO args); } #ifdef DEBUG_NUMA #define ARRAY_INITIALISER -1 @@ -36,10 +35,19 @@ cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; int nr_cpus_in_node[MAX_NUMNODES] = { [0 ... (MAX_NUMNODES -1)] = 0}; -struct pglist_data node_data[MAX_NUMNODES]; -bootmem_data_t plat_node_bdata[MAX_NUMNODES]; +struct pglist_data *node_data[MAX_NUMNODES]; +bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES]; static unsigned long node0_io_hole_size; +/* + * We need somewhere to store start/span for each node until we have + * allocated the real node_data structures. + */ +static struct { + unsigned long node_start_pfn; + unsigned long node_spanned_pages; +} init_node_data[MAX_NUMNODES] __initdata; + EXPORT_SYMBOL(node_data); EXPORT_SYMBOL(numa_cpu_lookup_table); EXPORT_SYMBOL(numa_memory_lookup_table); @@ -48,7 +56,6 @@ static inline void map_cpu_to_node(int cpu, int node) { - dbg("cpu %d maps to domain %d\n", cpu, node); numa_cpu_lookup_table[cpu] = node; if (!(cpu_isset(cpu, numa_cpumask_lookup_table[node]))) { cpu_set(cpu, numa_cpumask_lookup_table[node]); @@ -107,8 +114,8 @@ if (tmp && (tmp[0] >= depth)) { numa_domain = tmp[depth]; } else { - printk(KERN_ERR "WARNING: no NUMA information for " - "%s\n", device->full_name); + dbg("WARNING: no NUMA information for %s\n", + device->full_name); numa_domain = 0; } return numa_domain; @@ -137,11 +144,8 @@ rtas_root = of_find_node_by_path("/rtas"); - if (!rtas_root) { - printk(KERN_ERR "WARNING: %s() could not find rtas root\n", - __FUNCTION__); + if (!rtas_root) return -1; - } /* * this property is 2 32-bit integers, each representing a level of @@ -155,8 +159,8 @@ if ((len >= 1) && ref_points) { depth = ref_points[1]; } else { - printk(KERN_ERR "WARNING: could not find NUMA " - "associativity reference point\n"); + dbg("WARNING: could not find NUMA " + "associativity reference point\n"); depth = -1; } of_node_put(rtas_root); @@ -187,20 +191,21 @@ long entries = lmb_end_of_DRAM() >> MEMORY_INCREMENT_SHIFT; unsigned long i; - if (strstr(saved_command_line, "numa=off")) { + if (numa_enabled == 0) { printk(KERN_WARNING "NUMA disabled by user\n"); return -1; } numa_memory_lookup_table = (char *)abs_to_virt(lmb_alloc(entries * sizeof(char), 1)); + memset(numa_memory_lookup_table, 0, entries * sizeof(char)); for (i = 0; i < entries ; i++) numa_memory_lookup_table[i] = ARRAY_INITIALISER; depth = find_min_common_depth(); - printk(KERN_INFO "NUMA associativity depth for CPU/Memory: %d\n", depth); + dbg("NUMA associativity depth for CPU/Memory: %d\n", depth); if (depth < 0) return depth; @@ -225,8 +230,7 @@ numa_domain = 0; } } else { - printk(KERN_ERR "WARNING: no NUMA information for " - "cpu %ld\n", i); + dbg("WARNING: no NUMA information for cpu %ld\n", i); numa_domain = 0; } @@ -281,22 +285,22 @@ * this simple case and complain if there is a gap in * memory */ - if (node_data[numa_domain].node_spanned_pages) { + if (init_node_data[numa_domain].node_spanned_pages) { unsigned long shouldstart = - node_data[numa_domain].node_start_pfn + - node_data[numa_domain].node_spanned_pages; + init_node_data[numa_domain].node_start_pfn + + init_node_data[numa_domain].node_spanned_pages; if (shouldstart != (start / PAGE_SIZE)) { - printk(KERN_ERR "Hole in node, disabling " - "region start %lx length %lx\n", - start, size); + printk(KERN_ERR "WARNING: Hole in node, " + "disabling region start %lx " + "length %lx\n", start, size); continue; } - node_data[numa_domain].node_spanned_pages += + init_node_data[numa_domain].node_spanned_pages += size / PAGE_SIZE; } else { - node_data[numa_domain].node_start_pfn = + init_node_data[numa_domain].node_start_pfn = start / PAGE_SIZE; - node_data[numa_domain].node_spanned_pages = + init_node_data[numa_domain].node_spanned_pages = size / PAGE_SIZE; } @@ -304,9 +308,6 @@ numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = numa_domain; - dbg("memory region %lx to %lx maps to domain %d\n", - start, start+size, numa_domain); - ranges--; if (ranges) goto new_range; @@ -332,6 +333,7 @@ long entries = top_of_ram >> MEMORY_INCREMENT_SHIFT; numa_memory_lookup_table = (char *)abs_to_virt(lmb_alloc(entries * sizeof(char), 1)); + memset(numa_memory_lookup_table, 0, entries * sizeof(char)); for (i = 0; i < entries ; i++) numa_memory_lookup_table[i] = ARRAY_INITIALISER; } @@ -341,8 +343,8 @@ node_set_online(0); - node_data[0].node_start_pfn = 0; - node_data[0].node_spanned_pages = lmb_end_of_DRAM() / PAGE_SIZE; + init_node_data[0].node_start_pfn = 0; + init_node_data[0].node_spanned_pages = lmb_end_of_DRAM() / PAGE_SIZE; for (i = 0 ; i < top_of_ram; i += MEMORY_INCREMENT) numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0; @@ -350,6 +352,108 @@ node0_io_hole_size = top_of_ram - total_ram; } +static void __init dump_numa_topology(void) +{ + unsigned int node; + unsigned int cpu, count; + + for (node = 0; node < MAX_NUMNODES; node++) { + if (!node_online(node)) + continue; + + printk(KERN_INFO "Node %d CPUs:", node); + + count = 0; + /* + * If we used a CPU iterator here we would miss printing + * the holes in the cpumap. + */ + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) { + if (count == 0) + printk(" %u", cpu); + ++count; + } else { + if (count > 1) + printk("-%u", cpu - 1); + count = 0; + } + } + + if (count > 1) + printk("-%u", NR_CPUS - 1); + printk("\n"); + } + + for (node = 0; node < MAX_NUMNODES; node++) { + unsigned long i; + + if (!node_online(node)) + continue; + + printk(KERN_INFO "Node %d Memory:", node); + + count = 0; + + for (i = 0; i < lmb_end_of_DRAM(); i += MEMORY_INCREMENT) { + if (numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] == node) { + if (count == 0) + printk(" 0x%lx", i); + ++count; + } else { + if (count > 0) + printk("-0x%lx", i); + count = 0; + } + } + + if (count > 0) + printk("-0x%lx", i); + printk("\n"); + } +} + +/* + * Allocate some memory, satisfying the lmb or bootmem allocator where + * required. nid is the preferred node and end is the physical address of + * the highest address in the node. + * + * Returns the physical address of the memory. + */ +static unsigned long careful_allocation(int nid, unsigned long size, + unsigned long align, unsigned long end) +{ + unsigned long ret = lmb_alloc_base(size, align, end); + + /* retry over all memory */ + if (!ret) + ret = lmb_alloc_base(size, align, lmb_end_of_DRAM()); + + if (!ret) + panic("numa.c: cannot allocate %lu bytes on node %d", + size, nid); + + /* + * If the memory came from a previously allocated node, we must + * retry with the bootmem allocator. + */ + if (pa_to_nid(ret) < nid) { + nid = pa_to_nid(ret); + ret = (unsigned long)__alloc_bootmem_node(NODE_DATA(nid), + size, align, 0); + + if (!ret) + panic("numa.c: cannot allocate %lu bytes on node %d", + size, nid); + + ret = virt_to_abs(ret); + + dbg("alloc_bootmem %lx %lx\n", ret, size); + } + + return ret; +} + void __init do_init_bootmem(void) { int nid; @@ -360,6 +464,8 @@ if (parse_numa_properties()) setup_nonnuma(); + else + dump_numa_topology(); for (nid = 0; nid < numnodes; nid++) { unsigned long start_paddr, end_paddr; @@ -367,24 +473,38 @@ unsigned long bootmem_paddr; unsigned long bootmap_pages; - if (node_data[nid].node_spanned_pages == 0) - continue; + start_paddr = init_node_data[nid].node_start_pfn * PAGE_SIZE; + end_paddr = start_paddr + (init_node_data[nid].node_spanned_pages * PAGE_SIZE); + + /* Allocate the node structure node local if possible */ + NODE_DATA(nid) = (struct pglist_data *)careful_allocation(nid, + sizeof(struct pglist_data), + SMP_CACHE_BYTES, end_paddr); + NODE_DATA(nid) = abs_to_virt(NODE_DATA(nid)); + memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); - start_paddr = node_data[nid].node_start_pfn * PAGE_SIZE; - end_paddr = start_paddr + - (node_data[nid].node_spanned_pages * PAGE_SIZE); - - dbg("node %d\n", nid); - dbg("start_paddr = %lx\n", start_paddr); - dbg("end_paddr = %lx\n", end_paddr); + dbg("node %d\n", nid); + dbg("NODE_DATA() = %p\n", NODE_DATA(nid)); NODE_DATA(nid)->bdata = &plat_node_bdata[nid]; + NODE_DATA(nid)->node_start_pfn = + init_node_data[nid].node_start_pfn; + NODE_DATA(nid)->node_spanned_pages = + init_node_data[nid].node_spanned_pages; + + if (init_node_data[nid].node_spanned_pages == 0) + continue; + + dbg("start_paddr = %lx\n", start_paddr); + dbg("end_paddr = %lx\n", end_paddr); bootmap_pages = bootmem_bootmap_pages((end_paddr - start_paddr) >> PAGE_SHIFT); - dbg("bootmap_pages = %lx\n", bootmap_pages); - bootmem_paddr = lmb_alloc_base(bootmap_pages << PAGE_SHIFT, + bootmem_paddr = careful_allocation(nid, + bootmap_pages << PAGE_SHIFT, PAGE_SIZE, end_paddr); + memset(abs_to_virt(bootmem_paddr), 0, + bootmap_pages << PAGE_SHIFT); dbg("bootmap_paddr = %lx\n", bootmem_paddr); init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT, @@ -442,7 +562,6 @@ { unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; - struct page *node_mem_map; int nid; memset(zones_size, 0, sizeof(zones_size)); @@ -463,17 +582,22 @@ dbg("free_area_init node %d %lx %lx (hole: %lx)\n", nid, zones_size[ZONE_DMA], start_pfn, zholes_size[ZONE_DMA]); - /* - * Give this empty node a dummy struct page to avoid - * us from trying to allocate a node local mem_map - * in free_area_init_node (which will fail). - */ - if (!node_data[nid].node_spanned_pages) - node_mem_map = alloc_bootmem(sizeof(struct page)); - else - node_mem_map = NULL; - - free_area_init_node(nid, NODE_DATA(nid), node_mem_map, - zones_size, start_pfn, zholes_size); + free_area_init_node(nid, NODE_DATA(nid), zones_size, + start_pfn, zholes_size); } } + +static int __init early_numa(char *p) +{ + if (!p) + return 0; + + if (strstr(p, "off")) + numa_enabled = 0; + + if (strstr(p, "debug")) + numa_debug = 1; + + return 0; +} +early_param("numa", early_numa); diff -Nru a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c --- a/arch/ppc64/mm/slb.c 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/mm/slb.c 2004-10-18 14:56:32 -07:00 @@ -24,32 +24,55 @@ extern void slb_allocate(unsigned long ea); +static inline unsigned long mk_esid_data(unsigned long ea, unsigned long slot) +{ + return (ea & ESID_MASK) | SLB_ESID_V | slot; +} + +static inline unsigned long mk_vsid_data(unsigned long ea, unsigned long flags) +{ + return (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | flags; +} + static inline void create_slbe(unsigned long ea, unsigned long vsid, unsigned long flags, unsigned long entry) { - ea = (ea & ESID_MASK) | SLB_ESID_V | entry; - vsid = (vsid << SLB_VSID_SHIFT) | flags; asm volatile("slbmte %0,%1" : - : "r" (vsid), "r" (ea) + : "r" (mk_vsid_data(ea, flags)), + "r" (mk_esid_data(ea, entry)) : "memory" ); } -static void slb_add_bolted(void) +static void slb_flush_and_rebolt(void) { -#ifndef CONFIG_PPC_ISERIES - WARN_ON(!irqs_disabled()); - /* If you change this make sure you change SLB_NUM_BOLTED - * appropriately too */ + * appropriately too. */ + unsigned long ksp_flags = SLB_VSID_KERNEL; + unsigned long ksp_esid_data; - /* Slot 1 - first VMALLOC segment - * Since modules end up there it gets hit very heavily. - */ - create_slbe(VMALLOCBASE, get_kernel_vsid(VMALLOCBASE), - SLB_VSID_KERNEL, 1); + WARN_ON(!irqs_disabled()); - asm volatile("isync":::"memory"); -#endif + if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + ksp_flags |= SLB_VSID_L; + + ksp_esid_data = mk_esid_data(get_paca()->kstack, 2); + if ((ksp_esid_data & ESID_MASK) == KERNELBASE) + ksp_esid_data &= ~SLB_ESID_V; + + /* We need to do this all in asm, so we're sure we don't touch + * the stack between the slbia and rebolting it. */ + asm volatile("isync\n" + "slbia\n" + /* Slot 1 - first VMALLOC segment */ + "slbmte %0,%1\n" + /* Slot 2 - kernel stack */ + "slbmte %2,%3\n" + "isync" + :: "r"(mk_vsid_data(VMALLOCBASE, SLB_VSID_KERNEL)), + "r"(mk_esid_data(VMALLOCBASE, 1)), + "r"(mk_vsid_data(ksp_esid_data, ksp_flags)), + "r"(ksp_esid_data) + : "memory"); } /* Flush all user entries from the segment table of the current processor. */ @@ -71,8 +94,7 @@ } asm volatile("isync" : : : "memory"); } else { - asm volatile("isync; slbia; isync" : : : "memory"); - slb_add_bolted(); + slb_flush_and_rebolt(); } /* Workaround POWER5 < DD2.1 issue */ @@ -115,22 +137,27 @@ void slb_initialize(void) { -#ifdef CONFIG_PPC_ISERIES - asm volatile("isync; slbia; isync":::"memory"); -#else + /* On iSeries the bolted entries have already been set up by + * the hypervisor from the lparMap data in head.S */ +#ifndef CONFIG_PPC_ISERIES unsigned long flags = SLB_VSID_KERNEL; - /* Invalidate the entire SLB (even slot 0) & all the ERATS */ - if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) - flags |= SLB_VSID_L; + /* Invalidate the entire SLB (even slot 0) & all the ERATS */ + if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + flags |= SLB_VSID_L; - asm volatile("isync":::"memory"); - asm volatile("slbmte %0,%0"::"r" (0) : "memory"); + asm volatile("isync":::"memory"); + asm volatile("slbmte %0,%0"::"r" (0) : "memory"); asm volatile("isync; slbia; isync":::"memory"); - create_slbe(KERNELBASE, get_kernel_vsid(KERNELBASE), - flags, 0); - + create_slbe(KERNELBASE, get_kernel_vsid(KERNELBASE), flags, 0); + create_slbe(VMALLOCBASE, get_kernel_vsid(KERNELBASE), + SLB_VSID_KERNEL, 1); + /* We don't bolt the stack for the time being - we're in boot, + * so the stack is in the bolted segment. By the time it goes + * elsewhere, we'll call _switch() which will bolt in the new + * one. */ + asm volatile("isync":::"memory"); #endif - slb_add_bolted(); + get_paca()->stab_rr = SLB_NUM_BOLTED; } diff -Nru a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S --- a/arch/ppc64/mm/slb_low.S 2004-10-18 14:56:33 -07:00 +++ b/arch/ppc64/mm/slb_low.S 2004-10-18 14:56:33 -07:00 @@ -37,8 +37,21 @@ * a free slot first but that took too long. Unfortunately we * dont have any LRU information to help us choose a slot. */ +#ifdef CONFIG_PPC_ISERIES + /* + * On iSeries, the "bolted" stack segment can be cast out on + * shared processor switch so we need to check for a miss on + * it and restore it to the right slot. + */ + ld r9,PACAKSAVE(r13) + clrrdi r9,r9,28 + clrrdi r11,r3,28 + li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ + cmpld r9,r11 + beq 3f +#endif /* CONFIG_PPC_ISERIES */ + ld r10,PACASTABRR(r13) -3: addi r10,r10,1 /* use a cpu feature mask if we ever change our slb size */ cmpldi r10,SLB_NUM_ENTRIES @@ -46,55 +59,28 @@ blt+ 4f li r10,SLB_NUM_BOLTED - /* - * Never cast out the segment for our kernel stack. Since we - * dont invalidate the ERAT we could have a valid translation - * for the kernel stack during the first part of exception exit - * which gets invalidated due to a tlbie from another cpu at a - * non recoverable point (after setting srr0/1) - Anton - */ -4: slbmfee r11,r10 - srdi r11,r11,27 - /* - * Use paca->ksave as the value of the kernel stack pointer, - * because this is valid at all times. - * The >> 27 (rather than >> 28) is so that the LSB is the - * valid bit - this way we check valid and ESID in one compare. - * In order to completely close the tiny race in the context - * switch (between updating r1 and updating paca->ksave), - * we check against both r1 and paca->ksave. - */ - srdi r9,r1,27 - ori r9,r9,1 /* mangle SP for later compare */ - cmpd r11,r9 - beq- 3b - ld r9,PACAKSAVE(r13) - srdi r9,r9,27 - ori r9,r9,1 - cmpd r11,r9 - beq- 3b - +4: std r10,PACASTABRR(r13) - +3: /* r3 = faulting address, r10 = entry */ srdi r9,r3,60 /* get region */ srdi r3,r3,28 /* get esid */ cmpldi cr7,r9,0xc /* cmp KERNELBASE for later use */ - /* r9 = region, r3 = esid, cr7 = <>KERNELBASE */ - - rldicr. r11,r3,32,16 - bne- 8f /* invalid ea bits set */ - addi r11,r9,-1 - cmpldi r11,0xb - blt- 8f /* invalid region */ + rldimi r10,r3,28,0 /* r10= ESID<<28 | entry */ + oris r10,r10,SLB_ESID_V@h /* r10 |= SLB_ESID_V */ - /* r9 = region, r3 = esid, r10 = entry, cr7 = <>KERNELBASE */ + /* r3 = esid, r10 = esid_data, cr7 = <>KERNELBASE */ blt cr7,0f /* user or kernel? */ - /* kernel address */ + /* kernel address: proto-VSID = ESID */ + /* WARNING - MAGIC: we don't use the VSID 0xfffffffff, but + * this code will generate the protoVSID 0xfffffffff for the + * top segment. That's ok, the scramble below will translate + * it to VSID 0, which is reserved as a bad VSID - one which + * will never have any pages in it. */ li r11,SLB_VSID_KERNEL BEGIN_FTR_SECTION bne cr7,9f @@ -102,8 +88,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE) b 9f -0: /* user address */ +0: /* user address: proto-VSID = context<<15 | ESID */ li r11,SLB_VSID_USER + + srdi. r9,r3,13 + bne- 8f /* invalid ea bits set */ + #ifdef CONFIG_HUGETLB_PAGE BEGIN_FTR_SECTION /* check against the hugepage ranges */ @@ -125,33 +115,18 @@ #endif /* CONFIG_HUGETLB_PAGE */ 6: ld r9,PACACONTEXTID(r13) + rldimi r3,r9,USER_ESID_BITS,0 -9: /* r9 = "context", r3 = esid, r11 = flags, r10 = entry */ - - rldimi r9,r3,15,0 /* r9= VSID ordinal */ - -7: rldimi r10,r3,28,0 /* r10= ESID<<28 | entry */ - oris r10,r10,SLB_ESID_V@h /* r10 |= SLB_ESID_V */ - - /* r9 = ordinal, r3 = esid, r11 = flags, r10 = esid_data */ - - li r3,VSID_RANDOMIZER@higher - sldi r3,r3,32 - oris r3,r3,VSID_RANDOMIZER@h - ori r3,r3,VSID_RANDOMIZER@l - - mulld r9,r3,r9 /* r9 = ordinal * VSID_RANDOMIZER */ - clrldi r9,r9,28 /* r9 &= VSID_MASK */ - sldi r9,r9,SLB_VSID_SHIFT /* r9 <<= SLB_VSID_SHIFT */ - or r9,r9,r11 /* r9 |= flags */ +9: /* r3 = protovsid, r11 = flags, r10 = esid_data, cr7 = <>KERNELBASE */ + ASM_VSID_SCRAMBLE(r3,r9) - /* r9 = vsid_data, r10 = esid_data, cr7 = <>KERNELBASE */ + rldimi r11,r3,SLB_VSID_SHIFT,16 /* combine VSID and flags */ /* * No need for an isync before or after this slbmte. The exception * we enter with and the rfid we exit with are context synchronizing. */ - slbmte r9,r10 + slbmte r11,r10 bgelr cr7 /* we're done for kernel addresses */ @@ -174,6 +149,6 @@ blr 8: /* invalid EA */ - li r9,0 /* 0 VSID ordinal -> BAD_VSID */ + li r3,0 /* BAD_VSID */ li r11,SLB_VSID_USER /* flags don't much matter */ - b 7b + b 9b diff -Nru a/arch/ppc64/mm/stab.c b/arch/ppc64/mm/stab.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc64/mm/stab.c 2004-10-18 14:56:49 -07:00 @@ -0,0 +1,240 @@ +/* + * PowerPC64 Segment Translation Support. + * + * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com + * Copyright (c) 2001 Dave Engebretsen + * + * Copyright (C) 2002 Anton Blanchard , IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Both the segment table and SLB code uses the following cache */ +#define NR_STAB_CACHE_ENTRIES 8 +DEFINE_PER_CPU(long, stab_cache_ptr); +DEFINE_PER_CPU(long, stab_cache[NR_STAB_CACHE_ENTRIES]); + +/* + * Create a segment table entry for the given esid/vsid pair. + */ +static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) +{ + unsigned long esid_data, vsid_data; + unsigned long entry, group, old_esid, castout_entry, i; + unsigned int global_entry; + struct stab_entry *ste, *castout_ste; + unsigned long kernel_segment = (esid << SID_SHIFT) >= KERNELBASE; + + vsid_data = vsid << STE_VSID_SHIFT; + esid_data = esid << SID_SHIFT | STE_ESID_KP | STE_ESID_V; + if (! kernel_segment) + esid_data |= STE_ESID_KS; + + /* Search the primary group first. */ + global_entry = (esid & 0x1f) << 3; + ste = (struct stab_entry *)(stab | ((esid & 0x1f) << 7)); + + /* Find an empty entry, if one exists. */ + for (group = 0; group < 2; group++) { + for (entry = 0; entry < 8; entry++, ste++) { + if (!(ste->esid_data & STE_ESID_V)) { + ste->vsid_data = vsid_data; + asm volatile("eieio":::"memory"); + ste->esid_data = esid_data; + return (global_entry | entry); + } + } + /* Now search the secondary group. */ + global_entry = ((~esid) & 0x1f) << 3; + ste = (struct stab_entry *)(stab | (((~esid) & 0x1f) << 7)); + } + + /* + * Could not find empty entry, pick one with a round robin selection. + * Search all entries in the two groups. + */ + castout_entry = get_paca()->stab_rr; + for (i = 0; i < 16; i++) { + if (castout_entry < 8) { + global_entry = (esid & 0x1f) << 3; + ste = (struct stab_entry *)(stab | ((esid & 0x1f) << 7)); + castout_ste = ste + castout_entry; + } else { + global_entry = ((~esid) & 0x1f) << 3; + ste = (struct stab_entry *)(stab | (((~esid) & 0x1f) << 7)); + castout_ste = ste + (castout_entry - 8); + } + + /* Dont cast out the first kernel segment */ + if ((castout_ste->esid_data & ESID_MASK) != KERNELBASE) + break; + + castout_entry = (castout_entry + 1) & 0xf; + } + + get_paca()->stab_rr = (castout_entry + 1) & 0xf; + + /* Modify the old entry to the new value. */ + + /* Force previous translations to complete. DRENG */ + asm volatile("isync" : : : "memory"); + + old_esid = castout_ste->esid_data >> SID_SHIFT; + castout_ste->esid_data = 0; /* Invalidate old entry */ + + asm volatile("sync" : : : "memory"); /* Order update */ + + castout_ste->vsid_data = vsid_data; + asm volatile("eieio" : : : "memory"); /* Order update */ + castout_ste->esid_data = esid_data; + + asm volatile("slbie %0" : : "r" (old_esid << SID_SHIFT)); + /* Ensure completion of slbie */ + asm volatile("sync" : : : "memory"); + + return (global_entry | (castout_entry & 0x7)); +} + +/* + * Allocate a segment table entry for the given ea and mm + */ +static int __ste_allocate(unsigned long ea, struct mm_struct *mm) +{ + unsigned long vsid; + unsigned char stab_entry; + unsigned long offset; + + /* Kernel or user address? */ + if (ea >= KERNELBASE) { + vsid = get_kernel_vsid(ea); + } else { + if ((ea >= TASK_SIZE_USER64) || (! mm)) + return 1; + + vsid = get_vsid(mm->context.id, ea); + } + + stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid); + + if (ea < KERNELBASE) { + offset = __get_cpu_var(stab_cache_ptr); + if (offset < NR_STAB_CACHE_ENTRIES) + __get_cpu_var(stab_cache[offset++]) = stab_entry; + else + offset = NR_STAB_CACHE_ENTRIES+1; + __get_cpu_var(stab_cache_ptr) = offset; + + /* Order update */ + asm volatile("sync":::"memory"); + } + + return 0; +} + +int ste_allocate(unsigned long ea) +{ + return __ste_allocate(ea, current->mm); +} + +/* + * Do the segment table work for a context switch: flush all user + * entries from the table, then preload some probably useful entries + * for the new task + */ +void switch_stab(struct task_struct *tsk, struct mm_struct *mm) +{ + struct stab_entry *stab = (struct stab_entry *) get_paca()->stab_addr; + struct stab_entry *ste; + unsigned long offset = __get_cpu_var(stab_cache_ptr); + unsigned long pc = KSTK_EIP(tsk); + unsigned long stack = KSTK_ESP(tsk); + unsigned long unmapped_base; + + /* Force previous translations to complete. DRENG */ + asm volatile("isync" : : : "memory"); + + if (offset <= NR_STAB_CACHE_ENTRIES) { + int i; + + for (i = 0; i < offset; i++) { + ste = stab + __get_cpu_var(stab_cache[i]); + ste->esid_data = 0; /* invalidate entry */ + } + } else { + unsigned long entry; + + /* Invalidate all entries. */ + ste = stab; + + /* Never flush the first entry. */ + ste += 1; + for (entry = 1; + entry < (PAGE_SIZE / sizeof(struct stab_entry)); + entry++, ste++) { + unsigned long ea; + ea = ste->esid_data & ESID_MASK; + if (ea < KERNELBASE) { + ste->esid_data = 0; + } + } + } + + asm volatile("sync; slbia; sync":::"memory"); + + __get_cpu_var(stab_cache_ptr) = 0; + + /* Now preload some entries for the new task */ + if (test_tsk_thread_flag(tsk, TIF_32BIT)) + unmapped_base = TASK_UNMAPPED_BASE_USER32; + else + unmapped_base = TASK_UNMAPPED_BASE_USER64; + + __ste_allocate(pc, mm); + + if (GET_ESID(pc) == GET_ESID(stack)) + return; + + __ste_allocate(stack, mm); + + if ((GET_ESID(pc) == GET_ESID(unmapped_base)) + || (GET_ESID(stack) == GET_ESID(unmapped_base))) + return; + + __ste_allocate(unmapped_base, mm); + + /* Order update */ + asm volatile("sync" : : : "memory"); +} + +extern void slb_initialize(void); + +/* + * Build an entry for the base kernel segment and put it into + * the segment table or SLB. All other segment table or SLB + * entries are faulted in. + */ +void stab_initialize(unsigned long stab) +{ + unsigned long vsid = get_kernel_vsid(KERNELBASE); + + if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) { + slb_initialize(); + } else { + asm volatile("isync; slbia; isync":::"memory"); + make_ste(stab, GET_ESID(KERNELBASE), vsid); + + /* Order update */ + asm volatile("sync":::"memory"); + } +} diff -Nru a/arch/ppc64/mm/tlb.c b/arch/ppc64/mm/tlb.c --- a/arch/ppc64/mm/tlb.c 2004-10-18 14:56:31 -07:00 +++ b/arch/ppc64/mm/tlb.c 2004-10-18 14:56:31 -07:00 @@ -26,10 +26,10 @@ #include #include #include +#include #include #include #include -#include #include DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch); diff -Nru a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c --- a/arch/ppc64/oprofile/common.c 2004-10-18 14:57:04 -07:00 +++ b/arch/ppc64/oprofile/common.c 2004-10-18 14:57:04 -07:00 @@ -52,17 +52,10 @@ static void op_ppc64_shutdown(void) { - /* - * We need to be sure we have cleared all pending exceptions before - * removing the interrupt handler. For the moment we play it safe and - * leave it in - */ -#if 0 mb(); /* Remove our interrupt handler. We may be removing this module. */ perf_irq = save_perf_irq; -#endif } static void op_ppc64_cpu_start(void *dummy) @@ -90,6 +83,14 @@ { int i; + /* + * There is one mmcr0, mmcr1 and mmcra for setting the events for + * all of the counters. + */ + oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); + oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); + oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); + for (i = 0; i < model->num_counters; ++i) { struct dentry *dir; char buf[3]; @@ -112,6 +113,10 @@ oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); + /* Default to tracing both kernel and user */ + sys.enable_kernel = 1; + sys.enable_user = 1; + return 0; } @@ -128,7 +133,7 @@ { unsigned int pvr; - pvr = _get_PVR(); + pvr = mfspr(SPRN_PVR); switch (PVR_VER(pvr)) { case PV_630: diff -Nru a/arch/ppc64/oprofile/op_impl.h b/arch/ppc64/oprofile/op_impl.h --- a/arch/ppc64/oprofile/op_impl.h 2004-10-18 14:56:32 -07:00 +++ b/arch/ppc64/oprofile/op_impl.h 2004-10-18 14:56:32 -07:00 @@ -19,6 +19,12 @@ /* freeze counters. set to 1 on a perfmon exception */ #define MMCR0_FC (1UL << (31 - 0)) +/* freeze in supervisor state */ +#define MMCR0_KERNEL_DISABLE (1UL << (31 - 1)) + +/* freeze in problem state */ +#define MMCR0_PROBLEM_DISABLE (1UL << (31 - 2)) + /* freeze counters while MSR mark = 1 */ #define MMCR0_FCM1 (1UL << (31 - 3)) @@ -28,15 +34,15 @@ /* freeze counters on enabled condition or event */ #define MMCR0_FCECE (1UL << (31 - 6)) -/* performance monitor alert has occurred, set to 0 after handling exception */ -#define MMCR0_PMAO (1UL << (31 - 24)) - /* PMC1 count enable*/ #define MMCR0_PMC1INTCONTROL (1UL << (31 - 16)) /* PMCn count enable*/ #define MMCR0_PMCNINTCONTROL (1UL << (31 - 17)) +/* performance monitor alert has occurred, set to 0 after handling exception */ +#define MMCR0_PMAO (1UL << (31 - 24)) + /* state of MSR HV when SIAR set */ #define MMCRA_SIHV (1UL << (63 - 35)) @@ -60,6 +66,9 @@ /* System-wide configuration as set via oprofilefs. */ struct op_system_config { + unsigned long mmcr0; + unsigned long mmcr1; + unsigned long mmcra; unsigned long enable_kernel; unsigned long enable_user; }; diff -Nru a/arch/ppc64/oprofile/op_model_power4.c b/arch/ppc64/oprofile/op_model_power4.c --- a/arch/ppc64/oprofile/op_model_power4.c 2004-10-18 14:56:48 -07:00 +++ b/arch/ppc64/oprofile/op_model_power4.c 2004-10-18 14:56:48 -07:00 @@ -17,7 +17,7 @@ #include #include -#define dbg(args...) printk(args) +#define dbg(args...) #include "op_impl.h" @@ -27,6 +27,11 @@ static int oprofile_running; static int mmcra_has_sihv; +/* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */ +static u32 mmcr0_val; +static u64 mmcr1_val; +static u32 mmcra_val; + static void power4_reg_setup(struct op_counter_config *ctr, struct op_system_config *sys, int num_ctrs) @@ -45,18 +50,36 @@ if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA_SIHV) mmcra_has_sihv = 1; + /* + * The performance counter event settings are given in the mmcr0, + * mmcr1 and mmcra values passed from the user in the + * op_system_config structure (sys variable). + */ + mmcr0_val = sys->mmcr0; + mmcr1_val = sys->mmcr1; + mmcra_val = sys->mmcra; + for (i = 0; i < num_counters; ++i) reset_value[i] = 0x80000000UL - ctr[i].count; - /* XXX setup user and kernel profiling */ + /* setup user and kernel profiling */ + if (sys->enable_kernel) + mmcr0_val &= ~MMCR0_KERNEL_DISABLE; + else + mmcr0_val |= MMCR0_KERNEL_DISABLE; + + if (sys->enable_user) + mmcr0_val &= ~MMCR0_PROBLEM_DISABLE; + else + mmcr0_val |= MMCR0_PROBLEM_DISABLE; } extern void ppc64_enable_pmcs(void); static void power4_cpu_setup(void *unused) { - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - unsigned long mmcra = mfspr(SPRN_MMCRA); + unsigned int mmcr0 = mmcr0_val; + unsigned long mmcra = mmcra_val; ppc64_enable_pmcs(); @@ -67,6 +90,8 @@ mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE; mmcr0 |= MMCR0_PMC1INTCONTROL|MMCR0_PMCNINTCONTROL; mtspr(SPRN_MMCR0, mmcr0); + + mtspr(SPRN_MMCR1, mmcr1_val); mmcra |= MMCRA_SAMPLE_ENABLE; mtspr(SPRN_MMCRA, mmcra); diff -Nru a/arch/ppc64/oprofile/op_model_rs64.c b/arch/ppc64/oprofile/op_model_rs64.c --- a/arch/ppc64/oprofile/op_model_rs64.c 2004-10-18 14:57:03 -07:00 +++ b/arch/ppc64/oprofile/op_model_rs64.c 2004-10-18 14:57:03 -07:00 @@ -15,14 +15,14 @@ #include #include -#define dbg(args...) printk(args) +#define dbg(args...) #include "op_impl.h" static void ctrl_write(unsigned int i, unsigned int val) { - unsigned int tmp; - unsigned long shift, mask; + unsigned int tmp = 0; + unsigned long shift = 0, mask = 0; dbg("ctrl_write %d %x\n", i, val); diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c --- a/arch/ppc64/xmon/xmon.c 2004-10-18 14:56:50 -07:00 +++ b/arch/ppc64/xmon/xmon.c 2004-10-18 14:56:50 -07:00 @@ -252,30 +252,28 @@ static inline void disable_surveillance(void) { -#ifndef CONFIG_PPC_ISERIES +#ifdef CONFIG_PPC_PSERIES /* Since this can't be a module, args should end up below 4GB. */ static struct rtas_args args; - if (systemcfg->platform & PLATFORM_PSERIES) { - /* - * At this point we have got all the cpus we can into - * xmon, so there is hopefully no other cpu calling RTAS - * at the moment, even though we don't take rtas.lock. - * If we did try to take rtas.lock there would be a - * real possibility of deadlock. - */ - args.token = rtas_token("set-indicator"); - if (args.token == RTAS_UNKNOWN_SERVICE) - return; - args.nargs = 3; - args.nret = 1; - args.rets = &args.args[3]; - args.args[0] = SURVEILLANCE_TOKEN; - args.args[1] = 0; - args.args[2] = 0; - enter_rtas(__pa(&args)); - } -#endif + /* + * At this point we have got all the cpus we can into + * xmon, so there is hopefully no other cpu calling RTAS + * at the moment, even though we don't take rtas.lock. + * If we did try to take rtas.lock there would be a + * real possibility of deadlock. + */ + args.token = rtas_token("set-indicator"); + if (args.token == RTAS_UNKNOWN_SERVICE) + return; + args.nargs = 3; + args.nret = 1; + args.rets = &args.args[3]; + args.args[0] = SURVEILLANCE_TOKEN; + args.args[1] = 0; + args.args[2] = 0; + enter_rtas(__pa(&args)); +#endif /* CONFIG_PPC_PSERIES */ } #ifdef CONFIG_SMP @@ -2059,7 +2057,7 @@ { int nr, dotted; unsigned long first_adr; - unsigned long inst, last_inst; + unsigned long inst, last_inst = 0; unsigned char val[4]; dotted = 0; diff -Nru a/arch/s390/Kconfig b/arch/s390/Kconfig --- a/arch/s390/Kconfig 2004-10-18 14:56:28 -07:00 +++ b/arch/s390/Kconfig 2004-10-18 14:56:28 -07:00 @@ -48,34 +48,6 @@ depends on ARCH_S390X = 'n' default y -choice - prompt "Processor type" - default MARCH_G5 - -config MARCH_G5 - bool "S/390 model G5 and G6" - depends on ARCH_S390_31 - help - Select this to build a 31 bit kernel that works - on all S/390 and zSeries machines. - -config MARCH_Z900 - bool "IBM eServer zSeries model z800 and z900" - help - Select this to optimize for zSeries machines. This - will enable some optimizations that are not available - on older 31 bit only CPUs. - -config MARCH_Z990 - bool "IBM eServer zSeries model z890 and z990" - help - Select this enable optimizations for model z890/z990. - This will be slightly faster but does not work on - older machines such as the z900. - -endchoice - - config SMP bool "Symmetric multi-processing support" ---help--- @@ -121,7 +93,7 @@ depends on MARCH_G5 help This option is required for IEEE compliant floating point arithmetic - on older S/390 machines. Say Y unless you know your machine doesn't + on older S/390 machines. Say Y unless you know your machine doesn't need this. config S390_SUPPORT @@ -150,13 +122,112 @@ This allows you to run 32-bit Linux/ELF binaries on your zSeries in 64 bit mode. Everybody wants this; say Y. +comment "Code generation options" + +choice + prompt "Processor type" + default MARCH_G5 + +config MARCH_G5 + bool "S/390 model G5 and G6" + depends on ARCH_S390_31 + help + Select this to build a 31 bit kernel that works + on all S/390 and zSeries machines. + +config MARCH_Z900 + bool "IBM eServer zSeries model z800 and z900" + help + Select this to optimize for zSeries machines. This + will enable some optimizations that are not available + on older 31 bit only CPUs. + +config MARCH_Z990 + bool "IBM eServer zSeries model z890 and z990" + help + Select this enable optimizations for model z890/z990. + This will be slightly faster but does not work on + older machines such as the z900. + +endchoice + +config PACK_STACK + bool "Pack kernel stack" + help + This option enables the compiler option -mkernel-backchain if it + is available. If the option is available the compiler supports + the new stack layout which dramatically reduces the minimum stack + frame size. With an old compiler a non-leaf function needs a + minimum of 96 bytes on 31 bit and 160 bytes on 64 bit. With + -mkernel-backchain the minimum size drops to 16 byte on 31 bit + and 24 byte on 64 bit. + + Say Y if you are unsure. + +config SMALL_STACK + bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb" + depends on PACK_STACK + help + If you say Y here and the compiler supports the -mkernel-backchain + option the kernel will use a smaller kernel stack size. For 31 bit + the reduced size is 4kb instead of 8kb and for 64 bit it is 8kb + instead of 16kb. This allows to run more thread on a system and + reduces the pressure on the memory management for higher order + page allocations. + + Say N if you are unsure. + + +config CHECK_STACK + bool "Detect kernel stack overflow" + help + This option enables the compiler option -mstack-guard and + -mstack-size if they are available. If the compiler supports them + it will emit additional code to each function prolog to trigger + an illegal operation if the kernel stack is about to overflow. + + Say N if you are unsure. + +config STACK_GUARD + int "Size of the guard area (128-1024)" + range 128 1024 + depends on CHECK_STACK + default "256" + help + This allows you to specify the size of the guard area at the lower + end of the kernel stack. If the kernel stack points into the guard + area on function entry an illegal operation is triggered. The size + needs to be a power of 2. Please keep in mind that the size of an + interrupt frame is 184 bytes for 31 bit and 328 bytes on 64 bit. + The minimum size for the stack guard should be 256 for 31 bit and + 512 for 64 bit. + +config WARN_STACK + bool "Emit compiler warnings for function with broken stack usage" + help + This option enables the compiler options -mwarn-framesize and + -mwarn-dynamicstack. If the compiler supports these options it + will generate warnings for function which either use alloca or + create a stack frame bigger then CONFIG_WARN_STACK_SIZE. + + Say N if you are unsure. + +config WARN_STACK_SIZE + int "Maximum frame size considered safe (128-2048)" + range 128 2048 + depends on WARN_STACK + default "256" + help + This allows you to specify the maximum frame size a function may + have without the compiler complaining about it. + comment "I/O subsystem configuration" config MACHCHK_WARNING bool "Process warning machine checks" help Select this option if you want the machine check handler on IBM S/390 or - zSeries to process warning machine checks (e.g. on power failures). + zSeries to process warning machine checks (e.g. on power failures). If unsure, say "Y". config QDIO @@ -388,64 +459,10 @@ source "arch/s390/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config KALLSYMS - bool "Load all symbols for debugging/kksymoops" - depends on DEBUG_KERNEL - help - Say Y here to let the kernel print out symbolic crash information and - symbolic stack backtraces. This increases the size of the kernel - somewhat, as all symbols have to be loaded into the kernel image. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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" - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -endmenu +source "arch/s390/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/s390/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,5 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +endmenu diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile --- a/arch/s390/Makefile 2004-10-18 14:56:17 -07:00 +++ b/arch/s390/Makefile 2004-10-18 14:56:17 -07:00 @@ -18,6 +18,7 @@ CFLAGS += -m31 AFLAGS += -m31 UTS_MACHINE := s390 +STACK_SIZE := 8192 endif ifdef CONFIG_ARCH_S390X @@ -26,16 +27,37 @@ CFLAGS += -m64 AFLAGS += -m64 UTS_MACHINE := s390x +STACK_SIZE := 16384 endif -cflags-$(CONFIG_MARCH_G5) += $(call check_gcc,-march=g5,) -cflags-$(CONFIG_MARCH_Z900) += $(call check_gcc,-march=z900,) -cflags-$(CONFIG_MARCH_Z990) += $(call check_gcc,-march=z990,) +cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5) +cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) +cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) -CFLAGS += $(cflags-y) -CFLAGS += $(call check_gcc,-finline-limit=10000,) +ifeq ($(call cc-option-yn,-mkernel-backchain),y) +cflags-$(CONFIG_PACK_STACK) += -mkernel-backchain -D__PACK_STACK +aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK +cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK +aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK +ifdef CONFIG_SMALL_STACK +STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) ) +endif +endif + +ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y) +cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE) +cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD) +endif + +ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y) +cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack +cflags-$(CONFIG_WARN_STACK) += -mwarn-framesize=$(CONFIG_WARN_STACK_SIZE) +endif + +CFLAGS += -mbackchain $(cflags-y) +CFLAGS += $(call cc-option,-finline-limit=10000) CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare -CFLAGS += -mbackchain +AFLAGS += $(aflags-y) OBJCOPYFLAGS := -O binary LDFLAGS_vmlinux := -e start diff -Nru a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c --- a/arch/s390/appldata/appldata_mem.c 2004-10-18 14:55:55 -07:00 +++ b/arch/s390/appldata/appldata_mem.c 2004-10-18 14:55:55 -07:00 @@ -102,8 +102,12 @@ */ static void appldata_get_mem_data(void *data) { - struct sysinfo val; - struct page_state ps; + /* + * don't put large structures on the stack, we are + * serialized through the appldata_ops_lock and can use static + */ + static struct sysinfo val; + static struct page_state ps; struct appldata_mem_data *mem_data; mem_data = data; diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig --- a/arch/s390/defconfig 2004-10-18 14:56:50 -07:00 +++ b/arch/s390/defconfig 2004-10-18 14:56:50 -07:00 @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3 +# Fri Oct 8 19:17:35 2004 # CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y @@ -15,6 +17,7 @@ # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set @@ -36,6 +39,8 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -56,15 +61,23 @@ # CONFIG_ARCH_S390X is not set # CONFIG_64BIT is not set CONFIG_ARCH_S390_31=y -CONFIG_MARCH_G5=y -# CONFIG_MARCH_Z900 is not set -# CONFIG_MARCH_Z990 is not set CONFIG_SMP=y CONFIG_NR_CPUS=32 # CONFIG_HOTPLUG_CPU is not set CONFIG_MATHEMU=y # +# Code generation options +# +CONFIG_MARCH_G5=y +# CONFIG_MARCH_Z900 is not set +# CONFIG_MARCH_Z990 is not set +CONFIG_PACK_STACK=y +# CONFIG_SMALL_STACK is not set +# CONFIG_CHECK_STACK is not set +# CONFIG_WARN_STACK is not set + +# # I/O subsystem configuration # CONFIG_MACHCHK_WARNING=y @@ -130,9 +143,7 @@ # # SCSI low-level drivers # -# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_DEBUG is not set CONFIG_ZFCP=y CONFIG_CCW=y @@ -154,7 +165,7 @@ CONFIG_BLK_DEV_XPRAM=m # CONFIG_DCSSBLK is not set CONFIG_DASD=y -# CONFIG_DASD_PROFILE is not set +CONFIG_DASD_PROFILE=y CONFIG_DASD_ECKD=y CONFIG_DASD_FBA=y CONFIG_DASD_DIAG=y @@ -168,6 +179,7 @@ CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=m # CONFIG_MD_RAID6 is not set CONFIG_MD_MULTIPATH=m @@ -236,11 +248,13 @@ # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set CONFIG_XFRM=y @@ -419,7 +433,6 @@ # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -443,6 +456,7 @@ CONFIG_EXPORTFS=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set @@ -486,8 +500,8 @@ CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set # # Security options @@ -506,16 +520,18 @@ # CONFIG_CRYPTO_SHA1_Z990 is not set # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_DES_Z990 is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_AES_GENERIC is not set +# CONFIG_CRYPTO_AES is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set # CONFIG_CRYPTO_TEA is not set # CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set diff -Nru a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile --- a/arch/s390/kernel/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/s390/kernel/Makefile 2004-10-18 14:57:04 -07:00 @@ -6,11 +6,11 @@ obj-y := bitmap.o traps.o time.o process.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o profile.o + semaphore.o s390_ext.o debug.o profile.o irq.o extra-$(CONFIG_ARCH_S390_31) += head.o extra-$(CONFIG_ARCH_S390X) += head64.o -extra-y += init_task.o vmlinux.lds.s +extra-y += init_task.o vmlinux.lds obj-$(CONFIG_MODULES) += s390_ksyms.o module.o obj-$(CONFIG_SMP) += smp.o diff -Nru a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c --- a/arch/s390/kernel/asm-offsets.c 2004-10-18 14:56:21 -07:00 +++ b/arch/s390/kernel/asm-offsets.c 2004-10-18 14:56:21 -07:00 @@ -39,5 +39,9 @@ DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),); DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),); DEFINE(__PT_SIZE, sizeof(struct pt_regs),); + BLANK(); + DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain),); + DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs),); + DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1),); return 0; } diff -Nru a/arch/s390/kernel/compat_exec.c b/arch/s390/kernel/compat_exec.c --- a/arch/s390/kernel/compat_exec.c 2004-10-18 14:56:50 -07:00 +++ b/arch/s390/kernel/compat_exec.c 2004-10-18 14:56:50 -07:00 @@ -69,7 +69,7 @@ mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; insert_vm_struct(mm, mpnt); - mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + mm->stack_vm = mm->total_vm = vma_pages(mpnt); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff -Nru a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c --- a/arch/s390/kernel/compat_linux.c 2004-10-18 14:56:49 -07:00 +++ b/arch/s390/kernel/compat_linux.c 2004-10-18 14:56:49 -07:00 @@ -725,8 +725,7 @@ int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info, uinfo, 3*sizeof(int)) || - copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) + if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, &info); @@ -1219,7 +1218,7 @@ child_tidptr = (int *) (regs.gprs[5] & 0x7fffffffUL); if (!newsp) newsp = regs.gprs[15]; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } diff -Nru a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c --- a/arch/s390/kernel/compat_signal.c 2004-10-18 14:57:03 -07:00 +++ b/arch/s390/kernel/compat_signal.c 2004-10-18 14:57:03 -07:00 @@ -118,10 +118,10 @@ err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_code, &from->si_code); - if (from->si_code < 0) + if (to->si_code < 0) err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { - switch (from->si_code >> 16) { + switch (to->si_code >> 16) { case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __get_user(to->si_int, &from->si_int); @@ -218,14 +218,17 @@ struct old_sigaction32 __user *oact) { struct k_sigaction new_ka, old_ka; + unsigned long sa_handler, sa_restorer; int ret; if (act) { compat_old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler) || - __get_user((unsigned long)new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(sa_handler, &act->sa_handler) || + __get_user(sa_restorer, &act->sa_restorer)) return -EFAULT; + new_ka.sa.sa_handler = (__sighandler_t) sa_handler; + new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer; __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); @@ -234,9 +237,11 @@ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { + sa_handler = (unsigned long) old_ka.sa.sa_handler; + sa_restorer = (unsigned long) old_ka.sa.sa_restorer; if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user((unsigned long)old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(sa_handler, &oact->sa_handler) || + __put_user(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); @@ -253,6 +258,7 @@ struct sigaction32 __user *oact, size_t sigsetsize) { struct k_sigaction new_ka, old_ka; + unsigned long sa_handler; int ret; compat_sigset_t set32; @@ -261,7 +267,7 @@ return -EINVAL; if (act) { - ret = get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler); + ret = get_user(sa_handler, &act->sa_handler); ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); switch (_NSIG_WORDS) { @@ -278,6 +284,7 @@ if (ret) return -EFAULT; + new_ka.sa.sa_handler = (__sighandler_t) sa_handler; } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); @@ -311,17 +318,19 @@ struct pt_regs *regs) { stack_t kss, koss; + unsigned long ss_sp; int ret, err = 0; mm_segment_t old_fs = get_fs(); if (uss) { if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) return -EFAULT; - err |= __get_user((unsigned long) kss.ss_sp, &uss->ss_sp); + err |= __get_user(ss_sp, &uss->ss_sp); err |= __get_user(kss.ss_size, &uss->ss_size); err |= __get_user(kss.ss_flags, &uss->ss_flags); if (err) return -EFAULT; + kss.ss_sp = (void *) ss_sp; } set_fs (KERNEL_DS); @@ -333,7 +342,8 @@ if (!ret && uoss) { if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) return -EFAULT; - err |= __put_user((unsigned long) koss.ss_sp, &uoss->ss_sp); + ss_sp = (unsigned long) koss.ss_sp; + err |= __put_user(ss_sp, &uoss->ss_sp); err |= __put_user(koss.ss_size, &uoss->ss_size); err |= __put_user(koss.ss_flags, &uoss->ss_flags); if (err) @@ -552,9 +562,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -604,9 +612,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* @@ -614,19 +620,14 @@ */ void -handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs) +handle_signal32(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame32(sig, ka, info, oldset, regs); else setup_frame32(sig, ka, oldset, regs); - - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); diff -Nru a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c --- a/arch/s390/kernel/debug.c 2004-10-18 14:55:55 -07:00 +++ b/arch/s390/kernel/debug.c 2004-10-18 14:55:55 -07:00 @@ -24,7 +24,6 @@ #include -#define MIN(a,b) (((a)<(b))?(a):(b)) #define DEBUG_PROLOG_ENTRY -1 /* typedefs */ @@ -435,7 +434,7 @@ while(count < len){ size = debug_format_entry(p_info); - size = MIN((len - count), (size - entry_offset)); + size = min((len - count), (size - entry_offset)); if(size){ if (copy_to_user(user_buf + count, @@ -723,7 +722,7 @@ spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); debug_finish_entry(id, active, level, 0); spin_unlock_irqrestore(&id->lock, flags); @@ -744,7 +743,7 @@ spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); debug_finish_entry(id, active, level, 1); spin_unlock_irqrestore(&id->lock, flags); @@ -789,7 +788,7 @@ curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active); va_start(ap,string); curr_event->string=string; - for(idx=0;idxbuf_size / sizeof(long))-1));idx++) + for(idx=0;idxbuf_size / sizeof(long))-1);idx++) curr_event->args[idx]=va_arg(ap,long); va_end(ap); debug_finish_entry(id, active, level, 0); @@ -821,7 +820,7 @@ curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active); va_start(ap,string); curr_event->string=string; - for(idx=0;idxbuf_size / sizeof(long))-1));idx++) + for(idx=0;idxbuf_size / sizeof(long))-1);idx++) curr_event->args[idx]=va_arg(ap,long); va_end(ap); debug_finish_entry(id, active, level, 1); @@ -1157,7 +1156,7 @@ } /* number of arguments used for sprintf (without the format string) */ - num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + num_used_args = min(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int)); diff -Nru a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c --- a/arch/s390/kernel/ebcdic.c 2004-10-18 14:57:05 -07:00 +++ b/arch/s390/kernel/ebcdic.c 2004-10-18 14:57:05 -07:00 @@ -391,10 +391,10 @@ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; -EXPORT_SYMBOL_NOVERS(_ascebc_500); -EXPORT_SYMBOL_NOVERS(_ebcasc_500); -EXPORT_SYMBOL_NOVERS(_ascebc); -EXPORT_SYMBOL_NOVERS(_ebcasc); -EXPORT_SYMBOL_NOVERS(_ebc_tolower); -EXPORT_SYMBOL_NOVERS(_ebc_toupper); +EXPORT_SYMBOL(_ascebc_500); +EXPORT_SYMBOL(_ebcasc_500); +EXPORT_SYMBOL(_ascebc); +EXPORT_SYMBOL(_ebcasc); +EXPORT_SYMBOL(_ebc_tolower); +EXPORT_SYMBOL(_ebc_toupper); diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S --- a/arch/s390/kernel/entry.S 2004-10-18 14:56:17 -07:00 +++ b/arch/s390/kernel/entry.S 2004-10-18 14:56:17 -07:00 @@ -19,6 +19,7 @@ #include #include #include +#include /* * Stack layout for the system_call stack entry. @@ -52,6 +53,9 @@ _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) +STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER +STACK_SIZE = 1 << STACK_SHIFT + #define BASED(name) name-system_call(%r13) /* @@ -86,10 +90,16 @@ bnz BASED(1f) 0: l %r14,__LC_ASYNC_STACK # are we already on the async stack ? slr %r14,%r15 - sra %r14,13 + sra %r14,STACK_SHIFT be BASED(2f) 1: l %r15,__LC_ASYNC_STACK .endif +#ifdef CONFIG_CHECK_STACK + b BASED(3f) +2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD + bz BASED(stack_overflow) +3: +#endif 2: s %r15,BASED(.Lc_spsize) # make room for registers & psw mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack la %r12,\psworg @@ -99,7 +109,7 @@ st %r12,SP_ILC(%r15) mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack la %r12,0 - st %r12,0(%r15) # clear back chain + st %r12,__SF_BACKCHAIN(%r15) # clear back chain .endm .macro RESTORE_ALL sync @@ -124,46 +134,22 @@ __switch_to_base: tm __THREAD_per(%r3),0xe8 # new process is using per ? bz __switch_to_noper-__switch_to_base(%r1) # if not we're fine - stctl %c9,%c11,24(%r15) # We are using per stuff - clc __THREAD_per(12,%r3),24(%r15) + stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff + clc __THREAD_per(12,%r3),__SF_EMPTY(%r15) be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: - stm %r6,%r15,24(%r15) # store __switch_to registers of prev task + stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp - lm %r6,%r15,24(%r15) # load __switch_to registers of next task + lm %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task st %r3,__LC_CURRENT # __LC_CURRENT = current task struct l %r3,__THREAD_info(%r3) # load thread_info from task struct st %r3,__LC_THREAD_INFO - ahi %r3,8192 + ahi %r3,STACK_SIZE st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack br %r14 -/* - * do_softirq calling function. We want to run the softirq functions on the - * asynchronous interrupt stack. - */ - .global do_call_softirq -do_call_softirq: - stnsm 24(%r15),0xfc - stm %r12,%r15,28(%r15) - lr %r12,%r15 - basr %r13,0 -do_call_base: - l %r0,__LC_ASYNC_STACK - slr %r0,%r15 - sra %r0,13 - be 0f-do_call_base(%r13) - l %r15,__LC_ASYNC_STACK -0: sl %r15,.Lc_overhead-do_call_base(%r13) - st %r12,0(%r15) # store backchain - l %r1,.Ldo_softirq-do_call_base(%r13) - basr %r14,%r1 - lm %r12,%r15,28(%r12) - ssm 24(%r15) - br %r14 - __critical_start: /* * SVC interrupt handler routine. System calls are synchronous events and @@ -304,9 +290,12 @@ ret_from_fork: l %r13,__LC_SVC_NEW_PSW+4 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct - l %r1,BASED(.Lschedtail) + tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? + bo BASED(0f) + st %r15,SP_R15(%r15) # store stack pointer for new kthread +0: l %r1,BASED(.Lschedtail) basr %r14,%r1 - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts b BASED(sysc_return) # @@ -457,7 +446,7 @@ mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts b BASED(sysc_do_svc) /* @@ -493,16 +482,16 @@ l %r1,SP_R15(%r15) s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(4,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 io_resume_loop: tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bno BASED(io_leave) mvc __TI_precount(4,%r9),BASED(.Lc_pactive) - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts l %r1,BASED(.Lschedule) basr %r14,%r1 # call schedule - stnsm 24(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts xc __TI_precount(4,%r9),__TI_precount(%r9) b BASED(io_resume_loop) #endif @@ -514,7 +503,7 @@ l %r1,__LC_KERNEL_STACK s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(4,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 # # One of the work bits is on. Find out which one. @@ -532,9 +521,9 @@ # io_reschedule: l %r1,BASED(.Lschedule) - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts basr %r14,%r1 # call scheduler - stnsm 24(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts tm __TI_flags+3(%r9),_TIF_WORK_INT bz BASED(io_leave) # there is no work to do b BASED(io_work_loop) @@ -543,12 +532,12 @@ # _TIF_SIGPENDING is set, call do_signal # io_sigpending: - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset l %r1,BASED(.Ldo_signal) basr %r14,%r1 # call do_signal - stnsm 24(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts b BASED(io_leave) # out of here, do NOT recheck /* @@ -589,8 +578,8 @@ l %r15,__LC_SAVE_AREA+60 # load ksp lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs lam %a0,%a15,__LC_AREGS_SAVE_AREA - stosm 0(%r15),0x04 # now we can turn dat on - lm %r6,%r15,24(%r15) # load registers from clone + lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone + stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on basr %r14,0 l %r14,restart_addr-.(%r14) br %r14 # branch to start_secondary @@ -611,6 +600,31 @@ restart_go: #endif +#ifdef CONFIG_CHECK_STACK +/* + * The synchronous or the asynchronous stack overflowed. We are dead. + * No need to properly save the registers, we are going to panic anyway. + * Setup a pt_regs so that show_trace can provide a good call trace. + */ +stack_overflow: + l %r15,__LC_PANIC_STACK # change to panic stack + sl %r15,BASED(.Lc_spsize) + mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack + stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack + la %r1,__LC_SAVE_AREA + ch %r12,BASED(.L0x020) # old psw addr == __LC_SVC_OLD_PSW ? + be BASED(0f) + ch %r12,BASED(.L0x028) # old psw addr == __LC_PGM_OLD_PSW ? + be BASED(0f) + la %r1,__LC_SAVE_AREA+16 +0: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain + l %r1,BASED(1f) # branch to kernel_stack_overflow + la %r2,SP_PTREGS(%r15) # load pt_regs + br %r1 +1: .long kernel_stack_overflow +#endif + cleanup_table_system_call: .long system_call + 0x80000000, sysc_do_svc + 0x80000000 cleanup_table_sysc_return: @@ -695,7 +709,6 @@ .Ldo_IRQ: .long do_IRQ .Ldo_extint: .long do_extint .Ldo_signal: .long do_signal -.Ldo_softirq: .long do_softirq .Lhandle_per: .long do_single_step .Ljump_table: .long pgm_check_table .Lschedule: .long schedule diff -Nru a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S --- a/arch/s390/kernel/entry64.S 2004-10-18 14:56:17 -07:00 +++ b/arch/s390/kernel/entry64.S 2004-10-18 14:56:17 -07:00 @@ -19,6 +19,7 @@ #include #include #include +#include /* * Stack layout for the system_call stack entry. @@ -48,6 +49,9 @@ SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE +STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER +STACK_SIZE = 1 << STACK_SHIFT + _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) @@ -85,10 +89,16 @@ jnz 1f 0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ? slgr %r14,%r15 - srag %r14,%r14,14 + srag %r14,%r14,STACK_SHIFT jz 2f 1: lg %r15,__LC_ASYNC_STACK # load async stack .endif +#ifdef CONFIG_CHECK_STACK + j 3f +2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD + jz stack_overflow +3: +#endif 2: aghi %r15,-SP_SIZE # make room for registers & psw mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack la %r12,\psworg @@ -98,7 +108,7 @@ st %r12,SP_ILC(%r15) mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack la %r12,0 - stg %r12,0(%r15) + stg %r12,__SF_BACKCHAIN(%r15) .endm .macro RESTORE_ALL sync @@ -121,43 +131,22 @@ __switch_to: tm __THREAD_per+4(%r3),0xe8 # is the new process using per ? jz __switch_to_noper # if not we're fine - stctg %c9,%c11,48(%r15) # We are using per stuff - clc __THREAD_per(24,%r3),48(%r15) + stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff + clc __THREAD_per(24,%r3),__SF_EMPTY(%r15) je __switch_to_noper # we got away without bashing TLB's lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: - stmg %r6,%r15,48(%r15) # store __switch_to registers of prev task + stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp - lmg %r6,%r15,48(%r15) # load __switch_to registers of next task + lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task stg %r3,__LC_CURRENT # __LC_CURRENT = current task struct lg %r3,__THREAD_info(%r3) # load thread_info from task struct stg %r3,__LC_THREAD_INFO - aghi %r3,16384 + aghi %r3,STACK_SIZE stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack br %r14 -/* - * do_softirq calling function. We want to run the softirq functions on the - * asynchronous interrupt stack. - */ - .global do_call_softirq -do_call_softirq: - stnsm 48(%r15),0xfc - stmg %r12,%r15,56(%r15) - lgr %r12,%r15 - lg %r0,__LC_ASYNC_STACK - slgr %r0,%r15 - srag %r0,%r0,14 - je 0f - lg %r15,__LC_ASYNC_STACK -0: aghi %r15,-STACK_FRAME_OVERHEAD - stg %r12,0(%r15) # store back chain - brasl %r14,do_softirq - lmg %r12,%r15,56(%r12) - ssm 48(%r15) - br %r14 - __critical_start: /* * SVC interrupt handler routine. System calls are synchronous events and @@ -304,7 +293,10 @@ ret_from_fork: lg %r13,__LC_SVC_NEW_PSW+8 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - brasl %r14,schedule_tail + tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? + jo 0f + stg %r15,SP_R15(%r15) # store stack pointer for new kthread +0: brasl %r14,schedule_tail stosm 24(%r15),0x03 # reenable interrupts j sysc_return @@ -504,7 +496,7 @@ mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - stosm 48(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts j sysc_do_svc /* @@ -539,16 +531,16 @@ lg %r1,SP_R15(%r15) aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(8,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 io_resume_loop: tm __TI_flags+7(%r9),_TIF_NEED_RESCHED jno io_leave larl %r1,.Lc_pactive mvc __TI_precount(4,%r9),0(%r1) - stosm 48(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts brasl %r14,schedule # call schedule - stnsm 48(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts xc __TI_precount(4,%r9),__TI_precount(%r9) j io_resume_loop #endif @@ -560,7 +552,7 @@ lg %r1,__LC_KERNEL_STACK aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(8,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 # # One of the work bits is on. Find out which one. @@ -577,23 +569,23 @@ # _TIF_NEED_RESCHED is set, call schedule # io_reschedule: - stosm 48(%r15),0x03 # reenable interrupts - brasl %r14,schedule # call scheduler - stnsm 48(%r15),0xfc # disable I/O and ext. interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + brasl %r14,schedule # call scheduler + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts tm __TI_flags+7(%r9),_TIF_WORK_INT - jz io_leave # there is no work to do + jz io_leave # there is no work to do j io_work_loop # # _TIF_SIGPENDING is set, call do_signal # io_sigpending: - stosm 48(%r15),0x03 # reenable interrupts - la %r2,SP_PTREGS(%r15) # load pt_regs - slgr %r3,%r3 # clear *oldset - brasl %r14,do_signal # call do_signal - stnsm 48(%r15),0xfc # disable I/O and ext. interrupts - j sysc_leave # out of here, do NOT recheck + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + la %r2,SP_PTREGS(%r15) # load pt_regs + slgr %r3,%r3 # clear *oldset + brasl %r14,do_signal # call do_signal + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts + j sysc_leave # out of here, do NOT recheck /* * External interrupt handler routine @@ -631,8 +623,8 @@ lctlg %c0,%c15,0(%r10) # get new ctl regs lghi %r10,__LC_AREGS_SAVE_AREA lam %a0,%a15,0(%r10) - stosm 0(%r15),0x04 # now we can turn dat on - lmg %r6,%r15,48(%r15) # load registers from clone + lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone + stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on jg start_secondary #else /* @@ -647,6 +639,29 @@ restart_crash: .long 0x000a0000,0x00000000,0x00000000,0x00000000 restart_go: +#endif + +#ifdef CONFIG_CHECK_STACK +/* + * The synchronous or the asynchronous stack overflowed. We are dead. + * No need to properly save the registers, we are going to panic anyway. + * Setup a pt_regs so that show_trace can provide a good call trace. + */ +stack_overflow: + lg %r15,__LC_PANIC_STACK # change to panic stack + aghi %r1,-SP_SIZE + mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack + stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack + la %r1,__LC_SAVE_AREA + chi %r12,__LC_SVC_OLD_PSW + je 0f + chi %r12,__LC_PGM_OLD_PSW + je 0f + la %r1,__LC_SAVE_AREA+16 +0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack + xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain + la %r2,SP_PTREGS(%r15) # load pt_regs + jg kernel_stack_overflow #endif cleanup_table_system_call: diff -Nru a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S --- a/arch/s390/kernel/head.S 2004-10-18 14:56:27 -07:00 +++ b/arch/s390/kernel/head.S 2004-10-18 14:56:27 -07:00 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifndef CONFIG_IPL .org 0 @@ -741,10 +743,10 @@ # l %r15,.Linittu-.LPG2(%r13) mvc __LC_CURRENT(4),__TI_task(%r15) - ahi %r15,8192 # init_task_union + 8192 + ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE st %r15,__LC_KERNEL_STACK # set end of kernel stack ahi %r15,-96 - xc 0(4,%r15),0(%r15) # set backchain to zero + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain # check control registers stctl %c0,%c15,0(%r15) diff -Nru a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S --- a/arch/s390/kernel/head64.S 2004-10-18 14:56:28 -07:00 +++ b/arch/s390/kernel/head64.S 2004-10-18 14:56:28 -07:00 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifndef CONFIG_IPL .org 0 @@ -741,10 +743,10 @@ larl %r15,init_thread_union lg %r14,__TI_task(%r15) # cache current in lowcore stg %r14,__LC_CURRENT - aghi %r15,16384 # init_task_union + 16384 + aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE stg %r15,__LC_KERNEL_STACK # set end of kernel stack aghi %r15,-160 - xc 0(8,%r15),0(%r15) # set backchain to zero + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain # check control registers stctg %c0,%c15,0(%r15) diff -Nru a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/s390/kernel/irq.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,99 @@ +/* + * arch/s390/kernel/irq.c + * + * S390 version + * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * + * This file contains interrupt related functions. + */ + +#include +#include +#include +#include +#include +#include + +/* + * show_interrupts is needed by /proc/interrupts. + */ +int show_interrupts(struct seq_file *p, void *v) +{ + static const char *intrclass_names[] = { "EXT", "I/O", }; + int i = *(loff_t *) v, j; + + if (i == 0) { + seq_puts(p, " "); + for (j=0; j> (PAGE_SHIFT + THREAD_ORDER)) != 0) { + /* Need to switch to the async. stack. */ + new -= STACK_FRAME_OVERHEAD; + ((struct stack_frame *) new)->back_chain = old; + + asm volatile(" la 15,0(%0)\n" + " basr 14,%2\n" + " la 15,0(%1)\n" + : : "a" (new), "a" (old), + "a" (__do_softirq) + : "0", "1", "2", "3", "4", "5", + "cc", "memory" ); + } else + /* We are already on the async stack. */ + __do_softirq(); + } + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(do_softirq); diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c --- a/arch/s390/kernel/process.c 2004-10-18 14:56:49 -07:00 +++ b/arch/s390/kernel/process.c 2004-10-18 14:56:49 -07:00 @@ -58,14 +58,11 @@ */ unsigned long thread_saved_pc(struct task_struct *tsk) { - unsigned long bc; + struct stack_frame *sf; - bc = *((unsigned long *) tsk->thread.ksp); -#ifndef CONFIG_ARCH_S390X - return *((unsigned long *) (bc+56)); -#else - return *((unsigned long *) (bc+112)); -#endif + sf = (struct stack_frame *) tsk->thread.ksp; + sf = (struct stack_frame *) sf->back_chain; + return sf->gprs[8]; } /* @@ -186,41 +183,20 @@ extern void kernel_thread_starter(void); -#ifndef CONFIG_ARCH_S390X - __asm__(".align 4\n" "kernel_thread_starter:\n" - " l 15,0(8)\n" - " sr 15,7\n" - " stosm 24(15),3\n" - " lr 2,10\n" + " la 2,0(10)\n" " basr 14,9\n" - " sr 2,2\n" + " la 2,0\n" " br 11\n"); -#else /* CONFIG_ARCH_S390X */ - -__asm__(".align 4\n" - "kernel_thread_starter:\n" - " lg 15,0(8)\n" - " sgr 15,7\n" - " stosm 48(15),3\n" - " lgr 2,10\n" - " basr 14,9\n" - " sgr 2,2\n" - " br 11\n"); - -#endif /* CONFIG_ARCH_S390X */ - int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); - regs.psw.mask = PSW_KERNEL_BITS; + regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE; - regs.gprs[7] = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); - regs.gprs[8] = __LC_KERNEL_STACK; regs.gprs[9] = (unsigned long) fn; regs.gprs[10] = (unsigned long) arg; regs.gprs[11] = (unsigned long) do_exit; @@ -253,20 +229,13 @@ unsigned long unused, struct task_struct * p, struct pt_regs * regs) { - struct stack_frame + struct fake_frame { - unsigned long back_chain; - unsigned long eos; - unsigned long glue1; - unsigned long glue2; - unsigned long scratch[2]; - unsigned long gprs[10]; /* gprs 6 -15 */ - unsigned int fprs[4]; /* fpr 4 and 6 */ - unsigned int empty[4]; + struct stack_frame sf; struct pt_regs childregs; } *frame; - frame = ((struct stack_frame *) + frame = ((struct fake_frame *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; p->thread.ksp = (unsigned long) frame; p->set_child_tid = p->clear_child_tid = NULL; @@ -274,13 +243,13 @@ frame->childregs = *regs; frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ frame->childregs.gprs[15] = new_stackp; - frame->back_chain = frame->eos = 0; + frame->sf.back_chain = 0; /* new return point is ret_from_fork */ - frame->gprs[8] = (unsigned long) ret_from_fork; + frame->sf.gprs[8] = (unsigned long) ret_from_fork; /* fake return stack for resume(), don't go back to schedule */ - frame->gprs[9] = (unsigned long) frame; + frame->sf.gprs[9] = (unsigned long) frame; /* Save access registers to new thread structure. */ save_access_regs(&p->thread.acrs[0]); @@ -336,7 +305,7 @@ child_tidptr = (int __user *) regs.gprs[5]; if (!newsp) newsp = regs.gprs[15]; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } @@ -423,30 +392,26 @@ unsigned long get_wchan(struct task_struct *p) { - unsigned long r14, r15, bc; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) + struct stack_frame *sf, *low, *high; + unsigned long return_address; + int count; + + if (!p || p == current || p->state == TASK_RUNNING || !p->thread_info) return 0; - stack_page = (unsigned long) p->thread_info; - r15 = p->thread.ksp; - if (!stack_page || r15 < stack_page || - r15 >= THREAD_SIZE - sizeof(unsigned long) + stack_page) + low = (struct stack_frame *) p->thread_info; + high = (struct stack_frame *) + ((unsigned long) p->thread_info + THREAD_SIZE) - 1; + sf = (struct stack_frame *) (p->thread.ksp & PSW_ADDR_INSN); + if (sf <= low || sf > high) return 0; - bc = (*(unsigned long *) r15) & PSW_ADDR_INSN; - do { - if (bc < stack_page || - bc >= THREAD_SIZE - sizeof(unsigned long) + stack_page) + for (count = 0; count < 16; count++) { + sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN); + if (sf <= low || sf > high) return 0; -#ifndef CONFIG_ARCH_S390X - r14 = (*(unsigned long *) (bc+56)) & PSW_ADDR_INSN; -#else - r14 = *(unsigned long *) (bc+112); -#endif - if (!in_sched_functions(r14)) - return r14; - bc = (*(unsigned long *) bc) & PSW_ADDR_INSN; - } while (count++ < 16); + return_address = sf->gprs[8] & PSW_ADDR_INSN; + if (!in_sched_functions(return_address)) + return return_address; + } return 0; } diff -Nru a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c --- a/arch/s390/kernel/profile.c 2004-10-18 14:56:32 -07:00 +++ b/arch/s390/kernel/profile.c 2004-10-18 14:56:32 -07:00 @@ -6,52 +6,15 @@ * */ #include +#include static struct proc_dir_entry * root_irq_dir; -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, - const char __user *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - -cpumask_t prof_cpu_mask = CPU_MASK_ALL; - void init_irq_proc(void) { - struct proc_dir_entry *entry; - /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); } diff -Nru a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c --- a/arch/s390/kernel/s390_ext.c 2004-10-18 14:56:29 -07:00 +++ b/arch/s390/kernel/s390_ext.c 2004-10-18 14:56:29 -07:00 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff -Nru a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c --- a/arch/s390/kernel/s390_ksyms.c 2004-10-18 14:56:33 -07:00 +++ b/arch/s390/kernel/s390_ksyms.c 2004-10-18 14:56:33 -07:00 @@ -23,16 +23,18 @@ /* * memory management */ -EXPORT_SYMBOL_NOVERS(_oi_bitmap); -EXPORT_SYMBOL_NOVERS(_ni_bitmap); -EXPORT_SYMBOL_NOVERS(_zb_findmap); -EXPORT_SYMBOL_NOVERS(_sb_findmap); -EXPORT_SYMBOL_NOVERS(__copy_from_user_asm); -EXPORT_SYMBOL_NOVERS(__copy_to_user_asm); -EXPORT_SYMBOL_NOVERS(__clear_user_asm); -EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm); -EXPORT_SYMBOL_NOVERS(__strnlen_user_asm); +EXPORT_SYMBOL(_oi_bitmap); +EXPORT_SYMBOL(_ni_bitmap); +EXPORT_SYMBOL(_zb_findmap); +EXPORT_SYMBOL(_sb_findmap); +EXPORT_SYMBOL(__copy_from_user_asm); +EXPORT_SYMBOL(__copy_to_user_asm); +EXPORT_SYMBOL(__copy_in_user_asm); +EXPORT_SYMBOL(__clear_user_asm); +EXPORT_SYMBOL(__strncpy_from_user_asm); +EXPORT_SYMBOL(__strnlen_user_asm); EXPORT_SYMBOL(diag10); +EXPORT_SYMBOL(default_storage_key); /* * semaphore ops @@ -60,6 +62,5 @@ EXPORT_SYMBOL(console_mode); EXPORT_SYMBOL(console_devno); EXPORT_SYMBOL(console_irq); -EXPORT_SYMBOL_NOVERS(do_call_softirq); EXPORT_SYMBOL(sys_wait4); EXPORT_SYMBOL(cpcmd); diff -Nru a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c --- a/arch/s390/kernel/setup.c 2004-10-18 14:55:54 -07:00 +++ b/arch/s390/kernel/setup.c 2004-10-18 14:55:54 -07:00 @@ -53,6 +53,7 @@ unsigned int console_irq = -1; unsigned long memory_size = 0; unsigned long machine_flags = 0; +unsigned int default_storage_key = 0; struct { unsigned long addr, size, type; } memory_chunk[MEMORY_CHUNKS] = { { 0 } }; @@ -503,6 +504,10 @@ lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; lc->async_stack = (unsigned long) __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; +#ifdef CONFIG_CHECK_STACK + lc->panic_stack = (unsigned long) + __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; +#endif lc->current_task = (unsigned long) init_thread_union.thread_info.task; lc->thread_info = (unsigned long) &init_thread_union; #ifdef CONFIG_ARCH_S390X @@ -604,49 +609,3 @@ .show = show_cpuinfo, }; -/* - * show_interrupts is needed by /proc/interrupts. - */ - -static const char *intrclass_names[] = { - "EXT", - "I/O", -}; - -int show_interrupts(struct seq_file *p, void *v) -{ - int i = *(loff_t *) v, j; - - if (i == 0) { - seq_puts(p, " "); - for (j=0; jsa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -414,9 +412,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* @@ -424,20 +420,15 @@ */ static void -handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs) +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(sig, ka, info, oldset, regs); else setup_frame(sig, ka, oldset, regs); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -461,6 +452,7 @@ unsigned long retval = 0, continue_addr = 0, restart_addr = 0; siginfo_t info; int signr; + struct k_sigaction ka; /* * We want the common case to go fast, which @@ -494,7 +486,7 @@ /* Get signal to deliver. When running under ptrace, at this point the debugger may change all our registers ... */ - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); /* Depending on the signal settings we may need to revert the decision to restart the system call. */ @@ -513,14 +505,15 @@ #ifdef CONFIG_S390_SUPPORT if (test_thread_flag(TIF_31BIT)) { extern void handle_signal32(unsigned long sig, + struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs); - handle_signal32(signr, &info, oldset, regs); + handle_signal32(signr, &ka, &info, oldset, regs); return 1; } #endif - handle_signal(signr, &info, oldset, regs); + handle_signal(signr, &ka, &info, oldset, regs); return 1; } diff -Nru a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c --- a/arch/s390/kernel/smp.c 2004-10-18 14:55:53 -07:00 +++ b/arch/s390/kernel/smp.c 2004-10-18 14:55:53 -07:00 @@ -562,21 +562,15 @@ static void __init smp_create_idle(unsigned int cpu) { - struct pt_regs regs; struct task_struct *p; /* * don't care about the psw and regs settings since we'll never * reschedule the forked task. */ - memset(®s, 0, sizeof(struct pt_regs)); - p = copy_process(CLONE_VM | CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); + p = fork_idle(cpu); if (IS_ERR(p)) panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - - wake_up_forked_process(p); - init_idle(p, cpu); - unhash_process(p); current_set[cpu] = p; } @@ -643,6 +637,7 @@ { struct task_struct *idle; struct _lowcore *cpu_lowcore; + struct stack_frame *sf; sigp_ccode ccode; int curr_cpu; @@ -666,9 +661,14 @@ idle = current_set[cpu]; cpu_lowcore = lowcore_ptr[cpu]; - cpu_lowcore->save_area[15] = idle->thread.ksp; cpu_lowcore->kernel_stack = (unsigned long) idle->thread_info + (THREAD_SIZE); + sf = (struct stack_frame *) (cpu_lowcore->kernel_stack + - sizeof(struct pt_regs) + - sizeof(struct stack_frame)); + memset(sf, 0, sizeof(struct stack_frame)); + sf->gprs[9] = (unsigned long) sf; + cpu_lowcore->save_area[15] = (unsigned long) sf; __ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15); __asm__ __volatile__("stam 0,15,0(%0)" : : "a" (&cpu_lowcore->access_regs_save_area) @@ -747,7 +747,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) { - unsigned long async_stack; + unsigned long stack; unsigned int cpu; int i; @@ -767,12 +767,18 @@ lowcore_ptr[i] = (struct _lowcore *) __get_free_pages(GFP_KERNEL|GFP_DMA, sizeof(void*) == 8 ? 1 : 0); - async_stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER); - if (lowcore_ptr[i] == NULL || async_stack == 0ULL) + stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER); + if (lowcore_ptr[i] == NULL || stack == 0ULL) panic("smp_boot_cpus failed to allocate memory\n"); *(lowcore_ptr[i]) = S390_lowcore; - lowcore_ptr[i]->async_stack = async_stack + (ASYNC_SIZE); + lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE); +#ifdef CONFIG_CHECK_STACK + stack = __get_free_pages(GFP_KERNEL,0); + if (stack == 0ULL) + panic("smp_boot_cpus failed to allocate memory\n"); + lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE); +#endif } set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); diff -Nru a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c --- a/arch/s390/kernel/time.c 2004-10-18 14:55:54 -07:00 +++ b/arch/s390/kernel/time.c 2004-10-18 14:55:54 -07:00 @@ -174,47 +174,7 @@ #ifdef CONFIG_PROFILING -extern char _stext, _etext; - -/* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ -static inline void s390_do_profile(struct pt_regs * regs) -{ - unsigned long eip; - extern cpumask_t prof_cpu_mask; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - eip = instruction_pointer(regs); - - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!cpu_isset(smp_processor_id(), prof_cpu_mask)) - return; - - eip -= (unsigned long) &_stext; - eip >>= prof_shift; - /* - * Don't ignore out-of-bounds EIP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (eip > prof_len-1) - eip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[eip]); -} +#define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) #else #define s390_do_profile(regs) do { ; } while(0) #endif /* CONFIG_PROFILING */ diff -Nru a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c --- a/arch/s390/kernel/traps.c 2004-10-18 14:56:28 -07:00 +++ b/arch/s390/kernel/traps.c 2004-10-18 14:56:28 -07:00 @@ -67,54 +67,93 @@ #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) #ifndef CONFIG_ARCH_S390X -#define RET_ADDR 56 #define FOURLONG "%08lx %08lx %08lx %08lx\n" static int kstack_depth_to_print = 12; - #else /* CONFIG_ARCH_S390X */ -#define RET_ADDR 112 #define FOURLONG "%016lx %016lx %016lx %016lx\n" static int kstack_depth_to_print = 20; - #endif /* CONFIG_ARCH_S390X */ -void show_trace(struct task_struct *task, unsigned long * stack) +/* + * For show_trace we have tree different stack to consider: + * - the panic stack which is used if the kernel stack has overflown + * - the asynchronous interrupt stack (cpu related) + * - the synchronous kernel stack (process related) + * The stack trace can start at any of the three stack and can potentially + * touch all of them. The order is: panic stack, async stack, sync stack. + */ +static unsigned long +__show_trace(unsigned long sp, unsigned long low, unsigned long high) { - unsigned long backchain, low_addr, high_addr, ret_addr; + struct stack_frame *sf; + struct pt_regs *regs; - if (!stack) - stack = (task == NULL) ? *stack_pointer : &(task->thread.ksp); + while (1) { + sp = sp & PSW_ADDR_INSN; + if (sp < low || sp > high - sizeof(*sf)) + return sp; + sf = (struct stack_frame *) sp; + printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); + print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN); + /* Follow the backchain. */ + while (1) { + low = sp; + sp = sf->back_chain & PSW_ADDR_INSN; + if (!sp) + break; + if (sp <= low || sp > high - sizeof(*sf)) + return sp; + sf = (struct stack_frame *) sp; + printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); + print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN); + } + /* Zero backchain detected, check for interrupt frame. */ + sp = (unsigned long) (sf + 1); + if (sp <= low || sp > high - sizeof(*regs)) + return sp; + regs = (struct pt_regs *) sp; + printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN); + print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN); + low = sp; + sp = regs->gprs[15]; + } +} +void show_trace(struct task_struct *task, unsigned long * stack) +{ + register unsigned long __r15 asm ("15"); + unsigned long sp; + + sp = (unsigned long) stack; + if (!sp) + sp = task ? task->thread.ksp : __r15; printk("Call Trace:\n"); - low_addr = ((unsigned long) stack) & PSW_ADDR_INSN; - high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE; - /* Skip the first frame (biased stack) */ - backchain = *((unsigned long *) low_addr) & PSW_ADDR_INSN; - /* Print up to 8 lines */ - while (backchain > low_addr && backchain <= high_addr) { - ret_addr = *((unsigned long *) (backchain+RET_ADDR)) & PSW_ADDR_INSN; - printk(" [<%016lx>] ", ret_addr); - print_symbol("%s\n", ret_addr); - low_addr = backchain; - backchain = *((unsigned long *) backchain) & PSW_ADDR_INSN; - } +#ifdef CONFIG_CHECK_STACK + sp = __show_trace(sp, S390_lowcore.panic_stack - 4096, + S390_lowcore.panic_stack); +#endif + sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE, + S390_lowcore.async_stack); + if (task) + __show_trace(sp, (unsigned long) task->thread_info, + (unsigned long) task->thread_info + THREAD_SIZE); + else + __show_trace(sp, S390_lowcore.thread_info, + S390_lowcore.thread_info + THREAD_SIZE); printk("\n"); } void show_stack(struct task_struct *task, unsigned long *sp) { + register unsigned long * __r15 asm ("15"); unsigned long *stack; int i; // debugging aid: "show_stack(NULL);" prints the // back trace for this cpu. - if (!sp) { - if (task) - sp = (unsigned long *) task->thread.ksp; - else - sp = *stack_pointer; - } + if (!sp) + sp = task ? (unsigned long *) task->thread.ksp : __r15; stack = sp; for (i = 0; i < kstack_depth_to_print; i++) { @@ -591,6 +630,11 @@ } } +asmlinkage void kernel_stack_overflow(struct pt_regs * regs) +{ + die("Kernel stack overflow", regs, 0); + panic("Corrupt kernel stack, can't continue."); +} /* init is done in lowcore.S and head.S */ diff -Nru a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S --- a/arch/s390/kernel/vmlinux.lds.S 2004-10-18 14:56:28 -07:00 +++ b/arch/s390/kernel/vmlinux.lds.S 2004-10-18 14:56:28 -07:00 @@ -24,6 +24,7 @@ .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x0700 @@ -78,9 +79,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c --- a/arch/s390/kernel/vtime.c 2004-10-18 14:57:04 -07:00 +++ b/arch/s390/kernel/vtime.c 2004-10-18 14:57:04 -07:00 @@ -21,7 +21,7 @@ #include #include -#define VTIMER_MAGIC (0x4b87ad6e + 1) +#define VTIMER_MAGIC (TIMER_MAGIC + 1) static ext_int_info_t ext_int_info_timer; DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); diff -Nru a/arch/s390/lib/string.c b/arch/s390/lib/string.c --- a/arch/s390/lib/string.c 2004-10-18 14:56:28 -07:00 +++ b/arch/s390/lib/string.c 2004-10-18 14:56:28 -07:00 @@ -46,7 +46,7 @@ { return __strend(s) - s; } -EXPORT_SYMBOL_NOVERS(strlen); +EXPORT_SYMBOL(strlen); /** * strnlen - Find the length of a length-limited string @@ -59,7 +59,7 @@ { return __strnend(s, n) - s; } -EXPORT_SYMBOL_NOVERS(strnlen); +EXPORT_SYMBOL(strnlen); /** * strcpy - Copy a %NUL terminated string @@ -79,7 +79,7 @@ : "cc", "memory" ); return ret; } -EXPORT_SYMBOL_NOVERS(strcpy); +EXPORT_SYMBOL(strcpy); /** * strlcpy - Copy a %NUL terminated string into a sized buffer @@ -103,7 +103,7 @@ } return ret; } -EXPORT_SYMBOL_NOVERS(strlcpy); +EXPORT_SYMBOL(strlcpy); /** * strncpy - Copy a length-limited, %NUL-terminated string @@ -121,7 +121,7 @@ __builtin_memcpy(dest, src, len); return dest; } -EXPORT_SYMBOL_NOVERS(strncpy); +EXPORT_SYMBOL(strncpy); /** * strcat - Append one %NUL-terminated string to another @@ -144,7 +144,7 @@ : "d" (r0), "0" (0UL) : "cc", "memory" ); return ret; } -EXPORT_SYMBOL_NOVERS(strcat); +EXPORT_SYMBOL(strcat); /** * strlcat - Append a length-limited, %NUL-terminated string to another @@ -168,7 +168,7 @@ } return res; } -EXPORT_SYMBOL_NOVERS(strlcat); +EXPORT_SYMBOL(strlcat); /** * strncat - Append a length-limited, %NUL-terminated string to another @@ -190,7 +190,7 @@ __builtin_memcpy(p, src, len); return dest; } -EXPORT_SYMBOL_NOVERS(strncat); +EXPORT_SYMBOL(strncat); /** * strcmp - Compare two strings @@ -217,7 +217,7 @@ : : "cc" ); return ret; } -EXPORT_SYMBOL_NOVERS(strcmp); +EXPORT_SYMBOL(strcmp); /** * strrchr - Find the last occurrence of a character in a string @@ -235,7 +235,7 @@ } while (--len > 0); return 0; } -EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL(strrchr); /** * strstr - Find the first substring in a %NUL terminated string @@ -269,7 +269,7 @@ } return 0; } -EXPORT_SYMBOL_NOVERS(strstr); +EXPORT_SYMBOL(strstr); /** * memchr - Find a character in an area of memory. @@ -293,7 +293,7 @@ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); return (void *) ret; } -EXPORT_SYMBOL_NOVERS(memchr); +EXPORT_SYMBOL(memchr); /** * memcmp - Compare two areas of memory @@ -319,7 +319,7 @@ ret = *(char *) r2 - *(char *) r4; return ret; } -EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL(memcmp); /** * memscan - Find a character in an area of memory. @@ -340,7 +340,7 @@ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); return (void *) ret; } -EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL(memscan); /** * memcpy - Copy one area of memory to another @@ -354,7 +354,7 @@ { return __builtin_memcpy(dest, src, n); } -EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL(memcpy); /** * bcopy - Copy one area of memory to another @@ -369,7 +369,7 @@ { __builtin_memcpy(destp, srcp, n); } -EXPORT_SYMBOL_NOVERS(bcopy); +EXPORT_SYMBOL(bcopy); /** * memset - Fill a region of memory with the given value @@ -393,4 +393,4 @@ } while (--n > 0); return s; } -EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memset); diff -Nru a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile --- a/arch/s390/mm/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/s390/mm/Makefile 2004-10-18 14:57:04 -07:00 @@ -2,6 +2,6 @@ # Makefile for the linux s390-specific parts of the memory manager. # -obj-y := init.o fault.o ioremap.o extmem.o +obj-y := init.o fault.o ioremap.o extmem.o mmap.o obj-$(CONFIG_CMM) += cmm.o diff -Nru a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c --- a/arch/s390/mm/fault.c 2004-10-18 14:57:21 -07:00 +++ b/arch/s390/mm/fault.c 2004-10-18 14:57:21 -07:00 @@ -25,11 +25,11 @@ #include #include #include +#include #include #include #include -#include #ifndef CONFIG_ARCH_S390X #define __FAIL_ADDR_MASK 0x7ffff000 @@ -126,8 +126,8 @@ * Send SIGSEGV to task. This is an external routine * to keep the stack usage of do_page_fault small. */ -static void force_sigsegv(struct pt_regs *regs, unsigned long error_code, - int si_code, unsigned long address) +static void do_sigsegv(struct pt_regs *regs, unsigned long error_code, + int si_code, unsigned long address) { struct siginfo si; @@ -282,7 +282,7 @@ if (regs->psw.mask & PSW_MASK_PSTATE) { tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; - force_sigsegv(regs, error_code, si_code, address); + do_sigsegv(regs, error_code, si_code, address); return; } diff -Nru a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/s390/mm/mmap.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,83 @@ +/* + * linux/arch/s390/mm/mmap.c + * + * flexible mmap layout support + * + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Started by Ingo Molnar + */ + +#include +#include + +/* + * Top of mmap area (just below the process stack). + * + * Leave an at least ~128 MB hole. + */ +#define MIN_GAP (128*1024*1024) +#define MAX_GAP (TASK_SIZE/6*5) + +static inline unsigned long mmap_base(void) +{ + unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur; + + if (gap < MIN_GAP) + gap = MIN_GAP; + else if (gap > MAX_GAP) + gap = MAX_GAP; + + return TASK_SIZE - (gap & PAGE_MASK); +} + +static inline int mmap_is_legacy(void) +{ +#ifdef CONFIG_ARCH_S390X + /* + * Force standard allocation for 64 bit programs. + */ + if (!test_thread_flag(TIF_31BIT)) + return 1; +#endif + return sysctl_legacy_va_layout || + (current->personality & ADDR_COMPAT_LAYOUT) || + current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY; +} + +/* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: + */ +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + /* + * Fall back to the standard layout if the personality + * bit is set, or if the expected stack growth is unlimited: + */ + if (mmap_is_legacy()) { + mm->mmap_base = TASK_UNMAPPED_BASE; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; + } else { + mm->mmap_base = mmap_base(); + mm->get_unmapped_area = arch_get_unmapped_area_topdown; + mm->unmap_area = arch_unmap_area_topdown; + } +} diff -Nru a/arch/sh/Kconfig b/arch/sh/Kconfig --- a/arch/sh/Kconfig 2004-10-18 14:57:04 -07:00 +++ b/arch/sh/Kconfig 2004-10-18 14:57:04 -07:00 @@ -194,7 +194,7 @@ choice prompt "Processor subtype" - + config CPU_SUBTYPE_SH7604 bool "SH7604" depends on CPU_SH2 @@ -301,7 +301,7 @@ ---help--- Computers built with Hitachi SuperH processors always map the ROM starting at address zero. But the processor - does not specify the range that RAM takes. + does not specify the range that RAM takes. The physical memory (RAM) start address will be automatically set to 08000000, unless you selected one of the following @@ -339,7 +339,7 @@ # If none of the above have set memory start/size, ask the user. config MEMORY_OVERRIDE bool "Override default load address and memory size" - + # XXX: break these out into the board-specific configs below config CF_ENABLER bool "Compact Flash Enabler support" @@ -522,7 +522,7 @@ help Selecting this option will enable an in-kernel API for manipulating the store queues integrated in the SH-4 processors. - + config SMP bool "Symmetric multi-processing support" ---help--- @@ -711,7 +711,6 @@ endmenu - menu "Executable file formats" source "fs/Kconfig.binfmt" @@ -742,161 +741,10 @@ source "arch/sh/oprofile/Kconfig" -menu "Kernel hacking" - -config MAGIC_SYSRQ - bool "Magic SysRq key" - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - help - If you say Y here the resulting kernel image will include - 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 SH_STANDARD_BIOS - bool "Use LinuxSH standard BIOS" - help - Say Y here if your target has the gdb-sh-stub - package from www.m17n.org (or any conforming standard LinuxSH BIOS) - in FLASH or EPROM. The kernel will use standard BIOS calls during - boot for various housekeeping tasks (including calls to read and - write characters to a system console, get a MAC address from an - on-board Ethernet interface, and shut down the hardware). Note this - does not work with machines with an existing operating system in - mask ROM and no flash (WindowsCE machines fall in this category). - If unsure, say N. - -config EARLY_SCIF_CONSOLE - bool "Use early SCIF console" - depends on CPU_SH4 - -config EARLY_PRINTK - bool "Early printk support" - depends on SH_STANDARD_BIOS || EARLY_SCIF_CONSOLE - help - Say Y here to redirect kernel printk messages to the serial port - used by the SH-IPL bootloader, starting very early in the boot - process and ending when the kernel's serial console is initialised. - This option is only useful porting the kernel to a new machine, - when the kernel may crash or hang before the serial console is - initialised. If unsure, say N. - -config KGDB - bool "Include KGDB kernel debugger" - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -menu "KGDB configuration options" - depends on KGDB - -config MORE_COMPILE_OPTIONS - bool "Add any additional compile options" - help - If you want to add additional CFLAGS to the kernel build, enable this - option and then enter what you would like to add in the next question. - Note however that -g is already appended with the selection of KGDB. - -config COMPILE_OPTIONS - string "Additional compile arguments" - depends on MORE_COMPILE_OPTIONS - -config KGDB_NMI - bool "Enter KGDB on NMI" - default n - -config KGDB_THREAD - bool "Include KGDB thread support" - default y - -config SH_KGDB_CONSOLE - bool "Console messages through GDB" - default n - -config KGDB_SYSRQ - bool "Allow SysRq 'G' to enter KGDB" - default y - -config KGDB_KERNEL_ASSERTS - bool "Include KGDB kernel assertions" - default n - -comment "Serial port setup" - -config KGDB_DEFPORT - int "Port number (ttySCn)" - default "1" - -config KGDB_DEFBAUD - int "Baud rate" - default "115200" - -choice - prompt "Parity" - depends on KGDB - default KGDB_DEFPARITY_N - -config KGDB_DEFPARITY_N - bool "None" - -config KGDB_DEFPARITY_E - bool "Even" - -config KGDB_DEFPARITY_O - bool "Odd" - -endchoice - -choice - prompt "Data bits" - depends on KGDB - default KGDB_DEFBITS_8 - -config KGDB_DEFBITS_8 - bool "8" - -config KGDB_DEFBITS_7 - bool "7" - -endchoice - -endmenu - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - default y if 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. - -endmenu +source "arch/sh/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sh/Kconfig.debug 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,124 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config SH_STANDARD_BIOS + bool "Use LinuxSH standard BIOS" + help + Say Y here if your target has the gdb-sh-stub + package from www.m17n.org (or any conforming standard LinuxSH BIOS) + in FLASH or EPROM. The kernel will use standard BIOS calls during + boot for various housekeeping tasks (including calls to read and + write characters to a system console, get a MAC address from an + on-board Ethernet interface, and shut down the hardware). Note this + does not work with machines with an existing operating system in + mask ROM and no flash (WindowsCE machines fall in this category). + If unsure, say N. + +config EARLY_SCIF_CONSOLE + bool "Use early SCIF console" + depends on CPU_SH4 + +config EARLY_PRINTK + bool "Early printk support" + depends on SH_STANDARD_BIOS || EARLY_SCIF_CONSOLE + help + Say Y here to redirect kernel printk messages to the serial port + used by the SH-IPL bootloader, starting very early in the boot + process and ending when the kernel's serial console is initialised. + This option is only useful porting the kernel to a new machine, + when the kernel may crash or hang before the serial console is + initialised. If unsure, say N. + +config KGDB + bool "Include KGDB kernel debugger" + help + Include in-kernel hooks for kgdb, the Linux kernel source level + debugger. See for more information. + Unless you are intending to debug the kernel, say N here. + +menu "KGDB configuration options" + depends on KGDB + +config MORE_COMPILE_OPTIONS + bool "Add any additional compile options" + help + If you want to add additional CFLAGS to the kernel build, enable this + option and then enter what you would like to add in the next question. + Note however that -g is already appended with the selection of KGDB. + +config COMPILE_OPTIONS + string "Additional compile arguments" + depends on MORE_COMPILE_OPTIONS + +config KGDB_NMI + bool "Enter KGDB on NMI" + default n + +config KGDB_THREAD + bool "Include KGDB thread support" + default y + +config SH_KGDB_CONSOLE + bool "Console messages through GDB" + default n + +config KGDB_SYSRQ + bool "Allow SysRq 'G' to enter KGDB" + default y + +config KGDB_KERNEL_ASSERTS + bool "Include KGDB kernel assertions" + default n + +comment "Serial port setup" + +config KGDB_DEFPORT + int "Port number (ttySCn)" + default "1" + +config KGDB_DEFBAUD + int "Baud rate" + default "115200" + +choice + prompt "Parity" + depends on KGDB + default KGDB_DEFPARITY_N + +config KGDB_DEFPARITY_N + bool "None" + +config KGDB_DEFPARITY_E + bool "Even" + +config KGDB_DEFPARITY_O + bool "Odd" + +endchoice + +choice + prompt "Data bits" + depends on KGDB + default KGDB_DEFBITS_8 + +config KGDB_DEFBITS_8 + bool "8" + +config KGDB_DEFBITS_7 + bool "7" + +endchoice + +endmenu + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + default y if 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. + +endmenu diff -Nru a/arch/sh/Makefile b/arch/sh/Makefile --- a/arch/sh/Makefile 2004-10-18 14:56:33 -07:00 +++ b/arch/sh/Makefile 2004-10-18 14:56:33 -07:00 @@ -31,7 +31,7 @@ cflags-$(CONFIG_CPU_SH2) += -m2 cflags-$(CONFIG_CPU_SH3) += -m3 cflags-$(CONFIG_CPU_SH4) += -m4 \ - $(call check_gcc,-mno-implicit-fp,-m4-nofpu) + $(call cc-option,-mno-implicit-fp,-m4-nofpu) cflags-$(CONFIG_SH_DSP) += -Wa,-dsp cflags-$(CONFIG_SH_KGDB) += -g @@ -122,7 +122,7 @@ boot := arch/sh/boot -AFLAGS_vmlinux.lds.o := -traditional +CPPFLAGS_vmlinux.lds := -traditional prepare: target_links diff -Nru a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c --- a/arch/sh/boards/mpc1211/pci.c 2004-10-18 14:56:50 -07:00 +++ b/arch/sh/boards/mpc1211/pci.c 2004-10-18 14:56:50 -07:00 @@ -176,14 +176,7 @@ dev->resource[4].end = 0xf00f; dev->resource[4].flags = IORESOURCE_IO; } - - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, - PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports); char * __devinit pcibios_setup(char *str) { diff -Nru a/arch/sh/boards/overdrive/galileo.c b/arch/sh/boards/overdrive/galileo.c --- a/arch/sh/boards/overdrive/galileo.c 2004-10-18 14:56:27 -07:00 +++ b/arch/sh/boards/overdrive/galileo.c 2004-10-18 14:56:27 -07:00 @@ -455,13 +455,7 @@ } } } - - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); void __init pcibios_init(void) { diff -Nru a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile --- a/arch/sh/boot/compressed/Makefile 2004-10-18 14:56:32 -07:00 +++ b/arch/sh/boot/compressed/Makefile 2004-10-18 14:56:32 -07:00 @@ -22,7 +22,7 @@ CONFIG_BOOT_LINK_OFFSET ?= 0x00800000 IMAGE_OFFSET := $(shell printf "0x%8x" $$[0x80000000+$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)]) -LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds.s +LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE $(call if_changed,ld) diff -Nru a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c --- a/arch/sh/drivers/pci/fixups-dreamcast.c 2004-10-18 14:57:04 -07:00 +++ b/arch/sh/drivers/pci/fixups-dreamcast.c 2004-10-18 14:57:04 -07:00 @@ -47,11 +47,7 @@ } } -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, - PCI_ANY_ID, gapspci_fixup_resources }, - { 0, } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources); void __init pcibios_fixup_bus(struct pci_bus *bus) { diff -Nru a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c --- a/arch/sh/drivers/pci/pci-sh7751.c 2004-10-18 14:56:49 -07:00 +++ b/arch/sh/drivers/pci/pci-sh7751.c 2004-10-18 14:56:49 -07:00 @@ -177,15 +177,8 @@ } } } +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); #endif - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { -#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, -#endif - { 0 } -}; /* * Called after each bus is probed, but before its children diff -Nru a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c --- a/arch/sh/drivers/pci/pci-st40.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sh/drivers/pci/pci-st40.c 2004-10-18 14:56:33 -07:00 @@ -160,13 +160,7 @@ } } } - - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); int __init st40pci_init(unsigned memStart, unsigned memSize) { diff -Nru a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile --- a/arch/sh/kernel/Makefile 2004-10-18 14:56:33 -07:00 +++ b/arch/sh/kernel/Makefile 2004-10-18 14:56:33 -07:00 @@ -2,7 +2,7 @@ # Makefile for the Linux/SuperH kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps.o irq.o \ ptrace.o setup.o time.o sys_sh.o semaphore.o \ diff -Nru a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c --- a/arch/sh/kernel/irq.c 2004-10-18 14:56:28 -07:00 +++ b/arch/sh/kernel/irq.c 2004-10-18 14:56:28 -07:00 @@ -137,14 +137,16 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); diff -Nru a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c --- a/arch/sh/kernel/process.c 2004-10-18 14:56:48 -07:00 +++ b/arch/sh/kernel/process.c 2004-10-18 14:56:48 -07:00 @@ -440,7 +440,7 @@ { if (!newsp) newsp = regs.regs[15]; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, (int __user *)parent_tidptr, (int __user *)child_tidptr); } diff -Nru a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c --- a/arch/sh/kernel/sh_ksyms.c 2004-10-18 14:56:17 -07:00 +++ b/arch/sh/kernel/sh_ksyms.c 2004-10-18 14:56:17 -07:00 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -87,7 +86,7 @@ EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__const_udelay); -#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL_NOVERS(name) +#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name) /* These symbols are generated by the compiler itself */ DECLARE_EXPORT(__udivsi3); diff -Nru a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c --- a/arch/sh/kernel/signal.c 2004-10-18 14:57:19 -07:00 +++ b/arch/sh/kernel/signal.c 2004-10-18 14:57:19 -07:00 @@ -413,9 +413,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -490,9 +488,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* diff -Nru a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c --- a/arch/sh/kernel/smp.c 2004-10-18 14:56:29 -07:00 +++ b/arch/sh/kernel/smp.c 2004-10-18 14:56:29 -07:00 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -98,18 +97,11 @@ int __cpu_up(unsigned int cpu) { struct task_struct *tsk; - struct pt_regs regs; - memset(®s, 0, sizeof(struct pt_regs)); - tsk = copy_process(CLONE_VM | CLONE_IDLETASK, 0, ®s, 0, 0, 0); + tsk = fork_idle(cpu); if (IS_ERR(tsk)) panic("Failed forking idle task for cpu %d\n", cpu); - - wake_up_forked_process(tsk); - - init_idle(tsk, cpu); - unhash_process(tsk); tsk->thread_info->cpu = cpu; diff -Nru a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c --- a/arch/sh/kernel/time.c 2004-10-18 14:55:53 -07:00 +++ b/arch/sh/kernel/time.c 2004-10-18 14:55:53 -07:00 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -250,36 +251,6 @@ /* last time the RTC clock got updated */ static long last_rtc_update; -/* Profiling definitions */ -extern unsigned long prof_cpu_mask; -extern unsigned int * prof_buffer; -extern unsigned long prof_len; -extern unsigned long prof_shift; -extern char _stext; - -static inline void sh_do_profile(unsigned long pc) -{ - /* Don't profile cpu_idle.. */ - if (!prof_buffer || !current->pid) - return; - - if (pc >= 0xa0000000UL && pc < 0xc0000000UL) - pc -= 0x20000000; - - pc -= (unsigned long)&_stext; - pc >>= prof_shift; - - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -287,9 +258,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { do_timer(regs); - - if (!user_mode(regs)) - sh_do_profile(regs->pc); + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_HEARTBEAT if (sh_mv.mv_heartbeat != NULL) diff -Nru a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S --- a/arch/sh/kernel/vmlinux.lds.S 2004-10-18 14:56:32 -07:00 +++ b/arch/sh/kernel/vmlinux.lds.S 2004-10-18 14:56:32 -07:00 @@ -23,6 +23,7 @@ .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x0009 @@ -75,9 +76,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/sh/mm/fault-nommu.c b/arch/sh/mm/fault-nommu.c --- a/arch/sh/mm/fault-nommu.c 2004-10-18 14:56:49 -07:00 +++ b/arch/sh/mm/fault-nommu.c 2004-10-18 14:56:49 -07:00 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c --- a/arch/sh/mm/fault.c 2004-10-18 14:56:27 -07:00 +++ b/arch/sh/mm/fault.c 2004-10-18 14:56:27 -07:00 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sh/mm/init.c b/arch/sh/mm/init.c --- a/arch/sh/mm/init.c 2004-10-18 14:56:49 -07:00 +++ b/arch/sh/mm/init.c 2004-10-18 14:56:49 -07:00 @@ -214,8 +214,8 @@ */ disable_mmu(); #endif - - free_area_init_node(0, NODE_DATA(0), 0, zones_size, __MEMORY_START >> PAGE_SHIFT, 0); + NODE_DATA(0)->node_mem_map = NULL; + free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0); /* XXX: MRB-remove - this doesn't seem sane, should this be done somewhere else ?*/ mem_map = NODE_DATA(0)->node_mem_map; @@ -225,7 +225,7 @@ */ zones_size[ZONE_DMA] = __MEMORY_SIZE_2ND >> PAGE_SHIFT; zones_size[ZONE_NORMAL] = 0; - free_area_init_node(1, NODE_DATA(1), 0, zones_size, __MEMORY_START_2ND >> PAGE_SHIFT, 0); + free_area_init_node(1, NODE_DATA(1), zones_size, __MEMORY_START_2ND >> PAGE_SHIFT, 0); #endif } diff -Nru a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c --- a/arch/sh/mm/tlb-sh3.c 2004-10-18 14:56:28 -07:00 +++ b/arch/sh/mm/tlb-sh3.c 2004-10-18 14:56:28 -07:00 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c --- a/arch/sh/mm/tlb-sh4.c 2004-10-18 14:56:48 -07:00 +++ b/arch/sh/mm/tlb-sh4.c 2004-10-18 14:56:48 -07:00 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sh64/Kconfig b/arch/sh64/Kconfig --- a/arch/sh64/Kconfig 2004-10-18 14:56:49 -07:00 +++ b/arch/sh64/Kconfig 2004-10-18 14:56:49 -07:00 @@ -263,58 +263,10 @@ source "arch/sh64/oprofile/Kconfig" -menu "Kernel hacking" - -config MAGIC_SYSRQ - bool "Magic SysRq key" - 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 EARLY_PRINTK - bool "Early SCIF console support" - -config DEBUG_KERNEL_WITH_GDB_STUB - bool "GDB Stub kernel debug" - -config SH64_PROC_TLB - bool "Debug: report TLB fill/purge activity through /proc/tlb" - depends on PROC_FS - -config SH64_PROC_ASIDS - bool "Debug: report ASIDs through /proc/asids" - depends on PROC_FS - -config SH64_SR_WATCH - bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" - -config SH_ALPHANUMERIC - bool "Enable debug outputs to on-board alphanumeric display" - -config SH_NO_BSS_INIT - bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - default y if 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. - -endmenu +source "arch/sh64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/sh64/Kconfig.debug b/arch/sh64/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sh64/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,37 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config EARLY_PRINTK + bool "Early SCIF console support" + +config DEBUG_KERNEL_WITH_GDB_STUB + bool "GDB Stub kernel debug" + +config SH64_PROC_TLB + bool "Debug: report TLB fill/purge activity through /proc/tlb" + depends on PROC_FS + +config SH64_PROC_ASIDS + bool "Debug: report ASIDs through /proc/asids" + depends on PROC_FS + +config SH64_SR_WATCH + bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" + +config SH_ALPHANUMERIC + bool "Enable debug outputs to on-board alphanumeric display" + +config SH_NO_BSS_INIT + bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + default y if 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. + +endmenu diff -Nru a/arch/sh64/boot/compressed/Makefile b/arch/sh64/boot/compressed/Makefile --- a/arch/sh64/boot/compressed/Makefile 2004-10-18 14:56:49 -07:00 +++ b/arch/sh64/boot/compressed/Makefile 2004-10-18 14:56:49 -07:00 @@ -12,7 +12,7 @@ # targets := vmlinux vmlinux.bin vmlinux.bin.gz \ - head.o misc.o cache.o piggy.o vmlinux.lds.o + head.o misc.o cache.o piggy.o vmlinux.lds EXTRA_AFLAGS := -traditional @@ -25,7 +25,7 @@ ZIMAGE_OFFSET = $(shell printf "0x%8x" $$[$(CONFIG_MEMORY_START)+0x400000+0x10000]) LDFLAGS_vmlinux := -Ttext $(ZIMAGE_OFFSET) -e startup \ - -T $(obj)/../../kernel/vmlinux.lds.s \ + -T $(obj)/../../kernel/vmlinux.lds \ --no-warn-mismatch $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE @@ -41,6 +41,6 @@ LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh64-linux -T OBJCOPYFLAGS += -R .empty_zero_page -$(obj)/piggy.o: $(obj)/vmlinux.lds.s $(obj)/vmlinux.bin.gz FORCE +$(obj)/piggy.o: $(obj)/vmlinux.lds $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld) diff -Nru a/arch/sh64/kernel/irq.c b/arch/sh64/kernel/irq.c --- a/arch/sh64/kernel/irq.c 2004-10-18 14:56:14 -07:00 +++ b/arch/sh64/kernel/irq.c 2004-10-18 14:56:14 -07:00 @@ -148,6 +148,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status; + int ret; status = 1; /* Force the "do bottom halves" bit */ @@ -155,8 +156,9 @@ local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) diff -Nru a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c --- a/arch/sh64/kernel/pci_sh5.c 2004-10-18 14:57:05 -07:00 +++ b/arch/sh64/kernel/pci_sh5.c 2004-10-18 14:57:05 -07:00 @@ -48,12 +48,7 @@ } } } - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); char * __init pcibios_setup(char *str) { diff -Nru a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c --- a/arch/sh64/kernel/process.c 2004-10-18 14:57:18 -07:00 +++ b/arch/sh64/kernel/process.c 2004-10-18 14:57:18 -07:00 @@ -820,7 +820,7 @@ { if (!newsp) newsp = pregs->regs[15]; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, pregs, 0, 0, 0); + return do_fork(clone_flags, newsp, pregs, 0, 0, 0); } /* @@ -901,7 +901,7 @@ */ pc = thread_saved_pc(p); -#if CONFIG_FRAME_POINTER +#ifdef CONFIG_FRAME_POINTER if (in_sh64_switch_to(pc)) { sh64_switch_to_fp = (long) p->thread.sp; /* r14 is saved at offset 4 in the sh64_switch_to frame */ diff -Nru a/arch/sh64/kernel/ptrace.c b/arch/sh64/kernel/ptrace.c --- a/arch/sh64/kernel/ptrace.c 2004-10-18 14:56:48 -07:00 +++ b/arch/sh64/kernel/ptrace.c 2004-10-18 14:56:48 -07:00 @@ -311,11 +311,8 @@ if (!(tsk->ptrace & PT_PTRACED)) return; - tsk->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - tsk->state = TASK_STOPPED; - notify_parent(tsk, 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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c --- a/arch/sh64/kernel/sh_ksyms.c 2004-10-18 14:56:13 -07:00 +++ b/arch/sh64/kernel/sh_ksyms.c 2004-10-18 14:56:13 -07:00 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -59,17 +58,17 @@ EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL_NOVERS(__down); -EXPORT_SYMBOL_NOVERS(__down_trylock); -EXPORT_SYMBOL_NOVERS(__up); -EXPORT_SYMBOL_NOVERS(__put_user_asm_l); -EXPORT_SYMBOL_NOVERS(__get_user_asm_l); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(strchr); -EXPORT_SYMBOL_NOVERS(strlen); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_trylock); +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__put_user_asm_l); +EXPORT_SYMBOL(__get_user_asm_l); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(flush_dcache_page); @@ -78,7 +77,7 @@ extern void __sdivsi3(void); extern void __muldi3(void); extern void __udivsi3(void); -EXPORT_SYMBOL_NOVERS(__sdivsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__udivsi3); +EXPORT_SYMBOL(__sdivsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__udivsi3); diff -Nru a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c --- a/arch/sh64/kernel/signal.c 2004-10-18 14:56:29 -07:00 +++ b/arch/sh64/kernel/signal.c 2004-10-18 14:56:29 -07:00 @@ -520,9 +520,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -628,9 +626,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* diff -Nru a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c --- a/arch/sh64/kernel/time.c 2004-10-18 14:56:32 -07:00 +++ b/arch/sh64/kernel/time.c 2004-10-18 14:56:32 -07:00 @@ -298,37 +298,6 @@ /* last time the RTC clock got updated */ static long last_rtc_update = 0; -static inline void sh64_do_profile(struct pt_regs *regs) -{ - extern int _stext; - unsigned long pc; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - /* Don't profile cpu_idle.. */ - if (!prof_buffer || !current->pid) - return; - - pc = instruction_pointer(regs); - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - - /* - * Don't ignore out-of-bounds PC values silently, put them into the - * last histogram slot, so if present, they will show up as a sharp - * peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - - /* We could just be sloppy and not lock against a re-entry on this - increment, but the profiling code won't always be linked in anyway. */ - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -340,8 +309,7 @@ ctc_last_interrupt = (unsigned long) current_ctc; do_timer(regs); - - sh64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_HEARTBEAT { diff -Nru a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S --- a/arch/sh64/kernel/vmlinux.lds.S 2004-10-18 14:56:13 -07:00 +++ b/arch/sh64/kernel/vmlinux.lds.S 2004-10-18 14:56:13 -07:00 @@ -59,6 +59,7 @@ *(.text64) *(.text..SHmedia32) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) #ifdef CONFIG_LITTLE_ENDIAN @@ -106,9 +107,6 @@ __setup_start = .; .init.setup : C_PHYS(.init.setup) { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : C_PHYS(__param) { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : C_PHYS(.initcall.init) { *(.initcall1.init) diff -Nru a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c --- a/arch/sh64/mm/fault.c 2004-10-18 14:56:29 -07:00 +++ b/arch/sh64/mm/fault.c 2004-10-18 14:56:29 -07:00 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include /* required by inline asm statements */ diff -Nru a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c --- a/arch/sh64/mm/init.c 2004-10-18 14:57:21 -07:00 +++ b/arch/sh64/mm/init.c 2004-10-18 14:57:21 -07:00 @@ -122,8 +122,8 @@ * All memory is good as ZONE_NORMAL (fall-through) and ZONE_DMA. */ zones_size[ZONE_DMA] = MAX_LOW_PFN - START_PFN; - - free_area_init_node(0, NODE_DATA(0), 0, zones_size, __MEMORY_START >> PAGE_SHIFT, 0); + NODE_DATA(0)->node_mem_map = NULL; + free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0); /* XXX: MRB-remove - this doesn't seem sane, should this be done somewhere else ?*/ mem_map = NODE_DATA(0)->node_mem_map; diff -Nru a/arch/sh64/mm/tlbmiss.c b/arch/sh64/mm/tlbmiss.c --- a/arch/sh64/mm/tlbmiss.c 2004-10-18 14:55:55 -07:00 +++ b/arch/sh64/mm/tlbmiss.c 2004-10-18 14:55:55 -07:00 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include /* required by inline asm statements */ diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig --- a/arch/sparc/Kconfig 2004-10-18 14:55:46 -07:00 +++ b/arch/sparc/Kconfig 2004-10-18 14:55:46 -07:00 @@ -23,8 +23,7 @@ source "init/Kconfig" - -menu "General setup" +menu "General machine setup" config VT bool @@ -217,8 +216,8 @@ bool default y help - Enable power management and CPU standby features on supported - SPARC platforms. + Enable power management and CPU standby features on supported + SPARC platforms. config SUN4 bool "Support for SUN4 machines (disables SUN4[CDM] support)" @@ -380,81 +379,10 @@ source "drivers/char/watchdog/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_STACK_USAGE - bool "Enable stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - help - This options enables additional error checking for high memory - systems. Disable for production systems. - -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. - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" - depends on DEBUG_KERNEL - help - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -endmenu +source "arch/sparc/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc/Kconfig.debug 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,14 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +endmenu diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile --- a/arch/sparc/Makefile 2004-10-18 14:55:55 -07:00 +++ b/arch/sparc/Makefile 2004-10-18 14:55:55 -07:00 @@ -13,7 +13,7 @@ AS := $(AS) -32 LDFLAGS := -m elf32_sparc -CHECK := $(CHECK) -D__sparc__=1 +CHECKFLAGS += -D__sparc__ #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 CFLAGS := $(CFLAGS) -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 diff -Nru a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile --- a/arch/sparc/boot/Makefile 2004-10-18 14:57:03 -07:00 +++ b/arch/sparc/boot/Makefile 2004-10-18 14:57:03 -07:00 @@ -7,28 +7,52 @@ ROOT_IMG := /usr/src/root.img ELFTOAOUT := elftoaout -host-progs := piggyback btfixupprep -targets := tftpboot.img btfix.o btfix.s image +hostprogs-y := piggyback btfixupprep +targets := tftpboot.img btfix.o btfix.S image quiet_cmd_elftoaout = ELFTOAOUT $@ cmd_elftoaout = $(ELFTOAOUT) $(obj)/image -o $@ -quiet_cmd_piggy = PIGGY $@ +quiet_cmd_piggy = PIGGY $@ cmd_piggy = $(obj)/piggyback $@ $(obj)/System.map $(ROOT_IMG) -quiet_cmd_btfix = BTFIX $@ +quiet_cmd_btfix = BTFIX $@ cmd_btfix = $(OBJDUMP) -x vmlinux | $(obj)/btfixupprep > $@ +quiet_cmd_sysmap = SYSMAP $(obj)/System.map + cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap +quiet_cmd_image = LD $@ + cmd_image = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) -o $@ + +define rule_image + $(if $($(quiet)cmd_image), \ + echo ' $($(quiet)cmd_image)' &&) \ + $(cmd_image); \ + $(if $($(quiet)cmd_sysmap), \ + echo ' $($(quiet)cmd_sysmap)' &&) \ + $(cmd_sysmap) $@ $(obj)/System.map; \ + if [ $$? -ne 0 ]; then \ + rm -f $@; \ + /bin/false; \ + fi; \ + echo 'cmd_$@ := $(cmd_image)' > $(@D)/.$(@F).cmd +endef BTOBJS := $(HEAD_Y) $(INIT_Y) BTLIBS := $(CORE_Y) $(LIBS_Y) $(DRIVERS_Y) $(NET_Y) -LDFLAGS_image := -T arch/sparc/kernel/vmlinux.lds.s $(BTOBJS) --start-group $(BTLIBS) --end-group $(kallsyms.o) +LDFLAGS_image := -T arch/sparc/kernel/vmlinux.lds $(BTOBJS) \ + --start-group $(BTLIBS) --end-group \ + $(kallsyms.o) $(obj)/btfix.o -# Actual linking +# Link the final image including btfixup'ed symbols. +# This is a replacement for the link done in the top-level Makefile. +# Note: No dependency on the prerequisite files since that would require +# make to try check if they are updated - and due to changes +# in gcc options (path for example) this would result in +# these files being recompiled for each build. $(obj)/image: $(obj)/btfix.o FORCE - $(call if_changed,ld) - $(NM) $@ | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > $(obj)/System.map + $(call if_changed_rule,image) $(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE $(call if_changed,elftoaout) $(call if_changed,piggy) -$(obj)/btfix.s: $(obj)/btfixupprep vmlinux FORCE +$(obj)/btfix.S: $(obj)/btfixupprep vmlinux FORCE $(call if_changed,btfix) diff -Nru a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile --- a/arch/sparc/kernel/Makefile 2004-10-18 14:56:50 -07:00 +++ b/arch/sparc/kernel/Makefile 2004-10-18 14:56:50 -07:00 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds EXTRA_AFLAGS := -ansi diff -Nru a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S --- a/arch/sparc/kernel/entry.S 2004-10-18 14:56:29 -07:00 +++ b/arch/sparc/kernel/entry.S 2004-10-18 14:56:29 -07:00 @@ -858,7 +858,7 @@ vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG .globl invalid_segment_patch1, invalid_segment_patch2 - .globl num_context_patch1, num_context_patch2 + .globl num_context_patch1 .globl vac_linesize_patch, vac_hwflush_patch1 .globl vac_hwflush_patch2 diff -Nru a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c --- a/arch/sparc/kernel/init_task.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc/kernel/init_task.c 2004-10-18 14:56:33 -07:00 @@ -23,6 +23,6 @@ * in etrap.S which assumes it. */ union thread_union init_thread_union - __attribute__((section (".text,#alloc"))) + __attribute__((section (".text\"\n\t#"))) __attribute__((aligned (THREAD_SIZE))) = { INIT_THREAD_INFO(init_task) }; diff -Nru a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c --- a/arch/sparc/kernel/irq.c 2004-10-18 14:55:54 -07:00 +++ b/arch/sparc/kernel/irq.c 2004-10-18 14:55:54 -07:00 @@ -45,7 +45,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c --- a/arch/sparc/kernel/pcic.c 2004-10-18 14:56:32 -07:00 +++ b/arch/sparc/kernel/pcic.c 2004-10-18 14:56:32 -07:00 @@ -36,10 +36,6 @@ #include -struct pci_fixup pcibios_fixups[] = { - { 0 } -}; - unsigned int pcic_pin_to_irq(unsigned int pin, char *name); /* diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c --- a/arch/sparc/kernel/process.c 2004-10-18 14:55:55 -07:00 +++ b/arch/sparc/kernel/process.c 2004-10-18 14:55:55 -07:00 @@ -435,8 +435,6 @@ { unsigned long parent_tid_ptr, child_tid_ptr; - clone_flags &= ~CLONE_IDLETASK; - parent_tid_ptr = regs->u_regs[UREG_I2]; child_tid_ptr = regs->u_regs[UREG_I4]; diff -Nru a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c --- a/arch/sparc/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 @@ -614,12 +614,9 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - current->state = TASK_STOPPED; current->thread.flags ^= MAGIC_CONSTANT; - 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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c --- a/arch/sparc/kernel/setup.c 2004-10-18 14:55:54 -07:00 +++ b/arch/sparc/kernel/setup.c 2004-10-18 14:55:54 -07:00 @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c --- a/arch/sparc/kernel/signal.c 2004-10-18 14:56:48 -07:00 +++ b/arch/sparc/kernel/signal.c 2004-10-18 14:56:48 -07:00 @@ -274,7 +274,7 @@ return; segv_and_exit: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } asmlinkage void do_sigreturn(struct pt_regs *regs) @@ -341,7 +341,7 @@ return; segv_and_exit: - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); } asmlinkage void do_rt_sigreturn(struct pt_regs *regs) @@ -401,7 +401,7 @@ spin_unlock_irq(¤t->sighand->siglock); return; segv: - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); } /* Checks if the fp is valid */ @@ -549,7 +549,7 @@ sigill_and_return: do_exit(SIGILL); sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signr, current); } @@ -635,6 +635,7 @@ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 4. signal handler */ regs->pc = (unsigned long) ka->sa.sa_handler; @@ -662,7 +663,7 @@ sigill_and_return: do_exit(SIGILL); sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signo, current); } static inline void @@ -719,6 +720,7 @@ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; regs->pc = (unsigned long) ka->sa.sa_handler; regs->npc = (regs->pc + 4); @@ -744,7 +746,7 @@ sigill: do_exit(SIGILL); sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signo, current); } /* Setup a Solaris stack frame */ @@ -874,7 +876,7 @@ sigill_and_return: do_exit(SIGILL); sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signr, current); } asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs) @@ -887,7 +889,7 @@ synchronize_user_stack(); if (current_thread_info()->w_saved) - goto sigsegv_and_return; + return -EFAULT; err = clear_user(uc, sizeof(*uc)); if (err) @@ -928,9 +930,6 @@ * we have already stuffed all of it with sync_user_stack */ return (err ? -EFAULT : 0); - -sigsegv_and_return: - do_exit(SIGSEGV); } /* Set the context for a svr4 application, this is Solaris way to sigreturn */ @@ -1016,7 +1015,7 @@ return (err ? -EFAULT : 0); sigsegv_and_return: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } static inline void @@ -1034,8 +1033,6 @@ else setup_frame(&ka->sa, regs, signr, oldset, info); } - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -1075,6 +1072,7 @@ { siginfo_t info; struct sparc_deliver_cookie cookie; + struct k_sigaction ka; int signr; /* @@ -1094,15 +1092,12 @@ if (!oldset) oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, regs, &cookie); + signr = get_signal_to_deliver(&info, &ka, regs, &cookie); if (signr > 0) { - struct k_sigaction *ka; - - ka = ¤t->sighand->action[signr-1]; - if (cookie.restart_syscall) - syscall_restart(cookie.orig_i0, regs, &ka->sa); - handle_signal(signr, ka, &info, oldset, regs, svr4_signal); + syscall_restart(cookie.orig_i0, regs, &ka.sa); + handle_signal(signr, &ka, &info, oldset, + regs, svr4_signal); return 1; } if (cookie.restart_syscall && diff -Nru a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c --- a/arch/sparc/kernel/smp.c 2004-10-18 14:56:27 -07:00 +++ b/arch/sparc/kernel/smp.c 2004-10-18 14:56:27 -07:00 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c --- a/arch/sparc/kernel/sparc_ksyms.c 2004-10-18 14:55:54 -07:00 +++ b/arch/sparc/kernel/sparc_ksyms.c 2004-10-18 14:55:54 -07:00 @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -214,6 +213,10 @@ EXPORT_SYMBOL(pci_dma_sync_single_for_device); EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu); EXPORT_SYMBOL(pci_dma_sync_sg_for_device); +EXPORT_SYMBOL(pci_map_sg); +EXPORT_SYMBOL(pci_unmap_sg); +EXPORT_SYMBOL(pci_map_page); +EXPORT_SYMBOL(pci_unmap_page); /* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */ EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(iounmap); @@ -297,6 +300,9 @@ /* Cache flushing. */ EXPORT_SYMBOL(sparc_flush_page_to_ram); + +/* For when serial stuff is built as modules. */ +EXPORT_SYMBOL(sun_do_break); EXPORT_SYMBOL(__ret_efault); diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c --- a/arch/sparc/kernel/sun4d_smp.c 2004-10-18 14:55:55 -07:00 +++ b/arch/sparc/kernel/sun4d_smp.c 2004-10-18 14:55:55 -07:00 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -201,18 +201,9 @@ int no; /* Cook up an idler for this guy. */ - kernel_thread(start_secondary, NULL, CLONE_IDLETASK); - + p = fork_idle(i); cpucount++; - - p = prev_task(&init_task); - - init_idle(p, i); - current_set[i] = p->thread_info; - - unhash_process(p); - for (no = 0; !cpu_find_by_instance(no, NULL, &mid) && mid != i; no++) ; @@ -418,8 +409,6 @@ panic("Bogon SMP message pass."); } -extern void sparc_do_profile(unsigned long pc, unsigned long o7); - void smp4d_percpu_timer_interrupt(struct pt_regs *regs) { int cpu = hard_smp4d_processor_id(); @@ -437,8 +426,7 @@ show_leds(cpu); } - if(!user_mode(regs)) - sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + profile_tick(CPU_PROFILING, regs); if(!--prof_counter(cpu)) { int user = user_mode(regs); diff -Nru a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c --- a/arch/sparc/kernel/sun4m_smp.c 2004-10-18 14:56:50 -07:00 +++ b/arch/sparc/kernel/sun4m_smp.c 2004-10-18 14:56:50 -07:00 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #define IRQ_RESCHEDULE 13 @@ -173,18 +173,9 @@ int timeout; /* Cook up an idler for this guy. */ - kernel_thread(start_secondary, NULL, CLONE_IDLETASK); - + p = fork_idle(i); cpucount++; - - p = prev_task(&init_task); - - init_idle(p, i); - current_set[i] = p->thread_info; - - unhash_process(p); - /* See trampoline.S for details... */ entry += ((i-1) * 3); @@ -400,16 +391,13 @@ ccall_info.processors_out[i] = 1; } -extern void sparc_do_profile(unsigned long pc, unsigned long o7); - void smp4m_percpu_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); clear_profile_irq(cpu); - if(!user_mode(regs)) - sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + profile_tick(CPU_PROFILING, regs); if(!--prof_counter(cpu)) { int user = user_mode(regs); diff -Nru a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S --- a/arch/sparc/kernel/systbls.S 2004-10-18 14:56:32 -07:00 +++ b/arch/sparc/kernel/systbls.S 2004-10-18 14:56:32 -07:00 @@ -74,7 +74,7 @@ /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink -/*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall +/*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .long sys_ni_syscall, sys_ni_syscall, sys_ni_syscall #ifdef CONFIG_SUNOS_EMUL diff -Nru a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c --- a/arch/sparc/kernel/time.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc/kernel/time.c 2004-10-18 14:56:33 -07:00 @@ -79,38 +79,26 @@ #endif -static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; - -/* 32-bit Sparc specific profiling function. */ -void sparc_do_profile(unsigned long pc, unsigned long o7) +unsigned long profile_pc(struct pt_regs *regs) { - if(prof_buffer && current->pid) { - extern int _stext; - extern int __copy_user_begin, __copy_user_end; - extern int __atomic_begin, __atomic_end; - extern int __bzero_begin, __bzero_end; - extern int __bitops_begin, __bitops_end; - - if ((pc >= (unsigned long) &__copy_user_begin && - pc < (unsigned long) &__copy_user_end) || - (pc >= (unsigned long) &__atomic_begin && - pc < (unsigned long) &__atomic_end) || - (pc >= (unsigned long) &__bzero_begin && - pc < (unsigned long) &__bzero_end) || - (pc >= (unsigned long) &__bitops_begin && - pc < (unsigned long) &__bitops_end)) - pc = o7; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - - spin_lock(&ticker_lock); - if(pc < prof_len) - prof_buffer[pc]++; - else - prof_buffer[prof_len - 1]++; - spin_unlock(&ticker_lock); - } + extern char __copy_user_begin[], __copy_user_end[]; + extern char __atomic_begin[], __atomic_end[]; + extern char __bzero_begin[], __bzero_end[]; + extern char __bitops_begin[], __bitops_end[]; + + unsigned long pc = regs->pc; + + if (in_lock_functions(pc) || + (pc >= (unsigned long) __copy_user_begin && + pc < (unsigned long) __copy_user_end) || + (pc >= (unsigned long) __atomic_begin && + pc < (unsigned long) __atomic_end) || + (pc >= (unsigned long) __bzero_begin && + pc < (unsigned long) __bzero_end) || + (pc >= (unsigned long) __bitops_begin && + pc < (unsigned long) __bitops_end)) + pc = regs->u_regs[UREG_RETPC]; + return pc; } __volatile__ unsigned int *master_l10_counter; @@ -129,8 +117,7 @@ static long last_rtc_update; #ifndef CONFIG_SMP - if(!user_mode(regs)) - sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + profile_tick(CPU_PROFILING, regs); #endif /* Protect counter clear so that do_gettimeoffset works */ diff -Nru a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S --- a/arch/sparc/kernel/vmlinux.lds.S 2004-10-18 14:55:54 -07:00 +++ b/arch/sparc/kernel/vmlinux.lds.S 2004-10-18 14:55:54 -07:00 @@ -13,6 +13,7 @@ { *(.text) SCHED_TEXT + LOCK_TEXT *(.gnu.warning) } =0 _etext = .; @@ -46,9 +47,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c --- a/arch/sparc/mm/srmmu.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc/mm/srmmu.c 2004-10-18 14:56:33 -07:00 @@ -1341,7 +1341,7 @@ zones_size[ZONE_HIGHMEM] = npages; zholes_size[ZONE_HIGHMEM] = npages - calc_highpages(); - free_area_init_node(0, &contig_page_data, NULL, zones_size, + free_area_init_node(0, &contig_page_data, zones_size, pfn_base, zholes_size); mem_map = contig_page_data.node_mem_map; } diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c --- a/arch/sparc/mm/sun4c.c 2004-10-18 14:56:49 -07:00 +++ b/arch/sparc/mm/sun4c.c 2004-10-18 14:56:49 -07:00 @@ -379,7 +379,7 @@ extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff; extern unsigned long invalid_segment_patch1_1ff, invalid_segment_patch2_1ff; extern unsigned long num_context_patch1, num_context_patch1_16; -extern unsigned long num_context_patch2, num_context_patch2_16; +extern unsigned long num_context_patch2_16; extern unsigned long vac_linesize_patch, vac_linesize_patch_32; extern unsigned long vac_hwflush_patch1, vac_hwflush_patch1_on; extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on; @@ -2114,7 +2114,7 @@ zones_size[ZONE_HIGHMEM] = npages; zholes_size[ZONE_HIGHMEM] = npages - calc_highpages(); - free_area_init_node(0, &contig_page_data, NULL, zones_size, + free_area_init_node(0, &contig_page_data, zones_size, pfn_base, zholes_size); mem_map = contig_page_data.node_mem_map; } diff -Nru a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig --- a/arch/sparc64/Kconfig 2004-10-18 14:56:50 -07:00 +++ b/arch/sparc64/Kconfig 2004-10-18 14:56:50 -07:00 @@ -12,10 +12,13 @@ bool default y -source "init/Kconfig" +config TIME_INTERPOLATION + bool + default y +source "init/Kconfig" -menu "General setup" +menu "General machine setup" config BBC_I2C tristate "UltraSPARC-III bootbus i2c controller driver" @@ -549,7 +552,6 @@ endmenu - menu "XFree86 DRI support" config DRM @@ -604,113 +606,10 @@ source "arch/sparc64/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_STACK_USAGE - bool "Enable stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - depends 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. - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" - depends on DEBUG_KERNEL - help - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -config DEBUG_DCFLUSH - bool "D-cache flush debugging" - depends on DEBUG_KERNEL - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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 STACK_DEBUG - depends on DEBUG_KERNEL - bool "Stack Overflow Detection Support" - -config DEBUG_BOOTMEM - depends on DEBUG_KERNEL - bool "Debug BOOTMEM initialization" - -# 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 - default y - -config MCOUNT - bool - depends on STACK_DEBUG - default y - -config FRAME_POINTER - bool - depends on MCOUNT - default y - -endmenu +source "arch/sparc64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/Kconfig.debug 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,54 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". + +config DEBUG_DCFLUSH + bool "D-cache flush debugging" + depends on DEBUG_KERNEL + +config STACK_DEBUG + depends on DEBUG_KERNEL + bool "Stack Overflow Detection Support" + +config DEBUG_BOOTMEM + depends on DEBUG_KERNEL + bool "Debug BOOTMEM initialization" + +# 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 + default y + +config MCOUNT + bool + depends on STACK_DEBUG + default y + +config FRAME_POINTER + bool + depends on MCOUNT + default y + +endmenu diff -Nru a/arch/sparc64/Makefile b/arch/sparc64/Makefile --- a/arch/sparc64/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/Makefile 2004-10-18 14:57:04 -07:00 @@ -8,16 +8,16 @@ # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) # -CHECK := $(CHECK) -D__sparc__=1 -D__sparc_v9__=1 +CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -AFLAGS_vmlinux.lds.o += -Usparc +CPPFLAGS_vmlinux.lds += -Usparc CC := $(shell if $(CC) -m64 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo $(CC); else echo sparc64-linux-gcc; fi ) -NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) +NEW_GCC := $(call cc-option-yn, -m64 -mcmodel=medlow) NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; ) -INLINE_LIMIT := $(shell if $(CC) -m64 -finline-limit=100000 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) +INLINE_LIMIT := $(call cc-option-yn, -m64 -finline-limit=100000) export NEW_GCC diff -Nru a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile --- a/arch/sparc64/boot/Makefile 2004-10-18 14:55:53 -07:00 +++ b/arch/sparc64/boot/Makefile 2004-10-18 14:55:53 -07:00 @@ -7,7 +7,7 @@ ROOT_IMG := /usr/src/root.img ELFTOAOUT := elftoaout -host-progs := piggyback +hostprogs-y := piggyback targets := image tftpboot.img vmlinux.aout quiet_cmd_elftoaout = ELF2AOUT $@ diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig 2004-10-18 14:56:28 -07:00 +++ b/arch/sparc64/defconfig 2004-10-18 14:56:28 -07:00 @@ -1,8 +1,11 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3 +# Sun Oct 3 14:28:53 2004 # CONFIG_64BIT=y CONFIG_MMU=y +CONFIG_TIME_INTERPOLATION=y # # Code maturity level options @@ -13,6 +16,7 @@ # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -33,6 +37,8 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -46,7 +52,7 @@ CONFIG_STOP_MACHINE=y # -# General setup +# General machine setup # CONFIG_BBC_I2C=m CONFIG_VT=y @@ -65,6 +71,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=m CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m # CONFIG_CPU_FREQ_24_API is not set CONFIG_SPARC64=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y @@ -118,6 +125,7 @@ # Graphics support # CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y # CONFIG_FB_CIRRUS is not set CONFIG_FB_PM2=y # CONFIG_FB_PM2_FIFO_DISCONNECT is not set @@ -153,7 +161,6 @@ # # Console display driver support # -# CONFIG_MDA_CONSOLE is not set # CONFIG_PROM_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y @@ -217,6 +224,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_UB=m # CONFIG_BLK_DEV_RAM is not set # @@ -251,7 +259,6 @@ # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_IDEDMA_ONLYDISK=y -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set CONFIG_BLK_DEV_ALI15X3=y # CONFIG_WDC_ALI15X3 is not set @@ -328,7 +335,8 @@ # CONFIG_AIC79XX_DEBUG_ENABLE is not set CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y CONFIG_SCSI_SATA_SVW=m CONFIG_SCSI_ATA_PIIX=m @@ -353,9 +361,7 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set -CONFIG_SCSI_IPR=m -# CONFIG_SCSI_IPR_TRACE is not set -# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR is not set CONFIG_SCSI_QLOGIC_ISP=m CONFIG_SCSI_QLOGIC_FC=y CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y @@ -398,6 +404,7 @@ CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m CONFIG_MD_RAID5=m CONFIG_MD_RAID6=m CONFIG_MD_MULTIPATH=m @@ -412,7 +419,6 @@ # CONFIG_FUSION=m CONFIG_FUSION_MAX_SGE=40 -CONFIG_FUSION_ISENSE=m CONFIG_FUSION_CTL=m CONFIG_FUSION_LAN=m @@ -475,6 +481,7 @@ CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_TUNNEL=y # # IP: Virtual Server Configuration @@ -514,6 +521,7 @@ CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -523,6 +531,8 @@ # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_CT_ACCT=y +CONFIG_IP_NF_CT_PROTO_SCTP=m CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m CONFIG_IP_NF_TFTP=m @@ -548,8 +558,15 @@ CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_OWNER=m CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_REALM=m +CONFIG_IP_NF_MATCH_SCTP=m +CONFIG_IP_NF_MATCH_COMMENT=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_NAT=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m @@ -568,18 +585,13 @@ CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_CLASSIFY=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_NOTRACK=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_COMPAT_IPFWADM=m -CONFIG_IP_NF_TARGET_NOTRACK=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_MATCH_REALM=m # # IPv6: Netfilter Configuration @@ -599,6 +611,7 @@ CONFIG_IP6_NF_MATCH_AHESP=m CONFIG_IP6_NF_MATCH_LENGTH=m CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_PHYSDEV=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_TARGET_LOG=m CONFIG_IP6_NF_MANGLE=m @@ -704,6 +717,8 @@ CONFIG_NET_CLS_RSVP6=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y # # Network testing @@ -880,6 +895,7 @@ CONFIG_HAMACHI=m CONFIG_YELLOWFIN=m CONFIG_R8169=m +CONFIG_R8169_NAPI=y CONFIG_SK98LIN=m CONFIG_TIGON3=m @@ -1064,6 +1080,7 @@ # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PARKBD is not set CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m # # Input Device Drivers @@ -1095,6 +1112,7 @@ # CONFIG_I2C_ALGOBIT=y CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m # # I2C Hardware Bus support @@ -1119,6 +1137,7 @@ CONFIG_I2C_VIA=m CONFIG_I2C_VIAPRO=m CONFIG_I2C_VOODOO3=m +CONFIG_I2C_PCA_ISA=m # # Hardware Sensors Chip support @@ -1140,6 +1159,7 @@ CONFIG_SENSORS_LM85=m CONFIG_SENSORS_LM90=m CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_SMSC47M1=m CONFIG_SENSORS_VIA686A=m CONFIG_SENSORS_W83781D=m CONFIG_SENSORS_W83L785TS=m @@ -1262,6 +1282,7 @@ CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m CONFIG_SMB_FS=m # CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m @@ -1473,6 +1494,7 @@ CONFIG_SND_AC97_CODEC=m CONFIG_SND_ALI5451=m CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m CONFIG_SND_AU8810=m CONFIG_SND_AU8820=m CONFIG_SND_AU8830=m @@ -1512,6 +1534,7 @@ # ALSA USB devices # # CONFIG_SND_USB_AUDIO is not set +CONFIG_SND_USB_USX2Y=m # # ALSA Sparc devices @@ -1531,6 +1554,7 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -1596,7 +1620,6 @@ # CONFIG_USB_IBMCAM is not set # CONFIG_USB_KONICAWC is not set # CONFIG_USB_OV511 is not set -CONFIG_USB_PWC=m # CONFIG_USB_SE401 is not set CONFIG_USB_SN9C102=m # CONFIG_USB_STV680 is not set @@ -1733,14 +1756,15 @@ # Kernel hacking # CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_SLAB is not set CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_DCFLUSH is not set # CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_KPROBES=y +# CONFIG_DEBUG_DCFLUSH is not set # CONFIG_STACK_DEBUG is not set # CONFIG_DEBUG_BOOTMEM is not set CONFIG_HAVE_DEC_LOCK=y @@ -1761,6 +1785,7 @@ CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile --- a/arch/sparc64/kernel/Makefile 2004-10-18 14:56:17 -07:00 +++ b/arch/sparc64/kernel/Makefile 2004-10-18 14:56:17 -07:00 @@ -5,7 +5,7 @@ EXTRA_AFLAGS := -ansi EXTRA_CFLAGS := -Werror -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ traps.o devices.o auxio.o \ @@ -22,6 +22,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o +obj-$(CONFIG_KPROBES) += kprobes.o ifdef CONFIG_SUNOS_EMUL obj-y += sys_sunos32.o sunos_ioctl32.o diff -Nru a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c --- a/arch/sparc64/kernel/auxio.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc64/kernel/auxio.c 2004-10-18 14:56:33 -07:00 @@ -17,7 +17,7 @@ #include /* This cannot be static, as it is referenced in entry.S */ -unsigned long auxio_register = 0UL; +void __iomem *auxio_register = 0UL; enum auxio_type { AUXIO_TYPE_NODEV, @@ -30,7 +30,7 @@ static void __auxio_sbus_set(u8 bits_on, u8 bits_off) { - if(auxio_register) { + if (auxio_register) { unsigned char regval; unsigned long flags; unsigned char newval; @@ -49,7 +49,7 @@ static void __auxio_ebus_set(u8 bits_on, u8 bits_off) { - if(auxio_register) { + if (auxio_register) { unsigned char regval; unsigned long flags; unsigned char newval; @@ -126,7 +126,8 @@ if (sdev) { auxio_devtype = AUXIO_TYPE_SBUS; auxio_register = sbus_ioremap(&sdev->resource[0], 0, - sdev->reg_addrs[0].reg_size, "auxiliaryIO"); + sdev->reg_addrs[0].reg_size, + "auxiliaryIO"); } #ifdef CONFIG_PCI else { @@ -142,7 +143,7 @@ ebus_done: if (edev) { auxio_devtype = AUXIO_TYPE_EBUS; - auxio_register = (unsigned long) + auxio_register = ioremap(edev->resource[0].start, sizeof(u32)); } } diff -Nru a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c --- a/arch/sparc64/kernel/binfmt_elf32.c 2004-10-18 14:56:50 -07:00 +++ b/arch/sparc64/kernel/binfmt_elf32.c 2004-10-18 14:56:50 -07:00 @@ -27,12 +27,12 @@ #define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ do { unsigned int *dest = &(__elf_regs[0]); \ struct pt_regs *src = (__pt_regs); \ - unsigned int *sp; \ + unsigned int __user *sp; \ int i; \ for(i = 0; i < 16; i++) \ dest[i] = (unsigned int) src->u_regs[i];\ /* Don't try this at home kids... */ \ - sp = (unsigned int *) (src->u_regs[14] & \ + sp = (unsigned int __user *) (src->u_regs[14] & \ 0x00000000fffffffc); \ for(i = 0; i < 16; i++) \ __get_user(dest[i+16], &sp[i]); \ diff -Nru a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c --- a/arch/sparc64/kernel/chmc.c 2004-10-18 14:56:27 -07:00 +++ b/arch/sparc64/kernel/chmc.c 2004-10-18 14:56:27 -07:00 @@ -72,7 +72,7 @@ struct obp_mem_layout layout_prop; int layout_size; - void *regs; + void __iomem *regs; u64 timing_control1; u64 timing_control2; diff -Nru a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S --- a/arch/sparc64/kernel/etrap.S 2004-10-18 14:56:28 -07:00 +++ b/arch/sparc64/kernel/etrap.S 2004-10-18 14:56:28 -07:00 @@ -17,7 +17,8 @@ #define TASK_REGOFF (THREAD_SIZE-TRACEREG_SZ-STACKFRAME_SZ) #define ETRAP_PSTATE1 (PSTATE_RMO | PSTATE_PRIV) -#define ETRAP_PSTATE2 (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE) +#define ETRAP_PSTATE2 \ + (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE) /* * On entry, %g7 is return address - 0x4. @@ -27,91 +28,91 @@ .text .align 64 .globl etrap, etrap_irq, etraptl1 -etrap: rdpr %pil, %g2 ! Single Group +etrap: rdpr %pil, %g2 etrap_irq: - rdpr %tstate, %g1 ! Single Group - sllx %g2, 20, %g3 ! IEU0 Group - andcc %g1, TSTATE_PRIV, %g0 ! IEU1 - or %g1, %g3, %g1 ! IEU0 Group - bne,pn %xcc, 1f ! CTI - sub %sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2 ! IEU1 - wrpr %g0, 7, %cleanwin ! Single Group+4bubbles - - sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group - sethi %hi(TSTATE_PEF), %g3 ! IEU1 - or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group - and %g1, %g3, %g3 ! IEU1 - brnz,pn %g3, 1f ! CTI+IEU1 Group - add %g6, %g2, %g2 ! IEU0 - wr %g0, 0, %fprs ! Single Group+4bubbles -1: rdpr %tpc, %g3 ! Single Group - - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] ! Store Group - rdpr %tnpc, %g1 ! Single Group - stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] ! Store Group - rd %y, %g3 ! Single Group+4bubbles - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] ! Store Group - st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] ! Store Group - save %g2, -STACK_BIAS, %sp ! Ordering here is critical ! Single Group - mov %g6, %l6 ! IEU0 Group - - bne,pn %xcc, 3f ! CTI - mov PRIMARY_CONTEXT, %l4 ! IEU1 - rdpr %canrestore, %g3 ! Single Group+4bubbles - rdpr %wstate, %g2 ! Single Group+4bubbles - wrpr %g0, 0, %canrestore ! Single Group+4bubbles - sll %g2, 3, %g2 ! IEU0 Group - mov 1, %l5 ! IEU1 - stb %l5, [%l6 + TI_FPDEPTH] ! Store - - wrpr %g3, 0, %otherwin ! Single Group+4bubbles - wrpr %g2, 0, %wstate ! Single Group+4bubbles - stxa %g0, [%l4] ASI_DMMU ! Store Group - flush %l6 ! Single Group+9bubbles - wr %g0, ASI_AIUS, %asi ! Single Group+4bubbles -2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles - mov %g4, %l4 ! IEU1 - mov %g5, %l5 ! IEU0 Group - - mov %g7, %l2 ! IEU1 - wrpr %g0, ETRAP_PSTATE1, %pstate ! Single Group+4bubbles - stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] ! Store Group - stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] ! Store Group - stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] ! Store Group - stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] ! Store Group - stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] ! Store Group - stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] ! Store Group - - stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] ! Store Group - stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] ! Store Group - stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] ! Store Group - stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] ! Store Group - stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] ! Store Group - stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] ! Store Group - stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] ! Store Group - - stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] ! Store Group - stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] ! Store Group - wrpr %g0, ETRAP_PSTATE2, %pstate ! Single Group+4bubbles - mov %l6, %g6 ! IEU0 - jmpl %l2 + 0x4, %g0 ! CTI Group - ldx [%g6 + TI_TASK], %g4 ! Load + rdpr %tstate, %g1 + sllx %g2, 20, %g3 + andcc %g1, TSTATE_PRIV, %g0 + or %g1, %g3, %g1 + bne,pn %xcc, 1f + sub %sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2 + wrpr %g0, 7, %cleanwin + + sethi %hi(TASK_REGOFF), %g2 + sethi %hi(TSTATE_PEF), %g3 + or %g2, %lo(TASK_REGOFF), %g2 + and %g1, %g3, %g3 + brnz,pn %g3, 1f + add %g6, %g2, %g2 + wr %g0, 0, %fprs +1: rdpr %tpc, %g3 + + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] + rdpr %tnpc, %g1 + stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] + rd %y, %g3 + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] + st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] + save %g2, -STACK_BIAS, %sp ! Ordering here is critical + mov %g6, %l6 + + bne,pn %xcc, 3f + mov PRIMARY_CONTEXT, %l4 + rdpr %canrestore, %g3 + rdpr %wstate, %g2 + wrpr %g0, 0, %canrestore + sll %g2, 3, %g2 + mov 1, %l5 + stb %l5, [%l6 + TI_FPDEPTH] + + wrpr %g3, 0, %otherwin + wrpr %g2, 0, %wstate + stxa %g0, [%l4] ASI_DMMU + flush %l6 + wr %g0, ASI_AIUS, %asi +2: wrpr %g0, 0x0, %tl + mov %g4, %l4 + mov %g5, %l5 + + mov %g7, %l2 + wrpr %g0, ETRAP_PSTATE1, %pstate + stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] + stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] + stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] + stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] + stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] + stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] + + stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] + stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] + stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] + stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] + stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] + stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] + stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] + + stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] + stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] + wrpr %g0, ETRAP_PSTATE2, %pstate + mov %l6, %g6 + jmpl %l2 + 0x4, %g0 + ldx [%g6 + TI_TASK], %g4 nop nop nop -3: ldub [%l6 + TI_FPDEPTH], %l5 ! Load Group - add %l6, TI_FPSAVED + 1, %l4 ! IEU0 - srl %l5, 1, %l3 ! IEU0 Group - add %l5, 2, %l5 ! IEU1 - stb %l5, [%l6 + TI_FPDEPTH] ! Store - ba,pt %xcc, 2b ! CTI - stb %g0, [%l4 + %l3] ! Store Group +3: ldub [%l6 + TI_FPDEPTH], %l5 + add %l6, TI_FPSAVED + 1, %l4 + srl %l5, 1, %l3 + add %l5, 2, %l5 + stb %l5, [%l6 + TI_FPDEPTH] + ba,pt %xcc, 2b + stb %g0, [%l4 + %l3] nop etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. - * We place this right after pt_regs on the trap stack. The layout - * is: + * We place this right after pt_regs on the trap stack. + * The layout is: * 0x00 TL1's TSTATE * 0x08 TL1's TPC * 0x10 TL1's TNPC @@ -166,81 +167,81 @@ wrpr %g1, %tl stx %g1, [%g2 + STACK_BIAS + 0x80] - rdpr %tstate, %g1 ! Single Group+4bubbles - sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 - ba,pt %xcc, 1b ! CTI Group - andcc %g1, TSTATE_PRIV, %g0 ! IEU0 + rdpr %tstate, %g1 + sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2 + ba,pt %xcc, 1b + andcc %g1, TSTATE_PRIV, %g0 .align 64 .globl scetrap -scetrap: rdpr %pil, %g2 ! Single Group - rdpr %tstate, %g1 ! Single Group - sllx %g2, 20, %g3 ! IEU0 Group - andcc %g1, TSTATE_PRIV, %g0 ! IEU1 - or %g1, %g3, %g1 ! IEU0 Group - bne,pn %xcc, 1f ! CTI - sub %sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2 ! IEU1 - wrpr %g0, 7, %cleanwin ! Single Group+4bubbles - - sllx %g1, 51, %g3 ! IEU0 Group - sethi %hi(TASK_REGOFF), %g2 ! IEU1 - or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group - brlz,pn %g3, 1f ! CTI+IEU1 - add %g6, %g2, %g2 ! IEU0 Group - wr %g0, 0, %fprs ! Single Group+4bubbles -1: rdpr %tpc, %g3 ! Single Group - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] ! Store Group - - rdpr %tnpc, %g1 ! Single Group - stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] ! Store Group - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] ! Store Group - save %g2, -STACK_BIAS, %sp ! Ordering here is critical ! Single Group - mov %g6, %l6 ! IEU0 Group - bne,pn %xcc, 2f ! CTI - mov ASI_P, %l7 ! IEU1 - rdpr %canrestore, %g3 ! Single Group+4bubbles - - rdpr %wstate, %g2 ! Single Group+4bubbles - wrpr %g0, 0, %canrestore ! Single Group+4bubbles - sll %g2, 3, %g2 ! IEU0 Group - mov PRIMARY_CONTEXT, %l4 ! IEU1 - wrpr %g3, 0, %otherwin ! Single Group+4bubbles - wrpr %g2, 0, %wstate ! Single Group+4bubbles - stxa %g0, [%l4] ASI_DMMU ! Store - flush %l6 ! Single Group+9bubbles - - mov ASI_AIUS, %l7 ! IEU0 Group -2: mov %g4, %l4 ! IEU1 - mov %g5, %l5 ! IEU0 Group - add %g7, 0x4, %l2 ! IEU1 - wrpr %g0, ETRAP_PSTATE1, %pstate ! Single Group+4bubbles - stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] ! Store Group - stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] ! Store Group - sllx %l7, 24, %l7 ! IEU0 - - stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] ! Store Group - rdpr %cwp, %l0 ! Single Group - stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] ! Store Group - stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] ! Store Group - stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] ! Store Group - stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] ! Store Group - or %l7, %l0, %l7 ! IEU0 - sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 ! IEU1 - - or %l7, %l0, %l7 ! IEU0 Group - wrpr %l2, %tnpc ! Single Group+4bubbles - wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate ! Single Group+4bubbles - stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] ! Store Group - stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] ! Store Group - stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] ! Store Group - stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] ! Store Group - stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] ! Store Group - - stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] ! Store Group - stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] ! Store Group - mov %l6, %g6 ! IEU1 - stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] ! Store Group - ldx [%g6 + TI_TASK], %g4 ! Load Group +scetrap: rdpr %pil, %g2 + rdpr %tstate, %g1 + sllx %g2, 20, %g3 + andcc %g1, TSTATE_PRIV, %g0 + or %g1, %g3, %g1 + bne,pn %xcc, 1f + sub %sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2 + wrpr %g0, 7, %cleanwin + + sllx %g1, 51, %g3 + sethi %hi(TASK_REGOFF), %g2 + or %g2, %lo(TASK_REGOFF), %g2 + brlz,pn %g3, 1f + add %g6, %g2, %g2 + wr %g0, 0, %fprs +1: rdpr %tpc, %g3 + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] + + rdpr %tnpc, %g1 + stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] + save %g2, -STACK_BIAS, %sp ! Ordering here is critical + mov %g6, %l6 + bne,pn %xcc, 2f + mov ASI_P, %l7 + rdpr %canrestore, %g3 + + rdpr %wstate, %g2 + wrpr %g0, 0, %canrestore + sll %g2, 3, %g2 + mov PRIMARY_CONTEXT, %l4 + wrpr %g3, 0, %otherwin + wrpr %g2, 0, %wstate + stxa %g0, [%l4] ASI_DMMU + flush %l6 + + mov ASI_AIUS, %l7 +2: mov %g4, %l4 + mov %g5, %l5 + add %g7, 0x4, %l2 + wrpr %g0, ETRAP_PSTATE1, %pstate + stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] + stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] + sllx %l7, 24, %l7 + + stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] + rdpr %cwp, %l0 + stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] + stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] + stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] + stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] + or %l7, %l0, %l7 + sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 + + or %l7, %l0, %l7 + wrpr %l2, %tnpc + wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate + stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] + stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] + stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] + stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] + stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] + + stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] + stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] + mov %l6, %g6 + stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] + ldx [%g6 + TI_TASK], %g4 done nop nop diff -Nru a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S --- a/arch/sparc64/kernel/head.S 2004-10-18 14:56:28 -07:00 +++ b/arch/sparc64/kernel/head.S 2004-10-18 14:56:28 -07:00 @@ -50,6 +50,7 @@ */ .global root_flags, ram_flags, root_dev .global sparc_ramdisk_image, sparc_ramdisk_size + .global sparc_ramdisk_image64 .ascii "HdrS" .word LINUX_VERSION_CODE @@ -60,7 +61,7 @@ * 0x0202 : Supports kernel params string * 0x0201 : Supports reboot_command */ - .half 0x0300 /* HdrS version */ + .half 0x0301 /* HdrS version */ root_flags: .half 1 @@ -74,6 +75,8 @@ .word 0 .xword reboot_command .xword bootstr_info +sparc_ramdisk_image64: + .xword 0 .word _end /* We must be careful, 32-bit OpenBOOT will get confused if it diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c --- a/arch/sparc64/kernel/irq.c 2004-10-18 14:57:03 -07:00 +++ b/arch/sparc64/kernel/irq.c 2004-10-18 14:57:03 -07:00 @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -791,16 +790,24 @@ #endif if ((flags & IBF_MULTI) == 0) { struct irqaction *ap = bp->irq_info; - ap->handler(__irq(bp), ap->dev_id, regs); - random |= ap->flags & SA_SAMPLE_RANDOM; + int ret; + + ret = ap->handler(__irq(bp), ap->dev_id, regs); + if (ret == IRQ_HANDLED) + random |= ap->flags; } else { void **vector = (void **)bp->irq_info; int ent; for (ent = 0; ent < 4; ent++) { struct irqaction *ap = vector[ent]; if (ap != NULL) { - ap->handler(__irq(bp), ap->dev_id, regs); - random |= ap->flags & SA_SAMPLE_RANDOM; + int ret; + + ret = ap->handler(__irq(bp), + ap->dev_id, + regs); + if (ret == IRQ_HANDLED) + random |= ap->flags; } } } @@ -813,8 +820,9 @@ } #endif upa_writel(ICLR_IDLE, bp->iclr); + /* Test and add entropy */ - if (random) + if (random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); } } else diff -Nru a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/kernel/kprobes.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,373 @@ +/* arch/sparc64/kernel/kprobes.c + * + * Copyright (C) 2004 David S. Miller + */ + +#include +#include +#include + +#include +#include + +/* We do not have hardware single-stepping on sparc64. + * So we implement software single-stepping with breakpoint + * traps. The top-level scheme is similar to that used + * in the x86 kprobes implementation. + * + * In the kprobe->insn[] array we store the original + * instruction at index zero and a break instruction at + * index one. + * + * When we hit a kprobe we: + * - Run the pre-handler + * - Remember "regs->tnpc" and interrupt level stored in + * "regs->tstate" so we can restore them later + * - Disable PIL interrupts + * - Set regs->tpc to point to kprobe->insn[0] + * - Set regs->tnpc to point to kprobe->insn[1] + * - Mark that we are actively in a kprobe + * + * At this point we wait for the second breakpoint at + * kprobe->insn[1] to hit. When it does we: + * - Run the post-handler + * - Set regs->tpc to "remembered" regs->tnpc stored above, + * restore the PIL interrupt level in "regs->tstate" as well + * - Make any adjustments necessary to regs->tnpc in order + * to handle relative branches correctly. See below. + * - Mark that we are no longer actively in a kprobe. + */ + +void arch_prepare_kprobe(struct kprobe *p) +{ + p->insn[0] = *p->addr; + p->insn[1] = BREAKPOINT_INSTRUCTION_2; +} + +/* kprobe_status settings */ +#define KPROBE_HIT_ACTIVE 0x00000001 +#define KPROBE_HIT_SS 0x00000002 + +static struct kprobe *current_kprobe; +static unsigned long current_kprobe_orig_tnpc; +static unsigned long current_kprobe_orig_tstate_pil; +static unsigned int kprobe_status; + +static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + current_kprobe_orig_tnpc = regs->tnpc; + current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); + regs->tstate |= TSTATE_PIL; + + regs->tpc = (unsigned long) &p->insn[0]; + regs->tnpc = (unsigned long) &p->insn[1]; +} + +static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + *p->addr = p->opcode; + flushi(p->addr); + + regs->tpc = (unsigned long) p->addr; + regs->tnpc = current_kprobe_orig_tnpc; + regs->tstate = ((regs->tstate & ~TSTATE_PIL) | + current_kprobe_orig_tstate_pil); +} + +static int kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + void *addr = (void *) regs->tpc; + int ret = 0; + + preempt_disable(); + + if (kprobe_running()) { + /* We *are* holding lock here, so this is safe. + * Disarm the probe we just hit, and ignore it. + */ + p = get_kprobe(addr); + if (p) { + disarm_kprobe(p, regs); + ret = 1; + } else { + p = current_kprobe; + if (p->break_handler && p->break_handler(p, regs)) + goto ss_probe; + } + /* If it's not ours, can't be delete race, (we hold lock). */ + goto no_kprobe; + } + + lock_kprobes(); + p = get_kprobe(addr); + if (!p) { + unlock_kprobes(); + if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) { + /* + * The breakpoint instruction was removed right + * after we hit it. Another cpu has removed + * either a probepoint or a debugger breakpoint + * at this address. In either case, no further + * handling of this interrupt is appropriate. + */ + ret = 1; + } + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + kprobe_status = KPROBE_HIT_ACTIVE; + current_kprobe = p; + if (p->pre_handler(p, regs)) + return 1; + +ss_probe: + prepare_singlestep(p, regs); + kprobe_status = KPROBE_HIT_SS; + return 1; + +no_kprobe: + preempt_enable_no_resched(); + return ret; +} + +/* If INSN is a relative control transfer instruction, + * return the corrected branch destination value. + * + * The original INSN location was REAL_PC, it actually + * executed at PC and produced destination address NPC. + */ +static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc, + unsigned long pc, unsigned long npc) +{ + /* Branch not taken, no mods necessary. */ + if (npc == pc + 0x4UL) + return real_pc + 0x4UL; + + /* The three cases are call, branch w/prediction, + * and traditional branch. + */ + if ((insn & 0xc0000000) == 0x40000000 || + (insn & 0xc1c00000) == 0x00400000 || + (insn & 0xc1c00000) == 0x00800000) { + /* The instruction did all the work for us + * already, just apply the offset to the correct + * instruction location. + */ + return (real_pc + (npc - pc)); + } + + return real_pc + 0x4UL; +} + +/* If INSN is an instruction which writes it's PC location + * into a destination register, fix that up. + */ +static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc) +{ + unsigned long *slot = NULL; + + /* Simplest cast is call, which always uses %o7 */ + if ((insn & 0xc0000000) == 0x40000000) { + slot = ®s->u_regs[UREG_I7]; + } + + /* Jmpl encodes the register inside of the opcode */ + if ((insn & 0xc1f80000) == 0x81c00000) { + unsigned long rd = ((insn >> 25) & 0x1f); + + if (rd <= 15) { + slot = ®s->u_regs[rd]; + } else { + /* Hard case, it goes onto the stack. */ + flushw_all(); + + rd -= 16; + slot = (unsigned long *) + (regs->u_regs[UREG_FP] + STACK_BIAS); + slot += rd; + } + } + if (slot != NULL) + *slot = real_pc; +} + +/* + * Called after single-stepping. p->addr is the address of the + * instruction whose first byte has been replaced by the breakpoint + * instruction. To avoid the SMP problems that can occur when we + * temporarily put back the original opcode to single-step, we + * single-stepped a copy of the instruction. The address of this + * copy is p->insn. + * + * This function prepares to return from the post-single-step + * breakpoint trap. + */ +static void resume_execution(struct kprobe *p, struct pt_regs *regs) +{ + u32 insn = p->insn[0]; + + regs->tpc = current_kprobe_orig_tnpc; + regs->tnpc = relbranch_fixup(insn, + (unsigned long) p->addr, + (unsigned long) &p->insn[0], + regs->tnpc); + retpc_fixup(regs, insn, (unsigned long) p->addr); + + regs->tstate = ((regs->tstate & ~TSTATE_PIL) | + current_kprobe_orig_tstate_pil); +} + +static inline int post_kprobe_handler(struct pt_regs *regs) +{ + if (!kprobe_running()) + return 0; + + if (current_kprobe->post_handler) + current_kprobe->post_handler(current_kprobe, regs, 0); + + resume_execution(current_kprobe, regs); + + unlock_kprobes(); + preempt_enable_no_resched(); + + return 1; +} + +/* Interrupts disabled, kprobe_lock held. */ +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + if (current_kprobe->fault_handler + && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + return 1; + + if (kprobe_status & KPROBE_HIT_SS) { + resume_execution(current_kprobe, regs); + + unlock_kprobes(); + preempt_enable_no_resched(); + } + return 0; +} + +/* + * Wrapper routine to for handling exceptions. + */ +int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, + void *data) +{ + struct die_args *args = (struct die_args *)data; + switch (val) { + case DIE_DEBUG: + if (kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_DEBUG_2: + if (post_kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_GPF: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + case DIE_PAGE_FAULT: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + default: + break; + } + return NOTIFY_DONE; +} + +asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs) +{ + BUG_ON(trap_level != 0x170 && trap_level != 0x171); + + if (user_mode(regs)) { + local_irq_enable(); + bad_trap(regs, trap_level); + return; + } + + /* trap_level == 0x170 --> ta 0x70 + * trap_level == 0x171 --> ta 0x71 + */ + if (notify_die((trap_level == 0x170) ? DIE_DEBUG : DIE_DEBUG_2, + (trap_level == 0x170) ? "debug" : "debug_2", + regs, 0, trap_level, SIGTRAP) != NOTIFY_STOP) + bad_trap(regs, trap_level); +} + +/* Jprobes support. */ +static struct pt_regs jprobe_saved_regs; +static struct pt_regs *jprobe_saved_regs_location; +static struct sparc_stackf jprobe_saved_stack; + +int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + + jprobe_saved_regs_location = regs; + memcpy(&jprobe_saved_regs, regs, sizeof(*regs)); + + /* Save a whole stack frame, this gets arguments + * pushed onto the stack after using up all the + * arg registers. + */ + memcpy(&jprobe_saved_stack, + (char *) (regs->u_regs[UREG_FP] + STACK_BIAS), + sizeof(jprobe_saved_stack)); + + regs->tpc = (unsigned long) jp->entry; + regs->tnpc = ((unsigned long) jp->entry) + 0x4UL; + regs->tstate |= TSTATE_PIL; + + return 1; +} + +void jprobe_return(void) +{ + preempt_enable_no_resched(); + __asm__ __volatile__( + ".globl jprobe_return_trap_instruction\n" +"jprobe_return_trap_instruction:\n\t" + "ta 0x70"); +} + +extern void jprobe_return_trap_instruction(void); + +extern void __show_regs(struct pt_regs * regs); + +int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +{ + u32 *addr = (u32 *) regs->tpc; + + if (addr == (u32 *) jprobe_return_trap_instruction) { + if (jprobe_saved_regs_location != regs) { + printk("JPROBE: Current regs (%p) does not match " + "saved regs (%p).\n", + regs, jprobe_saved_regs_location); + printk("JPROBE: Saved registers\n"); + __show_regs(jprobe_saved_regs_location); + printk("JPROBE: Current registers\n"); + __show_regs(regs); + BUG(); + } + /* Restore old register state. Do pt_regs + * first so that UREG_FP is the original one for + * the stack frame restore. + */ + memcpy(regs, &jprobe_saved_regs, sizeof(*regs)); + + memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS), + &jprobe_saved_stack, + sizeof(jprobe_saved_stack)); + + return 1; + } + return 0; +} diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c --- a/arch/sparc64/kernel/pci.c 2004-10-18 14:55:46 -07:00 +++ b/arch/sparc64/kernel/pci.c 2004-10-18 14:55:46 -07:00 @@ -41,7 +41,6 @@ #else /* List of all PCI controllers found in the system. */ -spinlock_t pci_controller_lock = SPIN_LOCK_UNLOCKED; struct pci_controller_info *pci_controller_root = NULL; /* Each PCI controller found gets a unique index. */ @@ -298,12 +297,9 @@ static void __init pci_scan_each_controller_bus(void) { struct pci_controller_info *p; - unsigned long flags; - spin_lock_irqsave(&pci_controller_lock, flags); for (p = pci_controller_root; p; p = p->next) p->scan_bus(p); - spin_unlock_irqrestore(&pci_controller_lock, flags); } /* Reorder the pci_dev chain, so that onboard devices come first @@ -350,10 +346,6 @@ } subsys_initcall(pcibios_init); - -struct pci_fixup pcibios_fixups[] = { - { 0 } -}; void pcibios_fixup_bus(struct pci_bus *pbus) { diff -Nru a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c --- a/arch/sparc64/kernel/pci_common.c 2004-10-18 14:56:21 -07:00 +++ b/arch/sparc64/kernel/pci_common.c 2004-10-18 14:56:21 -07:00 @@ -15,18 +15,13 @@ */ void __init pci_fixup_host_bridge_self(struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; - - walk = walk->next; - while (walk != &pbus->devices) { - struct pci_dev *pdev = pci_dev_b(walk); + struct pci_dev *pdev; + list_for_each_entry(pdev, &pbus->devices, bus_list) { if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) { pbus->self = pdev; return; } - - walk = walk->next; } prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n"); @@ -217,31 +212,18 @@ struct pci_pbm_info *pbm, int prom_node) { - struct list_head *walk = &pbus->devices; - - /* This loop is coded like this because the cookie - * fillin routine can delete devices from the tree. - */ - walk = walk->next; - while (walk != &pbus->devices) { - struct pci_dev *pdev = pci_dev_b(walk); - struct list_head *walk_next = walk->next; + struct pci_dev *pdev, *pdev_next; + struct pci_bus *this_pbus, *pbus_next; + /* This must be _safe because the cookie fillin + routine can delete devices from the tree. */ + list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list) pdev_cookie_fillin(pbm, pdev, prom_node); - walk = walk_next; - } - - walk = &pbus->children; - walk = walk->next; - while (walk != &pbus->children) { - struct pci_bus *this_pbus = pci_bus_b(walk); + list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) { struct pcidev_cookie *pcp = this_pbus->self->sysdata; - struct list_head *walk_next = walk->next; pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node); - - walk = walk_next; } } @@ -431,14 +413,14 @@ void __init pci_record_assignments(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_record_assignments(pbm, pci_dev_b(walk)); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_record_assignments(pbm, dev); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_record_assignments(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_record_assignments(pbm, bus); } /* Return non-zero if PDEV has implicit I/O resources even @@ -549,14 +531,14 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_assign_unassigned(pbm, pci_dev_b(walk)); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_assign_unassigned(pbm, dev); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_assign_unassigned(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_assign_unassigned(pbm, bus); } static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) @@ -797,14 +779,14 @@ void __init pci_fixup_irq(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_fixup_irq(pci_dev_b(walk)); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_fixup_irq(dev); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_fixup_irq(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_fixup_irq(pbm, bus); } static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) @@ -897,7 +879,7 @@ void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk; + struct pci_dev *pdev; int all_are_66mhz; u16 status; @@ -906,11 +888,8 @@ goto out; } - walk = &pbus->devices; all_are_66mhz = 1; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); - + list_for_each_entry(pdev, &pbus->devices, bus_list) { pci_read_config_word(pdev, PCI_STATUS, &status); if (!(status & PCI_STATUS_66MHZ)) { all_are_66mhz = 0; @@ -929,17 +908,17 @@ void pci_setup_busmastering(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; int is_66mhz; is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_setup_busmastering(pci_dev_b(walk), is_66mhz); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_setup_busmastering(dev, is_66mhz); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_setup_busmastering(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_setup_busmastering(pbm, bus); } void pci_register_legacy_regions(struct resource *io_res, @@ -987,10 +966,10 @@ struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *pdev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &pbus->devices, bus_list) { u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -1005,19 +984,18 @@ } } - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_scan_for_target_abort(p, pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_scan_for_target_abort(p, pbm, bus); } void pci_scan_for_master_abort(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *pdev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &pbus->devices, bus_list) { u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -1031,19 +1009,18 @@ } } - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_scan_for_master_abort(p, pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_scan_for_master_abort(p, pbm, bus); } void pci_scan_for_parity_error(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *pdev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &pbus->devices, bus_list) { u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -1058,7 +1035,6 @@ } } - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_scan_for_parity_error(p, pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_scan_for_parity_error(p, pbm, bus); } diff -Nru a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h --- a/arch/sparc64/kernel/pci_impl.h 2004-10-18 14:56:32 -07:00 +++ b/arch/sparc64/kernel/pci_impl.h 2004-10-18 14:56:32 -07:00 @@ -11,7 +11,6 @@ #include #include -extern spinlock_t pci_controller_lock; extern struct pci_controller_info *pci_controller_root; extern int pci_num_controllers; diff -Nru a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c --- a/arch/sparc64/kernel/pci_iommu.c 2004-10-18 14:55:55 -07:00 +++ b/arch/sparc64/kernel/pci_iommu.c 2004-10-18 14:55:55 -07:00 @@ -56,6 +56,39 @@ } } +#define IOPTE_CONSISTENT(CTX) \ + (IOPTE_VALID | IOPTE_CACHE | \ + (((CTX) << 47) & IOPTE_CONTEXT)) + +#define IOPTE_STREAMING(CTX) \ + (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) + +/* Existing mappings are never marked invalid, instead they + * are pointed to a dummy page. + */ +#define IOPTE_IS_DUMMY(iommu, iopte) \ + ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa) + +static void inline iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) +{ + unsigned long val = iopte_val(*iopte); + + val &= ~IOPTE_PAGE; + val |= iommu->dummy_page_pa; + + iopte_val(*iopte) = val; +} + +void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize) +{ + int i; + + tsbsize /= sizeof(iopte_t); + + for (i = 0; i < tsbsize; i++) + iopte_make_dummy(iommu, &iommu->page_table[i]); +} + static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages) { iopte_t *iopte, *limit, *first; @@ -79,7 +112,7 @@ first = iopte; for (;;) { - if (iopte_val(*iopte) == 0UL) { + if (IOPTE_IS_DUMMY(iommu, iopte)) { if ((iopte + (1 << cnum)) >= limit) ent = 0; else @@ -142,12 +175,12 @@ iopte = iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)); while (iopte > iommu->page_table) { iopte--; - if (!(iopte_val(*iopte) & IOPTE_VALID)) { + if (IOPTE_IS_DUMMY(iommu, iopte)) { unsigned long tmp = npages; while (--tmp) { iopte--; - if (iopte_val(*iopte) & IOPTE_VALID) + if (!IOPTE_IS_DUMMY(iommu, iopte)) break; } if (tmp == 0) { @@ -162,15 +195,6 @@ return NULL; } -#define IOPTE_CONSISTENT(CTX) \ - (IOPTE_VALID | IOPTE_CACHE | \ - (((CTX) << 47) & IOPTE_CONTEXT)) - -#define IOPTE_STREAMING(CTX) \ - (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) - -#define IOPTE_INVALID 0UL - /* Allocate and map kernel buffer of size SIZE using consistent mode * DMA for PCI device PDEV. Return non-NULL cpu-side address if * successful and set *DMA_ADDRP to the PCI side dma address. @@ -261,7 +285,7 @@ limit = (iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); while (walk < limit) { - if (iopte_val(*walk) != IOPTE_INVALID) + if (!IOPTE_IS_DUMMY(iommu, walk)) break; walk++; } @@ -280,7 +304,7 @@ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; for (i = 0; i < npages; i++, iopte++) - iopte_val(*iopte) = IOPTE_INVALID; + iopte_make_dummy(iommu, iopte); if (iommu->iommu_ctxflush) { pci_iommu_write(iommu->iommu_ctxflush, ctx); @@ -376,7 +400,7 @@ base = iommu->page_table + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU - if (iopte_val(*base) == IOPTE_INVALID) + if (IOPTE_IS_DUMMY(iommu, base)) printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", bus_addr, sz, __builtin_return_address(0)); #endif @@ -415,7 +439,7 @@ } /* Step 2: Clear out first TSB entry. */ - iopte_val(*base) = IOPTE_INVALID; + iopte_make_dummy(iommu, base); free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); @@ -611,7 +635,7 @@ ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU - if (iopte_val(*base) == IOPTE_INVALID) + if (IOPTE_IS_DUMMY(iommu, base)) printk("pci_unmap_sg called on non-mapped region %016lx,%d from %016lx\n", sglist->dma_address, nelems, __builtin_return_address(0)); #endif @@ -648,7 +672,7 @@ } /* Step 2: Clear out first TSB entry. */ - iopte_val(*base) = IOPTE_INVALID; + iopte_make_dummy(iommu, base); free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); diff -Nru a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c --- a/arch/sparc64/kernel/pci_psycho.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc64/kernel/pci_psycho.c 2004-10-18 14:56:33 -07:00 @@ -1076,17 +1076,17 @@ * bits for each PBM. */ tmp = psycho_read(base + PSYCHO_PCIA_CTRL); - tmp |= (PSYCHO_PCICTRL_SBH_ERR | - PSYCHO_PCICTRL_SERR | - PSYCHO_PCICTRL_SBH_INT | + tmp |= (PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); + tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIA_CTRL, tmp); tmp = psycho_read(base + PSYCHO_PCIB_CTRL); - tmp |= (PSYCHO_PCICTRL_SBH_ERR | - PSYCHO_PCICTRL_SERR | - PSYCHO_PCICTRL_SBH_INT | + tmp |= (PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); + tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIB_CTRL, tmp); } @@ -1241,6 +1241,14 @@ * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. @@ -1254,7 +1262,7 @@ iommu->page_table_sz_bits = 17; iommu->page_table_map_base = 0xc0000000; iommu->dma_addr_mask = 0xffffffff; - memset((char *)tsbbase, 0, IO_TSB_SIZE); + pci_iommu_table_init(iommu, IO_TSB_SIZE); /* We start with no consistent mappings. */ iommu->lowest_consistent_map = @@ -1479,22 +1487,18 @@ struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; struct pci_iommu *iommu; - unsigned long flags; u32 upa_portid; int is_pbm_a, err; upa_portid = prom_getintdefault(node, "upa-portid", 0xff); - spin_lock_irqsave(&pci_controller_lock, flags); for(p = pci_controller_root; p; p = p->next) { if (p->pbm_A.portid == upa_portid) { - spin_unlock_irqrestore(&pci_controller_lock, flags); is_pbm_a = (p->pbm_A.prom_node == 0); psycho_pbm_init(p, node, is_pbm_a); return; } } - spin_unlock_irqrestore(&pci_controller_lock, flags); p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); if (!p) { @@ -1510,10 +1514,8 @@ memset(iommu, 0, sizeof(*iommu)); p->pbm_A.iommu = p->pbm_B.iommu = iommu; - spin_lock_irqsave(&pci_controller_lock, flags); p->next = pci_controller_root; pci_controller_root = p; - spin_unlock_irqrestore(&pci_controller_lock, flags); p->pbm_A.portid = upa_portid; p->pbm_B.portid = upa_portid; diff -Nru a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c --- a/arch/sparc64/kernel/pci_sabre.c 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/kernel/pci_sabre.c 2004-10-18 14:57:04 -07:00 @@ -1113,10 +1113,9 @@ static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) { - struct list_head *walk = &sabre_bus->devices; + struct pci_dev *pdev; - for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &sabre_bus->devices, bus_list) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { @@ -1178,10 +1177,9 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) { static int once; - struct pci_bus *sabre_bus; + struct pci_bus *sabre_bus, *pbus; struct pci_pbm_info *pbm; struct pcidev_cookie *cookie; - struct list_head *walk; int sabres_scanned; /* The APB bridge speaks to the Sabre host PCI bridge @@ -1217,9 +1215,7 @@ sabres_scanned = 0; - walk = &sabre_bus->children; - for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) { - struct pci_bus *pbus = pci_bus_b(walk); + list_for_each_entry(pbus, &sabre_bus->children, node) { if (pbus->number == p->pbm_A.pci_first_busno) { pbm = &p->pbm_A; @@ -1293,6 +1289,14 @@ * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8)); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); @@ -1301,7 +1305,7 @@ iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = dvma_offset; iommu->dma_addr_mask = dma_mask; - memset((char *)tsbbase, 0, PAGE_SIZE << order); + pci_iommu_table_init(iommu, PAGE_SIZE << order); sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); @@ -1546,7 +1550,6 @@ struct linux_prom64_registers pr_regs[2]; struct pci_controller_info *p; struct pci_iommu *iommu; - unsigned long flags; int tsbsize, err; u32 busrange[2]; u32 vdma[2]; @@ -1594,10 +1597,8 @@ upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); - spin_lock_irqsave(&pci_controller_lock, flags); p->next = pci_controller_root; pci_controller_root = p; - spin_unlock_irqrestore(&pci_controller_lock, flags); p->pbm_A.portid = upa_portid; p->pbm_B.portid = upa_portid; diff -Nru a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c --- a/arch/sparc64/kernel/pci_schizo.c 2004-10-18 14:56:48 -07:00 +++ b/arch/sparc64/kernel/pci_schizo.c 2004-10-18 14:56:48 -07:00 @@ -1171,7 +1171,7 @@ prom_halt(); } bucket = __bucket(irq); - tmp = readl(bucket->imap); + tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); @@ -1309,7 +1309,7 @@ prom_halt(); } bucket = __bucket(irq); - tmp = readl(bucket->imap); + tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_CE_INO); @@ -1372,10 +1372,10 @@ SCHIZO_PCICTRL_RTRY_ERR | SCHIZO_PCICTRL_SBH_ERR | SCHIZO_PCICTRL_SERR | - SCHIZO_PCICTRL_SBH_INT | SCHIZO_PCICTRL_EEN); - err_no_mask = SCHIZO_PCICTRL_DTO_ERR; + err_no_mask = (SCHIZO_PCICTRL_DTO_ERR | + SCHIZO_PCICTRL_SBH_INT); /* Enable PCI Error interrupts and clear error * bits for each PBM. @@ -1766,6 +1766,14 @@ * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. @@ -1780,7 +1788,7 @@ iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = vdma[0]; iommu->dma_addr_mask = dma_mask; - memset((char *)tsbbase, 0, PAGE_SIZE << order); + pci_iommu_table_init(iommu, PAGE_SIZE << order); switch (tsbsize) { case 64: @@ -2073,13 +2081,11 @@ { struct pci_controller_info *p; struct pci_iommu *iommu; - unsigned long flags; int is_pbm_a; u32 portid; portid = prom_getintdefault(node, "portid", 0xff); - spin_lock_irqsave(&pci_controller_lock, flags); for(p = pci_controller_root; p; p = p->next) { struct pci_pbm_info *pbm; @@ -2091,13 +2097,11 @@ &p->pbm_B); if (portid_compare(pbm->portid, portid, chip_type)) { - spin_unlock_irqrestore(&pci_controller_lock, flags); is_pbm_a = (p->pbm_A.prom_node == 0); schizo_pbm_init(p, node, portid, chip_type); return; } } - spin_unlock_irqrestore(&pci_controller_lock, flags); p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); if (!p) { @@ -2122,10 +2126,8 @@ memset(iommu, 0, sizeof(*iommu)); p->pbm_B.iommu = iommu; - spin_lock_irqsave(&pci_controller_lock, flags); p->next = pci_controller_root; pci_controller_root = p; - spin_unlock_irqrestore(&pci_controller_lock, flags); p->index = pci_num_controllers++; p->pbms_same_domain = 0; diff -Nru a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c --- a/arch/sparc64/kernel/power.c 2004-10-18 14:57:03 -07:00 +++ b/arch/sparc64/kernel/power.c 2004-10-18 14:57:03 -07:00 @@ -27,7 +27,7 @@ int scons_pwroff = 1; #ifdef CONFIG_PCI -static unsigned long power_reg = 0UL; +static void __iomem *power_reg; static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); static int button_pressed; @@ -52,7 +52,7 @@ { if (!serial_console || scons_pwroff) { #ifdef CONFIG_PCI - if (power_reg != 0UL) { + if (power_reg) { /* Both register bits seem to have the * same effect, so until I figure out * what the difference is... @@ -130,8 +130,8 @@ return; found: - power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4); - printk("power: Control reg at %016lx ... ", power_reg); + power_reg = ioremap(edev->resource[0].start, 0x4); + printk("power: Control reg at %p ... ", power_reg); poweroff_method = machine_halt; /* able to use the standard halt */ if (has_button_interrupt(edev)) { if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { @@ -141,8 +141,7 @@ printk("powerd running.\n"); if (request_irq(edev->irqs[0], - power_handler, SA_SHIRQ, "power", - (void *) power_reg) < 0) + power_handler, SA_SHIRQ, "power", NULL) < 0) printk("power: Error, cannot register IRQ handler.\n"); } else { printk("not using powerd.\n"); diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c --- a/arch/sparc64/kernel/process.c 2004-10-18 14:56:29 -07:00 +++ b/arch/sparc64/kernel/process.c 2004-10-18 14:56:29 -07:00 @@ -588,8 +588,6 @@ { int __user *parent_tid_ptr, *child_tid_ptr; - clone_flags &= ~CLONE_IDLETASK; - #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_32BIT)) { parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]); diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c --- a/arch/sparc64/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/kernel/ptrace.c 2004-10-18 14:57:04 -07:00 @@ -627,11 +627,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - 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 -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c --- a/arch/sparc64/kernel/setup.c 2004-10-18 14:56:28 -07:00 +++ b/arch/sparc64/kernel/setup.c 2004-10-18 14:56:28 -07:00 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c --- a/arch/sparc64/kernel/signal.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc64/kernel/signal.c 2004-10-18 14:56:33 -07:00 @@ -84,8 +84,8 @@ regs->tnpc = npc; err |= __get_user(regs->y, &((*grp)[MC_Y])); err |= __get_user(tstate, &((*grp)[MC_TSTATE])); - regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); - regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); + regs->tstate &= ~(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC); + regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)); err |= __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); err |= __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2])); err |= __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3])); @@ -135,7 +135,7 @@ return; do_sigsegv: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } asmlinkage void sparc64_get_context(struct pt_regs *regs) @@ -226,7 +226,7 @@ return; do_sigsegv: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } struct rt_signal_frame { @@ -408,9 +408,9 @@ err |= __get_user(tstate, &sf->regs.tstate); err |= copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs)); - /* User can only change condition codes in %tstate. */ - regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); - regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); + /* User can only change condition codes and %asi in %tstate. */ + regs->tstate &= ~(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC); + regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)); err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -439,7 +439,7 @@ spin_unlock_irq(¤t->sighand->siglock); return; segv: - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); } /* Checks if the fp is valid */ @@ -545,6 +545,12 @@ regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + /* The sigcontext is passed in this way because of how it + * is defined in GLIBC's /usr/include/bits/sigcontext.h + * for sparc64. It includes the 128 bytes of siginfo_t. + */ + regs->u_regs[UREG_I2] = (unsigned long) &sf->info; + /* 5. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); @@ -559,7 +565,7 @@ sigill: do_exit(SIGILL); sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signo, current); } static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, @@ -568,8 +574,6 @@ { setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -609,6 +613,7 @@ { siginfo_t info; struct signal_deliver_cookie cookie; + struct k_sigaction ka; int signr; cookie.restart_syscall = restart_syscall; @@ -626,15 +631,11 @@ } #endif - signr = get_signal_to_deliver(&info, regs, &cookie); + signr = get_signal_to_deliver(&info, &ka, regs, &cookie); if (signr > 0) { - struct k_sigaction *ka; - - ka = ¤t->sighand->action[signr-1]; - if (cookie.restart_syscall) - syscall_restart(orig_i0, regs, &ka->sa); - handle_signal(signr, ka, &info, oldset, regs); + syscall_restart(orig_i0, regs, &ka.sa); + handle_signal(signr, &ka, &info, oldset, regs); return 1; } if (cookie.restart_syscall && diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c --- a/arch/sparc64/kernel/signal32.c 2004-10-18 14:55:53 -07:00 +++ b/arch/sparc64/kernel/signal32.c 2004-10-18 14:55:53 -07:00 @@ -59,6 +59,16 @@ unsigned int extramask[_COMPAT_NSIG_WORDS - 1]; }; +/* This magic should be in g_upper[0] for all upper parts + * to be valid. + */ +#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269 +typedef struct { + unsigned int g_upper[8]; + unsigned int o_upper[8]; + unsigned int asi; +} siginfo_extra_v8plus_t; + /* * And the new one, intended to be used for Linux applications only * (we have enough in there to work with clone). @@ -76,9 +86,61 @@ __siginfo_fpu_t fpu_state; }; +struct siginfo32 { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE32]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + sigval_t32 _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + sigval_t32 _sigval; + } _rt; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ + struct { + u32 _addr; /* faulting insn/memory ref. */ + int _trapno; + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +}; + struct rt_signal_frame32 { struct sparc_stackf32 ss; - siginfo_t32 info; + struct siginfo32 info; struct pt_regs32 regs; compat_sigset_t mask; /* __siginfo_fpu32_t * */ u32 fpu_save; @@ -95,11 +157,11 @@ #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) -int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) +int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from) { int err; - if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok(VERIFY_WRITE, to, sizeof(struct siginfo32))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -119,7 +181,7 @@ case __SI_TIMER >> 16: err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user((u32)(u64)from->si_ptr, &to->si_ptr); + err |= __put_user(from->si_int, &to->si_int); break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); @@ -145,6 +207,22 @@ return err; } +/* CAUTION: This is just a very minimalist implementation for the + * sake of compat_sys_rt_sigqueueinfo() + */ +int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from) +{ + if (!access_ok(VERIFY_WRITE, from, sizeof(struct siginfo32))) + return -EFAULT; + + if (copy_from_user(to, from, 3*sizeof(int)) || + copy_from_user(to->_sifields._pad, from->_sifields._pad, + SI_PAD_SIZE)) + return -EFAULT; + + return 0; +} + /* * atomically swap in the new signal mask, and wait for a signal. * This is really tricky on the Sparc, watch out... @@ -299,8 +377,13 @@ if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { err |= __get_user(i, &sf->v8plus.g_upper[0]); if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + unsigned long asi; + for (i = UREG_G1; i <= UREG_I7; i++) err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __get_user(asi, &sf->v8plus.asi); + regs->tstate &= ~TSTATE_ASI; + regs->tstate |= ((asi & 0xffUL) << 24UL); } } @@ -330,7 +413,7 @@ return; segv: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } asmlinkage void do_sigreturn32(struct pt_regs *regs) @@ -400,7 +483,7 @@ return; segv: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) @@ -447,8 +530,13 @@ if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { err |= __get_user(i, &sf->v8plus.g_upper[0]); if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + unsigned long asi; + for (i = UREG_G1; i <= UREG_I7; i++) err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __get_user(asi, &sf->v8plus.asi); + regs->tstate &= ~TSTATE_ASI; + regs->tstate |= ((asi & 0xffUL) << 24UL); } } @@ -487,7 +575,7 @@ spin_unlock_irq(¤t->sighand->siglock); return; segv: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } /* Checks if the fp is valid */ @@ -648,7 +736,7 @@ return; sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signr, current); } @@ -715,7 +803,10 @@ err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size); err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]); for (i = 1; i < 16; i++) - err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __put_user(((u32 *)regs->u_regs)[2*i], + &sf->v8plus.g_upper[i]); + err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL, + &sf->v8plus.asi); if (psr & PSR_EF) { err |= save_fpu_state32(regs, &sf->fpu_state); @@ -749,6 +840,7 @@ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 4. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; @@ -795,7 +887,7 @@ sigill: do_exit(SIGILL); sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signo, current); } /* Setup a Solaris stack frame */ @@ -919,7 +1011,7 @@ return; sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signr, current); } asmlinkage int @@ -1070,7 +1162,7 @@ return -EINTR; sigsegv: - do_exit(SIGSEGV); + return -EFAULT; } static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, @@ -1119,6 +1211,8 @@ for (i = 1; i < 16; i++) err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL, + &sf->v8plus.asi); if (psr & PSR_EF) { err |= save_fpu_state32(regs, &sf->fpu_state); @@ -1157,6 +1251,7 @@ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signr; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; /* 4. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; @@ -1206,7 +1301,7 @@ sigill: do_exit(SIGILL); sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signr, current); } static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, @@ -1225,8 +1320,6 @@ else setup_frame32(&ka->sa, regs, signr, oldset, info); } - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -1266,21 +1359,19 @@ { siginfo_t info; struct signal_deliver_cookie cookie; + struct k_sigaction ka; int signr; int svr4_signal = current->personality == PER_SVR4; cookie.restart_syscall = restart_syscall; cookie.orig_i0 = orig_i0; - signr = get_signal_to_deliver(&info, regs, &cookie); + signr = get_signal_to_deliver(&info, &ka, regs, &cookie); if (signr > 0) { - struct k_sigaction *ka; - - ka = ¤t->sighand->action[signr-1]; - if (cookie.restart_syscall) - syscall_restart32(orig_i0, regs, &ka->sa); - handle_signal32(signr, ka, &info, oldset, regs, svr4_signal); + syscall_restart32(orig_i0, regs, &ka.sa); + handle_signal32(signr, &ka, &info, oldset, + regs, svr4_signal); return 1; } if (cookie.restart_syscall && diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c --- a/arch/sparc64/kernel/smp.c 2004-10-18 14:55:53 -07:00 +++ b/arch/sparc64/kernel/smp.c 2004-10-18 14:55:53 -07:00 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -303,14 +303,7 @@ struct task_struct *p; int timeout, ret, cpu_node; - kernel_thread(NULL, NULL, CLONE_IDLETASK); - - p = prev_task(&init_task); - - init_idle(p, cpu); - - unhash_process(p); - + p = fork_idle(cpu); callin_flag = 0; cpu_new_thread = p->thread_info; cpu_set(cpu, cpu_callout_map); @@ -981,8 +974,6 @@ smp_cross_call(&xcall_promstop, 0, 0, 0); } -extern void sparc64_do_profile(struct pt_regs *regs); - #define prof_multiplier(__cpu) cpu_data(__cpu).multiplier #define prof_counter(__cpu) cpu_data(__cpu).counter @@ -1008,7 +999,7 @@ } do { - sparc64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); if (!--prof_counter(cpu)) { irq_enter(); diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c 2004-10-18 14:56:49 -07:00 +++ b/arch/sparc64/kernel/sparc64_ksyms.c 2004-10-18 14:56:49 -07:00 @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -74,8 +73,6 @@ extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); -extern int __strncmp(const char *, const char *, __kernel_size_t); -extern __kernel_size_t __strlen(const char *); extern __kernel_size_t strlen(const char *); extern void linux_sparc_syscall(void); extern void rtrap(void); @@ -144,7 +141,7 @@ #if defined(CONFIG_MCOUNT) extern void _mcount(void); -EXPORT_SYMBOL_NOVERS(_mcount); +EXPORT_SYMBOL(_mcount); #endif /* CPU online map and active count. */ @@ -187,8 +184,6 @@ EXPORT_SYMBOL(___test_and_set_bit); EXPORT_SYMBOL(___test_and_clear_bit); EXPORT_SYMBOL(___test_and_change_bit); -EXPORT_SYMBOL(___test_and_set_le_bit); -EXPORT_SYMBOL(___test_and_clear_le_bit); /* Bit searching */ EXPORT_SYMBOL(find_next_bit); @@ -295,7 +290,6 @@ EXPORT_SYMBOL(__prom_getsibling); /* sparc library symbols */ -EXPORT_SYMBOL(__strlen); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(__strlen_user); @@ -334,7 +328,6 @@ #endif /* Special internal versions of library functions. */ -EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(copy_user_page); @@ -342,8 +335,7 @@ EXPORT_SYMBOL(__memscan_zero); EXPORT_SYMBOL(__memscan_generic); EXPORT_SYMBOL(__memcmp); -EXPORT_SYMBOL(__strncmp); -EXPORT_SYMBOL(__memmove); +EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(csum_partial); @@ -351,9 +343,12 @@ EXPORT_SYMBOL(ip_fast_csum); /* Moving data to/from/in userspace. */ -EXPORT_SYMBOL(__copy_to_user); -EXPORT_SYMBOL(__copy_from_user); -EXPORT_SYMBOL(__copy_in_user); +EXPORT_SYMBOL(___copy_to_user); +EXPORT_SYMBOL(___copy_from_user); +EXPORT_SYMBOL(___copy_in_user); +EXPORT_SYMBOL(copy_to_user_fixup); +EXPORT_SYMBOL(copy_from_user_fixup); +EXPORT_SYMBOL(copy_in_user_fixup); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__bzero_noasi); @@ -367,17 +362,24 @@ /* No version information on this, heavily used in inline asm, * and will always be 'void __ret_efault(void)'. */ -EXPORT_SYMBOL_NOVERS(__ret_efault); +EXPORT_SYMBOL(__ret_efault); /* No version information on these, as gcc produces such symbols. */ -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strncmp); + +/* Delay routines. */ +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(__ndelay); +EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL(__delay); void VISenter(void); /* RAID code needs this */ -EXPORT_SYMBOL_NOVERS(VISenter); +EXPORT_SYMBOL(VISenter); /* for input/keybdev */ EXPORT_SYMBOL(sun_do_break); diff -Nru a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S --- a/arch/sparc64/kernel/sys32.S 2004-10-18 14:56:16 -07:00 +++ b/arch/sparc64/kernel/sys32.S 2004-10-18 14:56:16 -07:00 @@ -120,7 +120,7 @@ SIGN2(sys32_setpgid, sys_setpgid, %o0, %o1) SIGN3(sys32_setpriority, sys_setpriority, %o0, %o1, %o2) SIGN1(sys32_ssetmask, sys_ssetmask, %o0) -SIGN2(sys32_syslog, sys_syslog, %o0, %o1) +SIGN2(sys32_syslog, sys_syslog, %o0, %o2) SIGN1(sys32_umask, sys_umask, %o0) SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2) SIGN1(sys32_sendto, sys_sendto, %o0) diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c --- a/arch/sparc64/kernel/sys_sparc32.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc64/kernel/sys_sparc32.c 2004-10-18 14:56:33 -07:00 @@ -1045,7 +1045,7 @@ } asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, - siginfo_t32 __user *uinfo, + struct siginfo32 __user *uinfo, struct compat_timespec __user *uts, compat_size_t sigsetsize) { @@ -1130,15 +1130,15 @@ } asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, - siginfo_t32 __user *uinfo) + struct siginfo32 __user *uinfo) { siginfo_t info; int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info, uinfo, 3*sizeof(int)) || - copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) + if (copy_siginfo_to_kernel32(&info, uinfo)) return -EFAULT; + set_fs (KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); set_fs (old_fs); @@ -1736,3 +1736,33 @@ return err; } +asmlinkage long compat_sys_waitid(u32 which, u32 pid, + struct siginfo32 __user *uinfo, u32 options, + struct compat_rusage __user *uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + memset(&info, 0, sizeof(info)); + + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, + options, + uru ? (struct rusage __user *) &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru) { + ret = put_compat_rusage(&ru, uru); + if (ret) + return ret; + } + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return copy_siginfo_to_user32(uinfo, &info); +} diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S --- a/arch/sparc64/kernel/systbls.S 2004-10-18 14:56:29 -07:00 +++ b/arch/sparc64/kernel/systbls.S 2004-10-18 14:56:29 -07:00 @@ -75,7 +75,7 @@ /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink - .word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, sys_ni_syscall + .word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall #endif /* CONFIG_COMPAT */ @@ -141,7 +141,7 @@ /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink - .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall + .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c --- a/arch/sparc64/kernel/time.c 2004-10-18 14:56:31 -07:00 +++ b/arch/sparc64/kernel/time.c 2004-10-18 14:56:31 -07:00 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,18 @@ #define TICK_PRIV_BIT (1UL << 63) +#ifdef CONFIG_SMP +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (in_lock_functions(pc)) + return regs->u_regs[UREG_RETPC]; + return pc; +} +EXPORT_SYMBOL(profile_pc); +#endif + static void tick_disable_protection(void) { /* Set things up so user can access tick register for profiling @@ -418,7 +431,6 @@ unsigned long timer_tick_offset; unsigned long timer_tick_compare; -static unsigned long timer_ticks_per_usec_quotient; static unsigned long timer_ticks_per_nsec_quotient; #define TICK_SIZE (tick_nsec / 1000) @@ -441,28 +453,6 @@ } } -void sparc64_do_profile(struct pt_regs *regs) -{ - unsigned long pc; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - pc = regs->tpc; - - pc -= (unsigned long) _stext; - pc >>= prof_shift; - - if(pc >= prof_len) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { unsigned long ticks, pstate; @@ -471,7 +461,7 @@ do { #ifndef CONFIG_SMP - sparc64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #endif do_timer(regs); @@ -920,10 +910,10 @@ } /* This is gets the master TICK_INT timer going. */ -static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +static unsigned long sparc64_init_timers(void) { - unsigned long pstate, clock; - int node, err; + unsigned long clock; + int node; #ifdef CONFIG_SMP extern void smp_tick_init(void); #endif @@ -956,6 +946,14 @@ smp_tick_init(); #endif + return clock; +} + +static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +{ + unsigned long pstate; + int err; + /* Register IRQ handler. */ err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC, "timer", NULL); @@ -981,8 +979,6 @@ : "r" (pstate)); local_irq_enable(); - - return clock; } struct freq_table { @@ -1034,18 +1030,27 @@ static struct notifier_block sparc64_cpufreq_notifier_block = { .notifier_call = sparc64_cpufreq_notifier }; -#endif + +#endif /* CONFIG_CPU_FREQ */ + +static struct time_interpolator sparc64_cpu_interpolator = { + .source = TIME_SOURCE_CPU, + .shift = 16, +}; /* The quotient formula is taken from the IA64 port. */ -#define SPARC64_USEC_PER_CYC_SHIFT 30UL #define SPARC64_NSEC_PER_CYC_SHIFT 30UL void __init time_init(void) { - unsigned long clock = sparc64_init_timers(timer_interrupt); + unsigned long clock = sparc64_init_timers(); - timer_ticks_per_usec_quotient = - (((1000000UL << SPARC64_USEC_PER_CYC_SHIFT) + - (clock / 2)) / clock); + sparc64_cpu_interpolator.frequency = clock; + register_time_interpolator(&sparc64_cpu_interpolator); + + /* Now that the interpolator is registered, it is + * safe to start the timer ticking. + */ + sparc64_start_timers(timer_interrupt); timer_ticks_per_nsec_quotient = (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + @@ -1057,17 +1062,6 @@ #endif } -static __inline__ unsigned long do_gettimeoffset(void) -{ - unsigned long ticks = tick_ops->get_tick(); - - ticks += timer_tick_offset; - ticks -= timer_tick_compare; - - return (ticks * timer_ticks_per_usec_quotient) - >> SPARC64_USEC_PER_CYC_SHIFT; -} - unsigned long long sched_clock(void) { unsigned long ticks = tick_ops->get_tick(); @@ -1075,100 +1069,6 @@ return (ticks * timer_ticks_per_nsec_quotient) >> SPARC64_NSEC_PER_CYC_SHIFT; } - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - if (this_is_starfire) - return 0; - - write_seqlock_irq(&xtime_lock); - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * made, and then undo it! - */ - nsec -= do_gettimeoffset() * 1000; - nsec -= (jiffies - wall_jiffies) * (NSEC_PER_SEC / HZ); - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - -/* Ok, my cute asm atomicity trick doesn't work anymore. - * There are just too many variables that need to be protected - * now (both members of xtime, wall_jiffies, et al.) - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long seq; - unsigned long usec, sec; - unsigned long max_ntp_tick = tick_usec - tickadj; - - do { - unsigned long lost; - - seq = read_seqbegin(&xtime_lock); - usec = do_gettimeoffset(); - lost = jiffies - wall_jiffies; - - /* - * If time_adjust is negative then NTP is slowing the clock - * so make sure not to go into next possible interval. - * Better to lose some accuracy than have time go backwards.. - */ - if (unlikely(time_adjust < 0)) { - usec = min(usec, max_ntp_tick); - - if (lost) - usec += lost * max_ntp_tick; - } - else if (unlikely(lost)) - usec += lost * tick_usec; - - sec = xtime.tv_sec; - - /* Believe it or not, this divide shows up on - * kernel profiles. The problem is that it is - * both 64-bit and signed. Happily, 32-bits - * of precision is all we really need and in - * doing so gcc ends up emitting a cheap multiply. - * - * XXX Why is tv_nsec 'long' and 'signed' in - * XXX the first place, can it even be negative? - */ - usec += ((unsigned int) xtime.tv_nsec / 1000U); - } while (read_seqretry(&xtime_lock, seq)); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); static int set_rtc_mmss(unsigned long nowtime) { diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c --- a/arch/sparc64/kernel/traps.c 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/kernel/traps.c 2004-10-18 14:57:04 -07:00 @@ -36,10 +36,24 @@ #include #include #include +#include #ifdef CONFIG_KMOD #include #endif +struct notifier_block *sparc64die_chain; +static spinlock_t die_notifier_lock = SPIN_LOCK_UNLOCKED; + +int register_die_notifier(struct notifier_block *nb) +{ + int err = 0; + unsigned long flags; + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&sparc64die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + return err; +} + /* When an irrecoverable trap occurs at tl > 0, the trap entry * code logs the trap state registers at every level in the trap * stack. It is found at (pt_regs + sizeof(pt_regs)) and the layout @@ -71,11 +85,20 @@ } } -void bad_trap (struct pt_regs *regs, long lvl) +void do_call_debug(struct pt_regs *regs) +{ + notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); +} + +void bad_trap(struct pt_regs *regs, long lvl) { char buffer[32]; siginfo_t info; + if (notify_die(DIE_TRAP, "bad trap", regs, + 0, lvl, SIGTRAP) == NOTIFY_STOP) + return; + if (lvl < 0x100) { sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl); die_if_kernel(buffer, regs); @@ -84,7 +107,7 @@ lvl -= 0x100; if (regs->tstate & TSTATE_PRIV) { sprintf(buffer, "Kernel bad sw trap %lx", lvl); - die_if_kernel (buffer, regs); + die_if_kernel(buffer, regs); } if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; @@ -98,10 +121,14 @@ force_sig_info(SIGILL, &info, current); } -void bad_trap_tl1 (struct pt_regs *regs, long lvl) +void bad_trap_tl1(struct pt_regs *regs, long lvl) { char buffer[32]; + if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs, + 0, lvl, SIGTRAP) == NOTIFY_STOP) + return; + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); sprintf (buffer, "Bad trap %lx at tl>0", lvl); @@ -121,6 +148,10 @@ { siginfo_t info; + if (notify_die(DIE_TRAP, "instruction access exception", regs, + 0, 0x8, SIGTRAP) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) { printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", sfsr, sfar); @@ -141,15 +172,23 @@ void instruction_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { + if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs, + 0, 0x8, SIGTRAP) == NOTIFY_STOP) + return; + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); instruction_access_exception(regs, sfsr, sfar); } -void data_access_exception (struct pt_regs *regs, - unsigned long sfsr, unsigned long sfar) +void data_access_exception(struct pt_regs *regs, + unsigned long sfsr, unsigned long sfar) { siginfo_t info; + if (notify_die(DIE_TRAP, "data access exception", regs, + 0, 0x30, SIGTRAP) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) { /* Test if this comes from uaccess places. */ unsigned long fixup; @@ -220,6 +259,10 @@ spitfire_clean_and_reenable_l1_caches(); + if (notify_die(DIE_TRAP, "instruction access exception", regs, + 0, 0x8, SIGTRAP) == NOTIFY_STOP) + return; + info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_OBJERR; @@ -230,6 +273,8 @@ void do_dae(struct pt_regs *regs) { + siginfo_t info; + #ifdef CONFIG_PCI if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { spitfire_clean_and_reenable_l1_caches(); @@ -244,7 +289,18 @@ return; } #endif - do_iae(regs); + spitfire_clean_and_reenable_l1_caches(); + + if (notify_die(DIE_TRAP, "data access exception", regs, + 0, 0x30, SIGTRAP) == NOTIFY_STOP) + return; + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_OBJERR; + info.si_addr = (void *)0; + info.si_trapno = 0; + force_sig_info(SIGBUS, &info, current); } static char ecc_syndrome_table[] = { @@ -1638,6 +1694,10 @@ void do_fpieee(struct pt_regs *regs) { + if (notify_die(DIE_TRAP, "fpu exception ieee", regs, + 0, 0x24, SIGFPE) == NOTIFY_STOP) + return; + do_fpe_common(regs); } @@ -1648,6 +1708,10 @@ struct fpustate *f = FPUSTATE; int ret = 0; + if (notify_die(DIE_TRAP, "fpu exception other", regs, + 0, 0x25, SIGFPE) == NOTIFY_STOP) + return; + switch ((current_thread_info()->xfsr[0] & 0x1c000)) { case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ @@ -1663,6 +1727,10 @@ { siginfo_t info; + if (notify_die(DIE_TRAP, "tagged arithmetic overflow", regs, + 0, 0x26, SIGEMT) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) die_if_kernel("Penguin overflow trap from kernel mode", regs); if (test_thread_flag(TIF_32BIT)) { @@ -1681,6 +1749,10 @@ { siginfo_t info; + if (notify_die(DIE_TRAP, "integer division by zero", regs, + 0, 0x28, SIGFPE) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) die_if_kernel("TL0: Kernel divide by zero.", regs); if (test_thread_flag(TIF_32BIT)) { @@ -1771,6 +1843,37 @@ EXPORT_SYMBOL(dump_stack); +static inline int is_kernel_stack(struct task_struct *task, + struct reg_window *rw) +{ + unsigned long rw_addr = (unsigned long) rw; + unsigned long thread_base, thread_end; + + if (rw_addr < PAGE_OFFSET) { + if (task != &init_task) + return 0; + } + + thread_base = (unsigned long) task->thread_info; + thread_end = thread_base + sizeof(union thread_union); + if (rw_addr >= thread_base && + rw_addr < thread_end && + !(rw_addr & 0x7UL)) + return 1; + + return 0; +} + +static inline struct reg_window *kernel_stack_up(struct reg_window *rw) +{ + unsigned long fp = rw->ins[6]; + + if (!fp) + return NULL; + + return (struct reg_window *) (fp + STACK_BIAS); +} + void die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; @@ -1786,6 +1889,7 @@ " \\__U_/\n"); printk("%s(%d): %s [#%d]\n", current->comm, current->pid, str, ++die_counter); + notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV); __asm__ __volatile__("flushw"); __show_regs(regs); if (regs->tstate & TSTATE_PRIV) { @@ -1795,17 +1899,14 @@ /* Stop the back trace when we hit userland or we * find some badly aligned kernel stack. */ - while (rw && - count++ < 30 && - (((unsigned long) rw) >= PAGE_OFFSET) && - (char *) rw < ((char *) current) - + sizeof (union thread_union) && - !(((unsigned long) rw) & 0x7)) { + while (rw && + count++ < 30&& + is_kernel_stack(current, rw)) { printk("Caller[%016lx]", rw->ins[7]); print_symbol(": %s", rw->ins[7]); printk("\n"); - rw = (struct reg_window *) - (rw->ins[6] + STACK_BIAS); + + rw = kernel_stack_up(rw); } instruction_dump ((unsigned int *) regs->tpc); } else { @@ -1834,6 +1935,10 @@ u32 insn; siginfo_t info; + if (notify_die(DIE_TRAP, "illegal instruction", regs, + 0, 0x10, SIGILL) == NOTIFY_STOP) + return; + if (tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); if (test_thread_flag(TIF_32BIT)) @@ -1859,6 +1964,10 @@ { siginfo_t info; + if (notify_die(DIE_TRAP, "memory address unaligned", regs, + 0, 0x34, SIGSEGV) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) { extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, @@ -1880,6 +1989,10 @@ void do_privop(struct pt_regs *regs) { siginfo_t info; + + if (notify_die(DIE_TRAP, "privileged operation", regs, + 0, 0x11, SIGILL) == NOTIFY_STOP) + return; if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; diff -Nru a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S --- a/arch/sparc64/kernel/ttable.S 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc64/kernel/ttable.S 2004-10-18 14:56:33 -07:00 @@ -158,7 +158,7 @@ tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) tl0_linux64: LINUX_64BIT_SYSCALL_TRAP tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) -tl0_resv170: BTRAP(0x170) BTRAP(0x171) BTRAP(0x172) +tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) BTRAP(0x172) tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177) tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) diff -Nru a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S --- a/arch/sparc64/kernel/vmlinux.lds.S 2004-10-18 14:56:50 -07:00 +++ b/arch/sparc64/kernel/vmlinux.lds.S 2004-10-18 14:56:50 -07:00 @@ -16,6 +16,7 @@ { *(.text) SCHED_TEXT + LOCK_TEXT *(.gnu.warning) } =0 _etext = .; @@ -52,9 +53,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile --- a/arch/sparc64/lib/Makefile 2004-10-18 14:55:54 -07:00 +++ b/arch/sparc64/lib/Makefile 2004-10-18 14:55:54 -07:00 @@ -7,11 +7,12 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ - VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ - VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ - U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o mcount.o ipcsum.o rwsem.o xor.o splock.o \ - find_bit.o + VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ + VIScsumcopyusr.o VISsave.o atomic.o bitops.o \ + U1memcpy.o U1copy_from_user.o U1copy_to_user.o \ + U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \ + copy_in_user.o user_fixup.o memmove.o \ + mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o iomap.o lib-$(CONFIG_DEBUG_SPINLOCK) += debuglocks.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff -Nru a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c --- a/arch/sparc64/lib/PeeCeeI.c 2004-10-18 14:56:49 -07:00 +++ b/arch/sparc64/lib/PeeCeeI.c 2004-10-18 14:56:49 -07:00 @@ -7,7 +7,7 @@ #include #include -void outsb(unsigned long addr, const void *src, unsigned long count) +void outsb(void __iomem *addr, const void *src, unsigned long count) { const u8 *p = src; @@ -15,7 +15,7 @@ outb(*p++, addr); } -void outsw(unsigned long addr, const void *src, unsigned long count) +void outsw(void __iomem *addr, const void *src, unsigned long count) { if(count) { u16 *ps = (u16 *)src; @@ -44,7 +44,7 @@ } } -void outsl(unsigned long addr, const void *src, unsigned long count) +void outsl(void __iomem *addr, const void *src, unsigned long count) { if(count) { if((((u64)src) & 0x3) == 0) { @@ -119,7 +119,7 @@ } } -void insb(unsigned long addr, void *dst, unsigned long count) +void insb(void __iomem *addr, void *dst, unsigned long count) { if(count) { u32 *pi; @@ -144,7 +144,7 @@ } } -void insw(unsigned long addr, void *dst, unsigned long count) +void insw(void __iomem *addr, void *dst, unsigned long count) { if(count) { u16 *ps = dst; @@ -169,7 +169,7 @@ } } -void insl(unsigned long addr, void *dst, unsigned long count) +void insl(void __iomem *addr, void *dst, unsigned long count) { if(count) { if((((unsigned long)dst) & 0x3) == 0) { diff -Nru a/arch/sparc64/lib/U1copy_from_user.S b/arch/sparc64/lib/U1copy_from_user.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/U1copy_from_user.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,33 @@ +/* U1copy_from_user.S: UltraSparc-I/II/IIi/IIe optimized copy from userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#define EX_LD(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME ___copy_from_user +#define LOAD(type,addr,dest) type##a [addr] %asi, dest +#define LOAD_BLK(addr,dest) ldda [addr] ASI_BLK_AIUS, dest +#define EX_RETVAL(x) 0 + + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ + +#include "U1memcpy.S" diff -Nru a/arch/sparc64/lib/U1copy_to_user.S b/arch/sparc64/lib/U1copy_to_user.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/U1copy_to_user.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,33 @@ +/* U1copy_to_user.S: UltraSparc-I/II/IIi/IIe optimized copy to userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#define EX_ST(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME ___copy_to_user +#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS +#define EX_RETVAL(x) 0 + + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ + +#include "U1memcpy.S" diff -Nru a/arch/sparc64/lib/U1memcpy.S b/arch/sparc64/lib/U1memcpy.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/U1memcpy.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,555 @@ +/* U1memcpy.S: UltraSPARC-I/II/IIi/IIe optimized memcpy. + * + * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#ifdef __KERNEL__ +#include +#include +#else +#define ASI_BLK_P 0xf0 +#define FPRS_FEF 0x04 +#ifdef MEMCPY_DEBUG +#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs; \ + clr %g1; clr %g2; clr %g3; subcc %g0, %g0, %g0; +#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#else +#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs +#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#endif +#endif + +#ifndef EX_LD +#define EX_LD(x) x +#endif + +#ifndef EX_ST +#define EX_ST(x) x +#endif + +#ifndef EX_RETVAL +#define EX_RETVAL(x) x +#endif + +#ifndef LOAD +#define LOAD(type,addr,dest) type [addr], dest +#endif + +#ifndef LOAD_BLK +#define LOAD_BLK(addr,dest) ldda [addr] ASI_BLK_P, dest +#endif + +#ifndef STORE +#define STORE(type,src,addr) type src, [addr] +#endif + +#ifndef STORE_BLK +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_P +#endif + +#ifndef FUNC_NAME +#define FUNC_NAME memcpy +#endif + +#ifndef PREAMBLE +#define PREAMBLE +#endif + +#ifndef XCC +#define XCC xcc +#endif + +#define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + faligndata %f1, %f2, %f48; \ + faligndata %f2, %f3, %f50; \ + faligndata %f3, %f4, %f52; \ + faligndata %f4, %f5, %f54; \ + faligndata %f5, %f6, %f56; \ + faligndata %f6, %f7, %f58; \ + faligndata %f7, %f8, %f60; \ + faligndata %f8, %f9, %f62; + +#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \ + EX_LD(LOAD_BLK(%src, %fdest)); \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %src, 0x40, %src; \ + subcc %len, 0x40, %len; \ + be,pn %xcc, jmptgt; \ + add %dest, 0x40, %dest; \ + +#define LOOP_CHUNK1(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f0, f48, len, branch_dest) +#define LOOP_CHUNK2(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest) +#define LOOP_CHUNK3(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest) + +#define STORE_SYNC(dest, fsrc) \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %dest, 0x40, %dest; + +#define STORE_JUMP(dest, fsrc, target) \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %dest, 0x40, %dest; \ + ba,pt %xcc, target; + +#define FINISH_VISCHUNK(dest, f0, f1, left) \ + subcc %left, 8, %left;\ + bl,pn %xcc, 95f; \ + faligndata %f0, %f1, %f48; \ + EX_ST(STORE(std, %f48, %dest)); \ + add %dest, 8, %dest; + +#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ + subcc %left, 8, %left; \ + bl,pn %xcc, 95f; \ + fsrc1 %f0, %f1; + +#define UNEVEN_VISCHUNK(dest, f0, f1, left) \ + UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ + ba,a,pt %xcc, 93f; + + .register %g2,#scratch + .register %g3,#scratch + + .text + .align 64 + + .globl FUNC_NAME + .type FUNC_NAME,#function +FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ + PREAMBLE + mov %o0, %g5 + cmp %o2, 0 + be,pn %XCC, 85f + or %o0, %o1, %o3 + cmp %o2, 16 + blu,a,pn %XCC, 80f + or %o3, %o2, %o3 + + cmp %o2, (5 * 64) + blu,pt %XCC, 70f + andcc %o3, 0x7, %g0 + + /* Clobbers o5/g1/g2/g3/g7/icc/xcc. */ + VISEntry + + /* Is 'dst' already aligned on an 64-byte boundary? */ + andcc %o0, 0x3f, %g2 + be,pt %XCC, 2f + + /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number + * of bytes to copy to make 'dst' 64-byte aligned. We pre- + * subtract this from 'len'. + */ + sub %o0, %o1, %o4 + sub %g2, 0x40, %g2 + sub %g0, %g2, %g2 + sub %o2, %g2, %o2 + andcc %g2, 0x7, %g1 + be,pt %icc, 2f + and %g2, 0x38, %g2 + +1: subcc %g1, 0x1, %g1 + EX_LD(LOAD(ldub, %o1 + 0x00, %o3)) + EX_ST(STORE(stb, %o3, %o1 + %o4)) + bgu,pt %XCC, 1b + add %o1, 0x1, %o1 + + add %o1, %o4, %o0 + +2: cmp %g2, 0x0 + and %o1, 0x7, %g1 + be,pt %icc, 3f + alignaddr %o1, %g0, %o1 + + EX_LD(LOAD(ldd, %o1, %f4)) +1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f4, %f6, %f0 + EX_ST(STORE(std, %f0, %o0)) + be,pn %icc, 3f + add %o0, 0x8, %o0 + + EX_LD(LOAD(ldd, %o1 + 0x8, %f4)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f6, %f4, %f0 + EX_ST(STORE(std, %f0, %o0)) + bne,pt %icc, 1b + add %o0, 0x8, %o0 + + /* Destination is 64-byte aligned. */ +3: + membar #LoadStore | #StoreStore | #StoreLoad + + subcc %o2, 0x40, %o4 + add %o1, %g1, %g1 + andncc %o4, (0x40 - 1), %o4 + srl %g1, 3, %g2 + sub %o2, %o4, %g3 + andn %o1, (0x40 - 1), %o1 + and %g2, 7, %g2 + andncc %g3, 0x7, %g3 + fmovd %f0, %f2 + sub %g3, 0x8, %g3 + sub %o2, %o4, %o2 + + add %g1, %o4, %g1 + subcc %o2, %g3, %o2 + + EX_LD(LOAD_BLK(%o1, %f0)) + add %o1, 0x40, %o1 + add %g1, %g3, %g1 + EX_LD(LOAD_BLK(%o1, %f16)) + add %o1, 0x40, %o1 + sub %o4, 0x80, %o4 + EX_LD(LOAD_BLK(%o1, %f32)) + add %o1, 0x40, %o1 + + /* There are 8 instances of the unrolled loop, + * one for each possible alignment of the + * source buffer. Each loop instance is 452 + * bytes. + */ + sll %g2, 3, %o3 + sub %o3, %g2, %o3 + sllx %o3, 4, %o3 + add %o3, %g2, %o3 + sllx %o3, 2, %g2 +1: rd %pc, %o3 + add %o3, %lo(1f - 1b), %o3 + jmpl %o3 + %g2, %g0 + nop + + .align 64 +1: FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f0, %f2, %f48 +1: FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + STORE_JUMP(o0, f48, 40f) membar #Sync +2: FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + STORE_JUMP(o0, f48, 48f) membar #Sync +3: FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + STORE_JUMP(o0, f48, 56f) membar #Sync + +1: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f2, %f4, %f48 +1: FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + STORE_JUMP(o0, f48, 41f) membar #Sync +2: FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + STORE_JUMP(o0, f48, 49f) membar #Sync +3: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + STORE_JUMP(o0, f48, 57f) membar #Sync + +1: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f4, %f6, %f48 +1: FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + STORE_JUMP(o0, f48, 42f) membar #Sync +2: FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + STORE_JUMP(o0, f48, 50f) membar #Sync +3: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + STORE_JUMP(o0, f48, 58f) membar #Sync + +1: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f6, %f8, %f48 +1: FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + STORE_JUMP(o0, f48, 43f) membar #Sync +2: FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + STORE_JUMP(o0, f48, 51f) membar #Sync +3: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + STORE_JUMP(o0, f48, 59f) membar #Sync + +1: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f8, %f10, %f48 +1: FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + STORE_JUMP(o0, f48, 44f) membar #Sync +2: FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + STORE_JUMP(o0, f48, 52f) membar #Sync +3: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + STORE_JUMP(o0, f48, 60f) membar #Sync + +1: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f10, %f12, %f48 +1: FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + STORE_JUMP(o0, f48, 45f) membar #Sync +2: FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + STORE_JUMP(o0, f48, 53f) membar #Sync +3: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + STORE_JUMP(o0, f48, 61f) membar #Sync + +1: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f12, %f14, %f48 +1: FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + STORE_JUMP(o0, f48, 46f) membar #Sync +2: FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + STORE_JUMP(o0, f48, 54f) membar #Sync +3: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + STORE_JUMP(o0, f48, 62f) membar #Sync + +1: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f14, %f16, %f48 +1: FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + STORE_JUMP(o0, f48, 47f) membar #Sync +2: FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + STORE_JUMP(o0, f48, 55f) membar #Sync +3: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + STORE_JUMP(o0, f48, 63f) membar #Sync + +40: FINISH_VISCHUNK(o0, f0, f2, g3) +41: FINISH_VISCHUNK(o0, f2, f4, g3) +42: FINISH_VISCHUNK(o0, f4, f6, g3) +43: FINISH_VISCHUNK(o0, f6, f8, g3) +44: FINISH_VISCHUNK(o0, f8, f10, g3) +45: FINISH_VISCHUNK(o0, f10, f12, g3) +46: FINISH_VISCHUNK(o0, f12, f14, g3) +47: UNEVEN_VISCHUNK(o0, f14, f0, g3) +48: FINISH_VISCHUNK(o0, f16, f18, g3) +49: FINISH_VISCHUNK(o0, f18, f20, g3) +50: FINISH_VISCHUNK(o0, f20, f22, g3) +51: FINISH_VISCHUNK(o0, f22, f24, g3) +52: FINISH_VISCHUNK(o0, f24, f26, g3) +53: FINISH_VISCHUNK(o0, f26, f28, g3) +54: FINISH_VISCHUNK(o0, f28, f30, g3) +55: UNEVEN_VISCHUNK(o0, f30, f0, g3) +56: FINISH_VISCHUNK(o0, f32, f34, g3) +57: FINISH_VISCHUNK(o0, f34, f36, g3) +58: FINISH_VISCHUNK(o0, f36, f38, g3) +59: FINISH_VISCHUNK(o0, f38, f40, g3) +60: FINISH_VISCHUNK(o0, f40, f42, g3) +61: FINISH_VISCHUNK(o0, f42, f44, g3) +62: FINISH_VISCHUNK(o0, f44, f46, g3) +63: UNEVEN_VISCHUNK_LAST(o0, f46, f0, g3) + +93: EX_LD(LOAD(ldd, %o1, %f2)) + add %o1, 8, %o1 + subcc %g3, 8, %g3 + faligndata %f0, %f2, %f8 + EX_ST(STORE(std, %f8, %o0)) + bl,pn %xcc, 95f + add %o0, 8, %o0 + EX_LD(LOAD(ldd, %o1, %f0)) + add %o1, 8, %o1 + subcc %g3, 8, %g3 + faligndata %f2, %f0, %f8 + EX_ST(STORE(std, %f8, %o0)) + bge,pt %xcc, 93b + add %o0, 8, %o0 + +95: brz,pt %o2, 2f + mov %g1, %o1 + +1: EX_LD(LOAD(ldub, %o1, %o3)) + add %o1, 1, %o1 + subcc %o2, 1, %o2 + EX_ST(STORE(stb, %o3, %o0)) + bne,pt %xcc, 1b + add %o0, 1, %o0 + +2: membar #StoreLoad | #StoreStore + VISExit + retl + mov EX_RETVAL(%g5), %o0 + + .align 64 +70: /* 16 < len <= (5 * 64) */ + bne,pn %XCC, 75f + sub %o0, %o1, %o3 + +72: andn %o2, 0xf, %o4 + and %o2, 0xf, %o2 +1: EX_LD(LOAD(ldx, %o1 + 0x00, %o5)) + EX_LD(LOAD(ldx, %o1 + 0x08, %g1)) + subcc %o4, 0x10, %o4 + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 + EX_ST(STORE(stx, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 +73: andcc %o2, 0x8, %g0 + be,pt %XCC, 1f + nop + EX_LD(LOAD(ldx, %o1, %o5)) + sub %o2, 0x8, %o2 + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 +1: andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + EX_LD(LOAD(lduw, %o1, %o5)) + sub %o2, 0x4, %o2 + EX_ST(STORE(stw, %o5, %o1 + %o3)) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, 85f + nop + ba,pt %xcc, 90f + nop + +75: andcc %o0, 0x7, %g1 + sub %g1, 0x8, %g1 + be,pn %icc, 2f + sub %g0, %g1, %g1 + sub %o2, %g1, %o2 + +1: EX_LD(LOAD(ldub, %o1, %o5)) + subcc %g1, 1, %g1 + EX_ST(STORE(stb, %o5, %o1 + %o3)) + bgu,pt %icc, 1b + add %o1, 1, %o1 + +2: add %o1, %o3, %o0 + andcc %o1, 0x7, %g1 + bne,pt %icc, 8f + sll %g1, 3, %g1 + + cmp %o2, 16 + bgeu,pt %icc, 72b + nop + ba,a,pt %xcc, 73b + +8: mov 64, %o3 + andn %o1, 0x7, %o1 + EX_LD(LOAD(ldx, %o1, %g2)) + sub %o3, %g1, %o3 + andn %o2, 0x7, %o4 + sllx %g2, %g1, %g2 +1: EX_LD(LOAD(ldx, %o1 + 0x8, %g3)) + subcc %o4, 0x8, %o4 + add %o1, 0x8, %o1 + srlx %g3, %o3, %o5 + or %o5, %g2, %o5 + EX_ST(STORE(stx, %o5, %o0)) + add %o0, 0x8, %o0 + bgu,pt %icc, 1b + sllx %g3, %g1, %g2 + + srl %g1, 3, %g1 + andcc %o2, 0x7, %o2 + be,pn %icc, 85f + add %o1, %g1, %o1 + ba,pt %xcc, 90f + sub %o0, %o1, %o3 + + .align 64 +80: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + +1: EX_LD(LOAD(lduw, %o1, %g1)) + subcc %o2, 4, %o2 + EX_ST(STORE(stw, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 4, %o1 + +85: retl + mov EX_RETVAL(%g5), %o0 + + .align 32 +90: EX_LD(LOAD(ldub, %o1, %g1)) + subcc %o2, 1, %o2 + EX_ST(STORE(stb, %g1, %o1 + %o3)) + bgu,pt %XCC, 90b + add %o1, 1, %o1 + retl + mov EX_RETVAL(%g5), %o0 + + .size FUNC_NAME, .-FUNC_NAME diff -Nru a/arch/sparc64/lib/U3copy_from_user.S b/arch/sparc64/lib/U3copy_from_user.S --- a/arch/sparc64/lib/U3copy_from_user.S 2004-10-18 14:56:17 -07:00 +++ b/arch/sparc64/lib/U3copy_from_user.S 2004-10-18 14:56:17 -07:00 @@ -3,410 +3,20 @@ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#include -#include -#include -#include +#define EX_LD(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME U3copy_from_user +#define LOAD(type,addr,dest) type##a [addr] %asi, dest +#define EX_RETVAL(x) 0 -#define XCC xcc - -#define EXNV_RAW(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: add %o1, %o3, %o0; \ - ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV4(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: add %o1, %o3, %o0; \ - a, b, %o1; \ - ba U3cfu_fixup; \ - add %o1, 4, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV8(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: add %o1, %o3, %o0; \ - a, b, %o1; \ - ba U3cfu_fixup; \ - add %o1, 8, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - add %o1, %o4, %o1; \ - ba U3cfu_fixup; \ - add %o1, 0x1c0, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - sll %g3, 6, %g3; \ - add %o1, 0x80, %o1; \ - ba U3cfu_fixup; \ - add %o1, %g3, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX4(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - add %o1, 0x40, %o1; \ - ba U3cfu_fixup; \ - add %o1, %g3, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; - - .register %g2,#scratch - .register %g3,#scratch - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - */ - - .text - .align 32 - - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. - */ - - .globl U3copy_from_user -U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */ - cmp %o2, 0 - be,pn %XCC, 85f - or %o0, %o1, %o3 - cmp %o2, 16 - bleu,a,pn %XCC, 80f - or %o3, %o2, %o3 - - cmp %o2, 256 - blu,pt %XCC, 70f - andcc %o3, 0x7, %g0 - - ba,pt %xcc, 1f - andcc %o0, 0x3f, %g2 - - /* Here len >= 256 and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -1: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %XCC, 2f - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV_RAW(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - - bg,pt %XCC, 1b - stb %o3, [%o0 + -1] - -2: VISEntryHalf - and %o1, 0x7, %g1 - ba,pt %xcc, 1f - alignaddr %o1, %g0, %o1 - - .align 64 -1: - membar #StoreLoad | #StoreStore | #LoadStore - prefetcha [%o1 + 0x000] %asi, #one_read - prefetcha [%o1 + 0x040] %asi, #one_read - andn %o2, (0x40 - 1), %o4 - prefetcha [%o1 + 0x080] %asi, #one_read - prefetcha [%o1 + 0x0c0] %asi, #one_read - EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) - prefetcha [%o1 + 0x100] %asi, #one_read - EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) - prefetcha [%o1 + 0x140] %asi, #one_read - EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) - prefetcha [%o1 + 0x180] %asi, #one_read - faligndata %f0, %f2, %f16 - EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) - faligndata %f2, %f4, %f18 - EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) - faligndata %f4, %f6, %f20 - EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) - faligndata %f6, %f8, %f22 - - EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) - faligndata %f8, %f10, %f24 - EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) - faligndata %f10, %f12, %f26 - EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) - - sub %o4, 0x80, %o4 - add %o1, 0x40, %o1 - ba,pt %xcc, 1f - srl %o4, 6, %o3 - - .align 64 -1: - EX3(ldda [%o1 + 0x008] %asi, %f2) - faligndata %f12, %f14, %f28 - EX3(ldda [%o1 + 0x010] %asi, %f4) - faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - EX3(ldda [%o1 + 0x018] %asi, %f6) - faligndata %f0, %f2, %f16 - - EX3(ldda [%o1 + 0x020] %asi, %f8) - faligndata %f2, %f4, %f18 - EX3(ldda [%o1 + 0x028] %asi, %f10) - faligndata %f4, %f6, %f20 - EX3(ldda [%o1 + 0x030] %asi, %f12) - faligndata %f6, %f8, %f22 - EX3(ldda [%o1 + 0x038] %asi, %f14) - faligndata %f8, %f10, %f24 - - EX3(ldda [%o1 + 0x040] %asi, %f0) - prefetcha [%o1 + 0x180] %asi, #one_read - faligndata %f10, %f12, %f26 - subcc %o3, 0x01, %o3 - add %o1, 0x40, %o1 - bg,pt %XCC, 1b - add %o0, 0x40, %o0 - - /* Finally we copy the last full 64-byte block. */ - EX3(ldda [%o1 + 0x008] %asi, %f2) - faligndata %f12, %f14, %f28 - EX3(ldda [%o1 + 0x010] %asi, %f4) - faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - EX3(ldda [%o1 + 0x018] %asi, %f6) - faligndata %f0, %f2, %f16 - EX3(ldda [%o1 + 0x020] %asi, %f8) - faligndata %f2, %f4, %f18 - EX3(ldda [%o1 + 0x028] %asi, %f10) - faligndata %f4, %f6, %f20 - EX3(ldda [%o1 + 0x030] %asi, %f12) - faligndata %f6, %f8, %f22 - EX3(ldda [%o1 + 0x038] %asi, %f14) - faligndata %f8, %f10, %f24 - cmp %g1, 0 - be,pt %XCC, 1f - add %o0, 0x40, %o0 - EX4(ldda [%o1 + 0x040] %asi, %f0) -1: faligndata %f10, %f12, %f26 - faligndata %f12, %f14, %f28 - faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - add %o0, 0x40, %o0 - add %o1, 0x40, %o1 - - membar #Sync - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer. - */ - and %o2, 0x3f, %o2 - andcc %o2, 0x38, %g2 - be,pn %XCC, 10f - subcc %g2, 0x8, %g2 - be,pn %XCC, 10f - cmp %g1, 0 - - be,a,pt %XCC, 1f - EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) - -1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f0, %f2, %f8 - std %f8, [%o0 + 0x00] - be,pn %XCC, 10f - add %o0, 0x8, %o0 - EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f2, %f0, %f8 - std %f8, [%o0 + 0x00] - bne,pn %XCC, 1b - add %o0, 0x8, %o0 - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -10: - cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %XCC, 85f - sub %o0, %o1, %o3 - - andcc %g1, 0x7, %g0 - bne,pn %icc, 90f - andcc %o2, 0x8, %g0 - be,pt %icc, 1f - nop - EXNV(ldxa [%o1] %asi, %o5, add %o2, %g0) - stx %o5, [%o1 + %o3] - add %o1, 0x8, %o1 - -1: andcc %o2, 0x4, %g0 - be,pt %icc, 1f - nop - EXNV(lduwa [%o1] %asi, %o5, and %o2, 0x7) - stw %o5, [%o1 + %o3] - add %o1, 0x4, %o1 - -1: andcc %o2, 0x2, %g0 - be,pt %icc, 1f - nop - EXNV(lduha [%o1] %asi, %o5, and %o2, 0x3) - sth %o5, [%o1 + %o3] - add %o1, 0x2, %o1 - -1: andcc %o2, 0x1, %g0 - be,pt %icc, 85f - nop - EXNV(lduba [%o1] %asi, %o5, and %o2, 0x1) - ba,pt %xcc, 85f - stb %o5, [%o1 + %o3] - -70: /* 16 < len <= 64 */ - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - - andn %o2, 0x7, %o4 - and %o2, 0x7, %o2 -1: subcc %o4, 0x8, %o4 - EXNV8(ldxa [%o1] %asi, %o5, add %o2, %o4) - stx %o5, [%o1 + %o3] - bgu,pt %XCC, 1b - add %o1, 0x8, %o1 - andcc %o2, 0x4, %g0 - be,pt %XCC, 1f - nop - sub %o2, 0x4, %o2 - EXNV4(lduwa [%o1] %asi, %o5, add %o2, %g0) - stw %o5, [%o1 + %o3] - add %o1, 0x4, %o1 -1: cmp %o2, 0 - be,pt %XCC, 85f - nop - ba,pt %xcc, 90f - nop - -80: /* 0 < len <= 16 */ - andcc %o3, 0x3, %g0 - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - -1: - subcc %o2, 4, %o2 - EXNV(lduwa [%o1] %asi, %g1, add %o2, %g0) - stw %g1, [%o1 + %o3] - bgu,pt %XCC, 1b - add %o1, 4, %o1 - -85: retl - clr %o0 - - .align 32 -90: - subcc %o2, 1, %o2 - EXNV(lduba [%o1] %asi, %g1, add %o2, %g0) - stb %g1, [%o1 + %o3] - bgu,pt %XCC, 90b - add %o1, 1, %o1 - retl - clr %o0 - -U3cfu_fixup: - /* Since this is copy_from_user(), zero out the rest of the - * kernel buffer. - */ - cmp %o1, 0 - ble,pn %icc, 2f - mov %o1, %g2 - -1: subcc %g2, 1, %g2 - stb %g0, [%o0] - bne,pt %icc, 1b - add %o0, 1, %o0 - -2: retl - mov %o1, %o0 +#include "U3memcpy.S" diff -Nru a/arch/sparc64/lib/U3copy_in_user.S b/arch/sparc64/lib/U3copy_in_user.S --- a/arch/sparc64/lib/U3copy_in_user.S 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,140 +0,0 @@ -/* U3copy_in_user.S: UltraSparc-III optimized memcpy. - * - * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) - */ - -#include -#include -#include -#include - -#define XCC xcc - -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV1(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 1, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV4(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 4, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV8(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 8, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; - - .register %g2,#scratch - .register %g3,#scratch - - .text - .align 32 - - /* Don't try to get too fancy here, just nice and - * simple. This is predominantly used for well aligned - * small copies in the compat layer. It is also used - * to copy register windows around during thread cloning. - */ - - .globl U3copy_in_user -U3copy_in_user: /* %o0=dst, %o1=src, %o2=len */ - /* Writing to %asi is _expensive_ so we hardcode it. - * Reading %asi to check for KERNEL_DS is comparatively - * cheap. - */ - rd %asi, %g1 - cmp %g1, ASI_AIUS - bne,pn %icc, U3memcpy_user_stub - nop - - cmp %o2, 0 - be,pn %XCC, out - or %o0, %o1, %o3 - cmp %o2, 16 - bleu,a,pn %XCC, small_copy - or %o3, %o2, %o3 - -medium_copy: /* 16 < len <= 64 */ - andcc %o3, 0x7, %g0 - bne,pn %XCC, small_copy_unaligned - sub %o0, %o1, %o3 - -medium_copy_aligned: - andn %o2, 0x7, %o4 - and %o2, 0x7, %o2 -1: subcc %o4, 0x8, %o4 - EXNV8(ldxa [%o1] %asi, %o5, add %o4, %o2) - EXNV8(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o4, %o2) - bgu,pt %XCC, 1b - add %o1, 0x8, %o1 - andcc %o2, 0x4, %g0 - be,pt %XCC, 1f - nop - sub %o2, 0x4, %o2 - EXNV4(lduwa [%o1] %asi, %o5, add %o4, %o2) - EXNV4(stwa %o5, [%o1 + %o3] ASI_AIUS, add %o4, %o2) - add %o1, 0x4, %o1 -1: cmp %o2, 0 - be,pt %XCC, out - nop - ba,pt %xcc, small_copy_unaligned - nop - -small_copy: /* 0 < len <= 16 */ - andcc %o3, 0x3, %g0 - bne,pn %XCC, small_copy_unaligned - sub %o0, %o1, %o3 - -small_copy_aligned: - subcc %o2, 4, %o2 - EXNV4(lduwa [%o1] %asi, %g1, add %o2, %g0) - EXNV4(stwa %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - bgu,pt %XCC, small_copy_aligned - add %o1, 4, %o1 - -out: retl - clr %o0 - - .align 32 -small_copy_unaligned: - subcc %o2, 1, %o2 - EXNV1(lduba [%o1] %asi, %g1, add %o2, %g0) - EXNV1(stba %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - bgu,pt %XCC, small_copy_unaligned - add %o1, 1, %o1 - retl - clr %o0 diff -Nru a/arch/sparc64/lib/U3copy_to_user.S b/arch/sparc64/lib/U3copy_to_user.S --- a/arch/sparc64/lib/U3copy_to_user.S 2004-10-18 14:55:46 -07:00 +++ b/arch/sparc64/lib/U3copy_to_user.S 2004-10-18 14:55:46 -07:00 @@ -1,415 +1,33 @@ -/* U3copy_to_user.S: UltraSparc-III optimized memcpy. +/* U3copy_to_user.S: UltraSparc-III optimized copy to userspace. * * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#include -#include -#include -#include +#define EX_ST(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME U3copy_to_user +#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS +#define EX_RETVAL(x) 0 -#define XCC xcc - -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV2(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 1, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV3(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 4, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV4(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 8, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK1(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - add %o4, 0x1c0, %o1; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - sll %o3, 6, %o3; \ - and %o2, (0x40 - 1), %o2; \ - add %o3, 0x80, %o1; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x80, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK4(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x40, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; - - .register %g2,#scratch - .register %g3,#scratch - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - */ - - .text - .align 32 - - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. - */ - - .globl U3copy_to_user -U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */ /* Writing to %asi is _expensive_ so we hardcode it. * Reading %asi to check for KERNEL_DS is comparatively * cheap. */ - rd %asi, %g1 - cmp %g1, ASI_AIUS - bne,pn %icc, U3memcpy_user_stub - nop - - cmp %o2, 0 - be,pn %XCC, 85f - or %o0, %o1, %o3 - cmp %o2, 16 - bleu,a,pn %XCC, 80f - or %o3, %o2, %o3 - - cmp %o2, 256 - blu,pt %XCC, 70f - andcc %o3, 0x7, %g0 - - ba,pt %xcc, 1f - andcc %o0, 0x3f, %g2 - - /* Here len >= 256 and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -1: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %XCC, 2f - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - - bg,pt %XCC, 1b - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) - -2: VISEntryHalf - and %o1, 0x7, %g1 - ba,pt %xcc, 1f - alignaddr %o1, %g0, %o1 - - .align 64 -1: - membar #StoreLoad | #StoreStore | #LoadStore - prefetch [%o1 + 0x000], #one_read - prefetch [%o1 + 0x040], #one_read - andn %o2, (0x40 - 1), %o4 - prefetch [%o1 + 0x080], #one_read - prefetch [%o1 + 0x0c0], #one_read - ldd [%o1 + 0x000], %f0 - prefetch [%o1 + 0x100], #one_read - ldd [%o1 + 0x008], %f2 - prefetch [%o1 + 0x140], #one_read - ldd [%o1 + 0x010], %f4 - prefetch [%o1 + 0x180], #one_read - faligndata %f0, %f2, %f16 - ldd [%o1 + 0x018], %f6 - faligndata %f2, %f4, %f18 - ldd [%o1 + 0x020], %f8 - faligndata %f4, %f6, %f20 - ldd [%o1 + 0x028], %f10 - faligndata %f6, %f8, %f22 - - ldd [%o1 + 0x030], %f12 - faligndata %f8, %f10, %f24 - ldd [%o1 + 0x038], %f14 - faligndata %f10, %f12, %f26 - ldd [%o1 + 0x040], %f0 - - sub %o4, 0x80, %o4 - add %o1, 0x40, %o1 - ba,pt %xcc, 1f - srl %o4, 6, %o3 - - .align 64 -1: - ldd [%o1 + 0x008], %f2 - faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 - faligndata %f14, %f0, %f30 - EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) - ldd [%o1 + 0x018], %f6 - faligndata %f0, %f2, %f16 - - ldd [%o1 + 0x020], %f8 - faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 - faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 - faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 - faligndata %f8, %f10, %f24 - - ldd [%o1 + 0x040], %f0 - prefetch [%o1 + 0x180], #one_read - faligndata %f10, %f12, %f26 - subcc %o3, 0x01, %o3 - add %o1, 0x40, %o1 - bg,pt %XCC, 1b - add %o0, 0x40, %o0 - - /* Finally we copy the last full 64-byte block. */ - ldd [%o1 + 0x008], %f2 - faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 - faligndata %f14, %f0, %f30 - EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) - ldd [%o1 + 0x018], %f6 - faligndata %f0, %f2, %f16 - ldd [%o1 + 0x020], %f8 - faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 - faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 - faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 - faligndata %f8, %f10, %f24 - cmp %g1, 0 - be,pt %XCC, 1f - add %o0, 0x40, %o0 - ldd [%o1 + 0x040], %f0 -1: faligndata %f10, %f12, %f26 - faligndata %f12, %f14, %f28 - faligndata %f14, %f0, %f30 - EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) - add %o0, 0x40, %o0 - add %o1, 0x40, %o1 - - membar #Sync - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer. - */ - and %o2, 0x3f, %o2 - andcc %o2, 0x38, %g2 - be,pn %XCC, 2f - subcc %g2, 0x8, %g2 - be,pn %XCC, 2f - cmp %g1, 0 - - be,a,pt %XCC, 1f - ldd [%o1 + 0x00], %f0 - -1: ldd [%o1 + 0x08], %f2 - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f0, %f2, %f8 - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) - be,pn %XCC, 2f - add %o0, 0x8, %o0 - ldd [%o1 + 0x08], %f0 - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f2, %f0, %f8 - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) - bne,pn %XCC, 1b - add %o0, 0x8, %o0 - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -2: - cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %XCC, 85f - sub %o0, %o1, %o3 - - andcc %g1, 0x7, %g0 - bne,pn %icc, 90f - andcc %o2, 0x8, %g0 - be,pt %icc, 1f - nop - ldx [%o1], %o5 - EXNV(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - add %o1, 0x8, %o1 - -1: andcc %o2, 0x4, %g0 - be,pt %icc, 1f - nop - lduw [%o1], %o5 - EXNV(stwa %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x7) - add %o1, 0x4, %o1 - -1: andcc %o2, 0x2, %g0 - be,pt %icc, 1f - nop - lduh [%o1], %o5 - EXNV(stha %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x3) - add %o1, 0x2, %o1 - -1: andcc %o2, 0x1, %g0 - be,pt %icc, 85f - nop - ldub [%o1], %o5 - ba,pt %xcc, 85f - EXNV(stba %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x1) - -70: /* 16 < len <= 64 */ - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - - andn %o2, 0x7, %o4 - and %o2, 0x7, %o2 -1: subcc %o4, 0x8, %o4 - ldx [%o1], %o5 - EXNV4(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %o4) - bgu,pt %XCC, 1b - add %o1, 0x8, %o1 - andcc %o2, 0x4, %g0 - be,pt %XCC, 1f - nop - sub %o2, 0x4, %o2 - lduw [%o1], %o5 - EXNV3(stwa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - add %o1, 0x4, %o1 -1: cmp %o2, 0 - be,pt %XCC, 85f - nop - ba,pt %xcc, 90f - nop - -80: /* 0 < len <= 16 */ - andcc %o3, 0x3, %g0 - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - -1: - subcc %o2, 4, %o2 - lduw [%o1], %g1 - EXNV3(stwa %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - bgu,pt %XCC, 1b - add %o1, 4, %o1 - -85: retl - clr %o0 +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ - .align 32 -90: - subcc %o2, 1, %o2 - ldub [%o1], %g1 - EXNV2(stba %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - bgu,pt %XCC, 90b - add %o1, 1, %o1 - retl - clr %o0 +#include "U3memcpy.S" diff -Nru a/arch/sparc64/lib/U3memcpy.S b/arch/sparc64/lib/U3memcpy.S --- a/arch/sparc64/lib/U3memcpy.S 2004-10-18 14:57:05 -07:00 +++ b/arch/sparc64/lib/U3memcpy.S 2004-10-18 14:57:05 -07:00 @@ -6,14 +6,50 @@ #ifdef __KERNEL__ #include #include -#include -#include #else #define ASI_BLK_P 0xf0 #define FPRS_FEF 0x04 +#ifdef MEMCPY_DEBUG +#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs; \ + clr %g1; clr %g2; clr %g3; subcc %g0, %g0, %g0; +#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#else #define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs #endif +#endif + +#ifndef EX_LD +#define EX_LD(x) x +#endif + +#ifndef EX_ST +#define EX_ST(x) x +#endif + +#ifndef EX_RETVAL +#define EX_RETVAL(x) x +#endif + +#ifndef LOAD +#define LOAD(type,addr,dest) type [addr], dest +#endif + +#ifndef STORE +#define STORE(type,src,addr) type src, [addr] +#endif + +#ifndef STORE_BLK +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_P +#endif + +#ifndef FUNC_NAME +#define FUNC_NAME U3memcpy +#endif + +#ifndef PREAMBLE +#define PREAMBLE +#endif #ifndef XCC #define XCC xcc @@ -33,7 +69,7 @@ */ .text - .align 32 + .align 64 /* The cheetah's flexible spine, oversized liver, enlarged heart, * slender muscular body, and claws make it the swiftest hunter @@ -41,137 +77,158 @@ * of up to 2.4GB per second. */ - .globl U3memcpy -U3memcpy: /* %o0=dst, %o1=src, %o2=len */ + .globl FUNC_NAME + .type FUNC_NAME,#function +FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ + PREAMBLE mov %o0, %g5 cmp %o2, 0 be,pn %XCC, 85f or %o0, %o1, %o3 cmp %o2, 16 - bleu,a,pn %XCC, 70f + blu,a,pn %XCC, 80f or %o3, %o2, %o3 - cmp %o2, 256 - blu,pt %XCC, 80f + cmp %o2, (3 * 64) + blu,pt %XCC, 70f andcc %o3, 0x7, %g0 - ba,pt %xcc, 1f - andcc %o0, 0x3f, %g2 - - /* Here len >= 256 and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. + /* Clobbers o5/g1/g2/g3/g7/icc/xcc. We must preserve + * o5 from here until we hit VISExitHalf. */ - .align 64 -1: + VISEntryHalf + /* Is 'dst' already aligned on an 64-byte boundary? */ + andcc %o0, 0x3f, %g2 be,pt %XCC, 2f /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number * of bytes to copy to make 'dst' 64-byte aligned. We pre- * subtract this from 'len'. */ - sub %g2, 0x40, %g2 + sub %o0, %o1, %o4 + sub %g2, 0x40, %g2 sub %g0, %g2, %g2 sub %o2, %g2, %o2 + andcc %g2, 0x7, %g1 + be,pt %icc, 2f + and %g2, 0x38, %g2 + +1: subcc %g1, 0x1, %g1 + EX_LD(LOAD(ldub, %o1 + 0x00, %o3)) + EX_ST(STORE(stb, %o3, %o1 + %o4)) + bgu,pt %XCC, 1b + add %o1, 0x1, %o1 - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - - bg,pt %XCC, 1b - stb %o3, [%o0 + -1] + add %o1, %o4, %o0 -2: VISEntryHalf +2: cmp %g2, 0x0 and %o1, 0x7, %g1 - ba,pt %xcc, 1f + be,pt %icc, 3f alignaddr %o1, %g0, %o1 - .align 64 -1: - membar #StoreLoad | #StoreStore | #LoadStore - prefetch [%o1 + 0x000], #one_read - prefetch [%o1 + 0x040], #one_read + EX_LD(LOAD(ldd, %o1, %f4)) +1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f4, %f6, %f0 + EX_ST(STORE(std, %f0, %o0)) + be,pn %icc, 3f + add %o0, 0x8, %o0 + + EX_LD(LOAD(ldd, %o1 + 0x8, %f4)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f6, %f4, %f2 + EX_ST(STORE(std, %f2, %o0)) + bne,pt %icc, 1b + add %o0, 0x8, %o0 + +3: LOAD(prefetch, %o1 + 0x000, #one_read) + LOAD(prefetch, %o1 + 0x040, #one_read) andn %o2, (0x40 - 1), %o4 - prefetch [%o1 + 0x080], #one_read - prefetch [%o1 + 0x0c0], #one_read - ldd [%o1 + 0x000], %f0 - prefetch [%o1 + 0x100], #one_read - ldd [%o1 + 0x008], %f2 - prefetch [%o1 + 0x140], #one_read - ldd [%o1 + 0x010], %f4 - prefetch [%o1 + 0x180], #one_read + LOAD(prefetch, %o1 + 0x080, #one_read) + LOAD(prefetch, %o1 + 0x0c0, #one_read) + LOAD(prefetch, %o1 + 0x100, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x000, %f0)) + LOAD(prefetch, %o1 + 0x140, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) + LOAD(prefetch, %o1 + 0x180, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) + LOAD(prefetch, %o1 + 0x1c0, #one_read) faligndata %f0, %f2, %f16 - ldd [%o1 + 0x018], %f6 + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) faligndata %f2, %f4, %f18 - ldd [%o1 + 0x020], %f8 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) faligndata %f4, %f6, %f20 - ldd [%o1 + 0x028], %f10 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) faligndata %f6, %f8, %f22 - ldd [%o1 + 0x030], %f12 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) faligndata %f8, %f10, %f24 - ldd [%o1 + 0x038], %f14 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) faligndata %f10, %f12, %f26 - ldd [%o1 + 0x040], %f0 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) - sub %o4, 0x80, %o4 + subcc %o4, 0x80, %o4 add %o1, 0x40, %o1 - ba,pt %xcc, 1f + bgu,pt %XCC, 1f srl %o4, 6, %o3 + ba,pt %xcc, 2f + nop .align 64 1: - ldd [%o1 + 0x008], %f2 + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - ldd [%o1 + 0x018], %f6 + EX_ST(STORE_BLK(%f16, %o0)) + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) faligndata %f0, %f2, %f16 + add %o0, 0x40, %o0 - ldd [%o1 + 0x020], %f8 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) + subcc %o3, 0x01, %o3 faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 - faligndata %f8, %f10, %f24 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) - ldd [%o1 + 0x040], %f0 - prefetch [%o1 + 0x180], #one_read + faligndata %f8, %f10, %f24 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) + LOAD(prefetch, %o1 + 0x1c0, #one_read) faligndata %f10, %f12, %f26 - subcc %o3, 0x01, %o3 - add %o1, 0x40, %o1 bg,pt %XCC, 1b - add %o0, 0x40, %o0 + add %o1, 0x40, %o1 /* Finally we copy the last full 64-byte block. */ - ldd [%o1 + 0x008], %f2 +2: + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - ldd [%o1 + 0x018], %f6 + EX_ST(STORE_BLK(%f16, %o0)) + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) faligndata %f0, %f2, %f16 - ldd [%o1 + 0x020], %f8 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) faligndata %f8, %f10, %f24 cmp %g1, 0 be,pt %XCC, 1f add %o0, 0x40, %o0 - ldd [%o1 + 0x040], %f0 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) 1: faligndata %f10, %f12, %f26 faligndata %f12, %f14, %f28 faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P + EX_ST(STORE_BLK(%f16, %o0)) add %o0, 0x40, %o0 add %o1, 0x40, %o1 membar #Sync @@ -189,23 +246,22 @@ be,pn %XCC, 2f cmp %g1, 0 + sub %o2, %g2, %o2 be,a,pt %XCC, 1f - ldd [%o1 + 0x00], %f0 + EX_LD(LOAD(ldd, %o1 + 0x00, %f0)) -1: ldd [%o1 + 0x08], %f2 +1: EX_LD(LOAD(ldd, %o1 + 0x08, %f2)) add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 subcc %g2, 0x8, %g2 faligndata %f0, %f2, %f8 - std %f8, [%o0 + 0x00] + EX_ST(STORE(std, %f8, %o0)) be,pn %XCC, 2f add %o0, 0x8, %o0 - ldd [%o1 + 0x08], %f0 + EX_LD(LOAD(ldd, %o1 + 0x08, %f0)) add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 subcc %g2, 0x8, %g2 faligndata %f2, %f0, %f8 - std %f8, [%o0 + 0x00] + EX_ST(STORE(std, %f8, %o0)) bne,pn %XCC, 1b add %o0, 0x8, %o0 @@ -225,48 +281,60 @@ andcc %o2, 0x8, %g0 be,pt %icc, 1f nop - ldx [%o1], %o5 - stx %o5, [%o1 + %o3] + EX_LD(LOAD(ldx, %o1, %o5)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) add %o1, 0x8, %o1 1: andcc %o2, 0x4, %g0 be,pt %icc, 1f nop - lduw [%o1], %o5 - stw %o5, [%o1 + %o3] + EX_LD(LOAD(lduw, %o1, %o5)) + EX_ST(STORE(stw, %o5, %o1 + %o3)) add %o1, 0x4, %o1 1: andcc %o2, 0x2, %g0 be,pt %icc, 1f nop - lduh [%o1], %o5 - sth %o5, [%o1 + %o3] + EX_LD(LOAD(lduh, %o1, %o5)) + EX_ST(STORE(sth, %o5, %o1 + %o3)) add %o1, 0x2, %o1 1: andcc %o2, 0x1, %g0 be,pt %icc, 85f nop - ldub [%o1], %o5 + EX_LD(LOAD(ldub, %o1, %o5)) ba,pt %xcc, 85f - stb %o5, [%o1 + %o3] + EX_ST(STORE(stb, %o5, %o1 + %o3)) + .align 64 70: /* 16 < len <= 64 */ - bne,pn %XCC, 90f + bne,pn %XCC, 75f sub %o0, %o1, %o3 - andn %o2, 0x7, %o4 - and %o2, 0x7, %o2 -1: subcc %o4, 0x8, %o4 - ldx [%o1], %o5 - stx %o5, [%o1 + %o3] +72: + andn %o2, 0xf, %o4 + and %o2, 0xf, %o2 +1: subcc %o4, 0x10, %o4 + EX_LD(LOAD(ldx, %o1 + 0x00, %o5)) + EX_LD(LOAD(ldx, %o1 + 0x08, %g1)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 + EX_ST(STORE(stx, %g1, %o1 + %o3)) bgu,pt %XCC, 1b add %o1, 0x8, %o1 - andcc %o2, 0x4, %g0 +73: andcc %o2, 0x8, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x8, %o2 + EX_LD(LOAD(ldx, %o1, %o5)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 +1: andcc %o2, 0x4, %g0 be,pt %XCC, 1f nop sub %o2, 0x4, %o2 - lduw [%o1], %o5 - stw %o5, [%o1 + %o3] + EX_LD(LOAD(lduw, %o1, %o5)) + EX_ST(STORE(stw, %o5, %o1 + %o3)) add %o1, 0x4, %o1 1: cmp %o2, 0 be,pt %XCC, 85f @@ -274,6 +342,53 @@ ba,pt %xcc, 90f nop +75: + andcc %o0, 0x7, %g1 + sub %g1, 0x8, %g1 + be,pn %icc, 2f + sub %g0, %g1, %g1 + sub %o2, %g1, %o2 + +1: subcc %g1, 1, %g1 + EX_LD(LOAD(ldub, %o1, %o5)) + EX_ST(STORE(stb, %o5, %o1 + %o3)) + bgu,pt %icc, 1b + add %o1, 1, %o1 + +2: add %o1, %o3, %o0 + andcc %o1, 0x7, %g1 + bne,pt %icc, 8f + sll %g1, 3, %g1 + + cmp %o2, 16 + bgeu,pt %icc, 72b + nop + ba,a,pt %xcc, 73b + +8: mov 64, %o3 + andn %o1, 0x7, %o1 + EX_LD(LOAD(ldx, %o1, %g2)) + sub %o3, %g1, %o3 + andn %o2, 0x7, %o4 + sllx %g2, %g1, %g2 +1: EX_LD(LOAD(ldx, %o1 + 0x8, %g3)) + subcc %o4, 0x8, %o4 + add %o1, 0x8, %o1 + srlx %g3, %o3, %o5 + or %o5, %g2, %o5 + EX_ST(STORE(stx, %o5, %o0)) + add %o0, 0x8, %o0 + bgu,pt %icc, 1b + sllx %g3, %g1, %g2 + + srl %g1, 3, %g1 + andcc %o2, 0x7, %o2 + be,pn %icc, 85f + add %o1, %g1, %o1 + ba,pt %xcc, 90f + sub %o0, %o1, %o3 + + .align 64 80: /* 0 < len <= 16 */ andcc %o3, 0x3, %g0 bne,pn %XCC, 90f @@ -281,34 +396,22 @@ 1: subcc %o2, 4, %o2 - lduw [%o1], %g1 - stw %g1, [%o1 + %o3] + EX_LD(LOAD(lduw, %o1, %g1)) + EX_ST(STORE(stw, %g1, %o1 + %o3)) bgu,pt %XCC, 1b add %o1, 4, %o1 85: retl - mov %g5, %o0 + mov EX_RETVAL(%g5), %o0 - .align 32 + .align 32 90: subcc %o2, 1, %o2 - ldub [%o1], %g1 - stb %g1, [%o1 + %o3] + EX_LD(LOAD(ldub, %o1, %g1)) + EX_ST(STORE(stb, %g1, %o1 + %o3)) bgu,pt %XCC, 90b add %o1, 1, %o1 retl - mov %g5, %o0 + mov EX_RETVAL(%g5), %o0 - /* Act like copy_{to,in}_user(), ie. return zero instead - * of original destination pointer. This is invoked when - * copy_{to,in}_user() finds that %asi is kernel space. - */ - .globl U3memcpy_user_stub -U3memcpy_user_stub: - save %sp, -192, %sp - mov %i0, %o0 - mov %i1, %o1 - call U3memcpy - mov %i2, %o2 - ret - restore %g0, %g0, %o0 + .size FUNC_NAME, .-FUNC_NAME diff -Nru a/arch/sparc64/lib/U3patch.S b/arch/sparc64/lib/U3patch.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/U3patch.S 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,32 @@ +/* U3patch.S: Patch Ultra-I routines with Ultra-III variant. + * + * Copyright (C) 2004 David S. Miller + */ + +#define BRANCH_ALWAYS 0x10680000 +#define NOP 0x01000000 +#define ULTRA3_DO_PATCH(OLD, NEW) \ + sethi %hi(NEW), %g1; \ + or %g1, %lo(NEW), %g1; \ + sethi %hi(OLD), %g2; \ + or %g2, %lo(OLD), %g2; \ + sub %g1, %g2, %g1; \ + sethi %hi(BRANCH_ALWAYS), %g3; \ + srl %g1, 2, %g1; \ + or %g3, %lo(BRANCH_ALWAYS), %g3; \ + or %g3, %g1, %g3; \ + stw %g3, [%g2]; \ + sethi %hi(NOP), %g3; \ + or %g3, %lo(NOP), %g3; \ + stw %g3, [%g2 + 0x4]; \ + flush %g2; + + .globl cheetah_patch_copyops + .type cheetah_patch_copyops,#function +cheetah_patch_copyops: + ULTRA3_DO_PATCH(memcpy, U3memcpy) + ULTRA3_DO_PATCH(___copy_from_user, U3copy_from_user) + ULTRA3_DO_PATCH(___copy_to_user, U3copy_to_user) + retl + nop + .size cheetah_patch_copyops,.-cheetah_patch_copyops diff -Nru a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S --- a/arch/sparc64/lib/VIScopy.S 2004-10-18 14:55:54 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,1138 +0,0 @@ -/* $Id: VIScopy.S,v 1.27 2002/02/09 19:49:30 davem Exp $ - * VIScopy.S: High speed copy operations utilizing the UltraSparc - * Visual Instruction Set. - * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) - */ - -#include "VIS.h" - - /* VIS code can be used for numerous copy/set operation variants. - * It can be made to work in the kernel, one single instance, - * for all of memcpy, copy_to_user, and copy_from_user by setting - * the ASI src/dest globals correctly. Furthermore it can - * be used for kernel-->kernel page copies as well, a hook label - * is put in here just for this purpose. - * - * For userland, compiling this without __KERNEL__ defined makes - * it work just fine as a generic libc bcopy and memcpy. - * If for userland it is compiled with a 32bit gcc (but you need - * -Wa,-Av9a for as), the code will just rely on lower 32bits of - * IEU registers, if you compile it with 64bit gcc (ie. define - * __sparc_v9__), the code will use full 64bit. - */ - -#ifdef __KERNEL__ - -#include -#include - -#define FPU_CLEAN_RETL \ - ldub [%g6 + TI_CURRENT_DS], %o1; \ - VISExit \ - clr %o0; \ - retl; \ - wr %o1, %g0, %asi; -#define FPU_RETL \ - ldub [%g6 + TI_CURRENT_DS], %o1; \ - VISExit \ - clr %o0; \ - retl; \ - wr %o1, %g0, %asi; -#define NORMAL_RETL \ - ldub [%g6 + TI_CURRENT_DS], %o1; \ - clr %o0; \ - retl; \ - wr %o1, %g0, %asi; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: ba VIScopyfixup_ret; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX2(x,y,c,d,e,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: c, d, e; \ - ba VIScopyfixup_ret; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXO2(x,y) \ -98: x,y; \ - .section __ex_table; \ - .align 4; \ - .word 98b, VIScopyfixup_reto2; \ - .text; \ - .align 4; -#define EXVISN(x,y,n) \ -98: x,y; \ - .section __ex_table; \ - .align 4; \ - .word 98b, VIScopyfixup_vis##n; \ - .text; \ - .align 4; -#define EXT(start,end,handler) \ - .section __ex_table; \ - .align 4; \ - .word start, 0, end, handler; \ - .text; \ - .align 4; -#else -#ifdef REGS_64BIT -#define FPU_CLEAN_RETL \ - retl; \ - mov %g6, %o0; -#define FPU_RETL \ - retl; \ - mov %g6, %o0; -#else -#define FPU_CLEAN_RETL \ - wr %g0, FPRS_FEF, %fprs; \ - retl; \ - mov %g6, %o0; -#define FPU_RETL \ - wr %g0, FPRS_FEF, %fprs; \ - retl; \ - mov %g6, %o0; -#endif -#define NORMAL_RETL \ - retl; \ - mov %g6, %o0; -#define EX(x,y,a,b) x,y -#define EX2(x,y,c,d,e,a,b) x,y -#define EXO2(x,y) x,y -#define EXVISN(x,y,n) x,y -#define EXT(a,b,c) -#endif -#define EXVIS(x,y) EXVISN(x,y,0) -#define EXVIS1(x,y) EXVISN(x,y,1) -#define EXVIS2(x,y) EXVISN(x,y,2) -#define EXVIS3(x,y) EXVISN(x,y,3) -#define EXVIS4(x,y) EXVISN(x,y,4) - -#define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9) \ - faligndata %f1, %f2, %f48; \ - faligndata %f2, %f3, %f50; \ - faligndata %f3, %f4, %f52; \ - faligndata %f4, %f5, %f54; \ - faligndata %f5, %f6, %f56; \ - faligndata %f6, %f7, %f58; \ - faligndata %f7, %f8, %f60; \ - faligndata %f8, %f9, %f62; - -#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \ - EXVIS(LDBLK [%src] ASIBLK, %fdest); \ - ASI_SETDST_BLK \ - EXVIS(STBLK %fsrc, [%dest] ASIBLK); \ - add %src, 0x40, %src; \ - subcc %len, 0x40, %len; \ - be,pn %xcc, jmptgt; \ - add %dest, 0x40, %dest; \ - ASI_SETSRC_BLK - -#define LOOP_CHUNK1(src, dest, len, branch_dest) \ - MAIN_LOOP_CHUNK(src, dest, f0, f48, len, branch_dest) -#define LOOP_CHUNK2(src, dest, len, branch_dest) \ - MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest) -#define LOOP_CHUNK3(src, dest, len, branch_dest) \ - MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest) - -#define STORE_SYNC(dest, fsrc) \ - EXVIS(STBLK %fsrc, [%dest] ASIBLK); \ - add %dest, 0x40, %dest; - -#ifdef __KERNEL__ -#define STORE_JUMP(dest, fsrc, target) \ - srl asi_dest, 3, %g5; \ - EXVIS2(STBLK %fsrc, [%dest] ASIBLK); \ - xor asi_dest, ASI_BLK_XOR1, asi_dest;\ - add %dest, 0x40, %dest; \ - xor asi_dest, %g5, asi_dest; \ - ba,pt %xcc, target; -#else -#define STORE_JUMP(dest, fsrc, target) \ - EXVIS2(STBLK %fsrc, [%dest] ASIBLK); \ - add %dest, 0x40, %dest; \ - ba,pt %xcc, target; -#endif - -#ifndef __KERNEL__ -#define VISLOOP_PAD nop; nop; nop; nop; \ - nop; nop; nop; nop; \ - nop; nop; nop; nop; \ - nop; nop; nop; -#else -#define VISLOOP_PAD -#endif - -#define FINISH_VISCHUNK(dest, f0, f1, left) \ - ASI_SETDST_NOBLK \ - subcc %left, 8, %left; \ - bl,pn %xcc, vis_out; \ - faligndata %f0, %f1, %f48; \ - EXVIS3(STDF %f48, [%dest] ASINORMAL); \ - add %dest, 8, %dest; - -#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ - subcc %left, 8, %left; \ - bl,pn %xcc, vis_out; \ - fsrc1 %f0, %f1; -#define UNEVEN_VISCHUNK(dest, f0, f1, left) \ - UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ - ba,a,pt %xcc, vis_out_slk; - - /* Macros for non-VIS memcpy code. */ -#ifdef REGS_64BIT - -#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ASI_SETSRC_NOBLK \ - LDX [%src + offset + 0x00] ASINORMAL, %t0; \ - LDX [%src + offset + 0x08] ASINORMAL, %t1; \ - LDX [%src + offset + 0x10] ASINORMAL, %t2; \ - LDX [%src + offset + 0x18] ASINORMAL, %t3; \ - ASI_SETDST_NOBLK \ - STW %t0, [%dst + offset + 0x04] ASINORMAL; \ - srlx %t0, 32, %t0; \ - STW %t0, [%dst + offset + 0x00] ASINORMAL; \ - STW %t1, [%dst + offset + 0x0c] ASINORMAL; \ - srlx %t1, 32, %t1; \ - STW %t1, [%dst + offset + 0x08] ASINORMAL; \ - STW %t2, [%dst + offset + 0x14] ASINORMAL; \ - srlx %t2, 32, %t2; \ - STW %t2, [%dst + offset + 0x10] ASINORMAL; \ - STW %t3, [%dst + offset + 0x1c] ASINORMAL; \ - srlx %t3, 32, %t3; \ - STW %t3, [%dst + offset + 0x18] ASINORMAL; - -#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ASI_SETSRC_NOBLK \ - LDX [%src + offset + 0x00] ASINORMAL, %t0; \ - LDX [%src + offset + 0x08] ASINORMAL, %t1; \ - LDX [%src + offset + 0x10] ASINORMAL, %t2; \ - LDX [%src + offset + 0x18] ASINORMAL, %t3; \ - ASI_SETDST_NOBLK \ - STX %t0, [%dst + offset + 0x00] ASINORMAL; \ - STX %t1, [%dst + offset + 0x08] ASINORMAL; \ - STX %t2, [%dst + offset + 0x10] ASINORMAL; \ - STX %t3, [%dst + offset + 0x18] ASINORMAL; \ - ASI_SETSRC_NOBLK \ - LDX [%src + offset + 0x20] ASINORMAL, %t0; \ - LDX [%src + offset + 0x28] ASINORMAL, %t1; \ - LDX [%src + offset + 0x30] ASINORMAL, %t2; \ - LDX [%src + offset + 0x38] ASINORMAL, %t3; \ - ASI_SETDST_NOBLK \ - STX %t0, [%dst + offset + 0x20] ASINORMAL; \ - STX %t1, [%dst + offset + 0x28] ASINORMAL; \ - STX %t2, [%dst + offset + 0x30] ASINORMAL; \ - STX %t3, [%dst + offset + 0x38] ASINORMAL; - -#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ASI_SETSRC_NOBLK \ - LDX [%src - offset - 0x10] ASINORMAL, %t0; \ - LDX [%src - offset - 0x08] ASINORMAL, %t1; \ - ASI_SETDST_NOBLK \ - STW %t0, [%dst - offset - 0x0c] ASINORMAL; \ - srlx %t0, 32, %t2; \ - STW %t2, [%dst - offset - 0x10] ASINORMAL; \ - STW %t1, [%dst - offset - 0x04] ASINORMAL; \ - srlx %t1, 32, %t3; \ - STW %t3, [%dst - offset - 0x08] ASINORMAL; - -#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1) \ - ASI_SETSRC_NOBLK \ - LDX [%src - offset - 0x10] ASINORMAL, %t0; \ - LDX [%src - offset - 0x08] ASINORMAL, %t1; \ - ASI_SETDST_NOBLK \ - STX %t0, [%dst - offset - 0x10] ASINORMAL; \ - STX %t1, [%dst - offset - 0x08] ASINORMAL; - -#else /* !REGS_64BIT */ - -#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lduw [%src + offset + 0x00], %t0; \ - lduw [%src + offset + 0x04], %t1; \ - lduw [%src + offset + 0x08], %t2; \ - lduw [%src + offset + 0x0c], %t3; \ - stw %t0, [%dst + offset + 0x00]; \ - stw %t1, [%dst + offset + 0x04]; \ - stw %t2, [%dst + offset + 0x08]; \ - stw %t3, [%dst + offset + 0x0c]; \ - lduw [%src + offset + 0x10], %t0; \ - lduw [%src + offset + 0x14], %t1; \ - lduw [%src + offset + 0x18], %t2; \ - lduw [%src + offset + 0x1c], %t3; \ - stw %t0, [%dst + offset + 0x10]; \ - stw %t1, [%dst + offset + 0x14]; \ - stw %t2, [%dst + offset + 0x18]; \ - stw %t3, [%dst + offset + 0x1c]; - -#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lduw [%src - offset - 0x10], %t0; \ - lduw [%src - offset - 0x0c], %t1; \ - lduw [%src - offset - 0x08], %t2; \ - lduw [%src - offset - 0x04], %t3; \ - stw %t0, [%dst - offset - 0x10]; \ - stw %t1, [%dst - offset - 0x0c]; \ - stw %t2, [%dst - offset - 0x08]; \ - stw %t3, [%dst - offset - 0x04]; - -#endif /* !REGS_64BIT */ - -#ifdef __KERNEL__ - .section __ex_table,#alloc - .section .fixup,#alloc,#execinstr -#endif - - .text - .align 32 - .globl memcpy - .type memcpy,@function - - .globl bcopy - .type bcopy,@function - -#ifdef __KERNEL__ -memcpy_private: -memcpy: mov ASI_P, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - mov ASI_P, asi_dest ! IEU1 - retl - clr %o0 - - .align 32 - .globl __copy_from_user - .type __copy_from_user,@function -__copy_from_user:rd %asi, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - mov ASI_P, asi_dest ! IEU1 - - .globl __copy_to_user - .type __copy_to_user,@function -__copy_to_user: mov ASI_P, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - rd %asi, asi_dest ! IEU1 - retl ! CTI Group - clr %o0 ! IEU0 Group - - .globl __copy_in_user - .type __copy_in_user,@function -__copy_in_user: rd %asi, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - mov asi_src, asi_dest ! IEU1 - retl ! CTI Group - clr %o0 ! IEU0 Group -#endif - -bcopy: or %o0, 0, %g3 ! IEU0 Group - addcc %o1, 0, %o0 ! IEU1 - brgez,pt %o2, memcpy_private ! CTI - or %g3, 0, %o1 ! IEU0 Group - retl ! CTI Group brk forced - clr %o0 ! IEU0 - - -#ifdef __KERNEL__ -#define BRANCH_ALWAYS 0x10680000 -#define NOP 0x01000000 -#define ULTRA3_DO_PATCH(OLD, NEW) \ - sethi %hi(NEW), %g1; \ - or %g1, %lo(NEW), %g1; \ - sethi %hi(OLD), %g2; \ - or %g2, %lo(OLD), %g2; \ - sub %g1, %g2, %g1; \ - sethi %hi(BRANCH_ALWAYS), %g3; \ - srl %g1, 2, %g1; \ - or %g3, %lo(BRANCH_ALWAYS), %g3; \ - or %g3, %g1, %g3; \ - stw %g3, [%g2]; \ - sethi %hi(NOP), %g3; \ - or %g3, %lo(NOP), %g3; \ - stw %g3, [%g2 + 0x4]; \ - flush %g2; - - .globl cheetah_patch_copyops -cheetah_patch_copyops: - ULTRA3_DO_PATCH(memcpy, U3memcpy) - ULTRA3_DO_PATCH(__copy_from_user, U3copy_from_user) - ULTRA3_DO_PATCH(__copy_to_user, U3copy_to_user) - ULTRA3_DO_PATCH(__copy_in_user, U3copy_in_user) - retl - nop -#undef BRANCH_ALWAYS -#undef NOP -#undef ULTRA3_DO_PATCH -#endif /* __KERNEL__ */ - - .align 32 -#ifdef __KERNEL__ - andcc %o0, 7, %g2 ! IEU1 Group -#endif -VIS_enter: - be,pt %xcc, dest_is_8byte_aligned ! CTI -#ifdef __KERNEL__ - nop ! IEU0 Group -#else - andcc %o0, 0x38, %g5 ! IEU1 Group -#endif -do_dest_8byte_align: - mov 8, %g1 ! IEU0 - sub %g1, %g2, %g2 ! IEU0 Group - andcc %o0, 1, %g0 ! IEU1 - be,pt %icc, 2f ! CTI - sub %o2, %g2, %o2 ! IEU0 Group -1: ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %o5, - add %o2, %g2) ! Load Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %g2, 1, %g2 ! IEU1 Group - be,pn %xcc, 3f ! CTI - EX2(STB %o5, [%o0 - 1] ASINORMAL, - add %g2, 1, %g2, - add %o2, %g2) ! Store -2: ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %o5, - add %o2, %g2) ! Load Group - add %o0, 2, %o0 ! IEU0 - EX2(LDUB [%o1 + 1] ASINORMAL, %g3, - sub %o0, 2, %o0, - add %o2, %g2) ! Load Group - ASI_SETDST_NOBLK ! LSU Group - subcc %g2, 2, %g2 ! IEU1 Group - EX2(STB %o5, [%o0 - 2] ASINORMAL, - add %g2, 2, %g2, - add %o2, %g2) ! Store - add %o1, 2, %o1 ! IEU0 - bne,pt %xcc, 2b ! CTI Group - EX2(STB %g3, [%o0 - 1] ASINORMAL, - add %g2, 1, %g2, - add %o2, %g2) ! Store -#ifdef __KERNEL__ -3: -dest_is_8byte_aligned: - VISEntry - andcc %o0, 0x38, %g5 ! IEU1 Group -#else -3: andcc %o0, 0x38, %g5 ! IEU1 Group -dest_is_8byte_aligned: -#endif - be,pt %icc, dest_is_64byte_aligned ! CTI - mov 64, %g1 ! IEU0 - fmovd %f0, %f2 ! FPU - sub %g1, %g5, %g5 ! IEU0 Group - ASI_SETSRC_NOBLK ! LSU Group - alignaddr %o1, %g0, %g1 ! GRU Group - EXO2(LDDF [%g1] ASINORMAL, %f4) ! Load Group - sub %o2, %g5, %o2 ! IEU0 -1: EX(LDDF [%g1 + 0x8] ASINORMAL, %f6, - add %o2, %g5) ! Load Group - add %g1, 0x8, %g1 ! IEU0 Group - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f4, %f6, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %g5, 8, %g5, - add %o2, %g5) ! Store - add %o1, 8, %o1 ! IEU0 Group - be,pn %xcc, dest_is_64byte_aligned ! CTI - add %o0, 8, %o0 ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDDF [%g1 + 0x8] ASINORMAL, %f4, - add %o2, %g5) ! Load Group - add %g1, 8, %g1 ! IEU0 - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f6, %f4, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %g5, 8, %g5, - add %o2, %g5) ! Store - add %o1, 8, %o1 ! IEU0 - ASI_SETSRC_NOBLK ! LSU Group - bne,pt %xcc, 1b ! CTI Group - add %o0, 8, %o0 ! IEU0 -dest_is_64byte_aligned: - membar #LoadStore | #StoreStore | #StoreLoad ! LSU Group -#ifndef __KERNEL__ - wr %g0, ASI_BLK_P, %asi ! LSU Group -#endif - subcc %o2, 0x40, %g7 ! IEU1 Group - mov %o1, %g1 ! IEU0 - andncc %g7, (0x40 - 1), %g7 ! IEU1 Group - srl %g1, 3, %g2 ! IEU0 - sub %o2, %g7, %g3 ! IEU0 Group - andn %o1, (0x40 - 1), %o1 ! IEU1 - and %g2, 7, %g2 ! IEU0 Group - andncc %g3, 0x7, %g3 ! IEU1 - fmovd %f0, %f2 ! FPU - sub %g3, 0x10, %g3 ! IEU0 Group - sub %o2, %g7, %o2 ! IEU1 -#ifdef __KERNEL__ - or asi_src, ASI_BLK_OR, asi_src ! IEU0 Group - or asi_dest, ASI_BLK_OR, asi_dest ! IEU1 -#endif - alignaddr %g1, %g0, %g0 ! GRU Group - add %g1, %g7, %g1 ! IEU0 Group - subcc %o2, %g3, %o2 ! IEU1 - ASI_SETSRC_BLK ! LSU Group - EXVIS1(LDBLK [%o1 + 0x00] ASIBLK, %f0) ! LSU Group - add %g1, %g3, %g1 ! IEU0 - EXVIS1(LDBLK [%o1 + 0x40] ASIBLK, %f16) ! LSU Group - sub %g7, 0x80, %g7 ! IEU0 - EXVIS(LDBLK [%o1 + 0x80] ASIBLK, %f32) ! LSU Group -#ifdef __KERNEL__ -vispc: sll %g2, 9, %g2 ! IEU0 Group - sethi %hi(vis00), %g5 ! IEU1 - or %g5, %lo(vis00), %g5 ! IEU0 Group - jmpl %g5 + %g2, %g0 ! CTI Group brk forced - addcc %o1, 0xc0, %o1 ! IEU1 Group -#else - ! Clk1 Group 8-( - ! Clk2 Group 8-( - ! Clk3 Group 8-( - ! Clk4 Group 8-( -vispc: rd %pc, %g5 ! PDU Group 8-( - addcc %g5, %lo(vis00 - vispc), %g5 ! IEU1 Group - sll %g2, 9, %g2 ! IEU0 - jmpl %g5 + %g2, %g0 ! CTI Group brk forced - addcc %o1, 0xc0, %o1 ! IEU1 Group -#endif - .align 512 /* OK, here comes the fun part... */ -vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01) - FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02) - FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) LOOP_CHUNK3(o1, o0, g7, vis03) - b,pt %xcc, vis00+4; faligndata %f0, %f2, %f48 -vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_JUMP(o0, f48, finish_f0) membar #Sync -vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, finish_f16) membar #Sync -vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync - VISLOOP_PAD -vis10:FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) LOOP_CHUNK1(o1, o0, g7, vis11) - FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) LOOP_CHUNK2(o1, o0, g7, vis12) - FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) LOOP_CHUNK3(o1, o0, g7, vis13) - b,pt %xcc, vis10+4; faligndata %f2, %f4, %f48 -vis11:FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) STORE_JUMP(o0, f48, finish_f2) membar #Sync -vis12:FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) STORE_JUMP(o0, f48, finish_f18) membar #Sync -vis13:FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) STORE_JUMP(o0, f48, finish_f34) membar #Sync - VISLOOP_PAD -vis20:FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) LOOP_CHUNK1(o1, o0, g7, vis21) - FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) LOOP_CHUNK2(o1, o0, g7, vis22) - FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) LOOP_CHUNK3(o1, o0, g7, vis23) - b,pt %xcc, vis20+4; faligndata %f4, %f6, %f48 -vis21:FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) STORE_JUMP(o0, f48, finish_f4) membar #Sync -vis22:FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) STORE_JUMP(o0, f48, finish_f20) membar #Sync -vis23:FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) STORE_JUMP(o0, f48, finish_f36) membar #Sync - VISLOOP_PAD -vis30:FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) LOOP_CHUNK1(o1, o0, g7, vis31) - FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) LOOP_CHUNK2(o1, o0, g7, vis32) - FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) LOOP_CHUNK3(o1, o0, g7, vis33) - b,pt %xcc, vis30+4; faligndata %f6, %f8, %f48 -vis31:FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) STORE_JUMP(o0, f48, finish_f6) membar #Sync -vis32:FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) STORE_JUMP(o0, f48, finish_f22) membar #Sync -vis33:FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) STORE_JUMP(o0, f48, finish_f38) membar #Sync - VISLOOP_PAD -vis40:FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) LOOP_CHUNK1(o1, o0, g7, vis41) - FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) LOOP_CHUNK2(o1, o0, g7, vis42) - FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) LOOP_CHUNK3(o1, o0, g7, vis43) - b,pt %xcc, vis40+4; faligndata %f8, %f10, %f48 -vis41:FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) STORE_JUMP(o0, f48, finish_f8) membar #Sync -vis42:FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) STORE_JUMP(o0, f48, finish_f24) membar #Sync -vis43:FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) STORE_JUMP(o0, f48, finish_f40) membar #Sync - VISLOOP_PAD -vis50:FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) LOOP_CHUNK1(o1, o0, g7, vis51) - FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) LOOP_CHUNK2(o1, o0, g7, vis52) - FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) LOOP_CHUNK3(o1, o0, g7, vis53) - b,pt %xcc, vis50+4; faligndata %f10, %f12, %f48 -vis51:FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) STORE_JUMP(o0, f48, finish_f10) membar #Sync -vis52:FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) STORE_JUMP(o0, f48, finish_f26) membar #Sync -vis53:FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) STORE_JUMP(o0, f48, finish_f42) membar #Sync - VISLOOP_PAD -vis60:FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) LOOP_CHUNK1(o1, o0, g7, vis61) - FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) LOOP_CHUNK2(o1, o0, g7, vis62) - FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) LOOP_CHUNK3(o1, o0, g7, vis63) - b,pt %xcc, vis60+4; faligndata %f12, %f14, %f48 -vis61:FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) STORE_JUMP(o0, f48, finish_f12) membar #Sync -vis62:FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) STORE_JUMP(o0, f48, finish_f28) membar #Sync -vis63:FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) STORE_JUMP(o0, f48, finish_f44) membar #Sync - VISLOOP_PAD -vis70:FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) LOOP_CHUNK1(o1, o0, g7, vis71) - FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) LOOP_CHUNK2(o1, o0, g7, vis72) - FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) LOOP_CHUNK3(o1, o0, g7, vis73) - b,pt %xcc, vis70+4; faligndata %f14, %f16, %f48 -vis71:FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) STORE_JUMP(o0, f48, finish_f14) membar #Sync -vis72:FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) STORE_JUMP(o0, f48, finish_f30) membar #Sync -vis73:FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) STORE_JUMP(o0, f48, finish_f46) membar #Sync - VISLOOP_PAD -finish_f0: FINISH_VISCHUNK(o0, f0, f2, g3) -finish_f2: FINISH_VISCHUNK(o0, f2, f4, g3) -finish_f4: FINISH_VISCHUNK(o0, f4, f6, g3) -finish_f6: FINISH_VISCHUNK(o0, f6, f8, g3) -finish_f8: FINISH_VISCHUNK(o0, f8, f10, g3) -finish_f10: FINISH_VISCHUNK(o0, f10, f12, g3) -finish_f12: FINISH_VISCHUNK(o0, f12, f14, g3) -finish_f14: UNEVEN_VISCHUNK(o0, f14, f0, g3) -finish_f16: FINISH_VISCHUNK(o0, f16, f18, g3) -finish_f18: FINISH_VISCHUNK(o0, f18, f20, g3) -finish_f20: FINISH_VISCHUNK(o0, f20, f22, g3) -finish_f22: FINISH_VISCHUNK(o0, f22, f24, g3) -finish_f24: FINISH_VISCHUNK(o0, f24, f26, g3) -finish_f26: FINISH_VISCHUNK(o0, f26, f28, g3) -finish_f28: FINISH_VISCHUNK(o0, f28, f30, g3) -finish_f30: UNEVEN_VISCHUNK(o0, f30, f0, g3) -finish_f32: FINISH_VISCHUNK(o0, f32, f34, g3) -finish_f34: FINISH_VISCHUNK(o0, f34, f36, g3) -finish_f36: FINISH_VISCHUNK(o0, f36, f38, g3) -finish_f38: FINISH_VISCHUNK(o0, f38, f40, g3) -finish_f40: FINISH_VISCHUNK(o0, f40, f42, g3) -finish_f42: FINISH_VISCHUNK(o0, f42, f44, g3) -finish_f44: FINISH_VISCHUNK(o0, f44, f46, g3) -finish_f46: UNEVEN_VISCHUNK_LAST(o0, f46, f0, g3) -vis_out_slk: -#ifdef __KERNEL__ - srl asi_src, 3, %g5 ! IEU0 Group - xor asi_src, ASI_BLK_XOR1, asi_src ! IEU1 - xor asi_src, %g5, asi_src ! IEU0 Group -#endif -vis_slk:ASI_SETSRC_NOBLK ! LSU Group - EXVIS3(LDDF [%o1] ASINORMAL, %f2) ! Load Group - add %o1, 8, %o1 ! IEU0 - subcc %g3, 8, %g3 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f0, %f2, %f8 ! GRU Group - EXVIS4(STDF %f8, [%o0] ASINORMAL) ! Store - bl,pn %xcc, vis_out_slp ! CTI - add %o0, 8, %o0 ! IEU0 Group - ASI_SETSRC_NOBLK ! LSU Group - EXVIS3(LDDF [%o1] ASINORMAL, %f0) ! Load Group - add %o1, 8, %o1 ! IEU0 - subcc %g3, 8, %g3 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f2, %f0, %f8 ! GRU Group - EXVIS4(STDF %f8, [%o0] ASINORMAL) ! Store - bge,pt %xcc, vis_slk ! CTI - add %o0, 8, %o0 ! IEU0 Group -vis_out_slp: -#ifdef __KERNEL__ - brz,pt %o2, vis_ret ! CTI Group - mov %g1, %o1 ! IEU0 - ba,pt %xcc, vis_slp+4 ! CTI Group - ASI_SETSRC_NOBLK ! LSU Group -#endif -vis_out:brz,pt %o2, vis_ret ! CTI Group - mov %g1, %o1 ! IEU0 -#ifdef __KERNEL__ - srl asi_src, 3, %g5 ! IEU0 Group - xor asi_src, ASI_BLK_XOR1, asi_src ! IEU1 - xor asi_src, %g5, asi_src ! IEU0 Group -#endif -vis_slp:ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 1, %o2 ! IEU1 - bne,pt %xcc, vis_slp ! CTI - EX(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store Group -vis_ret:membar #StoreLoad | #StoreStore ! LSU Group - FPU_CLEAN_RETL - - -__memcpy_short: - andcc %o2, 1, %g0 ! IEU1 Group - be,pt %icc, 2f ! CTI -1: ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 1, %o2 ! IEU1 Group - be,pn %xcc, short_ret ! CTI - EX(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store -2: ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD Group - add %o0, 2, %o0 ! IEU0 - EX2(LDUB [%o1 + 1] ASINORMAL, %o5, - sub %o0, 2, %o0, - add %o2, %g0) ! LOAD Group - add %o1, 2, %o1 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 2, %o2 ! IEU1 Group - EX(STB %g5, [%o0 - 2] ASINORMAL, - add %o2, 2) ! Store - bne,pt %xcc, 2b ! CTI - EX(STB %o5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store -short_ret: - NORMAL_RETL - -#ifndef __KERNEL__ -memcpy_private: -memcpy: -#ifndef REGS_64BIT - srl %o2, 0, %o2 ! IEU1 Group -#endif - brz,pn %o2, short_ret ! CTI Group - mov %o0, %g6 ! IEU0 -#endif -__memcpy_entry: - cmp %o2, 15 ! IEU1 Group - bleu,pn %xcc, __memcpy_short ! CTI - cmp %o2, (64 * 6) ! IEU1 Group - bgeu,pn %xcc, VIS_enter ! CTI - andcc %o0, 7, %g2 ! IEU1 Group - sub %o0, %o1, %g5 ! IEU0 - andcc %g5, 3, %o5 ! IEU1 Group - bne,pn %xcc, memcpy_noVIS_misaligned ! CTI - andcc %o1, 3, %g0 ! IEU1 Group -#ifdef REGS_64BIT - be,a,pt %xcc, 3f ! CTI - andcc %o1, 4, %g0 ! IEU1 Group - andcc %o1, 1, %g0 ! IEU1 Group -#else /* !REGS_64BIT */ - be,pt %xcc, 5f ! CTI - andcc %o1, 1, %g0 ! IEU1 Group -#endif /* !REGS_64BIT */ - be,pn %xcc, 4f ! CTI - andcc %o1, 2, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g2) ! Load Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - sub %o2, 1, %o2 ! IEU0 Group - ASI_SETDST_NOBLK ! LSU Group - bne,pn %xcc, 5f ! CTI Group - EX(STB %g2, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store -4: ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUH [%o1] ASINORMAL, %g2) ! Load Group - add %o1, 2, %o1 ! IEU0 - add %o0, 2, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - sub %o2, 2, %o2 ! IEU0 - EX(STH %g2, [%o0 - 2] ASINORMAL, - add %o2, 2) ! Store Group + bubble -#ifdef REGS_64BIT -5: andcc %o1, 4, %g0 ! IEU1 -3: be,a,pn %xcc, 2f ! CTI - andcc %o2, -128, %g7 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUW [%o1] ASINORMAL, %g5) ! Load Group - add %o1, 4, %o1 ! IEU0 - add %o0, 4, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - sub %o2, 4, %o2 ! IEU0 Group - EX(STW %g5, [%o0 - 4] ASINORMAL, - add %o2, 4) ! Store - andcc %o2, -128, %g7 ! IEU1 Group -2: be,pn %xcc, 3f ! CTI - andcc %o0, 4, %g0 ! IEU1 Group - be,pn %xcc, 82f + 4 ! CTI Group -#else /* !REGS_64BIT */ -5: andcc %o2, -128, %g7 ! IEU1 - be,a,pn %xcc, 41f ! CTI - andcc %o2, 0x70, %g7 ! IEU1 Group -#endif /* !REGS_64BIT */ -5: MOVE_BIGCHUNK(o1, o0, 0x00, g1, g3, g5, o5) - MOVE_BIGCHUNK(o1, o0, 0x20, g1, g3, g5, o5) - MOVE_BIGCHUNK(o1, o0, 0x40, g1, g3, g5, o5) - MOVE_BIGCHUNK(o1, o0, 0x60, g1, g3, g5, o5) - EXT(5b,35f,VIScopyfixup1) -35: subcc %g7, 128, %g7 ! IEU1 Group - add %o1, 128, %o1 ! IEU0 - bne,pt %xcc, 5b ! CTI - add %o0, 128, %o0 ! IEU0 Group -3: andcc %o2, 0x70, %g7 ! IEU1 Group -41: be,pn %xcc, 80f ! CTI - andcc %o2, 8, %g0 ! IEU1 Group -#ifdef __KERNEL__ -79: sethi %hi(80f), %o5 ! IEU0 - sll %g7, 1, %g5 ! IEU0 Group - add %o1, %g7, %o1 ! IEU1 - srl %g7, 1, %g2 ! IEU0 Group - sub %o5, %g5, %o5 ! IEU1 - sub %o5, %g2, %o5 ! IEU0 Group - jmpl %o5 + %lo(80f), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#else - ! Clk1 8-( - ! Clk2 8-( - ! Clk3 8-( - ! Clk4 8-( -79: rd %pc, %o5 ! PDU Group - sll %g7, 1, %g5 ! IEU0 Group - add %o1, %g7, %o1 ! IEU1 - sub %o5, %g5, %o5 ! IEU0 Group - jmpl %o5 + %lo(80f - 79b), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#endif -36: MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g5, o5) - EXT(36b,80f,VIScopyfixup2) -80: be,pt %xcc, 81f ! CTI - andcc %o2, 4, %g0 ! IEU1 -#ifdef REGS_64BIT - ASI_SETSRC_NOBLK ! LSU Group - EX(LDX [%o1] ASINORMAL, %g2, - and %o2, 0xf) ! Load Group - add %o0, 8, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - EX(STW %g2, [%o0 - 0x4] ASINORMAL, - and %o2, 0xf) ! Store Group - add %o1, 8, %o1 ! IEU1 - srlx %g2, 32, %g2 ! IEU0 Group - EX2(STW %g2, [%o0 - 0x8] ASINORMAL, - and %o2, 0xf, %o2, - sub %o2, 4) ! Store -#else /* !REGS_64BIT */ - lduw [%o1], %g2 ! Load Group - add %o0, 8, %o0 ! IEU0 - lduw [%o1 + 0x4], %g3 ! Load Group - add %o1, 8, %o1 ! IEU0 - stw %g2, [%o0 - 0x8] ! Store Group - stw %g3, [%o0 - 0x4] ! Store Group -#endif /* !REGS_64BIT */ -81: be,pt %xcc, 1f ! CTI - andcc %o2, 2, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUW [%o1] ASINORMAL, %g2, - and %o2, 0x7) ! Load Group - add %o1, 4, %o1 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - EX(STW %g2, [%o0] ASINORMAL, - and %o2, 0x7) ! Store Group - add %o0, 4, %o0 ! IEU0 -1: be,pt %xcc, 1f ! CTI - andcc %o2, 1, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUH [%o1] ASINORMAL, %g2, - and %o2, 0x3) ! Load Group - add %o1, 2, %o1 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - EX(STH %g2, [%o0] ASINORMAL, - and %o2, 0x3) ! Store Group - add %o0, 2, %o0 ! IEU0 -1: be,pt %xcc, normal_retl ! CTI - nop ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %g2, - add %g0, 1) ! Load Group - ASI_SETDST_NOBLK ! LSU Group - EX(STB %g2, [%o0] ASINORMAL, - add %g0, 1) ! Store Group + bubble -normal_retl: - NORMAL_RETL - -#ifdef REGS_64BIT -82: MOVE_BIGALIGNCHUNK(o1, o0, 0x00, g1, g3, g5, o5) - MOVE_BIGALIGNCHUNK(o1, o0, 0x40, g1, g3, g5, o5) - EXT(82b,37f,VIScopyfixup3) -37: subcc %g7, 128, %g7 ! IEU1 Group - add %o1, 128, %o1 ! IEU0 - bne,pt %xcc, 82b ! CTI - add %o0, 128, %o0 ! IEU0 Group - andcc %o2, 0x70, %g7 ! IEU1 - be,pn %xcc, 84f ! CTI - andcc %o2, 8, %g0 ! IEU1 Group -#ifdef __KERNEL__ -83: srl %g7, 1, %g5 ! IEU0 - sethi %hi(84f), %o5 ! IEU0 Group - add %g7, %g5, %g5 ! IEU1 - add %o1, %g7, %o1 ! IEU0 Group - sub %o5, %g5, %o5 ! IEU1 - jmpl %o5 + %lo(84f), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#else - ! Clk1 8-( - ! Clk2 8-( - ! Clk3 8-( - ! Clk4 8-( -83: rd %pc, %o5 ! PDU Group - add %o1, %g7, %o1 ! IEU0 Group - sub %o5, %g7, %o5 ! IEU1 - jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#endif -38: MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3) - EXT(38b,84f,VIScopyfixup4) -84: be,pt %xcc, 85f ! CTI Group - andcc %o2, 4, %g0 ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDX [%o1] ASINORMAL, %g2, - and %o2, 0xf) ! Load Group - add %o0, 8, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - add %o1, 8, %o1 ! IEU0 Group - EX(STX %g2, [%o0 - 0x8] ASINORMAL, - and %o2, 0xf) ! Store -85: be,pt %xcc, 1f ! CTI - andcc %o2, 2, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUW [%o1] ASINORMAL, %g2, - and %o2, 0x7) ! Load Group - add %o0, 4, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - add %o1, 4, %o1 ! IEU0 Group - EX(STW %g2, [%o0 - 0x4] ASINORMAL, - and %o2, 0x7) ! Store -1: be,pt %xcc, 1f ! CTI - andcc %o2, 1, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUH [%o1] ASINORMAL, %g2, - and %o2, 0x3) ! Load Group - add %o0, 2, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - add %o1, 2, %o1 ! IEU0 Group - EX(STH %g2, [%o0 - 0x2] ASINORMAL, - and %o2, 0x3) ! Store -1: be,pt %xcc, 1f ! CTI - nop ! IEU0 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %g2, - add %g0, 1) ! Load Group - ASI_SETDST_NOBLK ! LSU Group - EX(STB %g2, [%o0] ASINORMAL, - add %g0, 1) ! Store Group + bubble -1: NORMAL_RETL -#endif /* REGS_64BIT */ - -memcpy_noVIS_misaligned: - brz,pt %g2, 2f ! CTI Group - mov 8, %g1 ! IEU0 - sub %g1, %g2, %g2 ! IEU0 Group - sub %o2, %g2, %o2 ! IEU0 Group -1: ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %g5, - add %o2, %g2) ! Load Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %g2, 1, %g2 ! IEU1 Group - bne,pt %xcc, 1b ! CTI - EX2(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, %g2, %o2, - add %o2, 1) ! Store -2: -#ifdef __KERNEL__ - VISEntry -#endif - andn %o2, 7, %g5 ! IEU0 Group - and %o2, 7, %o2 ! IEU1 - fmovd %f0, %f2 ! FPU - ASI_SETSRC_NOBLK ! LSU Group - alignaddr %o1, %g0, %g1 ! GRU Group - EXO2(LDDF [%g1] ASINORMAL, %f4) ! Load Group -1: EX(LDDF [%g1 + 0x8] ASINORMAL, %f6, - add %o2, %g5) ! Load Group - add %g1, 0x8, %g1 ! IEU0 Group - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f4, %f6, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %o2, %g5, %o2, - add %o2, 8) ! Store - add %o1, 8, %o1 ! IEU0 Group - be,pn %xcc, end_cruft ! CTI - add %o0, 8, %o0 ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDDF [%g1 + 0x8] ASINORMAL, %f4, - add %o2, %g5) ! Load Group - add %g1, 8, %g1 ! IEU0 - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f6, %f4, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %o2, %g5, %o2, - add %o2, 8) ! Store - add %o1, 8, %o1 ! IEU0 - ASI_SETSRC_NOBLK ! LSU Group - bne,pn %xcc, 1b ! CTI Group - add %o0, 8, %o0 ! IEU0 -end_cruft: - brz,pn %o2, fpu_retl ! CTI Group -#ifndef __KERNEL__ - nop ! IEU0 -#else - ASI_SETSRC_NOBLK ! LSU Group -#endif - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 1, %o2 ! IEU1 - bne,pt %xcc, vis_slp ! CTI - EX(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store Group -fpu_retl: - FPU_RETL - -#ifdef __KERNEL__ - .section .fixup - .align 4 -VIScopyfixup_reto2: - mov %o2, %o1 -VIScopyfixup_ret: - /* If this is copy_from_user(), zero out the rest of the - * kernel buffer. - */ - ldub [%g6 + TI_CURRENT_DS], %o4 - andcc asi_src, 0x1, %g0 - be,pt %icc, 1f - VISExit - andcc asi_dest, 0x1, %g0 - bne,pn %icc, 1f - nop - save %sp, -160, %sp - mov %i0, %o0 - call __bzero - mov %i1, %o1 - restore -1: mov %o1, %o0 - retl - wr %o4, %g0, %asi -VIScopyfixup1: subcc %g2, 18, %g2 - add %o0, 32, %o0 - bgeu,a,pt %icc, VIScopyfixup1 - sub %g7, 32, %g7 - sub %o0, 32, %o0 - rd %pc, %g5 - add %g2, (18 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 2f -.byte 0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 12, 12, 16, 20, 20, 24, 28, 28 - .align 4 -VIScopyfixup2: mov (7 * 16), %g7 -1: subcc %g2, 10, %g2 - bgeu,a,pt %icc, 1b - sub %g7, 16, %g7 - sub %o0, %g7, %o0 - rd %pc, %g5 - add %g2, (10 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 4f -.byte 0, 0, 0, 0, 0, 4, 4, 8, 12, 12 - .align 4 -VIScopyfixup3: subcc %g2, 10, %g2 - add %o0, 32, %o0 - bgeu,a,pt %icc, VIScopyfixup3 - sub %g7, 32, %g7 - sub %o0, 32, %o0 - rd %pc, %g5 - add %g2, (10 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 2f -.byte 0, 0, 0, 0, 0, 0, 0, 8, 16, 24 - .align 4 -2: and %o2, 0x7f, %o2 - sub %g7, %g2, %g7 - ba,pt %xcc, VIScopyfixup_ret - add %g7, %o2, %o1 -VIScopyfixup4: mov (7 * 16), %g7 -3: subcc %g2, 6, %g2 - bgeu,a,pt %icc, 3b - sub %g7, 16, %g7 - sub %o0, %g7, %o0 - rd %pc, %g5 - add %g2, (6 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 4f -.byte 0, 0, 0, 0, 0, 8 - .align 4 -4: and %o2, 0xf, %o2 - sub %g7, %g2, %g7 - ba,pt %xcc, VIScopyfixup_ret - add %g7, %o2, %o1 -VIScopyfixup_vis2: - sub %o2, 0x40, %o2 -VIScopyfixup_vis0: - add %o2, 0x80, %o2 -VIScopyfixup_vis1: - add %g7, %g3, %g7 - ba,pt %xcc, VIScopyfixup_ret - add %o2, %g7, %o1 -VIScopyfixup_vis4: - add %g3, 8, %g3 -VIScopyfixup_vis3: - add %g3, 8, %g3 - ba,pt %xcc, VIScopyfixup_ret - add %o2, %g3, %o1 -#endif - -#ifdef __KERNEL__ - .text - .align 32 - - .globl __memmove - .type __memmove,@function - - .globl memmove - .type memmove,@function - -memmove: -__memmove: cmp %o0, %o1 - blu,pt %xcc, memcpy_private - sub %o0, %o1, %g5 - add %o1, %o2, %g3 - cmp %g3, %o0 - bleu,pt %xcc, memcpy_private - add %o1, %o2, %g5 - add %o0, %o2, %o5 - - sub %g5, 1, %o1 - sub %o5, 1, %o0 -1: ldub [%o1], %g5 - subcc %o2, 1, %o2 - sub %o1, 1, %o1 - stb %g5, [%o0] - bne,pt %icc, 1b - sub %o0, 1, %o0 - - retl - clr %o0 -#endif diff -Nru a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S --- a/arch/sparc64/lib/atomic.S 2004-10-18 14:57:03 -07:00 +++ b/arch/sparc64/lib/atomic.S 2004-10-18 14:57:03 -07:00 @@ -10,6 +10,7 @@ .align 64 .globl __atomic_add + .type __atomic_add,#function __atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ lduw [%o1], %g5 add %g5, %o0, %g7 @@ -19,8 +20,10 @@ membar #StoreLoad | #StoreStore retl add %g7, %o0, %o0 + .size __atomic_add, .-__atomic_add .globl __atomic_sub + .type __atomic_sub,#function __atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */ lduw [%o1], %g5 sub %g5, %o0, %g7 @@ -30,8 +33,10 @@ membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 + .size __atomic_sub, .-__atomic_sub .globl __atomic64_add + .type __atomic64_add,#function __atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ ldx [%o1], %g5 add %g5, %o0, %g7 @@ -41,8 +46,10 @@ membar #StoreLoad | #StoreStore retl add %g7, %o0, %o0 + .size __atomic64_add, .-__atomic64_add .globl __atomic64_sub + .type __atomic64_sub,#function __atomic64_sub: /* %o0 = increment, %o1 = atomic_ptr */ ldx [%o1], %g5 sub %g5, %o0, %g7 @@ -52,4 +59,4 @@ membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 - + .size __atomic64_sub, .-__atomic64_sub diff -Nru a/arch/sparc64/lib/bitops.S b/arch/sparc64/lib/bitops.S --- a/arch/sparc64/lib/bitops.S 2004-10-18 14:57:03 -07:00 +++ b/arch/sparc64/lib/bitops.S 2004-10-18 14:57:03 -07:00 @@ -9,6 +9,7 @@ .text .align 64 .globl ___test_and_set_bit + .type ___test_and_set_bit,#function ___test_and_set_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 @@ -26,8 +27,10 @@ ldx [%o1], %g7 2: retl membar #StoreLoad | #StoreStore + .size ___test_and_set_bit, .-___test_and_set_bit .globl ___test_and_clear_bit + .type ___test_and_clear_bit,#function ___test_and_clear_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 @@ -45,8 +48,10 @@ ldx [%o1], %g7 2: retl membar #StoreLoad | #StoreStore + .size ___test_and_clear_bit, .-___test_and_clear_bit .globl ___test_and_change_bit + .type ___test_and_change_bit,#function ___test_and_change_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 @@ -64,41 +69,4 @@ 2: retl membar #StoreLoad | #StoreStore nop - - .globl ___test_and_set_le_bit -___test_and_set_le_bit: /* %o0=nr, %o1=addr */ - srlx %o0, 5, %g1 - mov 1, %g5 - sllx %g1, 2, %g3 - and %o0, 31, %g2 - sllx %g5, %g2, %g5 - add %o1, %g3, %o1 - lduwa [%o1] ASI_PL, %g7 -1: andcc %g7, %g5, %o0 - bne,pn %icc, 2f - xor %g7, %g5, %g1 - casa [%o1] ASI_PL, %g7, %g1 - cmp %g7, %g1 - bne,a,pn %icc, 1b - lduwa [%o1] ASI_PL, %g7 -2: retl - membar #StoreLoad | #StoreStore - - .globl ___test_and_clear_le_bit -___test_and_clear_le_bit: /* %o0=nr, %o1=addr */ - srlx %o0, 5, %g1 - mov 1, %g5 - sllx %g1, 2, %g3 - and %o0, 31, %g2 - sllx %g5, %g2, %g5 - add %o1, %g3, %o1 - lduwa [%o1] ASI_PL, %g7 -1: andcc %g7, %g5, %o0 - be,pn %icc, 2f - xor %g7, %g5, %g1 - casa [%o1] ASI_PL, %g7, %g1 - cmp %g7, %g1 - bne,a,pn %icc, 1b - lduwa [%o1] ASI_PL, %g7 -2: retl - membar #StoreLoad | #StoreStore + .size ___test_and_change_bit, .-___test_and_change_bit diff -Nru a/arch/sparc64/lib/copy_in_user.S b/arch/sparc64/lib/copy_in_user.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/copy_in_user.S 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,119 @@ +/* copy_in_user.S: Copy from userspace to userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#include + +#define XCC xcc + +#define EX(x,y) \ +98: x,y; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + + .register %g2,#scratch + .register %g3,#scratch + + .text + .align 32 + + /* Don't try to get too fancy here, just nice and + * simple. This is predominantly used for well aligned + * small copies in the compat layer. It is also used + * to copy register windows around during thread cloning. + */ + + .globl ___copy_in_user + .type ___copy_in_user,#function +___copy_in_user: /* %o0=dst, %o1=src, %o2=len */ + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ + rd %asi, %g1 + cmp %g1, ASI_AIUS + bne,pn %icc, memcpy_user_stub + nop + + cmp %o2, 0 + be,pn %XCC, 85f + or %o0, %o1, %o3 + cmp %o2, 16 + bleu,a,pn %XCC, 80f + or %o3, %o2, %o3 + + /* 16 < len <= 64 */ + andcc %o3, 0x7, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + + andn %o2, 0x7, %o4 + and %o2, 0x7, %o2 +1: subcc %o4, 0x8, %o4 + EX(ldxa [%o1] %asi, %o5) + EX(stxa %o5, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 + andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + EX(lduwa [%o1] %asi, %o5) + EX(stwa %o5, [%o1 + %o3] ASI_AIUS) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, 85f + nop + ba,pt %xcc, 90f + nop + +80: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + +82: + subcc %o2, 4, %o2 + EX(lduwa [%o1] %asi, %g1) + EX(stwa %g1, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 82b + add %o1, 4, %o1 + +85: retl + clr %o0 + + .align 32 +90: + subcc %o2, 1, %o2 + EX(lduba [%o1] %asi, %g1) + EX(stba %g1, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 90b + add %o1, 1, %o1 + retl + clr %o0 + + .size ___copy_in_user, .-___copy_in_user + + /* Act like copy_{to,in}_user(), ie. return zero instead + * of original destination pointer. This is invoked when + * copy_{to,in}_user() finds that %asi is kernel space. + */ + .globl memcpy_user_stub + .type memcpy_user_stub,#function +memcpy_user_stub: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + call memcpy + mov %i2, %o2 + ret + restore %g0, %g0, %o0 + .size memcpy_user_stub, .-memcpy_user_stub diff -Nru a/arch/sparc64/lib/copy_page.S b/arch/sparc64/lib/copy_page.S --- a/arch/sparc64/lib/copy_page.S 2004-10-18 14:56:49 -07:00 +++ b/arch/sparc64/lib/copy_page.S 2004-10-18 14:56:49 -07:00 @@ -45,6 +45,7 @@ .align 32 .globl copy_user_page + .type copy_user_page,#function copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ lduw [%g6 + TI_PRE_COUNT], %o4 sethi %uhi(PAGE_OFFSET), %g2 @@ -237,3 +238,5 @@ retl stw %o4, [%g6 + TI_PRE_COUNT] + + .size copy_user_page, .-copy_user_page diff -Nru a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c --- a/arch/sparc64/lib/debuglocks.c 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc64/lib/debuglocks.c 2004-10-18 14:56:33 -07:00 @@ -84,7 +84,7 @@ put_cpu(); } -int _spin_trylock(spinlock_t *lock) +int _do_spin_trylock(spinlock_t *lock) { unsigned long val, caller; int cpu = get_cpu(); diff -Nru a/arch/sparc64/lib/delay.c b/arch/sparc64/lib/delay.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/delay.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,49 @@ +/* delay.c: Delay loops for sparc64 + * + * Copyright (C) 2004 David S. Miller + * + * Based heavily upon x86 variant which is: + * Copyright (C) 1993 Linus Torvalds + * Copyright (C) 1997 Martin Mares + */ + +#include + +void __delay(unsigned long loops) +{ + __asm__ __volatile__( +" b,pt %%xcc, 1f\n" +" cmp %0, 0\n" +" .align 32\n" +"1:\n" +" bne,pt %%xcc, 1b\n" +" subcc %0, 1, %0\n" + : "=&r" (loops) + : "0" (loops) + : "cc"); +} + +/* We used to multiply by HZ after shifting down by 32 bits + * but that runs into problems for higher values of HZ and + * slow cpus. + */ +void __const_udelay(unsigned long n) +{ + n *= 4; + + n *= (cpu_data(smp_processor_id()).udelay_val * (HZ/4)); + n >>= 32; + + __delay(n + 1); +} + +void __udelay(unsigned long n) +{ + __const_udelay(n * 0x10c7UL); +} + + +void __ndelay(unsigned long n) +{ + __const_udelay(n * 0x5UL); +} diff -Nru a/arch/sparc64/lib/iomap.c b/arch/sparc64/lib/iomap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/iomap.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,48 @@ +/* + * Implement the sparc64 iomap interfaces + */ +#include +#include +#include + +/* Create a virtual mapping cookie for an IO port range */ +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return (void __iomem *) (unsigned long) port; +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + +/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem * addr) +{ + /* nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); diff -Nru a/arch/sparc64/lib/ipcsum.S b/arch/sparc64/lib/ipcsum.S --- a/arch/sparc64/lib/ipcsum.S 2004-10-18 14:56:29 -07:00 +++ b/arch/sparc64/lib/ipcsum.S 2004-10-18 14:56:29 -07:00 @@ -1,6 +1,7 @@ .text - .align 32 - .globl ip_fast_csum + .align 32 + .globl ip_fast_csum + .type ip_fast_csum,#function ip_fast_csum: /* %o0 = iph, %o1 = ihl */ sub %o1, 4, %g7 lduw [%o0 + 0x00], %o2 @@ -30,3 +31,4 @@ set 0xffff, %o1 retl and %o2, %o1, %o0 + .size ip_fast_csum, .-ip_fast_csum diff -Nru a/arch/sparc64/lib/memmove.S b/arch/sparc64/lib/memmove.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/memmove.S 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,33 @@ +/* memmove.S: Simple memmove implementation. + * + * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + + .text + .align 32 + .globl memmove + .type memmove,#function +memmove: + mov %o0, %g1 + cmp %o0, %o1 + blu,pt %xcc, memcpy + sub %o0, %o1, %g5 + add %o1, %o2, %g3 + cmp %g3, %o0 + bleu,pt %xcc, memcpy + add %o1, %o2, %g5 + add %o0, %o2, %o5 + + sub %g5, 1, %o1 + sub %o5, 1, %o0 +1: ldub [%o1], %g5 + subcc %o2, 1, %o2 + sub %o1, 1, %o1 + stb %g5, [%o0] + bne,pt %icc, 1b + sub %o0, 1, %o0 + + retl + mov %g1, %o0 + .size memmove, .-memmove diff -Nru a/arch/sparc64/lib/rwlock.S b/arch/sparc64/lib/rwlock.S --- a/arch/sparc64/lib/rwlock.S 2004-10-18 14:56:29 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,85 +0,0 @@ -/* $Id: rwlock.S,v 1.4 2000/09/09 00:00:34 davem Exp $ - * rwlocks.S: These things are too big to do inline. - * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - */ - - .text - .align 64 - - /* The non-contention read lock usage is 2 cache lines. */ - - .globl __read_lock, __read_unlock -__read_lock: /* %o0 = lock_ptr */ - ldsw [%o0], %g5 - brlz,pn %g5, __read_wait_for_writer -4: add %g5, 1, %g7 - cas [%o0], %g5, %g7 - cmp %g5, %g7 - bne,pn %icc, __read_lock - membar #StoreLoad | #StoreStore -99: retl - nop -__read_unlock: /* %o0 = lock_ptr */ - lduw [%o0], %g5 - sub %g5, 1, %g7 - cas [%o0], %g5, %g7 - cmp %g5, %g7 - be,pt %xcc, 99b - membar #StoreLoad | #StoreStore - ba,a,pt %xcc, __read_unlock - -__read_wait_for_writer: - ldsw [%o0], %g5 - brlz,pt %g5, __read_wait_for_writer - membar #LoadLoad - ba,a,pt %xcc, 4b -__write_wait_for_any: - lduw [%o0], %g5 - brnz,pt %g5, __write_wait_for_any - membar #LoadLoad - ba,a,pt %xcc, 4f - - .align 64 - .globl __write_unlock -__write_unlock: /* %o0 = lock_ptr */ - membar #LoadStore | #StoreStore - retl - stw %g0, [%o0] - - .globl __write_lock -__write_lock: /* %o0 = lock_ptr */ - sethi %hi(0x80000000), %g2 - -1: lduw [%o0], %g5 - brnz,pn %g5, __write_wait_for_any -4: or %g5, %g2, %g7 - cas [%o0], %g5, %g7 - - cmp %g5, %g7 - be,pt %icc, 99b - membar #StoreLoad | #StoreStore - ba,a,pt %xcc, 1b - - .globl __write_trylock -__write_trylock: /* %o0 = lock_ptr */ - sethi %hi(0x80000000), %g2 -1: lduw [%o0], %g5 - brnz,pn %g5, __write_trylock_fail -4: or %g5, %g2, %g7 - - cas [%o0], %g5, %g7 - cmp %g5, %g7 - be,pt %icc, __write_trylock_succeed - membar #StoreLoad | #StoreStore - - ba,pt %xcc, 1b - nop -__write_trylock_succeed: - retl - mov 1, %o0 - -__write_trylock_fail: - retl - mov 0, %o0 - diff -Nru a/arch/sparc64/lib/splock.S b/arch/sparc64/lib/splock.S --- a/arch/sparc64/lib/splock.S 2004-10-18 14:56:50 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,35 +0,0 @@ -/* splock.S: Spinlock primitives too large to inline. - * - * Copyright (C) 2004 David S. Miller (davem@redhat.com) - */ - - .text - .align 64 - - .globl _raw_spin_lock -_raw_spin_lock: /* %o0 = lock_ptr */ -1: ldstub [%o0], %g7 - brnz,pn %g7, 2f - membar #StoreLoad | #StoreStore - retl - nop -2: ldub [%o0], %g7 - brnz,pt %g7, 2b - membar #LoadLoad - ba,a,pt %xcc, 1b - - .globl _raw_spin_lock_flags -_raw_spin_lock_flags: /* %o0 = lock_ptr, %o1 = irq_flags */ -1: ldstub [%o0], %g7 - brnz,pn %g7, 2f - membar #StoreLoad | #StoreStore - retl - nop - -2: rdpr %pil, %g2 ! Save PIL - wrpr %o1, %pil ! Set previous PIL -3: ldub [%o0], %g7 ! Spin on lock set - brnz,pt %g7, 3b - membar #LoadLoad - ba,pt %xcc, 1b ! Retry lock acquire - wrpr %g2, %pil ! Restore PIL diff -Nru a/arch/sparc64/lib/strlen.S b/arch/sparc64/lib/strlen.S --- a/arch/sparc64/lib/strlen.S 2004-10-18 14:56:27 -07:00 +++ b/arch/sparc64/lib/strlen.S 2004-10-18 14:56:27 -07:00 @@ -9,9 +9,9 @@ #define HI_MAGIC 0x80808080 .align 32 - .global strlen, __strlen + .globl strlen + .type strlen,#function strlen: -__strlen: mov %o0, %o1 andcc %o0, 3, %g0 be,pt %icc, 9f @@ -76,3 +76,5 @@ 13: retl mov 2, %o0 + + .size strlen, .-strlen diff -Nru a/arch/sparc64/lib/strncmp.S b/arch/sparc64/lib/strncmp.S --- a/arch/sparc64/lib/strncmp.S 2004-10-18 14:56:33 -07:00 +++ b/arch/sparc64/lib/strncmp.S 2004-10-18 14:56:33 -07:00 @@ -7,9 +7,9 @@ #include .text - .align 4 - .global __strncmp, strncmp -__strncmp: + .align 32 + .globl strncmp + .type strncmp,#function strncmp: brlez,pn %o2, 3f lduba [%o0] (ASI_PNF), %o3 @@ -29,3 +29,4 @@ 3: retl clr %o0 + .size strncmp, .-strncmp diff -Nru a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S --- a/arch/sparc64/lib/strncpy_from_user.S 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/lib/strncpy_from_user.S 2004-10-18 14:57:04 -07:00 @@ -12,7 +12,7 @@ 0: .xword 0x0101010101010101 .text - .align 4 + .align 32 /* Must return: * @@ -31,6 +31,7 @@ */ .globl __strncpy_from_user + .type __strncpy_from_user,#function __strncpy_from_user: /* %o0=dest, %o1=src, %o2=count */ sethi %hi(0b), %o5 ! IEU0 Group @@ -122,6 +123,7 @@ mov %o2, %o0 2: retl add %o2, %o3, %o0 + .size __strncpy_from_user, .-__strncpy_from_user .section .fixup,#alloc,#execinstr .align 4 diff -Nru a/arch/sparc64/lib/user_fixup.c b/arch/sparc64/lib/user_fixup.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/sparc64/lib/user_fixup.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,68 @@ +/* user_fixup.c: Fix up user copy faults. + * + * Copyright (C) 2004 David S. Miller + */ + +#include +#include +#include +#include +#include + +/* Calculating the exact fault address when using + * block loads and stores can be very complicated. + * Instead of trying to be clever and handling all + * of the cases, just fix things up simply here. + */ + +unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) +{ + char *dst = to; + const char __user *src = from; + + while (size--) { + if (__get_user(*dst, src)) + break; + dst++; + src++; + } + + if (size) + memset(dst, 0, size); + + return size; +} + +unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) +{ + char __user *dst = to; + const char *src = from; + + while (size--) { + if (__put_user(*src, dst)) + break; + dst++; + src++; + } + + return size; +} + +unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) +{ + char __user *dst = to; + char __user *src = from; + + while (size--) { + char tmp; + + if (__get_user(tmp, src)) + break; + if (__put_user(tmp, dst)) + break; + dst++; + src++; + } + + return size; +} diff -Nru a/arch/sparc64/lib/xor.S b/arch/sparc64/lib/xor.S --- a/arch/sparc64/lib/xor.S 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/lib/xor.S 2004-10-18 14:57:04 -07:00 @@ -18,8 +18,9 @@ * !(len & 127) && len >= 256 */ .text - .globl xor_vis_2 - .type xor_vis_2,@function + .align 32 + .globl xor_vis_2 + .type xor_vis_2,#function xor_vis_2: rd %fprs, %o5 andcc %o5, FPRS_FEF|FPRS_DU, %g0 @@ -87,11 +88,10 @@ wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_2, .-xor_vis_2 + .size xor_vis_2, .-xor_vis_2 - - .globl xor_vis_3 - .type xor_vis_3,@function + .globl xor_vis_3 + .type xor_vis_3,#function xor_vis_3: rd %fprs, %o5 andcc %o5, FPRS_FEF|FPRS_DU, %g0 @@ -156,11 +156,10 @@ wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_3, .-xor_vis_3 - + .size xor_vis_3, .-xor_vis_3 - .globl xor_vis_4 - .type xor_vis_4,@function + .globl xor_vis_4 + .type xor_vis_4,#function xor_vis_4: rd %fprs, %o5 andcc %o5, FPRS_FEF|FPRS_DU, %g0 @@ -244,11 +243,10 @@ wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_4, .-xor_vis_4 - + .size xor_vis_4, .-xor_vis_4 - .globl xor_vis_5 - .type xor_vis_5,@function + .globl xor_vis_5 + .type xor_vis_5,#function xor_vis_5: mov %o5, %g5 rd %fprs, %o5 @@ -353,4 +351,4 @@ wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_5, .-xor_vis_5 + .size xor_vis_5, .-xor_vis_5 diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c --- a/arch/sparc64/mm/fault.c 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/mm/fault.c 2004-10-18 14:57:04 -07:00 @@ -27,6 +27,7 @@ #include #include #include +#include #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0])) @@ -147,6 +148,9 @@ printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", (tsk->mm ? (unsigned long) tsk->mm->pgd : (unsigned long) tsk->active_mm->pgd)); + if (notify_die(DIE_GPF, "general protection fault", regs, + 0, 0, SIGSEGV) == NOTIFY_STOP) + return; die_if_kernel("Oops", regs); } @@ -318,8 +322,13 @@ int si_code, fault_code; unsigned long address; - si_code = SEGV_MAPERR; fault_code = get_thread_fault_code(); + + if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, + fault_code, 0, SIGSEGV) == NOTIFY_STOP) + return; + + si_code = SEGV_MAPERR; address = current_thread_info()->fault_address; if ((fault_code & FAULT_CODE_ITLB) && diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c --- a/arch/sparc64/mm/init.c 2004-10-18 14:56:28 -07:00 +++ b/arch/sparc64/mm/init.c 2004-10-18 14:56:28 -07:00 @@ -68,6 +68,7 @@ extern char _start[], _end[]; /* Initial ramdisk setup */ +extern unsigned long sparc_ramdisk_image64; extern unsigned int sparc_ramdisk_image; extern unsigned int sparc_ramdisk_size; @@ -1279,10 +1280,12 @@ #ifdef CONFIG_BLK_DEV_INITRD /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ - if (sparc_ramdisk_image) { - if (sparc_ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE) - sparc_ramdisk_image -= KERNBASE; - initrd_start = sparc_ramdisk_image + phys_base; + if (sparc_ramdisk_image || sparc_ramdisk_image64) { + unsigned long ramdisk_image = sparc_ramdisk_image ? + sparc_ramdisk_image : sparc_ramdisk_image64; + if (ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE) + ramdisk_image -= KERNBASE; + initrd_start = ramdisk_image + phys_base; initrd_end = initrd_start + sparc_ramdisk_size; if (initrd_end > end_of_phys_memory) { printk(KERN_CRIT "initrd extends beyond end of memory " @@ -1325,6 +1328,10 @@ size = initrd_end - initrd_start; /* Resert the initrd image area. */ +#ifdef CONFIG_DEBUG_BOOTMEM + prom_printf("reserve_bootmem(initrd): base[%llx] size[%lx]\n", + initrd_start, initrd_end); +#endif reserve_bootmem(initrd_start, size); *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; @@ -1377,7 +1384,7 @@ if ((real_end > ((unsigned long)KERNBASE + 0x400000))) bigkernel = 1; #ifdef CONFIG_BLK_DEV_INITRD - if (sparc_ramdisk_image) + if (sparc_ramdisk_image || sparc_ramdisk_image64) real_end = (PAGE_ALIGN(real_end) + PAGE_ALIGN(sparc_ramdisk_size)); #endif @@ -1502,7 +1509,7 @@ zones_size[ZONE_DMA] = npages; zholes_size[ZONE_DMA] = npages - pages_avail; - free_area_init_node(0, &contig_page_data, NULL, zones_size, + free_area_init_node(0, &contig_page_data, zones_size, phys_base >> PAGE_SHIFT, zholes_size); mem_map = contig_page_data.node_mem_map; } diff -Nru a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c --- a/arch/sparc64/solaris/misc.c 2004-10-18 14:57:04 -07:00 +++ b/arch/sparc64/solaris/misc.c 2004-10-18 14:57:04 -07:00 @@ -137,21 +137,34 @@ return sunos_brk(brk); } -#define set_utsfield(to, from, dotchop, countfrom) { \ - char *p; \ - int i, len = (countfrom) ? \ - ((sizeof(to) > sizeof(from) ? \ - sizeof(from) : sizeof(to))) : sizeof(to); \ - if (copy_to_user(to, from, len)) \ - return -EFAULT; \ - if (dotchop) \ - for (p=from,i=0; *p && *p != '.' && --len; p++,i++); \ - else \ - i = len - 1; \ - if (__put_user('\0', (char __user *)((to)+i))) \ - return -EFAULT; \ +static int __set_utsfield(char __user *to, int to_size, + const char *from, int from_size, + int dotchop, int countfrom) +{ + int len = countfrom ? (to_size > from_size ? + from_size : to_size) : to_size; + int off; + + if (copy_to_user(to, from, len)) + return -EFAULT; + + off = len < to_size? len: len - 1; + if (dotchop) { + const char *p = strnchr(from, len, '.'); + if (p) off = p - from; + } + + if (__put_user('\0', to + off)) + return -EFAULT; + + return 0; } +#define set_utsfield(to, from, dotchop, countfrom) \ + __set_utsfield((to), sizeof(to), \ + (from), sizeof(from), \ + (dotchop), (countfrom)) + struct sol_uname { char sysname[9]; char nodename[9]; @@ -219,17 +232,20 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) { struct sol_uname __user *v = A(buf); + int err; + switch (which) { case 0: /* old uname */ /* Let's cheat */ - set_utsfield(v->sysname, "SunOS", 1, 0); + err = set_utsfield(v->sysname, "SunOS", 1, 0); down_read(&uts_sem); - set_utsfield(v->nodename, system_utsname.nodename, 1, 1); + err |= set_utsfield(v->nodename, system_utsname.nodename, + 1, 1); up_read(&uts_sem); - set_utsfield(v->release, "2.6", 0, 0); - set_utsfield(v->version, "Generic", 0, 0); - set_utsfield(v->machine, machine(), 0, 0); - return 0; + err |= set_utsfield(v->release, "2.6", 0, 0); + err |= set_utsfield(v->version, "Generic", 0, 0); + err |= set_utsfield(v->machine, machine(), 0, 0); + return (err ? -EFAULT : 0); case 2: /* ustat */ return -ENOSYS; case 3: /* fusers */ @@ -242,15 +258,18 @@ asmlinkage int solaris_utsname(u32 buf) { struct sol_utsname __user *v = A(buf); + int err; + /* Why should we not lie a bit? */ down_read(&uts_sem); - set_utsfield(v->sysname, "SunOS", 0, 0); - set_utsfield(v->nodename, system_utsname.nodename, 1, 1); - set_utsfield(v->release, "5.6", 0, 0); - set_utsfield(v->version, "Generic", 0, 0); - set_utsfield(v->machine, machine(), 0, 0); + err = set_utsfield(v->sysname, "SunOS", 0, 0); + err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1); + err |= set_utsfield(v->release, "5.6", 0, 0); + err |= set_utsfield(v->version, "Generic", 0, 0); + err |= set_utsfield(v->machine, machine(), 0, 0); up_read(&uts_sem); - return 0; + + return (err ? -EFAULT : 0); } #define SI_SYSNAME 1 /* return name of operating system */ diff -Nru a/arch/um/Kconfig b/arch/um/Kconfig --- a/arch/um/Kconfig 2004-10-18 14:56:31 -07:00 +++ b/arch/um/Kconfig 2004-10-18 14:56:31 -07:00 @@ -34,7 +34,7 @@ help This option controls whether tracing thread support is compiled into UML. Normally, this should be set to Y. If you intend to - use only skas mode (and the host has the skas patch applied to it), + use only skas mode (and the host has the skas patch applied to it), then it is OK to say N here. config STATIC_LINK @@ -45,7 +45,7 @@ If CONFIG_MODE_TT is disabled, then this option gives you the ability to force a static link of UML. Normally, if only skas mode is built in to UML, it will be linked as a shared binary. This is inconvenient - for use in a chroot jail. So, if you intend to run UML inside a + for use in a chroot jail. So, if you intend to run UML inside a chroot, and you disable CONFIG_MODE_TT, you probably want to say Y here. @@ -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" @@ -82,9 +96,22 @@ For more information, see . - If you'd like to be able to work with files stored on the host, + 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" @@ -102,15 +129,12 @@ It is safe to say 'Y' here. -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on MCONSOLE - config HOST_2G_2G bool "2G/2G host address space split" -config UML_SMP +config SMP bool "Symmetric multi-processing support" + default n help This option enables UML SMP support. UML implements virtual SMP by allowing as many processes to run simultaneously on the host as @@ -119,13 +143,8 @@ will appear to be running simultaneously. If the host is a multiprocessor, then UML processes may run simultaneously, depending on the host scheduler. - CONFIG_SMP will be set to whatever this option is set to. It is safe to leave this unchanged. -config SMP - bool - default UML_SMP - config NR_CPUS int "Maximum number of CPUs (2-32)" range 2 32 @@ -140,11 +159,11 @@ in. Normally, this is zero, meaning that it will run directly on the host. Setting it to one will build a UML that can run inside a UML that is running on the host. Generally, if you intend this UML to run - inside another UML, set CONFIG_NEST_LEVEL to one more than the host + inside another UML, set CONFIG_NEST_LEVEL to one more than the host UML. - Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to - greater than one, then the guest UML should have its CONFIG_NEST_LEVEL + Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to + greater than one, then the guest UML should have its CONFIG_NEST_LEVEL set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. Only change this if you are running nested UMLs. @@ -159,6 +178,7 @@ config HIGHMEM bool "Highmem support" + depends on BROKEN config KERNEL_STACK_ORDER int "Kernel stack size order" @@ -168,6 +188,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" @@ -195,6 +226,7 @@ source "lib/Kconfig" menu "SCSI support" +depends on BROKEN config SCSI tristate "SCSI support" @@ -211,61 +243,8 @@ source "drivers/md/Kconfig" -source "drivers/mtd/Kconfig" - - -menu "Kernel hacking" - -config DEBUG_SLAB - bool "Debug memory allocations" - -config DEBUG_SPINLOCK - bool "Debug spinlocks usage" - -config DEBUG_INFO - bool "Enable kernel debugging symbols" - help - When this is enabled, the User-Mode Linux binary will include - debugging symbols. This enlarges the binary by a few megabytes, - but aids in tracking down kernel problems in UML. It is required - if you intend to do any kernel development. - - If you're truly short on disk space or don't expect to report any - bugs back to the UML developers, say N, otherwise say Y. - -config FRAME_POINTER - bool - default y if DEBUG_INFO - -config PT_PROXY - bool "Enable ptrace proxy" - depends on XTERM_CHAN && DEBUG_INFO - -config GPROF - bool "Enable gprof support" - depends on DEBUG_INFO - help - This allows profiling of a User-Mode Linux kernel with the gprof - utility. - - See for more - details. - - If you're involved in UML kernel development and want to use gprof, - say Y. If you're unsure, say N. - -config GCOV - bool "Enable gcov support" - depends on DEBUG_INFO - help - This option allows developers to retrieve coverage data from a UML - session. - - See for more - details. - - If you're involved in UML kernel development and want to use gcov, - say Y. If you're unsure, say N. - -endmenu +if BROKEN + source "drivers/mtd/Kconfig" +endif +source "arch/um/Kconfig.debug" diff -Nru a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/Kconfig.debug 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,43 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config FRAME_POINTER + bool + default y if DEBUG_INFO + +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" + depends on DEBUG_INFO + help + This allows profiling of a User-Mode Linux kernel with the gprof + utility. + + See for more + details. + + If you're involved in UML kernel development and want to use gprof, + say Y. If you're unsure, say N. + +config GCOV + bool "Enable gcov support" + depends on DEBUG_INFO + help + This option allows developers to retrieve coverage data from a UML + session. + + See for more + details. + + If you're involved in UML kernel development and want to use gcov, + say Y. If you're unsure, say N. + +endmenu diff -Nru a/arch/um/Kconfig_block b/arch/um/Kconfig_block --- a/arch/um/Kconfig_block 2004-10-18 14:56:48 -07:00 +++ b/arch/um/Kconfig_block 2004-10-18 14:56:48 -07:00 @@ -29,6 +29,10 @@ wise choice too. In all other cases (for example, if you're just playing around with User-Mode Linux) you can choose N. +config BLK_DEV_COW_COMMON + bool + default BLK_DEV_UBD + config BLK_DEV_LOOP tristate "Loopback device support" @@ -50,6 +54,7 @@ config MMAPPER tristate "Example IO memory driver" + depends on BROKEN help The User-Mode Linux port can provide support for IO Memory emulation with this option. This allows a host file to be diff -Nru a/arch/um/Kconfig_char b/arch/um/Kconfig_char --- a/arch/um/Kconfig_char 2004-10-18 14:56:29 -07:00 +++ b/arch/um/Kconfig_char 2004-10-18 14:56:29 -07:00 @@ -72,6 +72,10 @@ well, since UML's gdb currently requires an xterm. It is safe to say 'Y' here. +config NOCONFIG_CHAN + bool + default !(XTERM_CHAN && TTY_CHAN && PTY_CHAN && PORT_CHAN && FD_CHAN && NULL_CHAN) + config CON_ZERO_CHAN string "Default main console channel initialization" default "fd:0,fd:1" @@ -108,11 +112,55 @@ config UNIX98_PTYS bool "Unix98 PTY support" + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx for + masters and /dev/ttyxx for slaves of pseudo terminals. This scheme + has a number of problems. The GNU C library glibc 2.1 and later, + however, supports the Unix98 naming standard: in order to acquire a + pseudo terminal, a process opens /dev/ptmx; the number of the pseudo + terminal is then made available to the process and the pseudo + terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + All modern Linux systems use the Unix98 ptys. Say Y unless + you're on an embedded system and want to conserve memory. + +config LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. -config UNIX98_PTY_COUNT - int "Maximum number of Unix98 PTYs in use (0-2048)" - depends on UNIX98_PTYS + Linux has traditionally used the BSD-like names /dev/ptyxx + for masters and /dev/ttyxx for slaves of pseudo + terminals. This scheme has a number of problems, including + security. This option enables these legacy devices; on most + systems, it is safe to say N. + + +config LEGACY_PTY_COUNT + int "Maximum number of legacy PTY in use" + depends on LEGACY_PTYS default "256" + ---help--- + The maximum number of legacy PTYs that can be used at any one time. + The default is 256, and should be more than enough. Embedded + systems may want to reduce this to save memory. + + When not in use, each legacy PTY occupies 12 bytes on 32-bit + architectures and 24 bytes on 64-bit architectures. config WATCHDOG bool "Watchdog Timer Support" diff -Nru a/arch/um/Kconfig_net b/arch/um/Kconfig_net --- a/arch/um/Kconfig_net 2004-10-18 14:56:33 -07:00 +++ b/arch/um/Kconfig_net 2004-10-18 14:56:33 -07:00 @@ -1,5 +1,5 @@ -menu "Network Devices" +menu "UML Network Devices" depends on NET # UML virtual driver @@ -135,7 +135,7 @@ config UML_NET_PCAP bool "pcap transport" - depends on UML_NET + depends on UML_NET && BROKEN help The pcap transport makes a pcap packet stream on the host look like an ethernet device inside UML. This is useful for making @@ -175,74 +175,6 @@ don't need UML networking, say N. 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 -Nru a/arch/um/Makefile b/arch/um/Makefile --- a/arch/um/Makefile 2004-10-18 14:56:33 -07:00 +++ b/arch/um/Makefile 2004-10-18 14:56:33 -07:00 @@ -5,35 +5,25 @@ ARCH_DIR = arch/um OS := $(shell uname -s) +#We require it or things break. +SHELL := /bin/bash -# Recalculate MODLIB to reflect the EXTRAVERSION changes (via KERNELRELEASE) -# The way the toplevel Makefile is written EXTRAVERSION is not supposed -# to be changed outside the toplevel Makefile, but recalculating MODLIB is -# a sufficient workaround until we no longer need architecture dependent -# EXTRAVERSION... -MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) +filechk_gen_header = $< -ifeq ($(CONFIG_DEBUG_INFO),y) -CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -endif - -core-y += $(ARCH_DIR)/kernel/ \ - $(ARCH_DIR)/drivers/ \ +core-y += $(ARCH_DIR)/kernel/ \ + $(ARCH_DIR)/drivers/ \ $(ARCH_DIR)/sys-$(SUBARCH)/ # 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 +SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \ + arch-signal.h module.h +SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) 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) - MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas @@ -41,9 +31,11 @@ include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y)) endif -EXTRAVERSION := $(EXTRAVERSION)-1um +ARCH_INCLUDE := -I$(ARCH_DIR)/include +SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) -ARCH_INCLUDE = -I$(ARCH_DIR)/include +include $(ARCH_DIR)/Makefile-$(SUBARCH) +include $(ARCH_DIR)/Makefile-os-$(OS) # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common @@ -52,32 +44,32 @@ CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ - $(MODE_INCLUDE) + -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE) + +CFLAGS += $(call cc-option,-fno-unit-at-a-time,) 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) : $(ARCH_DIR)/include/skas_ptregs.h endif -include/linux/version.h: arch/$(ARCH)/Makefile - -$(ARCH_DIR)/vmlinux.lds.S : - touch $@ - -prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) - -LDFLAGS_vmlinux = -r - -vmlinux: $(ARCH_DIR)/main.o +prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \ + $(ARCH_DIR)/kernel/vmlinux.lds.S # These aren't in Makefile-tt because they are needed in the !CONFIG_MODE_TT + # CONFIG_MODE_SKAS + CONFIG_STATIC_LINK case. LINK_TT = -static -LD_SCRIPT_TT := uml.lds.s +LD_SCRIPT_TT := uml.lds.S ifeq ($(CONFIG_STATIC_LINK),y) LINK-y += $(LINK_TT) @@ -98,82 +90,99 @@ CONFIG_KERNEL_STACK_ORDER ?= 2 STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) -AFLAGS_vmlinux.lds.o = -U$(SUBARCH) \ - -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ - -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ - -DKERNEL_STACK_SIZE=$(STACK_SIZE) - -AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum - -LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y) +ifndef START + START = $$(($(TOP_ADDR) - $(SIZE))) +endif -$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE - $(call if_changed_dep,as_s_S) +CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \ + -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ + -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ + -DKERNEL_STACK_SIZE=$(STACK_SIZE)) -linux: vmlinux $(LD_SCRIPT-y) - $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \ - -o linux $(ARCH_DIR)/main.o vmlinux -L/usr/lib -lutil +CFLAGS_vmlinux = $(LINK-y) $(LINK_WRAPS) +define cmd_vmlinux__ + $(CC) $(CFLAGS_vmlinux) -o $@ \ + -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \ + -Wl,--start-group $(vmlinux-main) -Wl,--end-group \ + -L/usr/lib -lutil \ + $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^) +endef 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 -CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds.s \ - $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS) +#When cleaning we don't include .config, so we don't include +#TT or skas makefiles and don't clean skas_ptregs.h. +CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ + $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h -$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c - $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< +MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ + $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os archmrproper: - for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \ - do \ - $(MAKE) -C $$d archmrproper; \ - done - rm -f $(CLEAN_FILES) $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \ - $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) - -archclean: sysclean - for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \ - do \ - $(MAKE) -C $$d clean; \ - done - find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ + @: + +archclean: + $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util + @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ -o -name '*.gcov' \) -type f -print | xargs rm -f - rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS) -archdep: - for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done +#We need to re-preprocess this when the symlink dest changes. +#So we touch it. +$(ARCH_DIR)/kernel/vmlinux.lds.S: FORCE + @echo ' SYMLINK $@' + $(Q)ln -sf $(LD_SCRIPT-y) $@ + $(Q)touch $@ $(SYMLINK_HEADERS): - cd $(TOPDIR)/$(dir $@) ; \ + @echo ' SYMLINK $@' + $(Q)cd $(TOPDIR)/$(dir $@) ; \ ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@) include/asm-um/arch: - cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch + @echo ' SYMLINK $@' + $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch $(ARCH_DIR)/include/sysdep: - cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep + @echo ' SYMLINK $@' + $(Q)cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep $(ARCH_DIR)/os: - cd $(ARCH_DIR) && ln -sf os-$(OS) os + @echo ' SYMLINK $@' + $(Q)cd $(ARCH_DIR) && ln -sf os-$(OS) os + +# Generated files +define filechk_umlconfig + sed 's/ CONFIG/ UML_CONFIG/' +endef + +$(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h + $(call filechk,umlconfig) + +$(ARCH_DIR)/include/task.h: $(ARCH_DIR)/util/mk_task + $(call filechk,gen_header) + +$(ARCH_DIR)/include/kern_constants.h: $(ARCH_DIR)/util/mk_constants + $(call filechk,gen_header) -$(ARCH_DIR)/include/uml-config.h : - sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@ +$(ARCH_DIR)/include/skas_ptregs.h: $(ARCH_DIR)/kernel/skas/util/mk_ptregs + $(call filechk,gen_header) -$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task - $< > $@ +$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants: $(ARCH_DIR)/util \ + FORCE ; -$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants - $< > $@ +$(ARCH_DIR)/kernel/skas/util/mk_ptregs: $(ARCH_DIR)/kernel/skas/util FORCE ; -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ - $(ARCH_DIR)/util FORCE ; +$(ARCH_DIR)/util: scripts_basic $(SYS_DIR)/sc.h FORCE + $(Q)$(MAKE) $(build)=$@ -$(ARCH_DIR)/util: FORCE - @$(call descend,$@,) +$(ARCH_DIR)/kernel/skas/util: scripts_basic FORCE + $(Q)$(MAKE) $(build)=$@ export SUBARCH USER_CFLAGS OS diff -Nru a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 --- a/arch/um/Makefile-i386 2004-10-18 14:56:49 -07:00 +++ b/arch/um/Makefile-i386 2004-10-18 14:56:49 -07:00 @@ -1,37 +1,45 @@ ifeq ($(CONFIG_HOST_2G_2G), y) -TOP_ADDR = 0x80000000 +TOP_ADDR := 0x80000000 else -TOP_ADDR = 0xc0000000 +TOP_ADDR := 0xc0000000 +endif + +ifeq ($(CONFIG_MODE_SKAS),y) + ifneq ($(CONFIG_MODE_TT),y) + START := 0x8048000 + endif endif CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) -ELF_ARCH = $(SUBARCH) -ELF_FORMAT = elf32-$(SUBARCH) + +ifneq ($(CONFIG_GPROF),y) +ARCH_CFLAGS += -DUM_FASTCALL +endif + +ELF_ARCH := $(SUBARCH) +ELF_FORMAT := elf32-$(SUBARCH) OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_BLOB := --format binary --oformat elf32-i386 -SYS_DIR := $(ARCH_DIR)/include/sysdep-i386 SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util -SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h +SYS_HEADERS := $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h prepare: $(SYS_HEADERS) $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc - $< > $@ + $(call filechk,gen_header) $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread - $< > $@ + $(call filechk,gen_header) -$(SYS_UTIL_DIR)/mk_sc: FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_sc: scripts_basic FORCE + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ -$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ -$(SYS_UTIL_DIR): include/asm FORCE - @$(call descend,$@,) +$(SYS_UTIL_DIR): scripts_basic include/asm FORCE + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) -sysclean : - rm -f $(SYS_HEADERS) +CLEAN_FILES += $(SYS_HEADERS) diff -Nru a/arch/um/Makefile-skas b/arch/um/Makefile-skas --- a/arch/um/Makefile-skas 2004-10-18 14:56:29 -07:00 +++ b/arch/um/Makefile-skas 2004-10-18 14:56:29 -07:00 @@ -9,12 +9,9 @@ CFLAGS-$(CONFIG_GPROF) += $(PROFILE) LINK-$(CONFIG_GPROF) += $(PROFILE) -MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include +MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/kernel/skas/include LINK_SKAS = -Wl,-rpath,/lib -LD_SCRIPT_SKAS = dyn.lds.s +LD_SCRIPT_SKAS = dyn.lds.S -GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h - -$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : - $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h +GEN_HEADERS += $(ARCH_DIR)/include/skas_ptregs.h diff -Nru a/arch/um/Makefile-tt b/arch/um/Makefile-tt --- a/arch/um/Makefile-tt 2004-10-18 14:56:49 -07:00 +++ b/arch/um/Makefile-tt 2004-10-18 14:56:49 -07:00 @@ -3,5 +3,4 @@ # Licensed under the GPL # -MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/tt/include - +MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/kernel/tt/include diff -Nru a/arch/um/config.release b/arch/um/config.release --- a/arch/um/config.release 2004-10-18 14:57:04 -07:00 +++ b/arch/um/config.release 2004-10-18 14:57:04 -07:00 @@ -227,7 +227,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 -Nru a/arch/um/defconfig b/arch/um/defconfig --- a/arch/um/defconfig 2004-10-18 14:56:33 -07:00 +++ b/arch/um/defconfig 2004-10-18 14:56:33 -07:00 @@ -1,47 +1,79 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2-mm1 +# Thu Sep 16 23:44:48 2004 # 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 -# CONFIG_UML_SMP is not set # CONFIG_SMP is not set CONFIG_NEST_LEVEL=0 CONFIG_KERNEL_HALF_GIGS=1 # CONFIG_HIGHMEM is not set -CONFIG_PROC_MM=y CONFIG_KERNEL_STACK_ORDER=2 +CONFIG_UML_REAL_TIME_CLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support # -CONFIG_MODULES=y -# CONFIG_KMOD is not set +# CONFIG_MODULES is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set # # Character Devices @@ -58,7 +90,8 @@ CONFIG_CON_CHAN="xterm" CONFIG_SSL_CHAN="pty" CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_WATCHDOG is not set CONFIG_UML_SOUND=y CONFIG_SOUND=y @@ -69,6 +102,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 +112,7 @@ CONFIG_NETDEVICES=y # -# Network Devices +# UML Network Devices # CONFIG_UML_NET=y CONFIG_UML_NET_ETHERTAP=y @@ -88,22 +122,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 +133,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 @@ -126,23 +142,25 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set # 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_INET_TUNNEL is not set # CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE 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 @@ -154,11 +172,24 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=y # # Ethernet (10 or 100Mbit) @@ -170,83 +201,130 @@ # # -# Wireless LAN (non-hamradio) +# Ethernet (10000 Mbit) # -# CONFIG_NET_RADIO is not set # -# Token Ring devices (depends on LLC=y) +# Token Ring devices # -# CONFIG_SHAPER is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set # # Wan interfaces # # CONFIG_WAN is not set +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 +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE 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_REISER4_FS=y +CONFIG_REISER4_LARGE_KEY=y +# CONFIG_REISER4_CHECK is not set +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR 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 + +# +# Caches +# +# CONFIG_CACHEFS 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=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# 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_HFSPLUS_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_JFFS_PROC_FS is not set # 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_AFS_FS is not set # @@ -254,11 +332,11 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_NLS=y # # 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 @@ -283,6 +361,7 @@ # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -301,6 +380,7 @@ # # Security options # +# CONFIG_KEYS is not set # CONFIG_SECURITY is not set # @@ -311,33 +391,14 @@ # # Library routines # +# CONFIG_CRC_CCITT is not set # CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set # # 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) @@ -359,34 +420,46 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set +# CONFIG_INFTL is not set # # RAM/ROM/Flash chip drivers # # CONFIG_MTD_CFI is not set # CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # 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_PHRAM 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 @@ -396,6 +469,7 @@ # # Kernel hacking # +CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set CONFIG_DEBUG_INFO=y diff -Nru a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile --- a/arch/um/drivers/Makefile 2004-10-18 14:56:33 -07:00 +++ b/arch/um/drivers/Makefile 2004-10-18 14:56:33 -07:00 @@ -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 # @@ -15,7 +15,7 @@ #pcap-objs := pcap_kern.o pcap_user.o $(PCAP) net-objs := net_kern.o net_user.o mconsole-objs := mconsole_kern.o mconsole_user.o -hostaudio-objs := hostaudio_kern.o hostaudio_user.o +hostaudio-objs := hostaudio_kern.o ubd-objs := ubd_kern.o ubd_user.o port-objs := port_kern.o port_user.o harddog-objs := harddog_kern.o harddog_user.o @@ -39,6 +39,7 @@ 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_COMMON) += cow_user.o obj-y += stdio_console.o $(CHAN_OBJS) @@ -46,18 +47,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 $@ $< - -clean: - -modules: - -fastdep: - -dep: - -archmrproper: clean - diff -Nru a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c --- a/arch/um/drivers/chan_kern.c 2004-10-18 14:57:04 -07:00 +++ b/arch/um/drivers/chan_kern.c 2004-10-18 14:57:04 -07:00 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "chan_kern.h" @@ -16,7 +17,9 @@ #include "irq_user.h" #include "sigio.h" #include "line.h" +#include "os.h" +#ifdef CONFIG_NOCONFIG_CHAN static void *not_configged_init(char *str, int device, struct chan_opts *opts) { printk(KERN_ERR "Using a channel type which is configured out of " @@ -85,6 +88,55 @@ .free = not_configged_free, .winch = 0, }; +#endif /* CONFIG_NOCONFIG_CHAN */ + +void generic_close(int fd, void *unused) +{ + os_close_file(fd); +} + +int generic_read(int fd, char *c_out, void *unused) +{ + int n; + + 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) +{ + return(os_write_file(fd, buf, n)); +} + +int generic_window_size(int fd, void *unused, unsigned short *rows_out, + unsigned short *cols_out) +{ + 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; + + return(ret); +} + +void generic_free(void *data) +{ + kfree(data); +} static void tty_receive_char(struct tty_struct *tty, char ch) { @@ -265,6 +317,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 +477,8 @@ INIT_LIST_HEAD(chans); } - if((out = strchr(str, ',')) != NULL){ + out = strchr(str, ','); + if(out != NULL){ in = str; *out = '\0'; out++; @@ -475,12 +533,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 -Nru a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c --- a/arch/um/drivers/chan_user.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/drivers/chan_user.c 2004-10-18 14:55:54 -07:00 @@ -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 @@ -22,33 +21,6 @@ #include "choose-mode.h" #include "mode.h" -void generic_close(int fd, void *unused) -{ - close(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); -} - -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); -} - int generic_console_write(int fd, const char *buf, int n, void *unused) { struct termios save, new; @@ -65,26 +37,6 @@ return(err); } -int generic_window_size(int fd, void *unused, unsigned short *rows_out, - unsigned short *cols_out) -{ - struct winsize size; - int ret = 0; - - 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); -} - -void generic_free(void *data) -{ - kfree(data); -} - static void winch_handler(int sig) { } @@ -100,14 +52,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 +77,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 +106,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 +120,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 +135,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 -Nru a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/drivers/cow.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,41 @@ +#ifndef __COW_H__ +#define __COW_H__ + +#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 + +extern int init_cow_file(int fd, char *cow_file, char *backing_file, + int sectorsize, int alignment, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out); + +extern int file_reader(__u64 offset, char *buf, int len, void *arg); +extern int read_cow_header(int (*reader)(__u64, char *, int, void *), + void *arg, __u32 *version_out, + char **backing_file_out, time_t *mtime_out, + __u64 *size_out, int *sectorsize_out, + __u32 *align_out, int *bitmap_offset_out); + +extern int write_cow_header(char *cow_file, int fd, char *backing_file, + int sectorsize, int alignment, long long *size); + +extern void cow_sizes(int version, __u64 size, int sectorsize, int align, + int bitmap_offset, unsigned long *bitmap_len_out, + int *data_offset_out); + +#endif + +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Nru a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/drivers/cow_sys.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,48 @@ +#ifndef __COW_SYS_H__ +#define __COW_SYS_H__ + +#include "kern_util.h" +#include "user_util.h" +#include "os.h" +#include "user.h" + +static inline void *cow_malloc(int size) +{ + return(um_kmalloc(size)); +} + +static inline void cow_free(void *ptr) +{ + kfree(ptr); +} + +#define cow_printf printk + +static inline char *cow_strdup(char *str) +{ + return(uml_strdup(str)); +} + +static inline int cow_seek_file(int fd, __u64 offset) +{ + return(os_seek_file(fd, offset)); +} + +static inline int cow_file_size(char *file, __u64 *size_out) +{ + return(os_file_size(file, size_out)); +} + +static inline int cow_write_file(int fd, char *buf, int size) +{ + return(os_write_file(fd, buf, size)); +} + +#endif + +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Nru a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/drivers/cow_user.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "os.h" + +#include "cow.h" +#include "cow_sys.h" + +#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 { + __u32 magic; + __u32 version; + char backing_file[PATH_LEN_V2]; + time_t mtime; + __u64 size; + int sectorsize; +}; + +/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in + * case other systems have different values for MAXPATHLEN + */ +#define PATH_LEN_V3 4096 + +/* Changes from V2 - + * PATH_LEN_V3 as described above + * Explicitly specify field bit lengths for systems with different + * lengths for the usual C types. Not sure whether char or + * time_t should be changed, this can be changed later without + * breaking compatibility + * Add alignment field so that different alignments can be used for the + * bitmap and data + * Add cow_format field to allow for the possibility of different ways + * of specifying the COW blocks. For now, the only value is 0, + * for the traditional COW bitmap. + * Move the backing_file field to the end of the header. This allows + * for the possibility of expanding it into the padding required + * by the bitmap alignment. + * The bitmap and data portions of the file will be aligned as specified + * by the alignment field. This is to allow COW files to be + * put on devices with restrictions on access alignments, such as + * /dev/raw, with a 512 byte alignment restriction. This also + * allows the data to be more aligned more strictly than on + * sector boundaries. This is needed for ubd-mmap, which needs + * the data to be page aligned. + * Fixed (finally!) the rounding bug + */ + +struct cow_header_v3 { + __u32 magic; + __u32 version; + time_t mtime; + __u64 size; + __u32 sectorsize; + __u32 alignment; + __u32 cow_format; + char backing_file[PATH_LEN_V3]; +}; + +/* COW format definitions - for now, we have only the usual COW bitmap */ +#define COW_BITMAP 0 + +union cow_header { + struct cow_header_v1 v1; + struct cow_header_v2 v2; + struct cow_header_v3 v3; +}; + +#define COW_MAGIC 0x4f4f4f4d /* MOOO */ +#define COW_VERSION 3 + +#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len)) +#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align) + +void cow_sizes(int version, __u64 size, int sectorsize, int align, + int bitmap_offset, unsigned long *bitmap_len_out, + int *data_offset_out) +{ + if(version < 3){ + *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; + } + else { + *bitmap_len_out = DIV_ROUND(size, sectorsize); + *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8); + + *data_offset_out = bitmap_offset + *bitmap_len_out; + *data_offset_out = ROUND_UP(*data_offset_out, align); + } +} + +static int absolutize(char *to, int size, char *from) +{ + char save_cwd[256], *slash; + int remaining; + + if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { + cow_printf("absolutize : unable to get cwd - errno = %d\n", + errno); + return(-1); + } + slash = strrchr(from, '/'); + if(slash != NULL){ + *slash = '\0'; + if(chdir(from)){ + *slash = '/'; + cow_printf("absolutize : Can't cd to '%s' - " + "errno = %d\n", from, errno); + return(-1); + } + *slash = '/'; + if(getcwd(to, size) == NULL){ + cow_printf("absolutize : unable to get cwd of '%s' - " + "errno = %d\n", from, errno); + return(-1); + } + remaining = size - strlen(to); + if(strlen(slash) + 1 > remaining){ + cow_printf("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){ + cow_printf("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); +} + +int write_cow_header(char *cow_file, int fd, char *backing_file, + int sectorsize, int alignment, long long *size) +{ + struct cow_header_v3 *header; + unsigned long modtime; + int err; + + err = cow_seek_file(fd, 0); + if(err < 0){ + cow_printf("write_cow_header - lseek failed, err = %d\n", -err); + goto out; + } + + err = -ENOMEM; + header = cow_malloc(sizeof(*header)); + if(header == NULL){ + cow_printf("Failed to allocate COW V3 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){ + cow_printf("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 = os_file_modtime(header->backing_file, &modtime); + if(err < 0){ + cow_printf("Backing file '%s' mtime request failed, " + "err = %d\n", header->backing_file, -err); + goto out_free; + } + + err = cow_file_size(header->backing_file, size); + if(err < 0){ + cow_printf("Couldn't get size of backing file '%s', " + "err = %d\n", header->backing_file, -err); + goto out_free; + } + + header->mtime = htonl(modtime); + header->size = htonll(*size); + header->sectorsize = htonl(sectorsize); + header->alignment = htonl(alignment); + header->cow_format = COW_BITMAP; + + err = os_write_file(fd, header, sizeof(*header)); + if(err != sizeof(*header)){ + cow_printf("Write of header to new COW file '%s' failed, " + "err = %d\n", cow_file, -err); + goto out_free; + } + err = 0; + out_free: + cow_free(header); + out: + return(err); +} + +int file_reader(__u64 offset, char *buf, int len, void *arg) +{ + int fd = *((int *) arg); + + return(pread(fd, buf, len, offset)); +} + +/* XXX Need to sanity-check the values read from the header */ + +int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, + __u32 *version_out, char **backing_file_out, + time_t *mtime_out, __u64 *size_out, + int *sectorsize_out, __u32 *align_out, + int *bitmap_offset_out) +{ + union cow_header *header; + char *file; + int err, n; + unsigned long version, magic; + + header = cow_malloc(sizeof(*header)); + if(header == NULL){ + cow_printf("read_cow_header - Failed to allocate header\n"); + return(-ENOMEM); + } + err = -EINVAL; + n = (*reader)(0, (char *) header, sizeof(*header), arg); + if(n < offsetof(typeof(header->v1), backing_file)){ + cow_printf("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); + } + /* No error printed because the non-COW case comes through here */ + else goto out; + + *version_out = version; + + if(version == 1){ + if(n < sizeof(header->v1)){ + cow_printf("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); + *align_out = *sectorsize_out; + file = header->v1.backing_file; + } + else if(version == 2){ + if(n < sizeof(header->v2)){ + cow_printf("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); + *align_out = *sectorsize_out; + file = header->v2.backing_file; + } + else if(version == 3){ + if(n < sizeof(header->v3)){ + cow_printf("read_cow_header - failed to read V2 " + "header\n"); + goto out; + } + *mtime_out = ntohl(header->v3.mtime); + *size_out = ntohll(header->v3.size); + *sectorsize_out = ntohl(header->v3.sectorsize); + *align_out = ntohl(header->v3.alignment); + *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); + file = header->v3.backing_file; + } + else { + cow_printf("read_cow_header - invalid COW version\n"); + goto out; + } + err = -ENOMEM; + *backing_file_out = cow_strdup(file); + if(*backing_file_out == NULL){ + cow_printf("read_cow_header - failed to allocate backing " + "file\n"); + goto out; + } + err = 0; + out: + cow_free(header); + return(err); +} + +int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, + int alignment, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out) +{ + __u64 size, offset; + char zero = 0; + int err; + + err = write_cow_header(cow_file, fd, backing_file, sectorsize, + alignment, &size); + if(err) + goto out; + + *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); + cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out, + bitmap_len_out, data_offset_out); + + offset = *data_offset_out + size - sizeof(zero); + err = cow_seek_file(fd, offset); + if(err < 0){ + cow_printf("cow bitmap lseek failed : err = %d\n", -err); + goto out; + } + + /* does not really matter how much we write it is just to set EOF + * this also sets the entire COW bitmap + * to zero without having to allocate it + */ + err = cow_write_file(fd, &zero, sizeof(zero)); + if(err != sizeof(zero)){ + cow_printf("Write of bitmap to new COW file '%s' failed, " + "err = %d\n", cow_file, -err); + err = -EINVAL; + goto out; + } + + return(0); + + out: + return(err); +} + +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Nru a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c --- a/arch/um/drivers/daemon_user.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/drivers/daemon_user.c 2004-10-18 14:56:28 -07:00 @@ -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 -Nru a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c --- a/arch/um/drivers/fd.c 2004-10-18 14:57:04 -07:00 +++ b/arch/um/drivers/fd.c 2004-10-18 14:57:04 -07:00 @@ -7,6 +7,7 @@ #include #include #include +#include #include "user.h" #include "user_util.h" #include "chan_user.h" @@ -35,7 +36,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); @@ -44,10 +46,16 @@ int fd_open(int input, int output, int primary, void *d, char **dev_out) { struct fd_chan *data = d; + int err; if(data->raw && isatty(data->fd)){ - tcgetattr(data->fd, &data->tt); - raw(data->fd, 0); + CATCH_EINTR(err = tcgetattr(data->fd, &data->tt)); + if(err) + return(err); + + err = raw(data->fd); + if(err) + return(err); } sprintf(data->str, "%d", data->fd); *dev_out = data->str; @@ -57,9 +65,13 @@ void fd_close(int fd, void *d) { struct fd_chan *data = d; + int err; if(data->raw && isatty(fd)){ - tcsetattr(fd, TCSAFLUSH, &data->tt); + CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt)); + if(err) + printk("Failed to restore terminal state - " + "errno = %d\n", -err); data->raw = 0; } } diff -Nru a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c --- a/arch/um/drivers/harddog_user.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/drivers/harddog_user.c 2004-10-18 14:56:28 -07:00 @@ -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 -Nru a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c --- a/arch/um/drivers/hostaudio_kern.c 2004-10-18 14:57:04 -07:00 +++ b/arch/um/drivers/hostaudio_kern.c 2004-10-18 14:57:04 -07:00 @@ -5,44 +5,64 @@ #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" +#include "os.h" + +struct hostaudio_state { + int fd; +}; + +struct hostmixer_state { + int fd; +}; + +#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" +#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" /* Only changed from linux_main at boot time */ 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 +71,56 @@ 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 = os_read_file(state->fd, kbuf, count); + 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 = os_write_file(state->fd, kbuf, count); + if(err < 0) + goto out; + *ppos += err; + + out: + kfree(kbuf); + return(err); } static unsigned int hostaudio_poll(struct file *file, @@ -86,12 +139,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 = os_ioctl_generic(state->fd, 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) @@ -105,17 +189,19 @@ #endif state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); - if(state == NULL) return(-ENOMEM); + if(state == NULL) + return(-ENOMEM); if(file->f_mode & FMODE_READ) r = 1; if(file->f_mode & FMODE_WRITE) w = 1; - ret = hostaudio_open_user(state, r, w, dsp); + ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); if(ret < 0){ kfree(state); return(ret); } + state->fd = ret; file->private_data = state; return(0); } @@ -123,16 +209,15 @@ static int hostaudio_release(struct inode *inode, struct file *file) { struct hostaudio_state *state = file->private_data; - int ret; #ifdef DEBUG printk("hostaudio: release called\n"); #endif - ret = hostaudio_release_user(state); + os_close_file(state->fd); kfree(state); - return(ret); + return(0); } /* /dev/mixer file operations */ @@ -146,7 +231,7 @@ printk("hostmixer: ioctl called\n"); #endif - return(hostmixer_ioctl_mixdev_user(state, cmd, arg)); + return(os_ioctl_generic(state->fd, cmd, arg)); } static int hostmixer_open_mixdev(struct inode *inode, struct file *file) @@ -165,9 +250,11 @@ if(file->f_mode & FMODE_READ) r = 1; if(file->f_mode & FMODE_WRITE) w = 1; - ret = hostmixer_open_mixdev_user(state, r, w, mixer); + ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); if(ret < 0){ + printk("hostaudio_open_mixdev failed to open '%s', err = %d\n", + dsp, -ret); kfree(state); return(ret); } @@ -179,16 +266,15 @@ static int hostmixer_release(struct inode *inode, struct file *file) { struct hostmixer_state *state = file->private_data; - int ret; #ifdef DEBUG printk("hostmixer: release called\n"); #endif - ret = hostmixer_release_mixdev_user(state); + os_close_file(state->fd); kfree(state); - return(ret); + return(0); } @@ -225,7 +311,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 -Nru a/arch/um/drivers/hostaudio_user.c b/arch/um/drivers/hostaudio_user.c --- a/arch/um/drivers/hostaudio_user.c 2004-10-18 14:56:48 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2002 Steve Schmidtke - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include "hostaudio.h" -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "os.h" - -/* /dev/dsp file operations */ - -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); -} - -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); -} - -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); -} - -int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) -{ -#ifdef DEBUG - 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); - - printk("hostaudio_open_user failed to open '%s', errno = %d\n", - dsp, errno); - - return(-errno); -} - -int hostaudio_release_user(struct hostaudio_state *state) -{ -#ifdef DEBUG - printk("hostaudio: release called\n"); -#endif - if(state->fd >= 0){ - close(state->fd); - state->fd=-1; - } - - return(0); -} - -/* /dev/mixer file operations */ - -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); -} - -int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, - char *mixer) -{ -#ifdef DEBUG - printk("hostmixer: open_user called\n"); -#endif - - 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); - - return(-errno); -} - -int hostmixer_release_mixdev_user(struct hostmixer_state *state) -{ -#ifdef DEBUG - printk("hostmixer: release_user called\n"); -#endif - - if(state->fd >= 0){ - close(state->fd); - state->fd = -1; - } - - 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 - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff -Nru a/arch/um/drivers/line.c b/arch/um/drivers/line.c --- a/arch/um/drivers/line.c 2004-10-18 14:57:03 -07:00 +++ b/arch/um/drivers/line.c 2004-10-18 14:57:03 -07:00 @@ -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); @@ -56,10 +73,11 @@ else { memcpy(line->tail, buf, end); buf += end; - len -= end; - memcpy(line->buffer, buf, len); - line->tail = line->buffer + len; + memcpy(line->buffer, buf, len - end); + line->tail = line->buffer + len - end; } + + return(len); } static int flush_buffer(struct line *line) @@ -95,7 +113,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 +122,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 +137,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 +192,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,20 +324,20 @@ if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return(1); + return(0); } init = end; } init++; if((n >= 0) && (n >= num)){ printk("line_setup - %d out of range ((0 ... %d) allowed)\n", - n, num); - return(1); + n, num - 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 +351,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 +365,7 @@ } } } - return(0); + return(1); } int line_config(struct line *lines, int num, char *str) @@ -357,7 +376,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 +388,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 +398,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 +415,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 +438,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 +459,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 +492,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 +520,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 +559,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 -Nru a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c --- a/arch/um/drivers/mcast_user.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/drivers/mcast_user.c 2004-10-18 14:56:32 -07:00 @@ -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 -Nru a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c --- a/arch/um/drivers/mconsole_kern.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/drivers/mconsole_kern.c 2004-10-18 14:55:54 -07:00 @@ -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) @@ -47,27 +51,26 @@ LIST_HEAD(mc_requests); -void mc_work_proc(void *unused) +static void mc_work_proc(void *unused) { struct mconsole_entry *req; unsigned long flags; - int done; - do { + while(!list_empty(&mc_requests)){ local_save_flags(flags); req = list_entry(mc_requests.next, struct mconsole_entry, list); list_del(&req->list); - done = list_empty(&mc_requests); local_irq_restore(flags); req->request.cmd->handler(&req->request); kfree(req); - } while(!done); + } } DECLARE_WORK(mconsole_work, mc_work_proc, NULL); -void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mconsole_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { int fd; struct mconsole_entry *new; @@ -75,9 +78,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 { @@ -86,8 +90,10 @@ } } } - if(!list_empty(&mc_requests)) schedule_work(&mconsole_work); + 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,109 @@ mconsole_reply(req, version, 0, 0); } +void mconsole_log(struct mc_request *req) +{ + int len; + char *ptr = req->request.data; + + ptr += strlen("log "); + + 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) @@ -279,8 +374,8 @@ ptr += strlen("sysrq"); while(isspace(*ptr)) ptr++; - handle_sysrq(*ptr, ¤t->thread.regs, NULL); mconsole_reply(req, "", 0, 0); + handle_sysrq(*ptr, ¤t->thread.regs, NULL); } #else void mconsole_sysrq(struct mc_request *req) @@ -302,7 +397,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 +439,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 -Nru a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c --- a/arch/um/drivers/mconsole_user.c 2004-10-18 14:56:16 -07:00 +++ b/arch/um/drivers/mconsole_user.c 2004-10-18 14:56:16 -07:00 @@ -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 -Nru a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c --- a/arch/um/drivers/mmapper_kern.c 2004-10-18 14:55:55 -07:00 +++ b/arch/um/drivers/mmapper_kern.c 2004-10-18 14:55:55 -07:00 @@ -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 -Nru a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c --- a/arch/um/drivers/net_kern.c 2004-10-18 14:56:29 -07:00 +++ b/arch/um/drivers/net_kern.c 2004-10-18 14:56:29 -07:00 @@ -19,6 +19,8 @@ #include "linux/inetdevice.h" #include "linux/ctype.h" #include "linux/bootmem.h" +#include "linux/ethtool.h" +#include "asm/uaccess.h" #include "user_util.h" #include "kern_util.h" #include "net_kern.h" @@ -26,6 +28,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 +40,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 +65,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 +87,7 @@ out: spin_unlock(&lp->lock); + return(IRQ_HANDLED); } static int uml_net_open(struct net_device *dev) @@ -124,6 +129,13 @@ spin_lock(&opened_lock); list_add(&lp->list, &opened); spin_unlock(&opened_lock); + + /* clear buffer - it can happen that the host side of the interface + * is full when we get here. In this case, new data is never queued, + * SIGIOs never arrive, and the net never works. + */ + while((err = uml_net_rx(dev)) > 0) ; + out: spin_unlock(&lp->lock); return(err); @@ -237,7 +249,30 @@ static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - return(-EINVAL); + static const struct ethtool_drvinfo info = { + .cmd = ETHTOOL_GDRVINFO, + .driver = "uml virtual ethernet", + .version = "42", + }; + void *useraddr; + u32 ethcmd; + + switch (cmd) { + case SIOCETHTOOL: + useraddr = ifr->ifr_data; + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + default: + return -EOPNOTSUPP; + } + default: + return -EINVAL; + } } void uml_net_user_timer_expire(unsigned long _conn) @@ -250,37 +285,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); @@ -290,7 +294,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); @@ -332,12 +336,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; @@ -364,21 +362,29 @@ } 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; @@ -611,7 +617,8 @@ unregister_netdev(dev); list_del(&device->list); - free_netdev(device); + kfree(device); + free_netdev(dev); return(0); } diff -Nru a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c --- a/arch/um/drivers/net_user.c 2004-10-18 14:56:17 -07:00 +++ b/arch/um/drivers/net_user.c 2004-10-18 14:56:17 -07:00 @@ -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,17 +165,18 @@ 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); + + CATCH_EINTR(err = waitpid(pid, NULL, 0)); return(pid); } diff -Nru a/arch/um/drivers/null.c b/arch/um/drivers/null.c --- a/arch/um/drivers/null.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/drivers/null.c 2004-10-18 14:55:54 -07:00 @@ -5,7 +5,6 @@ #include #include -#include #include "chan_user.h" #include "os.h" diff -Nru a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c --- a/arch/um/drivers/port_kern.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/drivers/port_kern.c 2004-10-18 14:55:54 -07:00 @@ -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 -Nru a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c --- a/arch/um/drivers/port_user.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/drivers/port_user.c 2004-10-18 14:56:33 -07:00 @@ -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, @@ -74,12 +76,17 @@ int port_open(int input, int output, int primary, void *d, char **dev_out) { struct port_chan *data = d; - int fd; + int fd, err; fd = port_wait(data->kernel_data); if((fd >= 0) && data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } *dev_out = data->dev; return(fd); @@ -90,7 +97,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 +137,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 +164,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 +177,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 +198,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 -Nru a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c --- a/arch/um/drivers/pty.c 2004-10-18 14:57:03 -07:00 +++ b/arch/um/drivers/pty.c 2004-10-18 14:57:03 -07:00 @@ -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 }); @@ -37,15 +38,21 @@ { struct pty_chan *data = d; char *dev; - int fd; + int fd, err; - if((fd = get_pty()) < 0){ + fd = get_pty(); + if(fd < 0){ printk("open_pts : Failed to open pts\n"); return(-errno); } if(data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } dev = ptsname(fd); @@ -57,29 +64,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); } } } @@ -89,13 +94,19 @@ int pty_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; - int fd; + int fd, err; char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; fd = getmaster(dev); - if(fd < 0) return(-errno); + if(fd < 0) + return(-errno); + + if(data->raw){ + err = raw(fd); + if(err) + return(err); + } - if(data->raw) raw(fd, 0); if(data->announce) (*data->announce)(dev, data->dev); sprintf(data->dev_name, "%s", dev); diff -Nru a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c --- a/arch/um/drivers/slip_user.c 2004-10-18 14:57:03 -07:00 +++ b/arch/um/drivers/slip_user.c 2004-10-18 14:57:03 -07:00 @@ -4,11 +4,9 @@ #include #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,16 +94,18 @@ 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); kfree(output); } - if(waitpid(pid, &status, 0) < 0) err = errno; + CATCH_EINTR(err = waitpid(pid, &status, 0)); + if(err < 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 +118,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); - } - if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){ - printk("Couldn't open tty for slip line\n"); - return(-1); + mfd = get_pty(); + if(mfd < 0){ + printk("umn : Failed to open pty, err = %d\n", -mfd); + return(mfd); + } + 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 +140,23 @@ err = slip_tramp(argv, sfd); - if(err != 0){ - printk("slip_tramp failed - errno = %d\n", err); - return(-err); - } - if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){ - printk("SIOCGIFNAME failed, errno = %d\n", errno); - return(-errno); + if(err < 0){ + printk("slip_tramp failed - err = %d\n", -err); + return(err); + } + 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 +178,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 +240,7 @@ { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; open_addr(addr, netmask, pri->name); } @@ -252,7 +249,7 @@ { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; close_addr(addr, netmask, pri->name); } diff -Nru a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c --- a/arch/um/drivers/slirp_user.c 2004-10-18 14:56:48 -07:00 +++ b/arch/um/drivers/slirp_user.c 2004-10-18 14:56:48 -07:00 @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include #include #include #include "user_util.h" @@ -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; @@ -114,13 +113,13 @@ } #endif - err = waitpid(pri->pid, &status, WNOHANG); - if(err<0) { + CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG)); + if(err < 0) { printk("slirp_close: waitpid returned %d\n", errno); return; } - if(err==0) { + if(err == 0) { printk("slirp_close: process %d has not exited\n"); return; } diff -Nru a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c --- a/arch/um/drivers/ssl.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/drivers/ssl.c 2004-10-18 14:56:32 -07:00 @@ -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,37 @@ */ static int ssl_init_done = 0; +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; @@ -227,17 +263,18 @@ 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); } -__initcall(ssl_init); +late_initcall(ssl_init); 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 -Nru a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c --- a/arch/um/drivers/stdio_console.c 2004-10-18 14:56:20 -07:00 +++ b/arch/um/drivers/stdio_console.c 2004-10-18 14:56:20 -07:00 @@ -17,8 +17,8 @@ #include "linux/init.h" #include "linux/interrupt.h" #include "linux/slab.h" +#include "linux/hardirq.h" #include "asm/current.h" -#include "asm/hardirq.h" #include "asm/irq.h" #include "stdio_console.h" #include "line.h" @@ -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,6 +160,15 @@ 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, +}; + int stdio_init(void) { char *new_title; @@ -166,7 +176,8 @@ printk(KERN_INFO "Initializing stdio console driver\n"); 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])); @@ -178,52 +189,53 @@ return(0); } -__initcall(stdio_init); +late_initcall(stdio_init); -static void console_write(struct console *console, const char *string, +static void uml_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) +static struct tty_driver *uml_console_device(struct console *c, int *index) { *index = c->index; return console_driver; } -static int console_setup(struct console *co, char *options) +static int uml_console_setup(struct console *co, char *options) { return(0); } -static struct console stdiocons = INIT_CONSOLE("tty", console_write, - console_device, console_setup, - CON_PRINTBUFFER); +static struct console stdiocons = { + name: "tty", + write: uml_console_write, + device: uml_console_device, + setup: uml_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 -Nru a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c --- a/arch/um/drivers/tty.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/drivers/tty.c 2004-10-18 14:56:28 -07:00 @@ -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 }); @@ -41,13 +41,18 @@ int tty_open(int input, int output, int primary, void *d, char **dev_out) { struct tty_chan *data = d; - int fd; + int fd, err; fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0); if(fd < 0) return(fd); if(data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } *dev_out = data->dev; diff -Nru a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c --- a/arch/um/drivers/ubd_kern.c 2004-10-18 14:56:31 -07:00 +++ b/arch/um/drivers/ubd_kern.c 2004-10-18 14:56:31 -07:00 @@ -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, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1); 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; } @@ -343,14 +396,13 @@ */ int intr_count = 0; -static void ubd_finish(struct request *req, int error) +/* call ubd_finish if you need to serialize */ +static void __ubd_finish(struct request *req, int error) { int nsect; if(error){ - spin_lock(&ubd_io_lock); end_request(req, 0); - spin_unlock(&ubd_io_lock); return; } nsect = req->current_nr_sectors; @@ -359,41 +411,57 @@ req->errors = 0; req->nr_sectors -= nsect; req->current_nr_sectors = 0; - spin_lock(&ubd_io_lock); end_request(req, 1); +} + +static inline void ubd_finish(struct request *req, int error) +{ + spin_lock(&ubd_io_lock); + __ubd_finish(req, error); spin_unlock(&ubd_io_lock); } +/* Called without ubd_io_lock held */ static void ubd_handler(void) { 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. */ @@ -417,10 +485,14 @@ static void ubd_close(struct ubd *dev) { + if(ubd_do_mmap) + physmem_forget_descriptor(dev->fd); os_close_file(dev->fd); if(dev->cow.file == NULL) return; + if(ubd_do_mmap) + physmem_forget_descriptor(dev->cow.fd); os_close_file(dev->cow.fd); vfree(dev->cow.bitmap); dev->cow.bitmap = NULL; @@ -429,18 +501,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 +529,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 +559,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 +598,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 +650,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 +693,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]; @@ -667,9 +754,7 @@ return -1; } - 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); @@ -688,9 +773,11 @@ unsigned long stack; int err; + /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/ if(global_openflags.s){ - printk(KERN_INFO "ubd : Synchronous mode\n"); - return(0); + printk(KERN_INFO "ubd: Synchronous mode\n"); + /* Letting ubd=sync be like using ubd#s= instead of ubd#= is + * enough. So use anyway the io thread. */ } stack = alloc_stack(0, 0); io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), @@ -699,12 +786,13 @@ printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); + io_pid = -1; return(0); } 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 +802,9 @@ { struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; - int err = -EISDIR; + int err = 0; - if(dev->is_dir == 1) - goto out; - - 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,91 +831,211 @@ 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) { - int i, update_bitmap, sector = req->offset >> 9; + __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) +{ + __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); } +/* Called with ubd_io_lock held */ 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); - spin_lock(&ubd_io_lock); end_request(req, 0); - spin_unlock(&ubd_io_lock); 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); } +/* Called with ubd_io_lock held */ static void do_ubd_request(request_queue_t *q) { struct io_thread_req io_req; @@ -841,18 +1043,17 @@ int err, n; if(thread_fd == -1){ - while(!list_empty(&q->queue_head)){ - req = elv_next_request(q); + while((req = elv_next_request(q)) != NULL){ err = prepare_request(req, &io_req); if(!err){ do_io(&io_req); - ubd_finish(req, io_req.error); + __ubd_finish(req, io_req.error); } } } else { - if(do_ubd || list_empty(&q->queue_head)) return; - req = elv_next_request(q); + if(do_ubd || (req = elv_next_request(q)) == NULL) + return; err = prepare_request(req, &io_req); if(!err){ do_ubd = ubd_handler; @@ -870,7 +1071,6 @@ { struct hd_geometry *loc = (struct hd_geometry *) arg; struct ubd *dev = inode->i_bdev->bd_disk->private_data; - int err; struct hd_driveid ubd_id = { .cyls = 0, .heads = 128, @@ -885,35 +1085,9 @@ 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: - if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if((arg > 1) || (inode->i_bdev->bd_contains != inode->i_bdev)) - return(-EINVAL); - return(0); - - case HDIO_GET_UNMASKINTR: - if(!arg) return(-EINVAL); - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if(err) - return(err); - return(0); - - case HDIO_GET_MULTCOUNT: - if(!arg) return(-EINVAL); - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if(err) - return(err); - return(0); - - case HDIO_SET_MULTCOUNT: - if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if(inode->i_bdev->bd_contains != inode->i_bdev) - return(-EINVAL); - return(0); - case HDIO_GET_IDENTITY: ubd_id.cyls = dev->size / (128 * 32 * 512); if(copy_to_user((char *) arg, (char *) &ubd_id, @@ -934,6 +1108,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. diff -Nru a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c --- a/arch/um/drivers/ubd_user.c 2004-10-18 14:56:20 -07:00 +++ b/arch/um/drivers/ubd_user.c 2004-10-18 14:56:20 -07:00 @@ -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,20 @@ NULL); if(pid < 0){ printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); - } - 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); + err = -errno; + goto out_close; } - 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 -Nru a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c --- a/arch/um/drivers/xterm.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/drivers/xterm.c 2004-10-18 14:55:54 -07:00 @@ -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, @@ -83,6 +83,7 @@ " are 'xterm=gnome-terminal,-t,-x'.\n\n" ); +/* XXX This badly needs some cleaning up in the error paths */ int xterm_open(int input, int output, int primary, void *d, char **dev_out) { struct xterm_chan *data = d; @@ -93,7 +94,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 +107,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,20 +129,32 @@ 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; } - tcgetattr(new, &data->tt); - if(data->raw) raw(new, 0); + CATCH_EINTR(err = tcgetattr(new, &data->tt)); + if(err){ + new = err; + goto out; + } + + if(data->raw){ + err = raw(new); + if(err){ + new = err; + goto out; + } + } data->pid = pid; *dev_out = NULL; @@ -160,7 +173,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 -Nru a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c --- a/arch/um/drivers/xterm_kern.c 2004-10-18 14:56:48 -07:00 +++ b/arch/um/drivers/xterm_kern.c 2004-10-18 14:56:48 -07:00 @@ -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 -Nru a/arch/um/dyn.lds.S b/arch/um/dyn.lds.S --- a/arch/um/dyn.lds.S 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,167 +0,0 @@ -OUTPUT_FORMAT(ELF_FORMAT) -OUTPUT_ARCH(ELF_ARCH) -ENTRY(_start) -jiffies = jiffies_64; - -SEARCH_DIR("/usr/local/i686-pc-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - . = START + SIZEOF_HEADERS; - .interp : { *(.interp) } - . = ALIGN(4096); - __binary_start = .; - . = ALIGN(4096); /* Init code and data */ - _stext = .; - __init_begin = .; - .text.init : { *(.text.init) } - - . = ALIGN(4096); - - /* Read-only sections, merged into text segment: */ - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { - KEEP (*(.init)) - } =0x90909090 - .plt : { *(.plt) } - .text : { - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0x90909090 - .fini : { - KEEP (*(.fini)) - } =0x90909090 - - .kstrtab : { *(.kstrtab) } - - #include "asm/common.lds.S" - - .data.init : { *(.data.init) } - - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(32 / 8); - .preinit_array : { *(.preinit_array) } - .init_array : { *(.init_array) } - .fini_array : { *(.fini_array) } - .data : { - . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ - *(.data.init_task) - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .eh_frame : { KEEP (*(.eh_frame)) } - .gcc_except_table : { *(.gcc_except_table) } - .dynamic : { *(.dynamic) } - .ctors : { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - /* We don't want to include the .ctor section from - from the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : { - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .got : { *(.got.plt) *(.got) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); - . = ALIGN(32 / 8); - } - _end = .; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} diff -Nru a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h --- a/arch/um/include/2_5compat.h 2004-10-18 14:56:29 -07:00 +++ b/arch/um/include/2_5compat.h 2004-10-18 14:56:29 -07:00 @@ -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 -Nru a/arch/um/include/Makefile b/arch/um/include/Makefile --- a/arch/um/include/Makefile 2004-10-18 14:57:04 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,7 +0,0 @@ -all : sc.h - -sc.h : ../util/mk_sc - ../util/mk_sc > $@ - -../util/mk_sc : - $(MAKE) -C ../util mk_sc diff -Nru a/arch/um/include/hostaudio.h b/arch/um/include/hostaudio.h --- a/arch/um/include/hostaudio.h 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2002 Steve Schmidtke - * Licensed under the GPL - */ - -#ifndef HOSTAUDIO_H -#define HOSTAUDIO_H - -#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" -#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" - -struct hostaudio_state { - int fd; -}; - -struct hostmixer_state { - int fd; -}; - -/* UML user-side protoypes */ -extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, - size_t count, loff_t *ppos); -extern ssize_t hostaudio_write_user(struct hostaudio_state *state, - const char *buffer, size_t count, - loff_t *ppos); -extern int hostaudio_ioctl_user(struct hostaudio_state *state, - unsigned int cmd, unsigned long arg); -extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w, - char *dsp); -extern int hostaudio_release_user(struct hostaudio_state *state); -extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, - unsigned int cmd, unsigned long arg); -extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, - int w, char *mixer); -extern int hostmixer_release_mixdev_user(struct hostmixer_state *state); - -#endif /* HOSTAUDIO_H */ - -/* - * 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 -Nru a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/include/irq_kern.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __IRQ_KERN_H__ +#define __IRQ_KERN_H__ + +#include "linux/interrupt.h" + +extern int um_request_irq(unsigned int irq, int fd, int type, + irqreturn_t (*handler)(int, void *, + struct pt_regs *), + unsigned long irqflags, const char * devname, + void *dev_id); + +#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 -Nru a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h --- a/arch/um/include/irq_user.h 2004-10-18 14:56:33 -07:00 +++ b/arch/um/include/irq_user.h 2004-10-18 14:56:33 -07:00 @@ -14,6 +14,7 @@ extern void free_irq_by_fd(int fd); extern void reactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum); +extern int deactivate_all_fds(void); extern void forward_interrupts(int pid); extern void init_irq_signals(int on_sigstack); extern void forward_ipi(int fd, int pid); diff -Nru a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h --- a/arch/um/include/kern_util.h 2004-10-18 14:56:28 -07:00 +++ b/arch/um/include/kern_util.h 2004-10-18 14:56:28 -07:00 @@ -60,12 +60,11 @@ extern void paging_init(void); extern void init_flush_vm(void); extern void *syscall_sp(void *t); -extern void syscall_trace(void); +extern void syscall_trace(union uml_pt_regs *regs, int entryexit); 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); @@ -89,9 +88,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); @@ -100,7 +97,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); @@ -111,6 +110,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 -Nru a/arch/um/include/line.h b/arch/um/include/line.h --- a/arch/um/include/line.h 2004-10-18 14:56:49 -07:00 +++ b/arch/um/include/line.h 2004-10-18 14:56:49 -07:00 @@ -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 -Nru a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h --- a/arch/um/include/mconsole.h 2004-10-18 14:56:29 -07:00 +++ b/arch/um/include/mconsole.h 2004-10-18 14:56:29 -07:00 @@ -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 -Nru a/arch/um/include/mem.h b/arch/um/include/mem.h --- a/arch/um/include/mem.h 2004-10-18 14:57:04 -07:00 +++ b/arch/um/include/mem.h 2004-10-18 14:57:04 -07:00 @@ -1,19 +1,18 @@ /* - * 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); +extern void physmem_forget_descriptor(int fd); #endif diff -Nru a/arch/um/include/mem_kern.h b/arch/um/include/mem_kern.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/include/mem_kern.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __MEM_KERN_H__ +#define __MEM_KERN_H__ + +#include "linux/list.h" +#include "linux/types.h" + +struct remapper { + struct list_head list; + int (*proc)(int, unsigned long, int, __u64); +}; + +extern void register_remapper(struct remapper *info); + +#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 -Nru a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h --- a/arch/um/include/mem_user.h 2004-10-18 14:56:33 -07:00 +++ b/arch/um/include/mem_user.h 2004-10-18 14:56:33 -07:00 @@ -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 -Nru a/arch/um/include/os.h b/arch/um/include/os.h --- a/arch/um/include/os.h 2004-10-18 14:56:18 -07:00 +++ b/arch/um/include/os.h 2004-10-18 14:56:18 -07:00 @@ -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,48 @@ 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_clear_fd_async(int fd); 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 +160,13 @@ 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); +extern unsigned long long os_usecs(void); #endif diff -Nru a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h --- a/arch/um/include/signal_user.h 2004-10-18 14:55:54 -07:00 +++ b/arch/um/include/signal_user.h 2004-10-18 14:55:54 -07:00 @@ -11,6 +11,8 @@ extern int change_sig(int signal, int on); extern void set_sigstack(void *stack, int size); extern void set_handler(int sig, void (*handler)(int), int flags, ...); +extern int set_signals(int enable); +extern int get_signals(void); #endif diff -Nru a/arch/um/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h --- a/arch/um/include/skas_ptrace.h 2004-10-18 14:57:03 -07:00 +++ b/arch/um/include/skas_ptrace.h 2004-10-18 14:57:03 -07:00 @@ -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 -Nru a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h --- a/arch/um/include/sysdep-i386/checksum.h 2004-10-18 14:57:19 -07:00 +++ b/arch/um/include/sysdep-i386/checksum.h 2004-10-18 14:57:19 -07:00 @@ -5,6 +5,7 @@ #ifndef __UM_SYSDEP_CHECKSUM_H #define __UM_SYSDEP_CHECKSUM_H +#include "linux/in6.h" #include "linux/string.h" /* @@ -102,7 +103,8 @@ are modified, we must also specify them as outputs, or gcc will assume they contain their original values. */ : "=r" (sum), "=r" (iph), "=r" (ihl) - : "1" (iph), "2" (ihl)); + : "1" (iph), "2" (ihl) + : "memory"); return(sum); } diff -Nru a/arch/um/include/sysdep-i386/frame_user.h b/arch/um/include/sysdep-i386/frame_user.h --- a/arch/um/include/sysdep-i386/frame_user.h 2004-10-18 14:57:04 -07:00 +++ b/arch/um/include/sysdep-i386/frame_user.h 2004-10-18 14:57:04 -07:00 @@ -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 -Nru a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h --- a/arch/um/include/sysdep-i386/sigcontext.h 2004-10-18 14:56:48 -07:00 +++ b/arch/um/include/sysdep-i386/sigcontext.h 2004-10-18 14:56:48 -07:00 @@ -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 -Nru a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h --- a/arch/um/include/sysdep-i386/syscalls.h 2004-10-18 14:55:55 -07:00 +++ b/arch/um/include/sysdep-i386/syscalls.h 2004-10-18 14:55:55 -07:00 @@ -11,39 +11,34 @@ #define EXECUTE_SYSCALL(syscall, regs) \ ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) -extern syscall_handler_t sys_modify_ldt; -extern syscall_handler_t old_mmap_i386; -extern syscall_handler_t old_select; -extern syscall_handler_t sys_ni_syscall; - #define ARCH_SYSCALLS \ - [ __NR_mmap ] = old_mmap_i386, \ - [ __NR_select ] = old_select, \ - [ __NR_vm86old ] = sys_ni_syscall, \ - [ __NR_modify_ldt ] = sys_modify_ldt, \ - [ __NR_lchown32 ] = sys_lchown, \ - [ __NR_getuid32 ] = sys_getuid, \ - [ __NR_getgid32 ] = sys_getgid, \ - [ __NR_geteuid32 ] = sys_geteuid, \ - [ __NR_getegid32 ] = sys_getegid, \ - [ __NR_setreuid32 ] = sys_setreuid, \ - [ __NR_setregid32 ] = sys_setregid, \ - [ __NR_getgroups32 ] = sys_getgroups, \ - [ __NR_setgroups32 ] = sys_setgroups, \ - [ __NR_fchown32 ] = sys_fchown, \ - [ __NR_setresuid32 ] = sys_setresuid, \ - [ __NR_getresuid32 ] = sys_getresuid, \ - [ __NR_setresgid32 ] = sys_setresgid, \ - [ __NR_getresgid32 ] = sys_getresgid, \ - [ __NR_chown32 ] = sys_chown, \ - [ __NR_setuid32 ] = sys_setuid, \ - [ __NR_setgid32 ] = sys_setgid, \ - [ __NR_setfsuid32 ] = sys_setfsuid, \ - [ __NR_setfsgid32 ] = sys_setfsgid, \ - [ __NR_pivot_root ] = sys_pivot_root, \ - [ __NR_mincore ] = sys_mincore, \ - [ __NR_madvise ] = sys_madvise, \ - [ 222 ] = sys_ni_syscall, + [ __NR_mmap ] = (syscall_handler_t *) old_mmap_i386, \ + [ __NR_select ] = (syscall_handler_t *) old_select, \ + [ __NR_vm86old ] = (syscall_handler_t *) sys_ni_syscall, \ + [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \ + [ __NR_lchown32 ] = (syscall_handler_t *) sys_lchown, \ + [ __NR_getuid32 ] = (syscall_handler_t *) sys_getuid, \ + [ __NR_getgid32 ] = (syscall_handler_t *) sys_getgid, \ + [ __NR_geteuid32 ] = (syscall_handler_t *) sys_geteuid, \ + [ __NR_getegid32 ] = (syscall_handler_t *) sys_getegid, \ + [ __NR_setreuid32 ] = (syscall_handler_t *) sys_setreuid, \ + [ __NR_setregid32 ] = (syscall_handler_t *) sys_setregid, \ + [ __NR_getgroups32 ] = (syscall_handler_t *) sys_getgroups, \ + [ __NR_setgroups32 ] = (syscall_handler_t *) sys_setgroups, \ + [ __NR_fchown32 ] = (syscall_handler_t *) sys_fchown, \ + [ __NR_setresuid32 ] = (syscall_handler_t *) sys_setresuid, \ + [ __NR_getresuid32 ] = (syscall_handler_t *) sys_getresuid, \ + [ __NR_setresgid32 ] = (syscall_handler_t *) sys_setresgid, \ + [ __NR_getresgid32 ] = (syscall_handler_t *) sys_getresgid, \ + [ __NR_chown32 ] = (syscall_handler_t *) sys_chown, \ + [ __NR_setuid32 ] = (syscall_handler_t *) sys_setuid, \ + [ __NR_setgid32 ] = (syscall_handler_t *) sys_setgid, \ + [ __NR_setfsuid32 ] = (syscall_handler_t *) sys_setfsuid, \ + [ __NR_setfsgid32 ] = (syscall_handler_t *) sys_setfsgid, \ + [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \ + [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \ + [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \ + [ 222 ] = (syscall_handler_t *) sys_ni_syscall, /* 222 doesn't yet have a name in include/asm-i386/unistd.h */ diff -Nru a/arch/um/include/time_user.h b/arch/um/include/time_user.h --- a/arch/um/include/time_user.h 2004-10-18 14:56:17 -07:00 +++ b/arch/um/include/time_user.h 2004-10-18 14:56:17 -07:00 @@ -11,6 +11,7 @@ extern void set_interval(int timer_type); extern void idle_sleep(int secs); extern void enable_timer(void); +extern void disable_timer(void); extern unsigned long time_lock(void); extern void time_unlock(unsigned long); diff -Nru a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h --- a/arch/um/include/ubd_user.h 2004-10-18 14:56:32 -07:00 +++ b/arch/um/include/ubd_user.h 2004-10-18 14:56:32 -07:00 @@ -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 -Nru a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h --- a/arch/um/include/um_uaccess.h 2004-10-18 14:56:48 -07:00 +++ b/arch/um/include/um_uaccess.h 2004-10-18 14:56:48 -07:00 @@ -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 -Nru a/arch/um/include/user.h b/arch/um/include/user.h --- a/arch/um/include/user.h 2004-10-18 14:55:54 -07:00 +++ b/arch/um/include/user.h 2004-10-18 14:55:54 -07:00 @@ -14,6 +14,9 @@ extern void kfree(void *ptr); extern int in_aton(char *str); extern int open_gdb_chan(void); +extern int strlcpy(char *, const char *, int); +extern void *um_vmalloc(int size); +extern void vfree(void *ptr); #endif diff -Nru a/arch/um/include/user_util.h b/arch/um/include/user_util.h --- a/arch/um/include/user_util.h 2004-10-18 14:55:55 -07:00 +++ b/arch/um/include/user_util.h 2004-10-18 14:55:55 -07:00 @@ -8,14 +8,14 @@ #include "sysdep/ptrace.h" +#define CATCH_EINTR(expr) while (((expr) < 0) && (errno == EINTR)) + extern int mode_tt; extern int grantpt(int __fd); 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,13 +59,11 @@ 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); extern int get_pty(void); extern void *um_kmalloc(int size); -extern int raw(int fd, int complain); extern int switcheroo(int fd, int prot, void *from, void *to, int size); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(void); @@ -76,7 +74,6 @@ extern void tracer_panic(char *msg, ...); extern char *get_umid(int only_if_set); extern void do_longjmp(void *p, int val); -extern void suspend_new_thread(int fd); extern int detach(int pid, int sig); extern int attach(int pid); extern void kill_child_dead(int pid); @@ -86,11 +83,15 @@ 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); +extern int setjmp_wrapper(void (*proc)(void *, void *), ...); +extern int raw(int fd); + #endif /* diff -Nru a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile --- a/arch/um/kernel/Makefile 2004-10-18 14:56:48 -07:00 +++ b/arch/um/kernel/Makefile 2004-10-18 14:56:48 -07:00 @@ -3,15 +3,16 @@ # Licensed under the GPL # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds +clean-files := vmlinux.lds.S 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 + helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.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_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o obj-$(CONFIG_GPROF) += gprof_syms.o @@ -24,43 +25,19 @@ user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ - process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o + main.o process.o tempfile.o time.o tty_log.o umid.o user_util.o frame.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__ -DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__ - - -CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \ - -I/usr/include -I../include - -CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS)) +CFLAGS_frame.o := -fno-omit-frame-pointer $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -# This has to be separate because it needs be compiled with frame pointers -# regardless of how the rest of the kernel is built. - -$(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 $$_ }' - -$(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: + $(CC) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) -c -o $@ $< -dep: +QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' -archmrproper: clean +quiet_cmd_quote = QUOTE $@ +cmd_quote = $(PERL) -e $(QUOTE) < $< > $@ +targets += config.c +$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config FORCE + $(call if_changed,quote) diff -Nru a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in --- a/arch/um/kernel/config.c.in 2004-10-18 14:56:48 -07:00 +++ b/arch/um/kernel/config.c.in 2004-10-18 14:56:48 -07:00 @@ -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 -Nru a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/kernel/dyn.lds.S 2004-10-18 14:56:32 -07:00 @@ -0,0 +1,171 @@ +#include + +OUTPUT_FORMAT(ELF_FORMAT) +OUTPUT_ARCH(ELF_ARCH) +ENTRY(_start) +jiffies = jiffies_64; + +SECTIONS +{ + . = START + SIZEOF_HEADERS; + .interp : { *(.interp) } + __binary_start = .; + . = ALIGN(4096); /* Init code and data */ + _stext = .; + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + + . = ALIGN(4096); + + /* Read-only sections, merged into text segment: */ + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : { + *(.text) + SCHED_TEXT + *(.stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : { + KEEP (*(.fini)) + } =0x90909090 + + .kstrtab : { *(.kstrtab) } + + #include "asm/common.lds.S" + + init.data : { *(.init.data) } + + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + .preinit_array : { *(.preinit_array) } + .init_array : { *(.init_array) } + .fini_array : { *(.fini_array) } + .data : { + . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ + *(.data.init_task) + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + } + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff -Nru a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c --- a/arch/um/kernel/exec_kern.c 2004-10-18 14:56:27 -07:00 +++ b/arch/um/kernel/exec_kern.c 2004-10-18 14:56:27 -07:00 @@ -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 -Nru a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c --- a/arch/um/kernel/frame.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/kernel/frame.c 2004-10-18 14:56:28 -07:00 @@ -21,6 +21,7 @@ #include "sysdep/sigcontext.h" #include "frame_user.h" #include "kern_util.h" +#include "user_util.h" #include "ptrace_user.h" #include "os.h" @@ -40,7 +41,7 @@ /* Wait for it to stop itself and continue it with a SIGUSR1 to force * it into the signal handler. */ - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); @@ -60,7 +61,7 @@ * At this point, the handler has stuffed the addresses of * sig, sc, and SA_RESTORER in raw. */ - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); @@ -82,7 +83,8 @@ errno); exit(1); } - if(waitpid(pid, &status, 0) < 0){ + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); } @@ -279,7 +281,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 +294,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 -Nru a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c --- a/arch/um/kernel/frame_kern.c 2004-10-18 14:57:19 -07:00 +++ b/arch/um/kernel/frame_kern.c 2004-10-18 14:57:19 -07:00 @@ -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 -Nru a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c --- a/arch/um/kernel/helper.c 2004-10-18 14:56:31 -07:00 +++ b/arch/um/kernel/helper.c 2004-10-18 14:56:31 -07:00 @@ -7,12 +7,12 @@ #include #include #include -#include #include #include #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "os.h" struct helper_data { @@ -33,6 +33,7 @@ { struct helper_data *data = arg; char **argv = data->argv; + int errval; if(helper_pause){ signal(SIGHUP, helper_hup); @@ -41,8 +42,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 +61,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 +85,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; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + 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, @@ -116,10 +132,12 @@ return(-errno); } if(stack_out == NULL){ - pid = waitpid(pid, &status, 0); - if(pid < 0) + CATCH_EINTR(pid = waitpid(pid, &status, 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); @@ -133,7 +151,7 @@ { int ret; - ret = waitpid(pid, NULL, WNOHANG); + CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); if(ret < 0){ printk("helper_wait : waitpid failed, errno = %d\n", errno); return(-errno); diff -Nru a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c --- a/arch/um/kernel/init_task.c 2004-10-18 14:57:05 -07:00 +++ b/arch/um/kernel/init_task.c 2004-10-18 14:57:05 -07:00 @@ -8,7 +8,6 @@ #include "linux/module.h" #include "linux/sched.h" #include "linux/init_task.h" -#include "linux/version.h" #include "linux/mqueue.h" #include "asm/uaccess.h" #include "asm/pgtable.h" @@ -19,7 +18,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); /* @@ -44,24 +43,10 @@ __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); } /* diff -Nru a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c --- a/arch/um/kernel/initrd_user.c 2004-10-18 14:56:17 -07:00 +++ b/arch/um/kernel/initrd_user.c 2004-10-18 14:56:17 -07:00 @@ -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 -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c --- a/arch/um/kernel/irq.c 2004-10-18 14:56:49 -07:00 +++ b/arch/um/kernel/irq.c 2004-10-18 14:56:49 -07:00 @@ -18,9 +18,10 @@ #include "linux/proc_fs.h" #include "linux/init.h" #include "linux/seq_file.h" +#include "linux/profile.h" +#include "linux/hardirq.h" #include "asm/irq.h" #include "asm/hw_irq.h" -#include "asm/hardirq.h" #include "asm/atomic.h" #include "asm/signal.h" #include "asm/system.h" @@ -29,6 +30,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 +85,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; } /* @@ -155,13 +147,16 @@ struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -169,7 +164,7 @@ local_irq_disable(); - return status; + return retval; } /* @@ -282,13 +277,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 +379,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,16 +427,22 @@ 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); } +EXPORT_SYMBOL(um_request_irq); +EXPORT_SYMBOL(reactivate_fd); /* this was setup_x86_irq but it seems pretty generic */ int setup_irq(unsigned int irq, struct irqaction * new) @@ -474,7 +474,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 +587,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 /* @@ -599,9 +602,11 @@ * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. */ - cpus_and(tmp, new_value, cpu_online_map); - if (cpus_empty(tmp)) - return -EINVAL; + { cpumask_t tmp; + cpus_and(tmp, new_value, cpu_online_map); + if (cpus_empty(tmp)) + return -EINVAL; + } #endif irq_affinity[irq] = new_value; @@ -610,30 +615,6 @@ return full_count; } -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data, new_value; - unsigned long full_count = count, err; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -662,24 +643,15 @@ smp_affinity_entry[irq] = entry; } -/* Read and written as a long */ -cpumask_t prof_cpu_mask = CPU_MASK_ALL; - void __init init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff -Nru a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c --- a/arch/um/kernel/irq_user.c 2004-10-18 14:56:29 -07:00 +++ b/arch/um/kernel/irq_user.c 2004-10-18 14:56:29 -07:00 @@ -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); @@ -364,36 +364,47 @@ irq_unlock(flags); } -void forward_ipi(int fd, int pid) +int deactivate_all_fds(void) { - 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); - } + struct irq_fd *irq; + int err; + + for(irq=active_fds;irq != NULL;irq = irq->next){ + err = os_clear_fd_async(irq->fd); + if(err) + return(err); } + + return(0); +} + +void forward_ipi(int fd, int pid) +{ + 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 -Nru a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c --- a/arch/um/kernel/ksyms.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/kernel/ksyms.c 2004-10-18 14:55:54 -07:00 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -8,7 +8,7 @@ #include "linux/string.h" #include "linux/smp_lock.h" #include "linux/spinlock.h" -#include +#include "linux/highmem.h" #include "asm/current.h" #include "asm/delay.h" #include "asm/processor.h" @@ -19,6 +19,7 @@ #include "asm/tlbflush.h" #include "kern_util.h" #include "user_util.h" +#include "mem_user.h" #include "os.h" #include "helper.h" @@ -34,34 +35,67 @@ 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); +EXPORT_SYMBOL(find_iomem); +#ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(strncpy_from_user_tt); +EXPORT_SYMBOL(copy_from_user_tt); +EXPORT_SYMBOL(copy_to_user_tt); +#endif + +#ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(strncpy_from_user_skas); +EXPORT_SYMBOL(copy_to_user_skas); +EXPORT_SYMBOL(copy_from_user_skas); +#endif +EXPORT_SYMBOL(uml_strdup); + +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_ioctl_generic); 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. */ @@ -75,10 +109,10 @@ /* required for SMP */ extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); -EXPORT_SYMBOL_NOVERS(__write_lock_failed); +EXPORT_SYMBOL(__write_lock_failed); extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); -EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(__read_lock_failed); #endif @@ -90,3 +124,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 -Nru a/arch/um/kernel/main.c b/arch/um/kernel/main.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/kernel/main.c 2004-10-18 14:56:49 -07:00 @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "mem_user.h" +#include "signal_user.h" +#include "user.h" +#include "init.h" +#include "mode.h" +#include "choose-mode.h" +#include "uml-config.h" + +/* Set in set_stklim, which is called from main and __wrap_malloc. + * __wrap_malloc only calls it if main hasn't started. + */ +unsigned long stacksizelim; + +/* Set in main */ +char *linux_prog; + +#define PGD_BOUND (4 * 1024 * 1024) +#define STACKSIZE (8 * 1024 * 1024) +#define THREAD_NAME_LEN (256) + +static void set_stklim(void) +{ + struct rlimit lim; + + if(getrlimit(RLIMIT_STACK, &lim) < 0){ + perror("getrlimit"); + exit(1); + } + if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){ + lim.rlim_cur = STACKSIZE; + if(setrlimit(RLIMIT_STACK, &lim) < 0){ + perror("setrlimit"); + exit(1); + } + } + stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); +} + +static __init void do_uml_initcalls(void) +{ + initcall_t *call; + + call = &__uml_initcall_start; + while (call < &__uml_initcall_end){; + (*call)(); + call++; + } +} + +static void last_ditch_exit(int sig) +{ + CHOOSE_MODE(kmalloc_ok = 0, (void) 0); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + uml_cleanup(); + exit(1); +} + +extern int uml_exitcode; + +int main(int argc, char **argv, char **envp) +{ + char **new_argv; + sigset_t mask; + int ret, i; + + /* Enable all signals except SIGIO - in some environments, we can + * enter with some signals blocked + */ + + sigemptyset(&mask); + sigaddset(&mask, SIGIO); + if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){ + perror("sigprocmask"); + exit(1); + } + +#ifdef UML_CONFIG_MODE_TT + /* Allocate memory for thread command lines */ + if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ + + char padding[THREAD_NAME_LEN] = { + [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0' + }; + + new_argv = malloc((argc + 2) * sizeof(char*)); + if(!new_argv) { + perror("Allocating extended argv"); + exit(1); + } + + new_argv[0] = argv[0]; + new_argv[1] = padding; + + for(i = 2; i <= argc; i++) + new_argv[i] = argv[i - 1]; + new_argv[argc + 1] = NULL; + + execvp(new_argv[0], new_argv); + perror("execing with extended args"); + exit(1); + } +#endif + + linux_prog = argv[0]; + + set_stklim(); + + new_argv = malloc((argc + 1) * sizeof(char *)); + if(new_argv == NULL){ + perror("Mallocing argv"); + exit(1); + } + for(i=0;i= uml_physmem) && (addr < high_physmem)){ + if(CAN_KMALLOC()) + kfree(ptr); + } + else if((addr >= start_vm) && (addr < end_vm)){ + if(CAN_KMALLOC()) + vfree(ptr); + } + else __real_free(ptr); +} + +/* + * 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 -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c --- a/arch/um/kernel/mem.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/kernel/mem.c 2004-10-18 14:56:28 -07:00 @@ -1,74 +1,66 @@ /* - * 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; +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); + set_page_count(page, 1); + __free_page(page); + } +} +#endif void mem_init(void) { @@ -103,50 +95,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 +135,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 +173,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); - set_page_count(page, 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 +197,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 @@ -400,395 +280,6 @@ printk("%d pages shared\n", shared); 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 -Nru a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c --- a/arch/um/kernel/mem_user.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/kernel/mem_user.c 2004-10-18 14:56:32 -07:00 @@ -34,10 +34,9 @@ #include #include #include -#include #include #include -#include +#include #include #include #include "kern_util.h" @@ -47,105 +46,147 @@ #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, size; 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; + } + + size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); + + *new = ((struct iomem_region) { .next = iomem_regions, + .driver = driver, + .fd = fd, + .size = 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,71 +194,18 @@ " 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; } /* diff -Nru a/arch/um/kernel/mprot.h b/arch/um/kernel/mprot.h --- a/arch/um/kernel/mprot.h 2004-10-18 14:56:29 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,6 +0,0 @@ -#ifndef __MPROT_H__ -#define __MPROT_H__ - -extern void no_access(unsigned long addr, unsigned int len); - -#endif diff -Nru a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/kernel/physmem.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "linux/rbtree.h" +#include "linux/slab.h" +#include "linux/vmalloc.h" +#include "linux/bootmem.h" +#include "linux/module.h" +#include "asm/types.h" +#include "asm/pgtable.h" +#include "kern_util.h" +#include "user_util.h" +#include "mode_kern.h" +#include "mem.h" +#include "mem_user.h" +#include "os.h" +#include "kern.h" +#include "init.h" + +struct phys_desc { + struct rb_node rb; + int fd; + __u64 offset; + void *virt; + unsigned long phys; + struct list_head list; +}; + +static struct rb_root phys_mappings = RB_ROOT; + +static struct rb_node **find_rb(void *virt) +{ + struct rb_node **n = &phys_mappings.rb_node; + struct phys_desc *d; + + while(*n != NULL){ + d = rb_entry(*n, struct phys_desc, rb); + if(d->virt == virt) + return(n); + + if(d->virt > virt) + n = &(*n)->rb_left; + else + n = &(*n)->rb_right; + } + + return(n); +} + +static struct phys_desc *find_phys_mapping(void *virt) +{ + struct rb_node **n = find_rb(virt); + + if(*n == NULL) + return(NULL); + + return(rb_entry(*n, struct phys_desc, rb)); +} + +static void insert_phys_mapping(struct phys_desc *desc) +{ + struct rb_node **n = find_rb(desc->virt); + + if(*n != NULL) + panic("Physical remapping for %p already present", + desc->virt); + + rb_link_node(&desc->rb, (*n)->rb_parent, n); + rb_insert_color(&desc->rb, &phys_mappings); +} + +LIST_HEAD(descriptor_mappings); + +struct desc_mapping { + int fd; + struct list_head list; + struct list_head pages; +}; + +static struct desc_mapping *find_mapping(int fd) +{ + struct desc_mapping *desc; + struct list_head *ele; + + list_for_each(ele, &descriptor_mappings){ + desc = list_entry(ele, struct desc_mapping, list); + if(desc->fd == fd) + return(desc); + } + + return(NULL); +} + +static struct desc_mapping *descriptor_mapping(int fd) +{ + struct desc_mapping *desc; + + desc = find_mapping(fd); + if(desc != NULL) + return(desc); + + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if(desc == NULL) + return(NULL); + + *desc = ((struct desc_mapping) + { .fd = fd, + .list = LIST_HEAD_INIT(desc->list), + .pages = LIST_HEAD_INIT(desc->pages) }); + list_add(&desc->list, &descriptor_mappings); + + return(desc); +} + +int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) +{ + struct desc_mapping *fd_maps; + struct phys_desc *desc; + unsigned long phys; + int err; + + fd_maps = descriptor_mapping(fd); + if(fd_maps == NULL) + return(-ENOMEM); + + phys = __pa(virt); + desc = find_phys_mapping(virt); + if(desc != NULL) + panic("Address 0x%p is already substituted\n", virt); + + err = -ENOMEM; + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if(desc == NULL) + goto out; + + *desc = ((struct phys_desc) + { .fd = fd, + .offset = offset, + .virt = virt, + .phys = __pa(virt), + .list = LIST_HEAD_INIT(desc->list) }); + insert_phys_mapping(desc); + + list_add(&desc->list, &fd_maps->pages); + + virt = (void *) ((unsigned long) virt & PAGE_MASK); + err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0); + if(!err) + goto out; + + rb_erase(&desc->rb, &phys_mappings); + kfree(desc); + out: + return(err); +} + +static int physmem_fd = -1; + +static void remove_mapping(struct phys_desc *desc) +{ + void *virt = desc->virt; + int err; + + rb_erase(&desc->rb, &phys_mappings); + list_del(&desc->list); + kfree(desc); + + err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0); + if(err) + panic("Failed to unmap block device page from physical memory, " + "errno = %d", -err); +} + +int physmem_remove_mapping(void *virt) +{ + struct phys_desc *desc; + + virt = (void *) ((unsigned long) virt & PAGE_MASK); + desc = find_phys_mapping(virt); + if(desc == NULL) + return(0); + + remove_mapping(desc); + return(1); +} + +void physmem_forget_descriptor(int fd) +{ + struct desc_mapping *desc; + struct phys_desc *page; + struct list_head *ele, *next; + __u64 offset; + void *addr; + int err; + + desc = find_mapping(fd); + if(desc == NULL) + return; + + list_for_each_safe(ele, next, &desc->pages){ + page = list_entry(ele, struct phys_desc, list); + offset = page->offset; + addr = page->virt; + remove_mapping(page); + err = os_seek_file(fd, offset); + if(err) + panic("physmem_forget_descriptor - failed to seek " + "to %lld in fd %d, error = %d\n", + offset, fd, -err); + err = os_read_file(fd, addr, PAGE_SIZE); + if(err < 0) + panic("physmem_forget_descriptor - failed to read " + "from fd %d to 0x%p, error = %d\n", + fd, addr, -err); + } + + list_del(&desc->list); + kfree(desc); +} + +EXPORT_SYMBOL(physmem_forget_descriptor); +EXPORT_SYMBOL(physmem_remove_mapping); +EXPORT_SYMBOL(physmem_subst_mapping); + +void arch_free_page(struct page *page, int order) +{ + void *virt; + int i; + + for(i = 0; i < (1 << order); i++){ + virt = __va(page_to_phys(page + i)); + physmem_remove_mapping(virt); + } +} + +int is_remapped(void *virt) +{ + struct phys_desc *desc = find_phys_mapping(virt); + + return(desc != NULL); +} + +/* Changed during early boot */ +unsigned long high_physmem; + +extern unsigned long physmem_size; + +void *to_virt(unsigned long phys) +{ + return((void *) uml_physmem + phys); +} + +unsigned long to_phys(void *virt) +{ + return(((unsigned long) virt) - uml_physmem); +} + +int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) +{ + struct page *p, *map; + unsigned long phys_len, phys_pages, highmem_len, highmem_pages; + unsigned long iomem_len, iomem_pages, total_len, total_pages; + int i; + + phys_pages = physmem >> PAGE_SHIFT; + phys_len = phys_pages * sizeof(struct page); + + iomem_pages = iomem >> PAGE_SHIFT; + iomem_len = iomem_pages * sizeof(struct page); + + highmem_pages = highmem >> PAGE_SHIFT; + highmem_len = highmem_pages * sizeof(struct page); + + total_pages = phys_pages + iomem_pages + highmem_pages; + total_len = phys_len + iomem_pages + highmem_len; + + if(kmalloc_ok){ + map = kmalloc(total_len, GFP_KERNEL); + if(map == NULL) + map = vmalloc(total_len); + } + else map = alloc_bootmem_low_pages(total_len); + + if(map == NULL) + return(-ENOMEM); + + for(i = 0; i < total_pages; i++){ + p = &map[i]; + set_page_count(p, 0); + SetPageReserved(p); + INIT_LIST_HEAD(&p->lru); + } + + mem_map = map; + max_mapnr = total_pages; + return(0); +} + +struct page *phys_to_page(const unsigned long phys) +{ + return(&mem_map[phys >> PAGE_SHIFT]); +} + +struct page *__virt_to_page(const unsigned long virt) +{ + return(&mem_map[__pa(virt) >> PAGE_SHIFT]); +} + +unsigned long page_to_phys(struct page *page) +{ + return((page - mem_map) << PAGE_SHIFT); +} + +pte_t mk_pte(struct page *page, pgprot_t pgprot) +{ + pte_t pte; + + pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot); + if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte)); + return(pte); +} + +/* 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 map_memory(unsigned long virt, unsigned long phys, unsigned long len, + int r, int w, int x) +{ + __u64 offset; + int fd, err; + + fd = phys_mapping(phys, &offset); + err = os_map_memory((void *) virt, fd, offset, len, r, w, x); + if(err) { + if(err == -ENOMEM) + printk("try increasing the host's " + "/proc/sys/vm/max_map_count to /4096\n"); + panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, " + "err = %d\n", virt, fd, offset, len, r, w, x, err); + } +} + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) + +void setup_physmem(unsigned long start, unsigned long reserve_end, + unsigned long len, unsigned long highmem) +{ + unsigned long reserve = reserve_end - start; + int pfn = PFN_UP(__pa(reserve_end)); + int delta = (len - reserve) >> PAGE_SHIFT; + int err, offset, bootmap_size; + + physmem_fd = create_mem_file(len + highmem); + + offset = uml_reserved - uml_physmem; + err = os_map_memory((void *) uml_reserved, physmem_fd, offset, + len - offset, 1, 1, 0); + if(err < 0){ + os_print_error(err, "Mapping memory"); + exit(1); + } + + bootmap_size = init_bootmem(pfn, pfn + delta); + free_bootmem(__pa(reserve_end) + bootmap_size, + len - bootmap_size - reserve); +} + +int phys_mapping(unsigned long phys, __u64 *offset_out) +{ + struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK)); + int fd = -1; + + if(desc != NULL){ + fd = desc->fd; + *offset_out = desc->offset; + } + else if(phys < physmem_size){ + fd = physmem_fd; + *offset_out = phys; + } + else if(phys < __pa(end_iomem)){ + struct iomem_region *region = iomem_regions; + + while(region != NULL){ + if((phys >= region->phys) && + (phys < region->phys + region->size)){ + fd = region->fd; + *offset_out = phys - region->phys; + break; + } + region = region->next; + } + } + else if(phys < __pa(end_iomem) + highmem){ + fd = physmem_fd; + *offset_out = phys - iomem_size; + } + + return(fd); +} + +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 host. It can\n" +" be more, and the excess, if it's ever used, will just be swapped out.\n" +" Example: mem=64M\n\n" +); + +unsigned long find_iomem(char *driver, unsigned long *len_out) +{ + struct iomem_region *region = iomem_regions; + + while(region != NULL){ + if(!strcmp(region->driver, driver)){ + *len_out = region->size; + return(region->virt); + } + } + + return(0); +} + +int setup_iomem(void) +{ + struct iomem_region *region = iomem_regions; + unsigned long iomem_start = high_physmem + PAGE_SIZE; + int err; + + while(region != NULL){ + err = os_map_memory((void *) iomem_start, region->fd, 0, + region->size, 1, 1, 0); + if(err) + printk("Mapping iomem region for driver '%s' failed, " + "errno = %d\n", region->driver, -err); + else { + region->virt = iomem_start; + region->phys = __pa(region->virt); + } + + iomem_start += region->size + PAGE_SIZE; + region = region->next; + } + + return(0); +} + +__initcall(setup_iomem); + +/* + * 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 -Nru a/arch/um/kernel/process.c b/arch/um/kernel/process.c --- a/arch/um/kernel/process.c 2004-10-18 14:56:50 -07:00 +++ b/arch/um/kernel/process.c 2004-10-18 14:56:50 -07:00 @@ -9,18 +9,17 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include #include +#include #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -47,7 +46,7 @@ int flags = 0, pages; if(sig_stack != NULL){ - pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; + pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); set_sigstack(sig_stack, pages * page_size()); flags = SA_ONSTACK; } @@ -71,8 +70,7 @@ set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 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); + flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); signal(SIGHUP, SIG_IGN); init_irq_signals(altstack); @@ -122,24 +120,19 @@ /* 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)) ; - 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"); - - return(arg.pid); -} + if(new_pid < 0) + return(new_pid); -void suspend_new_thread(int fd) -{ - char c; + CATCH_EINTR(err = waitpid(new_pid, &status, 0)); + if(err < 0) + panic("Waiting for outer trampoline failed - errno = %d", + errno); - os_stop_process(os_getpid()); + if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) + panic("outer trampoline didn't exit with SIGKILL, " + "status = %d", status); - if(read(fd, &c, sizeof(c)) != sizeof(c)) - panic("read failed in suspend_new_thread"); + return(arg.pid); } static int ptrace_child(void *arg) @@ -168,7 +161,7 @@ pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); if(pid < 0) panic("check_ptrace : clone failed, errno = %d", errno); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) @@ -185,7 +178,7 @@ if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, 0); + CATCH_EINTR(n = waitpid(pid, &status, 0)); if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) panic("check_ptrace : child exited with status 0x%x", status); @@ -193,6 +186,66 @@ panic("check_ptrace : munmap failed, errno = %d", errno); } +static int force_sysemu_disabled = 0; + +static int __init nosysemu_cmd_param(char *str, int* add) +{ + force_sysemu_disabled = 1; + return 0; +} + +__uml_setup("nosysemu", nosysemu_cmd_param, + "nosysemu\n" + " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n" + " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" + " behaviour of ptrace() and helps reducing host context switch rate.\n" + " To make it working, you need a kernel patch for your host, too.\n" + " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n"); + +static void __init check_sysemu(void) +{ + void *stack; + int pid, n, status; + + if (mode_tt) + return; + + printk("Checking syscall emulation patch for ptrace..."); + sysemu_supported = 0; + pid = start_ptraced_child(&stack); + if(ptrace(PTRACE_SYSEMU, pid, 0, 0) >= 0) { + struct user_regs_struct regs; + + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + if (n < 0) + panic("check_ptrace : wait failed, errno = %d", errno); + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("check_ptrace : expected SIGTRAP, " + "got status = %d", status); + + if (ptrace(PTRACE_GETREGS, pid, 0, ®s) < 0) + panic("check_ptrace : failed to read child " + "registers, errno = %d", errno); + regs.orig_eax = pid; + if (ptrace(PTRACE_SETREGS, pid, 0, ®s) < 0) + panic("check_ptrace : failed to modify child " + "registers, errno = %d", errno); + + stop_ptraced_child(pid, stack, 0); + + sysemu_supported = 1; + printk("found\n"); + } + else + { + stop_ptraced_child(pid, stack, 1); + sysemu_supported = 0; + printk("missing\n"); + } + + set_using_sysemu(!force_sysemu_disabled); +} + void __init check_ptrace(void) { void *stack; @@ -205,7 +258,7 @@ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) @@ -225,15 +278,16 @@ } stop_ptraced_child(pid, stack, 0); printk("OK\n"); + check_sysemu(); } int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) { - jmp_buf buf; + sigjmp_buf buf; int n; *jmp_ptr = &buf; - n = setjmp(buf); + n = sigsetjmp(buf, 1); if(n != 0) return(n); (*fn)(arg); @@ -273,7 +327,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 -Nru a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c --- a/arch/um/kernel/process_kern.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/kernel/process_kern.c 2004-10-18 14:56:32 -07:00 @@ -16,6 +16,8 @@ #include "linux/module.h" #include "linux/init.h" #include "linux/capability.h" +#include "linux/vmalloc.h" +#include "linux/spinlock.h" #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -23,7 +25,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 +53,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 +91,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,22 +100,25 @@ 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, struct task_struct *tsk) { - unsigned cpu = smp_processor_id(); + int cpu = smp_processor_id(); + if (prev != next) - clear_bit(cpu, &prev->cpu_vm_mask); - set_bit(cpu, &next->cpu_vm_mask); + cpu_clear(cpu, prev->cpu_vm_mask); + cpu_set(cpu, next->cpu_vm_mask); } void set_current(void *t) @@ -129,7 +129,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 +149,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,13 +157,15 @@ 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) { p->thread = (struct thread_struct) INIT_THREAD; - p->thread.kernel_stack = - (unsigned long) p->thread_info + 2 * PAGE_SIZE; return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, clone_flags, sp, stack_top, p, regs)); } @@ -190,7 +192,7 @@ void default_idle(void) { - idle_timer(); + uml_idle_timer(); atomic_inc(&init_mm.mm_count); current->mm = &init_mm; @@ -299,6 +301,11 @@ return(kmalloc(size, GFP_ATOMIC)); } +void *um_vmalloc(int size) +{ + return(vmalloc(size)); +} + unsigned long get_fault_addr(void) { return((unsigned long) current->thread.fault_addr); @@ -318,8 +325,7 @@ unsigned long stack; stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); - stack += 2 * PAGE_SIZE; - return(stack != current->thread.kernel_stack); + return(stack != (unsigned long) current_thread); } extern void remove_umid_dir(void); @@ -367,10 +373,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 +396,7 @@ int cpu(void) { - return(current->thread_info->cpu); + return(current_thread->cpu); } /* diff -Nru a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c --- a/arch/um/kernel/ptrace.c 2004-10-18 14:57:19 -07:00 +++ b/arch/um/kernel/ptrace.c 2004-10-18 14:57:19 -07:00 @@ -24,11 +24,6 @@ { } -extern long do_mmap2(struct task_struct *task, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, - unsigned long pgoff); - int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -292,7 +287,7 @@ } #endif default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: @@ -302,8 +297,17 @@ return ret; } -void syscall_trace(void) +void syscall_trace(union uml_pt_regs *regs, int entryexit) { + if (unlikely(current->audit_context)) { + if (!entryexit) + audit_syscall_entry(current, regs->orig_eax, + regs->ebx, regs->ecx, + regs->edx, regs->esi); + else + audit_syscall_exit(current, regs->eax); + } + if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; if (!(current->ptrace & PT_PTRACED)) @@ -311,11 +315,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 -Nru a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c --- a/arch/um/kernel/reboot.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/kernel/reboot.c 2004-10-18 14:56:32 -07:00 @@ -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 -Nru a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c --- a/arch/um/kernel/sigio_kern.c 2004-10-18 14:56:27 -07:00 +++ b/arch/um/kernel/sigio_kern.c 2004-10-18 14:56:27 -07:00 @@ -6,26 +6,33 @@ #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) +static 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) { - if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, + int err; + + err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", - NULL)){ - printk("write_sigio_irq : um_request_irq failed\n"); + NULL); + if(err){ + printk("write_sigio_irq : um_request_irq failed, err = %d\n", + err); return(-1); } sigio_irq_fd = fd; diff -Nru a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c --- a/arch/um/kernel/sigio_user.c 2004-10-18 14:57:04 -07:00 +++ b/arch/um/kernel/sigio_user.c 2004-10-18 14:57:04 -07:00 @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include "init.h" #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "sigio.h" #include "helper.h" #include "os.h" @@ -26,7 +26,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,19 +45,18 @@ 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)) { 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,14 @@ return; } - 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); + /* Not now, but complain so we now where we failed. */ + err = raw(master); + if (err < 0) + panic("check_sigio : __raw failed, errno = %d\n", -err); + + 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 +87,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 +102,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 +130,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 +192,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 +208,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 +242,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 +261,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 +359,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 +389,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 +402,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 -Nru a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c --- a/arch/um/kernel/signal_kern.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/signal_kern.c 2004-10-18 14:56:33 -07:00 @@ -31,17 +31,6 @@ EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(unblock_signals); -static void force_segv(int sig) -{ - if(sig == SIGSEGV){ - struct k_sigaction *ka; - - ka = ¤t->sig->action[SIGSEGV - 1]; - ka->sa.sa_handler = SIG_DFL; - } - force_sig(SIGSEGV, current); -} - #define _S(nr) (1<<((nr)-1)) #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) @@ -60,10 +49,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; @@ -124,27 +113,27 @@ return(0); segv: - force_segv(signr); + force_sigsegv(signr, current); return(1); } static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) { + struct k_sigaction ka_copy; siginfo_t info; - struct k_sigaction *ka; int err, sig; if (!oldset) oldset = ¤t->blocked; - sig = get_signal_to_deliver(&info, regs, NULL); + sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL); if(sig == 0) return(0); /* Whee! Actually deliver the signal. */ - ka = ¤t->sig->action[sig -1 ]; - err = handle_signal(regs, sig, ka, &info, oldset, error); - if(!err) return(1); + err = handle_signal(regs, sig, &ka_copy, &info, oldset, error); + if(!err) + return(1); /* Did we come from a system call? */ if(PT_REGS_SYSCALL_NR(regs) >= 0){ @@ -201,7 +190,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 +216,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 +285,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 +294,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 -Nru a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c --- a/arch/um/kernel/signal_user.c 2004-10-18 14:56:48 -07:00 +++ b/arch/um/kernel/signal_user.c 2004-10-18 14:56:48 -07:00 @@ -80,6 +80,12 @@ change_signals(SIG_UNBLOCK); } +/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled + * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to + * be able to profile all of UML, not just the non-critical sections. If + * profiling is not thread-safe, then that is not my problem. We can disable + * profiling when SMP is enabled in that case. + */ #define SIGIO_BIT 0 #define SIGVTALRM_BIT 1 @@ -114,6 +120,11 @@ sigaddset(&mask, SIGVTALRM); sigaddset(&mask, SIGALRM); } + + /* This is safe - sigprocmask is guaranteed to copy locally the + * value of new_set, do his work and then, at the end, write to + * old_set. + */ if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) panic("Failed to enable signals"); ret = enable_mask(&mask); diff -Nru a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile --- a/arch/um/kernel/skas/Makefile 2004-10-18 14:56:28 -07:00 +++ b/arch/um/kernel/skas/Makefile 2004-10-18 14:56:28 -07:00 @@ -3,22 +3,14 @@ # Licensed under the GPL # -obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ +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)/ + +subdir-y := util 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 - $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : - $(MAKE) -C util clean - $(RM) -f include/skas_ptregs.h diff -Nru a/arch/um/kernel/skas/exec_user.c b/arch/um/kernel/skas/exec_user.c --- a/arch/um/kernel/skas/exec_user.c 2004-10-18 14:56:17 -07:00 +++ b/arch/um/kernel/skas/exec_user.c 2004-10-18 14:56:17 -07:00 @@ -11,6 +11,7 @@ #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "os.h" #include "time_user.h" @@ -26,7 +27,7 @@ int user_thread(unsigned long stack, int flags) { - int pid, status; + int pid, status, err; pid = clone(user_thread_tramp, (void *) stack_sp(stack), flags | CLONE_FILES | SIGCHLD, NULL); @@ -35,7 +36,8 @@ return(pid); } - if(waitpid(pid, &status, WUNTRACED) < 0){ + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); + if(err < 0){ printk("user_thread - waitpid failed, errno = %d\n", errno); return(-errno); } diff -Nru a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h --- a/arch/um/kernel/skas/include/mode.h 2004-10-18 14:56:32 -07:00 +++ b/arch/um/kernel/skas/include/mode.h 2004-10-18 14:56:32 -07:00 @@ -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 -Nru a/arch/um/kernel/skas/include/ptrace-skas.h b/arch/um/kernel/skas/include/ptrace-skas.h --- a/arch/um/kernel/skas/include/ptrace-skas.h 2004-10-18 14:55:55 -07:00 +++ b/arch/um/kernel/skas/include/ptrace-skas.h 2004-10-18 14:55:55 -07:00 @@ -10,6 +10,16 @@ #ifdef UML_CONFIG_MODE_SKAS +/* syscall emulation path in ptrace */ + +#ifndef PTRACE_SYSEMU +#define PTRACE_SYSEMU 31 +#endif + +void set_using_sysemu(int value); +int get_using_sysemu(void); +extern int sysemu_supported; + #include "skas_ptregs.h" #define HOST_FRAME_SIZE 17 diff -Nru a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h --- a/arch/um/kernel/skas/include/skas.h 2004-10-18 14:56:27 -07:00 +++ b/arch/um/kernel/skas/include/skas.h 2004-10-18 14:56:27 -07:00 @@ -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 -Nru a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h --- a/arch/um/kernel/skas/include/uaccess.h 2004-10-18 14:56:29 -07:00 +++ b/arch/um/kernel/skas/include/uaccess.h 2004-10-18 14:56:29 -07:00 @@ -6,20 +6,12 @@ #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 +19,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 -Nru a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c --- a/arch/um/kernel/skas/mem_user.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/kernel/skas/mem_user.c 2004-10-18 14:56:28 -07:00 @@ -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 -Nru a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c --- a/arch/um/kernel/skas/mmu.c 2004-10-18 14:57:19 -07:00 +++ b/arch/um/kernel/skas/mmu.c 2004-10-18 14:57:19 -07:00 @@ -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 -Nru a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c --- a/arch/um/kernel/skas/process.c 2004-10-18 14:57:04 -07:00 +++ b/arch/um/kernel/skas/process.c 2004-10-18 14:57:04 -07:00 @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,19 @@ #include "os.h" #include "proc_mm.h" #include "skas_ptrace.h" +#include "chan_user.h" +#include "signal_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]; @@ -43,37 +57,39 @@ segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); } -static void handle_trap(int pid, union uml_pt_regs *regs) +/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ +static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu) { 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) - panic("handle_trap - nullifying syscall failed errno = %d\n", - errno); + if (!local_using_sysemu) + { + err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); + if(err < 0) + panic("handle_trap - nullifying syscall failed errno = %d\n", + errno); - err = ptrace(PTRACE_SYSCALL, pid, 0, 0); - if(err < 0) - panic("handle_trap - continuing to end of syscall failed, " - "errno = %d\n", errno); - - err = waitpid(pid, &status, WUNTRACED); - if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - panic("handle_trap - failed to wait at end of syscall, " - "errno = %d, status = %d\n", errno, status); + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); + if(err < 0) + panic("handle_trap - continuing to end of syscall failed, " + "errno = %d\n", errno); + + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); + if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("handle_trap - failed to wait at end of syscall, " + "errno = %d, status = %d\n", errno, status); + } handle_syscall(regs); } -int userspace_pid; - static int userspace_tramp(void *arg) { init_new_thread_signals(0); @@ -83,7 +99,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; @@ -101,7 +121,7 @@ panic("start_userspace : clone failed, errno = %d", errno); do { - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("start_userspace : wait failed, errno = %d", errno); @@ -114,21 +134,27 @@ 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]; + int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ restore_registers(regs); - err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0); + local_using_sysemu = get_using_sysemu(); + + if (local_using_sysemu) + err = ptrace(PTRACE_SYSEMU, pid, 0, 0); + else + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err) - panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", - errno); + panic("userspace - PTRACE_%s failed, errno = %d\n", + local_using_sysemu ? "SYSEMU" : "SYSCALL", errno); while(1){ - err = waitpid(userspace_pid, &status, WUNTRACED); + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); @@ -139,16 +165,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, local_using_sysemu); break; case SIGIO: case SIGVTALRM: case SIGILL: case SIGBUS: case SIGFPE: + case SIGWINCH: user_signal(WSTOPSIG(status), regs); break; default: @@ -160,45 +187,66 @@ restore_registers(regs); - op = singlestepping_skas() ? PTRACE_SINGLESTEP : - PTRACE_SYSCALL; - err = ptrace(op, userspace_pid, 0, 0); + /*Now we ended the syscall, so re-read local_using_sysemu.*/ + local_using_sysemu = get_using_sysemu(); + + if (local_using_sysemu) + op = singlestepping_skas() ? PTRACE_SINGLESTEP : + PTRACE_SYSEMU; + else + op = singlestepping_skas() ? PTRACE_SINGLESTEP : + PTRACE_SYSCALL; + + err = ptrace(op, pid, 0, 0); if(err) - panic("userspace - PTRACE_SYSCALL failed, " - "errno = %d\n", errno); + panic("userspace - PTRACE_%s failed, " + "errno = %d\n", + local_using_sysemu ? "SYSEMU" : "SYSCALL", errno); } } void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void (*handler)(int)) { - jmp_buf switch_buf, fork_buf; + unsigned long flags; + sigjmp_buf switch_buf, fork_buf; *switch_buf_ptr = &switch_buf; *fork_buf_ptr = &fork_buf; - if(setjmp(fork_buf) == 0) + /* Somewhat subtle - siglongjmp restores the signal mask before doing + * the longjmp. This means that when jumping from one stack to another + * when the target stack has interrupts enabled, an interrupt may occur + * on the source stack. This is bad when starting up a process because + * it's not supposed to get timer ticks until it has been scheduled. + * So, we disable interrupts around the sigsetjmp to ensure that + * they can't happen until we get back here where they are safe. + */ + flags = get_signals(); + block_signals(); + if(sigsetjmp(fork_buf, 1) == 0) new_thread_proc(stack, handler); + set_signals(flags); remove_sigstack(); } void thread_wait(void *sw, void *fb) { - jmp_buf buf, **switch_buf = sw, *fork_buf; + sigjmp_buf buf, **switch_buf = sw, *fork_buf; *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 +265,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,42 +286,43 @@ 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) { - jmp_buf my_buf, **me_ptr = me, *next_buf = next; + sigjmp_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; +static sigjmp_buf initial_jmpbuf; /* XXX Make these percpu */ static void (*cb_proc)(void *arg); static void *cb_arg; -static jmp_buf *cb_back; +static sigjmp_buf *cb_back; int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) { - jmp_buf **switch_buf = switch_buf_ptr; + sigjmp_buf **switch_buf = switch_buf_ptr; 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 +332,7 @@ kmalloc_ok = 0; return(1); } - longjmp(**switch_buf, 1); + siglongjmp(**switch_buf, 1); } void remove_sigstack(void) @@ -297,15 +347,15 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) { - jmp_buf here; + sigjmp_buf here; cb_proc = proc; cb_arg = arg; 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,40 +366,21 @@ void halt_skas(void) { block_signals(); - longjmp(initial_jmpbuf, 3); + siglongjmp(initial_jmpbuf, 3); } void reboot_skas(void) { block_signals(); - longjmp(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); - - if(fd < 0) - return(-errno); - - if(from != -1){ - copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, - .u = - { .copy_segments = from } } ); - n = os_write_file(fd, ©, sizeof(copy)); - if(n != sizeof(copy)) - printk("new_mm : /proc/mm copy_segments failed, " - "errno = %d\n", errno); - } - return(fd); + siglongjmp(initial_jmpbuf, 4); } void switch_mm_skas(int mm_fd) { 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 +388,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 -Nru a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c --- a/arch/um/kernel/skas/process_kern.c 2004-10-18 14:57:19 -07:00 +++ b/arch/um/kernel/skas/process_kern.c 2004-10-18 14:57:19 -07:00 @@ -6,6 +6,12 @@ #include "linux/sched.h" #include "linux/slab.h" #include "linux/ptrace.h" +#include "linux/proc_fs.h" +#include "linux/file.h" +#include "linux/errno.h" +#include "linux/init.h" +#include "asm/uaccess.h" +#include "asm/atomic.h" #include "kern_util.h" #include "time_user.h" #include "signal_user.h" @@ -16,6 +22,62 @@ #include "frame.h" #include "kern.h" #include "mode.h" +#include "proc_mm.h" + +static atomic_t using_sysemu; +int sysemu_supported; + +void set_using_sysemu(int value) +{ + atomic_set(&using_sysemu, sysemu_supported && value); +} + +int get_using_sysemu(void) +{ + return atomic_read(&using_sysemu); +} + +int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data) +{ + if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/ + *eof = 1; + + return strlen(buf); +} + +int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data) +{ + char tmp[2]; + + if (copy_from_user(tmp, buf, 1)) + return -EFAULT; + + if (tmp[0] == '0' || tmp[0] == '1') + set_using_sysemu(tmp[0] - '0'); + return count; /*We use the first char, but pretend to write everything*/ +} + +int __init make_proc_sysemu(void) +{ + struct proc_dir_entry *ent; + if (mode_tt || !sysemu_supported) + return 0; + + ent = create_proc_entry("sysemu", 0600, &proc_root); + + if (ent == NULL) + { + printk("Failed to register /proc/sysemu\n"); + return(0); + } + + ent->read_proc = proc_read_sysemu; + ent->write_proc = proc_write_sysemu; + + return 0; +} + +late_initcall(make_proc_sysemu); int singlestepping_skas(void) { @@ -61,11 +123,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,11 +157,11 @@ current->thread.mode.skas.fork_buf); force_flush_all(); -#ifdef CONFIG_SMP + if(current->thread.prev_sched == NULL) + panic("blech"); + schedule_tail(current->thread.prev_sched); -#endif current->thread.prev_sched = NULL; - unblock_signals(); userspace(¤t->thread.regs.regs); } @@ -128,15 +192,36 @@ handler = new_thread_handler; } - new_thread((void *) p->thread.kernel_stack, - &p->thread.mode.skas.switch_buf, + new_thread(p->thread_info, &p->thread.mode.skas.switch_buf, &p->thread.mode.skas.fork_buf, handler); return(0); } +int new_mm(int from) +{ + struct proc_mm_op copy; + int n, fd; + + fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); + if(fd < 0) + return(fd); + + if(from != -1){ + copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, + .u = + { .copy_segments = from } } ); + n = os_write_file(fd, ©, sizeof(copy)); + if(n != sizeof(copy)) + printk("new_mm : /proc/mm copy_segments failed, " + "err = %d\n", -n); + } + + return(fd); +} + 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,27 +245,29 @@ int start_uml_skas(void) { - start_userspace(); + start_userspace(0); capture_signal_stack(); init_new_thread_signals(1); - idle_timer(); + uml_idle_timer(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; - return(start_idle_thread((void *) init_task.thread.kernel_stack, + return(start_idle_thread(init_task.thread_info, &init_task.thread.mode.skas.switch_buf, &init_task.thread.mode.skas.fork_buf)); } 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 -Nru a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile --- a/arch/um/kernel/skas/sys-i386/Makefile 2004-10-18 14:57:03 -07:00 +++ b/arch/um/kernel/skas/sys-i386/Makefile 2004-10-18 14:57:03 -07:00 @@ -10,5 +10,3 @@ $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : diff -Nru a/arch/um/kernel/skas/sys-i386/sigcontext.c b/arch/um/kernel/skas/sys-i386/sigcontext.c --- a/arch/um/kernel/skas/sys-i386/sigcontext.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/kernel/skas/sys-i386/sigcontext.c 2004-10-18 14:55:54 -07:00 @@ -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 -Nru a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c --- a/arch/um/kernel/skas/syscall_kern.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/skas/syscall_kern.c 2004-10-18 14:56:33 -07:00 @@ -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 -Nru a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c --- a/arch/um/kernel/skas/syscall_user.c 2004-10-18 14:57:04 -07:00 +++ b/arch/um/kernel/skas/syscall_user.c 2004-10-18 14:57:04 -07:00 @@ -22,7 +22,7 @@ index = record_syscall_start(UPT_SYSCALL_NR(regs)); - syscall_trace(); + syscall_trace(regs, 1); result = execute_syscall(regs); REGS_SET_SYSCALL_RETURN(regs->skas.regs, result); @@ -30,7 +30,7 @@ (result == -ERESTARTNOINTR)) do_signal(result); - syscall_trace(); + syscall_trace(regs, 0); record_syscall_end(index, result); } diff -Nru a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c --- a/arch/um/kernel/skas/tlb.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/kernel/skas/tlb.c 2004-10-18 14:56:32 -07:00 @@ -77,7 +77,7 @@ int updated = 0, err; mm = &init_mm; - for(addr = start_vm; addr < end_vm;){ + for(addr = start; addr < end;){ pgd = pgd_offset(mm, addr); pmd = pmd_offset(pgd, addr); if(pmd_present(*pmd)){ diff -Nru a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c --- a/arch/um/kernel/skas/trap_user.c 2004-10-18 14:56:29 -07:00 +++ b/arch/um/kernel/skas/trap_user.c 2004-10-18 14:56:29 -07:00 @@ -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 */ @@ -19,8 +19,10 @@ struct skas_regs *r; struct signal_info *info; int save_errno = errno; + int save_user; r = &TASK_REGS(get_current())->skas; + save_user = r->is_user; r->is_user = 0; r->fault_addr = SC_FAULT_ADDR(sc); r->fault_type = SC_FAULT_TYPE(sc); @@ -33,16 +35,13 @@ (*info->handler)(sig, (union uml_pt_regs *) r); errno = save_errno; + r->is_user = save_user; } -extern int missed_ticks[]; - void user_signal(int sig, union uml_pt_regs *regs) { 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 -Nru a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/kernel/skas/uaccess.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/kernel.h" +#include "linux/string.h" +#include "linux/fs.h" +#include "linux/highmem.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/uaccess.h" +#include "kern_util.h" +#include "user_util.h" + +extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, + pte_t *pte_out); + +static unsigned long maybe_map(unsigned long virt, int is_write) +{ + pte_t pte; + int err; + + void *phys = um_virt_to_phys(current, virt, &pte); + int dummy_code; + + if(IS_ERR(phys) || (is_write && !pte_write(pte))){ + err = handle_page_fault(virt, 0, is_write, 1, &dummy_code); + if(err) + return(0); + phys = um_virt_to_phys(current, virt, NULL); + } + return((unsigned long) phys); +} + +static int do_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long addr, int len, void *arg), void *arg) +{ + struct page *page; + int n; + + addr = maybe_map(addr, is_write); + if(addr == -1) + return(-1); + + page = phys_to_page(addr); + addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); + n = (*op)(addr, len, arg); + kunmap(page); + + return(n); +} + +static void do_buffer_op(void *jmpbuf, void *arg_ptr) +{ + va_list args = *((va_list *) arg_ptr); + unsigned long addr = va_arg(args, unsigned long); + int len = va_arg(args, int); + int is_write = va_arg(args, int); + int (*op)(unsigned long, int, void *) = va_arg(args, void *); + void *arg = va_arg(args, void *); + int *res = va_arg(args, int *); + int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); + int remain = len, n; + + current->thread.fault_catcher = jmpbuf; + n = do_op(addr, size, is_write, op, arg); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } + + addr += size; + remain -= size; + if(remain == 0){ + *res = 0; + goto out; + } + + while(addr < ((addr + remain) & PAGE_MASK)){ + n = do_op(addr, PAGE_SIZE, is_write, op, arg); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } + + addr += PAGE_SIZE; + remain -= PAGE_SIZE; + } + if(remain == 0){ + *res = 0; + goto out; + } + + n = do_op(addr, remain, is_write, op, arg); + if(n != 0) + *res = (n < 0 ? remain : 0); + else *res = 0; + out: + current->thread.fault_catcher = NULL; +} + +static int buffer_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long addr, int len, void *arg), + void *arg) +{ + int faulted, res; + + faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, + &res); + if(!faulted) + return(res); + + return(addr + len - (unsigned long) current->thread.fault_addr); +} + +static int copy_chunk_from_user(unsigned long from, int len, void *arg) +{ + unsigned long *to_ptr = arg, to = *to_ptr; + + memcpy((void *) to, (void *) from, len); + *to_ptr += len; + return(0); +} + +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, 0, copy_chunk_from_user, &to): + n); +} + +static int copy_chunk_to_user(unsigned long to, int len, void *arg) +{ + unsigned long *from_ptr = arg, from = *from_ptr; + + memcpy((void *) to, (void *) from, len); + *from_ptr += len; + return(0); +} + +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, 1, copy_chunk_to_user, &from) : + n); +} + +static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) +{ + char **to_ptr = arg, *to = *to_ptr; + int n; + + strncpy(to, (void *) from, len); + n = strnlen(to, len); + *to_ptr += n; + + if(n < len) + return(1); + return(0); +} + +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, 0, strncpy_chunk_from_user, + &ptr); + if(n != 0) + return(-EFAULT); + return(strnlen(dst, count)); +} + +static int clear_chunk(unsigned long addr, int len, void *unused) +{ + memset((void *) addr, 0, len); + return(0); +} + +int __clear_user_skas(void *mem, int len) +{ + return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL)); +} + +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, 1, clear_chunk, NULL) : len); +} + +static int strnlen_chunk(unsigned long str, int len, void *arg) +{ + int *len_ptr = arg, n; + + n = strnlen((void *) str, len); + *len_ptr += n; + + if(n < len) + return(1); + return(0); +} + +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, 0, strnlen_chunk, &count); + if(n == 0) + return(count + 1); + return(-EFAULT); +} + +/* + * 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 -Nru a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile --- a/arch/um/kernel/skas/util/Makefile 2004-10-18 14:56:50 -07:00 +++ b/arch/um/kernel/skas/util/Makefile 2004-10-18 14:56:50 -07:00 @@ -1,10 +1,2 @@ -all: mk_ptregs - -mk_ptregs : mk_ptregs.o - $(CC) -o mk_ptregs mk_ptregs.o - -mk_ptregs.o : mk_ptregs.c - $(CC) -c $< - -clean : - $(RM) -f mk_ptregs *.o *~ +hostprogs-y := mk_ptregs +always := $(hostprogs-y) diff -Nru a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c --- a/arch/um/kernel/skas/util/mk_ptregs.c 2004-10-18 14:56:29 -07:00 +++ b/arch/um/kernel/skas/util/mk_ptregs.c 2004-10-18 14:56:29 -07:00 @@ -1,3 +1,4 @@ +#include #include #include diff -Nru a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c --- a/arch/um/kernel/smp.c 2004-10-18 14:56:19 -07:00 +++ b/arch/um/kernel/smp.c 2004-10-18 14:56:19 -07:00 @@ -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 @@ -12,10 +18,10 @@ #include "linux/threads.h" #include "linux/interrupt.h" #include "linux/err.h" +#include "linux/hardirq.h" #include "asm/smp.h" #include "asm/processor.h" #include "asm/spinlock.h" -#include "asm/hardirq.h" #include "user_util.h" #include "kern_util.h" #include "kern.h" @@ -23,9 +29,11 @@ #include "os.h" /* CPU online map, set by smp_boot_cpus */ -unsigned long cpu_online_map = cpumask_of_cpu(0); +cpumask_t cpu_online_map = CPU_MASK_NONE; +cpumask_t cpu_possible_map = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(cpu_possible_map); /* Per CPU bogomips and other parameters * The only piece used here is the ipi pipe, which is set before SMP is @@ -33,14 +41,6 @@ */ struct cpuinfo_um cpu_data[NR_CPUS]; -spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED; - -atomic_t global_bh_count; - -/* Not used by UML */ -unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile long global_irq_lock; - /* Set when the idlers are all forked */ int smp_threads_ready = 0; @@ -55,80 +55,44 @@ 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++; } -static void show(char * str) -{ - int cpu = smp_processor_id(); - - printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu); -} - -#define MAXCOUNT 100000000 - -static inline void wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if (!--count) { - show("wait_on_bh"); - count = ~0; - } - /* nothing .. wait for the other bh's to go away */ - } while (atomic_read(&global_bh_count) != 0); -} - -/* - * This is called when we want to synchronize with - * bottom half handlers. We need to wait until - * no other CPU is executing any bottom half handler. - * - * Don't wait if we're already running in an interrupt - * context or are inside a bh handler. - */ -void synchronize_bh(void) -{ - if (atomic_read(&global_bh_count) && !in_interrupt()) - wait_on_bh(); -} - void smp_send_stop(void) { int i; 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,14 +107,16 @@ 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 = fork_idle(cpu); + 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"); })); return(new_task); @@ -160,15 +126,21 @@ { struct task_struct *idle; unsigned long waittime; - int err, cpu; + int err, cpu, me = smp_processor_id(); + int i; - cpu_set(0, cpu_online_map); - cpu_set(0, smp_callin_map); + for (i = 0; i < ncpus; ++i) + cpu_set(i, cpu_possible_map); - err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); - if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); + cpu_clear(me, cpu_online_map); + cpu_set(me, cpu_online_map); + cpu_set(me, cpu_callin_map); + + 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 +152,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 +188,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); @@ -276,9 +248,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 -Nru a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c --- a/arch/um/kernel/sys_call_table.c 2004-10-18 14:56:50 -07:00 +++ b/arch/um/kernel/sys_call_table.c 2004-10-18 14:56:50 -07:00 @@ -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/syscalls.h" @@ -14,251 +13,49 @@ #include "sysdep/syscalls.h" #include "kern_util.h" -extern syscall_handler_t sys_restart_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_exit; +#ifdef CONFIG_NFSD +#define NFSSERVCTL sys_nfsservctl +#else +#define NFSSERVCTL sys_ni_syscall +#endif + +#define LAST_GENERIC_SYSCALL __NR_vserver + +#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL +#define LAST_SYSCALL LAST_GENERIC_SYSCALL +#else +#define LAST_SYSCALL LAST_ARCH_SYSCALL +#endif + extern syscall_handler_t sys_fork; -extern syscall_handler_t sys_creat; -extern syscall_handler_t sys_link; -extern syscall_handler_t sys_unlink; -extern syscall_handler_t sys_chdir; -extern syscall_handler_t sys_mknod; -extern syscall_handler_t sys_chmod; -extern syscall_handler_t sys_lchown16; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_stat; -extern syscall_handler_t sys_getpid; -extern syscall_handler_t sys_oldumount; -extern syscall_handler_t sys_setuid16; -extern syscall_handler_t sys_getuid16; +extern syscall_handler_t sys_execve; +extern syscall_handler_t um_time; +extern syscall_handler_t um_mount; +extern syscall_handler_t um_stime; extern syscall_handler_t sys_ptrace; -extern syscall_handler_t sys_alarm; -extern syscall_handler_t sys_fstat; -extern syscall_handler_t sys_pause; -extern syscall_handler_t sys_utime; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_access; -extern syscall_handler_t sys_nice; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_sync; -extern syscall_handler_t sys_kill; -extern syscall_handler_t sys_rename; -extern syscall_handler_t sys_mkdir; -extern syscall_handler_t sys_rmdir; extern syscall_handler_t sys_pipe; -extern syscall_handler_t sys_times; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_brk; -extern syscall_handler_t sys_setgid16; -extern syscall_handler_t sys_getgid16; -extern syscall_handler_t sys_signal; -extern syscall_handler_t sys_geteuid16; -extern syscall_handler_t sys_getegid16; -extern syscall_handler_t sys_acct; -extern syscall_handler_t sys_umount; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ioctl; -extern syscall_handler_t sys_fcntl; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_setpgid; -extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_olduname; -extern syscall_handler_t sys_umask; -extern syscall_handler_t sys_chroot; -extern syscall_handler_t sys_ustat; -extern syscall_handler_t sys_dup2; -extern syscall_handler_t sys_getppid; -extern syscall_handler_t sys_getpgrp; extern syscall_handler_t sys_sigaction; -extern syscall_handler_t sys_sgetmask; -extern syscall_handler_t sys_ssetmask; -extern syscall_handler_t sys_setreuid16; -extern syscall_handler_t sys_setregid16; extern syscall_handler_t sys_sigsuspend; -extern syscall_handler_t sys_sigpending; -extern syscall_handler_t sys_sethostname; -extern syscall_handler_t sys_setrlimit; -extern syscall_handler_t sys_old_getrlimit; -extern syscall_handler_t sys_getrusage; -extern syscall_handler_t sys_gettimeofday; -extern syscall_handler_t sys_settimeofday; -extern syscall_handler_t sys_getgroups16; -extern syscall_handler_t sys_setgroups16; -extern syscall_handler_t sys_symlink; -extern syscall_handler_t sys_lstat; -extern syscall_handler_t sys_readlink; -extern syscall_handler_t sys_swapon; -extern syscall_handler_t sys_uselib; -extern syscall_handler_t sys_reboot; extern syscall_handler_t old_readdir; -extern syscall_handler_t sys_munmap; -extern syscall_handler_t sys_truncate; -extern syscall_handler_t sys_ftruncate; -extern syscall_handler_t sys_fchmod; -extern syscall_handler_t sys_fchown16; -extern syscall_handler_t sys_getpriority; -extern syscall_handler_t sys_setpriority; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_statfs; -extern syscall_handler_t sys_fstatfs; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_socketcall; -extern syscall_handler_t sys_syslog; -extern syscall_handler_t sys_setitimer; -extern syscall_handler_t sys_getitimer; -extern syscall_handler_t sys_newstat; -extern syscall_handler_t sys_newlstat; -extern syscall_handler_t sys_newfstat; extern syscall_handler_t sys_uname; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_vhangup; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_swapoff; -extern syscall_handler_t sys_sysinfo; extern syscall_handler_t sys_ipc; -extern syscall_handler_t sys_fsync; extern syscall_handler_t sys_sigreturn; -extern syscall_handler_t sys_rt_sigreturn; extern syscall_handler_t sys_clone; -extern syscall_handler_t sys_setdomainname; -extern syscall_handler_t sys_newuname; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_adjtimex; -extern syscall_handler_t sys_mprotect; -extern syscall_handler_t sys_sigprocmask; -extern syscall_handler_t sys_init_module; -extern syscall_handler_t sys_delete_module; -extern syscall_handler_t sys_quotactl; -extern syscall_handler_t sys_getpgid; -extern syscall_handler_t sys_fchdir; -extern syscall_handler_t sys_bdflush; -extern syscall_handler_t sys_sysfs; -extern syscall_handler_t sys_personality; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_setfsuid16; -extern syscall_handler_t sys_setfsgid16; -extern syscall_handler_t sys_llseek; -extern syscall_handler_t sys_getdents; -extern syscall_handler_t sys_flock; -extern syscall_handler_t sys_msync; -extern syscall_handler_t sys_readv; -extern syscall_handler_t sys_writev; -extern syscall_handler_t sys_getsid; -extern syscall_handler_t sys_fdatasync; -extern syscall_handler_t sys_mlock; -extern syscall_handler_t sys_munlock; -extern syscall_handler_t sys_mlockall; -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; -extern syscall_handler_t sys_sched_rr_get_interval; -extern syscall_handler_t sys_nanosleep; -extern syscall_handler_t sys_mremap; -extern syscall_handler_t sys_setresuid16; -extern syscall_handler_t sys_getresuid16; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_poll; -extern syscall_handler_t sys_nfsservctl; -extern syscall_handler_t sys_setresgid16; -extern syscall_handler_t sys_getresgid16; -extern syscall_handler_t sys_prctl; -extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_rt_sigreturn; extern syscall_handler_t sys_rt_sigaction; -extern syscall_handler_t sys_rt_sigprocmask; -extern syscall_handler_t sys_rt_sigpending; -extern syscall_handler_t sys_rt_sigtimedwait; -extern syscall_handler_t sys_rt_sigqueueinfo; -extern syscall_handler_t sys_rt_sigsuspend; -extern syscall_handler_t sys_pread64; -extern syscall_handler_t sys_pwrite64; -extern syscall_handler_t sys_chown16; -extern syscall_handler_t sys_getcwd; -extern syscall_handler_t sys_capget; -extern syscall_handler_t sys_capset; extern syscall_handler_t sys_sigaltstack; -extern syscall_handler_t sys_sendfile; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_vfork; -extern syscall_handler_t sys_getrlimit; extern syscall_handler_t sys_mmap2; -extern syscall_handler_t sys_truncate64; -extern syscall_handler_t sys_ftruncate64; -extern syscall_handler_t sys_stat64; -extern syscall_handler_t sys_lstat64; -extern syscall_handler_t sys_fstat64; -extern syscall_handler_t sys_lchown; -extern syscall_handler_t sys_getuid; -extern syscall_handler_t sys_getgid; -extern syscall_handler_t sys_geteuid; -extern syscall_handler_t sys_getegid; -extern syscall_handler_t sys_setreuid; -extern syscall_handler_t sys_setregid; -extern syscall_handler_t sys_getgroups; -extern syscall_handler_t sys_setgroups; -extern syscall_handler_t sys_fchown; -extern syscall_handler_t sys_setresuid; -extern syscall_handler_t sys_getresuid; -extern syscall_handler_t sys_setresgid; -extern syscall_handler_t sys_getresgid; -extern syscall_handler_t sys_chown; -extern syscall_handler_t sys_setuid; -extern syscall_handler_t sys_setgid; -extern syscall_handler_t sys_setfsuid; -extern syscall_handler_t sys_setfsgid; -extern syscall_handler_t sys_pivot_root; -extern syscall_handler_t sys_mincore; -extern syscall_handler_t sys_madvise; -extern syscall_handler_t sys_fcntl64; -extern syscall_handler_t sys_getdents64; -extern syscall_handler_t sys_gettid; -extern syscall_handler_t sys_readahead; -extern syscall_handler_t sys_tkill; -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_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_exit_group; -extern syscall_handler_t sys_lookup_dcookie; -extern syscall_handler_t sys_epoll_create; -extern syscall_handler_t sys_epoll_ctl; -extern syscall_handler_t sys_epoll_wait; -extern syscall_handler_t sys_remap_file_pages; -extern syscall_handler_t sys_set_tid_address; - -#ifdef CONFIG_NFSD -#define NFSSERVCTL sys_nfsservctl -#else -#define NFSSERVCTL sys_ni_syscall -#endif - -extern syscall_handler_t um_mount; -extern syscall_handler_t um_time; -extern syscall_handler_t um_stime; - -#define LAST_GENERIC_SYSCALL __NR_set_tid_address - -#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL -#define LAST_SYSCALL LAST_GENERIC_SYSCALL -#else -#define LAST_SYSCALL LAST_ARCH_SYSCALL -#endif +extern syscall_handler_t old_mmap_i386; +extern syscall_handler_t old_select; +extern syscall_handler_t sys_modify_ldt; +extern syscall_handler_t sys_rt_sigsuspend; syscall_handler_t *sys_call_table[] = { - [ __NR_restart_syscall ] = sys_restart_syscall, - [ __NR_exit ] = sys_exit, - [ __NR_fork ] = sys_fork, + [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall, + [ __NR_exit ] (syscall_handler_t *) sys_exit, + [ __NR_fork ] (syscall_handler_t *) sys_fork, [ __NR_read ] = (syscall_handler_t *) sys_read, [ __NR_write ] = (syscall_handler_t *) sys_write, @@ -266,229 +63,249 @@ [ __NR_open ] = (syscall_handler_t *) sys_open, [ __NR_close ] = (syscall_handler_t *) sys_close, [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, - [ __NR_creat ] = sys_creat, - [ __NR_link ] = sys_link, - [ __NR_unlink ] = sys_unlink, + [ __NR_creat ] (syscall_handler_t *) sys_creat, + [ __NR_link ] (syscall_handler_t *) sys_link, + [ __NR_unlink ] (syscall_handler_t *) sys_unlink, [ __NR_execve ] = (syscall_handler_t *) sys_execve, /* declared differently in kern_util.h */ - [ __NR_chdir ] = sys_chdir, + [ __NR_chdir ] (syscall_handler_t *) sys_chdir, [ __NR_time ] = um_time, - [ __NR_mknod ] = sys_mknod, - [ __NR_chmod ] = sys_chmod, - [ __NR_lchown ] = sys_lchown16, - [ __NR_break ] = sys_ni_syscall, - [ __NR_oldstat ] = sys_stat, + [ __NR_mknod ] (syscall_handler_t *) sys_mknod, + [ __NR_chmod ] (syscall_handler_t *) sys_chmod, + [ __NR_lchown ] (syscall_handler_t *) sys_lchown16, + [ __NR_break ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_oldstat ] (syscall_handler_t *) sys_stat, [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, - [ __NR_getpid ] = sys_getpid, + [ __NR_getpid ] (syscall_handler_t *) sys_getpid, [ __NR_mount ] = um_mount, - [ __NR_umount ] = sys_oldumount, - [ __NR_setuid ] = sys_setuid16, - [ __NR_getuid ] = sys_getuid16, + [ __NR_umount ] (syscall_handler_t *) sys_oldumount, + [ __NR_setuid ] (syscall_handler_t *) sys_setuid16, + [ __NR_getuid ] (syscall_handler_t *) sys_getuid16, [ __NR_stime ] = um_stime, - [ __NR_ptrace ] = sys_ptrace, - [ __NR_alarm ] = sys_alarm, - [ __NR_oldfstat ] = sys_fstat, - [ __NR_pause ] = sys_pause, - [ __NR_utime ] = sys_utime, - [ __NR_stty ] = sys_ni_syscall, - [ __NR_gtty ] = sys_ni_syscall, - [ __NR_access ] = sys_access, - [ __NR_nice ] = sys_nice, - [ __NR_ftime ] = sys_ni_syscall, - [ __NR_sync ] = sys_sync, - [ __NR_kill ] = sys_kill, - [ __NR_rename ] = sys_rename, - [ __NR_mkdir ] = sys_mkdir, - [ __NR_rmdir ] = sys_rmdir, + [ __NR_ptrace ] (syscall_handler_t *) sys_ptrace, + [ __NR_alarm ] (syscall_handler_t *) sys_alarm, + [ __NR_oldfstat ] (syscall_handler_t *) sys_fstat, + [ __NR_pause ] (syscall_handler_t *) sys_pause, + [ __NR_utime ] (syscall_handler_t *) sys_utime, + [ __NR_stty ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_gtty ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_access ] (syscall_handler_t *) sys_access, + [ __NR_nice ] (syscall_handler_t *) sys_nice, + [ __NR_ftime ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_sync ] (syscall_handler_t *) sys_sync, + [ __NR_kill ] (syscall_handler_t *) sys_kill, + [ __NR_rename ] (syscall_handler_t *) sys_rename, + [ __NR_mkdir ] (syscall_handler_t *) sys_mkdir, + [ __NR_rmdir ] (syscall_handler_t *) sys_rmdir, /* Declared differently in asm/unistd.h */ [ __NR_dup ] = (syscall_handler_t *) sys_dup, - [ __NR_pipe ] = sys_pipe, - [ __NR_times ] = sys_times, - [ __NR_prof ] = sys_ni_syscall, - [ __NR_brk ] = sys_brk, - [ __NR_setgid ] = sys_setgid16, - [ __NR_getgid ] = sys_getgid16, - [ __NR_signal ] = sys_signal, - [ __NR_geteuid ] = sys_geteuid16, - [ __NR_getegid ] = sys_getegid16, - [ __NR_acct ] = sys_acct, - [ __NR_umount2 ] = sys_umount, - [ __NR_lock ] = sys_ni_syscall, - [ __NR_ioctl ] = sys_ioctl, - [ __NR_fcntl ] = sys_fcntl, - [ __NR_mpx ] = sys_ni_syscall, - [ __NR_setpgid ] = sys_setpgid, - [ __NR_ulimit ] = sys_ni_syscall, - [ __NR_oldolduname ] = sys_olduname, - [ __NR_umask ] = sys_umask, - [ __NR_chroot ] = sys_chroot, - [ __NR_ustat ] = sys_ustat, - [ __NR_dup2 ] = sys_dup2, - [ __NR_getppid ] = sys_getppid, - [ __NR_getpgrp ] = sys_getpgrp, + [ __NR_pipe ] (syscall_handler_t *) sys_pipe, + [ __NR_times ] (syscall_handler_t *) sys_times, + [ __NR_prof ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_brk ] (syscall_handler_t *) sys_brk, + [ __NR_setgid ] (syscall_handler_t *) sys_setgid16, + [ __NR_getgid ] (syscall_handler_t *) sys_getgid16, + [ __NR_signal ] (syscall_handler_t *) sys_signal, + [ __NR_geteuid ] (syscall_handler_t *) sys_geteuid16, + [ __NR_getegid ] (syscall_handler_t *) sys_getegid16, + [ __NR_acct ] (syscall_handler_t *) sys_acct, + [ __NR_umount2 ] (syscall_handler_t *) sys_umount, + [ __NR_lock ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_ioctl ] (syscall_handler_t *) sys_ioctl, + [ __NR_fcntl ] (syscall_handler_t *) sys_fcntl, + [ __NR_mpx ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_setpgid ] (syscall_handler_t *) sys_setpgid, + [ __NR_ulimit ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_oldolduname ] (syscall_handler_t *) sys_olduname, + [ __NR_umask ] (syscall_handler_t *) sys_umask, + [ __NR_chroot ] (syscall_handler_t *) sys_chroot, + [ __NR_ustat ] (syscall_handler_t *) sys_ustat, + [ __NR_dup2 ] (syscall_handler_t *) sys_dup2, + [ __NR_getppid ] (syscall_handler_t *) sys_getppid, + [ __NR_getpgrp ] (syscall_handler_t *) sys_getpgrp, [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, - [ __NR_sigaction ] = sys_sigaction, - [ __NR_sgetmask ] = sys_sgetmask, - [ __NR_ssetmask ] = sys_ssetmask, - [ __NR_setreuid ] = sys_setreuid16, - [ __NR_setregid ] = sys_setregid16, - [ __NR_sigsuspend ] = sys_sigsuspend, - [ __NR_sigpending ] = sys_sigpending, - [ __NR_sethostname ] = sys_sethostname, - [ __NR_setrlimit ] = sys_setrlimit, - [ __NR_getrlimit ] = sys_old_getrlimit, - [ __NR_getrusage ] = sys_getrusage, - [ __NR_gettimeofday ] = sys_gettimeofday, - [ __NR_settimeofday ] = sys_settimeofday, - [ __NR_getgroups ] = sys_getgroups16, - [ __NR_setgroups ] = sys_setgroups16, - [ __NR_symlink ] = sys_symlink, - [ __NR_oldlstat ] = sys_lstat, - [ __NR_readlink ] = sys_readlink, - [ __NR_uselib ] = sys_uselib, + [ __NR_sigaction ] (syscall_handler_t *) sys_sigaction, + [ __NR_sgetmask ] (syscall_handler_t *) sys_sgetmask, + [ __NR_ssetmask ] (syscall_handler_t *) sys_ssetmask, + [ __NR_setreuid ] (syscall_handler_t *) sys_setreuid16, + [ __NR_setregid ] (syscall_handler_t *) sys_setregid16, + [ __NR_sigsuspend ] (syscall_handler_t *) sys_sigsuspend, + [ __NR_sigpending ] (syscall_handler_t *) sys_sigpending, + [ __NR_sethostname ] (syscall_handler_t *) sys_sethostname, + [ __NR_setrlimit ] (syscall_handler_t *) sys_setrlimit, + [ __NR_getrlimit ] (syscall_handler_t *) sys_old_getrlimit, + [ __NR_getrusage ] (syscall_handler_t *) sys_getrusage, + [ __NR_gettimeofday ] (syscall_handler_t *) sys_gettimeofday, + [ __NR_settimeofday ] (syscall_handler_t *) sys_settimeofday, + [ __NR_getgroups ] (syscall_handler_t *) sys_getgroups16, + [ __NR_setgroups ] (syscall_handler_t *) sys_setgroups16, + [ __NR_symlink ] (syscall_handler_t *) sys_symlink, + [ __NR_oldlstat ] (syscall_handler_t *) sys_lstat, + [ __NR_readlink ] (syscall_handler_t *) sys_readlink, + [ __NR_uselib ] (syscall_handler_t *) sys_uselib, [ __NR_swapon ] = (syscall_handler_t *) sys_swapon, - [ __NR_reboot ] = sys_reboot, + [ __NR_reboot ] (syscall_handler_t *) sys_reboot, [ __NR_readdir ] = old_readdir, - [ __NR_munmap ] = sys_munmap, - [ __NR_truncate ] = sys_truncate, - [ __NR_ftruncate ] = sys_ftruncate, - [ __NR_fchmod ] = sys_fchmod, - [ __NR_fchown ] = sys_fchown16, - [ __NR_getpriority ] = sys_getpriority, - [ __NR_setpriority ] = sys_setpriority, - [ __NR_profil ] = sys_ni_syscall, - [ __NR_statfs ] = sys_statfs, - [ __NR_fstatfs ] = sys_fstatfs, - [ __NR_ioperm ] = sys_ni_syscall, - [ __NR_socketcall ] = sys_socketcall, - [ __NR_syslog ] = sys_syslog, - [ __NR_setitimer ] = sys_setitimer, - [ __NR_getitimer ] = sys_getitimer, - [ __NR_stat ] = sys_newstat, - [ __NR_lstat ] = sys_newlstat, - [ __NR_fstat ] = sys_newfstat, - [ __NR_olduname ] = sys_uname, - [ __NR_iopl ] = sys_ni_syscall, - [ __NR_vhangup ] = sys_vhangup, - [ __NR_idle ] = sys_ni_syscall, + [ __NR_munmap ] (syscall_handler_t *) sys_munmap, + [ __NR_truncate ] (syscall_handler_t *) sys_truncate, + [ __NR_ftruncate ] (syscall_handler_t *) sys_ftruncate, + [ __NR_fchmod ] (syscall_handler_t *) sys_fchmod, + [ __NR_fchown ] (syscall_handler_t *) sys_fchown16, + [ __NR_getpriority ] (syscall_handler_t *) sys_getpriority, + [ __NR_setpriority ] (syscall_handler_t *) sys_setpriority, + [ __NR_profil ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_statfs ] (syscall_handler_t *) sys_statfs, + [ __NR_fstatfs ] (syscall_handler_t *) sys_fstatfs, + [ __NR_ioperm ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_socketcall ] (syscall_handler_t *) sys_socketcall, + [ __NR_syslog ] (syscall_handler_t *) sys_syslog, + [ __NR_setitimer ] (syscall_handler_t *) sys_setitimer, + [ __NR_getitimer ] (syscall_handler_t *) sys_getitimer, + [ __NR_stat ] (syscall_handler_t *) sys_newstat, + [ __NR_lstat ] (syscall_handler_t *) sys_newlstat, + [ __NR_fstat ] (syscall_handler_t *) sys_newfstat, + [ __NR_olduname ] (syscall_handler_t *) sys_uname, + [ __NR_iopl ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_vhangup ] (syscall_handler_t *) sys_vhangup, + [ __NR_idle ] (syscall_handler_t *) sys_ni_syscall, [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, [ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff, - [ __NR_sysinfo ] = sys_sysinfo, - [ __NR_ipc ] = sys_ipc, - [ __NR_fsync ] = sys_fsync, - [ __NR_sigreturn ] = sys_sigreturn, - [ __NR_clone ] = sys_clone, - [ __NR_setdomainname ] = sys_setdomainname, - [ __NR_uname ] = sys_newuname, - [ __NR_adjtimex ] = sys_adjtimex, - [ __NR_mprotect ] = sys_mprotect, - [ __NR_sigprocmask ] = sys_sigprocmask, - [ __NR_create_module ] = sys_ni_syscall, - [ __NR_init_module ] = sys_init_module, - [ __NR_delete_module ] = sys_delete_module, - [ __NR_get_kernel_syms ] = sys_ni_syscall, - [ __NR_quotactl ] = sys_quotactl, - [ __NR_getpgid ] = sys_getpgid, - [ __NR_fchdir ] = sys_fchdir, - [ __NR_bdflush ] = sys_bdflush, - [ __NR_sysfs ] = sys_sysfs, - [ __NR_personality ] = sys_personality, - [ __NR_afs_syscall ] = sys_ni_syscall, - [ __NR_setfsuid ] = sys_setfsuid16, - [ __NR_setfsgid ] = sys_setfsgid16, - [ __NR__llseek ] = sys_llseek, - [ __NR_getdents ] = sys_getdents, + [ __NR_sysinfo ] (syscall_handler_t *) sys_sysinfo, + [ __NR_ipc ] (syscall_handler_t *) sys_ipc, + [ __NR_fsync ] (syscall_handler_t *) sys_fsync, + [ __NR_sigreturn ] (syscall_handler_t *) sys_sigreturn, + [ __NR_clone ] (syscall_handler_t *) sys_clone, + [ __NR_setdomainname ] (syscall_handler_t *) sys_setdomainname, + [ __NR_uname ] (syscall_handler_t *) sys_newuname, + [ __NR_adjtimex ] (syscall_handler_t *) sys_adjtimex, + [ __NR_mprotect ] (syscall_handler_t *) sys_mprotect, + [ __NR_sigprocmask ] (syscall_handler_t *) sys_sigprocmask, + [ __NR_create_module ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_init_module ] (syscall_handler_t *) sys_init_module, + [ __NR_delete_module ] (syscall_handler_t *) sys_delete_module, + [ __NR_get_kernel_syms ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_quotactl ] (syscall_handler_t *) sys_quotactl, + [ __NR_getpgid ] (syscall_handler_t *) sys_getpgid, + [ __NR_fchdir ] (syscall_handler_t *) sys_fchdir, + [ __NR_bdflush ] (syscall_handler_t *) sys_bdflush, + [ __NR_sysfs ] (syscall_handler_t *) sys_sysfs, + [ __NR_personality ] (syscall_handler_t *) sys_personality, + [ __NR_afs_syscall ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_setfsuid ] (syscall_handler_t *) sys_setfsuid16, + [ __NR_setfsgid ] (syscall_handler_t *) sys_setfsgid16, + [ __NR__llseek ] (syscall_handler_t *) sys_llseek, + [ __NR_getdents ] (syscall_handler_t *) sys_getdents, [ __NR__newselect ] = (syscall_handler_t *) sys_select, - [ __NR_flock ] = sys_flock, - [ __NR_msync ] = sys_msync, - [ __NR_readv ] = sys_readv, - [ __NR_writev ] = sys_writev, - [ __NR_getsid ] = sys_getsid, - [ __NR_fdatasync ] = sys_fdatasync, + [ __NR_flock ] (syscall_handler_t *) sys_flock, + [ __NR_msync ] (syscall_handler_t *) sys_msync, + [ __NR_readv ] (syscall_handler_t *) sys_readv, + [ __NR_writev ] (syscall_handler_t *) sys_writev, + [ __NR_getsid ] (syscall_handler_t *) sys_getsid, + [ __NR_fdatasync ] (syscall_handler_t *) sys_fdatasync, [ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl, - [ __NR_mlock ] = sys_mlock, - [ __NR_munlock ] = sys_munlock, - [ __NR_mlockall ] = sys_mlockall, - [ __NR_munlockall ] = sys_munlockall, - [ __NR_sched_setparam ] = sys_sched_setparam, - [ __NR_sched_getparam ] = sys_sched_getparam, - [ __NR_sched_setscheduler ] = sys_sched_setscheduler, - [ __NR_sched_getscheduler ] = sys_sched_getscheduler, + [ __NR_mlock ] (syscall_handler_t *) sys_mlock, + [ __NR_munlock ] (syscall_handler_t *) sys_munlock, + [ __NR_mlockall ] (syscall_handler_t *) sys_mlockall, + [ __NR_munlockall ] (syscall_handler_t *) sys_munlockall, + [ __NR_sched_setparam ] (syscall_handler_t *) sys_sched_setparam, + [ __NR_sched_getparam ] (syscall_handler_t *) sys_sched_getparam, + [ __NR_sched_setscheduler ] (syscall_handler_t *) sys_sched_setscheduler, + [ __NR_sched_getscheduler ] (syscall_handler_t *) sys_sched_getscheduler, [ __NR_sched_yield ] = (syscall_handler_t *) yield, - [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max, - [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min, - [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval, - [ __NR_nanosleep ] = sys_nanosleep, - [ __NR_mremap ] = sys_mremap, - [ __NR_setresuid ] = sys_setresuid16, - [ __NR_getresuid ] = sys_getresuid16, - [ __NR_vm86 ] = sys_ni_syscall, - [ __NR_query_module ] = sys_ni_syscall, - [ __NR_poll ] = sys_poll, - [ __NR_nfsservctl ] = NFSSERVCTL, - [ __NR_setresgid ] = sys_setresgid16, - [ __NR_getresgid ] = sys_getresgid16, - [ __NR_prctl ] = sys_prctl, - [ __NR_rt_sigreturn ] = sys_rt_sigreturn, - [ __NR_rt_sigaction ] = sys_rt_sigaction, - [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask, - [ __NR_rt_sigpending ] = sys_rt_sigpending, - [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait, - [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo, - [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend, - [ __NR_pread64 ] = sys_pread64, - [ __NR_pwrite64 ] = sys_pwrite64, - [ __NR_chown ] = sys_chown16, - [ __NR_getcwd ] = sys_getcwd, - [ __NR_capget ] = sys_capget, - [ __NR_capset ] = sys_capset, - [ __NR_sigaltstack ] = sys_sigaltstack, - [ __NR_sendfile ] = sys_sendfile, - [ __NR_getpmsg ] = sys_ni_syscall, - [ __NR_putpmsg ] = sys_ni_syscall, - [ __NR_vfork ] = sys_vfork, - [ __NR_ugetrlimit ] = sys_getrlimit, - [ __NR_mmap2 ] = sys_mmap2, - [ __NR_truncate64 ] = sys_truncate64, - [ __NR_ftruncate64 ] = sys_ftruncate64, - [ __NR_stat64 ] = sys_stat64, - [ __NR_lstat64 ] = sys_lstat64, - [ __NR_fstat64 ] = sys_fstat64, - [ __NR_fcntl64 ] = sys_fcntl64, - [ __NR_getdents64 ] = sys_getdents64, - [ __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_tkill ] = sys_tkill, - [ __NR_sendfile64 ] = sys_sendfile64, - [ __NR_futex ] = sys_futex, - [ __NR_sched_setaffinity ] = sys_sched_setaffinity, - [ __NR_sched_getaffinity ] = sys_sched_getaffinity, - [ __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_exit_group ] = sys_exit_group, - [ __NR_lookup_dcookie ] = sys_lookup_dcookie, - [ __NR_epoll_create ] = sys_epoll_create, - [ __NR_epoll_ctl ] = sys_epoll_ctl, - [ __NR_epoll_wait ] = sys_epoll_wait, - [ __NR_remap_file_pages ] = sys_remap_file_pages, - [ __NR_set_tid_address ] = sys_set_tid_address, + [ __NR_sched_get_priority_max ] (syscall_handler_t *) sys_sched_get_priority_max, + [ __NR_sched_get_priority_min ] (syscall_handler_t *) sys_sched_get_priority_min, + [ __NR_sched_rr_get_interval ] (syscall_handler_t *) sys_sched_rr_get_interval, + [ __NR_nanosleep ] (syscall_handler_t *) sys_nanosleep, + [ __NR_mremap ] (syscall_handler_t *) sys_mremap, + [ __NR_setresuid ] (syscall_handler_t *) sys_setresuid16, + [ __NR_getresuid ] (syscall_handler_t *) sys_getresuid16, + [ __NR_vm86 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_query_module ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_poll ] (syscall_handler_t *) sys_poll, + [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL, + [ __NR_setresgid ] (syscall_handler_t *) sys_setresgid16, + [ __NR_getresgid ] (syscall_handler_t *) sys_getresgid16, + [ __NR_prctl ] (syscall_handler_t *) sys_prctl, + [ __NR_rt_sigreturn ] (syscall_handler_t *) sys_rt_sigreturn, + [ __NR_rt_sigaction ] (syscall_handler_t *) sys_rt_sigaction, + [ __NR_rt_sigprocmask ] (syscall_handler_t *) sys_rt_sigprocmask, + [ __NR_rt_sigpending ] (syscall_handler_t *) sys_rt_sigpending, + [ __NR_rt_sigtimedwait ] (syscall_handler_t *) sys_rt_sigtimedwait, + [ __NR_rt_sigqueueinfo ] (syscall_handler_t *) sys_rt_sigqueueinfo, + [ __NR_rt_sigsuspend ] (syscall_handler_t *) sys_rt_sigsuspend, + [ __NR_pread64 ] (syscall_handler_t *) sys_pread64, + [ __NR_pwrite64 ] (syscall_handler_t *) sys_pwrite64, + [ __NR_chown ] (syscall_handler_t *) sys_chown16, + [ __NR_getcwd ] (syscall_handler_t *) sys_getcwd, + [ __NR_capget ] (syscall_handler_t *) sys_capget, + [ __NR_capset ] (syscall_handler_t *) sys_capset, + [ __NR_sigaltstack ] (syscall_handler_t *) sys_sigaltstack, + [ __NR_sendfile ] (syscall_handler_t *) sys_sendfile, + [ __NR_getpmsg ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_putpmsg ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_vfork ] (syscall_handler_t *) sys_vfork, + [ __NR_ugetrlimit ] (syscall_handler_t *) sys_getrlimit, + [ __NR_mmap2 ] (syscall_handler_t *) sys_mmap2, + [ __NR_truncate64 ] (syscall_handler_t *) sys_truncate64, + [ __NR_ftruncate64 ] (syscall_handler_t *) sys_ftruncate64, + [ __NR_stat64 ] (syscall_handler_t *) sys_stat64, + [ __NR_lstat64 ] (syscall_handler_t *) sys_lstat64, + [ __NR_fstat64 ] (syscall_handler_t *) sys_fstat64, + [ __NR_getdents64 ] (syscall_handler_t *) sys_getdents64, + [ __NR_fcntl64 ] (syscall_handler_t *) sys_fcntl64, + [ 223 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_gettid ] (syscall_handler_t *) sys_gettid, + [ __NR_readahead ] (syscall_handler_t *) sys_readahead, + [ __NR_setxattr ] (syscall_handler_t *) sys_setxattr, + [ __NR_lsetxattr ] (syscall_handler_t *) sys_lsetxattr, + [ __NR_fsetxattr ] (syscall_handler_t *) sys_fsetxattr, + [ __NR_getxattr ] (syscall_handler_t *) sys_getxattr, + [ __NR_lgetxattr ] (syscall_handler_t *) sys_lgetxattr, + [ __NR_fgetxattr ] (syscall_handler_t *) sys_fgetxattr, + [ __NR_listxattr ] (syscall_handler_t *) sys_listxattr, + [ __NR_llistxattr ] (syscall_handler_t *) sys_llistxattr, + [ __NR_flistxattr ] (syscall_handler_t *) sys_flistxattr, + [ __NR_removexattr ] (syscall_handler_t *) sys_removexattr, + [ __NR_lremovexattr ] (syscall_handler_t *) sys_lremovexattr, + [ __NR_fremovexattr ] (syscall_handler_t *) sys_fremovexattr, + [ __NR_tkill ] (syscall_handler_t *) sys_tkill, + [ __NR_sendfile64 ] (syscall_handler_t *) sys_sendfile64, + [ __NR_futex ] (syscall_handler_t *) sys_futex, + [ __NR_sched_setaffinity ] (syscall_handler_t *) sys_sched_setaffinity, + [ __NR_sched_getaffinity ] (syscall_handler_t *) sys_sched_getaffinity, + [ __NR_set_thread_area ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_get_thread_area ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_io_setup ] (syscall_handler_t *) sys_io_setup, + [ __NR_io_destroy ] (syscall_handler_t *) sys_io_destroy, + [ __NR_io_getevents ] (syscall_handler_t *) sys_io_getevents, + [ __NR_io_submit ] (syscall_handler_t *) sys_io_submit, + [ __NR_io_cancel ] (syscall_handler_t *) sys_io_cancel, + [ __NR_fadvise64 ] (syscall_handler_t *) sys_fadvise64, + [ 251 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_exit_group ] (syscall_handler_t *) sys_exit_group, + [ __NR_lookup_dcookie ] (syscall_handler_t *) sys_lookup_dcookie, + [ __NR_epoll_create ] (syscall_handler_t *) sys_epoll_create, + [ __NR_epoll_ctl ] (syscall_handler_t *) sys_epoll_ctl, + [ __NR_epoll_wait ] (syscall_handler_t *) sys_epoll_wait, + [ __NR_remap_file_pages ] (syscall_handler_t *) sys_remap_file_pages, + [ __NR_set_tid_address ] (syscall_handler_t *) sys_set_tid_address, + [ __NR_timer_create ] (syscall_handler_t *) sys_timer_create, + [ __NR_timer_settime ] (syscall_handler_t *) sys_timer_settime, + [ __NR_timer_gettime ] (syscall_handler_t *) sys_timer_gettime, + [ __NR_timer_getoverrun ] (syscall_handler_t *) sys_timer_getoverrun, + [ __NR_timer_delete ] (syscall_handler_t *) sys_timer_delete, + [ __NR_clock_settime ] (syscall_handler_t *) sys_clock_settime, + [ __NR_clock_gettime ] (syscall_handler_t *) sys_clock_gettime, + [ __NR_clock_getres ] (syscall_handler_t *) sys_clock_getres, + [ __NR_clock_nanosleep ] (syscall_handler_t *) sys_clock_nanosleep, + [ __NR_statfs64 ] (syscall_handler_t *) sys_statfs64, + [ __NR_fstatfs64 ] (syscall_handler_t *) sys_fstatfs64, + [ __NR_tgkill ] (syscall_handler_t *) sys_tgkill, + [ __NR_utimes ] (syscall_handler_t *) sys_utimes, + [ __NR_fadvise64_64 ] (syscall_handler_t *) sys_fadvise64_64, + [ __NR_vserver ] (syscall_handler_t *) sys_ni_syscall, ARCH_SYSCALLS [ LAST_SYSCALL + 1 ... NR_syscalls ] = diff -Nru a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c --- a/arch/um/kernel/syscall_kern.c 2004-10-18 14:56:48 -07:00 +++ b/arch/um/kernel/syscall_kern.c 2004-10-18 14:56:48 -07:00 @@ -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 */ @@ -36,32 +36,23 @@ 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); -} - -long sys_clone(unsigned long clone_flags, unsigned long newsp) -{ - struct task_struct *p; - - current->thread.forking = 1; - p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL); - 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 */ @@ -136,43 +127,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.. * @@ -254,7 +214,7 @@ return sys_shmctl (first, second, (struct shmid_ds *) ptr); default: - return -EINVAL; + return -ENOSYS; } } @@ -301,11 +261,6 @@ error = error ? -EFAULT : 0; 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) diff -Nru a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c --- a/arch/um/kernel/sysrq.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/kernel/sysrq.c 2004-10-18 14:56:28 -07:00 @@ -44,6 +44,11 @@ } EXPORT_SYMBOL(dump_stack); +void show_stack(struct task_struct *task, unsigned long *sp) +{ + 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 -Nru a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c --- a/arch/um/kernel/tempfile.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/kernel/tempfile.c 2004-10-18 14:56:32 -07:00 @@ -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 -Nru a/arch/um/kernel/time.c b/arch/um/kernel/time.c --- a/arch/um/kernel/time.c 2004-10-18 14:56:17 -07:00 +++ b/arch/um/kernel/time.c 2004-10-18 14:56:17 -07:00 @@ -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) @@ -44,6 +53,15 @@ errno); } +void disable_timer(void) +{ + struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); + if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || + (setitimer(ITIMER_REAL, &disable, NULL) < 0)) + printk("disnable_timer - setitimer failed, errno = %d\n", + errno); +} + void switch_timers(int to_real) { struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); @@ -66,7 +84,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 +94,23 @@ set_interval(ITIMER_REAL); } +extern int do_posix_clock_monotonic_gettime(struct timespec *tp); + void time_init(void) { + struct timespec now; + if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) panic("Couldn't set SIGVTALRM handler"); set_interval(ITIMER_VIRTUAL); + + do_posix_clock_monotonic_gettime(&now); + wall_to_monotonic.tv_sec = -now.tv_sec; + wall_to_monotonic.tv_nsec = -now.tv_nsec; } -struct timeval local_offset = { 0, 0 }; +/* Declared in linux/time.h, which can't be included here */ +extern void clock_was_set(void); void do_gettimeofday(struct timeval *tv) { @@ -96,15 +123,13 @@ clock_was_set(); } -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; @@ -114,9 +139,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 -Nru a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c --- a/arch/um/kernel/time_kern.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/time_kern.c 2004-10-18 14:56:33 -07:00 @@ -20,6 +20,7 @@ #include "user_util.h" #include "time_user.h" #include "mode.h" +#include "os.h" u64 jiffies_64; @@ -30,22 +31,63 @@ 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; -/* missed_ticks will be modified after kernel memory has been - * write-protected, so this puts it in a section which will be left - * write-enabled. - */ -int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS]; +static int first_tick; +static unsigned long long prev_usecs; +#ifdef CONFIG_UML_REAL_TIME_CLOCK +static long long delta; /* Deviation per interval */ +#endif + +#define MILLION 1000000 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(!timer_irq_inited) return; - missed_ticks[cpu] = 0; - while(ticks--) do_IRQ(TIMER_IRQ, regs); + if(first_tick){ +#ifdef CONFIG_UML_REAL_TIME_CLOCK + /* We've had 1 tick */ + unsigned long long usecs = os_usecs(); + + delta += usecs - prev_usecs; + prev_usecs = usecs; + + /* Protect against the host clock being set backwards */ + if(delta < 0) + delta = 0; + + ticks += (delta * HZ) / MILLION; + delta -= (ticks * MILLION) / HZ; +#else + ticks = 1; +#endif + } + else { + prev_usecs = os_usecs(); + first_tick = 1; + } + + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } } void boot_timer_handler(int sig) @@ -58,12 +100,15 @@ 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) { + unsigned long flags; + do_timer(regs); - write_seqlock(&xtime_lock); + write_seqlock_irqsave(&xtime_lock, flags); timer(); - write_sequnlock(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock, flags); + return(IRQ_HANDLED); } long um_time(int * tloc) @@ -81,12 +126,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; } @@ -110,7 +155,7 @@ { int i, n; - n = (loops_per_jiffy * HZ * usecs) / 1000000; + n = (loops_per_jiffy * HZ * usecs) / MILLION; for(i=0;ithread_info->cpu == 0) + if(current_thread->cpu == 0) timer_irq(regs); } @@ -136,6 +183,7 @@ unsigned long time_lock(void) { unsigned long flags; + spin_lock_irqsave(&timer_spinlock, flags); return(flags); } @@ -150,8 +198,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; @@ -159,7 +207,6 @@ } __initcall(timer_init); - /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -Nru a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c --- a/arch/um/kernel/trap_kern.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/kernel/trap_kern.c 2004-10-18 14:55:54 -07:00 @@ -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,10 @@ if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; page = address & PAGE_MASK; - if(page == (unsigned long) current->thread_info + 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++; @@ -75,10 +76,10 @@ } 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); @@ -94,10 +95,36 @@ down_read(&mm->mmap_sem); goto survive; } - err = -ENOMEM; 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 +136,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 +149,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 +183,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; @@ -178,6 +204,11 @@ if(current->thread.fault_catcher != NULL) do_longjmp(current->thread.fault_catcher, 1); else relay_signal(sig, regs); +} + +void winch(int sig, union uml_pt_regs *regs) +{ + do_IRQ(WINCH_IRQ, regs); } void trap_init(void) diff -Nru a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c --- a/arch/um/kernel/trap_user.c 2004-10-18 14:56:29 -07:00 +++ b/arch/um/kernel/trap_user.c 2004-10-18 14:56:29 -07:00 @@ -5,11 +5,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -34,7 +32,14 @@ { kill(pid, SIGKILL); kill(pid, SIGCONT); - while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT); + do { + int n; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + if (n > 0) + kill(pid, SIGCONT); + else + break; + } while(1); } /* Unlocked - don't care if this is a bit off */ @@ -82,6 +87,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, @@ -102,12 +109,11 @@ sig, &sc); } -extern int timer_irq_inited, missed_ticks[]; +extern int timer_irq_inited; void alarm_handler(int sig, struct sigcontext sc) { if(!timer_irq_inited) return; - missed_ticks[cpu()]++; if(sig == SIGALRM) switch_timers(0); @@ -121,9 +127,9 @@ void do_longjmp(void *b, int val) { - jmp_buf *buf = b; + sigjmp_buf *buf = b; - longjmp(*buf, val); + siglongjmp(*buf, val); } /* diff -Nru a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile --- a/arch/um/kernel/tt/Makefile 2004-10-18 14:56:32 -07:00 +++ b/arch/um/kernel/tt/Makefile 2004-10-18 14:56:32 -07:00 @@ -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/ @@ -27,5 +27,3 @@ $(obj)/unmap_fin.o : $(src)/unmap.o ld -r -o $@ $< -lc -L/usr/lib - -clean : diff -Nru a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c --- a/arch/um/kernel/tt/exec_kern.c 2004-10-18 14:56:17 -07:00 +++ b/arch/um/kernel/tt/exec_kern.c 2004-10-18 14:56:17 -07:00 @@ -14,9 +14,11 @@ #include "kern_util.h" #include "irq_user.h" #include "time_user.h" +#include "signal_user.h" #include "mem_user.h" #include "os.h" #include "tlb.h" +#include "mode.h" static int exec_tramp(void *sig_stack) { @@ -38,8 +40,7 @@ do_exit(SIGKILL); } - new_pid = start_fork_tramp((void *) current->thread.kernel_stack, - stack, 0, exec_tramp); + new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp); if(new_pid < 0){ printk(KERN_ERR "flush_thread : new thread failed, errno = %d\n", @@ -47,17 +48,19 @@ 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()); + change_sig(SIGUSR1, 1); + change_sig(SIGUSR1, 0); 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 -Nru a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c --- a/arch/um/kernel/tt/exec_user.c 2004-10-18 14:56:49 -07:00 +++ b/arch/um/kernel/tt/exec_user.c 2004-10-18 14:56:49 -07:00 @@ -19,11 +19,16 @@ void do_exec(int old_pid, int new_pid) { unsigned long regs[FRAME_SIZE]; + int err; if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) || - (waitpid(new_pid, 0, WUNTRACED) < 0)) + (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) tracer_panic("do_exec failed to attach proc - errno = %d", + errno); + + CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); + if (err < 0) + tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", errno); if(ptrace_getregs(old_pid, regs) < 0) diff -Nru a/arch/um/kernel/tt/include/mode.h b/arch/um/kernel/tt/include/mode.h --- a/arch/um/kernel/tt/include/mode.h 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/tt/include/mode.h 2004-10-18 14:56:33 -07:00 @@ -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 -Nru a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h --- a/arch/um/kernel/tt/include/uaccess.h 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/tt/include/uaccess.h 2004-10-18 14:56:33 -07:00 @@ -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 -Nru a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c --- a/arch/um/kernel/tt/mem.c 2004-10-18 14:56:29 -07:00 +++ b/arch/um/kernel/tt/mem.c 2004-10-18 14:56:29 -07:00 @@ -18,7 +18,7 @@ if(!jail || debug) remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1); remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1); - remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(brk_start), 1); + remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1); } #ifdef CONFIG_HOST_2G_2G diff -Nru a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c --- a/arch/um/kernel/tt/mem_user.c 2004-10-18 14:56:27 -07:00 +++ b/arch/um/kernel/tt/mem_user.c 2004-10-18 14:56:27 -07:00 @@ -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 -Nru a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c --- a/arch/um/kernel/tt/process_kern.c 2004-10-18 14:56:49 -07:00 +++ b/arch/um/kernel/tt/process_kern.c 2004-10-18 14:56:49 -07:00 @@ -28,7 +28,7 @@ void *switch_to_tt(void *prev, void *next, void *last) { - struct task_struct *from, *to; + struct task_struct *from, *to, *prev_sched; unsigned long flags; int err, vtalrm, alrm, prof, cpu; char c; @@ -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)) @@ -72,6 +72,18 @@ if(err != sizeof(c)) panic("read of switch_pipe failed, errno = %d", -err); + /* If the process that we have just scheduled away from has exited, + * then it needs to be killed here. The reason is that, even though + * it will kill itself when it next runs, that may be too late. Its + * stack will be freed, possibly before then, and if that happens, + * we have a use-after-free situation. So, it gets killed here + * in case it has not already killed itself. + */ + prev_sched = current->thread.prev_sched; + if((prev_sched->state == TASK_ZOMBIE) || + (prev_sched->state == TASK_DEAD)) + os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); + /* This works around a nasty race with 'jail'. If we are switching * between two threads of a threaded app and the incoming process * runs before the outgoing process reaches the read, and it makes @@ -104,50 +116,92 @@ 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 suspend_new_thread(int fd) +{ + int err; + char c; + + os_stop_process(os_getpid()); + err = os_read_file(fd, &c, sizeof(c)); + if(err != sizeof(c)) + panic("read failed in suspend_new_thread, err = %d", -err); } 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); + + /* XXX No set_user_mode here because a newly execed process will + * immediately segfault on its non-existent IP, coming straight back + * to the signal handler, which will call set_user_mode on its way + * out. This should probably change since it's confusing. + */ } 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()); + change_sig(SIGUSR1, 1); return(0); } @@ -156,7 +210,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 +219,33 @@ 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()); + change_sig(SIGUSR1, 1); return(0); } @@ -213,8 +265,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); } @@ -227,8 +279,7 @@ clone_flags &= CLONE_VM; p->thread.temp_stack = stack; - new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, - clone_flags, tramp); + new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp); if(new_pid < 0){ printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", -new_pid); @@ -246,19 +297,30 @@ current->thread.request.op = OP_FORK; current->thread.request.u.fork.pid = new_pid; os_usr1_process(os_getpid()); - return(0); + + /* Enable the signal and then disable it to ensure that it is handled + * here, and nowhere else. + */ + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); + err = 0; + out: + return(err); } void reboot_tt(void) { current->thread.request.op = OP_REBOOT; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); } void halt_tt(void) { current->thread.request.op = OP_HALT; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); } void kill_off_processes_tt(void) @@ -285,6 +347,9 @@ current->thread.request.u.cb.proc = proc; current->thread.request.u.cb.arg = arg; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); } } @@ -377,8 +442,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 +519,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) @@ -479,9 +545,9 @@ void *sp; int pages; - pages = (1 << CONFIG_KERNEL_STACK_ORDER) - 2; - sp = (void *) init_task.thread.kernel_stack + pages * PAGE_SIZE - - sizeof(unsigned long); + pages = (1 << CONFIG_KERNEL_STACK_ORDER); + sp = (void *) ((unsigned long) init_task.thread_info) + + pages * PAGE_SIZE - sizeof(unsigned long); return(tracer(start_kernel_proc, sp)); } diff -Nru a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile --- a/arch/um/kernel/tt/ptproxy/Makefile 2004-10-18 14:56:28 -07:00 +++ b/arch/um/kernel/tt/ptproxy/Makefile 2004-10-18 14:56:28 -07:00 @@ -9,5 +9,3 @@ $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean: diff -Nru a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c --- a/arch/um/kernel/tt/ptproxy/proxy.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/tt/ptproxy/proxy.c 2004-10-18 14:56:33 -07:00 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -273,7 +272,7 @@ child_proxy(1, W_EXITCODE(0, 0)); while(debugger.waiting == 1){ - pid = waitpid(debugger.pid, &status, WUNTRACED); + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); if(pid != debugger.pid){ printk("fake_child_exit - waitpid failed, " "errno = %d\n", errno); @@ -281,7 +280,7 @@ } debugger_proxy(status, debugger.pid); } - pid = waitpid(debugger.pid, &status, WUNTRACED); + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); if(pid != debugger.pid){ printk("fake_child_exit - waitpid failed, " "errno = %d\n", errno); @@ -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 -Nru a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c --- a/arch/um/kernel/tt/ptproxy/sysdep.c 2004-10-18 14:56:49 -07:00 +++ b/arch/um/kernel/tt/ptproxy/sysdep.c 2004-10-18 14:56:49 -07:00 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c --- a/arch/um/kernel/tt/ptproxy/wait.c 2004-10-18 14:56:50 -07:00 +++ b/arch/um/kernel/tt/ptproxy/wait.c 2004-10-18 14:56:50 -07:00 @@ -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); + IP_RESTART_SYSCALL(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 -Nru a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile --- a/arch/um/kernel/tt/sys-i386/Makefile 2004-10-18 14:56:29 -07:00 +++ b/arch/um/kernel/tt/sys-i386/Makefile 2004-10-18 14:56:29 -07:00 @@ -10,5 +10,3 @@ $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : diff -Nru a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c --- a/arch/um/kernel/tt/syscall_kern.c 2004-10-18 14:55:53 -07:00 +++ b/arch/um/kernel/tt/syscall_kern.c 2004-10-18 14:55:53 -07:00 @@ -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 -Nru a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c --- a/arch/um/kernel/tt/syscall_user.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/tt/syscall_user.c 2004-10-18 14:56:33 -07:00 @@ -33,7 +33,7 @@ SC_START_SYSCALL(sc); index = record_syscall_start(syscall); - syscall_trace(); + syscall_trace(regs, 1); result = execute_syscall(regs); /* regs->sc may have changed while the system call ran (there may @@ -46,7 +46,7 @@ (result == -ERESTARTNOINTR)) do_signal(result); - syscall_trace(); + syscall_trace(regs, 0); record_syscall_end(index, result); } diff -Nru a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c --- a/arch/um/kernel/tt/tlb.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/kernel/tt/tlb.c 2004-10-18 14:55:54 -07:00 @@ -10,6 +10,7 @@ #include "asm/page.h" #include "asm/pgtable.h" #include "asm/uaccess.h" +#include "asm/tlbflush.h" #include "user_util.h" #include "mem_user.h" #include "os.h" diff -Nru a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c --- a/arch/um/kernel/tt/tracer.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/kernel/tt/tracer.c 2004-10-18 14:55:54 -07:00 @@ -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; @@ -192,7 +192,7 @@ printf("tracing thread pid = %d\n", tracing_pid); pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("waitpid on idle thread failed, errno = %d\n", errno); exit(1); @@ -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){ + CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED)); + if(pid <= 0){ if(errno != ECHILD){ printf("wait failed - errno = %d\n", errno); } @@ -329,7 +330,8 @@ continue; } tracing = 0; - if(do_syscall(task, pid)) sig = SIGUSR2; + if(do_syscall(task, pid)) + sig = SIGUSR2; else clear_singlestep(task); break; case SIGPROF: @@ -401,7 +403,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 -Nru a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c --- a/arch/um/kernel/tt/trap_user.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/tt/trap_user.c 2004-10-18 14:56:33 -07:00 @@ -23,6 +23,13 @@ unprotect_kernel_mem(); + /* This is done because to allow SIGSEGV to be delivered inside a SEGV + * handler. This can happen in copy_user, and if SEGV is disabled, + * the process will die. + */ + if(sig == SIGSEGV) + change_sig(SIGSEGV, 1); + r = &TASK_REGS(get_current())->tt; save_regs = *r; is_user = user_context(SC_SP(sc)); @@ -30,7 +37,6 @@ if(sig != SIGUSR2) r->syscall = -1; - change_sig(SIGUSR1, 1); info = &sig_info[sig]; if(!info->is_irq) unblock_signals(); @@ -39,7 +45,6 @@ if(is_user){ interrupt_end(); block_signals(); - change_sig(SIGUSR1, 0); set_user_mode(NULL); } *r = save_regs; diff -Nru a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/kernel/tt/uaccess.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "asm/uaccess.h" + +int copy_from_user_tt(void *to, const void *from, int n) +{ + if(!access_ok_tt(VERIFY_READ, from, n)) + return(n); + + return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +int copy_to_user_tt(void *to, const void *from, int n) +{ + if(!access_ok_tt(VERIFY_WRITE, to, n)) + return(n); + + return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +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); +} + +int __clear_user_tt(void *mem, int len) +{ + return(__do_clear_user(mem, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +int clear_user_tt(void *mem, int len) +{ + if(!access_ok_tt(VERIFY_WRITE, mem, len)) + return(len); + + return(__do_clear_user(mem, len, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +int strnlen_user_tt(const void *str, int len) +{ + return(__do_strnlen_user(str, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +/* + * 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 -Nru a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c --- a/arch/um/kernel/tt/uaccess_user.c 2004-10-18 14:56:28 -07:00 +++ b/arch/um/kernel/tt/uaccess_user.c 2004-10-18 14:56:28 -07:00 @@ -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; + sigjmp_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 -Nru a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c --- a/arch/um/kernel/tt/unmap.c 2004-10-18 14:56:49 -07:00 +++ b/arch/um/kernel/tt/unmap.c 2004-10-18 14:56:49 -07:00 @@ -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 -Nru a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c --- a/arch/um/kernel/tty_log.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/kernel/tty_log.c 2004-10-18 14:56:33 -07:00 @@ -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(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)); } - return(write(fd, buf, len)); } +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 -Nru a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c --- a/arch/um/kernel/uaccess_user.c 2004-10-18 14:56:48 -07:00 +++ b/arch/um/kernel/uaccess_user.c 2004-10-18 14:56:48 -07:00 @@ -18,9 +18,9 @@ { unsigned long *faddrp = (unsigned long *) fault_addr, ret; - jmp_buf jbuf; + sigjmp_buf jbuf; *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ + if(sigsetjmp(jbuf, 1) == 0){ (*op)(to, from, n); ret = 0; *faulted_out = 0; diff -Nru a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c --- a/arch/um/kernel/um_arch.c 2004-10-18 14:56:49 -07:00 +++ b/arch/um/kernel/um_arch.c 2004-10-18 14:56:49 -07:00 @@ -27,7 +27,6 @@ #include "user_util.h" #include "kern_util.h" #include "kern.h" -#include "mprot.h" #include "mem_user.h" #include "mem.h" #include "umid.h" @@ -38,13 +37,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 +57,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 +142,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 +187,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 +218,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 +229,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,15 +299,15 @@ /* 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) int linux_main(int argc, char **argv) { - unsigned long avail; + unsigned long avail, diff; 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; @@ -315,6 +323,16 @@ brk_start = (unsigned long) sbrk(0); CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); + /* Increase physical memory size for exec-shield users + so they actually get what they asked for. This should + add zero for non-exec shield users */ + + diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + if(diff > 1024 * 1024){ + printf("Adding %ld bytes to physical memory to account for " + "exec-shield gap\n", diff); + physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + } uml_physmem = uml_start; @@ -328,12 +346,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 +365,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,28 +387,23 @@ 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())); } +extern int uml_exitcode; + static int panic_exit(struct notifier_block *self, unsigned long unused1, void *unused2) { #ifdef CONFIG_MAGIC_SYSRQ - handle_sysrq('p', ¤t->thread.regs, NULL, NULL); + handle_sysrq('p', ¤t->thread.regs, NULL); #endif + uml_exitcode = 1; machine_halt(); return(0); } @@ -403,6 +428,11 @@ arch_check_bugs(); check_ptrace(); check_sigio(); + check_devanon(); +} + +void apply_alternatives(void *start, void *end) +{ } /* diff -Nru a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c --- a/arch/um/kernel/umid.c 2004-10-18 14:57:03 -07:00 +++ b/arch/um/kernel/umid.c 2004-10-18 14:57:03 -07:00 @@ -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 %d " + "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); @@ -195,17 +199,20 @@ static int __init set_uml_dir(char *name, int *add) { if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ - uml_dir = malloc(strlen(name) + 1); + uml_dir = malloc(strlen(name) + 2); 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 here because do_initcalls doesn't look at + * the return value. + */ return(0); } sprintf(uml_dir, "%s/", name); } else uml_dir = name; - return 0; + return(0); } static int __init make_uml_dir(void) @@ -217,7 +224,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 +239,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 +304,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 -Nru a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/kernel/uml.lds.S 2004-10-18 14:56:29 -07:00 @@ -0,0 +1,96 @@ +#include + +OUTPUT_FORMAT(ELF_FORMAT) +OUTPUT_ARCH(ELF_ARCH) +ENTRY(_start) +jiffies = jiffies_64; + +SECTIONS +{ + . = START + SIZEOF_HEADERS; + + __binary_start = .; +#ifdef MODE_TT + .thread_private : { + __start_thread_private = .; + errno = .; + . += 4; + arch/um/kernel/tt/unmap_fin.o (.data) + __end_thread_private = .; + } + . = ALIGN(4096); + .remap : { arch/um/kernel/tt/unmap_fin.o (.text) } +#endif + + . = ALIGN(4096); /* Init code and data */ + _stext = .; + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + . = ALIGN(4096); + .text : + { + *(.text) + SCHED_TEXT + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } + + #include "asm/common.lds.S" + + init.data : { *(init.data) } + .data : + { + . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ + *(.data.init_task) + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + . = ALIGN(0x1000); + .sbss : + { + __bss_start = .; + PROVIDE(_bss_start = .); + *(.sbss) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -Nru a/arch/um/kernel/user_syms.c b/arch/um/kernel/user_syms.c --- a/arch/um/kernel/user_syms.c 2004-10-18 14:57:03 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,113 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "user_util.h" -#include "mem_user.h" -#include "uml-config.h" - -/* Had to steal this from linux/module.h because that file can't be included - * since this includes various user-level headers. - */ - -struct module_symbol -{ - unsigned long value; - const char *name; -}; - -/* Indirect stringification. */ - -#define __MODULE_STRING_1(x) #x -#define __MODULE_STRING(x) __MODULE_STRING_1(x) - -#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 -#define EXPORT_SYMBOL_NOVERS(var) error config_must_be_included_before_module - -#elif !defined(UML_CONFIG_MODULES) - -#define __EXPORT_SYMBOL(sym,str) -#define EXPORT_SYMBOL(var) -#define EXPORT_SYMBOL_NOVERS(var) - -#else - -#define __EXPORT_SYMBOL(sym, str) \ -const char __kstrtab_##sym[] \ -__attribute__((section(".kstrtab"))) = str; \ -const struct module_symbol __ksymtab_##sym \ -__attribute__((section("__ksymtab"))) = \ -{ (unsigned long)&sym, __kstrtab_##sym } - -#if defined(__MODVERSIONS__) || !defined(UML_CONFIG_MODVERSIONS) -#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) -#else -#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var))) -#endif - -#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) - -#endif - -EXPORT_SYMBOL(__errno_location); - -EXPORT_SYMBOL(access); -EXPORT_SYMBOL(open); -EXPORT_SYMBOL(open64); -EXPORT_SYMBOL(close); -EXPORT_SYMBOL(read); -EXPORT_SYMBOL(write); -EXPORT_SYMBOL(dup2); -EXPORT_SYMBOL(__xstat); -EXPORT_SYMBOL(__lxstat); -EXPORT_SYMBOL(__lxstat64); -EXPORT_SYMBOL(lseek); -EXPORT_SYMBOL(lseek64); -EXPORT_SYMBOL(chown); -EXPORT_SYMBOL(truncate); -EXPORT_SYMBOL(utime); -EXPORT_SYMBOL(chmod); -EXPORT_SYMBOL(rename); -EXPORT_SYMBOL(__xmknod); - -EXPORT_SYMBOL(symlink); -EXPORT_SYMBOL(link); -EXPORT_SYMBOL(unlink); -EXPORT_SYMBOL(readlink); - -EXPORT_SYMBOL(mkdir); -EXPORT_SYMBOL(rmdir); -EXPORT_SYMBOL(opendir); -EXPORT_SYMBOL(readdir); -EXPORT_SYMBOL(closedir); -EXPORT_SYMBOL(seekdir); -EXPORT_SYMBOL(telldir); - -EXPORT_SYMBOL(ioctl); - -extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes, - __off64_t __offset); -extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n, - __off64_t __offset); -EXPORT_SYMBOL(pread64); -EXPORT_SYMBOL(pwrite64); - -EXPORT_SYMBOL(statfs); -EXPORT_SYMBOL(statfs64); - -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(getuid); - -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(strstr); - -EXPORT_SYMBOL(find_iomem); diff -Nru a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c --- a/arch/um/kernel/user_util.c 2004-10-18 14:56:16 -07:00 +++ b/arch/um/kernel/user_util.c 2004-10-18 14:56:16 -07:00 @@ -5,10 +5,10 @@ #include #include -#include #include #include -#include +#include +#include #include #include #include @@ -81,19 +81,19 @@ int status, ret; while(1){ - if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) || + CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED)); + if((ret < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ if(ret < 0){ - if(errno == EINTR) continue; printk("wait failed, errno = %d\n", errno); } else if(WIFEXITED(status)) - printk("process exited with status %d\n", - WEXITSTATUS(status)); + printk("process %d exited with status %d\n", + pid, WEXITSTATUS(status)); else if(WIFSIGNALED(status)) - printk("process exited with signal %d\n", - WTERMSIG(status)); + printk("process %d exited with signal %d\n", + pid, WTERMSIG(status)); else if((WSTOPSIG(status) == SIGVTALRM) || (WSTOPSIG(status) == SIGALRM) || (WSTOPSIG(status) == SIGIO) || @@ -109,8 +109,8 @@ ptrace(cont_type, pid, 0, WSTOPSIG(status)); continue; } - else printk("process stopped with signal %d\n", - WSTOPSIG(status)); + else printk("process %d stopped with signal %d\n", + pid, WSTOPSIG(status)); panic("wait_for_stop failed to wait for %d to stop " "with %d\n", pid, sig); } @@ -118,29 +118,27 @@ } } -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) +int raw(int fd) { struct termios tt; int err; - tcgetattr(fd, &tt); + CATCH_EINTR(err = tcgetattr(fd, &tt)); + if (err < 0) { + printk("tcgetattr failed, errno = %d\n", errno); + return(-errno); + } + cfmakeraw(&tt); - err = tcsetattr(fd, TCSANOW, &tt); - if((err < 0) && complain){ - printk("tcsetattr failed, errno = %d\n", errno); + + CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); + if (err < 0) { + printk("tcsetattr failed, errno = %d\n", errno); return(-errno); } + + /* XXX tcsetattr could have applied only some changes + * (and cfmakeraw() is a set of changes) */ return(0); } @@ -161,6 +159,21 @@ uname(&host); sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename, host.release, host.version, host.machine); +} + +int setjmp_wrapper(void (*proc)(void *, void *), ...) +{ + va_list args; + sigjmp_buf buf; + int n; + + n = sigsetjmp(buf, 1); + if(n == 0){ + va_start(args, proc); + (*proc)(&buf, &args); + } + va_end(args); + return(n); } /* diff -Nru a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S --- a/arch/um/kernel/vmlinux.lds.S 2004-10-18 14:55:46 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,11 +0,0 @@ -#include - -OUTPUT_FORMAT(ELF_FORMAT) -OUTPUT_ARCH(ELF_ARCH) -ENTRY(_start) -jiffies = jiffies_64; - -SECTIONS -{ -#include "asm/common.lds.S" -} diff -Nru a/arch/um/main.c b/arch/um/main.c --- a/arch/um/main.c 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "user_util.h" -#include "kern_util.h" -#include "mem_user.h" -#include "signal_user.h" -#include "user.h" -#include "init.h" -#include "mode.h" -#include "choose-mode.h" -#include "uml-config.h" - -/* Set in set_stklim, which is called from main and __wrap_malloc. - * __wrap_malloc only calls it if main hasn't started. - */ -unsigned long stacksizelim; - -/* Set in main */ -char *linux_prog; - -#define PGD_BOUND (4 * 1024 * 1024) -#define STACKSIZE (8 * 1024 * 1024) -#define THREAD_NAME_LEN (256) - -static void set_stklim(void) -{ - struct rlimit lim; - - if(getrlimit(RLIMIT_STACK, &lim) < 0){ - perror("getrlimit"); - exit(1); - } - if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){ - lim.rlim_cur = STACKSIZE; - if(setrlimit(RLIMIT_STACK, &lim) < 0){ - perror("setrlimit"); - exit(1); - } - } - stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); -} - -static __init void do_uml_initcalls(void) -{ - initcall_t *call; - - call = &__uml_initcall_start; - while (call < &__uml_initcall_end){; - (*call)(); - call++; - } -} - -static void last_ditch_exit(int sig) -{ - CHOOSE_MODE(kmalloc_ok = 0, (void) 0); - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); - uml_cleanup(); - exit(1); -} - -extern int uml_exitcode; - -int main(int argc, char **argv, char **envp) -{ - char **new_argv; - sigset_t mask; - int ret, i; - - /* Enable all signals except SIGIO - in some environments, we can - * enter with some signals blocked - */ - - sigemptyset(&mask); - sigaddset(&mask, SIGIO); - if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){ - perror("sigprocmask"); - exit(1); - } - -#ifdef UML_CONFIG_MODE_TT - /* Allocate memory for thread command lines */ - if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ - - char padding[THREAD_NAME_LEN] = { - [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0' - }; - - new_argv = malloc((argc + 2) * sizeof(char*)); - if(!new_argv) { - perror("Allocating extended argv"); - exit(1); - } - - new_argv[0] = argv[0]; - new_argv[1] = padding; - - for(i = 2; i <= argc; i++) - new_argv[i] = argv[i - 1]; - new_argv[argc + 1] = NULL; - - execvp(new_argv[0], new_argv); - perror("execing with extended args"); - exit(1); - } -#endif - - linux_prog = argv[0]; - - set_stklim(); - - if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ - perror("Mallocing argv"); - exit(1); - } - for(i=0;i #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "net_user.h" #include "etap.h" #include "helper.h" @@ -42,13 +42,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 +83,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 +115,22 @@ 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; + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 0) + err = -errno; + else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) printk("uml_net didn't exit with status 1\n"); - } } return(err); } @@ -143,14 +145,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 +169,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 +185,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 -Nru a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c --- a/arch/um/os-Linux/drivers/tuntap_user.c 2004-10-18 14:57:05 -07:00 +++ b/arch/um/os-Linux/drivers/tuntap_user.c 2004-10-18 14:57:05 -07:00 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -19,6 +18,7 @@ #include "net_user.h" #include "tuntap.h" #include "kern_util.h" +#include "user_util.h" #include "user.h" #include "helper.h" #include "os.h" @@ -61,7 +61,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 +86,7 @@ if(pid < 0) return(-pid); - close(remote); + os_close_file(remote); msg.msg_name = NULL; msg.msg_namelen = 0; @@ -107,19 +107,19 @@ if(n < 0){ printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", errno); - return(errno); + return(-errno); } - waitpid(pid, NULL, 0); + CATCH_EINTR(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 +133,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 +168,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 +193,7 @@ if(!pri->fixed_config) iter_addresses(pri->dev, close_addr, pri->dev_name); - close(fd); + os_close_file(fd); pri->fd = -1; } diff -Nru a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c --- a/arch/um/os-Linux/file.c 2004-10-18 14:57:04 -07:00 +++ b/arch/um/os-Linux/file.c 2004-10-18 14:57:04 -07:00 @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,33 +19,236 @@ #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) +{ + 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; + + 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); + } + + return(0); +} + +int os_mode_fd(int fd, int mode) { - struct stat64 buf; + int err; + + do { + err = fchmod(fd, mode); + } while((err < 0) && (errno==EINTR)) ; - if(stat64(file, &buf) == -1) + if(err < 0) 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_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 +268,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 +293,7 @@ err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); if(err) - return(err); + return(-errno); return(fd); } @@ -109,88 +312,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) @@ -219,6 +496,16 @@ return(0); } +int os_clear_fd_async(int fd) +{ + int flags = fcntl(fd, F_GETFL); + + flags &= ~(O_ASYNC | O_NONBLOCK); + if(fcntl(fd, F_SETFL, flags) < 0) + return(-errno); + return(0); +} + int os_set_fd_block(int fd, int blocking) { int flags; @@ -270,7 +557,7 @@ return(-EINVAL); } err = shutdown(fd, what); - if(err) + if(err < 0) return(-errno); return(0); } @@ -315,7 +602,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 +614,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,12 +628,43 @@ 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); } /* diff -Nru a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c --- a/arch/um/os-Linux/process.c 2004-10-18 14:55:55 -07:00 +++ b/arch/um/os-Linux/process.c 2004-10-18 14:55:55 -07:00 @@ -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,35 +7,44 @@ #include #include #include +#include #include #include #include "os.h" #include "user.h" +#include "user_util.h" + +#define ARBITRARY_ADDR -1 +#define FAILURE_PID -1 + +#define STAT_PATH_LEN sizeof("/proc/#######/stat\0") +#define COMM_SCANF "%*[^)])" unsigned long os_process_pc(int pid) { - char proc_stat[sizeof("/proc/#####/stat\0")], buf[256]; + char proc_stat[STAT_PATH_LEN], 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; - if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d " + os_close_file(fd); + pc = ARBITRARY_ADDR; + if(sscanf(buf, "%*d " COMM_SCANF " %*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 %ld", &pc) != 1){ + "%*d %*d %*d %*d %*d %lu", &pc) != 1){ printk("os_process_pc - couldn't find pc in '%s'\n", buf); } return(pc); @@ -43,7 +52,7 @@ int os_process_parent(int pid) { - char stat[sizeof("/proc/nnnnn/stat\0")]; + char stat[STAT_PATH_LEN]; char data[256]; int parent, n, fd; @@ -52,22 +61,22 @@ 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; - /* 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); + parent = FAILURE_PID; + n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); + if(n != 1) + printk("Failed to scan '%s'\n", data); return(parent); } @@ -81,7 +90,7 @@ { kill(pid, SIGKILL); if(reap_child) - waitpid(pid, NULL, 0); + CATCH_EINTR(waitpid(pid, NULL, 0)); } @@ -95,7 +104,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 +113,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 +135,8 @@ int err; err = munmap(addr, len); - if(err < 0) return(-errno); + if(err < 0) + return(-errno); return(0); } diff -Nru a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/os-Linux/time.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,21 @@ +#include +#include + +unsigned long long os_usecs(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec); +} + +/* + * 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 -Nru a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c --- a/arch/um/os-Linux/tty.c 2004-10-18 14:56:33 -07:00 +++ b/arch/um/os-Linux/tty.c 2004-10-18 14:56:33 -07:00 @@ -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 -Nru a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/um/os-Linux/user_syms.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,90 @@ +#include "linux/types.h" +#include "linux/module.h" + +/* Some of this are builtin function (some are not but could in the future), + * so I *must* declare good prototypes for them and then EXPORT them. + * The kernel code uses the macro defined by include/linux/string.h, + * so I undef macros; the userspace code does not include that and I + * add an EXPORT for the glibc one.*/ + +#undef strlen +#undef strstr +#undef memcpy +#undef memset + +extern size_t strlen(const char *); +extern void *memcpy(void *, const void *, size_t); +extern void *memmove(void *, const void *, size_t); +extern void *memset(void *, int, size_t); +extern int printf(const char *, ...); + +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(printf); + +EXPORT_SYMBOL(strstr); + +/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. + * However, the modules will use the CRC defined *here*, no matter if it is + * good; so the versions of these symbols will always match + */ +#define EXPORT_SYMBOL_PROTO(sym) \ + int sym(void); \ + EXPORT_SYMBOL(sym); + +EXPORT_SYMBOL_PROTO(__errno_location); + +EXPORT_SYMBOL_PROTO(access); +EXPORT_SYMBOL_PROTO(open); +EXPORT_SYMBOL_PROTO(open64); +EXPORT_SYMBOL_PROTO(close); +EXPORT_SYMBOL_PROTO(read); +EXPORT_SYMBOL_PROTO(write); +EXPORT_SYMBOL_PROTO(dup2); +EXPORT_SYMBOL_PROTO(__xstat); +EXPORT_SYMBOL_PROTO(__lxstat); +EXPORT_SYMBOL_PROTO(__lxstat64); +EXPORT_SYMBOL_PROTO(lseek); +EXPORT_SYMBOL_PROTO(lseek64); +EXPORT_SYMBOL_PROTO(chown); +EXPORT_SYMBOL_PROTO(truncate); +EXPORT_SYMBOL_PROTO(utime); +EXPORT_SYMBOL_PROTO(chmod); +EXPORT_SYMBOL_PROTO(rename); +EXPORT_SYMBOL_PROTO(__xmknod); + +EXPORT_SYMBOL_PROTO(symlink); +EXPORT_SYMBOL_PROTO(link); +EXPORT_SYMBOL_PROTO(unlink); +EXPORT_SYMBOL_PROTO(readlink); + +EXPORT_SYMBOL_PROTO(mkdir); +EXPORT_SYMBOL_PROTO(rmdir); +EXPORT_SYMBOL_PROTO(opendir); +EXPORT_SYMBOL_PROTO(readdir); +EXPORT_SYMBOL_PROTO(closedir); +EXPORT_SYMBOL_PROTO(seekdir); +EXPORT_SYMBOL_PROTO(telldir); + +EXPORT_SYMBOL_PROTO(ioctl); + +EXPORT_SYMBOL_PROTO(pread64); +EXPORT_SYMBOL_PROTO(pwrite64); + +EXPORT_SYMBOL_PROTO(statfs); +EXPORT_SYMBOL_PROTO(statfs64); + +EXPORT_SYMBOL_PROTO(getuid); + +/* + * 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 -Nru a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile --- a/arch/um/sys-i386/Makefile 2004-10-18 14:56:13 -07:00 +++ b/arch/um/sys-i386/Makefile 2004-10-18 14:56:13 -07:00 @@ -1,14 +1,21 @@ -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 = bitops.o bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o \ + ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.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)) -SYMLINKS = semaphore.c highmem.c module.c +SYMLINKS = bitops.c semaphore.c highmem.c module.c + +# this needs to be before the foreach, because clean-files does not accept +# complete paths like $(src)/$f. +clean-files := $(SYMLINKS) + SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f) +bitops.c-dir = lib semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel @@ -24,19 +31,4 @@ $(SYMLINKS): $(call make_link,$@) -clean: - $(MAKE) -C util clean - -fastdep: - -dep: - -archmrproper: - rm -f $(SYMLINKS) - -archclean: - -archdep: - -modules: - +subdir- := util diff -Nru a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c --- a/arch/um/sys-i386/bugs.c 2004-10-18 14:57:21 -07:00 +++ b/arch/um/sys-i386/bugs.c 2004-10-18 14:57:21 -07:00 @@ -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,48 +137,76 @@ 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) { - unsigned long ip; + unsigned char tmp[2]; /* This is testing for a cmov (0x0f 0x4x) instruction causing a * SIGILL in init. */ if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0); - ip = UPT_IP(regs); - if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40)) + if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) + panic("SIGILL in init, could not read instructions!\n"); + if((tmp[0] != 0x0f) || ((tmp[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 -Nru a/arch/um/sys-i386/extable.c b/arch/um/sys-i386/extable.c --- a/arch/um/sys-i386/extable.c 2004-10-18 14:57:04 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,30 +0,0 @@ -/* - * linux/arch/i386/mm/extable.c - */ - -#include -#include -#include -#include - -/* Simple binary search */ -const struct exception_table_entry * -search_extable(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) -{ - while (first <= last) { - const struct exception_table_entry *mid; - long diff; - - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) - return mid; - else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - return NULL; -} diff -Nru a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c --- a/arch/um/sys-i386/fault.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/sys-i386/fault.c 2004-10-18 14:56:32 -07:00 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,16 +7,24 @@ #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" -extern unsigned long search_exception_table(unsigned long addr); +/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ +struct exception_table_entry +{ + unsigned long insn; + unsigned long fixup; +}; +const struct exception_table_entry *search_exception_tables(unsigned long add); + +/* Compare this to arch/i386/mm/extable.c:fixup_exception() */ int arch_fixup(unsigned long address, void *sc_ptr) { struct sigcontext *sc = sc_ptr; - unsigned long fixup; + const struct exception_table_entry *fixup; fixup = search_exception_tables(address); if(fixup != 0){ - sc->eip = fixup; + sc->eip = fixup->fixup; return(1); } return(0); diff -Nru a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c --- a/arch/um/sys-i386/ldt.c 2004-10-18 14:56:29 -07:00 +++ b/arch/um/sys-i386/ldt.c 2004-10-18 14:56:29 -07:00 @@ -13,6 +13,8 @@ #ifdef CONFIG_MODE_TT extern int modify_ldt(int func, void *ptr, unsigned long bytecount); +/* XXX this needs copy_to_user and copy_from_user */ + int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) { if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT); diff -Nru a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c --- a/arch/um/sys-i386/ptrace_user.c 2004-10-18 14:57:19 -07:00 +++ b/arch/um/sys-i386/ptrace_user.c 2004-10-18 14:57:19 -07:00 @@ -39,10 +39,11 @@ 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, value = 0x%x, errno = %d\n", i, + regs[i], errno); } } @@ -54,7 +55,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 -Nru a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c --- a/arch/um/sys-i386/syscalls.c 2004-10-18 14:56:32 -07:00 +++ b/arch/um/sys-i386/syscalls.c 2004-10-18 14:56:32 -07:00 @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include "linux/sched.h" #include "asm/mman.h" #include "asm/uaccess.h" #include "asm/unistd.h" @@ -54,6 +55,27 @@ return -EFAULT; /* sys_select() does the appropriate kernel locking */ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* The i386 version skips reading from %esi, the fourth argument. So we must do + * this, too. + */ +int sys_clone(unsigned long clone_flags, unsigned long newsp, int *parent_tid, + int unused, int *child_tid) +{ + long ret; + + /* XXX: normal arch do here this pass, and also pass the regs to + * do_fork, instead of NULL. Currently the arch-independent code + * ignores these values, while the UML code (actually it's + * copy_thread) does the right thing. But this should change, + probably. */ + /*if (!newsp) + newsp = UPT_SP(current->thread.regs);*/ + current->thread.forking = 1; + ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); + current->thread.forking = 0; + return(ret); } /* diff -Nru a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile --- a/arch/um/sys-i386/util/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/um/sys-i386/util/Makefile 2004-10-18 14:57:04 -07:00 @@ -1,17 +1,8 @@ -host-progs := mk_sc -always := $(host-progs) mk_thread -targets := mk_thread_kern.o mk_thread_user.o +hostprogs-y := mk_sc mk_thread +always := $(hostprogs-y) -mk_sc-objs := mk_sc.o +mk_thread-objs := mk_thread_kern.o mk_thread_user.o -$(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o - $(CC) $(CFLAGS) -o $@ $^ - -$(obj)/mk_thread_user.o : $(src)/mk_thread_user.c - $(CC) $(USER_CFLAGS) -c -o $@ $< - -clean : - $(RM) -f $(build-targets) - -archmrproper : clean +HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS) diff -Nru a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c --- a/arch/um/sys-i386/util/mk_sc.c 2004-10-18 14:57:03 -07:00 +++ b/arch/um/sys-i386/util/mk_sc.c 2004-10-18 14:57:03 -07:00 @@ -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 -Nru a/arch/um/sys-ia64/Makefile b/arch/um/sys-ia64/Makefile --- a/arch/um/sys-ia64/Makefile 2004-10-18 14:55:54 -07:00 +++ b/arch/um/sys-ia64/Makefile 2004-10-18 14:55:54 -07:00 @@ -7,18 +7,5 @@ $(OBJ): $(OBJS) rm -f $@ $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ -clean: - rm -f $(OBJS) -fastdep: - -archmrproper: - -archclean: - rm -f link.ld - @$(MAKEBOOT) clean - -archdep: - @$(MAKEBOOT) dep - -modules: +clean-files := $(OBJS) link.ld diff -Nru a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile --- a/arch/um/sys-ppc/Makefile 2004-10-18 14:56:29 -07:00 +++ b/arch/um/sys-ppc/Makefile 2004-10-18 14:56:29 -07:00 @@ -66,13 +66,4 @@ $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm -clean: - rm -f $(OBJS) - rm -f ppc_defs.h - rm -f checksum.S semaphore.c mk_defs.c - -fastdep: - -dep: - -modules: +clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c diff -Nru a/arch/um/uml.lds.S b/arch/um/uml.lds.S --- a/arch/um/uml.lds.S 2004-10-18 14:56:29 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,92 +0,0 @@ -#include - -OUTPUT_FORMAT(ELF_FORMAT) -OUTPUT_ARCH(ELF_ARCH) -ENTRY(_start) -jiffies = jiffies_64; - -SECTIONS -{ - . = START + SIZEOF_HEADERS; - - . = ALIGN(4096); - __binary_start = .; -#ifdef MODE_TT - .thread_private : { - __start_thread_private = .; - errno = .; - . += 4; - arch/um/kernel/tt/unmap_fin.o (.data) - __end_thread_private = .; - } - . = ALIGN(4096); - .remap : { arch/um/kernel/tt/unmap_fin.o (.text) } -#endif - - . = ALIGN(4096); /* Init code and data */ - _stext = .; - __init_begin = .; - .text.init : { *(.text.init) } - . = ALIGN(4096); - .text : - { - *(.text) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.gnu.linkonce.t*) - } - - #include "asm/common.lds.S" - - .data.init : { *(.data.init) } - .data : - { - . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ - *(.data.init_task) - *(.data) - *(.gnu.linkonce.d*) - CONSTRUCTORS - } - .data1 : { *(.data1) } - .ctors : - { - *(.ctors) - } - .dtors : - { - *(.dtors) - } - - .got : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - PROVIDE (edata = .); - . = ALIGN(0x1000); - .sbss : - { - __bss_start = .; - PROVIDE(_bss_start = .); - *(.sbss) - *(.scommon) - } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - } - _end = . ; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } -} diff -Nru a/arch/um/util/Makefile b/arch/um/util/Makefile --- a/arch/um/util/Makefile 2004-10-18 14:57:04 -07:00 +++ b/arch/um/util/Makefile 2004-10-18 14:57:04 -07:00 @@ -1,23 +1,8 @@ -always := mk_task mk_constants -targets := mk_task_user.o mk_task_kern.o \ - mk_constants_user.o mk_constants_kern.o +hostprogs-y := mk_task mk_constants +always := $(hostprogs-y) -$(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o - $(CC) -o $@ $^ +mk_task-objs := mk_task_user.o mk_task_kern.o +mk_constants-objs := mk_constants_user.o mk_constants_kern.o -$(obj)/mk_task_user.o: $(src)/mk_task_user.c - $(CC) -o $@ -c $< - -$(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o - $(CC) -o $@ $^ - -$(obj)/mk_constants_user.o : $(src)/mk_constants_user.c - $(CC) -c $< -o $@ - -$(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - $(RM) $(build-targets) - -archmrproper: +HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_constants_kern.o := $(CFLAGS) $(CPPFLAGS) diff -Nru a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c --- a/arch/um/util/mk_constants_kern.c 2004-10-18 14:55:54 -07:00 +++ b/arch/um/util/mk_constants_kern.c 2004-10-18 14:55:54 -07:00 @@ -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 -Nru a/arch/v850/Kconfig b/arch/v850/Kconfig --- a/arch/v850/Kconfig 2004-10-18 14:56:29 -07:00 +++ b/arch/v850/Kconfig 2004-10-18 14:56:29 -07:00 @@ -68,7 +68,6 @@ bool "Anna" endchoice - #### V850E processor-specific config # All CPUs currently supported use the v850e architecture @@ -153,7 +152,6 @@ bool default RTE_MB_A_PCI - #### Some feature-specific configs # Everything except for the GDB simulator uses the same interrupt controller @@ -181,7 +179,6 @@ bool default !V850E_CACHE && !V850E2_CACHE - #### Misc config config ROM_KERNEL @@ -305,34 +302,7 @@ source "drivers/usb/Kconfig" - -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - 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 MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - Enables console device to interprent special characters as - commands to dump state information. - -config NO_KERNEL_MSG - bool "Suppress Kernel BUG Messages" - help - Do not output any debug BUG messages within the kernel. - -endmenu +source "arch/v850/Kconfig.debug" source "security/Kconfig" diff -Nru a/arch/v850/Kconfig.debug b/arch/v850/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/v850/Kconfig.debug 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,10 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +endmenu diff -Nru a/arch/v850/kernel/Makefile b/arch/v850/kernel/Makefile --- a/arch/v850/kernel/Makefile 2004-10-18 14:57:05 -07:00 +++ b/arch/v850/kernel/Makefile 2004-10-18 14:57:05 -07:00 @@ -9,7 +9,7 @@ # for more details. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y += intv.o entry.o process.o syscalls.o time.o semaphore.o setup.o \ signal.o irq.o mach.o ptrace.o bug.o diff -Nru a/arch/v850/kernel/asm-consts.c b/arch/v850/kernel/asm-consts.c --- a/arch/v850/kernel/asm-consts.c 2004-10-18 14:56:27 -07:00 +++ b/arch/v850/kernel/asm-consts.c 2004-10-18 14:56:27 -07:00 @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #define DEFINE(sym, val) \ diff -Nru a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c --- a/arch/v850/kernel/irq.c 2004-10-18 14:56:49 -07:00 +++ b/arch/v850/kernel/irq.c 2004-10-18 14:56:49 -07:00 @@ -141,13 +141,15 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ + int ret; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) diff -Nru a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c --- a/arch/v850/kernel/ptrace.c 2004-10-18 14:56:32 -07:00 +++ b/arch/v850/kernel/ptrace.c 2004-10-18 14:56:32 -07:00 @@ -147,14 +147,8 @@ rval = ptrace_attach(child); goto out_tsk; } - rval = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->parent != current) + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; switch (request) { @@ -269,11 +263,8 @@ return; /* 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 * for normal use. strace only continues with a signal if the diff -Nru a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c --- a/arch/v850/kernel/rte_mb_a_pci.c 2004-10-18 14:56:27 -07:00 +++ b/arch/v850/kernel/rte_mb_a_pci.c 2004-10-18 14:56:27 -07:00 @@ -322,8 +322,6 @@ /* Stubs for things we don't use. */ -struct pci_fixup pcibios_fixups[] = { { 0 } }; - /* Called after each bus is probed, but before its children are examined. */ void pcibios_fixup_bus(struct pci_bus *b) { diff -Nru a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c --- a/arch/v850/kernel/setup.c 2004-10-18 14:56:29 -07:00 +++ b/arch/v850/kernel/setup.c 2004-10-18 14:56:29 -07:00 @@ -280,8 +280,8 @@ #if ((PAGE_OFFSET >> PAGE_SHIFT) & ((1UL << (MAX_ORDER - 1)) - 1)) #error MAX_ORDER is too large for given PAGE_OFFSET (use CONFIG_FORCE_MAX_ZONEORDER to change it) #endif - - free_area_init_node (0, NODE_DATA(0), 0, zones_size, + NODE_DATA(0)->node_mem_map = NULL; + free_area_init_node (0, NODE_DATA(0), zones_size, ADDR_TO_PAGE (PAGE_OFFSET), 0); mem_map = NODE_DATA(0)->node_mem_map; } diff -Nru a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c --- a/arch/v850/kernel/signal.c 2004-10-18 14:57:05 -07:00 +++ b/arch/v850/kernel/signal.c 2004-10-18 14:57:05 -07:00 @@ -344,9 +344,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -421,9 +419,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* diff -Nru a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c --- a/arch/v850/kernel/time.c 2004-10-18 14:56:33 -07:00 +++ b/arch/v850/kernel/time.c 2004-10-18 14:56:33 -07:00 @@ -40,24 +40,6 @@ return (unsigned long long)jiffies * (1000000000 / HZ); } -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -74,10 +56,7 @@ mach_tick (); do_timer (regs); - - if (! user_mode (regs)) - do_profile (regs->pc); - + profile_tick(CPU_PROFILING, regs); #if 0 /* * If we have an externally synchronized Linux clock, then update diff -Nru a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c --- a/arch/v850/kernel/v850_ksyms.c 2004-10-18 14:56:33 -07:00 +++ b/arch/v850/kernel/v850_ksyms.c 2004-10-18 14:56:33 -07:00 @@ -14,7 +14,6 @@ #include #include #include -#include #include @@ -37,29 +36,29 @@ EXPORT_SYMBOL (ip_fast_csum); /* string / mem functions */ -EXPORT_SYMBOL_NOVERS (strcpy); -EXPORT_SYMBOL_NOVERS (strncpy); -EXPORT_SYMBOL_NOVERS (strcat); -EXPORT_SYMBOL_NOVERS (strncat); -EXPORT_SYMBOL_NOVERS (strcmp); -EXPORT_SYMBOL_NOVERS (strncmp); -EXPORT_SYMBOL_NOVERS (strchr); -EXPORT_SYMBOL_NOVERS (strlen); -EXPORT_SYMBOL_NOVERS (strnlen); -EXPORT_SYMBOL_NOVERS (strpbrk); -EXPORT_SYMBOL_NOVERS (strrchr); -EXPORT_SYMBOL_NOVERS (strstr); -EXPORT_SYMBOL_NOVERS (memset); -EXPORT_SYMBOL_NOVERS (memcpy); -EXPORT_SYMBOL_NOVERS (memmove); -EXPORT_SYMBOL_NOVERS (memcmp); -EXPORT_SYMBOL_NOVERS (memscan); +EXPORT_SYMBOL (strcpy); +EXPORT_SYMBOL (strncpy); +EXPORT_SYMBOL (strcat); +EXPORT_SYMBOL (strncat); +EXPORT_SYMBOL (strcmp); +EXPORT_SYMBOL (strncmp); +EXPORT_SYMBOL (strchr); +EXPORT_SYMBOL (strlen); +EXPORT_SYMBOL (strnlen); +EXPORT_SYMBOL (strpbrk); +EXPORT_SYMBOL (strrchr); +EXPORT_SYMBOL (strstr); +EXPORT_SYMBOL (memset); +EXPORT_SYMBOL (memcpy); +EXPORT_SYMBOL (memmove); +EXPORT_SYMBOL (memcmp); +EXPORT_SYMBOL (memscan); /* semaphores */ -EXPORT_SYMBOL_NOVERS (__down); -EXPORT_SYMBOL_NOVERS (__down_interruptible); -EXPORT_SYMBOL_NOVERS (__down_trylock); -EXPORT_SYMBOL_NOVERS (__up); +EXPORT_SYMBOL (__down); +EXPORT_SYMBOL (__down_interruptible); +EXPORT_SYMBOL (__down_trylock); +EXPORT_SYMBOL (__up); /* * libgcc functions - functions that are used internally by the @@ -72,8 +71,8 @@ extern void __muldi3 (void); extern void __negdi2 (void); -EXPORT_SYMBOL_NOVERS (__ashldi3); -EXPORT_SYMBOL_NOVERS (__ashrdi3); -EXPORT_SYMBOL_NOVERS (__lshrdi3); -EXPORT_SYMBOL_NOVERS (__muldi3); -EXPORT_SYMBOL_NOVERS (__negdi2); +EXPORT_SYMBOL (__ashldi3); +EXPORT_SYMBOL (__ashrdi3); +EXPORT_SYMBOL (__lshrdi3); +EXPORT_SYMBOL (__muldi3); +EXPORT_SYMBOL (__negdi2); diff -Nru a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S --- a/arch/v850/kernel/vmlinux.lds.S 2004-10-18 14:56:33 -07:00 +++ b/arch/v850/kernel/vmlinux.lds.S 2004-10-18 14:56:33 -07:00 @@ -111,9 +111,6 @@ *(.init.setup) /* 2.5 convention */ \ *(.setup.init) /* 2.4 convention */ \ ___setup_end = . ; \ - ___start___param = . ; \ - *(__param) \ - ___stop___param = . ; \ ___initcall_start = . ; \ *(.initcall.init) \ *(.initcall1.init) \ diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig 2004-10-18 14:56:49 -07:00 +++ b/arch/x86_64/Kconfig 2004-10-18 14:56:49 -07:00 @@ -4,7 +4,7 @@ # # Note: ISA is disabled and will hopefully never be enabled. # If you managed to buy an ISA x86-64 box you'll have to fix all the -# ISA drivers you need yourself. +# ISA drivers you need yourself. # mainmenu "Linux Kernel Configuration" @@ -57,7 +57,7 @@ it is not recommended because it looks ugly and doesn't cooperate with klogd/syslogd or the X server. You should normally N here, unless you want to debug such a crash. - + config HPET_TIMER bool default y @@ -78,6 +78,10 @@ bool default y +config GENERIC_IOMAP + bool + default y + source "init/Kconfig" @@ -90,14 +94,14 @@ config MK8 bool "AMD-Opteron/Athlon64" help - Optimize for AMD Opteron/Athlon64/Hammer/K8 CPUs. + Optimize for AMD Opteron/Athlon64/Hammer/K8 CPUs. config MPSC - bool "Intel x86-64" + bool "Intel x86-64" help Optimize for Intel IA32 with 64bit extension CPUs (Prescott/Nocona/Potomac) - + config GENERIC_CPU bool "Generic-x86-64" help @@ -130,8 +134,8 @@ tristate "/dev/cpu/microcode - Intel CPU microcode support" ---help--- If you say Y here the 'File systems' section, you will be - able to update the microcode on Intel processors. You will - obviously need the actual microcode binary data itself which is + able to update the microcode on Intel processors. You will + obviously need the actual microcode binary data itself which is not shipped with the Linux kernel. For latest news and information on obtaining all the required @@ -165,7 +169,7 @@ bool depends on SMP && !MK8 default y - + config MATH_EMULATION bool @@ -231,13 +235,13 @@ be preempted even if it is in kernel mode executing a system call. This allows applications to run more reliably even when the system is under load. On contrary it may also break your drivers and add - priority inheritance problems to your system. Don't select it if + priority inheritance problems to your system. Don't select it if you rely on a stable system or have slightly obscure hardware. It's also not very well tested on x86-64 currently. You have been warned. - Say Y here if you are feeling brave and building a kernel for a - desktop, embedded or real-time system. Say N if you are unsure. + Say Y here if you are feeling brave and building a kernel for a + desktop, embedded or real-time system. Say N if you are unsure. config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" @@ -297,7 +301,7 @@ properly with 32-bit PCI devices that do not support DAC (Double Address Cycle). The IOMMU can be turned off at runtime with the iommu=off parameter. Normally the kernel will take the right choice by itself. - If unsure say Y + If unsure, say Y. # need this always enabled with GART_IOMMU for the VIA workaround config SWIOTLB @@ -310,13 +314,18 @@ depends on !GART_IOMMU && !SWIOTLB default y help - Don't use IOMMU code. This will cause problems when you have more than 4GB + Don't use IOMMU code. This will cause problems when you have more than 4GB of memory and any 32-bit devices. Don't turn on unless you know what you are doing. config X86_MCE - bool + bool "Machine check support" if EMBEDDED default y + help + Include a machine check error handler to report hardware errors. + This version will require the mcelog utility to decode some + machine check error logs. See + ftp://ftp.x86-64.org/pub/linux/tools/mcelog endmenu @@ -336,17 +345,27 @@ config PCI bool "PCI support" -# x86-64 doesn't support PCI BIOS access from long mode so always go direct. +# x86-64 doesn't support PCI BIOS access from long mode so always go direct. config PCI_DIRECT bool depends on PCI default y -config PCI_MMCONFIG - bool "Support mmconfig PCI config space access" +config PCI_MMCONFIG + bool "Support mmconfig PCI config space access" depends on PCI select ACPI_BOOT +config UNORDERED_IO + bool "Unordered IO mapping access" + depends on EXPERIMENTAL + help + Use unordered stores to access IO memory mappings in device drivers. + Still very experimental. When a driver works on IA64/ppc64/pa-risc it should + work with this option, but it makes the drivers behave differently + from i386. Requires that the driver writer used memory barriers + properly. + source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" @@ -398,110 +417,10 @@ source "arch/x86_64/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - 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 . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -# !SMP for now because the context switch early causes GPF in segment reloading -# and the GS base checking does the wrong thing then, causing a hang. -config CHECKING - bool "Additional run-time checks" - depends on DEBUG_KERNEL && !SMP - help - Enables some internal consistency checks for kernel debugging. - You should normally say N. - -config INIT_DEBUG - bool "Debug __init statements" - depends on DEBUG_KERNEL - help - Fill __init and __initdata at the end of boot. This helps debugging - illegal uses of __init and __initdata after initialization. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - Please note that this option requires new binutils. - If you don't debug the kernel, you can say N. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - help - Compile the kernel with frame pointers. This may help for some - debugging with external debuggers. Note the standard oops backtracer - doesn't make use of this and the x86-64 kernel doesn't ensure an consistent - frame pointer through inline assembly (semaphores etc.) - Normally you should say N. - -config IOMMU_DEBUG - depends on GART_IOMMU && DEBUG_KERNEL - bool "Enable IOMMU debugging" - help - Force the IOMMU to on even when you have less than 4GB of - memory and add debugging code. On overflow always panic. And - allow to enable IOMMU leak tracing. Can be disabled at boot - time with iommu=noforce. This will also enable scatter gather - list merging. Currently not recommended for production - code. When you use it make sure you have a big enough - IOMMU/AGP aperture. Most of the options enabled by this can - be set more finegrained using the iommu= command line - options. See Documentation/x86_64/boot-options.txt for more - details. - -config IOMMU_LEAK - bool "IOMMU leak tracing" - depends on DEBUG_KERNEL - depends on IOMMU_DEBUG - 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" - -endmenu +source "arch/x86_64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff -Nru a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/x86_64/Kconfig.debug 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,59 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +# !SMP for now because the context switch early causes GPF in segment reloading +# and the GS base checking does the wrong thing then, causing a hang. +config CHECKING + bool "Additional run-time checks" + depends on DEBUG_KERNEL && !SMP + help + Enables some internal consistency checks for kernel debugging. + You should normally say N. + +config INIT_DEBUG + bool "Debug __init statements" + depends on DEBUG_KERNEL + help + Fill __init and __initdata at the end of boot. This helps debugging + illegal uses of __init and __initdata after initialization. + +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on DEBUG_KERNEL && PROC_FS + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. + +config IOMMU_DEBUG + depends on GART_IOMMU && DEBUG_KERNEL + bool "Enable IOMMU debugging" + help + Force the IOMMU to on even when you have less than 4GB of + memory and add debugging code. On overflow always panic. And + allow to enable IOMMU leak tracing. Can be disabled at boot + time with iommu=noforce. This will also enable scatter gather + list merging. Currently not recommended for production + code. When you use it make sure you have a big enough + IOMMU/AGP aperture. Most of the options enabled by this can + be set more finegrained using the iommu= command line + options. See Documentation/x86_64/boot-options.txt for more + details. + +config IOMMU_LEAK + bool "IOMMU leak tracing" + depends on DEBUG_KERNEL + depends on IOMMU_DEBUG + 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" + +endmenu diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile --- a/arch/x86_64/Makefile 2004-10-18 14:57:03 -07:00 +++ b/arch/x86_64/Makefile 2004-10-18 14:57:03 -07:00 @@ -37,10 +37,10 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := -e stext -CHECK := $(CHECK) -D__x86_64__=1 +CHECKFLAGS += -D__x86_64__ -m64 -cflags-$(CONFIG_MK8) += $(call check_gcc,-march=k8,) -cflags-$(CONFIG_MPSC) += $(call check_gcc,-march=nocona,) +cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8) +cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona) CFLAGS += $(cflags-y) CFLAGS += -mno-red-zone @@ -54,11 +54,11 @@ CFLAGS += -fno-asynchronous-unwind-tables # -fweb shrinks the kernel a bit, but the difference is very small # it also messes up debugging, so don't use it for now. -#CFLAGS += $(call check_gcc,-fweb,) +#CFLAGS += $(call cc-option,-fweb) endif # -funit-at-a-time shrinks the kernel .text considerably # unfortunately it makes reading oopses harder. -CFLAGS += $(call check_gcc,-funit-at-a-time,) +CFLAGS += $(call cc-option,-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 @@ -77,6 +77,7 @@ all: bzImage BOOTIMAGE := arch/x86_64/boot/bzImage +KBUILD_IMAGE := $(BOOTIMAGE) bzImage: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE) diff -Nru a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile --- a/arch/x86_64/boot/Makefile 2004-10-18 14:56:28 -07:00 +++ b/arch/x86_64/boot/Makefile 2004-10-18 14:56:28 -07:00 @@ -30,7 +30,7 @@ EXTRA_CFLAGS := -m32 -host-progs := tools/build +hostprogs-y := tools/build subdir- := compressed/ #Let make clean descend in compressed/ # --------------------------------------------------------------------------- diff -Nru a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S --- a/arch/x86_64/boot/video.S 2004-10-18 14:56:32 -07:00 +++ b/arch/x86_64/boot/video.S 2004-10-18 14:56:32 -07:00 @@ -66,6 +66,7 @@ #define VIDEO_80x30 0x0f05 #define VIDEO_80x34 0x0f06 #define VIDEO_80x60 0x0f07 +#define VIDEO_GFX_HACK 0x0f08 #define VIDEO_LAST_SPECIAL 0x0f09 /* Video modes given by resolution */ @@ -97,7 +98,6 @@ #define PARAM_LFB_PAGES 0x32 #define PARAM_VESA_ATTRIB 0x34 - /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ #ifdef CONFIG_VIDEO_RETAIN #define DO_STORE call store_screen @@ -133,6 +133,7 @@ #ifdef CONFIG_VIDEO_RETAIN call restore_screen # Restore screen contents #endif /* CONFIG_VIDEO_RETAIN */ + call store_edid #endif /* CONFIG_VIDEO_SELECT */ call mode_params # Store mode parameters popw %ds # Restore original DS @@ -231,6 +232,41 @@ xorl %eax, %eax movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE) + +# switching the DAC to 8-bit is for <= 8 bpp only + movw %fs:(PARAM_LFB_DEPTH), %ax + cmpw $8, %ax + jg dac_done + +# get DAC switching capability + xorl %eax, %eax + movb 10(%di), %al + testb $1, %al + jz dac_set + +# attempt to switch DAC to 8-bit + movw $0x4f08, %ax + movw $0x0800, %bx + int $0x10 + cmpw $0x004f, %ax + jne dac_set + movb %bh, dac_size # store actual DAC size + +dac_set: +# set color size to DAC size + movb dac_size, %al + movb %al, %fs:(PARAM_LFB_COLORS+0) + movb %al, %fs:(PARAM_LFB_COLORS+2) + movb %al, %fs:(PARAM_LFB_COLORS+4) + movb %al, %fs:(PARAM_LFB_COLORS+6) + +# set color offsets to 0 + movb $0, %fs:(PARAM_LFB_COLORS+1) + movb $0, %fs:(PARAM_LFB_COLORS+3) + movb $0, %fs:(PARAM_LFB_COLORS+5) + movb $0, %fs:(PARAM_LFB_COLORS+7) + +dac_done: # get protected mode interface informations movw $0x4f0a, %ax xorw %bx, %bx @@ -440,7 +476,7 @@ # Setting of user mode (AX=mode ID) => CF=success mode_set: - movw %ax, %fs:(0x01fa) + movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S movw %ax, %bx cmpb $0xff, %ah jz setalias @@ -744,7 +780,15 @@ movw $0x503c, force_size jmp setvde +# Special hack for ThinkPad graphics set_gfx: +#ifdef CONFIG_VIDEO_GFX_HACK + movw $VIDEO_GFX_BIOS_AX, %ax + movw $VIDEO_GFX_BIOS_BX, %bx + int $0x10 + movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size + stc +#endif ret #ifdef CONFIG_VIDEO_RETAIN @@ -969,6 +1013,10 @@ .word 0x5022 # 80x34 .word VIDEO_80x60 .word 0x503c # 80x60 +#ifdef CONFIG_VIDEO_GFX_HACK + .word VIDEO_GFX_HACK + .word VIDEO_GFX_DUMMY_RESOLUTION +#endif vga_modes_end: # Detect VESA modes. @@ -1875,6 +1923,39 @@ popw %ax ret +store_edid: + pushw %es # just save all registers + pushw %ax + pushw %bx + pushw %cx + pushw %dx + pushw %di + + pushw %fs + popw %es + + movl $0x13131313, %eax # memset block with 0x13 + movw $32, %cx + movw $0x440, %di + cld + rep + stosl + + movw $0x4f15, %ax # do VBE/DDC + movw $0x01, %bx + movw $0x00, %cx + movw $0x01, %dx + movw $0x440, %di + int $0x10 + + popw %di # restore all registers + popw %dx + popw %cx + popw %bx + popw %ax + popw %es + ret + # VIDEO_SELECT-only variables mt_end: .word 0 # End of video mode table if built edit_buf: .space 6 # Line editor buffer @@ -1883,6 +1964,7 @@ do_restore: .byte 0 # Screen contents altered during mode change svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes graphic_mode: .byte 0 # Graphic mode with a linear frame buffer +dac_size: .byte 6 # DAC bit depth # Status messages keymsg: .ascii "Press to see video modes available, " diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig --- a/arch/x86_64/defconfig 2004-10-18 14:56:48 -07:00 +++ b/arch/x86_64/defconfig 2004-10-18 14:56:48 -07:00 @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc1-bk19 +# Sun Sep 12 23:13:23 2004 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -17,11 +19,11 @@ # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -35,6 +37,7 @@ # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -42,6 +45,8 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -123,6 +128,8 @@ CONFIG_PCI=y CONFIG_PCI_DIRECT=y CONFIG_PCI_MMCONFIG=y +CONFIG_UNORDERED_IO=y +CONFIG_PCI_MSI=y # CONFIG_PCI_LEGACY_PROC is not set # CONFIG_PCI_NAMES is not set @@ -144,6 +151,8 @@ # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_DEBUG_DRIVER is not set # @@ -171,7 +180,8 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_CARMEL is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -186,10 +196,10 @@ # # Please see Documentation/ide.txt for help/info on IDE drives # +# CONFIG_BLK_DEV_IDE_SATA is not set # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -273,16 +283,24 @@ # SCSI low-level drivers # CONFIG_BLK_DEV_3W_XXXX_RAID=y +# CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +CONFIG_SCSI_AIC79XX=y +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=4000 +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_SVW is not set CONFIG_SCSI_ATA_PIIX=y +# CONFIG_SCSI_SATA_NV is not set # CONFIG_SCSI_SATA_PROMISE is not set # CONFIG_SCSI_SATA_SX4 is not set # CONFIG_SCSI_SATA_SIL is not set @@ -290,7 +308,6 @@ CONFIG_SCSI_SATA_VIA=y # CONFIG_SCSI_SATA_VITESSE is not set # CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set @@ -324,7 +341,6 @@ # CONFIG_FUSION=y CONFIG_FUSION_MAX_SGE=40 -# CONFIG_FUSION_ISENSE is not set # CONFIG_FUSION_CTL is not set # @@ -362,11 +378,13 @@ # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set @@ -392,6 +410,7 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -452,6 +471,7 @@ # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set # # Ethernet (1000 Mbit) @@ -575,7 +595,6 @@ CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -602,6 +621,9 @@ # CONFIG_DRM is not set # CONFIG_MWAVE is not set CONFIG_RAW_DRIVER=y +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y CONFIG_MAX_RAW_DEVS=256 CONFIG_HANGCHECK_TIMER=y @@ -611,6 +633,11 @@ # CONFIG_I2C is not set # +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# # Misc devices # # CONFIG_IBM_ASM is not set @@ -635,7 +662,6 @@ # Console display driver support # CONFIG_VGA_CONSOLE=y -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y # @@ -686,6 +712,8 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -706,6 +734,7 @@ CONFIG_USB_PRINTER=y CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set @@ -830,7 +859,8 @@ # # DOS/FAT/NT Filesystems # -# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set # CONFIG_NTFS_FS is not set # @@ -879,6 +909,7 @@ CONFIG_EXPORTFS=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set @@ -906,12 +937,14 @@ # Kernel hacking # CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SLAB is not set CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_INIT_DEBUG is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_INFO is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_INIT_DEBUG is not set +# CONFIG_SCHEDSTATS is not set # CONFIG_IOMMU_DEBUG is not set # @@ -927,5 +960,6 @@ # # Library routines # +# CONFIG_CRC_CCITT is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c --- a/arch/x86_64/ia32/ia32_binfmt.c 2004-10-18 14:55:54 -07:00 +++ b/arch/x86_64/ia32/ia32_binfmt.c 2004-10-18 14:55:54 -07:00 @@ -301,6 +301,9 @@ #define elf_addr_t __u32 +#undef TASK_SIZE +#define TASK_SIZE 0xffffffff + static void elf32_init(struct pt_regs *); #include "../../../fs/binfmt_elf.c" @@ -365,7 +368,7 @@ mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? PAGE_COPY_EXEC : PAGE_COPY; insert_vm_struct(mm, mpnt); - mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + mm->stack_vm = mm->total_vm = vma_pages(mpnt); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c --- a/arch/x86_64/ia32/ia32_ioctl.c 2004-10-18 14:56:32 -07:00 +++ b/arch/x86_64/ia32/ia32_ioctl.c 2004-10-18 14:56:32 -07:00 @@ -171,23 +171,8 @@ COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS) COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) COMPATIBLE_IOCTL(BLKRASET) -COMPATIBLE_IOCTL(BLKFRASET) COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ -COMPATIBLE_IOCTL(RTC_AIE_ON) -COMPATIBLE_IOCTL(RTC_AIE_OFF) -COMPATIBLE_IOCTL(RTC_UIE_ON) -COMPATIBLE_IOCTL(RTC_UIE_OFF) -COMPATIBLE_IOCTL(RTC_PIE_ON) -COMPATIBLE_IOCTL(RTC_PIE_OFF) -COMPATIBLE_IOCTL(RTC_WIE_ON) -COMPATIBLE_IOCTL(RTC_WIE_OFF) -COMPATIBLE_IOCTL(RTC_ALM_SET) -COMPATIBLE_IOCTL(RTC_ALM_READ) -COMPATIBLE_IOCTL(RTC_RD_TIME) -COMPATIBLE_IOCTL(RTC_SET_TIME) -COMPATIBLE_IOCTL(RTC_WKALM_SET) -COMPATIBLE_IOCTL(RTC_WKALM_RD) COMPATIBLE_IOCTL(FIOQSIZE) /* And these ioctls need translation */ diff -Nru a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c --- a/arch/x86_64/ia32/ia32_signal.c 2004-10-18 14:57:04 -07:00 +++ b/arch/x86_64/ia32/ia32_signal.c 2004-10-18 14:57:04 -07:00 @@ -115,7 +115,8 @@ } asmlinkage long -sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs) +sys32_sigsuspend(int history0, int history1, old_sigset_t mask, + struct pt_regs *regs) { sigset_t saveset; @@ -126,11 +127,11 @@ recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - regs.rax = -EINTR; + regs->rax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(®s, &saveset)) + if (do_signal(regs, &saveset)) return -EINTR; } } @@ -138,7 +139,7 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, stack_ia32_t __user *uoss_ptr, - struct pt_regs regs) + struct pt_regs *regs) { stack_t uss,uoss; int ret; @@ -155,7 +156,7 @@ } seg = get_fs(); set_fs(KERNEL_DS); - ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs.rsp); + ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->rsp); set_fs(seg); if (ret >= 0 && uoss_ptr) { if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) || @@ -274,9 +275,9 @@ return 1; } -asmlinkage long sys32_sigreturn(struct pt_regs regs) +asmlinkage long sys32_sigreturn(struct pt_regs *regs) { - struct sigframe __user *frame = (struct sigframe __user *)(regs.rsp-8); + struct sigframe __user *frame = (struct sigframe __user *)(regs->rsp-8); sigset_t set; unsigned int eax; @@ -294,20 +295,23 @@ recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (ia32_restore_sigcontext(®s, &frame->sc, &eax)) + if (ia32_restore_sigcontext(regs, &frame->sc, &eax)) goto badframe; return eax; badframe: - signal_fault(®s, frame, "32bit sigreturn"); + signal_fault(regs, frame, "32bit sigreturn"); return 0; } -asmlinkage long sys32_rt_sigreturn(struct pt_regs regs) +asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) { - struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs.rsp - 4); + struct rt_sigframe __user *frame; sigset_t set; unsigned int eax; + struct pt_regs tregs; + + frame = (struct rt_sigframe __user *)(regs->rsp - 4); if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -320,16 +324,17 @@ recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (ia32_restore_sigcontext(®s, &frame->uc.uc_mcontext, &eax)) + if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) goto badframe; - if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, regs) == -EFAULT) + tregs = *regs; + if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT) goto badframe; return eax; badframe: - signal_fault(®s,frame,"32bit rt sigreturn"); + signal_fault(regs,frame,"32bit rt sigreturn"); return 0; } @@ -342,6 +347,7 @@ struct pt_regs *regs, unsigned int mask) { int tmp, err = 0; + u32 eflags; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); @@ -366,7 +372,11 @@ err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user((u32)regs->rip, &sc->eip); - err |= __put_user((u32)regs->eflags, &sc->eflags); + eflags = regs->eflags; + if (current->ptrace & PT_PTRACED) { + eflags &= ~TF_MASK; + } + err |= __put_user((u32)eflags, &sc->eflags); err |= __put_user((u32)regs->rsp, &sc->esp_at_signal); tmp = save_i387_ia32(current, fpstate, regs, 0); @@ -484,7 +494,13 @@ regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -494,9 +510,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - signal_fault(regs,frame,"32bit signal deliver"); + force_sigsegv(sig, current); } void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -580,7 +594,13 @@ regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -590,8 +610,6 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - signal_fault(regs, frame, "32bit rt signal setup"); + force_sigsegv(sig, current); } diff -Nru a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S --- a/arch/x86_64/ia32/ia32entry.S 2004-10-18 14:56:29 -07:00 +++ b/arch/x86_64/ia32/ia32entry.S 2004-10-18 14:56:29 -07:00 @@ -270,35 +270,32 @@ ret CFI_ENDPROC - .macro PTREGSCALL label, func + .macro PTREGSCALL label, func, arg .globl \label \label: leaq \func(%rip),%rax + leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */ jmp ia32_ptregs_common .endm - PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn - PTREGSCALL stub32_sigreturn, sys32_sigreturn - PTREGSCALL stub32_sigaltstack, sys32_sigaltstack - PTREGSCALL stub32_sigsuspend, sys32_sigsuspend - PTREGSCALL stub32_execve, sys32_execve - PTREGSCALL stub32_fork, sys_fork - PTREGSCALL stub32_clone, sys32_clone - PTREGSCALL stub32_vfork, sys_vfork - PTREGSCALL stub32_iopl, sys_iopl - PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend + PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi + PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi + PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx + PTREGSCALL stub32_sigsuspend, sys32_sigsuspend, %rcx + PTREGSCALL stub32_execve, sys32_execve, %rcx + PTREGSCALL stub32_fork, sys_fork, %rdi + PTREGSCALL stub32_clone, sys32_clone, %rdx + PTREGSCALL stub32_vfork, sys_vfork, %rdi + PTREGSCALL stub32_iopl, sys_iopl, %rsi + PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx ENTRY(ia32_ptregs_common) CFI_STARTPROC popq %r11 SAVE_REST - movq %r11, %r15 call *%rax - movq %r15, %r11 RESTORE_REST - leaq ia32_sysret(%rip),%r11 - pushq %r11 - ret + jmp ia32_sysret /* misbalances the return cache */ CFI_ENDPROC .data @@ -332,7 +329,7 @@ .quad sys_getuid16 .quad sys_stime /* stime */ /* 25 */ .quad sys32_ptrace /* ptrace */ - .quad sys_alarm /* XXX sign extension??? */ + .quad sys_alarm .quad sys_fstat /* (old)fstat */ .quad sys_pause .quad compat_sys_utime /* 30 */ @@ -558,7 +555,7 @@ .quad sys_fadvise64 /* 250 */ .quad quiet_ni_syscall /* free_huge_pages */ .quad sys_exit_group - .quad sys_lookup_dcookie + .quad sys32_lookup_dcookie .quad sys_epoll_create .quad sys_epoll_ctl /* 255 */ .quad sys_epoll_wait @@ -589,6 +586,7 @@ .quad compat_sys_mq_notify .quad compat_sys_mq_getsetattr .quad quiet_ni_syscall /* reserved for kexec */ + .quad sys32_waitid /* don't forget to change IA32_NR_syscalls */ ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 diff -Nru a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c --- a/arch/x86_64/ia32/ptrace32.c 2004-10-18 14:56:27 -07:00 +++ b/arch/x86_64/ia32/ptrace32.c 2004-10-18 14:56:27 -07:00 @@ -249,8 +249,8 @@ case PTRACE_GETFPREGS: case PTRACE_SETFPXREGS: case PTRACE_GETFPXREGS: + case PTRACE_GETEVENTMSG: break; - } child = find_target(request, pid, &ret); @@ -362,6 +362,10 @@ ret = 0; break; } + + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message,(unsigned int __user *)(u64)data); + break; default: ret = -EINVAL; diff -Nru a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c --- a/arch/x86_64/ia32/sys_ia32.c 2004-10-18 14:56:29 -07:00 +++ b/arch/x86_64/ia32/sys_ia32.c 2004-10-18 14:56:29 -07:00 @@ -1125,7 +1125,7 @@ } asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv, - compat_uptr_t __user *envp, struct pt_regs regs) + compat_uptr_t __user *envp, struct pt_regs *regs) { long error; char * filename; @@ -1134,21 +1134,47 @@ error = PTR_ERR(filename); if (IS_ERR(filename)) return error; - error = compat_do_execve(filename, argv, envp, ®s); + error = compat_do_execve(filename, argv, envp, regs); if (error == 0) current->ptrace &= ~PT_DTRACE; putname(filename); return error; } -asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs) +asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, + struct pt_regs *regs) { - void __user *parent_tid = (void __user *)regs.rdx; - void __user *child_tid = (void __user *)regs.rdi; + void __user *parent_tid = (void __user *)regs->rdx; + void __user *child_tid = (void __user *)regs->rdi; if (!newsp) - newsp = regs.rsp; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, - parent_tid, child_tid); + newsp = regs->rsp; + return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); +} + +asmlinkage long sys32_waitid(int which, compat_pid_t pid, + siginfo_t32 __user *uinfo, int options, + struct compat_rusage __user *uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + info.si_signo = 0; + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, + uru ? &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru && (ret = put_compat_rusage(&ru, uru))) + return ret; + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return ia32_copy_siginfo_to_user(uinfo, &info); } /* @@ -1262,7 +1288,7 @@ if (fd >= 0) { struct file *f = filp_open(tmp, flags, mode); error = PTR_ERR(f); - if (unlikely(IS_ERR(f))) { + if (IS_ERR(f)) { put_unused_fd(fd); fd = error; } else @@ -1336,6 +1362,12 @@ } return -ENOSYS; } + +long sys32_lookup_dcookie(u32 addr_low, u32 addr_high, + char __user * buf, size_t len) +{ + return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len); +} cond_syscall(sys32_ipc) diff -Nru a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c --- a/arch/x86_64/ia32/syscall32.c 2004-10-18 14:56:33 -07:00 +++ b/arch/x86_64/ia32/syscall32.c 2004-10-18 14:56:33 -07:00 @@ -30,16 +30,20 @@ char *syscall32_page; static int use_sysenter __initdata = -1; -/* RED-PEN: This knows too much about high level VM */ -/* Alternative would be to generate a vma with appropriate backing options - and let it be handled by generic VM */ -int map_syscall32(struct mm_struct *mm, unsigned long address) +/* + * Map the 32bit vsyscall page on demand. + * + * RED-PEN: This knows too much about high level VM. + * + * Alternative would be to generate a vma with appropriate backing options + * and let it be handled by generic VM. + */ +int __map_syscall32(struct mm_struct *mm, unsigned long address) { pte_t *pte; pmd_t *pmd; int err = 0; - down_read(&mm->mmap_sem); spin_lock(&mm->page_table_lock); pmd = pmd_alloc(mm, pgd_offset(mm, address), address); if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) { @@ -54,6 +58,14 @@ } else err = -ENOMEM; spin_unlock(&mm->page_table_lock); + return err; +} + +int map_syscall32(struct mm_struct *mm, unsigned long address) +{ + int err; + down_read(&mm->mmap_sem); + err = __map_syscall32(mm, address); up_read(&mm->mmap_sem); return err; } @@ -76,7 +88,8 @@ __initcall(init_syscall32); -void __init syscall32_cpu_init(void) +/* May not be __init: called during resume */ +void syscall32_cpu_init(void) { if (use_sysenter < 0) use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL); diff -Nru a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile --- a/arch/x86_64/kernel/Makefile 2004-10-18 14:56:49 -07:00 +++ b/arch/x86_64/kernel/Makefile 2004-10-18 14:56:49 -07:00 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o head64.o init_task.o vmlinux.lds.s +extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \ @@ -25,7 +25,6 @@ obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o obj-$(CONFIG_SWIOTLB) += swiotlb.o -obj-$(CONFIG_SCHED_SMT) += domain.o obj-$(CONFIG_MODULES) += module.o diff -Nru a/arch/x86_64/kernel/Makefile-HEAD b/arch/x86_64/kernel/Makefile-HEAD --- a/arch/x86_64/kernel/Makefile-HEAD 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,38 +0,0 @@ -# -# Makefile for the linux kernel. -# - -extra-y := head.o head64.o init_task.o vmlinux.lds.s -EXTRA_AFLAGS := -traditional -obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ - ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \ - x8664_ksyms.o i387.o syscall.o vsyscall.o \ - setup64.o bootflag.o e820.o reboot.o warmreboot.o -obj-y += mce.o - -obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ -obj-$(CONFIG_ACPI_BOOT) += acpi/ -obj-$(CONFIG_X86_MSR) += msr.o -obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o -obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o -obj-$(CONFIG_PM) += suspend.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o -obj-$(CONFIG_CPU_FREQ) += cpufreq/ -obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o -obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o -obj-$(CONFIG_SWIOTLB) += swiotlb.o -obj-$(CONFIG_SCHED_SMT) += domain.o - -obj-$(CONFIG_MODULES) += module.o - -obj-y += topology.o - -bootflag-y += ../../i386/kernel/bootflag.o -cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o -topology-y += ../../i386/mach-default/topology.o -swiotlb-$(CONFIG_SWIOTLB) += ../../ia64/lib/swiotlb.o -microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o diff -Nru a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c --- a/arch/x86_64/kernel/aperture.c 2004-10-18 14:56:49 -07:00 +++ b/arch/x86_64/kernel/aperture.c 2004-10-18 14:56:49 -07:00 @@ -31,6 +31,8 @@ int fallback_aper_order __initdata = 1; /* 64MB */ int fallback_aper_force __initdata = 0; +int fix_aperture __initdata = 1; + /* This code runs before the PCI subsystem is initialized, so just access the northbridge directly. */ @@ -202,7 +204,7 @@ u64 aper_base; int valid_agp = 0; - if (iommu_aperture_disabled) + if (iommu_aperture_disabled || !fix_aperture) return; printk("Checking aperture...\n"); @@ -241,20 +243,15 @@ /* Got the aperture from the AGP bridge */ } else if ((!no_iommu && end_pfn >= 0xffffffff>>PAGE_SHIFT) || force_iommu || - valid_agp || + valid_agp || fallback_aper_force) { - /* When there is a AGP bridge in the system assume the - user wants to use the AGP driver too and needs an - aperture. However this case (AGP but no good - aperture) should only happen with a more broken than - usual BIOS, because it would even break Windows. */ - - printk("Your BIOS doesn't leave a aperture memory hole\n"); - printk("Please enable the IOMMU option in the BIOS setup\n"); - printk("This costs you %d MB of RAM\n", 32 << fallback_aper_order); - + printk("Your BIOS doesn't leave a aperture memory hole\n"); + printk("Please enable the IOMMU option in the BIOS setup\n"); + printk("This costs you %d MB of RAM\n", + 32 << fallback_aper_order); + aper_order = fallback_aper_order; - aper_alloc = allocate_aperture(); + aper_alloc = allocate_aperture(); if (!aper_alloc) { /* Could disable AGP and IOMMU here, but it's probably not worth it. But the later users cannot deal with diff -Nru a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c --- a/arch/x86_64/kernel/apic.c 2004-10-18 14:56:11 -07:00 +++ b/arch/x86_64/kernel/apic.c 2004-10-18 14:56:11 -07:00 @@ -33,6 +33,8 @@ #include #include +int apic_verbosity; + int disable_apic_timer __initdata; /* Using APIC to generate smp_local_timer_interrupt? */ @@ -123,7 +125,7 @@ * PIC mode, enable APIC mode in the IMCR, i.e. * connect BSP's local APIC to INT and NMI lines. */ - printk(KERN_INFO "leaving PIC mode, enabling APIC mode.\n"); + apic_printk(APIC_VERBOSE, "leaving PIC mode, enabling APIC mode.\n"); outb(0x70, 0x22); outb(0x01, 0x23); } @@ -138,7 +140,7 @@ * interrupts, including IPIs, won't work beyond * this point! The only exception are INIT IPIs. */ - printk(KERN_INFO "disabling APIC mode, entering PIC mode.\n"); + apic_printk(APIC_QUIET, "disabling APIC mode, entering PIC mode.\n"); outb(0x70, 0x22); outb(0x00, 0x23); } @@ -172,10 +174,10 @@ * The version register is read-only in a real APIC. */ reg0 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg0); apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); reg1 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg1); /* * The two version reads above should print the same @@ -199,10 +201,10 @@ * The ID register is read/write in a real APIC. */ reg0 = apic_read(APIC_ID); - Dprintk("Getting ID: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); reg1 = apic_read(APIC_ID); - Dprintk("Getting ID: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); apic_write(APIC_ID, reg0); if (reg1 != (reg0 ^ APIC_ID_MASK)) return 0; @@ -213,9 +215,9 @@ * compatibility mode, but most boxes are anymore. */ reg0 = apic_read(APIC_LVT0); - Dprintk("Getting LVT0: %x\n", reg0); + apic_printk(APIC_DEBUG,"Getting LVT0: %x\n", reg0); reg1 = apic_read(APIC_LVT1); - Dprintk("Getting LVT1: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting LVT1: %x\n", reg1); return 1; } @@ -227,7 +229,7 @@ */ apic_wait_icr_idle(); - Dprintk("Synchronizing Arb IDs.\n"); + apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n"); apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT); } @@ -388,10 +390,10 @@ value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; if (!smp_processor_id() && (pic_mode || !value)) { value = APIC_DM_EXTINT; - Dprintk(KERN_INFO "enabled ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id()); } else { value = APIC_DM_EXTINT | APIC_LVT_MASKED; - Dprintk(KERN_INFO "masked ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id()); } apic_write_around(APIC_LVT0, value); @@ -407,12 +409,11 @@ apic_write_around(APIC_LVT1, value); if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */ + unsigned oldvalue; maxlvt = get_maxlvt(); if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); - value = apic_read(APIC_ESR); - Dprintk("ESR value before enabling vector: %08x\n", value); - + oldvalue = apic_read(APIC_ESR); value = ERROR_APIC_VECTOR; // enables sending errors apic_write_around(APIC_LVTERR, value); /* @@ -421,7 +422,10 @@ if (maxlvt > 3) apic_write(APIC_ESR, 0); value = apic_read(APIC_ESR); - Dprintk("ESR value after enabling vector: %08x\n", value); + if (value != oldvalue) + apic_printk(APIC_VERBOSE, + "ESR value after enabling vector: %08x, after %08x\n", + oldvalue, value); } else { if (esr_disable) /* @@ -430,9 +434,9 @@ * ESR disabled - we can't do anything useful with the * errors anyway - mbligh */ - printk("Leaving ESR disabled.\n"); + apic_printk(APIC_DEBUG, "Leaving ESR disabled.\n"); else - printk("No ESR for 82489DX.\n"); + apic_printk(APIC_DEBUG, "No ESR for 82489DX.\n"); } nmi_watchdog_default(); @@ -564,6 +568,21 @@ #endif /* CONFIG_PM */ +static int __init apic_set_verbosity(char *str) +{ + if (strcmp("debug", str) == 0) + apic_verbosity = APIC_DEBUG; + else if (strcmp("verbose", str) == 0) + apic_verbosity = APIC_VERBOSE; + else + printk(KERN_WARNING "APIC Verbosity level %s not recognised" + " use apic=verbose or apic=debug", str); + + return 0; +} + +__setup("apic=", apic_set_verbosity); + /* * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. @@ -599,7 +618,7 @@ apic_phys = mp_lapic_addr; set_fixmap_nocache(FIX_APIC_BASE, apic_phys); - Dprintk("mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); + apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); /* * Fetch the APIC ID of the BSP in case we have a @@ -621,7 +640,7 @@ ioapic_phys = __pa(ioapic_phys); } set_fixmap_nocache(idx, ioapic_phys); - Dprintk("mapped IOAPIC to %016lx (%016lx)\n", + apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n", __fix_to_virt(idx), ioapic_phys); idx++; } @@ -836,8 +855,7 @@ { int cpu = smp_processor_id(); - x86_do_profile(regs); - + profile_tick(CPU_PROFILING, regs); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got @@ -962,7 +980,7 @@ 6: Received illegal vector 7: Illegal register address */ - printk (KERN_INFO "APIC error on CPU%d: %02x(%02x)\n", + printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", smp_processor_id(), v , v1); irq_exit(); } diff -Nru a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c --- a/arch/x86_64/kernel/asm-offsets.c 2004-10-18 14:56:32 -07:00 +++ b/arch/x86_64/kernel/asm-offsets.c 2004-10-18 14:56:32 -07:00 @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include #include #include diff -Nru a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig --- a/arch/x86_64/kernel/cpufreq/Kconfig 2004-10-18 14:57:04 -07:00 +++ b/arch/x86_64/kernel/cpufreq/Kconfig 2004-10-18 14:57:04 -07:00 @@ -41,4 +41,58 @@ If in doubt, say N. +config X86_POWERNOW_K8_ACPI + bool + depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y")) + default y + +config X86_SPEEDSTEP_CENTRINO + tristate "Intel Enhanced SpeedStep" + depends on CPU_FREQ_TABLE + help + This adds the CPUFreq driver for Enhanced SpeedStep enabled + mobile CPUs. This means Intel Pentium M (Centrino) CPUs + or 64bit enabled Intel Xeons. + + For details, take a look at . + + If in doubt, say N. + +config X86_SPEEDSTEP_CENTRINO_TABLE + bool + depends on X86_SPEEDSTEP_CENTRINO + default y + +config X86_SPEEDSTEP_CENTRINO_ACPI + bool "Use ACPI tables to decode valid frequency/voltage pairs (EXPERIMENTAL)" + depends on EXPERIMENTAL + depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y")) + help + Use primarily the information provided in the BIOS ACPI tables + to determine valid CPU frequency and voltage pairings. + + If in doubt, say Y. + +config X86_ACPI_CPUFREQ + tristate "ACPI Processor P-States driver" + depends on CPU_FREQ_TABLE && ACPI_PROCESSOR + help + This driver adds a CPUFreq driver which utilizes the ACPI + Processor Performance States. + + For details, take a look at . + + If in doubt, say N. + +config X86_ACPI_CPUFREQ_PROC_INTF + bool "/proc/acpi/processor/../performance interface (deprecated)" + depends on X86_ACPI_CPUFREQ && PROC_FS + help + This enables the deprecated /proc/acpi/processor/../performance + interface. While it is helpful for debugging, the generic, + cross-architecture cpufreq interfaces should be used. + + If in doubt, say N. + endmenu + diff -Nru a/arch/x86_64/kernel/cpufreq/Makefile b/arch/x86_64/kernel/cpufreq/Makefile --- a/arch/x86_64/kernel/cpufreq/Makefile 2004-10-18 14:56:28 -07:00 +++ b/arch/x86_64/kernel/cpufreq/Makefile 2004-10-18 14:56:28 -07:00 @@ -2,6 +2,12 @@ # Reuse the i386 cpufreq drivers # +SRCDIR := ../../../i386/kernel/cpu/cpufreq + obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o +obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o +obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi.o -powernow-k8-objs := ../../../i386/kernel/cpu/cpufreq/powernow-k8.o +powernow-k8-objs := ${SRCDIR}/powernow-k8.o +speedstep-centrino-objs := ${SRCDIR}/speedstep-centrino.o +acpi-objs := ${SRCDIR}/acpi.o diff -Nru a/arch/x86_64/kernel/domain.c b/arch/x86_64/kernel/domain.c --- a/arch/x86_64/kernel/domain.c 2004-10-18 14:56:27 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,93 +0,0 @@ -#include -#include - -/* Don't do any NUMA setup on Opteron right now. They seem to be - better off with flat scheduling. This is just for SMT. */ - -#ifdef CONFIG_SCHED_SMT - -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, cpu_domains); -static DEFINE_PER_CPU(struct sched_domain, phys_domains); -__init void arch_init_sched_domains(void) -{ - int i; - struct sched_group *first = NULL, *last = NULL; - - /* Set up domains */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - struct sched_domain *phys_domain = &per_cpu(phys_domains, i); - - *cpu_domain = SD_SIBLING_INIT; - /* Disable SMT NICE for CMP */ - /* RED-PEN use a generic flag */ - if (cpu_data[i].x86_vendor == X86_VENDOR_AMD) - cpu_domain->flags &= ~SD_SHARE_CPUPOWER; - cpu_domain->span = cpu_sibling_map[i]; - cpu_domain->parent = phys_domain; - cpu_domain->groups = &sched_group_cpus[i]; - - *phys_domain = SD_CPU_INIT; - phys_domain->span = cpu_possible_map; - phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)]; - } - - /* Set up CPU (sibling) groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - int j; - first = last = 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); - cpu->cpu_power = SCHED_LOAD_SCALE; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - } - - first = last = NULL; - /* Set up physical groups */ - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - struct sched_group *cpu = &sched_group_phys[i]; - - if (i != first_cpu(cpu_domain->span)) - continue; - - cpu->cpumask = cpu_domain->span; - /* - * Make each extra sibling increase power by 10% of - * the basic CPU. This is very arbitrary. - */ - cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10; - - if (!first) - first = cpu; - if (last) - last->next = cpu; - last = cpu; - } - last->next = first; - - mb(); - for_each_cpu(i) { - struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); - cpu_attach_domain(cpu_domain, i); - } -} - -#endif diff -Nru a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c --- a/arch/x86_64/kernel/early_printk.c 2004-10-18 14:56:48 -07:00 +++ b/arch/x86_64/kernel/early_printk.c 2004-10-18 14:56:48 -07:00 @@ -8,7 +8,7 @@ /* Simple VGA output */ #ifdef __i386__ -#define VGABASE __pa(__PAGE_OFFSET + 0xb8000UL) +#define VGABASE (__ISA_IO_base + 0xb8000) #else #define VGABASE 0xffffffff800b8000UL #endif @@ -99,18 +99,17 @@ #define DEFAULT_BAUD 9600 -static __init void early_serial_init(char *opt) +static __init void early_serial_init(char *s) { unsigned char c; unsigned divisor; unsigned baud = DEFAULT_BAUD; - char *s, *e; + char *e; - if (*opt == ',') - ++opt; + if (*s == ',') + ++s; - s = strsep(&opt, ","); - if (s != NULL) { + if (*s) { unsigned port; if (!strncmp(s,"0x",2)) { early_serial_base = simple_strtoul(s, &e, 16); @@ -124,6 +123,9 @@ port = 0; early_serial_base = bases[port]; } + s += strcspn(s, ","); + if (*s == ',') + s++; } outb(0x3, early_serial_base + LCR); /* 8n1 */ @@ -131,8 +133,7 @@ outb(0, early_serial_base + FCR); /* no fifo */ outb(0x3, early_serial_base + MCR); /* DTR + RTS */ - s = strsep(&opt, ","); - if (s != NULL) { + if (*s) { baud = simple_strtoul(s, &e, 0); if (baud == 0 || s == e) baud = DEFAULT_BAUD; diff -Nru a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S --- a/arch/x86_64/kernel/entry.S 2004-10-18 14:56:28 -07:00 +++ b/arch/x86_64/kernel/entry.S 2004-10-18 14:56:28 -07:00 @@ -297,7 +297,7 @@ sti SAVE_REST /* Check for syscall exit trace */ - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),%edx + testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx jz int_signal pushq %rdi leaq 8(%rsp),%rdi # &ptregs -> arg1 @@ -305,6 +305,7 @@ popq %rdi btr $TIF_SYSCALL_TRACE,%edi btr $TIF_SYSCALL_AUDIT,%edi + btr $TIF_SINGLESTEP,%edi jmp int_restore_rest int_signal: @@ -323,19 +324,20 @@ * Certain special system calls that need to save a complete full stack frame. */ - .macro PTREGSCALL label,func + .macro PTREGSCALL label,func,arg .globl \label \label: leaq \func(%rip),%rax + leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */ jmp ptregscall_common .endm - PTREGSCALL stub_clone, sys_clone - PTREGSCALL stub_fork, sys_fork - PTREGSCALL stub_vfork, sys_vfork - PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend - PTREGSCALL stub_sigaltstack, sys_sigaltstack - PTREGSCALL stub_iopl, sys_iopl + PTREGSCALL stub_clone, sys_clone, %r8 + PTREGSCALL stub_fork, sys_fork, %rdi + PTREGSCALL stub_vfork, sys_vfork, %rdi + PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx + PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx + PTREGSCALL stub_iopl, sys_iopl, %rsi ENTRY(ptregscall_common) CFI_STARTPROC @@ -385,6 +387,7 @@ CFI_STARTPROC addq $8, %rsp SAVE_REST + movq %rsp,%rdi FIXUP_TOP_OF_STACK %r11 call sys_rt_sigreturn movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer diff -Nru a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c --- a/arch/x86_64/kernel/i8259.c 2004-10-18 14:56:13 -07:00 +++ b/arch/x86_64/kernel/i8259.c 2004-10-18 14:56:13 -07:00 @@ -329,7 +329,7 @@ * lets ACK and report it. [once per IRQ] */ if (!(spurious_irq_mask & irqmask)) { - printk("spurious 8259A interrupt: IRQ%d.\n", irq); + printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } atomic_inc(&irq_err_count); @@ -342,7 +342,7 @@ } } -void __init init_8259A(int auto_eoi) +void init_8259A(int auto_eoi) { unsigned long flags; @@ -384,6 +384,57 @@ spin_unlock_irqrestore(&i8259A_lock, flags); } + +static char irq_trigger[2]; +/** + * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ + */ +static void restore_ELCR(char *trigger) +{ + outb(trigger[0], 0x4d0); + outb(trigger[1], 0x4d1); +} + +static void save_ELCR(char *trigger) +{ + /* IRQ 0,1,2,8,13 are marked as reserved */ + trigger[0] = inb(0x4d0) & 0xF8; + trigger[1] = inb(0x4d1) & 0xDE; +} + +static int i8259A_resume(struct sys_device *dev) +{ + init_8259A(0); + restore_ELCR(irq_trigger); + return 0; +} + +static int i8259A_suspend(struct sys_device *dev, u32 state) +{ + save_ELCR(irq_trigger); + return 0; +} + +static struct sysdev_class i8259_sysdev_class = { + set_kset_name("i8259"), + .suspend = i8259A_suspend, + .resume = i8259A_resume, +}; + +static struct sys_device device_i8259A = { + .id = 0, + .cls = &i8259_sysdev_class, +}; + +static int __init i8259A_init_sysfs(void) +{ + int error = sysdev_class_register(&i8259_sysdev_class); + if (!error) + error = sysdev_register(&device_i8259A); + return error; +} + +device_initcall(i8259A_init_sysfs); /* * IRQ2 is cascade interrupt to second interrupt controller diff -Nru a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c --- a/arch/x86_64/kernel/init_task.c 2004-10-18 14:56:32 -07:00 +++ b/arch/x86_64/kernel/init_task.c 2004-10-18 14:56:32 -07:00 @@ -44,8 +44,7 @@ * 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; - +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp; #define ALIGN_TO_4K __attribute__((section(".data.init_task"))) diff -Nru a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c --- a/arch/x86_64/kernel/io_apic.c 2004-10-18 14:56:32 -07:00 +++ b/arch/x86_64/kernel/io_apic.c 2004-10-18 14:56:32 -07:00 @@ -30,12 +30,15 @@ #include #include #include +#include #include #include #include #include +#define __apicdebuginit __init + int sis_apic_bug; /* not actually supported, dummy for compile */ #undef APIC_LOCKUP_DEBUG @@ -292,13 +295,13 @@ pirq_entries[i] = -1; pirqs_enabled = 1; - printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); + apic_printk(APIC_VERBOSE, "PIRQ redirection, working around broken MP-BIOS.\n"); max = MAX_PIRQS; if (ints[0] < MAX_PIRQS) max = ints[0]; for (i = 0; i < max; i++) { - printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); + apic_printk(APIC_VERBOSE, "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* * PIRQs are mapped upside down, usually. */ @@ -357,10 +360,10 @@ { int apic, i, best_guess = -1; - Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", + apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", bus, slot, pin); if (mp_bus_id_to_pci_bus[bus] == -1) { - printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); + apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus); return -1; } for (i = 0; i < mp_irq_entries; i++) { @@ -402,7 +405,7 @@ unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } - printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); + apic_printk(APIC_VERBOSE, "Broken MPtable reports ISA irq %d\n", irq); return 0; } @@ -625,10 +628,10 @@ if ((pin >= 16) && (pin <= 23)) { if (pirq_entries[pin-16] != -1) { if (!pirq_entries[pin-16]) { - printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); + apic_printk(APIC_VERBOSE, "disabling PIRQ%d\n", pin-16); } else { irq = pirq_entries[pin-16]; - printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", + apic_printk(APIC_VERBOSE, "using PIRQ%d -> IRQ %d\n", pin-16, irq); } } @@ -719,7 +722,7 @@ int apic, pin, idx, irq, first_notcon = 1, vector; unsigned long flags; - printk(KERN_DEBUG "init IO_APIC IRQs\n"); + apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -732,15 +735,15 @@ entry.delivery_mode = dest_LowestPrio; entry.dest_mode = INT_DELIVERY_MODE; entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); first_notcon = 0; } else - printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mpc_apicid, pin); continue; } @@ -750,7 +753,7 @@ if (irq_trigger(idx)) { entry.trigger = 1; entry.mask = 1; - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); } irq = pin_2_irq(idx, apic, pin); @@ -775,7 +778,7 @@ } if (!first_notcon) - printk(" not connected.\n"); + apic_printk(APIC_VERBOSE," not connected.\n"); } /* @@ -800,7 +803,7 @@ */ entry.dest_mode = INT_DELIVERY_MODE; entry.mask = 0; /* unmask IRQ now */ - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.delivery_mode = dest_LowestPrio; entry.polarity = 0; entry.trigger = 0; @@ -825,13 +828,9 @@ void __init UNEXPECTED_IO_APIC(void) { -#if 0 - printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n"); - printk(KERN_WARNING " to linux-smp@vger.kernel.org\n"); -#endif } -void __init print_IO_APIC(void) +void __apicdebuginit print_IO_APIC(void) { int apic, i; union IO_APIC_reg_00 reg_00; @@ -839,7 +838,10 @@ union IO_APIC_reg_02 reg_02; unsigned long flags; - printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); + if (apic_verbosity == APIC_QUIET) + return; + + printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); @@ -955,11 +957,14 @@ return; } -static void print_APIC_bitfield (int base) +static __apicdebuginit void print_APIC_bitfield (int base) { unsigned int v; int i, j; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); for (i = 0; i < 8; i++) { v = apic_read(base + i*0x10); @@ -973,10 +978,13 @@ } } -void /*__init*/ print_local_APIC(void * dummy) +void __apicdebuginit print_local_APIC(void * dummy) { unsigned int v, ver, maxlvt; + if (apic_verbosity == APIC_QUIET) + return; + printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", smp_processor_id(), hard_smp_processor_id()); v = apic_read(APIC_ID); @@ -1058,12 +1066,15 @@ on_each_cpu(print_local_APIC, NULL, 1, 1); } -void /*__init*/ print_PIC(void) +void __apicdebuginit print_PIC(void) { extern spinlock_t i8259A_lock; unsigned int v; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "\nprinting PIC contents\n"); spin_lock_irqsave(&i8259A_lock, flags); @@ -1160,9 +1171,9 @@ old_id = mp_ioapics[apic].mpc_apicid; if (mp_ioapics[apic].mpc_apicid >= 0xf) { - printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", + apic_printk(APIC_QUIET,KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", apic, mp_ioapics[apic].mpc_apicid); - printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", + apic_printk(APIC_QUIET,KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", reg_00.bits.ID); mp_ioapics[apic].mpc_apicid = reg_00.bits.ID; } @@ -1205,7 +1216,7 @@ * Read the right value from the MPC table and * write it into the ID register. */ - printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", + apic_printk(APIC_VERBOSE,KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", mp_ioapics[apic].mpc_apicid); reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; @@ -1220,9 +1231,9 @@ reg_00.raw = io_apic_read(apic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) - panic("could not set ID!\n"); + printk("could not set ID!\n"); else - printk(" ok.\n"); + apic_printk(APIC_VERBOSE," ok.\n"); } } @@ -1671,7 +1682,7 @@ pin1 = find_isa_irq_pin(0, mp_INT); pin2 = find_isa_irq_pin(0, mp_ExtINT); - printk(KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2); + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2); if (pin1 != -1) { /* @@ -1689,12 +1700,12 @@ return; } clear_IO_APIC_pin(0, pin1); - printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); + apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); } - printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); + apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); if (pin2 != -1) { - printk("\n..... (found pin %d) ...", pin2); + apic_printk(APIC_VERBOSE,"\n..... (found pin %d) ...", pin2); /* * legacy devices should be connected to IO APIC #0 */ @@ -1720,7 +1731,7 @@ nmi_watchdog = 0; } - printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); + apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); disable_8259A_irq(0); irq_desc[0].handler = &lapic_irq_type; @@ -1728,13 +1739,13 @@ enable_8259A_irq(0); if (timer_irq_works()) { - printk(" works.\n"); + apic_printk(APIC_QUIET, " works.\n"); return; } apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); - printk(" failed.\n"); + apic_printk(APIC_VERBOSE," failed.\n"); - printk(KERN_INFO "...trying to set up timer as ExtINT IRQ..."); + apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ..."); init_8259A(0); make_8259A_irq(0); @@ -1743,10 +1754,10 @@ unlock_ExtINT_logic(); if (timer_irq_works()) { - printk(" works.\n"); + apic_printk(APIC_VERBOSE," works.\n"); return; } - printk(" failed :(.\n"); + apic_printk(APIC_VERBOSE," failed :(.\n"); panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); } @@ -1768,7 +1779,7 @@ else io_apic_irqs = ~PIC_IRQS; - printk("ENABLING IO-APIC IRQs\n"); + apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); /* * Set up the IO-APIC IRQ routing table. @@ -1783,6 +1794,98 @@ print_IO_APIC(); } +struct sysfs_ioapic_data { + struct sys_device dev; + struct IO_APIC_route_entry entry[0]; +}; +static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; + +static int ioapic_suspend(struct sys_device *dev, u32 state) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + spin_lock_irqsave(&ioapic_lock, flags); + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i); + *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static int ioapic_resume(struct sys_device *dev) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + union IO_APIC_reg_00 reg_00; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + + spin_lock_irqsave(&ioapic_lock, flags); + reg_00.raw = io_apic_read(dev->id, 0); + if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { + reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; + io_apic_write(dev->id, 0, reg_00.raw); + } + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1)); + io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0)); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static struct sysdev_class ioapic_sysdev_class = { + set_kset_name("ioapic"), + .suspend = ioapic_suspend, + .resume = ioapic_resume, +}; + +static int __init ioapic_init_sysfs(void) +{ + struct sys_device * dev; + int i, size, error = 0; + + error = sysdev_class_register(&ioapic_sysdev_class); + if (error) + return error; + + for (i = 0; i < nr_ioapics; i++ ) { + size = sizeof(struct sys_device) + nr_ioapic_registers[i] + * sizeof(struct IO_APIC_route_entry); + mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); + if (!mp_ioapic_data[i]) { + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + memset(mp_ioapic_data[i], 0, size); + dev = &mp_ioapic_data[i]->dev; + dev->id = i; + dev->cls = &ioapic_sysdev_class; + error = sysdev_register(dev); + if (error) { + kfree(mp_ioapic_data[i]); + mp_ioapic_data[i] = NULL; + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + } + + return 0; +} + +device_initcall(ioapic_init_sysfs); + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ @@ -1815,7 +1918,7 @@ spin_unlock_irqrestore(&ioapic_lock, flags); if (apic_id >= IO_APIC_MAX_ID) { - printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " + apic_printk(APIC_QUIET, KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " "%d\n", ioapic, apic_id, reg_00.bits.ID); apic_id = reg_00.bits.ID; } @@ -1834,7 +1937,7 @@ if (i == IO_APIC_MAX_ID) panic("Max apic_id exceeded!\n"); - printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " + apic_printk(APIC_VERBOSE, KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " "trying %d\n", ioapic, apic_id, i); apic_id = i; @@ -1855,7 +1958,7 @@ panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); } - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); + apic_printk(APIC_VERBOSE,KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } @@ -1893,7 +1996,7 @@ unsigned long flags; if (!IO_APIC_IRQ(irq)) { - printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", + apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", ioapic); return -EINVAL; } @@ -1908,7 +2011,7 @@ entry.delivery_mode = dest_LowestPrio; entry.dest_mode = INT_DELIVERY_MODE; - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.trigger = edge_level; entry.polarity = active_high_low; entry.mask = 1; /* Disabled (masked) */ @@ -1921,20 +2024,12 @@ entry.vector = assign_irq_vector(irq); - printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " + apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " "IRQ %d Mode:%i Active:%i)\n", ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); - if (use_pci_vector() && !platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); - if (edge_level) { - irq_desc[irq].handler = &ioapic_level_type; - } else { - irq_desc[irq].handler = &ioapic_edge_type; - } - - set_intr_gate(entry.vector, interrupt[irq]); + ioapic_register_intr(irq, entry.vector, edge_level); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); @@ -1966,3 +2061,28 @@ apic_write_around(APIC_ICR, cfg); } #endif + + +/* + * This function currently is only a helper for the i386 smp boot process where + * we need to reprogram the ioredtbls to cater for the cpus which have come online + * so mask in all cases should simply be TARGET_CPUS + */ +void __init setup_ioapic_dest(void) +{ + int pin, ioapic, irq, irq_entry; + + if (skip_ioapic_setup == 1) + return; + + for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { + for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { + irq_entry = find_irq_entry(ioapic, pin, mp_INT); + if (irq_entry == -1) + continue; + irq = pin_2_irq(irq_entry, ioapic, pin); + set_ioapic_affinity_irq(irq, TARGET_CPUS); + } + + } +} diff -Nru a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c --- a/arch/x86_64/kernel/ioport.c 2004-10-18 14:56:20 -07:00 +++ b/arch/x86_64/kernel/ioport.c 2004-10-18 14:56:20 -07:00 @@ -28,12 +28,12 @@ clear_bit(i, bitmap); } - /* * this changes the io permissions bitmap in the current task. */ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) { + unsigned int i, max_long, bytes, bytes_updated; struct thread_struct * t = ¤t->thread; struct tss_struct * tss; unsigned long *bitmap; @@ -59,16 +59,34 @@ /* * do it in the per-thread copy and in the TSS ... + * + * Disable preemption via get_cpu() - we must not switch away + * because the ->io_bitmap_max value must match the bitmap + * contents: */ + tss = &per_cpu(init_tss, get_cpu()); + set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); - tss = init_tss + get_cpu(); - if (tss->io_bitmap_base == IO_BITMAP_OFFSET) { /* already active? */ - set_bitmap(tss->io_bitmap, from, num, !turn_on); - } else { - memcpy(tss->io_bitmap, t->io_bitmap_ptr, IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; /* Activate it in the TSS */ - } + + /* + * Search for a (possibly new) maximum. This is simple and stupid, + * to keep it obviously correct: + */ + max_long = 0; + for (i = 0; i < IO_BITMAP_LONGS; i++) + if (t->io_bitmap_ptr[i] != ~0UL) + max_long = i; + + bytes = (max_long + 1) * sizeof(long); + bytes_updated = max(bytes, t->io_bitmap_max); + + t->io_bitmap_max = bytes; + + /* Update the TSS: */ + memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated); + put_cpu(); + return 0; } @@ -83,9 +101,9 @@ * code. */ -asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs) +asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs) { - unsigned int old = (regs.eflags >> 12) & 3; + unsigned int old = (regs->eflags >> 12) & 3; if (level > 3) return -EINVAL; @@ -94,6 +112,6 @@ if (!capable(CAP_SYS_RAWIO)) return -EPERM; } - regs.eflags = (regs.eflags &~ 0x3000UL) | (level << 12); + regs->eflags = (regs->eflags &~ 0x3000UL) | (level << 12); return 0; } diff -Nru a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c --- a/arch/x86_64/kernel/irq.c 2004-10-18 14:56:29 -07:00 +++ b/arch/x86_64/kernel/irq.c 2004-10-18 14:56:29 -07:00 @@ -213,13 +213,15 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ + int ret; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -862,31 +864,6 @@ #endif -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, - const char __user *buffer, - unsigned long count, void *data) -{ - unsigned long full_count = count, err; - cpumask_t new_value, *mask = (cpumask_t *)data; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -922,26 +899,15 @@ #endif } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. @@ -949,4 +915,3 @@ for (i = 0; i < NR_IRQS; i++) register_irq_proc(i); } - diff -Nru a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c --- a/arch/x86_64/kernel/ldt.c 2004-10-18 14:57:03 -07:00 +++ b/arch/x86_64/kernel/ldt.c 2004-10-18 14:57:03 -07:00 @@ -135,6 +135,7 @@ return 0; if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; + down(&mm->context.sem); size = mm->context.size*LDT_ENTRY_SIZE; if (size > bytecount) @@ -145,12 +146,17 @@ err = -EFAULT; up(&mm->context.sem); if (err < 0) - return err; + goto error_return; if (size != bytecount) { /* zero-fill the rest */ - clear_user(ptr+size, bytecount-size); + if (clear_user(ptr+size, bytecount-size) != 0) { + err = -EFAULT; + goto error_return; + } } return bytecount; +error_return: + return err; } static int read_default_ldt(void __user * ptr, unsigned long bytecount) diff -Nru a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c --- a/arch/x86_64/kernel/mce.c 2004-10-18 14:56:27 -07:00 +++ b/arch/x86_64/kernel/mce.c 2004-10-18 14:56:27 -07:00 @@ -24,7 +24,8 @@ #define MISC_MCELOG_MINOR 227 #define NR_BANKS 5 -static int mce_disabled __initdata; +static int mce_dont_init; + /* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic, 3: never panic or exit (for testing only) */ static int tolerant = 1; @@ -48,8 +49,7 @@ mce->finished = 0; smp_wmb(); for (;;) { - entry = mcelog.next; - read_barrier_depends(); + entry = rcu_dereference(mcelog.next); /* When the buffer fills up discard new entries. Assume that the earlier errors are the more interesting. */ if (entry >= MCE_LOG_LEN) { @@ -72,7 +72,8 @@ static void print_mce(struct mce *m) { - printk(KERN_EMERG + printk(KERN_EMERG "\n" + KERN_EMERG "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n", m->cpu, m->mcgstatus, m->bank, m->status); if (m->rip) { @@ -101,7 +102,7 @@ if (time_before(tsc, start)) continue; print_mce(&mcelog.entry[i]); - if (mcelog.entry[i].tsc == backup->tsc) + if (backup && mcelog.entry[i].tsc == backup->tsc) backup = NULL; } if (backup) @@ -114,9 +115,8 @@ static int mce_available(struct cpuinfo_x86 *c) { - return !mce_disabled && - test_bit(X86_FEATURE_MCE, &c->x86_capability) && - test_bit(X86_FEATURE_MCA, &c->x86_capability); + return test_bit(X86_FEATURE_MCE, &c->x86_capability) && + test_bit(X86_FEATURE_MCA, &c->x86_capability); } /* @@ -128,8 +128,9 @@ struct mce m, panicm; int nowayout = (tolerant < 1); int kill_it = 0; - u64 mcestart; + u64 mcestart = 0; int i; + int panicm_found = 0; if (regs) notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL); @@ -139,17 +140,11 @@ memset(&m, 0, sizeof(struct mce)); m.cpu = hard_smp_processor_id(); rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus); - if (!regs && (m.mcgstatus & MCG_STATUS_MCIP)) - return; if (!(m.mcgstatus & MCG_STATUS_RIPV)) kill_it = 1; - if (regs) { - m.rip = regs->rip; - m.cs = regs->cs; - } rdtscll(mcestart); - mb(); + barrier(); for (i = 0; i < banks; i++) { if (!bank[i]) @@ -157,52 +152,62 @@ m.misc = 0; m.addr = 0; + m.bank = i; + m.tsc = 0; rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status); if ((m.status & MCI_STATUS_VAL) == 0) continue; - /* Should be implied by the banks check above, but - check it anyways */ - if ((m.status & MCI_STATUS_EN) == 0) - continue; - /* Did this bank cause the exception? */ - /* Assume that the bank with uncorrectable errors did it, - and that there is only a single one. */ - if (m.status & MCI_STATUS_UC) { - panicm = m; - } else { - m.rip = 0; - m.cs = 0; + if (m.status & MCI_STATUS_EN) { + /* In theory _OVER could be a nowayout too, but + assume any overflowed errors were no fatal. */ + nowayout |= !!(m.status & MCI_STATUS_PCC); + kill_it |= !!(m.status & MCI_STATUS_UC); } - /* In theory _OVER could be a nowayout too, but - assume any overflowed errors were no fatal. */ - nowayout |= !!(m.status & MCI_STATUS_PCC); - kill_it |= !!(m.status & MCI_STATUS_UC); - m.bank = i; - if (m.status & MCI_STATUS_MISCV) rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc); if (m.status & MCI_STATUS_ADDRV) rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr); - rdtscll(m.tsc); + if (regs && (m.mcgstatus & MCG_STATUS_RIPV)) { + m.rip = regs->rip; + m.cs = regs->cs; + } else { + m.rip = 0; + m.cs = 0; + } + + if (error_code != -1) + rdtscll(m.tsc); wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0); mce_log(&m); + + /* Did this bank cause the exception? */ + /* Assume that the bank with uncorrectable errors did it, + and that there is only a single one. */ + if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) { + panicm = m; + panicm_found = 1; + } } - wrmsrl(MSR_IA32_MCG_STATUS, 0); /* Never do anything final in the polling timer */ if (!regs) - return; + goto out; + + /* If we didn't find an uncorrectable error, pick + the last one (shouldn't happen, just being safe). */ + if (!panicm_found) + panicm = m; if (nowayout) - mce_panic("Machine check", &m, mcestart); + mce_panic("Machine check", &panicm, mcestart); if (kill_it) { int user_space = 0; if (m.mcgstatus & MCG_STATUS_RIPV) - user_space = m.rip && (m.cs & 3); + user_space = panicm.rip && (panicm.cs & 3); /* When the machine was in user space and the CPU didn't get confused it's normally not necessary to panic, unless you @@ -215,18 +220,15 @@ (unsigned)current->pid <= 1) mce_panic("Uncorrected machine check", &panicm, mcestart); - /* do_exit takes an awful lot of locks and has as slight risk - of deadlocking. If you don't want that don't set tolerant >= 2 */ + /* do_exit takes an awful lot of locks and has as + slight risk of deadlocking. If you don't want that + don't set tolerant >= 2 */ if (tolerant < 3) do_exit(SIGBUS); } -} -static void mce_clear_all(void) -{ - int i; - for (i = 0; i < banks; i++) - wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0); + out: + /* Last thing done in the machine check exception to clear state. */ wrmsrl(MSR_IA32_MCG_STATUS, 0); } @@ -269,22 +271,25 @@ int i; rdmsrl(MSR_IA32_MCG_CAP, cap); - if (cap & MCG_CTL_P) - wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); - banks = cap & 0xff; if (banks > NR_BANKS) { printk(KERN_INFO "MCE: warning: using only %d banks\n", banks); banks = NR_BANKS; } - mce_clear_all(); + /* Log the machine checks left over from the previous reset. + This also clears all registers */ + do_machine_check(NULL, -1); + + set_in_cr4(X86_CR4_MCE); + + if (cap & MCG_CTL_P) + wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); + for (i = 0; i < banks; i++) { wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]); wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); } - - set_in_cr4(X86_CR4_MCE); } /* Add per CPU specific workarounds here */ @@ -308,7 +313,9 @@ mce_cpu_quirks(c); - if (test_and_set_bit(smp_processor_id(), &mce_cpus) || !mce_available(c)) + if (mce_dont_init || + test_and_set_bit(smp_processor_id(), &mce_cpus) || + !mce_available(c)) return; mce_init(NULL); @@ -333,9 +340,8 @@ int i, err; down(&mce_read_sem); - next = mcelog.next; - read_barrier_depends(); - + next = rcu_dereference(mcelog.next); + /* Only supports full reads right now */ if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { up(&mce_read_sem); @@ -412,15 +418,16 @@ static int __init mcheck_disable(char *str) { - mce_disabled = 1; + mce_dont_init = 1; return 0; } -/* mce=off disable machine check */ +/* mce=off disables machine check. Note you can reenable it later + using sysfs */ static int __init mcheck_enable(char *str) { if (!strcmp(str, "off")) - mce_disabled = 1; + mce_dont_init = 1; else printk("mce= argument %s ignored. Please use /sys", str); return 0; @@ -436,7 +443,6 @@ /* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */ static int mce_resume(struct sys_device *dev) { - mce_clear_all(); on_each_cpu(mce_init, NULL, 1, 1); return 0; } @@ -465,7 +471,7 @@ /* Why are there no generic functions for this? */ #define ACCESSOR(name, var, start) \ static ssize_t show_ ## name(struct sys_device *s, char *buf) { \ - return sprintf(buf, "%lu\n", (unsigned long)var); \ + return sprintf(buf, "%lx\n", (unsigned long)var); \ } \ static ssize_t set_ ## name(struct sys_device *s,const char *buf,size_t siz) { \ char *end; \ @@ -494,7 +500,7 @@ if (!err) err = sysdev_register(&device_mce); if (!err) { - /* could create per CPU objects, but is not worth it. */ + /* could create per CPU objects, but it is not worth it. */ sysdev_create_file(&device_mce, &attr_bank0ctl); sysdev_create_file(&device_mce, &attr_bank1ctl); sysdev_create_file(&device_mce, &attr_bank2ctl); diff -Nru a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c --- a/arch/x86_64/kernel/msr.c 2004-10-18 14:56:15 -07:00 +++ b/arch/x86_64/kernel/msr.c 2004-10-18 14:56:15 -07:00 @@ -46,234 +46,229 @@ static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) { - int err; + int err; - asm volatile( - "1: wrmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 1b,3b\n" - ".previous" - : "=&bDS" (err) - : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0)); + asm volatile ("1: wrmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 8\n" " .quad 1b,3b\n" ".previous":"=&bDS" (err) + :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0)); - return err; + return err; } static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) { - int err; + int err; - asm volatile( - "1: rdmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 1b,3b\n" - ".previous" - : "=&bDS" (err), "=a" (*eax), "=d" (*edx) - : "c" (reg), "i" (-EIO), "0" (0)); + asm volatile ("1: rdmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 8\n" + " .quad 1b,3b\n" + ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx) + :"c"(reg), "i"(-EIO), "0"(0)); - return err; + return err; } #ifdef CONFIG_SMP struct msr_command { - int cpu; - int err; - u32 reg; - u32 data[2]; + int cpu; + int err; + u32 reg; + u32 data[2]; }; static void msr_smp_wrmsr(void *cmd_block) { - struct msr_command *cmd = (struct msr_command *) cmd_block; - - if ( cmd->cpu == smp_processor_id() ) - cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); + struct msr_command *cmd = (struct msr_command *)cmd_block; + + if (cmd->cpu == smp_processor_id()) + cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); } static void msr_smp_rdmsr(void *cmd_block) { - struct msr_command *cmd = (struct msr_command *) cmd_block; - - if ( cmd->cpu == smp_processor_id() ) - cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); + struct msr_command *cmd = (struct msr_command *)cmd_block; + + if (cmd->cpu == smp_processor_id()) + cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); } static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) { - struct msr_command cmd; - int ret; + struct msr_command cmd; + int ret; + + preempt_disable(); + if (cpu == smp_processor_id()) { + ret = wrmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + cmd.data[0] = eax; + cmd.data[1] = edx; - preempt_disable(); - if ( cpu == smp_processor_id() ) { - ret = wrmsr_eio(reg, eax, edx); - } else { - cmd.cpu = cpu; - cmd.reg = reg; - cmd.data[0] = eax; - cmd.data[1] = edx; - - smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); - ret = cmd.err; - } - preempt_enable(); - return ret; + smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); + ret = cmd.err; + } + preempt_enable(); + return ret; } -static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx) { - struct msr_command cmd; - int ret; + struct msr_command cmd; + int ret; + + preempt_disable(); + if (cpu == smp_processor_id()) { + ret = rdmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + + smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); - preempt_disable(); - if ( cpu == smp_processor_id() ) { - ret = rdmsr_eio(reg, eax, edx); - } else { - cmd.cpu = cpu; - cmd.reg = reg; - - smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); - - *eax = cmd.data[0]; - *edx = cmd.data[1]; - - ret = cmd.err; - } - preempt_enable(); - return ret; + *eax = cmd.data[0]; + *edx = cmd.data[1]; + + ret = cmd.err; + } + preempt_enable(); + return ret; } -#else /* ! CONFIG_SMP */ +#else /* ! CONFIG_SMP */ static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) { - return wrmsr_eio(reg, eax, edx); + return wrmsr_eio(reg, eax, edx); } static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) { - return rdmsr_eio(reg, eax, edx); + return rdmsr_eio(reg, eax, edx); } -#endif /* ! CONFIG_SMP */ +#endif /* ! CONFIG_SMP */ static loff_t msr_seek(struct file *file, loff_t offset, int orig) { - loff_t ret = -EINVAL; - lock_kernel(); - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - } - unlock_kernel(); - return ret; -} - -static ssize_t msr_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - char __user *tmp = buf; - u32 data[2]; - size_t rv; - u32 reg = *ppos; - int cpu = iminor(file->f_dentry->d_inode); - int err; - - if ( count % 8 ) - return -EINVAL; /* Invalid chunk size */ - - for ( rv = 0 ; count ; count -= 8 ) { - err = do_rdmsr(cpu, reg, &data[0], &data[1]); - if ( err ) - return err; - if ( copy_to_user(tmp,&data,8) ) - return -EFAULT; - tmp += 8; - } + loff_t ret = -EINVAL; + + lock_kernel(); + switch (orig) { + case 0: + file->f_pos = offset; + ret = file->f_pos; + break; + case 1: + file->f_pos += offset; + ret = file->f_pos; + } + unlock_kernel(); + return ret; +} + +static ssize_t msr_read(struct file *file, char __user * buf, + size_t count, loff_t * ppos) +{ + u32 __user *tmp = (u32 __user *) buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = iminor(file->f_dentry->d_inode); + int err; + + if (count % 8) + return -EINVAL; /* Invalid chunk size */ + + for (rv = 0; count; count -= 8) { + err = do_rdmsr(cpu, reg, &data[0], &data[1]); + if (err) + return err; + if (copy_to_user(tmp, &data, 8)) + return -EFAULT; + tmp += 2; + } - return tmp - buf; + return ((char __user *)tmp) - buf; } -static ssize_t msr_write(struct file * file, const char __user * buf, +static ssize_t msr_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - const char __user *tmp = buf; - u32 data[2]; - size_t rv; - u32 reg = *ppos; - int cpu = iminor(file->f_dentry->d_inode); - int err; - - if ( count % 8 ) - return -EINVAL; /* Invalid chunk size */ - - for ( rv = 0 ; count ; count -= 8 ) { - if ( copy_from_user(&data,tmp,8) ) - return -EFAULT; - err = do_wrmsr(cpu, reg, data[0], data[1]); - if ( err ) - return err; - tmp += 8; - } + const u32 __user *tmp = (const u32 __user *)buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = iminor(file->f_dentry->d_inode); + int err; + + if (count % 8) + return -EINVAL; /* Invalid chunk size */ + + for (rv = 0; count; count -= 8) { + if (copy_from_user(&data, tmp, 8)) + return -EFAULT; + err = do_wrmsr(cpu, reg, data[0], data[1]); + if (err) + return err; + tmp += 2; + } - return tmp - buf; + return ((char __user *)tmp) - buf; } static int msr_open(struct inode *inode, struct file *file) { - int cpu = iminor(file->f_dentry->d_inode); - struct cpuinfo_x86 *c = &(cpu_data)[cpu]; - - if (cpu >= NR_CPUS || !cpu_online(cpu)) - return -ENXIO; /* No such CPU */ - if ( !cpu_has(c, X86_FEATURE_MSR) ) - return -EIO; /* MSR not supported */ - - return 0; + unsigned int cpu = iminor(file->f_dentry->d_inode); + struct cpuinfo_x86 *c = &(cpu_data)[cpu]; + + if (cpu >= NR_CPUS || !cpu_online(cpu)) + return -ENXIO; /* No such CPU */ + if (!cpu_has(c, X86_FEATURE_MSR)) + return -EIO; /* MSR not supported */ + + return 0; } /* * File operations we support */ static struct file_operations msr_fops = { - .owner = THIS_MODULE, - .llseek = msr_seek, - .read = msr_read, - .write = msr_write, - .open = msr_open, + .owner = THIS_MODULE, + .llseek = msr_seek, + .read = msr_read, + .write = msr_write, + .open = msr_open, }; int __init msr_init(void) { - if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { - printk(KERN_ERR "msr: unable to get major %d for msr\n", - MSR_MAJOR); - return -EBUSY; - } - - return 0; + if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { + printk(KERN_ERR "msr: unable to get major %d for msr\n", + MSR_MAJOR); + return -EBUSY; + } + + return 0; } void __exit msr_exit(void) { - unregister_chrdev(MSR_MAJOR, "cpu/msr"); + unregister_chrdev(MSR_MAJOR, "cpu/msr"); } module_init(msr_init); diff -Nru a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c --- a/arch/x86_64/kernel/nmi.c 2004-10-18 14:56:29 -07:00 +++ b/arch/x86_64/kernel/nmi.c 2004-10-18 14:56:29 -07:00 @@ -390,7 +390,8 @@ */ alert_counter[cpu]++; if (alert_counter[cpu] == 5*nmi_hz) { - if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD) { + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) { alert_counter[cpu] = 0; return; } diff -Nru a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c --- a/arch/x86_64/kernel/pci-dma.c 2004-10-18 14:57:03 -07:00 +++ b/arch/x86_64/kernel/pci-dma.c 2004-10-18 14:57:03 -07:00 @@ -1,5 +1,5 @@ /* - * Dynamic DMA mapping support. Common code + * Dynamic DMA mapping support. */ #include @@ -24,38 +24,37 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents, int direction) +int dma_map_sg(struct device *hwdev, struct scatterlist *sg, + int nents, int direction) { int i; - BUG_ON(direction == PCI_DMA_NONE); + BUG_ON(direction == DMA_NONE); for (i = 0; i < nents; i++ ) { struct scatterlist *s = &sg[i]; BUG_ON(!s->page); - s->dma_address = pci_map_page(hwdev, s->page, s->offset, - s->length, direction); + s->dma_address = virt_to_bus(page_address(s->page) +s->offset); s->dma_length = s->length; } return nents; } -EXPORT_SYMBOL(pci_map_sg); +EXPORT_SYMBOL(dma_map_sg); /* Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg, - int nents, int dir) +void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, int dir) { int i; for (i = 0; i < nents; i++) { struct scatterlist *s = &sg[i]; BUG_ON(s->page == NULL); BUG_ON(s->dma_address == 0); - pci_unmap_single(dev, s->dma_address, s->dma_length, dir); + dma_unmap_single(dev, s->dma_address, s->dma_length, dir); } } -EXPORT_SYMBOL(pci_unmap_sg); +EXPORT_SYMBOL(dma_unmap_sg); diff -Nru a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c --- a/arch/x86_64/kernel/pci-gart.c 2004-10-18 14:56:29 -07:00 +++ b/arch/x86_64/kernel/pci-gart.c 2004-10-18 14:56:29 -07:00 @@ -31,12 +31,6 @@ #include #include -#ifdef CONFIG_PREEMPT -#define preempt_atomic() in_atomic() -#else -#define preempt_atomic() 1 -#endif - dma_addr_t bad_dma_address; unsigned long iommu_bus_base; /* GART remapping area (physical) */ @@ -54,7 +48,7 @@ int panic_on_overflow = 0; int force_iommu = 0; #endif -int iommu_merge = 0; +int iommu_merge = 1; int iommu_sac_force = 0; /* If this is disabled the IOMMU will use an optimized flushing strategy @@ -64,6 +58,10 @@ also seen with Qlogic at least). */ int iommu_fullflush = 1; +/* This tells the BIO block layer to assume merging. Default to off + because we cannot guarantee merging later. */ +int iommu_bio_merge = 0; + #define MAX_NB 8 /* Allocation bitmap for the remapping area */ @@ -104,8 +102,16 @@ static unsigned long next_bit; /* protected by iommu_bitmap_lock */ static int need_flush; /* global flush state. set for each gart wrap */ -static dma_addr_t pci_map_area(struct pci_dev *dev, unsigned long phys_mem, - size_t size, int dir); +static dma_addr_t dma_map_area(struct device *dev, unsigned long phys_mem, + size_t size, int dir, int do_panic); + +/* Dummy device used for NULL arguments (normally ISA). Better would + be probably a smaller DMA mask, but this is bug-to-bug compatible to i386. */ +static struct device fallback_dev = { + .bus_id = "fallback device", + .coherent_dma_mask = 0xffffffff, + .dma_mask = &fallback_dev.coherent_dma_mask, +}; static unsigned long alloc_iommu(int size) { @@ -146,25 +152,31 @@ /* * Use global flush state to avoid races with multiple flushers. */ -static void flush_gart(struct pci_dev *dev) +static void flush_gart(struct device *dev) { unsigned long flags; int flushed = 0; - int i; + int i, max; spin_lock_irqsave(&iommu_bitmap_lock, flags); if (need_flush) { + max = 0; for (i = 0; i < MAX_NB; i++) { - u32 w; if (!northbridges[i]) continue; pci_write_config_dword(northbridges[i], 0x9c, northbridge_flush_word[i] | 1); + flushed++; + max = i; + } + for (i = 0; i <= max; i++) { + u32 w; + if (!northbridges[i]) + continue; /* Make sure the hardware actually executed the flush. */ do { pci_read_config_dword(northbridges[i], 0x9c, &w); } while (w & 1); - flushed++; } if (!flushed) printk("nothing to flush?\n"); @@ -173,31 +185,47 @@ spin_unlock_irqrestore(&iommu_bitmap_lock, flags); } +/* Allocate DMA memory on node near device */ +noinline +static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order) +{ + struct page *page; + int node; + if (dev->bus == &pci_bus_type) { + cpumask_t mask; + mask = pcibus_to_cpumask(to_pci_dev(dev)->bus->number); + node = cpu_to_node(first_cpu(mask)); + } else + node = numa_node_id(); + page = alloc_pages_node(node, gfp, order); + return page ? page_address(page) : NULL; +} + /* - * Allocate memory for a consistent mapping. + * Allocate memory for a coherent mapping. */ -void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) +void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + unsigned gfp) { void *memory; - int gfp = preempt_atomic() ? GFP_ATOMIC : GFP_KERNEL; unsigned long dma_mask = 0; u64 bus; - if (hwdev) - dma_mask = hwdev->dev.coherent_dma_mask; + if (!dev) + dev = &fallback_dev; + dma_mask = dev->coherent_dma_mask; if (dma_mask == 0) dma_mask = 0xffffffff; /* Kludge to make it bug-to-bug compatible with i386. i386 - uses the normal dma_mask for alloc_consistent. */ - if (hwdev) - dma_mask &= hwdev->dma_mask; + uses the normal dma_mask for alloc_coherent. */ + dma_mask &= *dev->dma_mask; again: - memory = (void *)__get_free_pages(gfp, get_order(size)); + memory = dma_alloc_pages(dev, gfp, get_order(size)); if (memory == NULL) - return NULL; + return NULL; { int high, mmu; @@ -223,28 +251,29 @@ } } - *dma_handle = pci_map_area(hwdev, bus, size, PCI_DMA_BIDIRECTIONAL); + *dma_handle = dma_map_area(dev, bus, size, PCI_DMA_BIDIRECTIONAL, 0); if (*dma_handle == bad_dma_address) goto error; - flush_gart(hwdev); + flush_gart(dev); return memory; error: if (panic_on_overflow) - panic("pci_alloc_consistent: overflow %lu bytes\n", size); + panic("dma_alloc_coherent: IOMMU overflow by %lu bytes\n", size); free: free_pages((unsigned long)memory, get_order(size)); + /* XXX Could use the swiotlb pool here too */ return NULL; } /* - * Unmap consistent memory. + * Unmap coherent memory. * The caller must ensure that the device has finished accessing the mapping. */ -void pci_free_consistent(struct pci_dev *hwdev, size_t size, +void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t bus) { - pci_unmap_single(hwdev, bus, size, 0); + dma_unmap_single(dev, bus, size, 0); free_pages((unsigned long)vaddr, get_order(size)); } @@ -280,7 +309,7 @@ #define CLEAR_LEAK(x) #endif -static void iommu_full(struct pci_dev *dev, size_t size, int dir) +static void iommu_full(struct device *dev, size_t size, int dir, int do_panic) { /* * Ran out of IOMMU space for this operation. This is very bad. @@ -293,14 +322,14 @@ */ printk(KERN_ERR - "PCI-DMA: Out of IOMMU space for %lu bytes at device %s[%s]\n", - size, dev ? pci_pretty_name(dev) : "", dev ? dev->slot_name : "?"); + "PCI-DMA: Out of IOMMU space for %lu bytes at device %s\n", + size, dev->bus_id); - if (size > PAGE_SIZE*EMERGENCY_PAGES) { + if (size > PAGE_SIZE*EMERGENCY_PAGES && do_panic) { if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) - panic("PCI-DMA: Memory will be corrupted\n"); + panic("PCI-DMA: Memory would be corrupted\n"); if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) - panic("PCI-DMA: Random memory will be DMAed\n"); + panic("PCI-DMA: Random memory would be DMAed\n"); } #ifdef CONFIG_IOMMU_LEAK @@ -308,9 +337,9 @@ #endif } -static inline int need_iommu(struct pci_dev *dev, unsigned long addr, size_t size) +static inline int need_iommu(struct device *dev, unsigned long addr, size_t size) { - u64 mask = dev ? dev->dma_mask : 0xffffffff; + u64 mask = *dev->dma_mask; int high = addr + size >= mask; int mmu = high; if (force_iommu) @@ -323,9 +352,9 @@ return mmu; } -static inline int nonforced_iommu(struct pci_dev *dev, unsigned long addr, size_t size) +static inline int nonforced_iommu(struct device *dev, unsigned long addr, size_t size) { - u64 mask = dev ? dev->dma_mask : 0xffffffff; + u64 mask = *dev->dma_mask; int high = addr + size >= mask; int mmu = high; if (no_iommu) { @@ -339,8 +368,8 @@ /* Map a single continuous physical area into the IOMMU. * Caller needs to check if the iommu is needed and flush. */ -static dma_addr_t pci_map_area(struct pci_dev *dev, unsigned long phys_mem, - size_t size, int dir) +static dma_addr_t dma_map_area(struct device *dev, unsigned long phys_mem, + size_t size, int dir, int do_panic) { unsigned long npages = to_pages(phys_mem, size); unsigned long iommu_page = alloc_iommu(npages); @@ -349,8 +378,8 @@ if (!nonforced_iommu(dev, phys_mem, size)) return phys_mem; if (panic_on_overflow) - panic("pci_map_area overflow %lu bytes\n", size); - iommu_full(dev, size, dir); + panic("dma_map_area overflow %lu bytes\n", size); + iommu_full(dev, size, dir, do_panic); return bad_dma_address; } @@ -363,44 +392,44 @@ } /* Map a single area into the IOMMU */ -dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size, int dir) -{ +dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size, int dir) +{ unsigned long phys_mem, bus; - BUG_ON(dir == PCI_DMA_NONE); + BUG_ON(dir == DMA_NONE); -#ifdef CONFIG_SWIOTLB if (swiotlb) - return swiotlb_map_single(&dev->dev,addr,size,dir); -#endif + return swiotlb_map_single(dev,addr,size,dir); + if (!dev) + dev = &fallback_dev; phys_mem = virt_to_phys(addr); if (!need_iommu(dev, phys_mem, size)) return phys_mem; - bus = pci_map_area(dev, phys_mem, size, dir); + bus = dma_map_area(dev, phys_mem, size, dir, 1); flush_gart(dev); return bus; } -/* Fallback for pci_map_sg in case of overflow */ -static int pci_map_sg_nonforce(struct pci_dev *dev, struct scatterlist *sg, +/* Fallback for dma_map_sg in case of overflow */ +static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, int nents, int dir) { int i; #ifdef CONFIG_IOMMU_DEBUG - printk(KERN_DEBUG "pci_map_sg overflow\n"); + printk(KERN_DEBUG "dma_map_sg overflow\n"); #endif for (i = 0; i < nents; i++ ) { struct scatterlist *s = &sg[i]; unsigned long addr = page_to_phys(s->page) + s->offset; if (nonforced_iommu(dev, addr, s->length)) { - addr = pci_map_area(dev, addr, s->length, dir); + addr = dma_map_area(dev, addr, s->length, dir, 0); if (addr == bad_dma_address) { if (i > 0) - pci_unmap_sg(dev, sg, i, dir); + dma_unmap_sg(dev, sg, i, dir); nents = 0; sg[0].dma_length = 0; break; @@ -414,7 +443,7 @@ } /* Map multiple scatterlist entries continuous into the first. */ -static int __pci_map_cont(struct scatterlist *sg, int start, int stopat, +static int __dma_map_cont(struct scatterlist *sg, int start, int stopat, struct scatterlist *sout, unsigned long pages) { unsigned long iommu_start = alloc_iommu(pages); @@ -452,7 +481,7 @@ return 0; } -static inline int pci_map_cont(struct scatterlist *sg, int start, int stopat, +static inline int dma_map_cont(struct scatterlist *sg, int start, int stopat, struct scatterlist *sout, unsigned long pages, int need) { @@ -462,14 +491,14 @@ sout->dma_length = sg[start].length; return 0; } - return __pci_map_cont(sg, start, stopat, sout, pages); + return __dma_map_cont(sg, start, stopat, sout, pages); } /* * DMA map all entries in a scatterlist. * Merge chunks that have page aligned sizes into a continuous mapping. - */ -int pci_map_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int dir) + */ +int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) { int i; int out; @@ -477,19 +506,14 @@ unsigned long pages = 0; int need = 0, nextneed; -#ifdef CONFIG_SWIOTLB - if (swiotlb) - return swiotlb_map_sg(&dev->dev,sg,nents,dir); -#endif - - BUG_ON(dir == PCI_DMA_NONE); + BUG_ON(dir == DMA_NONE); if (nents == 0) return 0; -#ifdef CONFIG_SWIOTLB if (swiotlb) - return swiotlb_map_sg(&dev->dev,sg,nents,dir); -#endif + return swiotlb_map_sg(dev,sg,nents,dir); + if (!dev) + dev = &fallback_dev; out = 0; start = 0; @@ -508,19 +532,19 @@ boundary and the new one doesn't have an offset. */ if (!iommu_merge || !nextneed || !need || s->offset || (ps->offset + ps->length) % PAGE_SIZE) { - if (pci_map_cont(sg, start, i, sg+out, pages, + if (dma_map_cont(sg, start, i, sg+out, pages, need) < 0) goto error; out++; pages = 0; start = i; } - } + } need = nextneed; pages += to_pages(s->offset, s->length); } - if (pci_map_cont(sg, start, i, sg+out, pages, need) < 0) + if (dma_map_cont(sg, start, i, sg+out, pages, need) < 0) goto error; out++; flush_gart(dev); @@ -530,34 +554,32 @@ error: flush_gart(NULL); - pci_unmap_sg(dev, sg, nents, dir); + dma_unmap_sg(dev, sg, nents, dir); /* When it was forced try again unforced */ if (force_iommu) - return pci_map_sg_nonforce(dev, sg, nents, dir); + return dma_map_sg_nonforce(dev, sg, nents, dir); if (panic_on_overflow) - panic("pci_map_sg: overflow on %lu pages\n", pages); - iommu_full(dev, pages << PAGE_SHIFT, dir); + panic("dma_map_sg: overflow on %lu pages\n", pages); + iommu_full(dev, pages << PAGE_SHIFT, dir, 0); for (i = 0; i < nents; i++) sg[i].dma_address = bad_dma_address; return 0; } /* - * Free a PCI mapping. + * Free a DMA mapping. */ -void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, +void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, int direction) { unsigned long iommu_page; int npages; int i; -#ifdef CONFIG_SWIOTLB if (swiotlb) { - swiotlb_unmap_single(&hwdev->dev,dma_addr,size,direction); + swiotlb_unmap_single(dev,dma_addr,size,direction); return; } -#endif if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || dma_addr >= iommu_bus_base + iommu_size) @@ -574,22 +596,25 @@ /* * Wrapper for pci_unmap_single working with scatterlists. */ -void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, - int dir) +void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) { int i; + if (swiotlb) { + swiotlb_unmap_sg(dev,sg,nents,dir); + return; + } for (i = 0; i < nents; i++) { struct scatterlist *s = &sg[i]; if (!s->dma_length || !s->length) break; - pci_unmap_single(dev, s->dma_address, s->dma_length, dir); + dma_unmap_single(dev, s->dma_address, s->dma_length, dir); } } -int pci_dma_supported(struct pci_dev *dev, u64 mask) +int dma_supported(struct device *dev, u64 mask) { /* Copied from i386. Doesn't make much sense, because it will - only work for pci_alloc_consistent. + only work for pci_alloc_coherent. The caller just has to use GFP_DMA in this case. */ if (mask < 0x00ffffff) return 0; @@ -605,22 +630,31 @@ Assume all masks <= 40 bits are of this type. Normally this doesn't make any difference, but gives more gentle handling of IOMMU overflow. */ if (iommu_sac_force && (mask >= 0xffffffffffULL)) { - printk(KERN_INFO "%s: Force SAC with mask %Lx\n", dev->slot_name,mask); + printk(KERN_INFO "%s: Force SAC with mask %Lx\n", dev->bus_id,mask); return 0; } return 1; } -EXPORT_SYMBOL(pci_unmap_sg); -EXPORT_SYMBOL(pci_map_sg); -EXPORT_SYMBOL(pci_map_single); -EXPORT_SYMBOL(pci_unmap_single); -EXPORT_SYMBOL(pci_dma_supported); +int dma_get_cache_alignment(void) +{ + return boot_cpu_data.x86_clflush_size; +} + +EXPORT_SYMBOL(dma_unmap_sg); +EXPORT_SYMBOL(dma_map_sg); +EXPORT_SYMBOL(dma_map_single); +EXPORT_SYMBOL(dma_unmap_single); +EXPORT_SYMBOL(dma_supported); EXPORT_SYMBOL(no_iommu); EXPORT_SYMBOL(force_iommu); EXPORT_SYMBOL(bad_dma_address); -EXPORT_SYMBOL(iommu_merge); +EXPORT_SYMBOL(iommu_bio_merge); +EXPORT_SYMBOL(iommu_sac_force); +EXPORT_SYMBOL(dma_get_cache_alignment); +EXPORT_SYMBOL(dma_alloc_coherent); +EXPORT_SYMBOL(dma_free_coherent); static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) { @@ -747,7 +781,7 @@ if (swiotlb) { no_iommu = 1; - printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n"); + printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n"); return -1; } @@ -851,7 +885,7 @@ fs_initcall(pci_iommu_init); /* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge] - [,forcesac][,fullflush][,nomerge] + [,forcesac][,fullflush][,nomerge][,biomerge] size set size of iommu (in bytes) noagp don't initialize the AGP driver and use full aperture. off don't use the IOMMU @@ -859,60 +893,73 @@ memaper[=order] allocate an own aperture over RAM with size 32MB^order. noforce don't force IOMMU usage. Default. force Force IOMMU. - merge Do SG merging. Implies force (experimental) + merge Do lazy merging. This may improve performance on some block devices. + Implies force (experimental) + biomerge Do merging at the BIO layer. This is more efficient than merge, + but should be only done with very big IOMMUs. Implies merge,force. nomerge Don't do SG merging. forcesac For SAC mode for masks <40bits (experimental) fullflush Flush IOMMU on each allocation (default) nofullflush Don't use IOMMU fullflush allowed overwrite iommu off workarounds for specific chipsets. soft Use software bounce buffering (default for Intel machines) + noaperture Don't touch the aperture for AGP. */ -__init int iommu_setup(char *opt) +__init int iommu_setup(char *p) { int arg; - char *p = opt; - - for (;;) { - if (!memcmp(p,"noagp", 5)) + + while (*p) { + if (!strncmp(p,"noagp",5)) no_agp = 1; - if (!memcmp(p,"off", 3)) + if (!strncmp(p,"off",3)) no_iommu = 1; - if (!memcmp(p,"force", 5)) { + if (!strncmp(p,"force",5)) { force_iommu = 1; iommu_aperture_allowed = 1; } - if (!memcmp(p,"allowed",7)) + if (!strncmp(p,"allowed",7)) iommu_aperture_allowed = 1; - if (!memcmp(p,"noforce", 7)) { + if (!strncmp(p,"noforce",7)) { iommu_merge = 0; force_iommu = 0; } - if (!memcmp(p, "memaper", 7)) { + if (!strncmp(p, "memaper", 7)) { fallback_aper_force = 1; p += 7; - if (*p == '=' && get_option(&p, &arg)) - fallback_aper_order = arg; + if (*p == '=') { + ++p; + if (get_option(&p, &arg)) + fallback_aper_order = arg; + } } - if (!memcmp(p, "panic", 5)) + if (!strncmp(p, "biomerge",8)) { + iommu_bio_merge = 4096; + iommu_merge = 1; + force_iommu = 1; + } + if (!strncmp(p, "panic",5)) panic_on_overflow = 1; - if (!memcmp(p, "nopanic", 7)) + if (!strncmp(p, "nopanic",7)) panic_on_overflow = 0; - if (!memcmp(p, "merge", 5)) { + if (!strncmp(p, "merge",5)) { iommu_merge = 1; force_iommu = 1; } - if (!memcmp(p, "nomerge", 7)) + if (!strncmp(p, "nomerge",7)) iommu_merge = 0; - if (!memcmp(p, "forcesac", 8)) + if (!strncmp(p, "forcesac",8)) iommu_sac_force = 1; - if (!memcmp(p, "fullflush", 9)) + if (!strncmp(p, "fullflush",8)) iommu_fullflush = 1; - if (!memcmp(p, "nofullflush", 11)) + if (!strncmp(p, "nofullflush",11)) iommu_fullflush = 0; - if (!memcmp(p, "soft", 4)) + if (!strncmp(p, "soft",4)) swiotlb = 1; + if (!strncmp(p, "noaperture",10)) + fix_aperture = 0; #ifdef CONFIG_IOMMU_LEAK - if (!memcmp(p,"leak", 4)) { + if (!strncmp(p,"leak",4)) { leak_trace = 1; p += 4; if (*p == '=') ++p; @@ -922,10 +969,9 @@ #endif if (isdigit(*p) && get_option(&p, &arg)) iommu_size = arg; - do { - if (*p == ' ' || *p == 0) - return 0; - } while (*p++ != ','); + p += strcspn(p, ","); + if (*p == ',') + ++p; } return 1; } diff -Nru a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c --- a/arch/x86_64/kernel/pci-nommu.c 2004-10-18 14:57:19 -07:00 +++ b/arch/x86_64/kernel/pci-nommu.c 2004-10-18 14:57:19 -07:00 @@ -1,8 +1,11 @@ +/* Fallback functions when the main IOMMU code is not compiled in. This + code is roughly equivalent to i386. */ #include #include #include #include #include +#include int iommu_merge = 0; EXPORT_SYMBOL(iommu_merge); @@ -10,57 +13,80 @@ dma_addr_t bad_dma_address; EXPORT_SYMBOL(bad_dma_address); +int iommu_bio_merge = 0; +EXPORT_SYMBOL(iommu_bio_merge); + +int iommu_sac_force = 0; +EXPORT_SYMBOL(iommu_sac_force); + /* * Dummy IO MMU functions */ -void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) +void *dma_alloc_coherent(struct device *hwdev, size_t size, + dma_addr_t *dma_handle, unsigned gfp) { void *ret; - int gfp = GFP_ATOMIC; - - if (hwdev == NULL || - end_pfn > (hwdev->dma_mask>>PAGE_SHIFT) || /* XXX */ - (u32)hwdev->dma_mask < 0xffffffff) - gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); + u64 mask; + int order = get_order(size); - if (ret != NULL) { - memset(ret, 0, size); + if (hwdev) + mask = hwdev->coherent_dma_mask & *hwdev->dma_mask; + else + mask = 0xffffffff; + for (;;) { + ret = (void *)__get_free_pages(gfp, order); + if (ret == NULL) + return NULL; *dma_handle = virt_to_bus(ret); + if ((*dma_handle & ~mask) == 0) + break; + free_pages((unsigned long)ret, order); + if (gfp & GFP_DMA) + return NULL; + gfp |= GFP_DMA; } + + memset(ret, 0, size); return ret; } +EXPORT_SYMBOL(dma_alloc_coherent); -void pci_free_consistent(struct pci_dev *hwdev, size_t size, +void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { free_pages((unsigned long)vaddr, get_order(size)); } +EXPORT_SYMBOL(dma_free_coherent); -int pci_dma_supported(struct pci_dev *hwdev, u64 mask) +int dma_supported(struct device *hwdev, u64 mask) { /* * we fall back to GFP_DMA when the mask isn't all 1s, * so we can't guarantee allocations that must be * within a tighter range than GFP_DMA.. - * RED-PEN this won't work for pci_map_single. Caller has to - * use GFP_DMA in the first place. + * RED-PEN this won't work for pci_map_single. Caller has to + * use GFP_DMA in the first place. */ if (mask < 0x00ffffff) return 0; return 1; } +EXPORT_SYMBOL(dma_supported); -EXPORT_SYMBOL(pci_dma_supported); +int dma_get_cache_alignment(void) +{ + return boot_cpu_data.x86_clflush_size; +} +EXPORT_SYMBOL(dma_get_cache_alignment); static int __init check_ram(void) { if (end_pfn >= 0xffffffff>>PAGE_SHIFT) { - printk(KERN_ERR "WARNING more than 4GB of memory but no IOMMU.\n" - KERN_ERR "WARNING 32bit PCI may malfunction.\n"); + printk( + KERN_ERR "WARNING more than 4GB of memory but IOMMU not compiled in.\n" + KERN_ERR "WARNING 32bit PCI may malfunction.\n"); } return 0; } diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c --- a/arch/x86_64/kernel/process.c 2004-10-18 14:56:32 -07:00 +++ b/arch/x86_64/kernel/process.c 2004-10-18 14:56:32 -07:00 @@ -130,11 +130,20 @@ { /* endless idle loop with no priority at all */ while (1) { - void (*idle)(void) = pm_idle; - if (!idle) - idle = default_idle; - while (!need_resched()) + while (!need_resched()) { + void (*idle)(void); + /* + * Mark this as an RCU critical section so that + * synchronize_kernel() in the unload path waits + * for our completion. + */ + rcu_read_lock(); + idle = pm_idle; + if (!idle) + idle = default_idle; idle(); + rcu_read_unlock(); + } schedule(); } } @@ -168,9 +177,7 @@ if (cpu_has(c, X86_FEATURE_MWAIT)) { /* * Skip, if setup has overridden idle. - * Also, take care of system with asymmetric CPUs. - * Use, mwait_idle only if all cpus support it. - * If not, we fallback to default_idle() + * One CPU supports mwait => All CPUs supports mwait */ if (!pm_idle) { if (!printed) { @@ -179,10 +186,7 @@ } pm_idle = mwait_idle; } - return; } - pm_idle = default_idle; - return; } static int __init idle_setup (char *str) @@ -255,11 +259,17 @@ void exit_thread(void) { struct task_struct *me = current; + struct thread_struct *t = &me->thread; if (me->thread.io_bitmap_ptr) { - struct tss_struct *tss = init_tss + get_cpu(); - kfree(me->thread.io_bitmap_ptr); - me->thread.io_bitmap_ptr = NULL; - tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); + + kfree(t->io_bitmap_ptr); + t->io_bitmap_ptr = NULL; + /* + * Careful, clear this in the TSS too: + */ + memset(tss->io_bitmap, 0xff, t->io_bitmap_max); + t->io_bitmap_max = 0; put_cpu(); } } @@ -367,8 +377,10 @@ if (unlikely(me->thread.io_bitmap_ptr != NULL)) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); - if (!p->thread.io_bitmap_ptr) + if (!p->thread.io_bitmap_ptr) { + p->thread.io_bitmap_max = 0; return -ENOMEM; + } memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, IO_BITMAP_BYTES); } @@ -387,8 +399,10 @@ } err = 0; out: - if (err && p->thread.io_bitmap_ptr) + if (err && p->thread.io_bitmap_ptr) { kfree(p->thread.io_bitmap_ptr); + p->thread.io_bitmap_max = 0; + } return err; } @@ -409,7 +423,7 @@ struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; int cpu = smp_processor_id(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); unlazy_fpu(prev_p); @@ -495,22 +509,18 @@ * Handle the IO bitmap */ if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { - if (next->io_bitmap_ptr) { + if (next->io_bitmap_ptr) /* - * 2 cachelines copy ... not good, but not that - * bad either. Anyone got something better? - * This only affects processes which use ioperm(). - */ - memcpy(tss->io_bitmap, next->io_bitmap_ptr, IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; - } else { + * Copy the relevant range of the IO bitmap. + * Normally this is 128 bytes or less: + */ + memcpy(tss->io_bitmap, next->io_bitmap_ptr, + max(prev->io_bitmap_max, next->io_bitmap_max)); + else { /* - * a bitmap offset pointing outside of the TSS limit - * causes a nicely controllable SIGSEGV if a process - * tries to use a port IO instruction. The first - * sys_ioperm() call sets up the bitmap properly. + * Clear any possible leftover bits: */ - tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); } } @@ -546,17 +556,16 @@ clear_thread_flag(TIF_IA32); } -asmlinkage long sys_fork(struct pt_regs regs) +asmlinkage long sys_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, regs.rsp, ®s, 0, NULL, NULL); + return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL); } -asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs regs) +asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) { if (!newsp) - newsp = regs.rsp; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, - parent_tid, child_tid); + newsp = regs->rsp; + return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); } /* @@ -569,9 +578,9 @@ * do not have enough call-clobbered registers to hold all * the information you need. */ -asmlinkage long sys_vfork(struct pt_regs regs) +asmlinkage long sys_vfork(struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, ®s, 0, + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0, NULL, NULL); } diff -Nru a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c --- a/arch/x86_64/kernel/ptrace.c 2004-10-18 14:56:28 -07:00 +++ b/arch/x86_64/kernel/ptrace.c 2004-10-18 14:56:28 -07:00 @@ -88,6 +88,7 @@ { long tmp; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); } @@ -344,6 +345,7 @@ set_tsk_thread_flag(child,TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET); @@ -395,6 +397,7 @@ ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; @@ -416,6 +419,7 @@ } tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); + set_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -429,30 +433,32 @@ break; case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned __user *)data, FRAME_SIZE)) { + if (!access_ok(VERIFY_WRITE, (unsigned __user *)data, + sizeof(struct user_regs_struct))) { ret = -EIO; break; } + ret = 0; for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) { - __put_user(getreg(child, ui),(unsigned long __user *) data); + ret |= __put_user(getreg(child, ui),(unsigned long __user *) data); data += sizeof(long); } - ret = 0; break; } case PTRACE_SETREGS: { /* Set all gp regs in the child. */ unsigned long tmp; - if (!access_ok(VERIFY_READ, (unsigned __user *)data, FRAME_SIZE)) { + if (!access_ok(VERIFY_READ, (unsigned __user *)data, + sizeof(struct user_regs_struct))) { ret = -EIO; break; } + ret = 0; for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) { - __get_user(tmp, (unsigned long __user *) data); + ret |= __get_user(tmp, (unsigned long __user *) data); putreg(child, ui, tmp); data += sizeof(long); } - ret = 0; break; } @@ -528,7 +534,8 @@ if (unlikely(current->audit_context)) audit_syscall_exit(current, regs->rax); - if (test_thread_flag(TIF_SYSCALL_TRACE) + if ((test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SINGLESTEP)) && (current->ptrace & PT_PTRACED)) syscall_trace(regs); } diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c --- a/arch/x86_64/kernel/setup.c 2004-10-18 14:55:54 -07:00 +++ b/arch/x86_64/kernel/setup.c 2004-10-18 14:55:54 -07:00 @@ -71,7 +71,7 @@ #ifdef CONFIG_ACPI_BOOT extern int __initdata acpi_ht; extern acpi_interrupt_flags acpi_sci_flags; -/* int __initdata acpi_force = 0; */ +int __initdata acpi_force = 0; #endif /* For PCI or other memory-mapped resources */ @@ -79,8 +79,10 @@ unsigned long saved_video_mode; +#ifdef CONFIG_SWIOTLB int swiotlb; EXPORT_SYMBOL(swiotlb); +#endif /* * Setup options @@ -105,7 +107,8 @@ struct resource standard_io_resources[] = { { "dma1", 0x00, 0x1f, IORESOURCE_BUSY | IORESOURCE_IO }, { "pic1", 0x20, 0x21, IORESOURCE_BUSY | IORESOURCE_IO }, - { "timer", 0x40, 0x5f, IORESOURCE_BUSY | IORESOURCE_IO }, + { "timer0", 0x40, 0x43, IORESOURCE_BUSY | IORESOURCE_IO }, + { "timer1", 0x50, 0x53, IORESOURCE_BUSY | IORESOURCE_IO }, { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY | IORESOURCE_IO }, { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY | IORESOURCE_IO }, { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY | IORESOURCE_IO }, @@ -248,14 +251,14 @@ if (!memcmp(from, "acpi=force", 10)) { /* add later when we do DMI horrors: */ - /* acpi_force = 1; */ + acpi_force = 1; acpi_disabled = 0; } /* acpi=ht just means: do ACPI MADT parsing at bootup, but don't enable the full ACPI interpreter */ if (!memcmp(from, "acpi=ht", 7)) { - /* if (!acpi_force) */ + if (!acpi_force) disable_acpi(); acpi_ht = 1; } @@ -423,6 +426,20 @@ } #endif +#define EBDA_ADDR_POINTER 0x40E +static void __init reserve_ebda_region(void) +{ + unsigned int addr; + /** + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E + */ + addr = *(unsigned short *)phys_to_virt(EBDA_ADDR_POINTER); + addr <<= 4; + if (addr) + reserve_bootmem_generic(addr, PAGE_SIZE); +} + void __init setup_arch(char **cmdline_p) { unsigned long low_mem_size; @@ -487,6 +504,9 @@ */ reserve_bootmem_generic(0, PAGE_SIZE); + /* reserve ebda region */ + reserve_ebda_region(); + #ifdef CONFIG_SMP /* * But first pinch a few for the stack/trampoline stuff @@ -662,6 +682,26 @@ } } display_cacheinfo(c); + + if (c->cpuid_level >= 0x80000008) { + c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1; + if (c->x86_num_cores & (c->x86_num_cores - 1)) + c->x86_num_cores = 1; + +#ifdef CONFIG_NUMA + /* On a dual core setup the lower bits of apic id + distingush the cores. Fix up the CPU<->node mappings + here based on that. + Assumes number of cores is a power of two. */ + if (c->x86_num_cores > 1) { + int cpu = c->x86_apicid; + cpu_to_node[cpu] = cpu >> hweight32(c->x86_num_cores - 1); + printk(KERN_INFO "CPU %d -> Node %d\n", + cpu, cpu_to_node[cpu]); + } +#endif + } + return r; } @@ -705,7 +745,7 @@ } if (index_lsb != index_msb ) index_msb++; - initial_apic_id = ebx >> 24 & 0xff; + initial_apic_id = hard_smp_processor_id(); phys_proc_id[cpu] = initial_apic_id >> index_msb; printk(KERN_INFO "CPU: Physical Processor ID: %d\n", @@ -748,6 +788,7 @@ { 0x43, LVL_2, 512 }, { 0x44, LVL_2, 1024 }, { 0x45, LVL_2, 2048 }, + { 0x60, LVL_1_DATA, 16 }, { 0x66, LVL_1_DATA, 8 }, { 0x67, LVL_1_DATA, 16 }, { 0x68, LVL_1_DATA, 32 }, @@ -885,6 +926,8 @@ c->x86_model_id[0] = '\0'; /* Unset */ c->x86_clflush_size = 64; c->x86_cache_alignment = c->x86_clflush_size; + c->x86_num_cores = 1; + c->x86_apicid = c == &boot_cpu_data ? 0 : c - cpu_data; memset(&c->x86_capability, 0, sizeof c->x86_capability); /* Get vendor name */ @@ -912,6 +955,7 @@ } if (c->x86_capability[0] & (1<<19)) c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; + c->x86_apicid = misc >> 24; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; @@ -931,8 +975,10 @@ /* AMD-defined flags: level 0x80000001 */ xlvl = cpuid_eax(0x80000000); if ( (xlvl & 0xffff0000) == 0x80000000 ) { - if ( xlvl >= 0x80000001 ) + if ( xlvl >= 0x80000001 ) { c->x86_capability[1] = cpuid_edx(0x80000001); + c->x86_capability[5] = cpuid_ecx(0x80000001); + } if ( xlvl >= 0x80000004 ) get_model_name(c); /* Default name */ } @@ -1042,8 +1088,8 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ - "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "tm2", - "est", NULL, "cid", NULL, NULL, "cmpxchg16b", NULL, NULL, + "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "est", + "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; @@ -1131,6 +1177,9 @@ seq_printf(m, " [%d]", i); } } + + if (c->x86_num_cores > 1) + seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores); seq_printf(m, "\n\n"); diff -Nru a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c --- a/arch/x86_64/kernel/setup64.c 2004-10-18 14:56:27 -07:00 +++ b/arch/x86_64/kernel/setup64.c 2004-10-18 14:56:27 -07:00 @@ -60,12 +60,12 @@ */ static int __init nonx_setup(char *str) { - if (!strncmp(str, "on",3)) { + if (!strcmp(str, "on")) { __supported_pte_mask |= _PAGE_NX; do_not_nx = 0; vm_data_default_flags &= ~VM_EXEC; vm_stack_flags &= ~VM_EXEC; - } else if (!strncmp(str, "noforce",7) || !strncmp(str,"off",3)) { + } else if (!strcmp(str, "noforce") || !strcmp(str, "off")) { do_not_nx = (str[0] == 'o'); if (do_not_nx) __supported_pte_mask &= ~_PAGE_NX; @@ -91,26 +91,28 @@ compat (default) Imply PROT_EXEC for PROT_READ */ - static int __init nonx32_setup(char *str) + static int __init nonx32_setup(char *s) { - char *s; - while ((s = strsep(&str, ",")) != NULL) { - if (!strcmp(s, "all") || !strcmp(s,"on")) { + while (*s) { + if (!strncmp(s, "all", 3) || !strncmp(s,"on",2)) { vm_data_default_flags32 &= ~VM_EXEC; vm_stack_flags32 &= ~VM_EXEC; - } else if (!strcmp(s, "off")) { + } else if (!strncmp(s, "off",3)) { vm_data_default_flags32 |= VM_EXEC; vm_stack_flags32 |= VM_EXEC; - } else if (!strcmp(s, "stack")) { + } else if (!strncmp(s, "stack", 5)) { vm_data_default_flags32 |= VM_EXEC; vm_stack_flags32 &= ~VM_EXEC; - } else if (!strcmp(s, "force")) { + } else if (!strncmp(s, "force",5)) { vm_force_exec32 = 0; - } else if (!strcmp(s, "compat")) { + } else if (!strncmp(s, "compat",5)) { vm_force_exec32 = PROT_EXEC; } - } - return 1; + s += strcspn(s, ","); + if (*s == ',') + ++s; + } + return 1; } __setup("noexec32=", nonx32_setup); @@ -193,7 +195,8 @@ char boot_exception_stacks[N_EXCEPTION_STACKS * EXCEPTION_STKSZ] __attribute__((section(".bss.page_aligned"))); -void __init syscall_init(void) +/* May not be marked __init: used by software suspend */ +void syscall_init(void) { /* * LSTAR and STAR live in a bit strange symbiosis. @@ -235,10 +238,11 @@ #else int cpu = smp_processor_id(); #endif - struct tss_struct * t = &init_tss[cpu]; + struct tss_struct *t = &per_cpu(init_tss, cpu); unsigned long v; char *estacks = NULL; struct task_struct *me; + int i; /* CPU 0 is initialised in head64.c */ if (cpu != 0) { @@ -302,12 +306,13 @@ t->ist[v] = (unsigned long)estacks; } - t->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap); /* - * This is required because the CPU will access up to + * <= is required because the CPU will access up to * 8 bits beyond the end of the IO permission bitmap. */ - t->io_bitmap[IO_BITMAP_LONGS] = ~0UL; + for (i = 0; i <= IO_BITMAP_LONGS; i++) + t->io_bitmap[i] = ~0UL; atomic_inc(&init_mm.mm_count); me->active_mm = &init_mm; diff -Nru a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c --- a/arch/x86_64/kernel/signal.c 2004-10-18 14:56:48 -07:00 +++ b/arch/x86_64/kernel/signal.c 2004-10-18 14:56:48 -07:00 @@ -40,7 +40,7 @@ sigset_t *set, struct pt_regs * regs); asmlinkage long -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs regs) +sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) { sigset_t saveset, newset; @@ -59,21 +59,22 @@ spin_unlock_irq(¤t->sighand->siglock); #ifdef DEBUG_SIG printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n", - saveset, newset, ®s, regs.rip); + saveset, newset, regs, regs->rip); #endif - regs.rax = -EINTR; + regs->rax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(®s, &saveset)) + if (do_signal(regs, &saveset)) return -EINTR; } } asmlinkage long -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs regs) +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + struct pt_regs *regs) { - return do_sigaltstack(uss, uoss, regs.rsp); + return do_sigaltstack(uss, uoss, regs->rsp); } @@ -134,13 +135,13 @@ return 1; } -asmlinkage long sys_rt_sigreturn(struct pt_regs regs) +asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe __user *frame; sigset_t set; long eax; - frame = (struct rt_sigframe __user *)(regs.rsp - 8); + frame = (struct rt_sigframe __user *)(regs->rsp - 8); if (verify_area(VERIFY_READ, frame, sizeof(*frame))) { goto badframe; } @@ -154,7 +155,7 @@ recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &eax)) { + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) { goto badframe; } @@ -162,13 +163,13 @@ printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax); #endif - if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs.rsp) == -EFAULT) + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->rsp) == -EFAULT) goto badframe; return eax; badframe: - signal_fault(®s,frame,"sigreturn"); + signal_fault(regs,frame,"sigreturn"); return 0; } @@ -180,6 +181,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me) { int err = 0; + unsigned long eflags; err |= __put_user(0, &sc->gs); err |= __put_user(0, &sc->fs); @@ -203,7 +205,11 @@ err |= __put_user(me->thread.trap_no, &sc->trapno); err |= __put_user(me->thread.error_code, &sc->err); err |= __put_user(regs->rip, &sc->rip); - err |= __put_user(regs->eflags, &sc->eflags); + eflags = regs->eflags; + if (current->ptrace & PT_PTRACED) { + eflags &= ~TF_MASK; + } + err |= __put_user(eflags, &sc->eflags); err |= __put_user(mask, &sc->oldmask); err |= __put_user(me->thread.cr2, &sc->cr2); @@ -287,7 +293,7 @@ if (ka->sa.sa_flags & SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { - printk("%s forgot to set SA_RESTORER for signal %d.\n", me->comm, sig); + /* could use a vstub here */ goto give_sigsegv; } @@ -318,7 +324,13 @@ regs->rsp = (unsigned long)frame; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #ifdef DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -328,9 +340,7 @@ return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - signal_fault(regs,frame,"signal deliver"); + force_sigsegv(sig, current); } /* @@ -338,11 +348,9 @@ */ static void -handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs) +handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, + sigset_t *oldset, struct pt_regs *regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - #ifdef DEBUG_SIG printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig, regs->rip, regs->rsp, regs); @@ -379,9 +387,6 @@ #endif setup_rt_frame(sig, ka, info, oldset, regs); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -398,6 +403,7 @@ */ int do_signal(struct pt_regs *regs, sigset_t *oldset) { + struct k_sigaction ka; siginfo_t info; int signr; @@ -419,7 +425,7 @@ if (!oldset) oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Reenable any watchpoints before delivering the * signal to user space. The processor register will @@ -430,7 +436,7 @@ asm volatile("movq %0,%%db7" : : "r" (current->thread.debugreg7)); /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, oldset, regs); + handle_signal(signr, &info, &ka, oldset, regs); return 1; } diff -Nru a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c --- a/arch/x86_64/kernel/smp.c 2004-10-18 14:57:19 -07:00 +++ b/arch/x86_64/kernel/smp.c 2004-10-18 14:57:19 -07:00 @@ -382,30 +382,14 @@ * this function sends a 'generic call function' IPI to all other CPUs * in the system. */ - -int smp_call_function (void (*func) (void *info), void *info, int nonatomic, - int wait) -/* - * [SUMMARY] Run a function on all other CPUs. - * The function to run. This must be fast and non-blocking. - * An arbitrary pointer to pass to the function. - * currently unused. - * If true, wait (atomically) until function has completed on other CPUs. - * [RETURNS] 0 on success, else a negative status code. Does not return until - * remote CPUs are nearly ready to execute <> or are or have executed. - * - * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. - */ +static void __smp_call_function (void (*func) (void *info), void *info, + int nonatomic, int wait) { struct call_data_struct data; int cpus = num_online_cpus()-1; if (!cpus) - return 0; - - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); + return; data.func = func; data.info = info; @@ -414,7 +398,6 @@ if (wait) atomic_set(&data.finished, 0); - spin_lock(&call_lock); call_data = &data; wmb(); /* Send a message to all other CPUs and wait for them to respond */ @@ -427,8 +410,29 @@ if (wait) while (atomic_read(&data.finished) != cpus) barrier(); - spin_unlock(&call_lock); +} +/* + * smp_call_function - run a function on all other CPUs. + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. + * @nonatomic: currently unused. + * @wait: If true, wait (atomically) until function has completed on other + * CPUs. + * + * Returns 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute func or are or have executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler or from a bottom half handler. + * Actually there are a few legal cases, like panic. + */ +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + spin_lock(&call_lock); + __smp_call_function(func,info,nonatomic,wait); + spin_unlock(&call_lock); return 0; } @@ -452,7 +456,16 @@ void smp_send_stop(void) { - smp_call_function(smp_really_stop_cpu, NULL, 1, 0); + int nolock = 0; + /* Don't deadlock on the call lock in panic */ + if (!spin_trylock(&call_lock)) { + udelay(100); + /* ignore locking because we have paniced anyways */ + nolock = 1; + } + __smp_call_function(smp_really_stop_cpu, NULL, 1, 0); + if (!nolock) + spin_unlock(&call_lock); smp_stop_cpu(); } diff -Nru a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c --- a/arch/x86_64/kernel/smpboot.c 2004-10-18 14:57:05 -07:00 +++ b/arch/x86_64/kernel/smpboot.c 2004-10-18 14:57:05 -07:00 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ /* which logical CPU number maps to which CPU (physical APIC ID) */ volatile char x86_cpu_to_apicid[NR_CPUS]; +EXPORT_SYMBOL(x86_cpu_to_apicid); static cpumask_t cpu_callin_map; cpumask_t cpu_callout_map; @@ -390,16 +392,6 @@ extern volatile unsigned long init_rsp; extern void (*initial_code)(void); -static struct task_struct * __init fork_by_hand(void) -{ - struct pt_regs regs; - /* - * don't care about the eip and regs settings since - * we'll never reschedule the forked task. - */ - return copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); -} - #if APIC_DEBUG static inline void inquire_remote_apic(int apicid) { @@ -573,26 +565,17 @@ * We can't use kernel_thread since we must avoid to * reschedule the child. */ - idle = fork_by_hand(); + idle = fork_idle(cpu); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); - wake_up_forked_process(idle); x86_cpu_to_apicid[cpu] = apicid; - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ - init_idle(idle,cpu); - - unhash_process(idle); - cpu_pda[cpu].pcurrent = idle; start_rip = setup_trampoline(); init_rsp = idle->thread.rsp; - init_tss[cpu].rsp0 = init_rsp; + per_cpu(init_tss,cpu).rsp0 = init_rsp; initial_code = start_secondary; clear_ti_thread_flag(idle->thread_info, TIF_FORK); @@ -967,6 +950,9 @@ void __init smp_cpus_done(unsigned int max_cpus) { +#ifdef CONFIG_X86_IO_APIC + setup_ioapic_dest(); +#endif zap_low_mappings(); } diff -Nru a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c --- a/arch/x86_64/kernel/suspend.c 2004-10-18 14:56:31 -07:00 +++ b/arch/x86_64/kernel/suspend.c 2004-10-18 14:56:31 -07:00 @@ -129,7 +129,7 @@ void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct *t = &per_cpu(init_tss, cpu); set_tss_desc(cpu,t); /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ diff -Nru a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S --- a/arch/x86_64/kernel/suspend_asm.S 2004-10-18 14:57:03 -07:00 +++ b/arch/x86_64/kernel/suspend_asm.S 2004-10-18 14:57:03 -07:00 @@ -1,22 +1,18 @@ -/* originally gcc generated, but now changed. don't overwrite. */ +/* Originally gcc generated, modified by hand + * + * This may not use any stack, nor any variable that is not "NoSave": + * + * Its rewriting one kernel image with another. What is stack in "old" + * image could very well be data page in "new" image, and overwriting + * your own stack under you is bad idea. + */ .text #include #include #include -/* Input: - * rdi resume flag - */ - -ENTRY(do_magic) -.LFB5: - subq $8, %rsp -.LCFI2: - testl %edi, %edi - jne .L90 - call do_magic_suspend_1 - call save_processor_state +ENTRY(swsusp_arch_suspend) movq %rsp, saved_context_esp(%rip) movq %rax, saved_context_eax(%rip) @@ -36,36 +32,35 @@ movq %r15, saved_context_r15(%rip) pushfq ; popq saved_context_eflags(%rip) - addq $8, %rsp - jmp do_magic_suspend_2 -.L90: + call swsusp_save + ret + +ENTRY(swsusp_arch_resume) /* set up cr3 */ leaq init_level4_pgt(%rip),%rax subq $__START_KERNEL_map,%rax - movq %rax,%cr3 + movq %rax,%cr3 movq mmu_cr4_features(%rip), %rax movq %rax, %rdx - andq $~(1<<7), %rdx # PGE - movq %rdx, %cr4; # turn off PGE - movq %cr3, %rcx; # flush TLB - movq %rcx, %cr3; - movq %rax, %cr4; # turn PGE back on + movq %rdx, %cr4; # turn off PGE + movq %cr3, %rcx; # flush TLB + movq %rcx, %cr3; + movq %rax, %cr4; # turn PGE back on - call do_magic_resume_1 movl nr_copy_pages(%rip), %eax xorl %ecx, %ecx - movq $0, loop(%rip) + movq $0, %r10 testl %eax, %eax - je .L108 + jz done .L105: xorl %esi, %esi - movq $0, loop2(%rip) + movq $0, %r11 jmp .L104 .p2align 4,,7 -.L111: - movq loop(%rip), %rcx +copy_one_page: + movq %r10, %rcx .L104: movq pagedir_nosave(%rip), %rdx movq %rcx, %rax @@ -75,27 +70,26 @@ movzbl (%rsi,%rax), %eax movb %al, (%rsi,%rcx) - movq %cr3, %rax; # flush TLB - movq %rax, %cr3; + movq %cr3, %rax; # flush TLB + movq %rax, %cr3; - movq loop2(%rip), %rax + movq %r11, %rax incq %rax cmpq $4095, %rax movq %rax, %rsi - movq %rax, loop2(%rip) - jbe .L111 - movq loop(%rip), %rax + movq %rax, %r11 + jbe copy_one_page + movq %r10, %rax incq %rax movq %rax, %rcx - movq %rax, loop(%rip) + movq %rax, %r10 mov nr_copy_pages(%rip), %eax cmpq %rax, %rcx jb .L105 -.L108: - .align 4 +done: movl $24, %eax + movl %eax, %ds - movl %eax, %ds movq saved_context_esp(%rip), %rsp movq saved_context_ebp(%rip), %rbp movq saved_context_eax(%rip), %rax @@ -113,13 +107,5 @@ movq saved_context_r14(%rip), %r14 movq saved_context_r15(%rip), %r15 pushq saved_context_eflags(%rip) ; popfq - call restore_processor_state - addq $8, %rsp - jmp do_magic_resume_2 - - .section .data.nosave -loop: - .quad 0 -loop2: - .quad 0 - .previous + call swsusp_restore + ret diff -Nru a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c --- a/arch/x86_64/kernel/time.c 2004-10-18 14:56:48 -07:00 +++ b/arch/x86_64/kernel/time.c 2004-10-18 14:56:48 -07:00 @@ -11,7 +11,6 @@ * Copyright (c) 2002 Vojtech Pavlik * Copyright (c) 2003 Andi Kleen * RTC support code taken from arch/i386/kernel/timers/time_hpet.c - * */ #include @@ -33,6 +32,7 @@ #include #include #include +#include #include #ifdef CONFIG_X86_LOCAL_APIC #include @@ -42,6 +42,10 @@ EXPORT_SYMBOL(jiffies_64); +#ifdef CONFIG_CPU_FREQ +static void cpufreq_delayed_get(void); +#endif + extern int using_apic_timer; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -82,7 +86,7 @@ * timer interrupt has happened already, but vxtime.trigger wasn't updated yet. * This is not a problem, because jiffies hasn't updated either. They are bound * together by xtime_lock. - */ + */ static inline unsigned int do_gettimeoffset_tsc(void) { @@ -119,7 +123,7 @@ usec = xtime.tv_nsec / 1000; /* i386 does some correction here to keep the clock - monotonus even when ntpd is fixing drift. + monotonous even when ntpd is fixing drift. But they didn't work for me, there is a non monotonic clock anyways with ntp. I dropped all corrections now until a real solution can @@ -176,6 +180,28 @@ EXPORT_SYMBOL(do_settimeofday); +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + /* Assume the lock function has either no stack frame or only a single word. + This checks if the address on the stack looks like a kernel text address. + There is a small window for false hits, but in that case the tick + is just accounted to the spinlock function. + Better would be to write these functions in assembler again + and check exactly. */ + if (in_lock_functions(pc)) { + char *v = *(char **)regs->rsp; + if ((v >= _stext && v <= _etext) || + (v >= _sinittext && v <= _einittext) || + (v >= (char *)MODULES_VADDR && v <= (char *)MODULES_END)) + return (unsigned long)v; + return ((unsigned long *)regs->rsp)[1]; + } + return pc; +} +EXPORT_SYMBOL(profile_pc); + /* * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500 * ms after the second nowtime has started, because when nowtime is written @@ -214,7 +240,7 @@ * overflow. This avoids messing with unknown time zones but requires your RTC * not to be off by more than 15 minutes. Since we're calling it only when * our clock is externally synchronized using NTP, this shouldn't be a problem. - */ + */ real_seconds = nowtime % 60; real_minutes = nowtime / 60; @@ -293,19 +319,56 @@ } EXPORT_SYMBOL(monotonic_clock); +static noinline void handle_lost_ticks(int lost, struct pt_regs *regs) +{ + static long lost_count; + static int warned; + + if (report_lost_ticks) { + printk(KERN_WARNING "time.c: Lost %d timer " + "tick(s)! ", lost); + print_symbol("rip %s)\n", regs->rip); + } + + if (lost_count == 100 && !warned) { + printk(KERN_WARNING + "warning: many lost ticks.\n" + KERN_WARNING "Your time source seems to be instable or " + "some driver is hogging interupts\n"); + print_symbol("rip %s\n", regs->rip); + if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) { + printk(KERN_WARNING "Falling back to HPET\n"); + vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; + vxtime.mode = VXTIME_HPET; + do_gettimeoffset = do_gettimeoffset_hpet; + } + /* else should fall back to PIT, but code missing. */ + warned = 1; + } else + lost_count++; + +#ifdef CONFIG_CPU_FREQ + /* In some cases the CPU can change frequency without us noticing + (like going into thermal throttle) + Give cpufreq a change to catch up. */ + if ((lost_count+1) % 25 == 0) { + cpufreq_delayed_get(); + } +#endif +} static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { static unsigned long rtc_update = 0; - unsigned long tsc, lost = 0; - int delay, offset = 0; + unsigned long tsc; + int delay, offset = 0, lost = 0; /* * Here we are in the timer irq handler. We have irqs locally disabled (so we * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running * on the other CPU, so we need a lock. We also need to lock the vsyscall * variables, because both do_timer() and us change them -arca+vojtech - */ + */ write_seqlock(&xtime_lock); @@ -354,12 +417,8 @@ (((long) offset << 32) / vxtime.tsc_quot) - 1; } - if (lost) { - if (report_lost_ticks) { - printk(KERN_WARNING "time.c: Lost %ld timer " - "tick(s)! ", lost); - print_symbol("rip %s)\n", regs->rip); - } + if (lost > 0) { + handle_lost_ticks(lost, regs); jiffies += lost; } @@ -376,7 +435,7 @@ */ #ifndef CONFIG_X86_LOCAL_APIC - x86_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #else if (!using_apic_timer) smp_local_timer_interrupt(regs); @@ -509,6 +568,38 @@ Should fix up last_tsc too. Currently gettimeofday in the first tick after the change will be slightly wrong. */ +#include + +static unsigned int cpufreq_delayed_issched = 0; +static unsigned int cpufreq_init = 0; +static struct work_struct cpufreq_delayed_get_work; + +static void handle_cpufreq_delayed_get(void *v) +{ + unsigned int cpu; + for_each_online_cpu(cpu) { + cpufreq_get(cpu); + } + cpufreq_delayed_issched = 0; +} + +/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries + * to verify the CPU frequency the timing core thinks the CPU is running + * at is still correct. + */ +static void cpufreq_delayed_get(void) +{ + static int warned; + if (cpufreq_init && !cpufreq_delayed_issched) { + cpufreq_delayed_issched = 1; + if (!warned) { + warned = 1; + printk(KERN_DEBUG "Losing some ticks... checking if CPU frequency changed.\n"); + } + schedule_work(&cpufreq_delayed_get_work); + } +} + static unsigned int ref_freq = 0; static unsigned long loops_per_jiffy_ref = 0; @@ -518,14 +609,18 @@ void *data) { struct cpufreq_freqs *freq = data; - unsigned long *lpj; + unsigned long *lpj, dummy; + lpj = &dummy; + if (!(freq->flags & CPUFREQ_CONST_LOOPS)) #ifdef CONFIG_SMP lpj = &cpu_data[freq->cpu].loops_per_jiffy; #else lpj = &boot_cpu_data.loops_per_jiffy; #endif + + if (!ref_freq) { ref_freq = freq->old; loops_per_jiffy_ref = *lpj; @@ -538,7 +633,8 @@ cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); - vxtime.tsc_quot = (1000L << 32) / cpu_khz; + if (!(freq->flags & CPUFREQ_CONST_LOOPS)) + vxtime.tsc_quot = (1000L << 32) / cpu_khz; } set_cyc2ns_scale(cpu_khz_ref / 1000); @@ -549,6 +645,18 @@ static struct notifier_block time_cpufreq_notifier_block = { .notifier_call = time_cpufreq_notifier }; + +static int __init cpufreq_tsc(void) +{ + INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL); + if (!cpufreq_register_notifier(&time_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER)) + cpufreq_init = 1; + return 0; +} + +core_initcall(cpufreq_tsc); + #endif /* @@ -705,9 +813,9 @@ outl(0x800038a0, 0xcf8); outl(0xff000001, 0xcfc); outl(0x800038a0, 0xcf8); - hpet_address = inl(0xcfc) & 0xfffffffe; + vxtime.hpet_address = inl(0xcfc) & 0xfffffffe; printk(KERN_WARNING "time.c: WARNING: Enabled HPET " - "at %#lx.\n", hpet_address); + "at %#lx.\n", vxtime.hpet_address); } #endif if (nohpet) @@ -725,8 +833,8 @@ cpu_khz = hpet_calibrate_tsc(); timename = "HPET"; } else { - pit_init(); - cpu_khz = pit_calibrate_tsc(); + pit_init(); + cpu_khz = pit_calibrate_tsc(); timename = "PIT"; } @@ -742,11 +850,6 @@ setup_irq(0, &irq0); set_cyc2ns_scale(cpu_khz / 1000); - -#ifdef CONFIG_CPU_FREQ - cpufreq_register_notifier(&time_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); -#endif } void __init time_init_smp(void) @@ -781,11 +884,12 @@ static int time_resume(struct sys_device *dev) { + unsigned long flags; unsigned long sec = get_cmos_time() + clock_cmos_diff; - write_seqlock_irq(&xtime_lock); + write_seqlock_irqsave(&xtime_lock,flags); xtime.tv_sec = sec; xtime.tv_nsec = 0; - write_sequnlock_irq(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock,flags); return 0; } @@ -1037,6 +1141,8 @@ return IRQ_HANDLED; } #endif + + static int __init nohpet_setup(char *s) { diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c 2004-10-18 14:55:54 -07:00 +++ b/arch/x86_64/kernel/traps.c 2004-10-18 14:55:54 -07:00 @@ -110,9 +110,10 @@ { int k; for (k = 0; k < N_EXCEPTION_STACKS; k++) { - unsigned long end = init_tss[cpu].ist[k] + EXCEPTION_STKSZ; + struct tss_struct *tss = &per_cpu(init_tss, cpu); + unsigned long end = tss->ist[k] + EXCEPTION_STKSZ; - if (stack >= init_tss[cpu].ist[k] && stack <= end) + if (stack >= tss->ist[k] && stack <= end) return (unsigned long *)end; } return NULL; @@ -352,7 +353,7 @@ #ifdef CONFIG_DEBUG_PAGEALLOC printk("DEBUG_PAGEALLOC"); #endif - printk("\n"); + printk("\n"); notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); show_registers(regs); /* Executive summary in case the oops scrolled away */ @@ -436,7 +437,8 @@ #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ return; \ do_trap(trapnr, signr, str, regs, error_code, NULL); \ } @@ -449,7 +451,8 @@ info.si_errno = 0; \ info.si_code = sicode; \ info.si_addr = (void __user *)siaddr; \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ return; \ do_trap(trapnr, signr, str, regs, error_code, &info); \ } @@ -463,14 +466,15 @@ DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) -DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) DO_ERROR(18, SIGSEGV, "reserved", reserved) #define DO_ERROR_STACK(trapnr, signr, str, name) \ asmlinkage void *do_##name(struct pt_regs * regs, long error_code) \ { \ struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ return regs; \ if (regs->cs & 3) { \ memcpy(pr, regs, sizeof(struct pt_regs)); \ @@ -513,7 +517,7 @@ tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; force_sig(SIGSEGV, tsk); - return; + return; } /* kernel gp */ @@ -564,7 +568,8 @@ unsigned char reason = inb(0x61); if (!(reason & 0xc0)) { - if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) == NOTIFY_BAD) + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) + == NOTIFY_STOP) return; #ifdef CONFIG_X86_LOCAL_APIC /* @@ -579,7 +584,7 @@ unknown_nmi_error(reason, regs); return; } - if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_BAD) + if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP) return; if (reason & 0x80) mem_parity_error(reason, regs); @@ -670,27 +675,53 @@ return regs; clear_TF_reenable: - printk("clear_tf_reenable\n"); set_tsk_thread_flag(tsk, TIF_SINGLESTEP); clear_TF: /* RED-PEN could cause spurious errors */ if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP) - != NOTIFY_BAD) + != NOTIFY_STOP) regs->eflags &= ~TF_MASK; return regs; } +static int kernel_math_error(struct pt_regs *regs, char *str) +{ + const struct exception_table_entry *fixup; + fixup = search_exception_tables(regs->rip); + if (fixup) { + regs->rip = fixup->fixup; + return 1; + } + notify_die(DIE_GPF, str, regs, 0, 16, SIGFPE); +#if 0 + /* This should be a die, but warn only for now */ + die(str, regs, 0); +#else + printk(KERN_DEBUG "%s: %s at ", current->comm, str); + printk_address(regs->rip); + printk("\n"); +#endif + return 0; +} + /* * Note that we play around with the 'TS' bit in an attempt to get * the correct behaviour even in the presence of the asynchronous * IRQ13 behaviour */ -void math_error(void __user *rip) +asmlinkage void do_coprocessor_error(struct pt_regs *regs) { + void __user *rip = (void __user *)(regs->rip); struct task_struct * task; siginfo_t info; unsigned short cwd, swd; + + conditional_sti(regs); + if ((regs->cs & 3) == 0 && + kernel_math_error(regs, "kernel x87 math error")) + return; + /* * Save the info for the exception handler and clear the error. */ @@ -740,23 +771,23 @@ force_sig_info(SIGFPE, &info, task); } -asmlinkage void do_coprocessor_error(struct pt_regs * regs) -{ - conditional_sti(regs); - math_error((void __user *)regs->rip); -} - asmlinkage void bad_intr(void) { printk("bad interrupt"); } -static inline void simd_math_error(void __user *rip) +asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) { + void __user *rip = (void __user *)(regs->rip); struct task_struct * task; siginfo_t info; unsigned short mxcsr; + conditional_sti(regs); + if ((regs->cs & 3) == 0 && + kernel_math_error(regs, "simd math error")) + return; + /* * Save the info for the exception handler and clear the error. */ @@ -797,12 +828,6 @@ break; } force_sig_info(SIGFPE, &info, task); -} - -asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs) -{ - conditional_sti(regs); - simd_math_error((void __user *)regs->rip); } asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs) diff -Nru a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S --- a/arch/x86_64/kernel/vmlinux.lds.S 2004-10-18 14:55:54 -07:00 +++ b/arch/x86_64/kernel/vmlinux.lds.S 2004-10-18 14:55:54 -07:00 @@ -16,6 +16,7 @@ .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x9090 @@ -91,9 +92,6 @@ __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; - __start___param = .; - __param : { *(__param) } - __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c --- a/arch/x86_64/kernel/x8664_ksyms.c 2004-10-18 14:56:13 -07:00 +++ b/arch/x86_64/kernel/x8664_ksyms.c 2004-10-18 14:56:13 -07:00 @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -63,10 +62,10 @@ EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(ip_compute_csum); @@ -76,14 +75,14 @@ EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL_NOVERS(__get_user_1); -EXPORT_SYMBOL_NOVERS(__get_user_2); -EXPORT_SYMBOL_NOVERS(__get_user_4); -EXPORT_SYMBOL_NOVERS(__get_user_8); -EXPORT_SYMBOL_NOVERS(__put_user_1); -EXPORT_SYMBOL_NOVERS(__put_user_2); -EXPORT_SYMBOL_NOVERS(__put_user_4); -EXPORT_SYMBOL_NOVERS(__put_user_8); +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); +EXPORT_SYMBOL(__get_user_8); +EXPORT_SYMBOL(__put_user_1); +EXPORT_SYMBOL(__put_user_2); +EXPORT_SYMBOL(__put_user_4); +EXPORT_SYMBOL(__put_user_8); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); @@ -108,18 +107,15 @@ EXPORT_SYMBOL(pci_mem_start); #endif -#ifdef CONFIG_X86_USE_3DNOW -EXPORT_SYMBOL(_mmx_memcpy); -EXPORT_SYMBOL(mmx_clear_page); -EXPORT_SYMBOL(mmx_copy_page); -#endif +EXPORT_SYMBOL(copy_page); +EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(cpu_pda); #ifdef CONFIG_SMP EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(cpu_online_map); -EXPORT_SYMBOL_NOVERS(__write_lock_failed); -EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(__write_lock_failed); +EXPORT_SYMBOL(__read_lock_failed); EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(smp_call_function); @@ -164,28 +160,35 @@ extern char * strcat(char *, const char *); extern int memcmp(const void * cs,const void * ct,size_t count); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(strlen); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(strcpy); -EXPORT_SYMBOL_NOVERS(strncmp); -EXPORT_SYMBOL_NOVERS(strncpy); -EXPORT_SYMBOL_NOVERS(strchr); -EXPORT_SYMBOL_NOVERS(strcmp); -EXPORT_SYMBOL_NOVERS(strcat); -EXPORT_SYMBOL_NOVERS(strncat); -EXPORT_SYMBOL_NOVERS(memchr); -EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(__memcpy); -EXPORT_SYMBOL_NOVERS(memcmp); - -/* syscall export needed for misdesigned sound drivers. */ -EXPORT_SYMBOL(sys_read); -EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_open); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(__memcpy); +EXPORT_SYMBOL(memcmp); + +#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM +/* prototypes are wrong, these are assembly with custom calling functions */ +extern void rwsem_down_read_failed_thunk(void); +extern void rwsem_wake_thunk(void); +extern void rwsem_downgrade_thunk(void); +extern void rwsem_down_write_failed_thunk(void); +EXPORT_SYMBOL(rwsem_down_read_failed_thunk); +EXPORT_SYMBOL(rwsem_wake_thunk); +EXPORT_SYMBOL(rwsem_downgrade_thunk); +EXPORT_SYMBOL(rwsem_down_write_failed_thunk); +#endif EXPORT_SYMBOL(empty_zero_page); @@ -201,7 +204,7 @@ #endif extern void do_softirq_thunk(void); -EXPORT_SYMBOL_NOVERS(do_softirq_thunk); +EXPORT_SYMBOL(do_softirq_thunk); void out_of_line_bug(void); EXPORT_SYMBOL(out_of_line_bug); @@ -211,10 +214,9 @@ extern unsigned long __supported_pte_mask; EXPORT_SYMBOL(__supported_pte_mask); -EXPORT_SYMBOL(clear_page); - #ifdef CONFIG_SMP EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL_GPL(flush_tlb_all); #endif +EXPORT_SYMBOL(cpu_khz); diff -Nru a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile --- a/arch/x86_64/lib/Makefile 2004-10-18 14:56:15 -07:00 +++ b/arch/x86_64/lib/Makefile 2004-10-18 14:56:15 -07:00 @@ -8,7 +8,7 @@ lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ - thunk.o clear_page.o copy_page.o bitstr.o + thunk.o clear_page.o copy_page.o bitstr.o bitops.o lib-y += memcpy.o memmove.o memset.o copy_user.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff -Nru a/arch/x86_64/lib/bitops.c b/arch/x86_64/lib/bitops.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/x86_64/lib/bitops.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,140 @@ +#include +#include + +#undef find_first_zero_bit +#undef find_next_zero_bit +#undef find_first_bit +#undef find_next_bit + +/** + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ +inline long find_first_zero_bit(const unsigned long * addr, unsigned long size) +{ + long d0, d1, d2; + long res; + + if (!size) + return 0; + asm volatile( + " repe; scasq\n" + " je 1f\n" + " xorq -8(%%rdi),%%rax\n" + " subq $8,%%rdi\n" + " bsfq %%rax,%%rdx\n" + "1: subq %[addr],%%rdi\n" + " shlq $3,%%rdi\n" + " addq %%rdi,%%rdx" + :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2) + :"0" (0ULL), "1" ((size + 63) >> 6), "2" (addr), "3" (-1ULL), + [addr] "r" (addr) : "memory"); + return res; +} + +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +long find_next_zero_bit (const unsigned long * addr, long size, long offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 6); + unsigned long set = 0; + unsigned long res, bit = offset&63; + + if (bit) { + /* + * Look for zero in first word + */ + asm("bsfq %1,%0\n\t" + "cmoveq %2,%0" + : "=r" (set) + : "r" (~(*p >> bit)), "r"(64L)); + if (set < (64 - bit)) + return set + offset; + set = 64 - bit; + p++; + } + /* + * No zero yet, search remaining full words for a zero + */ + res = find_first_zero_bit ((const unsigned long *)p, + size - 64 * (p - (unsigned long *) addr)); + return (offset + set + res); +} + +static inline long +__find_first_bit(const unsigned long * addr, unsigned long size) +{ + long d0, d1; + long res; + + asm volatile( + " repe; scasq\n" + " jz 1f\n" + " subq $8,%%rdi\n" + " bsfq (%%rdi),%%rax\n" + "1: subq %[addr],%%rdi\n" + " shlq $3,%%rdi\n" + " addq %%rdi,%%rax" + :"=a" (res), "=&c" (d0), "=&D" (d1) + :"0" (0ULL), + "1" ((size + 63) >> 6), "2" (addr), + [addr] "r" (addr) : "memory"); + return res; +} + +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first set bit, not the number of the byte + * containing a bit. + */ +long find_first_bit(const unsigned long * addr, unsigned long size) +{ + return __find_first_bit(addr,size); +} + +/** + * find_next_bit - find the first set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +long find_next_bit(const unsigned long * addr, long size, long offset) +{ + const unsigned long * p = addr + (offset >> 6); + unsigned long set = 0, bit = offset & 63, res; + + if (bit) { + /* + * Look for nonzero in the first 64 bits: + */ + asm("bsfq %1,%0\n\t" + "cmoveq %2,%0\n\t" + : "=r" (set) + : "r" (*p >> bit), "r" (64L)); + if (set < (64 - bit)) + return set + offset; + set = 64 - bit; + p++; + } + /* + * No set bit yet, search remaining full words for a bit + */ + res = __find_first_bit (p, size - 64 * (p - addr)); + return (offset + set + res); +} + +EXPORT_SYMBOL(find_next_bit); +EXPORT_SYMBOL(find_first_bit); +EXPORT_SYMBOL(find_first_zero_bit); +EXPORT_SYMBOL(find_next_zero_bit); diff -Nru a/arch/x86_64/lib/bitstr.c b/arch/x86_64/lib/bitstr.c --- a/arch/x86_64/lib/bitstr.c 2004-10-18 14:56:29 -07:00 +++ b/arch/x86_64/lib/bitstr.c 2004-10-18 14:56:29 -07:00 @@ -1,3 +1,4 @@ +#include #include /* Find string of zero bits in a bitmap */ @@ -23,3 +24,5 @@ } return n; } + +EXPORT_SYMBOL(find_next_zero_string); diff -Nru a/arch/x86_64/lib/csum-wrappers.c b/arch/x86_64/lib/csum-wrappers.c --- a/arch/x86_64/lib/csum-wrappers.c 2004-10-18 14:55:53 -07:00 +++ b/arch/x86_64/lib/csum-wrappers.c 2004-10-18 14:55:53 -07:00 @@ -22,6 +22,7 @@ csum_partial_copy_from_user(const char __user *src, char *dst, int len, unsigned int isum, int *errp) { + might_sleep(); *errp = 0; if (likely(access_ok(VERIFY_READ,src, len))) { /* Why 6, not 7? To handle odd addresses aligned we @@ -69,6 +70,7 @@ csum_partial_copy_to_user(const char *src, char __user *dst, int len, unsigned int isum, int *errp) { + might_sleep(); if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) { *errp = -EFAULT; return 0; diff -Nru a/arch/x86_64/lib/memmove.c b/arch/x86_64/lib/memmove.c --- a/arch/x86_64/lib/memmove.c 2004-10-18 14:56:28 -07:00 +++ b/arch/x86_64/lib/memmove.c 2004-10-18 14:56:28 -07:00 @@ -10,18 +10,10 @@ if (dest < src) { __inline_memcpy(dest,src,count); } else { - /* Could be more clever and move longs */ - unsigned long d0, d1, d2; - __asm__ __volatile__( - "std\n\t" - "rep\n\t" - "movsb\n\t" - "cld" - : "=&c" (d0), "=&S" (d1), "=&D" (d2) - :"0" (count), - "1" (count-1+(const char *)src), - "2" (count-1+(char *)dest) - :"memory"); + char *p = (char *) dest + count; + char *s = (char *) src + count; + while (count--) + *--p = *--s; } return dest; } diff -Nru a/arch/x86_64/lib/usercopy.c b/arch/x86_64/lib/usercopy.c --- a/arch/x86_64/lib/usercopy.c 2004-10-18 14:55:54 -07:00 +++ b/arch/x86_64/lib/usercopy.c 2004-10-18 14:55:54 -07:00 @@ -14,6 +14,7 @@ #define __do_strncpy_from_user(dst,src,count,res) \ do { \ long __d0, __d1, __d2; \ + might_sleep(); \ __asm__ __volatile__( \ " testq %1,%1\n" \ " jz 2f\n" \ @@ -63,6 +64,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size) { long __d0; + might_sleep(); /* no memory constraint because it doesn't change any memory gcc knows about */ asm volatile( diff -Nru a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c --- a/arch/x86_64/mm/fault.c 2004-10-18 14:55:54 -07:00 +++ b/arch/x86_64/mm/fault.c 2004-10-18 14:55:54 -07:00 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -58,16 +57,17 @@ /* Sometimes the CPU reports invalid exceptions on prefetch. Check that here and ignore. Opcode checker based on code by Richard Brunner */ -static int is_prefetch(struct pt_regs *regs, unsigned long addr) +static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, + unsigned long error_code) { unsigned char *instr = (unsigned char *)(regs->rip); int scan_more = 1; int prefetch = 0; unsigned char *max_instr = instr + 15; - /* Avoid recursive faults for this common case */ - if (regs->rip == addr) - return 0; + /* If it was a exec fault ignore */ + if (error_code & (1<<4)) + return 0; /* Code segments in LDT could have a non zero base. Don't check when that's possible */ @@ -218,6 +218,18 @@ (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); } +static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, + unsigned long error_code) +{ + oops_begin(); + printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", + current->comm, address); + dump_pagetable(address); + __die("Bad pagetable", regs, error_code); + oops_end(); + do_exit(SIGKILL); +} + int page_fault_trace; int exception_trace = 1; @@ -268,11 +280,32 @@ mm = tsk->mm; info.si_code = SEGV_MAPERR; - /* 5 => page not present and from supervisor mode */ - if (unlikely(!(error_code & 5) && - ((address >= VMALLOC_START && address <= VMALLOC_END) || - (address >= MODULES_VADDR && address <= MODULES_END)))) - goto vmalloc_fault; + + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + * + * This verifies that the fault happens in kernel space + * (error_code & 4) == 0, and that the fault was not a + * protection error (error_code & 1) == 0. + */ + if (unlikely(address >= TASK_SIZE)) { + if (!(error_code & 5)) + goto vmalloc_fault; + /* + * Don't take the mm semaphore here. If we fixup a prefetch + * fault we could otherwise deadlock. + */ + goto bad_area_nosemaphore; + } + + if (unlikely(error_code & (1 << 3))) + goto page_table_corruption; /* * If we're in an interrupt or have no user @@ -282,7 +315,27 @@ goto bad_area_nosemaphore; again: - down_read(&mm->mmap_sem); + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the + * kernel and should generate an OOPS. Unfortunatly, in the case of an + * erroneous fault occuring in a code path which already holds mmap_sem + * we will deadlock attempting to validate the fault against the + * address space. Luckily the kernel only validly references user + * space from well defined areas of code, which are listed in the + * exceptions table. + * + * As the vast majority of faults will be valid we will only perform + * the source reference check when there is a possibilty of a deadlock. + * Attempt to lock the address space, if we cannot we then validate the + * source. If this is invalid we can skip the address space check, + * thus avoiding the deadlock. + */ + if (!down_read_trylock(&mm->mmap_sem)) { + if ((error_code & 4) == 0 && + !search_exception_tables(regs->rip)) + goto bad_area_nosemaphore; + down_read(&mm->mmap_sem); + } vma = find_vma(mm, address); if (!vma) @@ -351,18 +404,18 @@ bad_area_nosemaphore: #ifdef CONFIG_IA32_EMULATION - /* 32bit vsyscall. map on demand. */ - if (test_thread_flag(TIF_IA32) && + /* 32bit vsyscall. map on demand. */ + if (test_thread_flag(TIF_IA32) && address >= 0xffffe000 && address < 0xffffe000 + PAGE_SIZE) { - if (map_syscall32(mm, address) < 0) - goto out_of_memory2; - return; - } + if (map_syscall32(mm, address) < 0) + goto out_of_memory2; + return; + } #endif /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { - if (is_prefetch(regs, address)) + if (is_prefetch(regs, address, error_code)) return; /* Work around K8 erratum #100 K8 in compat mode @@ -376,7 +429,7 @@ return; if (exception_trace && unhandled_signal(tsk, SIGSEGV)) { - printk(KERN_INFO + printk(KERN_INFO "%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n", tsk->comm, tsk->pid, address, regs->rip, regs->rsp, error_code); @@ -407,7 +460,7 @@ * Hall of shame of CPU/BIOS bugs. */ - if (is_prefetch(regs, address)) + if (is_prefetch(regs, address, error_code)) return; if (is_errata93(regs, address)) @@ -481,10 +534,8 @@ * is really there and when yes flush the local TLB. */ pgd = pgd_offset_k(address); - if (pgd != current_pgd_offset_k(address)) - BUG(); if (!pgd_present(*pgd)) - goto bad_area_nosemaphore; + goto bad_area_nosemaphore; pmd = pmd_offset(pgd, address); if (!pmd_present(*pmd)) goto bad_area_nosemaphore; @@ -495,4 +546,7 @@ __flush_tlb_all(); return; } + +page_table_corruption: + pgtable_bad(address, regs, error_code); } diff -Nru a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c --- a/arch/x86_64/mm/init.c 2004-10-18 14:56:17 -07:00 +++ b/arch/x86_64/mm/init.c 2004-10-18 14:56:17 -07:00 @@ -41,6 +41,10 @@ #define Dprintk(x...) #endif +#ifdef CONFIG_GART_IOMMU +extern int swiotlb; +#endif + extern char _stext[]; DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -396,6 +400,8 @@ return 0; } +extern int swiotlb_force; + static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, kcore_vsyscall; @@ -405,7 +411,10 @@ int tmp; #ifdef CONFIG_SWIOTLB - if (!iommu_aperture && end_pfn >= 0xffffffff>>PAGE_SHIFT) + if (swiotlb_force) + swiotlb = 1; + if (!iommu_aperture && + (end_pfn >= 0xffffffff>>PAGE_SHIFT || force_iommu)) swiotlb = 1; if (swiotlb) swiotlb_init(); @@ -596,7 +605,16 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk) { - return test_tsk_thread_flag(tsk, TIF_IA32) ? &gate32_vma : &gate_vma; +#ifdef CONFIG_IA32_EMULATION + if (test_tsk_thread_flag(tsk, TIF_IA32)) { + /* lookup code assumes the pages are present. set them up + now */ + if (__map_syscall32(tsk->mm, 0xfffe000) < 0) + return NULL; + return &gate32_vma; + } +#endif + return &gate_vma; } int in_gate_area(struct task_struct *task, unsigned long addr) diff -Nru a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c --- a/arch/x86_64/mm/ioremap.c 2004-10-18 14:57:04 -07:00 +++ b/arch/x86_64/mm/ioremap.c 2004-10-18 14:57:04 -07:00 @@ -111,7 +111,7 @@ * have to convert them into an offset in a page-aligned mapping, but the * caller shouldn't need to know that small detail. */ -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) { void * addr; struct vm_struct * area; @@ -126,7 +126,7 @@ * Don't remap the low PCI/ISA area, it's always mapped.. */ if (phys_addr >= 0xA0000 && last_addr < 0x100000) - return phys_to_virt(phys_addr); + return (__force void __iomem *)phys_to_virt(phys_addr); /* * Don't allow anybody to remap normal RAM that we're using.. @@ -164,7 +164,7 @@ vunmap(addr); return NULL; } - return (void *) (offset + (char *)addr); + return (__force void __iomem *) (offset + (char *)addr); } /** @@ -189,9 +189,9 @@ * Must be freed with iounmap. */ -void *ioremap_nocache (unsigned long phys_addr, unsigned long size) +void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) { - void *p = __ioremap(phys_addr, size, _PAGE_PCD); + void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD); if (!p) return p; @@ -212,7 +212,7 @@ return p; } -void iounmap(void *addr) +void iounmap(void __iomem *addr) { struct vm_struct *p; if (addr <= high_memory) diff -Nru a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c --- a/arch/x86_64/mm/k8topology.c 2004-10-18 14:57:04 -07:00 +++ b/arch/x86_64/mm/k8topology.c 2004-10-18 14:57:04 -07:00 @@ -100,8 +100,8 @@ limit <<= 24; limit |= (1<<24)-1; - if (limit > end_pfn_map << PAGE_SHIFT) - limit = end_pfn_map << PAGE_SHIFT; + if (limit > end_pfn << PAGE_SHIFT) + limit = end_pfn << PAGE_SHIFT; if (limit <= base) continue; diff -Nru a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c --- a/arch/x86_64/mm/numa.c 2004-10-18 14:56:49 -07:00 +++ b/arch/x86_64/mm/numa.c 2004-10-18 14:56:49 -07:00 @@ -135,7 +135,7 @@ zones[ZONE_NORMAL] = end_pfn - start_pfn; } - free_area_init_node(nodeid, NODE_DATA(nodeid), NULL, zones, + free_area_init_node(nodeid, NODE_DATA(nodeid), zones, start_pfn, NULL); } @@ -162,10 +162,58 @@ set_bit(0, &node_to_cpumask[cpu_to_node(0)]); } +int numa_fake __initdata = 0; + +/* Numa emulation */ +static int numa_emulation(unsigned long start_pfn, unsigned long end_pfn) +{ + int i; + struct node nodes[MAXNODE]; + unsigned long sz = ((end_pfn - start_pfn)< 1) { + unsigned long x = 1; + while ((x << 1) < sz) + x <<= 1; + if (x < sz/2) + printk("Numa emulation unbalanced. Complain to maintainer\n"); + sz = x; + } + + memset(&nodes,0,sizeof(nodes)); + for (i = 0; i < numa_fake; i++) { + nodes[i].start = (start_pfn<> 20); + } + numnodes = numa_fake; + memnode_shift = compute_hash_shift(nodes); + if (memnode_shift < 0) { + memnode_shift = 0; + printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n"); + return -1; + } + for (i = 0; i < numa_fake; i++) + setup_node_bootmem(i, nodes[i].start, nodes[i].end); + numa_init_array(); + return 0; +} + void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) { int i; + if (numa_fake && !numa_emulation(start_pfn, end_pfn)) + return; + #ifdef CONFIG_K8_NUMA if (!numa_off && !k8_scan_nodes(start_pfn<E #define D_KEY ctx->D -static u8 pow_tab[256]; -static u8 log_tab[256]; -static u8 sbx_tab[256]; -static u8 isb_tab[256]; +static u8 pow_tab[256] __initdata; +static u8 log_tab[256] __initdata; +static u8 sbx_tab[256] __initdata; +static u8 isb_tab[256] __initdata; static u32 rco_tab[10]; static u32 ft_tab[4][256]; static u32 it_tab[4][256]; @@ -113,7 +113,7 @@ static u32 fl_tab[4][256]; static u32 il_tab[4][256]; -static inline u8 +static inline u8 __init f_mult (u8 a, u8 b) { u8 aa = log_tab[a], cc = aa + log_tab[b]; @@ -153,14 +153,14 @@ il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) -static void +static void __init gen_tabs (void) { u32 i, t; u8 p, q; /* log and power tables for GF(2**8) finite field with - 0x011b as modular polynomial - the simplest prmitive + 0x011b as modular polynomial - the simplest primitive root is 0x03, used here to generate the tables */ for (i = 0, p = 1; i < 256; ++i) { diff -Nru a/crypto/api.c b/crypto/api.c --- a/crypto/api.c 2004-10-18 14:57:04 -07:00 +++ b/crypto/api.c 2004-10-18 14:57:04 -07:00 @@ -155,8 +155,12 @@ void crypto_free_tfm(struct crypto_tfm *tfm) { + struct crypto_alg *alg = tfm->__crt_alg; + int size = sizeof(*tfm) + alg->cra_ctxsize; + crypto_exit_ops(tfm); - crypto_alg_put(tfm->__crt_alg); + crypto_alg_put(alg); + memset(tfm, 0, size); kfree(tfm); } diff -Nru a/crypto/arc4.c b/crypto/arc4.c --- a/crypto/arc4.c 2004-10-18 14:55:55 -07:00 +++ b/crypto/arc4.c 2004-10-18 14:55:55 -07:00 @@ -3,7 +3,7 @@ * * ARC4 Cipher Algorithm * - * Jon Oberheide + * Jon Oberheide * * 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 @@ -100,4 +100,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); -MODULE_AUTHOR("Jon Oberheide "); +MODULE_AUTHOR("Jon Oberheide "); diff -Nru a/crypto/blowfish.c b/crypto/blowfish.c --- a/crypto/blowfish.c 2004-10-18 14:56:17 -07:00 +++ b/crypto/blowfish.c 2004-10-18 14:56:17 -07:00 @@ -3,9 +3,9 @@ * * Blowfish Cipher Algorithm, by Bruce Schneier. * http://www.counterpane.com/blowfish.html - * - * Adapated from Kerneli implementation. - * + * + * Adapted from Kerneli implementation. + * * Copyright (c) Herbert Valerio Riedel * Copyright (c) Kyle McMartin * Copyright (c) 2002 James Morris diff -Nru a/crypto/internal.h b/crypto/internal.h --- a/crypto/internal.h 2004-10-18 14:55:54 -07:00 +++ b/crypto/internal.h 2004-10-18 14:55:54 -07:00 @@ -17,7 +17,6 @@ #include #include #include -#include #include extern enum km_type crypto_km_types[]; diff -Nru a/crypto/scatterwalk.c b/crypto/scatterwalk.c --- a/crypto/scatterwalk.c 2004-10-18 14:56:32 -07:00 +++ b/crypto/scatterwalk.c 2004-10-18 14:56:32 -07:00 @@ -70,7 +70,7 @@ { /* walk->data may be pointing the first byte of the next page; however, we know we transfered at least one byte. So, - walk->data - 1 will be a virutual address in the mapped page. */ + walk->data - 1 will be a virtual address in the mapped page. */ if (out) flush_dcache_page(walk->page); diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c --- a/crypto/tcrypt.c 2004-10-18 14:56:49 -07:00 +++ b/crypto/tcrypt.c 2004-10-18 14:56:49 -07:00 @@ -24,6 +24,7 @@ #include #include #include +#include #include "tcrypt.h" /* @@ -61,7 +62,8 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", - "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", NULL + "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", + "wp512", "wp384", "wp256", NULL }; static void @@ -680,6 +682,9 @@ test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); + test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); + test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS); + test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS); test_deflate(); test_crc32c(); #ifdef CONFIG_CRYPTO_HMAC @@ -791,6 +796,19 @@ test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS); break; + case 22: + test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); + break; + + case 23: + test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS); + break; + + case 24: + test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS); + break; + + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); @@ -846,7 +864,7 @@ module_init(init); module_exit(fini); -MODULE_PARM(mode, "i"); +module_param(mode, int, 0); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Quick & dirty crypto testing module"); diff -Nru a/crypto/tcrypt.h b/crypto/tcrypt.h --- a/crypto/tcrypt.h 2004-10-18 14:57:03 -07:00 +++ b/crypto/tcrypt.h 2004-10-18 14:57:03 -07:00 @@ -301,6 +301,259 @@ }, }; + +/* + * WHIRLPOOL test vectors from Whirlpool package + * by Vincent Rijmen and Paulo S. L. M. Barreto as part of the NESSIE + * submission + */ +#define WP512_TEST_VECTORS 8 + +struct hash_testvec wp512_tv_template[] = { + { + .plaintext = "", + .psize = 0, + .digest = { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, + 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, + 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7, + 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, + 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57, + 0xEA, 0x89, 0x64, 0xE5, 0x9B, 0x63, 0xD9, 0x37, + 0x08, 0xB1, 0x38, 0xCC, 0x42, 0xA6, 0x6E, 0xB3 }, + + + }, { + .plaintext = "a", + .psize = 1, + .digest = { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F, + 0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7, + 0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69, + 0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42, + 0xD1, 0x1B, 0xC6, 0x45, 0x41, 0x3A, 0xEF, 0xF6, + 0x3A, 0x42, 0x39, 0x1A, 0x39, 0x14, 0x5A, 0x59, + 0x1A, 0x92, 0x20, 0x0D, 0x56, 0x01, 0x95, 0xE5, + 0x3B, 0x47, 0x85, 0x84, 0xFD, 0xAE, 0x23, 0x1A }, + }, { + .plaintext = "abc", + .psize = 3, + .digest = { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB, + 0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B, + 0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72, + 0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C, + 0x71, 0x81, 0xEE, 0xBD, 0xB6, 0xC5, 0x7E, 0x27, + 0x7D, 0x0E, 0x34, 0x95, 0x71, 0x14, 0xCB, 0xD6, + 0xC7, 0x97, 0xFC, 0x9D, 0x95, 0xD8, 0xB5, 0x82, + 0xD2, 0x25, 0x29, 0x20, 0x76, 0xD4, 0xEE, 0xF5 }, + }, { + .plaintext = "message digest", + .psize = 14, + .digest = { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, + 0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, + 0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, + 0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B, + 0x84, 0x21, 0x55, 0x76, 0x59, 0xEF, 0x55, 0xC1, + 0x06, 0xB4, 0xB5, 0x2A, 0xC5, 0xA4, 0xAA, 0xA6, + 0x92, 0xED, 0x92, 0x00, 0x52, 0x83, 0x8F, 0x33, + 0x62, 0xE8, 0x6D, 0xBD, 0x37, 0xA8, 0x90, 0x3E }, + }, { + .plaintext = "abcdefghijklmnopqrstuvwxyz", + .psize = 26, + .digest = { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9, + 0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A, + 0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5, + 0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B, + 0x08, 0xBF, 0x2A, 0x92, 0x51, 0xC3, 0x0B, 0x6A, + 0x0B, 0x8A, 0xAE, 0x86, 0x17, 0x7A, 0xB4, 0xA6, + 0xF6, 0x8F, 0x67, 0x3E, 0x72, 0x07, 0x86, 0x5D, + 0x5D, 0x98, 0x19, 0xA3, 0xDB, 0xA4, 0xEB, 0x3B }, + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789", + .psize = 62, + .digest = { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B, + 0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90, + 0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC, + 0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E, + 0x08, 0xEB, 0xA2, 0x66, 0x29, 0x12, 0x9D, 0x8F, + 0xB7, 0xCB, 0x57, 0x21, 0x1B, 0x92, 0x81, 0xA6, + 0x55, 0x17, 0xCC, 0x87, 0x9D, 0x7B, 0x96, 0x21, + 0x42, 0xC6, 0x5F, 0x5A, 0x7A, 0xF0, 0x14, 0x67 }, + }, { + .plaintext = "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + .psize = 80, + .digest = { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D, + 0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0, + 0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6, + 0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29, + 0x4D, 0x5B, 0xD8, 0xDF, 0x2A, 0x6C, 0x44, 0xE5, + 0x38, 0xCD, 0x04, 0x7B, 0x26, 0x81, 0xA5, 0x1A, + 0x2C, 0x60, 0x48, 0x1E, 0x88, 0xC5, 0xA2, 0x0B, + 0x2C, 0x2A, 0x80, 0xCF, 0x3A, 0x9A, 0x08, 0x3B }, + }, { + .plaintext = "abcdbcdecdefdefgefghfghighijhijk", + .psize = 32, + .digest = { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, + 0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48, + 0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62, + 0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69, + 0x16, 0xBD, 0xC8, 0x03, 0x1B, 0xC5, 0xBE, 0x1B, + 0x7B, 0x94, 0x76, 0x39, 0xFE, 0x05, 0x0B, 0x56, + 0x93, 0x9B, 0xAA, 0xA0, 0xAD, 0xFF, 0x9A, 0xE6, + 0x74, 0x5B, 0x7B, 0x18, 0x1C, 0x3B, 0xE3, 0xFD }, + }, +}; + +#define WP384_TEST_VECTORS 8 + +struct hash_testvec wp384_tv_template[] = { + { + .plaintext = "", + .psize = 0, + .digest = { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, + 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, + 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7, + 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, + 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57 }, + + + }, { + .plaintext = "a", + .psize = 1, + .digest = { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F, + 0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7, + 0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69, + 0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42, + 0xD1, 0x1B, 0xC6, 0x45, 0x41, 0x3A, 0xEF, 0xF6, + 0x3A, 0x42, 0x39, 0x1A, 0x39, 0x14, 0x5A, 0x59 }, + }, { + .plaintext = "abc", + .psize = 3, + .digest = { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB, + 0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B, + 0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72, + 0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C, + 0x71, 0x81, 0xEE, 0xBD, 0xB6, 0xC5, 0x7E, 0x27, + 0x7D, 0x0E, 0x34, 0x95, 0x71, 0x14, 0xCB, 0xD6 }, + }, { + .plaintext = "message digest", + .psize = 14, + .digest = { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, + 0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, + 0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, + 0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B, + 0x84, 0x21, 0x55, 0x76, 0x59, 0xEF, 0x55, 0xC1, + 0x06, 0xB4, 0xB5, 0x2A, 0xC5, 0xA4, 0xAA, 0xA6 }, + }, { + .plaintext = "abcdefghijklmnopqrstuvwxyz", + .psize = 26, + .digest = { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9, + 0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A, + 0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5, + 0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B, + 0x08, 0xBF, 0x2A, 0x92, 0x51, 0xC3, 0x0B, 0x6A, + 0x0B, 0x8A, 0xAE, 0x86, 0x17, 0x7A, 0xB4, 0xA6 }, + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789", + .psize = 62, + .digest = { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B, + 0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90, + 0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC, + 0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E, + 0x08, 0xEB, 0xA2, 0x66, 0x29, 0x12, 0x9D, 0x8F, + 0xB7, 0xCB, 0x57, 0x21, 0x1B, 0x92, 0x81, 0xA6 }, + }, { + .plaintext = "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + .psize = 80, + .digest = { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D, + 0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0, + 0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6, + 0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29, + 0x4D, 0x5B, 0xD8, 0xDF, 0x2A, 0x6C, 0x44, 0xE5, + 0x38, 0xCD, 0x04, 0x7B, 0x26, 0x81, 0xA5, 0x1A }, + }, { + .plaintext = "abcdbcdecdefdefgefghfghighijhijk", + .psize = 32, + .digest = { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, + 0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48, + 0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62, + 0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69, + 0x16, 0xBD, 0xC8, 0x03, 0x1B, 0xC5, 0xBE, 0x1B, + 0x7B, 0x94, 0x76, 0x39, 0xFE, 0x05, 0x0B, 0x56 }, + }, +}; + +#define WP256_TEST_VECTORS 8 + +struct hash_testvec wp256_tv_template[] = { + { + .plaintext = "", + .psize = 0, + .digest = { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, + 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, + 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7 }, + + + }, { + .plaintext = "a", + .psize = 1, + .digest = { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F, + 0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7, + 0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69, + 0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42 }, + }, { + .plaintext = "abc", + .psize = 3, + .digest = { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB, + 0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B, + 0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72, + 0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C }, + }, { + .plaintext = "message digest", + .psize = 14, + .digest = { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, + 0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, + 0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, + 0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B }, + }, { + .plaintext = "abcdefghijklmnopqrstuvwxyz", + .psize = 26, + .digest = { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9, + 0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A, + 0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5, + 0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B }, + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789", + .psize = 62, + .digest = { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B, + 0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90, + 0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC, + 0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E }, + }, { + .plaintext = "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + .psize = 80, + .digest = { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D, + 0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0, + 0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6, + 0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29 }, + }, { + .plaintext = "abcdbcdecdefdefgefghfghighijhijk", + .psize = 32, + .digest = { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, + 0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48, + 0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62, + 0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69 }, + }, +}; + + #ifdef CONFIG_CRYPTO_HMAC /* * HMAC-MD5 test vectors from RFC2202 @@ -1186,7 +1439,7 @@ /* * Serpent test vectors. These are backwards because Serpent writes - * octect sequences in right-to-left mode. + * octet sequences in right-to-left mode. */ #define SERPENT_ENC_TEST_VECTORS 4 #define SERPENT_DEC_TEST_VECTORS 4 diff -Nru a/crypto/tea.c b/crypto/tea.c --- a/crypto/tea.c 2004-10-18 14:57:19 -07:00 +++ b/crypto/tea.c 2004-10-18 14:57:19 -07:00 @@ -154,7 +154,7 @@ while (sum != limit) { y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; - sum += TEA_DELTA; + sum += XTEA_DELTA; z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; } diff -Nru a/crypto/twofish.c b/crypto/twofish.c --- a/crypto/twofish.c 2004-10-18 14:57:05 -07:00 +++ b/crypto/twofish.c 2004-10-18 14:57:05 -07:00 @@ -1,7 +1,7 @@ /* * Twofish for CryptoAPI * - * Originaly Twofish for GPG + * Originally Twofish for GPG * By Matthew Skala , July 26, 1998 * 256-bit key length added March 20, 1999 * Some modifications to reduce the text size by Werner Koch, April, 1998 @@ -514,7 +514,7 @@ * preprocessed through q0 and q1 respectively; for longer keys they are the * output of previous stages. j is the index of the first key byte to use. * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2 - * twice, doing the Psuedo-Hadamard Transform, and doing the necessary + * twice, doing the Pseudo-Hadamard Transform, and doing the necessary * rotations. Its parameters are: a, the array to write the results into, * j, the index of the first output entry, k and l, the preprocessed indices * for index 2i, and m and n, the preprocessed indices for index 2i+1. diff -Nru a/crypto/wp512.c b/crypto/wp512.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/crypto/wp512.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,1208 @@ +/* + * Cryptographic API. + * + * Whirlpool hashing Algorithm + * + * The Whirlpool algorithm was developed by Paulo S. L. M. Barreto and + * Vincent Rijmen. It has been selected as one of cryptographic + * primitives by the NESSIE project http://www.cryptonessie.org/ + * + * The original authors have disclaimed all copyright interest in this + * code and thus put it in the public domain. The subsequent authors + * have put this under the GNU General Public License. + * + * By Aaron Grothe ajgrothe@yahoo.com, August 23, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include + +#define WP512_DIGEST_SIZE 64 +#define WP384_DIGEST_SIZE 48 +#define WP256_DIGEST_SIZE 32 + +#define WP512_BLOCK_SIZE 64 +#define WP512_LENGTHBYTES 32 + +#define WHIRLPOOL_ROUNDS 10 + +struct wp512_ctx { + u8 bitLength[WP512_LENGTHBYTES]; + u8 buffer[WP512_BLOCK_SIZE]; + int bufferBits; + int bufferPos; + u64 hash[WP512_DIGEST_SIZE/8]; +}; + +/* + * Though Whirlpool is endianness-neutral, the encryption tables are listed + * in BIG-ENDIAN format, which is adopted throughout this implementation + * (but little-endian notation would be equally suitable if consistently + * employed). + */ + +static const u64 C0[256] = { + 0x18186018c07830d8ULL, 0x23238c2305af4626ULL, 0xc6c63fc67ef991b8ULL, + 0xe8e887e8136fcdfbULL, 0x878726874ca113cbULL, 0xb8b8dab8a9626d11ULL, + 0x0101040108050209ULL, 0x4f4f214f426e9e0dULL, 0x3636d836adee6c9bULL, + 0xa6a6a2a6590451ffULL, 0xd2d26fd2debdb90cULL, 0xf5f5f3f5fb06f70eULL, + 0x7979f979ef80f296ULL, 0x6f6fa16f5fcede30ULL, 0x91917e91fcef3f6dULL, + 0x52525552aa07a4f8ULL, 0x60609d6027fdc047ULL, 0xbcbccabc89766535ULL, + 0x9b9b569baccd2b37ULL, 0x8e8e028e048c018aULL, 0xa3a3b6a371155bd2ULL, + 0x0c0c300c603c186cULL, 0x7b7bf17bff8af684ULL, 0x3535d435b5e16a80ULL, + 0x1d1d741de8693af5ULL, 0xe0e0a7e05347ddb3ULL, 0xd7d77bd7f6acb321ULL, + 0xc2c22fc25eed999cULL, 0x2e2eb82e6d965c43ULL, 0x4b4b314b627a9629ULL, + 0xfefedffea321e15dULL, 0x575741578216aed5ULL, 0x15155415a8412abdULL, + 0x7777c1779fb6eee8ULL, 0x3737dc37a5eb6e92ULL, 0xe5e5b3e57b56d79eULL, + 0x9f9f469f8cd92313ULL, 0xf0f0e7f0d317fd23ULL, 0x4a4a354a6a7f9420ULL, + 0xdada4fda9e95a944ULL, 0x58587d58fa25b0a2ULL, 0xc9c903c906ca8fcfULL, + 0x2929a429558d527cULL, 0x0a0a280a5022145aULL, 0xb1b1feb1e14f7f50ULL, + 0xa0a0baa0691a5dc9ULL, 0x6b6bb16b7fdad614ULL, 0x85852e855cab17d9ULL, + 0xbdbdcebd8173673cULL, 0x5d5d695dd234ba8fULL, 0x1010401080502090ULL, + 0xf4f4f7f4f303f507ULL, 0xcbcb0bcb16c08bddULL, 0x3e3ef83eedc67cd3ULL, + 0x0505140528110a2dULL, 0x676781671fe6ce78ULL, 0xe4e4b7e47353d597ULL, + 0x27279c2725bb4e02ULL, 0x4141194132588273ULL, 0x8b8b168b2c9d0ba7ULL, + 0xa7a7a6a7510153f6ULL, 0x7d7de97dcf94fab2ULL, 0x95956e95dcfb3749ULL, + 0xd8d847d88e9fad56ULL, 0xfbfbcbfb8b30eb70ULL, 0xeeee9fee2371c1cdULL, + 0x7c7ced7cc791f8bbULL, 0x6666856617e3cc71ULL, 0xdddd53dda68ea77bULL, + 0x17175c17b84b2eafULL, 0x4747014702468e45ULL, 0x9e9e429e84dc211aULL, + 0xcaca0fca1ec589d4ULL, 0x2d2db42d75995a58ULL, 0xbfbfc6bf9179632eULL, + 0x07071c07381b0e3fULL, 0xadad8ead012347acULL, 0x5a5a755aea2fb4b0ULL, + 0x838336836cb51befULL, 0x3333cc3385ff66b6ULL, 0x636391633ff2c65cULL, + 0x02020802100a0412ULL, 0xaaaa92aa39384993ULL, 0x7171d971afa8e2deULL, + 0xc8c807c80ecf8dc6ULL, 0x19196419c87d32d1ULL, 0x494939497270923bULL, + 0xd9d943d9869aaf5fULL, 0xf2f2eff2c31df931ULL, 0xe3e3abe34b48dba8ULL, + 0x5b5b715be22ab6b9ULL, 0x88881a8834920dbcULL, 0x9a9a529aa4c8293eULL, + 0x262698262dbe4c0bULL, 0x3232c8328dfa64bfULL, 0xb0b0fab0e94a7d59ULL, + 0xe9e983e91b6acff2ULL, 0x0f0f3c0f78331e77ULL, 0xd5d573d5e6a6b733ULL, + 0x80803a8074ba1df4ULL, 0xbebec2be997c6127ULL, 0xcdcd13cd26de87ebULL, + 0x3434d034bde46889ULL, 0x48483d487a759032ULL, 0xffffdbffab24e354ULL, + 0x7a7af57af78ff48dULL, 0x90907a90f4ea3d64ULL, 0x5f5f615fc23ebe9dULL, + 0x202080201da0403dULL, 0x6868bd6867d5d00fULL, 0x1a1a681ad07234caULL, + 0xaeae82ae192c41b7ULL, 0xb4b4eab4c95e757dULL, 0x54544d549a19a8ceULL, + 0x93937693ece53b7fULL, 0x222288220daa442fULL, 0x64648d6407e9c863ULL, + 0xf1f1e3f1db12ff2aULL, 0x7373d173bfa2e6ccULL, 0x12124812905a2482ULL, + 0x40401d403a5d807aULL, 0x0808200840281048ULL, 0xc3c32bc356e89b95ULL, + 0xecec97ec337bc5dfULL, 0xdbdb4bdb9690ab4dULL, 0xa1a1bea1611f5fc0ULL, + 0x8d8d0e8d1c830791ULL, 0x3d3df43df5c97ac8ULL, 0x97976697ccf1335bULL, + 0x0000000000000000ULL, 0xcfcf1bcf36d483f9ULL, 0x2b2bac2b4587566eULL, + 0x7676c57697b3ece1ULL, 0x8282328264b019e6ULL, 0xd6d67fd6fea9b128ULL, + 0x1b1b6c1bd87736c3ULL, 0xb5b5eeb5c15b7774ULL, 0xafaf86af112943beULL, + 0x6a6ab56a77dfd41dULL, 0x50505d50ba0da0eaULL, 0x45450945124c8a57ULL, + 0xf3f3ebf3cb18fb38ULL, 0x3030c0309df060adULL, 0xefef9bef2b74c3c4ULL, + 0x3f3ffc3fe5c37edaULL, 0x55554955921caac7ULL, 0xa2a2b2a2791059dbULL, + 0xeaea8fea0365c9e9ULL, 0x656589650fecca6aULL, 0xbabad2bab9686903ULL, + 0x2f2fbc2f65935e4aULL, 0xc0c027c04ee79d8eULL, 0xdede5fdebe81a160ULL, + 0x1c1c701ce06c38fcULL, 0xfdfdd3fdbb2ee746ULL, 0x4d4d294d52649a1fULL, + 0x92927292e4e03976ULL, 0x7575c9758fbceafaULL, 0x06061806301e0c36ULL, + 0x8a8a128a249809aeULL, 0xb2b2f2b2f940794bULL, 0xe6e6bfe66359d185ULL, + 0x0e0e380e70361c7eULL, 0x1f1f7c1ff8633ee7ULL, 0x6262956237f7c455ULL, + 0xd4d477d4eea3b53aULL, 0xa8a89aa829324d81ULL, 0x96966296c4f43152ULL, + 0xf9f9c3f99b3aef62ULL, 0xc5c533c566f697a3ULL, 0x2525942535b14a10ULL, + 0x59597959f220b2abULL, 0x84842a8454ae15d0ULL, 0x7272d572b7a7e4c5ULL, + 0x3939e439d5dd72ecULL, 0x4c4c2d4c5a619816ULL, 0x5e5e655eca3bbc94ULL, + 0x7878fd78e785f09fULL, 0x3838e038ddd870e5ULL, 0x8c8c0a8c14860598ULL, + 0xd1d163d1c6b2bf17ULL, 0xa5a5aea5410b57e4ULL, 0xe2e2afe2434dd9a1ULL, + 0x616199612ff8c24eULL, 0xb3b3f6b3f1457b42ULL, 0x2121842115a54234ULL, + 0x9c9c4a9c94d62508ULL, 0x1e1e781ef0663ceeULL, 0x4343114322528661ULL, + 0xc7c73bc776fc93b1ULL, 0xfcfcd7fcb32be54fULL, 0x0404100420140824ULL, + 0x51515951b208a2e3ULL, 0x99995e99bcc72f25ULL, 0x6d6da96d4fc4da22ULL, + 0x0d0d340d68391a65ULL, 0xfafacffa8335e979ULL, 0xdfdf5bdfb684a369ULL, + 0x7e7ee57ed79bfca9ULL, 0x242490243db44819ULL, 0x3b3bec3bc5d776feULL, + 0xabab96ab313d4b9aULL, 0xcece1fce3ed181f0ULL, 0x1111441188552299ULL, + 0x8f8f068f0c890383ULL, 0x4e4e254e4a6b9c04ULL, 0xb7b7e6b7d1517366ULL, + 0xebeb8beb0b60cbe0ULL, 0x3c3cf03cfdcc78c1ULL, 0x81813e817cbf1ffdULL, + 0x94946a94d4fe3540ULL, 0xf7f7fbf7eb0cf31cULL, 0xb9b9deb9a1676f18ULL, + 0x13134c13985f268bULL, 0x2c2cb02c7d9c5851ULL, 0xd3d36bd3d6b8bb05ULL, + 0xe7e7bbe76b5cd38cULL, 0x6e6ea56e57cbdc39ULL, 0xc4c437c46ef395aaULL, + 0x03030c03180f061bULL, 0x565645568a13acdcULL, 0x44440d441a49885eULL, + 0x7f7fe17fdf9efea0ULL, 0xa9a99ea921374f88ULL, 0x2a2aa82a4d825467ULL, + 0xbbbbd6bbb16d6b0aULL, 0xc1c123c146e29f87ULL, 0x53535153a202a6f1ULL, + 0xdcdc57dcae8ba572ULL, 0x0b0b2c0b58271653ULL, 0x9d9d4e9d9cd32701ULL, + 0x6c6cad6c47c1d82bULL, 0x3131c43195f562a4ULL, 0x7474cd7487b9e8f3ULL, + 0xf6f6fff6e309f115ULL, 0x464605460a438c4cULL, 0xacac8aac092645a5ULL, + 0x89891e893c970fb5ULL, 0x14145014a04428b4ULL, 0xe1e1a3e15b42dfbaULL, + 0x16165816b04e2ca6ULL, 0x3a3ae83acdd274f7ULL, 0x6969b9696fd0d206ULL, + 0x09092409482d1241ULL, 0x7070dd70a7ade0d7ULL, 0xb6b6e2b6d954716fULL, + 0xd0d067d0ceb7bd1eULL, 0xeded93ed3b7ec7d6ULL, 0xcccc17cc2edb85e2ULL, + 0x424215422a578468ULL, 0x98985a98b4c22d2cULL, 0xa4a4aaa4490e55edULL, + 0x2828a0285d885075ULL, 0x5c5c6d5cda31b886ULL, 0xf8f8c7f8933fed6bULL, + 0x8686228644a411c2ULL, +}; + +static const u64 C1[256] = { + 0xd818186018c07830ULL, 0x2623238c2305af46ULL, 0xb8c6c63fc67ef991ULL, + 0xfbe8e887e8136fcdULL, 0xcb878726874ca113ULL, 0x11b8b8dab8a9626dULL, + 0x0901010401080502ULL, 0x0d4f4f214f426e9eULL, 0x9b3636d836adee6cULL, + 0xffa6a6a2a6590451ULL, 0x0cd2d26fd2debdb9ULL, 0x0ef5f5f3f5fb06f7ULL, + 0x967979f979ef80f2ULL, 0x306f6fa16f5fcedeULL, 0x6d91917e91fcef3fULL, + 0xf852525552aa07a4ULL, 0x4760609d6027fdc0ULL, 0x35bcbccabc897665ULL, + 0x379b9b569baccd2bULL, 0x8a8e8e028e048c01ULL, 0xd2a3a3b6a371155bULL, + 0x6c0c0c300c603c18ULL, 0x847b7bf17bff8af6ULL, 0x803535d435b5e16aULL, + 0xf51d1d741de8693aULL, 0xb3e0e0a7e05347ddULL, 0x21d7d77bd7f6acb3ULL, + 0x9cc2c22fc25eed99ULL, 0x432e2eb82e6d965cULL, 0x294b4b314b627a96ULL, + 0x5dfefedffea321e1ULL, 0xd5575741578216aeULL, 0xbd15155415a8412aULL, + 0xe87777c1779fb6eeULL, 0x923737dc37a5eb6eULL, 0x9ee5e5b3e57b56d7ULL, + 0x139f9f469f8cd923ULL, 0x23f0f0e7f0d317fdULL, 0x204a4a354a6a7f94ULL, + 0x44dada4fda9e95a9ULL, 0xa258587d58fa25b0ULL, 0xcfc9c903c906ca8fULL, + 0x7c2929a429558d52ULL, 0x5a0a0a280a502214ULL, 0x50b1b1feb1e14f7fULL, + 0xc9a0a0baa0691a5dULL, 0x146b6bb16b7fdad6ULL, 0xd985852e855cab17ULL, + 0x3cbdbdcebd817367ULL, 0x8f5d5d695dd234baULL, 0x9010104010805020ULL, + 0x07f4f4f7f4f303f5ULL, 0xddcbcb0bcb16c08bULL, 0xd33e3ef83eedc67cULL, + 0x2d0505140528110aULL, 0x78676781671fe6ceULL, 0x97e4e4b7e47353d5ULL, + 0x0227279c2725bb4eULL, 0x7341411941325882ULL, 0xa78b8b168b2c9d0bULL, + 0xf6a7a7a6a7510153ULL, 0xb27d7de97dcf94faULL, 0x4995956e95dcfb37ULL, + 0x56d8d847d88e9fadULL, 0x70fbfbcbfb8b30ebULL, 0xcdeeee9fee2371c1ULL, + 0xbb7c7ced7cc791f8ULL, 0x716666856617e3ccULL, 0x7bdddd53dda68ea7ULL, + 0xaf17175c17b84b2eULL, 0x454747014702468eULL, 0x1a9e9e429e84dc21ULL, + 0xd4caca0fca1ec589ULL, 0x582d2db42d75995aULL, 0x2ebfbfc6bf917963ULL, + 0x3f07071c07381b0eULL, 0xacadad8ead012347ULL, 0xb05a5a755aea2fb4ULL, + 0xef838336836cb51bULL, 0xb63333cc3385ff66ULL, 0x5c636391633ff2c6ULL, + 0x1202020802100a04ULL, 0x93aaaa92aa393849ULL, 0xde7171d971afa8e2ULL, + 0xc6c8c807c80ecf8dULL, 0xd119196419c87d32ULL, 0x3b49493949727092ULL, + 0x5fd9d943d9869aafULL, 0x31f2f2eff2c31df9ULL, 0xa8e3e3abe34b48dbULL, + 0xb95b5b715be22ab6ULL, 0xbc88881a8834920dULL, 0x3e9a9a529aa4c829ULL, + 0x0b262698262dbe4cULL, 0xbf3232c8328dfa64ULL, 0x59b0b0fab0e94a7dULL, + 0xf2e9e983e91b6acfULL, 0x770f0f3c0f78331eULL, 0x33d5d573d5e6a6b7ULL, + 0xf480803a8074ba1dULL, 0x27bebec2be997c61ULL, 0xebcdcd13cd26de87ULL, + 0x893434d034bde468ULL, 0x3248483d487a7590ULL, 0x54ffffdbffab24e3ULL, + 0x8d7a7af57af78ff4ULL, 0x6490907a90f4ea3dULL, 0x9d5f5f615fc23ebeULL, + 0x3d202080201da040ULL, 0x0f6868bd6867d5d0ULL, 0xca1a1a681ad07234ULL, + 0xb7aeae82ae192c41ULL, 0x7db4b4eab4c95e75ULL, 0xce54544d549a19a8ULL, + 0x7f93937693ece53bULL, 0x2f222288220daa44ULL, 0x6364648d6407e9c8ULL, + 0x2af1f1e3f1db12ffULL, 0xcc7373d173bfa2e6ULL, 0x8212124812905a24ULL, + 0x7a40401d403a5d80ULL, 0x4808082008402810ULL, 0x95c3c32bc356e89bULL, + 0xdfecec97ec337bc5ULL, 0x4ddbdb4bdb9690abULL, 0xc0a1a1bea1611f5fULL, + 0x918d8d0e8d1c8307ULL, 0xc83d3df43df5c97aULL, 0x5b97976697ccf133ULL, + 0x0000000000000000ULL, 0xf9cfcf1bcf36d483ULL, 0x6e2b2bac2b458756ULL, + 0xe17676c57697b3ecULL, 0xe68282328264b019ULL, 0x28d6d67fd6fea9b1ULL, + 0xc31b1b6c1bd87736ULL, 0x74b5b5eeb5c15b77ULL, 0xbeafaf86af112943ULL, + 0x1d6a6ab56a77dfd4ULL, 0xea50505d50ba0da0ULL, 0x5745450945124c8aULL, + 0x38f3f3ebf3cb18fbULL, 0xad3030c0309df060ULL, 0xc4efef9bef2b74c3ULL, + 0xda3f3ffc3fe5c37eULL, 0xc755554955921caaULL, 0xdba2a2b2a2791059ULL, + 0xe9eaea8fea0365c9ULL, 0x6a656589650feccaULL, 0x03babad2bab96869ULL, + 0x4a2f2fbc2f65935eULL, 0x8ec0c027c04ee79dULL, 0x60dede5fdebe81a1ULL, + 0xfc1c1c701ce06c38ULL, 0x46fdfdd3fdbb2ee7ULL, 0x1f4d4d294d52649aULL, + 0x7692927292e4e039ULL, 0xfa7575c9758fbceaULL, 0x3606061806301e0cULL, + 0xae8a8a128a249809ULL, 0x4bb2b2f2b2f94079ULL, 0x85e6e6bfe66359d1ULL, + 0x7e0e0e380e70361cULL, 0xe71f1f7c1ff8633eULL, 0x556262956237f7c4ULL, + 0x3ad4d477d4eea3b5ULL, 0x81a8a89aa829324dULL, 0x5296966296c4f431ULL, + 0x62f9f9c3f99b3aefULL, 0xa3c5c533c566f697ULL, 0x102525942535b14aULL, + 0xab59597959f220b2ULL, 0xd084842a8454ae15ULL, 0xc57272d572b7a7e4ULL, + 0xec3939e439d5dd72ULL, 0x164c4c2d4c5a6198ULL, 0x945e5e655eca3bbcULL, + 0x9f7878fd78e785f0ULL, 0xe53838e038ddd870ULL, 0x988c8c0a8c148605ULL, + 0x17d1d163d1c6b2bfULL, 0xe4a5a5aea5410b57ULL, 0xa1e2e2afe2434dd9ULL, + 0x4e616199612ff8c2ULL, 0x42b3b3f6b3f1457bULL, 0x342121842115a542ULL, + 0x089c9c4a9c94d625ULL, 0xee1e1e781ef0663cULL, 0x6143431143225286ULL, + 0xb1c7c73bc776fc93ULL, 0x4ffcfcd7fcb32be5ULL, 0x2404041004201408ULL, + 0xe351515951b208a2ULL, 0x2599995e99bcc72fULL, 0x226d6da96d4fc4daULL, + 0x650d0d340d68391aULL, 0x79fafacffa8335e9ULL, 0x69dfdf5bdfb684a3ULL, + 0xa97e7ee57ed79bfcULL, 0x19242490243db448ULL, 0xfe3b3bec3bc5d776ULL, + 0x9aabab96ab313d4bULL, 0xf0cece1fce3ed181ULL, 0x9911114411885522ULL, + 0x838f8f068f0c8903ULL, 0x044e4e254e4a6b9cULL, 0x66b7b7e6b7d15173ULL, + 0xe0ebeb8beb0b60cbULL, 0xc13c3cf03cfdcc78ULL, 0xfd81813e817cbf1fULL, + 0x4094946a94d4fe35ULL, 0x1cf7f7fbf7eb0cf3ULL, 0x18b9b9deb9a1676fULL, + 0x8b13134c13985f26ULL, 0x512c2cb02c7d9c58ULL, 0x05d3d36bd3d6b8bbULL, + 0x8ce7e7bbe76b5cd3ULL, 0x396e6ea56e57cbdcULL, 0xaac4c437c46ef395ULL, + 0x1b03030c03180f06ULL, 0xdc565645568a13acULL, 0x5e44440d441a4988ULL, + 0xa07f7fe17fdf9efeULL, 0x88a9a99ea921374fULL, 0x672a2aa82a4d8254ULL, + 0x0abbbbd6bbb16d6bULL, 0x87c1c123c146e29fULL, 0xf153535153a202a6ULL, + 0x72dcdc57dcae8ba5ULL, 0x530b0b2c0b582716ULL, 0x019d9d4e9d9cd327ULL, + 0x2b6c6cad6c47c1d8ULL, 0xa43131c43195f562ULL, 0xf37474cd7487b9e8ULL, + 0x15f6f6fff6e309f1ULL, 0x4c464605460a438cULL, 0xa5acac8aac092645ULL, + 0xb589891e893c970fULL, 0xb414145014a04428ULL, 0xbae1e1a3e15b42dfULL, + 0xa616165816b04e2cULL, 0xf73a3ae83acdd274ULL, 0x066969b9696fd0d2ULL, + 0x4109092409482d12ULL, 0xd77070dd70a7ade0ULL, 0x6fb6b6e2b6d95471ULL, + 0x1ed0d067d0ceb7bdULL, 0xd6eded93ed3b7ec7ULL, 0xe2cccc17cc2edb85ULL, + 0x68424215422a5784ULL, 0x2c98985a98b4c22dULL, 0xeda4a4aaa4490e55ULL, + 0x752828a0285d8850ULL, 0x865c5c6d5cda31b8ULL, 0x6bf8f8c7f8933fedULL, + 0xc28686228644a411ULL, +}; + +static const u64 C2[256] = { + 0x30d818186018c078ULL, 0x462623238c2305afULL, 0x91b8c6c63fc67ef9ULL, + 0xcdfbe8e887e8136fULL, 0x13cb878726874ca1ULL, 0x6d11b8b8dab8a962ULL, + 0x0209010104010805ULL, 0x9e0d4f4f214f426eULL, 0x6c9b3636d836adeeULL, + 0x51ffa6a6a2a65904ULL, 0xb90cd2d26fd2debdULL, 0xf70ef5f5f3f5fb06ULL, + 0xf2967979f979ef80ULL, 0xde306f6fa16f5fceULL, 0x3f6d91917e91fcefULL, + 0xa4f852525552aa07ULL, 0xc04760609d6027fdULL, 0x6535bcbccabc8976ULL, + 0x2b379b9b569baccdULL, 0x018a8e8e028e048cULL, 0x5bd2a3a3b6a37115ULL, + 0x186c0c0c300c603cULL, 0xf6847b7bf17bff8aULL, 0x6a803535d435b5e1ULL, + 0x3af51d1d741de869ULL, 0xddb3e0e0a7e05347ULL, 0xb321d7d77bd7f6acULL, + 0x999cc2c22fc25eedULL, 0x5c432e2eb82e6d96ULL, 0x96294b4b314b627aULL, + 0xe15dfefedffea321ULL, 0xaed5575741578216ULL, 0x2abd15155415a841ULL, + 0xeee87777c1779fb6ULL, 0x6e923737dc37a5ebULL, 0xd79ee5e5b3e57b56ULL, + 0x23139f9f469f8cd9ULL, 0xfd23f0f0e7f0d317ULL, 0x94204a4a354a6a7fULL, + 0xa944dada4fda9e95ULL, 0xb0a258587d58fa25ULL, 0x8fcfc9c903c906caULL, + 0x527c2929a429558dULL, 0x145a0a0a280a5022ULL, 0x7f50b1b1feb1e14fULL, + 0x5dc9a0a0baa0691aULL, 0xd6146b6bb16b7fdaULL, 0x17d985852e855cabULL, + 0x673cbdbdcebd8173ULL, 0xba8f5d5d695dd234ULL, 0x2090101040108050ULL, + 0xf507f4f4f7f4f303ULL, 0x8bddcbcb0bcb16c0ULL, 0x7cd33e3ef83eedc6ULL, + 0x0a2d050514052811ULL, 0xce78676781671fe6ULL, 0xd597e4e4b7e47353ULL, + 0x4e0227279c2725bbULL, 0x8273414119413258ULL, 0x0ba78b8b168b2c9dULL, + 0x53f6a7a7a6a75101ULL, 0xfab27d7de97dcf94ULL, 0x374995956e95dcfbULL, + 0xad56d8d847d88e9fULL, 0xeb70fbfbcbfb8b30ULL, 0xc1cdeeee9fee2371ULL, + 0xf8bb7c7ced7cc791ULL, 0xcc716666856617e3ULL, 0xa77bdddd53dda68eULL, + 0x2eaf17175c17b84bULL, 0x8e45474701470246ULL, 0x211a9e9e429e84dcULL, + 0x89d4caca0fca1ec5ULL, 0x5a582d2db42d7599ULL, 0x632ebfbfc6bf9179ULL, + 0x0e3f07071c07381bULL, 0x47acadad8ead0123ULL, 0xb4b05a5a755aea2fULL, + 0x1bef838336836cb5ULL, 0x66b63333cc3385ffULL, 0xc65c636391633ff2ULL, + 0x041202020802100aULL, 0x4993aaaa92aa3938ULL, 0xe2de7171d971afa8ULL, + 0x8dc6c8c807c80ecfULL, 0x32d119196419c87dULL, 0x923b494939497270ULL, + 0xaf5fd9d943d9869aULL, 0xf931f2f2eff2c31dULL, 0xdba8e3e3abe34b48ULL, + 0xb6b95b5b715be22aULL, 0x0dbc88881a883492ULL, 0x293e9a9a529aa4c8ULL, + 0x4c0b262698262dbeULL, 0x64bf3232c8328dfaULL, 0x7d59b0b0fab0e94aULL, + 0xcff2e9e983e91b6aULL, 0x1e770f0f3c0f7833ULL, 0xb733d5d573d5e6a6ULL, + 0x1df480803a8074baULL, 0x6127bebec2be997cULL, 0x87ebcdcd13cd26deULL, + 0x68893434d034bde4ULL, 0x903248483d487a75ULL, 0xe354ffffdbffab24ULL, + 0xf48d7a7af57af78fULL, 0x3d6490907a90f4eaULL, 0xbe9d5f5f615fc23eULL, + 0x403d202080201da0ULL, 0xd00f6868bd6867d5ULL, 0x34ca1a1a681ad072ULL, + 0x41b7aeae82ae192cULL, 0x757db4b4eab4c95eULL, 0xa8ce54544d549a19ULL, + 0x3b7f93937693ece5ULL, 0x442f222288220daaULL, 0xc86364648d6407e9ULL, + 0xff2af1f1e3f1db12ULL, 0xe6cc7373d173bfa2ULL, 0x248212124812905aULL, + 0x807a40401d403a5dULL, 0x1048080820084028ULL, 0x9b95c3c32bc356e8ULL, + 0xc5dfecec97ec337bULL, 0xab4ddbdb4bdb9690ULL, 0x5fc0a1a1bea1611fULL, + 0x07918d8d0e8d1c83ULL, 0x7ac83d3df43df5c9ULL, 0x335b97976697ccf1ULL, + 0x0000000000000000ULL, 0x83f9cfcf1bcf36d4ULL, 0x566e2b2bac2b4587ULL, + 0xece17676c57697b3ULL, 0x19e68282328264b0ULL, 0xb128d6d67fd6fea9ULL, + 0x36c31b1b6c1bd877ULL, 0x7774b5b5eeb5c15bULL, 0x43beafaf86af1129ULL, + 0xd41d6a6ab56a77dfULL, 0xa0ea50505d50ba0dULL, 0x8a5745450945124cULL, + 0xfb38f3f3ebf3cb18ULL, 0x60ad3030c0309df0ULL, 0xc3c4efef9bef2b74ULL, + 0x7eda3f3ffc3fe5c3ULL, 0xaac755554955921cULL, 0x59dba2a2b2a27910ULL, + 0xc9e9eaea8fea0365ULL, 0xca6a656589650fecULL, 0x6903babad2bab968ULL, + 0x5e4a2f2fbc2f6593ULL, 0x9d8ec0c027c04ee7ULL, 0xa160dede5fdebe81ULL, + 0x38fc1c1c701ce06cULL, 0xe746fdfdd3fdbb2eULL, 0x9a1f4d4d294d5264ULL, + 0x397692927292e4e0ULL, 0xeafa7575c9758fbcULL, 0x0c3606061806301eULL, + 0x09ae8a8a128a2498ULL, 0x794bb2b2f2b2f940ULL, 0xd185e6e6bfe66359ULL, + 0x1c7e0e0e380e7036ULL, 0x3ee71f1f7c1ff863ULL, 0xc4556262956237f7ULL, + 0xb53ad4d477d4eea3ULL, 0x4d81a8a89aa82932ULL, 0x315296966296c4f4ULL, + 0xef62f9f9c3f99b3aULL, 0x97a3c5c533c566f6ULL, 0x4a102525942535b1ULL, + 0xb2ab59597959f220ULL, 0x15d084842a8454aeULL, 0xe4c57272d572b7a7ULL, + 0x72ec3939e439d5ddULL, 0x98164c4c2d4c5a61ULL, 0xbc945e5e655eca3bULL, + 0xf09f7878fd78e785ULL, 0x70e53838e038ddd8ULL, 0x05988c8c0a8c1486ULL, + 0xbf17d1d163d1c6b2ULL, 0x57e4a5a5aea5410bULL, 0xd9a1e2e2afe2434dULL, + 0xc24e616199612ff8ULL, 0x7b42b3b3f6b3f145ULL, 0x42342121842115a5ULL, + 0x25089c9c4a9c94d6ULL, 0x3cee1e1e781ef066ULL, 0x8661434311432252ULL, + 0x93b1c7c73bc776fcULL, 0xe54ffcfcd7fcb32bULL, 0x0824040410042014ULL, + 0xa2e351515951b208ULL, 0x2f2599995e99bcc7ULL, 0xda226d6da96d4fc4ULL, + 0x1a650d0d340d6839ULL, 0xe979fafacffa8335ULL, 0xa369dfdf5bdfb684ULL, + 0xfca97e7ee57ed79bULL, 0x4819242490243db4ULL, 0x76fe3b3bec3bc5d7ULL, + 0x4b9aabab96ab313dULL, 0x81f0cece1fce3ed1ULL, 0x2299111144118855ULL, + 0x03838f8f068f0c89ULL, 0x9c044e4e254e4a6bULL, 0x7366b7b7e6b7d151ULL, + 0xcbe0ebeb8beb0b60ULL, 0x78c13c3cf03cfdccULL, 0x1ffd81813e817cbfULL, + 0x354094946a94d4feULL, 0xf31cf7f7fbf7eb0cULL, 0x6f18b9b9deb9a167ULL, + 0x268b13134c13985fULL, 0x58512c2cb02c7d9cULL, 0xbb05d3d36bd3d6b8ULL, + 0xd38ce7e7bbe76b5cULL, 0xdc396e6ea56e57cbULL, 0x95aac4c437c46ef3ULL, + 0x061b03030c03180fULL, 0xacdc565645568a13ULL, 0x885e44440d441a49ULL, + 0xfea07f7fe17fdf9eULL, 0x4f88a9a99ea92137ULL, 0x54672a2aa82a4d82ULL, + 0x6b0abbbbd6bbb16dULL, 0x9f87c1c123c146e2ULL, 0xa6f153535153a202ULL, + 0xa572dcdc57dcae8bULL, 0x16530b0b2c0b5827ULL, 0x27019d9d4e9d9cd3ULL, + 0xd82b6c6cad6c47c1ULL, 0x62a43131c43195f5ULL, 0xe8f37474cd7487b9ULL, + 0xf115f6f6fff6e309ULL, 0x8c4c464605460a43ULL, 0x45a5acac8aac0926ULL, + 0x0fb589891e893c97ULL, 0x28b414145014a044ULL, 0xdfbae1e1a3e15b42ULL, + 0x2ca616165816b04eULL, 0x74f73a3ae83acdd2ULL, 0xd2066969b9696fd0ULL, + 0x124109092409482dULL, 0xe0d77070dd70a7adULL, 0x716fb6b6e2b6d954ULL, + 0xbd1ed0d067d0ceb7ULL, 0xc7d6eded93ed3b7eULL, 0x85e2cccc17cc2edbULL, + 0x8468424215422a57ULL, 0x2d2c98985a98b4c2ULL, 0x55eda4a4aaa4490eULL, + 0x50752828a0285d88ULL, 0xb8865c5c6d5cda31ULL, 0xed6bf8f8c7f8933fULL, + 0x11c28686228644a4ULL, +}; + +static const u64 C3[256] = { + 0x7830d818186018c0ULL, 0xaf462623238c2305ULL, 0xf991b8c6c63fc67eULL, + 0x6fcdfbe8e887e813ULL, 0xa113cb878726874cULL, 0x626d11b8b8dab8a9ULL, + 0x0502090101040108ULL, 0x6e9e0d4f4f214f42ULL, 0xee6c9b3636d836adULL, + 0x0451ffa6a6a2a659ULL, 0xbdb90cd2d26fd2deULL, 0x06f70ef5f5f3f5fbULL, + 0x80f2967979f979efULL, 0xcede306f6fa16f5fULL, 0xef3f6d91917e91fcULL, + 0x07a4f852525552aaULL, 0xfdc04760609d6027ULL, 0x766535bcbccabc89ULL, + 0xcd2b379b9b569bacULL, 0x8c018a8e8e028e04ULL, 0x155bd2a3a3b6a371ULL, + 0x3c186c0c0c300c60ULL, 0x8af6847b7bf17bffULL, 0xe16a803535d435b5ULL, + 0x693af51d1d741de8ULL, 0x47ddb3e0e0a7e053ULL, 0xacb321d7d77bd7f6ULL, + 0xed999cc2c22fc25eULL, 0x965c432e2eb82e6dULL, 0x7a96294b4b314b62ULL, + 0x21e15dfefedffea3ULL, 0x16aed55757415782ULL, 0x412abd15155415a8ULL, + 0xb6eee87777c1779fULL, 0xeb6e923737dc37a5ULL, 0x56d79ee5e5b3e57bULL, + 0xd923139f9f469f8cULL, 0x17fd23f0f0e7f0d3ULL, 0x7f94204a4a354a6aULL, + 0x95a944dada4fda9eULL, 0x25b0a258587d58faULL, 0xca8fcfc9c903c906ULL, + 0x8d527c2929a42955ULL, 0x22145a0a0a280a50ULL, 0x4f7f50b1b1feb1e1ULL, + 0x1a5dc9a0a0baa069ULL, 0xdad6146b6bb16b7fULL, 0xab17d985852e855cULL, + 0x73673cbdbdcebd81ULL, 0x34ba8f5d5d695dd2ULL, 0x5020901010401080ULL, + 0x03f507f4f4f7f4f3ULL, 0xc08bddcbcb0bcb16ULL, 0xc67cd33e3ef83eedULL, + 0x110a2d0505140528ULL, 0xe6ce78676781671fULL, 0x53d597e4e4b7e473ULL, + 0xbb4e0227279c2725ULL, 0x5882734141194132ULL, 0x9d0ba78b8b168b2cULL, + 0x0153f6a7a7a6a751ULL, 0x94fab27d7de97dcfULL, 0xfb374995956e95dcULL, + 0x9fad56d8d847d88eULL, 0x30eb70fbfbcbfb8bULL, 0x71c1cdeeee9fee23ULL, + 0x91f8bb7c7ced7cc7ULL, 0xe3cc716666856617ULL, 0x8ea77bdddd53dda6ULL, + 0x4b2eaf17175c17b8ULL, 0x468e454747014702ULL, 0xdc211a9e9e429e84ULL, + 0xc589d4caca0fca1eULL, 0x995a582d2db42d75ULL, 0x79632ebfbfc6bf91ULL, + 0x1b0e3f07071c0738ULL, 0x2347acadad8ead01ULL, 0x2fb4b05a5a755aeaULL, + 0xb51bef838336836cULL, 0xff66b63333cc3385ULL, 0xf2c65c636391633fULL, + 0x0a04120202080210ULL, 0x384993aaaa92aa39ULL, 0xa8e2de7171d971afULL, + 0xcf8dc6c8c807c80eULL, 0x7d32d119196419c8ULL, 0x70923b4949394972ULL, + 0x9aaf5fd9d943d986ULL, 0x1df931f2f2eff2c3ULL, 0x48dba8e3e3abe34bULL, + 0x2ab6b95b5b715be2ULL, 0x920dbc88881a8834ULL, 0xc8293e9a9a529aa4ULL, + 0xbe4c0b262698262dULL, 0xfa64bf3232c8328dULL, 0x4a7d59b0b0fab0e9ULL, + 0x6acff2e9e983e91bULL, 0x331e770f0f3c0f78ULL, 0xa6b733d5d573d5e6ULL, + 0xba1df480803a8074ULL, 0x7c6127bebec2be99ULL, 0xde87ebcdcd13cd26ULL, + 0xe468893434d034bdULL, 0x75903248483d487aULL, 0x24e354ffffdbffabULL, + 0x8ff48d7a7af57af7ULL, 0xea3d6490907a90f4ULL, 0x3ebe9d5f5f615fc2ULL, + 0xa0403d202080201dULL, 0xd5d00f6868bd6867ULL, 0x7234ca1a1a681ad0ULL, + 0x2c41b7aeae82ae19ULL, 0x5e757db4b4eab4c9ULL, 0x19a8ce54544d549aULL, + 0xe53b7f93937693ecULL, 0xaa442f222288220dULL, 0xe9c86364648d6407ULL, + 0x12ff2af1f1e3f1dbULL, 0xa2e6cc7373d173bfULL, 0x5a24821212481290ULL, + 0x5d807a40401d403aULL, 0x2810480808200840ULL, 0xe89b95c3c32bc356ULL, + 0x7bc5dfecec97ec33ULL, 0x90ab4ddbdb4bdb96ULL, 0x1f5fc0a1a1bea161ULL, + 0x8307918d8d0e8d1cULL, 0xc97ac83d3df43df5ULL, 0xf1335b97976697ccULL, + 0x0000000000000000ULL, 0xd483f9cfcf1bcf36ULL, 0x87566e2b2bac2b45ULL, + 0xb3ece17676c57697ULL, 0xb019e68282328264ULL, 0xa9b128d6d67fd6feULL, + 0x7736c31b1b6c1bd8ULL, 0x5b7774b5b5eeb5c1ULL, 0x2943beafaf86af11ULL, + 0xdfd41d6a6ab56a77ULL, 0x0da0ea50505d50baULL, 0x4c8a574545094512ULL, + 0x18fb38f3f3ebf3cbULL, 0xf060ad3030c0309dULL, 0x74c3c4efef9bef2bULL, + 0xc37eda3f3ffc3fe5ULL, 0x1caac75555495592ULL, 0x1059dba2a2b2a279ULL, + 0x65c9e9eaea8fea03ULL, 0xecca6a656589650fULL, 0x686903babad2bab9ULL, + 0x935e4a2f2fbc2f65ULL, 0xe79d8ec0c027c04eULL, 0x81a160dede5fdebeULL, + 0x6c38fc1c1c701ce0ULL, 0x2ee746fdfdd3fdbbULL, 0x649a1f4d4d294d52ULL, + 0xe0397692927292e4ULL, 0xbceafa7575c9758fULL, 0x1e0c360606180630ULL, + 0x9809ae8a8a128a24ULL, 0x40794bb2b2f2b2f9ULL, 0x59d185e6e6bfe663ULL, + 0x361c7e0e0e380e70ULL, 0x633ee71f1f7c1ff8ULL, 0xf7c4556262956237ULL, + 0xa3b53ad4d477d4eeULL, 0x324d81a8a89aa829ULL, 0xf4315296966296c4ULL, + 0x3aef62f9f9c3f99bULL, 0xf697a3c5c533c566ULL, 0xb14a102525942535ULL, + 0x20b2ab59597959f2ULL, 0xae15d084842a8454ULL, 0xa7e4c57272d572b7ULL, + 0xdd72ec3939e439d5ULL, 0x6198164c4c2d4c5aULL, 0x3bbc945e5e655ecaULL, + 0x85f09f7878fd78e7ULL, 0xd870e53838e038ddULL, 0x8605988c8c0a8c14ULL, + 0xb2bf17d1d163d1c6ULL, 0x0b57e4a5a5aea541ULL, 0x4dd9a1e2e2afe243ULL, + 0xf8c24e616199612fULL, 0x457b42b3b3f6b3f1ULL, 0xa542342121842115ULL, + 0xd625089c9c4a9c94ULL, 0x663cee1e1e781ef0ULL, 0x5286614343114322ULL, + 0xfc93b1c7c73bc776ULL, 0x2be54ffcfcd7fcb3ULL, 0x1408240404100420ULL, + 0x08a2e351515951b2ULL, 0xc72f2599995e99bcULL, 0xc4da226d6da96d4fULL, + 0x391a650d0d340d68ULL, 0x35e979fafacffa83ULL, 0x84a369dfdf5bdfb6ULL, + 0x9bfca97e7ee57ed7ULL, 0xb44819242490243dULL, 0xd776fe3b3bec3bc5ULL, + 0x3d4b9aabab96ab31ULL, 0xd181f0cece1fce3eULL, 0x5522991111441188ULL, + 0x8903838f8f068f0cULL, 0x6b9c044e4e254e4aULL, 0x517366b7b7e6b7d1ULL, + 0x60cbe0ebeb8beb0bULL, 0xcc78c13c3cf03cfdULL, 0xbf1ffd81813e817cULL, + 0xfe354094946a94d4ULL, 0x0cf31cf7f7fbf7ebULL, 0x676f18b9b9deb9a1ULL, + 0x5f268b13134c1398ULL, 0x9c58512c2cb02c7dULL, 0xb8bb05d3d36bd3d6ULL, + 0x5cd38ce7e7bbe76bULL, 0xcbdc396e6ea56e57ULL, 0xf395aac4c437c46eULL, + 0x0f061b03030c0318ULL, 0x13acdc565645568aULL, 0x49885e44440d441aULL, + 0x9efea07f7fe17fdfULL, 0x374f88a9a99ea921ULL, 0x8254672a2aa82a4dULL, + 0x6d6b0abbbbd6bbb1ULL, 0xe29f87c1c123c146ULL, 0x02a6f153535153a2ULL, + 0x8ba572dcdc57dcaeULL, 0x2716530b0b2c0b58ULL, 0xd327019d9d4e9d9cULL, + 0xc1d82b6c6cad6c47ULL, 0xf562a43131c43195ULL, 0xb9e8f37474cd7487ULL, + 0x09f115f6f6fff6e3ULL, 0x438c4c464605460aULL, 0x2645a5acac8aac09ULL, + 0x970fb589891e893cULL, 0x4428b414145014a0ULL, 0x42dfbae1e1a3e15bULL, + 0x4e2ca616165816b0ULL, 0xd274f73a3ae83acdULL, 0xd0d2066969b9696fULL, + 0x2d12410909240948ULL, 0xade0d77070dd70a7ULL, 0x54716fb6b6e2b6d9ULL, + 0xb7bd1ed0d067d0ceULL, 0x7ec7d6eded93ed3bULL, 0xdb85e2cccc17cc2eULL, + 0x578468424215422aULL, 0xc22d2c98985a98b4ULL, 0x0e55eda4a4aaa449ULL, + 0x8850752828a0285dULL, 0x31b8865c5c6d5cdaULL, 0x3fed6bf8f8c7f893ULL, + 0xa411c28686228644ULL, +}; + +static const u64 C4[256] = { + 0xc07830d818186018ULL, 0x05af462623238c23ULL, 0x7ef991b8c6c63fc6ULL, + 0x136fcdfbe8e887e8ULL, 0x4ca113cb87872687ULL, 0xa9626d11b8b8dab8ULL, + 0x0805020901010401ULL, 0x426e9e0d4f4f214fULL, 0xadee6c9b3636d836ULL, + 0x590451ffa6a6a2a6ULL, 0xdebdb90cd2d26fd2ULL, 0xfb06f70ef5f5f3f5ULL, + 0xef80f2967979f979ULL, 0x5fcede306f6fa16fULL, 0xfcef3f6d91917e91ULL, + 0xaa07a4f852525552ULL, 0x27fdc04760609d60ULL, 0x89766535bcbccabcULL, + 0xaccd2b379b9b569bULL, 0x048c018a8e8e028eULL, 0x71155bd2a3a3b6a3ULL, + 0x603c186c0c0c300cULL, 0xff8af6847b7bf17bULL, 0xb5e16a803535d435ULL, + 0xe8693af51d1d741dULL, 0x5347ddb3e0e0a7e0ULL, 0xf6acb321d7d77bd7ULL, + 0x5eed999cc2c22fc2ULL, 0x6d965c432e2eb82eULL, 0x627a96294b4b314bULL, + 0xa321e15dfefedffeULL, 0x8216aed557574157ULL, 0xa8412abd15155415ULL, + 0x9fb6eee87777c177ULL, 0xa5eb6e923737dc37ULL, 0x7b56d79ee5e5b3e5ULL, + 0x8cd923139f9f469fULL, 0xd317fd23f0f0e7f0ULL, 0x6a7f94204a4a354aULL, + 0x9e95a944dada4fdaULL, 0xfa25b0a258587d58ULL, 0x06ca8fcfc9c903c9ULL, + 0x558d527c2929a429ULL, 0x5022145a0a0a280aULL, 0xe14f7f50b1b1feb1ULL, + 0x691a5dc9a0a0baa0ULL, 0x7fdad6146b6bb16bULL, 0x5cab17d985852e85ULL, + 0x8173673cbdbdcebdULL, 0xd234ba8f5d5d695dULL, 0x8050209010104010ULL, + 0xf303f507f4f4f7f4ULL, 0x16c08bddcbcb0bcbULL, 0xedc67cd33e3ef83eULL, + 0x28110a2d05051405ULL, 0x1fe6ce7867678167ULL, 0x7353d597e4e4b7e4ULL, + 0x25bb4e0227279c27ULL, 0x3258827341411941ULL, 0x2c9d0ba78b8b168bULL, + 0x510153f6a7a7a6a7ULL, 0xcf94fab27d7de97dULL, 0xdcfb374995956e95ULL, + 0x8e9fad56d8d847d8ULL, 0x8b30eb70fbfbcbfbULL, 0x2371c1cdeeee9feeULL, + 0xc791f8bb7c7ced7cULL, 0x17e3cc7166668566ULL, 0xa68ea77bdddd53ddULL, + 0xb84b2eaf17175c17ULL, 0x02468e4547470147ULL, 0x84dc211a9e9e429eULL, + 0x1ec589d4caca0fcaULL, 0x75995a582d2db42dULL, 0x9179632ebfbfc6bfULL, + 0x381b0e3f07071c07ULL, 0x012347acadad8eadULL, 0xea2fb4b05a5a755aULL, + 0x6cb51bef83833683ULL, 0x85ff66b63333cc33ULL, 0x3ff2c65c63639163ULL, + 0x100a041202020802ULL, 0x39384993aaaa92aaULL, 0xafa8e2de7171d971ULL, + 0x0ecf8dc6c8c807c8ULL, 0xc87d32d119196419ULL, 0x7270923b49493949ULL, + 0x869aaf5fd9d943d9ULL, 0xc31df931f2f2eff2ULL, 0x4b48dba8e3e3abe3ULL, + 0xe22ab6b95b5b715bULL, 0x34920dbc88881a88ULL, 0xa4c8293e9a9a529aULL, + 0x2dbe4c0b26269826ULL, 0x8dfa64bf3232c832ULL, 0xe94a7d59b0b0fab0ULL, + 0x1b6acff2e9e983e9ULL, 0x78331e770f0f3c0fULL, 0xe6a6b733d5d573d5ULL, + 0x74ba1df480803a80ULL, 0x997c6127bebec2beULL, 0x26de87ebcdcd13cdULL, + 0xbde468893434d034ULL, 0x7a75903248483d48ULL, 0xab24e354ffffdbffULL, + 0xf78ff48d7a7af57aULL, 0xf4ea3d6490907a90ULL, 0xc23ebe9d5f5f615fULL, + 0x1da0403d20208020ULL, 0x67d5d00f6868bd68ULL, 0xd07234ca1a1a681aULL, + 0x192c41b7aeae82aeULL, 0xc95e757db4b4eab4ULL, 0x9a19a8ce54544d54ULL, + 0xece53b7f93937693ULL, 0x0daa442f22228822ULL, 0x07e9c86364648d64ULL, + 0xdb12ff2af1f1e3f1ULL, 0xbfa2e6cc7373d173ULL, 0x905a248212124812ULL, + 0x3a5d807a40401d40ULL, 0x4028104808082008ULL, 0x56e89b95c3c32bc3ULL, + 0x337bc5dfecec97ecULL, 0x9690ab4ddbdb4bdbULL, 0x611f5fc0a1a1bea1ULL, + 0x1c8307918d8d0e8dULL, 0xf5c97ac83d3df43dULL, 0xccf1335b97976697ULL, + 0x0000000000000000ULL, 0x36d483f9cfcf1bcfULL, 0x4587566e2b2bac2bULL, + 0x97b3ece17676c576ULL, 0x64b019e682823282ULL, 0xfea9b128d6d67fd6ULL, + 0xd87736c31b1b6c1bULL, 0xc15b7774b5b5eeb5ULL, 0x112943beafaf86afULL, + 0x77dfd41d6a6ab56aULL, 0xba0da0ea50505d50ULL, 0x124c8a5745450945ULL, + 0xcb18fb38f3f3ebf3ULL, 0x9df060ad3030c030ULL, 0x2b74c3c4efef9befULL, + 0xe5c37eda3f3ffc3fULL, 0x921caac755554955ULL, 0x791059dba2a2b2a2ULL, + 0x0365c9e9eaea8feaULL, 0x0fecca6a65658965ULL, 0xb9686903babad2baULL, + 0x65935e4a2f2fbc2fULL, 0x4ee79d8ec0c027c0ULL, 0xbe81a160dede5fdeULL, + 0xe06c38fc1c1c701cULL, 0xbb2ee746fdfdd3fdULL, 0x52649a1f4d4d294dULL, + 0xe4e0397692927292ULL, 0x8fbceafa7575c975ULL, 0x301e0c3606061806ULL, + 0x249809ae8a8a128aULL, 0xf940794bb2b2f2b2ULL, 0x6359d185e6e6bfe6ULL, + 0x70361c7e0e0e380eULL, 0xf8633ee71f1f7c1fULL, 0x37f7c45562629562ULL, + 0xeea3b53ad4d477d4ULL, 0x29324d81a8a89aa8ULL, 0xc4f4315296966296ULL, + 0x9b3aef62f9f9c3f9ULL, 0x66f697a3c5c533c5ULL, 0x35b14a1025259425ULL, + 0xf220b2ab59597959ULL, 0x54ae15d084842a84ULL, 0xb7a7e4c57272d572ULL, + 0xd5dd72ec3939e439ULL, 0x5a6198164c4c2d4cULL, 0xca3bbc945e5e655eULL, + 0xe785f09f7878fd78ULL, 0xddd870e53838e038ULL, 0x148605988c8c0a8cULL, + 0xc6b2bf17d1d163d1ULL, 0x410b57e4a5a5aea5ULL, 0x434dd9a1e2e2afe2ULL, + 0x2ff8c24e61619961ULL, 0xf1457b42b3b3f6b3ULL, 0x15a5423421218421ULL, + 0x94d625089c9c4a9cULL, 0xf0663cee1e1e781eULL, 0x2252866143431143ULL, + 0x76fc93b1c7c73bc7ULL, 0xb32be54ffcfcd7fcULL, 0x2014082404041004ULL, + 0xb208a2e351515951ULL, 0xbcc72f2599995e99ULL, 0x4fc4da226d6da96dULL, + 0x68391a650d0d340dULL, 0x8335e979fafacffaULL, 0xb684a369dfdf5bdfULL, + 0xd79bfca97e7ee57eULL, 0x3db4481924249024ULL, 0xc5d776fe3b3bec3bULL, + 0x313d4b9aabab96abULL, 0x3ed181f0cece1fceULL, 0x8855229911114411ULL, + 0x0c8903838f8f068fULL, 0x4a6b9c044e4e254eULL, 0xd1517366b7b7e6b7ULL, + 0x0b60cbe0ebeb8bebULL, 0xfdcc78c13c3cf03cULL, 0x7cbf1ffd81813e81ULL, + 0xd4fe354094946a94ULL, 0xeb0cf31cf7f7fbf7ULL, 0xa1676f18b9b9deb9ULL, + 0x985f268b13134c13ULL, 0x7d9c58512c2cb02cULL, 0xd6b8bb05d3d36bd3ULL, + 0x6b5cd38ce7e7bbe7ULL, 0x57cbdc396e6ea56eULL, 0x6ef395aac4c437c4ULL, + 0x180f061b03030c03ULL, 0x8a13acdc56564556ULL, 0x1a49885e44440d44ULL, + 0xdf9efea07f7fe17fULL, 0x21374f88a9a99ea9ULL, 0x4d8254672a2aa82aULL, + 0xb16d6b0abbbbd6bbULL, 0x46e29f87c1c123c1ULL, 0xa202a6f153535153ULL, + 0xae8ba572dcdc57dcULL, 0x582716530b0b2c0bULL, 0x9cd327019d9d4e9dULL, + 0x47c1d82b6c6cad6cULL, 0x95f562a43131c431ULL, 0x87b9e8f37474cd74ULL, + 0xe309f115f6f6fff6ULL, 0x0a438c4c46460546ULL, 0x092645a5acac8aacULL, + 0x3c970fb589891e89ULL, 0xa04428b414145014ULL, 0x5b42dfbae1e1a3e1ULL, + 0xb04e2ca616165816ULL, 0xcdd274f73a3ae83aULL, 0x6fd0d2066969b969ULL, + 0x482d124109092409ULL, 0xa7ade0d77070dd70ULL, 0xd954716fb6b6e2b6ULL, + 0xceb7bd1ed0d067d0ULL, 0x3b7ec7d6eded93edULL, 0x2edb85e2cccc17ccULL, + 0x2a57846842421542ULL, 0xb4c22d2c98985a98ULL, 0x490e55eda4a4aaa4ULL, + 0x5d8850752828a028ULL, 0xda31b8865c5c6d5cULL, 0x933fed6bf8f8c7f8ULL, + 0x44a411c286862286ULL, +}; + +static const u64 C5[256] = { + 0x18c07830d8181860ULL, 0x2305af462623238cULL, 0xc67ef991b8c6c63fULL, + 0xe8136fcdfbe8e887ULL, 0x874ca113cb878726ULL, 0xb8a9626d11b8b8daULL, + 0x0108050209010104ULL, 0x4f426e9e0d4f4f21ULL, 0x36adee6c9b3636d8ULL, + 0xa6590451ffa6a6a2ULL, 0xd2debdb90cd2d26fULL, 0xf5fb06f70ef5f5f3ULL, + 0x79ef80f2967979f9ULL, 0x6f5fcede306f6fa1ULL, 0x91fcef3f6d91917eULL, + 0x52aa07a4f8525255ULL, 0x6027fdc04760609dULL, 0xbc89766535bcbccaULL, + 0x9baccd2b379b9b56ULL, 0x8e048c018a8e8e02ULL, 0xa371155bd2a3a3b6ULL, + 0x0c603c186c0c0c30ULL, 0x7bff8af6847b7bf1ULL, 0x35b5e16a803535d4ULL, + 0x1de8693af51d1d74ULL, 0xe05347ddb3e0e0a7ULL, 0xd7f6acb321d7d77bULL, + 0xc25eed999cc2c22fULL, 0x2e6d965c432e2eb8ULL, 0x4b627a96294b4b31ULL, + 0xfea321e15dfefedfULL, 0x578216aed5575741ULL, 0x15a8412abd151554ULL, + 0x779fb6eee87777c1ULL, 0x37a5eb6e923737dcULL, 0xe57b56d79ee5e5b3ULL, + 0x9f8cd923139f9f46ULL, 0xf0d317fd23f0f0e7ULL, 0x4a6a7f94204a4a35ULL, + 0xda9e95a944dada4fULL, 0x58fa25b0a258587dULL, 0xc906ca8fcfc9c903ULL, + 0x29558d527c2929a4ULL, 0x0a5022145a0a0a28ULL, 0xb1e14f7f50b1b1feULL, + 0xa0691a5dc9a0a0baULL, 0x6b7fdad6146b6bb1ULL, 0x855cab17d985852eULL, + 0xbd8173673cbdbdceULL, 0x5dd234ba8f5d5d69ULL, 0x1080502090101040ULL, + 0xf4f303f507f4f4f7ULL, 0xcb16c08bddcbcb0bULL, 0x3eedc67cd33e3ef8ULL, + 0x0528110a2d050514ULL, 0x671fe6ce78676781ULL, 0xe47353d597e4e4b7ULL, + 0x2725bb4e0227279cULL, 0x4132588273414119ULL, 0x8b2c9d0ba78b8b16ULL, + 0xa7510153f6a7a7a6ULL, 0x7dcf94fab27d7de9ULL, 0x95dcfb374995956eULL, + 0xd88e9fad56d8d847ULL, 0xfb8b30eb70fbfbcbULL, 0xee2371c1cdeeee9fULL, + 0x7cc791f8bb7c7cedULL, 0x6617e3cc71666685ULL, 0xdda68ea77bdddd53ULL, + 0x17b84b2eaf17175cULL, 0x4702468e45474701ULL, 0x9e84dc211a9e9e42ULL, + 0xca1ec589d4caca0fULL, 0x2d75995a582d2db4ULL, 0xbf9179632ebfbfc6ULL, + 0x07381b0e3f07071cULL, 0xad012347acadad8eULL, 0x5aea2fb4b05a5a75ULL, + 0x836cb51bef838336ULL, 0x3385ff66b63333ccULL, 0x633ff2c65c636391ULL, + 0x02100a0412020208ULL, 0xaa39384993aaaa92ULL, 0x71afa8e2de7171d9ULL, + 0xc80ecf8dc6c8c807ULL, 0x19c87d32d1191964ULL, 0x497270923b494939ULL, + 0xd9869aaf5fd9d943ULL, 0xf2c31df931f2f2efULL, 0xe34b48dba8e3e3abULL, + 0x5be22ab6b95b5b71ULL, 0x8834920dbc88881aULL, 0x9aa4c8293e9a9a52ULL, + 0x262dbe4c0b262698ULL, 0x328dfa64bf3232c8ULL, 0xb0e94a7d59b0b0faULL, + 0xe91b6acff2e9e983ULL, 0x0f78331e770f0f3cULL, 0xd5e6a6b733d5d573ULL, + 0x8074ba1df480803aULL, 0xbe997c6127bebec2ULL, 0xcd26de87ebcdcd13ULL, + 0x34bde468893434d0ULL, 0x487a75903248483dULL, 0xffab24e354ffffdbULL, + 0x7af78ff48d7a7af5ULL, 0x90f4ea3d6490907aULL, 0x5fc23ebe9d5f5f61ULL, + 0x201da0403d202080ULL, 0x6867d5d00f6868bdULL, 0x1ad07234ca1a1a68ULL, + 0xae192c41b7aeae82ULL, 0xb4c95e757db4b4eaULL, 0x549a19a8ce54544dULL, + 0x93ece53b7f939376ULL, 0x220daa442f222288ULL, 0x6407e9c86364648dULL, + 0xf1db12ff2af1f1e3ULL, 0x73bfa2e6cc7373d1ULL, 0x12905a2482121248ULL, + 0x403a5d807a40401dULL, 0x0840281048080820ULL, 0xc356e89b95c3c32bULL, + 0xec337bc5dfecec97ULL, 0xdb9690ab4ddbdb4bULL, 0xa1611f5fc0a1a1beULL, + 0x8d1c8307918d8d0eULL, 0x3df5c97ac83d3df4ULL, 0x97ccf1335b979766ULL, + 0x0000000000000000ULL, 0xcf36d483f9cfcf1bULL, 0x2b4587566e2b2bacULL, + 0x7697b3ece17676c5ULL, 0x8264b019e6828232ULL, 0xd6fea9b128d6d67fULL, + 0x1bd87736c31b1b6cULL, 0xb5c15b7774b5b5eeULL, 0xaf112943beafaf86ULL, + 0x6a77dfd41d6a6ab5ULL, 0x50ba0da0ea50505dULL, 0x45124c8a57454509ULL, + 0xf3cb18fb38f3f3ebULL, 0x309df060ad3030c0ULL, 0xef2b74c3c4efef9bULL, + 0x3fe5c37eda3f3ffcULL, 0x55921caac7555549ULL, 0xa2791059dba2a2b2ULL, + 0xea0365c9e9eaea8fULL, 0x650fecca6a656589ULL, 0xbab9686903babad2ULL, + 0x2f65935e4a2f2fbcULL, 0xc04ee79d8ec0c027ULL, 0xdebe81a160dede5fULL, + 0x1ce06c38fc1c1c70ULL, 0xfdbb2ee746fdfdd3ULL, 0x4d52649a1f4d4d29ULL, + 0x92e4e03976929272ULL, 0x758fbceafa7575c9ULL, 0x06301e0c36060618ULL, + 0x8a249809ae8a8a12ULL, 0xb2f940794bb2b2f2ULL, 0xe66359d185e6e6bfULL, + 0x0e70361c7e0e0e38ULL, 0x1ff8633ee71f1f7cULL, 0x6237f7c455626295ULL, + 0xd4eea3b53ad4d477ULL, 0xa829324d81a8a89aULL, 0x96c4f43152969662ULL, + 0xf99b3aef62f9f9c3ULL, 0xc566f697a3c5c533ULL, 0x2535b14a10252594ULL, + 0x59f220b2ab595979ULL, 0x8454ae15d084842aULL, 0x72b7a7e4c57272d5ULL, + 0x39d5dd72ec3939e4ULL, 0x4c5a6198164c4c2dULL, 0x5eca3bbc945e5e65ULL, + 0x78e785f09f7878fdULL, 0x38ddd870e53838e0ULL, 0x8c148605988c8c0aULL, + 0xd1c6b2bf17d1d163ULL, 0xa5410b57e4a5a5aeULL, 0xe2434dd9a1e2e2afULL, + 0x612ff8c24e616199ULL, 0xb3f1457b42b3b3f6ULL, 0x2115a54234212184ULL, + 0x9c94d625089c9c4aULL, 0x1ef0663cee1e1e78ULL, 0x4322528661434311ULL, + 0xc776fc93b1c7c73bULL, 0xfcb32be54ffcfcd7ULL, 0x0420140824040410ULL, + 0x51b208a2e3515159ULL, 0x99bcc72f2599995eULL, 0x6d4fc4da226d6da9ULL, + 0x0d68391a650d0d34ULL, 0xfa8335e979fafacfULL, 0xdfb684a369dfdf5bULL, + 0x7ed79bfca97e7ee5ULL, 0x243db44819242490ULL, 0x3bc5d776fe3b3becULL, + 0xab313d4b9aabab96ULL, 0xce3ed181f0cece1fULL, 0x1188552299111144ULL, + 0x8f0c8903838f8f06ULL, 0x4e4a6b9c044e4e25ULL, 0xb7d1517366b7b7e6ULL, + 0xeb0b60cbe0ebeb8bULL, 0x3cfdcc78c13c3cf0ULL, 0x817cbf1ffd81813eULL, + 0x94d4fe354094946aULL, 0xf7eb0cf31cf7f7fbULL, 0xb9a1676f18b9b9deULL, + 0x13985f268b13134cULL, 0x2c7d9c58512c2cb0ULL, 0xd3d6b8bb05d3d36bULL, + 0xe76b5cd38ce7e7bbULL, 0x6e57cbdc396e6ea5ULL, 0xc46ef395aac4c437ULL, + 0x03180f061b03030cULL, 0x568a13acdc565645ULL, 0x441a49885e44440dULL, + 0x7fdf9efea07f7fe1ULL, 0xa921374f88a9a99eULL, 0x2a4d8254672a2aa8ULL, + 0xbbb16d6b0abbbbd6ULL, 0xc146e29f87c1c123ULL, 0x53a202a6f1535351ULL, + 0xdcae8ba572dcdc57ULL, 0x0b582716530b0b2cULL, 0x9d9cd327019d9d4eULL, + 0x6c47c1d82b6c6cadULL, 0x3195f562a43131c4ULL, 0x7487b9e8f37474cdULL, + 0xf6e309f115f6f6ffULL, 0x460a438c4c464605ULL, 0xac092645a5acac8aULL, + 0x893c970fb589891eULL, 0x14a04428b4141450ULL, 0xe15b42dfbae1e1a3ULL, + 0x16b04e2ca6161658ULL, 0x3acdd274f73a3ae8ULL, 0x696fd0d2066969b9ULL, + 0x09482d1241090924ULL, 0x70a7ade0d77070ddULL, 0xb6d954716fb6b6e2ULL, + 0xd0ceb7bd1ed0d067ULL, 0xed3b7ec7d6eded93ULL, 0xcc2edb85e2cccc17ULL, + 0x422a578468424215ULL, 0x98b4c22d2c98985aULL, 0xa4490e55eda4a4aaULL, + 0x285d8850752828a0ULL, 0x5cda31b8865c5c6dULL, 0xf8933fed6bf8f8c7ULL, + 0x8644a411c2868622ULL, +}; + +static const u64 C6[256] = { + 0x6018c07830d81818ULL, 0x8c2305af46262323ULL, 0x3fc67ef991b8c6c6ULL, + 0x87e8136fcdfbe8e8ULL, 0x26874ca113cb8787ULL, 0xdab8a9626d11b8b8ULL, + 0x0401080502090101ULL, 0x214f426e9e0d4f4fULL, 0xd836adee6c9b3636ULL, + 0xa2a6590451ffa6a6ULL, 0x6fd2debdb90cd2d2ULL, 0xf3f5fb06f70ef5f5ULL, + 0xf979ef80f2967979ULL, 0xa16f5fcede306f6fULL, 0x7e91fcef3f6d9191ULL, + 0x5552aa07a4f85252ULL, 0x9d6027fdc0476060ULL, 0xcabc89766535bcbcULL, + 0x569baccd2b379b9bULL, 0x028e048c018a8e8eULL, 0xb6a371155bd2a3a3ULL, + 0x300c603c186c0c0cULL, 0xf17bff8af6847b7bULL, 0xd435b5e16a803535ULL, + 0x741de8693af51d1dULL, 0xa7e05347ddb3e0e0ULL, 0x7bd7f6acb321d7d7ULL, + 0x2fc25eed999cc2c2ULL, 0xb82e6d965c432e2eULL, 0x314b627a96294b4bULL, + 0xdffea321e15dfefeULL, 0x41578216aed55757ULL, 0x5415a8412abd1515ULL, + 0xc1779fb6eee87777ULL, 0xdc37a5eb6e923737ULL, 0xb3e57b56d79ee5e5ULL, + 0x469f8cd923139f9fULL, 0xe7f0d317fd23f0f0ULL, 0x354a6a7f94204a4aULL, + 0x4fda9e95a944dadaULL, 0x7d58fa25b0a25858ULL, 0x03c906ca8fcfc9c9ULL, + 0xa429558d527c2929ULL, 0x280a5022145a0a0aULL, 0xfeb1e14f7f50b1b1ULL, + 0xbaa0691a5dc9a0a0ULL, 0xb16b7fdad6146b6bULL, 0x2e855cab17d98585ULL, + 0xcebd8173673cbdbdULL, 0x695dd234ba8f5d5dULL, 0x4010805020901010ULL, + 0xf7f4f303f507f4f4ULL, 0x0bcb16c08bddcbcbULL, 0xf83eedc67cd33e3eULL, + 0x140528110a2d0505ULL, 0x81671fe6ce786767ULL, 0xb7e47353d597e4e4ULL, + 0x9c2725bb4e022727ULL, 0x1941325882734141ULL, 0x168b2c9d0ba78b8bULL, + 0xa6a7510153f6a7a7ULL, 0xe97dcf94fab27d7dULL, 0x6e95dcfb37499595ULL, + 0x47d88e9fad56d8d8ULL, 0xcbfb8b30eb70fbfbULL, 0x9fee2371c1cdeeeeULL, + 0xed7cc791f8bb7c7cULL, 0x856617e3cc716666ULL, 0x53dda68ea77bddddULL, + 0x5c17b84b2eaf1717ULL, 0x014702468e454747ULL, 0x429e84dc211a9e9eULL, + 0x0fca1ec589d4cacaULL, 0xb42d75995a582d2dULL, 0xc6bf9179632ebfbfULL, + 0x1c07381b0e3f0707ULL, 0x8ead012347acadadULL, 0x755aea2fb4b05a5aULL, + 0x36836cb51bef8383ULL, 0xcc3385ff66b63333ULL, 0x91633ff2c65c6363ULL, + 0x0802100a04120202ULL, 0x92aa39384993aaaaULL, 0xd971afa8e2de7171ULL, + 0x07c80ecf8dc6c8c8ULL, 0x6419c87d32d11919ULL, 0x39497270923b4949ULL, + 0x43d9869aaf5fd9d9ULL, 0xeff2c31df931f2f2ULL, 0xabe34b48dba8e3e3ULL, + 0x715be22ab6b95b5bULL, 0x1a8834920dbc8888ULL, 0x529aa4c8293e9a9aULL, + 0x98262dbe4c0b2626ULL, 0xc8328dfa64bf3232ULL, 0xfab0e94a7d59b0b0ULL, + 0x83e91b6acff2e9e9ULL, 0x3c0f78331e770f0fULL, 0x73d5e6a6b733d5d5ULL, + 0x3a8074ba1df48080ULL, 0xc2be997c6127bebeULL, 0x13cd26de87ebcdcdULL, + 0xd034bde468893434ULL, 0x3d487a7590324848ULL, 0xdbffab24e354ffffULL, + 0xf57af78ff48d7a7aULL, 0x7a90f4ea3d649090ULL, 0x615fc23ebe9d5f5fULL, + 0x80201da0403d2020ULL, 0xbd6867d5d00f6868ULL, 0x681ad07234ca1a1aULL, + 0x82ae192c41b7aeaeULL, 0xeab4c95e757db4b4ULL, 0x4d549a19a8ce5454ULL, + 0x7693ece53b7f9393ULL, 0x88220daa442f2222ULL, 0x8d6407e9c8636464ULL, + 0xe3f1db12ff2af1f1ULL, 0xd173bfa2e6cc7373ULL, 0x4812905a24821212ULL, + 0x1d403a5d807a4040ULL, 0x2008402810480808ULL, 0x2bc356e89b95c3c3ULL, + 0x97ec337bc5dfececULL, 0x4bdb9690ab4ddbdbULL, 0xbea1611f5fc0a1a1ULL, + 0x0e8d1c8307918d8dULL, 0xf43df5c97ac83d3dULL, 0x6697ccf1335b9797ULL, + 0x0000000000000000ULL, 0x1bcf36d483f9cfcfULL, 0xac2b4587566e2b2bULL, + 0xc57697b3ece17676ULL, 0x328264b019e68282ULL, 0x7fd6fea9b128d6d6ULL, + 0x6c1bd87736c31b1bULL, 0xeeb5c15b7774b5b5ULL, 0x86af112943beafafULL, + 0xb56a77dfd41d6a6aULL, 0x5d50ba0da0ea5050ULL, 0x0945124c8a574545ULL, + 0xebf3cb18fb38f3f3ULL, 0xc0309df060ad3030ULL, 0x9bef2b74c3c4efefULL, + 0xfc3fe5c37eda3f3fULL, 0x4955921caac75555ULL, 0xb2a2791059dba2a2ULL, + 0x8fea0365c9e9eaeaULL, 0x89650fecca6a6565ULL, 0xd2bab9686903babaULL, + 0xbc2f65935e4a2f2fULL, 0x27c04ee79d8ec0c0ULL, 0x5fdebe81a160dedeULL, + 0x701ce06c38fc1c1cULL, 0xd3fdbb2ee746fdfdULL, 0x294d52649a1f4d4dULL, + 0x7292e4e039769292ULL, 0xc9758fbceafa7575ULL, 0x1806301e0c360606ULL, + 0x128a249809ae8a8aULL, 0xf2b2f940794bb2b2ULL, 0xbfe66359d185e6e6ULL, + 0x380e70361c7e0e0eULL, 0x7c1ff8633ee71f1fULL, 0x956237f7c4556262ULL, + 0x77d4eea3b53ad4d4ULL, 0x9aa829324d81a8a8ULL, 0x6296c4f431529696ULL, + 0xc3f99b3aef62f9f9ULL, 0x33c566f697a3c5c5ULL, 0x942535b14a102525ULL, + 0x7959f220b2ab5959ULL, 0x2a8454ae15d08484ULL, 0xd572b7a7e4c57272ULL, + 0xe439d5dd72ec3939ULL, 0x2d4c5a6198164c4cULL, 0x655eca3bbc945e5eULL, + 0xfd78e785f09f7878ULL, 0xe038ddd870e53838ULL, 0x0a8c148605988c8cULL, + 0x63d1c6b2bf17d1d1ULL, 0xaea5410b57e4a5a5ULL, 0xafe2434dd9a1e2e2ULL, + 0x99612ff8c24e6161ULL, 0xf6b3f1457b42b3b3ULL, 0x842115a542342121ULL, + 0x4a9c94d625089c9cULL, 0x781ef0663cee1e1eULL, 0x1143225286614343ULL, + 0x3bc776fc93b1c7c7ULL, 0xd7fcb32be54ffcfcULL, 0x1004201408240404ULL, + 0x5951b208a2e35151ULL, 0x5e99bcc72f259999ULL, 0xa96d4fc4da226d6dULL, + 0x340d68391a650d0dULL, 0xcffa8335e979fafaULL, 0x5bdfb684a369dfdfULL, + 0xe57ed79bfca97e7eULL, 0x90243db448192424ULL, 0xec3bc5d776fe3b3bULL, + 0x96ab313d4b9aababULL, 0x1fce3ed181f0ceceULL, 0x4411885522991111ULL, + 0x068f0c8903838f8fULL, 0x254e4a6b9c044e4eULL, 0xe6b7d1517366b7b7ULL, + 0x8beb0b60cbe0ebebULL, 0xf03cfdcc78c13c3cULL, 0x3e817cbf1ffd8181ULL, + 0x6a94d4fe35409494ULL, 0xfbf7eb0cf31cf7f7ULL, 0xdeb9a1676f18b9b9ULL, + 0x4c13985f268b1313ULL, 0xb02c7d9c58512c2cULL, 0x6bd3d6b8bb05d3d3ULL, + 0xbbe76b5cd38ce7e7ULL, 0xa56e57cbdc396e6eULL, 0x37c46ef395aac4c4ULL, + 0x0c03180f061b0303ULL, 0x45568a13acdc5656ULL, 0x0d441a49885e4444ULL, + 0xe17fdf9efea07f7fULL, 0x9ea921374f88a9a9ULL, 0xa82a4d8254672a2aULL, + 0xd6bbb16d6b0abbbbULL, 0x23c146e29f87c1c1ULL, 0x5153a202a6f15353ULL, + 0x57dcae8ba572dcdcULL, 0x2c0b582716530b0bULL, 0x4e9d9cd327019d9dULL, + 0xad6c47c1d82b6c6cULL, 0xc43195f562a43131ULL, 0xcd7487b9e8f37474ULL, + 0xfff6e309f115f6f6ULL, 0x05460a438c4c4646ULL, 0x8aac092645a5acacULL, + 0x1e893c970fb58989ULL, 0x5014a04428b41414ULL, 0xa3e15b42dfbae1e1ULL, + 0x5816b04e2ca61616ULL, 0xe83acdd274f73a3aULL, 0xb9696fd0d2066969ULL, + 0x2409482d12410909ULL, 0xdd70a7ade0d77070ULL, 0xe2b6d954716fb6b6ULL, + 0x67d0ceb7bd1ed0d0ULL, 0x93ed3b7ec7d6ededULL, 0x17cc2edb85e2ccccULL, + 0x15422a5784684242ULL, 0x5a98b4c22d2c9898ULL, 0xaaa4490e55eda4a4ULL, + 0xa0285d8850752828ULL, 0x6d5cda31b8865c5cULL, 0xc7f8933fed6bf8f8ULL, + 0x228644a411c28686ULL, +}; + +static const u64 C7[256] = { + 0x186018c07830d818ULL, 0x238c2305af462623ULL, 0xc63fc67ef991b8c6ULL, + 0xe887e8136fcdfbe8ULL, 0x8726874ca113cb87ULL, 0xb8dab8a9626d11b8ULL, + 0x0104010805020901ULL, 0x4f214f426e9e0d4fULL, 0x36d836adee6c9b36ULL, + 0xa6a2a6590451ffa6ULL, 0xd26fd2debdb90cd2ULL, 0xf5f3f5fb06f70ef5ULL, + 0x79f979ef80f29679ULL, 0x6fa16f5fcede306fULL, 0x917e91fcef3f6d91ULL, + 0x525552aa07a4f852ULL, 0x609d6027fdc04760ULL, 0xbccabc89766535bcULL, + 0x9b569baccd2b379bULL, 0x8e028e048c018a8eULL, 0xa3b6a371155bd2a3ULL, + 0x0c300c603c186c0cULL, 0x7bf17bff8af6847bULL, 0x35d435b5e16a8035ULL, + 0x1d741de8693af51dULL, 0xe0a7e05347ddb3e0ULL, 0xd77bd7f6acb321d7ULL, + 0xc22fc25eed999cc2ULL, 0x2eb82e6d965c432eULL, 0x4b314b627a96294bULL, + 0xfedffea321e15dfeULL, 0x5741578216aed557ULL, 0x155415a8412abd15ULL, + 0x77c1779fb6eee877ULL, 0x37dc37a5eb6e9237ULL, 0xe5b3e57b56d79ee5ULL, + 0x9f469f8cd923139fULL, 0xf0e7f0d317fd23f0ULL, 0x4a354a6a7f94204aULL, + 0xda4fda9e95a944daULL, 0x587d58fa25b0a258ULL, 0xc903c906ca8fcfc9ULL, + 0x29a429558d527c29ULL, 0x0a280a5022145a0aULL, 0xb1feb1e14f7f50b1ULL, + 0xa0baa0691a5dc9a0ULL, 0x6bb16b7fdad6146bULL, 0x852e855cab17d985ULL, + 0xbdcebd8173673cbdULL, 0x5d695dd234ba8f5dULL, 0x1040108050209010ULL, + 0xf4f7f4f303f507f4ULL, 0xcb0bcb16c08bddcbULL, 0x3ef83eedc67cd33eULL, + 0x05140528110a2d05ULL, 0x6781671fe6ce7867ULL, 0xe4b7e47353d597e4ULL, + 0x279c2725bb4e0227ULL, 0x4119413258827341ULL, 0x8b168b2c9d0ba78bULL, + 0xa7a6a7510153f6a7ULL, 0x7de97dcf94fab27dULL, 0x956e95dcfb374995ULL, + 0xd847d88e9fad56d8ULL, 0xfbcbfb8b30eb70fbULL, 0xee9fee2371c1cdeeULL, + 0x7ced7cc791f8bb7cULL, 0x66856617e3cc7166ULL, 0xdd53dda68ea77bddULL, + 0x175c17b84b2eaf17ULL, 0x47014702468e4547ULL, 0x9e429e84dc211a9eULL, + 0xca0fca1ec589d4caULL, 0x2db42d75995a582dULL, 0xbfc6bf9179632ebfULL, + 0x071c07381b0e3f07ULL, 0xad8ead012347acadULL, 0x5a755aea2fb4b05aULL, + 0x8336836cb51bef83ULL, 0x33cc3385ff66b633ULL, 0x6391633ff2c65c63ULL, + 0x020802100a041202ULL, 0xaa92aa39384993aaULL, 0x71d971afa8e2de71ULL, + 0xc807c80ecf8dc6c8ULL, 0x196419c87d32d119ULL, 0x4939497270923b49ULL, + 0xd943d9869aaf5fd9ULL, 0xf2eff2c31df931f2ULL, 0xe3abe34b48dba8e3ULL, + 0x5b715be22ab6b95bULL, 0x881a8834920dbc88ULL, 0x9a529aa4c8293e9aULL, + 0x2698262dbe4c0b26ULL, 0x32c8328dfa64bf32ULL, 0xb0fab0e94a7d59b0ULL, + 0xe983e91b6acff2e9ULL, 0x0f3c0f78331e770fULL, 0xd573d5e6a6b733d5ULL, + 0x803a8074ba1df480ULL, 0xbec2be997c6127beULL, 0xcd13cd26de87ebcdULL, + 0x34d034bde4688934ULL, 0x483d487a75903248ULL, 0xffdbffab24e354ffULL, + 0x7af57af78ff48d7aULL, 0x907a90f4ea3d6490ULL, 0x5f615fc23ebe9d5fULL, + 0x2080201da0403d20ULL, 0x68bd6867d5d00f68ULL, 0x1a681ad07234ca1aULL, + 0xae82ae192c41b7aeULL, 0xb4eab4c95e757db4ULL, 0x544d549a19a8ce54ULL, + 0x937693ece53b7f93ULL, 0x2288220daa442f22ULL, 0x648d6407e9c86364ULL, + 0xf1e3f1db12ff2af1ULL, 0x73d173bfa2e6cc73ULL, 0x124812905a248212ULL, + 0x401d403a5d807a40ULL, 0x0820084028104808ULL, 0xc32bc356e89b95c3ULL, + 0xec97ec337bc5dfecULL, 0xdb4bdb9690ab4ddbULL, 0xa1bea1611f5fc0a1ULL, + 0x8d0e8d1c8307918dULL, 0x3df43df5c97ac83dULL, 0x976697ccf1335b97ULL, + 0x0000000000000000ULL, 0xcf1bcf36d483f9cfULL, 0x2bac2b4587566e2bULL, + 0x76c57697b3ece176ULL, 0x82328264b019e682ULL, 0xd67fd6fea9b128d6ULL, + 0x1b6c1bd87736c31bULL, 0xb5eeb5c15b7774b5ULL, 0xaf86af112943beafULL, + 0x6ab56a77dfd41d6aULL, 0x505d50ba0da0ea50ULL, 0x450945124c8a5745ULL, + 0xf3ebf3cb18fb38f3ULL, 0x30c0309df060ad30ULL, 0xef9bef2b74c3c4efULL, + 0x3ffc3fe5c37eda3fULL, 0x554955921caac755ULL, 0xa2b2a2791059dba2ULL, + 0xea8fea0365c9e9eaULL, 0x6589650fecca6a65ULL, 0xbad2bab9686903baULL, + 0x2fbc2f65935e4a2fULL, 0xc027c04ee79d8ec0ULL, 0xde5fdebe81a160deULL, + 0x1c701ce06c38fc1cULL, 0xfdd3fdbb2ee746fdULL, 0x4d294d52649a1f4dULL, + 0x927292e4e0397692ULL, 0x75c9758fbceafa75ULL, 0x061806301e0c3606ULL, + 0x8a128a249809ae8aULL, 0xb2f2b2f940794bb2ULL, 0xe6bfe66359d185e6ULL, + 0x0e380e70361c7e0eULL, 0x1f7c1ff8633ee71fULL, 0x62956237f7c45562ULL, + 0xd477d4eea3b53ad4ULL, 0xa89aa829324d81a8ULL, 0x966296c4f4315296ULL, + 0xf9c3f99b3aef62f9ULL, 0xc533c566f697a3c5ULL, 0x25942535b14a1025ULL, + 0x597959f220b2ab59ULL, 0x842a8454ae15d084ULL, 0x72d572b7a7e4c572ULL, + 0x39e439d5dd72ec39ULL, 0x4c2d4c5a6198164cULL, 0x5e655eca3bbc945eULL, + 0x78fd78e785f09f78ULL, 0x38e038ddd870e538ULL, 0x8c0a8c148605988cULL, + 0xd163d1c6b2bf17d1ULL, 0xa5aea5410b57e4a5ULL, 0xe2afe2434dd9a1e2ULL, + 0x6199612ff8c24e61ULL, 0xb3f6b3f1457b42b3ULL, 0x21842115a5423421ULL, + 0x9c4a9c94d625089cULL, 0x1e781ef0663cee1eULL, 0x4311432252866143ULL, + 0xc73bc776fc93b1c7ULL, 0xfcd7fcb32be54ffcULL, 0x0410042014082404ULL, + 0x515951b208a2e351ULL, 0x995e99bcc72f2599ULL, 0x6da96d4fc4da226dULL, + 0x0d340d68391a650dULL, 0xfacffa8335e979faULL, 0xdf5bdfb684a369dfULL, + 0x7ee57ed79bfca97eULL, 0x2490243db4481924ULL, 0x3bec3bc5d776fe3bULL, + 0xab96ab313d4b9aabULL, 0xce1fce3ed181f0ceULL, 0x1144118855229911ULL, + 0x8f068f0c8903838fULL, 0x4e254e4a6b9c044eULL, 0xb7e6b7d1517366b7ULL, + 0xeb8beb0b60cbe0ebULL, 0x3cf03cfdcc78c13cULL, 0x813e817cbf1ffd81ULL, + 0x946a94d4fe354094ULL, 0xf7fbf7eb0cf31cf7ULL, 0xb9deb9a1676f18b9ULL, + 0x134c13985f268b13ULL, 0x2cb02c7d9c58512cULL, 0xd36bd3d6b8bb05d3ULL, + 0xe7bbe76b5cd38ce7ULL, 0x6ea56e57cbdc396eULL, 0xc437c46ef395aac4ULL, + 0x030c03180f061b03ULL, 0x5645568a13acdc56ULL, 0x440d441a49885e44ULL, + 0x7fe17fdf9efea07fULL, 0xa99ea921374f88a9ULL, 0x2aa82a4d8254672aULL, + 0xbbd6bbb16d6b0abbULL, 0xc123c146e29f87c1ULL, 0x535153a202a6f153ULL, + 0xdc57dcae8ba572dcULL, 0x0b2c0b582716530bULL, 0x9d4e9d9cd327019dULL, + 0x6cad6c47c1d82b6cULL, 0x31c43195f562a431ULL, 0x74cd7487b9e8f374ULL, + 0xf6fff6e309f115f6ULL, 0x4605460a438c4c46ULL, 0xac8aac092645a5acULL, + 0x891e893c970fb589ULL, 0x145014a04428b414ULL, 0xe1a3e15b42dfbae1ULL, + 0x165816b04e2ca616ULL, 0x3ae83acdd274f73aULL, 0x69b9696fd0d20669ULL, + 0x092409482d124109ULL, 0x70dd70a7ade0d770ULL, 0xb6e2b6d954716fb6ULL, + 0xd067d0ceb7bd1ed0ULL, 0xed93ed3b7ec7d6edULL, 0xcc17cc2edb85e2ccULL, + 0x4215422a57846842ULL, 0x985a98b4c22d2c98ULL, 0xa4aaa4490e55eda4ULL, + 0x28a0285d88507528ULL, 0x5c6d5cda31b8865cULL, 0xf8c7f8933fed6bf8ULL, + 0x86228644a411c286ULL, +}; + +static const u64 rc[WHIRLPOOL_ROUNDS + 1] = { + 0x0000000000000000ULL, 0x1823c6e887b8014fULL, 0x36a6d2f5796f9152ULL, + 0x60bc9b8ea30c7b35ULL, 0x1de0d7c22e4bfe57ULL, 0x157737e59ff04adaULL, + 0x58c9290ab1a06b85ULL, 0xbd5d10f4cb3e0567ULL, 0xe427418ba77d95d8ULL, + 0xfbee7c66dd17479eULL, 0xca2dbf07ad5a8333ULL, +}; + +/** + * The core Whirlpool transform. + */ + +static void wp512_process_buffer(struct wp512_ctx *wctx) { + int i, r; + u64 K[8]; /* the round key */ + u64 block[8]; /* mu(buffer) */ + u64 state[8]; /* the cipher state */ + u64 L[8]; + u8 *buffer = wctx->buffer; + + for (i = 0; i < 8; i++, buffer += 8) { + block[i] = + (((u64)buffer[0] ) << 56) ^ + (((u64)buffer[1] & 0xffL) << 48) ^ + (((u64)buffer[2] & 0xffL) << 40) ^ + (((u64)buffer[3] & 0xffL) << 32) ^ + (((u64)buffer[4] & 0xffL) << 24) ^ + (((u64)buffer[5] & 0xffL) << 16) ^ + (((u64)buffer[6] & 0xffL) << 8) ^ + (((u64)buffer[7] & 0xffL) ); + } + + state[0] = block[0] ^ (K[0] = wctx->hash[0]); + state[1] = block[1] ^ (K[1] = wctx->hash[1]); + state[2] = block[2] ^ (K[2] = wctx->hash[2]); + state[3] = block[3] ^ (K[3] = wctx->hash[3]); + state[4] = block[4] ^ (K[4] = wctx->hash[4]); + state[5] = block[5] ^ (K[5] = wctx->hash[5]); + state[6] = block[6] ^ (K[6] = wctx->hash[6]); + state[7] = block[7] ^ (K[7] = wctx->hash[7]); + + for (r = 1; r <= WHIRLPOOL_ROUNDS; r++) { + + L[0] = C0[(int)(K[0] >> 56) ] ^ + C1[(int)(K[7] >> 48) & 0xff] ^ + C2[(int)(K[6] >> 40) & 0xff] ^ + C3[(int)(K[5] >> 32) & 0xff] ^ + C4[(int)(K[4] >> 24) & 0xff] ^ + C5[(int)(K[3] >> 16) & 0xff] ^ + C6[(int)(K[2] >> 8) & 0xff] ^ + C7[(int)(K[1] ) & 0xff] ^ + rc[r]; + + L[1] = C0[(int)(K[1] >> 56) ] ^ + C1[(int)(K[0] >> 48) & 0xff] ^ + C2[(int)(K[7] >> 40) & 0xff] ^ + C3[(int)(K[6] >> 32) & 0xff] ^ + C4[(int)(K[5] >> 24) & 0xff] ^ + C5[(int)(K[4] >> 16) & 0xff] ^ + C6[(int)(K[3] >> 8) & 0xff] ^ + C7[(int)(K[2] ) & 0xff]; + + L[2] = C0[(int)(K[2] >> 56) ] ^ + C1[(int)(K[1] >> 48) & 0xff] ^ + C2[(int)(K[0] >> 40) & 0xff] ^ + C3[(int)(K[7] >> 32) & 0xff] ^ + C4[(int)(K[6] >> 24) & 0xff] ^ + C5[(int)(K[5] >> 16) & 0xff] ^ + C6[(int)(K[4] >> 8) & 0xff] ^ + C7[(int)(K[3] ) & 0xff]; + + L[3] = C0[(int)(K[3] >> 56) ] ^ + C1[(int)(K[2] >> 48) & 0xff] ^ + C2[(int)(K[1] >> 40) & 0xff] ^ + C3[(int)(K[0] >> 32) & 0xff] ^ + C4[(int)(K[7] >> 24) & 0xff] ^ + C5[(int)(K[6] >> 16) & 0xff] ^ + C6[(int)(K[5] >> 8) & 0xff] ^ + C7[(int)(K[4] ) & 0xff]; + + L[4] = C0[(int)(K[4] >> 56) ] ^ + C1[(int)(K[3] >> 48) & 0xff] ^ + C2[(int)(K[2] >> 40) & 0xff] ^ + C3[(int)(K[1] >> 32) & 0xff] ^ + C4[(int)(K[0] >> 24) & 0xff] ^ + C5[(int)(K[7] >> 16) & 0xff] ^ + C6[(int)(K[6] >> 8) & 0xff] ^ + C7[(int)(K[5] ) & 0xff]; + + L[5] = C0[(int)(K[5] >> 56) ] ^ + C1[(int)(K[4] >> 48) & 0xff] ^ + C2[(int)(K[3] >> 40) & 0xff] ^ + C3[(int)(K[2] >> 32) & 0xff] ^ + C4[(int)(K[1] >> 24) & 0xff] ^ + C5[(int)(K[0] >> 16) & 0xff] ^ + C6[(int)(K[7] >> 8) & 0xff] ^ + C7[(int)(K[6] ) & 0xff]; + + L[6] = C0[(int)(K[6] >> 56) ] ^ + C1[(int)(K[5] >> 48) & 0xff] ^ + C2[(int)(K[4] >> 40) & 0xff] ^ + C3[(int)(K[3] >> 32) & 0xff] ^ + C4[(int)(K[2] >> 24) & 0xff] ^ + C5[(int)(K[1] >> 16) & 0xff] ^ + C6[(int)(K[0] >> 8) & 0xff] ^ + C7[(int)(K[7] ) & 0xff]; + + L[7] = C0[(int)(K[7] >> 56) ] ^ + C1[(int)(K[6] >> 48) & 0xff] ^ + C2[(int)(K[5] >> 40) & 0xff] ^ + C3[(int)(K[4] >> 32) & 0xff] ^ + C4[(int)(K[3] >> 24) & 0xff] ^ + C5[(int)(K[2] >> 16) & 0xff] ^ + C6[(int)(K[1] >> 8) & 0xff] ^ + C7[(int)(K[0] ) & 0xff]; + + K[0] = L[0]; + K[1] = L[1]; + K[2] = L[2]; + K[3] = L[3]; + K[4] = L[4]; + K[5] = L[5]; + K[6] = L[6]; + K[7] = L[7]; + + L[0] = C0[(int)(state[0] >> 56) ] ^ + C1[(int)(state[7] >> 48) & 0xff] ^ + C2[(int)(state[6] >> 40) & 0xff] ^ + C3[(int)(state[5] >> 32) & 0xff] ^ + C4[(int)(state[4] >> 24) & 0xff] ^ + C5[(int)(state[3] >> 16) & 0xff] ^ + C6[(int)(state[2] >> 8) & 0xff] ^ + C7[(int)(state[1] ) & 0xff] ^ + K[0]; + + L[1] = C0[(int)(state[1] >> 56) ] ^ + C1[(int)(state[0] >> 48) & 0xff] ^ + C2[(int)(state[7] >> 40) & 0xff] ^ + C3[(int)(state[6] >> 32) & 0xff] ^ + C4[(int)(state[5] >> 24) & 0xff] ^ + C5[(int)(state[4] >> 16) & 0xff] ^ + C6[(int)(state[3] >> 8) & 0xff] ^ + C7[(int)(state[2] ) & 0xff] ^ + K[1]; + + L[2] = C0[(int)(state[2] >> 56) ] ^ + C1[(int)(state[1] >> 48) & 0xff] ^ + C2[(int)(state[0] >> 40) & 0xff] ^ + C3[(int)(state[7] >> 32) & 0xff] ^ + C4[(int)(state[6] >> 24) & 0xff] ^ + C5[(int)(state[5] >> 16) & 0xff] ^ + C6[(int)(state[4] >> 8) & 0xff] ^ + C7[(int)(state[3] ) & 0xff] ^ + K[2]; + + L[3] = C0[(int)(state[3] >> 56) ] ^ + C1[(int)(state[2] >> 48) & 0xff] ^ + C2[(int)(state[1] >> 40) & 0xff] ^ + C3[(int)(state[0] >> 32) & 0xff] ^ + C4[(int)(state[7] >> 24) & 0xff] ^ + C5[(int)(state[6] >> 16) & 0xff] ^ + C6[(int)(state[5] >> 8) & 0xff] ^ + C7[(int)(state[4] ) & 0xff] ^ + K[3]; + + L[4] = C0[(int)(state[4] >> 56) ] ^ + C1[(int)(state[3] >> 48) & 0xff] ^ + C2[(int)(state[2] >> 40) & 0xff] ^ + C3[(int)(state[1] >> 32) & 0xff] ^ + C4[(int)(state[0] >> 24) & 0xff] ^ + C5[(int)(state[7] >> 16) & 0xff] ^ + C6[(int)(state[6] >> 8) & 0xff] ^ + C7[(int)(state[5] ) & 0xff] ^ + K[4]; + + L[5] = C0[(int)(state[5] >> 56) ] ^ + C1[(int)(state[4] >> 48) & 0xff] ^ + C2[(int)(state[3] >> 40) & 0xff] ^ + C3[(int)(state[2] >> 32) & 0xff] ^ + C4[(int)(state[1] >> 24) & 0xff] ^ + C5[(int)(state[0] >> 16) & 0xff] ^ + C6[(int)(state[7] >> 8) & 0xff] ^ + C7[(int)(state[6] ) & 0xff] ^ + K[5]; + + L[6] = C0[(int)(state[6] >> 56) ] ^ + C1[(int)(state[5] >> 48) & 0xff] ^ + C2[(int)(state[4] >> 40) & 0xff] ^ + C3[(int)(state[3] >> 32) & 0xff] ^ + C4[(int)(state[2] >> 24) & 0xff] ^ + C5[(int)(state[1] >> 16) & 0xff] ^ + C6[(int)(state[0] >> 8) & 0xff] ^ + C7[(int)(state[7] ) & 0xff] ^ + K[6]; + + L[7] = C0[(int)(state[7] >> 56) ] ^ + C1[(int)(state[6] >> 48) & 0xff] ^ + C2[(int)(state[5] >> 40) & 0xff] ^ + C3[(int)(state[4] >> 32) & 0xff] ^ + C4[(int)(state[3] >> 24) & 0xff] ^ + C5[(int)(state[2] >> 16) & 0xff] ^ + C6[(int)(state[1] >> 8) & 0xff] ^ + C7[(int)(state[0] ) & 0xff] ^ + K[7]; + + state[0] = L[0]; + state[1] = L[1]; + state[2] = L[2]; + state[3] = L[3]; + state[4] = L[4]; + state[5] = L[5]; + state[6] = L[6]; + state[7] = L[7]; + } + /* + * apply the Miyaguchi-Preneel compression function: + */ + wctx->hash[0] ^= state[0] ^ block[0]; + wctx->hash[1] ^= state[1] ^ block[1]; + wctx->hash[2] ^= state[2] ^ block[2]; + wctx->hash[3] ^= state[3] ^ block[3]; + wctx->hash[4] ^= state[4] ^ block[4]; + wctx->hash[5] ^= state[5] ^ block[5]; + wctx->hash[6] ^= state[6] ^ block[6]; + wctx->hash[7] ^= state[7] ^ block[7]; + +} + +static void wp512_init (void *ctx) { + int i; + struct wp512_ctx *wctx = ctx; + + memset(wctx->bitLength, 0, 32); + wctx->bufferBits = wctx->bufferPos = 0; + wctx->buffer[0] = 0; + for (i = 0; i < 8; i++) { + wctx->hash[i] = 0L; + } +} + +static void wp512_update(void *ctx, const u8 *source, unsigned int len) +{ + + struct wp512_ctx *wctx = ctx; + int sourcePos = 0; + unsigned int bits_len = len * 8; // convert to number of bits + int sourceGap = (8 - ((int)bits_len & 7)) & 7; + int bufferRem = wctx->bufferBits & 7; + int i; + u32 b, carry; + u8 *buffer = wctx->buffer; + u8 *bitLength = wctx->bitLength; + int bufferBits = wctx->bufferBits; + int bufferPos = wctx->bufferPos; + + u64 value = bits_len; + for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != 0ULL); i--) { + carry += bitLength[i] + ((u32)value & 0xff); + bitLength[i] = (u8)carry; + carry >>= 8; + value >>= 8; + } + while (bits_len > 8) { + b = ((source[sourcePos] << sourceGap) & 0xff) | + ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap)); + buffer[bufferPos++] |= (u8)(b >> bufferRem); + bufferBits += 8 - bufferRem; + if (bufferBits == WP512_BLOCK_SIZE * 8) { + wp512_process_buffer(wctx); + bufferBits = bufferPos = 0; + } + buffer[bufferPos] = b << (8 - bufferRem); + bufferBits += bufferRem; + bits_len -= 8; + sourcePos++; + } + if (bits_len > 0) { + b = (source[sourcePos] << sourceGap) & 0xff; + buffer[bufferPos] |= b >> bufferRem; + } else { + b = 0; + } + if (bufferRem + bits_len < 8) { + bufferBits += bits_len; + } else { + bufferPos++; + bufferBits += 8 - bufferRem; + bits_len -= 8 - bufferRem; + if (bufferBits == WP512_BLOCK_SIZE * 8) { + wp512_process_buffer(wctx); + bufferBits = bufferPos = 0; + } + buffer[bufferPos] = b << (8 - bufferRem); + bufferBits += (int)bits_len; + } + + wctx->bufferBits = bufferBits; + wctx->bufferPos = bufferPos; + +} + +static void wp512_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + int i; + u8 *buffer = wctx->buffer; + u8 *bitLength = wctx->bitLength; + int bufferBits = wctx->bufferBits; + int bufferPos = wctx->bufferPos; + u8 *digest = out; + + buffer[bufferPos] |= 0x80U >> (bufferBits & 7); + bufferPos++; + if (bufferPos > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) { + if (bufferPos < WP512_BLOCK_SIZE) { + memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos); + } + wp512_process_buffer(wctx); + bufferPos = 0; + } + if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES) { + memset(&buffer[bufferPos], 0, + (WP512_BLOCK_SIZE - WP512_LENGTHBYTES) - bufferPos); + } + bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES; + memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES], + bitLength, WP512_LENGTHBYTES); + wp512_process_buffer(wctx); + for (i = 0; i < WP512_DIGEST_SIZE/8; i++) { + digest[0] = (u8)(wctx->hash[i] >> 56); + digest[1] = (u8)(wctx->hash[i] >> 48); + digest[2] = (u8)(wctx->hash[i] >> 40); + digest[3] = (u8)(wctx->hash[i] >> 32); + digest[4] = (u8)(wctx->hash[i] >> 24); + digest[5] = (u8)(wctx->hash[i] >> 16); + digest[6] = (u8)(wctx->hash[i] >> 8); + digest[7] = (u8)(wctx->hash[i] ); + digest += 8; + } + wctx->bufferBits = bufferBits; + wctx->bufferPos = bufferPos; +} + +static void wp384_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + u8 D[64]; + + wp512_final (wctx, D); + memcpy (out, D, WP384_DIGEST_SIZE); + memset (D, 0, WP512_DIGEST_SIZE); +} + +static void wp256_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + u8 D[64]; + + wp512_final (wctx, D); + memcpy (out, D, WP256_DIGEST_SIZE); + memset (D, 0, WP512_DIGEST_SIZE); +} + +static struct crypto_alg wp512 = { + .cra_name = "wp512", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp512.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP512_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp512_final } } +}; + +static struct crypto_alg wp384 = { + .cra_name = "wp384", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp384.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP384_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp384_final } } +}; + +static struct crypto_alg wp256 = { + .cra_name = "wp256", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp256.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP256_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp256_final } } +}; + +static int __init init(void) +{ + int ret = 0; + + ret = crypto_register_alg(&wp512); + + if (ret < 0) + goto out; + + ret = crypto_register_alg(&wp384); + if (ret < 0) + { + crypto_unregister_alg(&wp512); + goto out; + } + + ret = crypto_register_alg(&wp256); + if (ret < 0) + { + crypto_unregister_alg(&wp512); + crypto_unregister_alg(&wp384); + } +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&wp512); + crypto_unregister_alg(&wp384); + crypto_unregister_alg(&wp256); +} + +MODULE_ALIAS("wp384"); +MODULE_ALIAS("wp256"); + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Whirlpool Message Digest Algorithm"); diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile 2004-10-18 14:56:49 -07:00 +++ b/drivers/Makefile 2004-10-18 14:56:49 -07:00 @@ -7,6 +7,7 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ +obj-y += video/ obj-$(CONFIG_ACPI_BOOT) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi # was used and do nothing if so @@ -15,6 +16,13 @@ # char/ comes before serial/ etc so that the VT console is the boot-time # default. obj-y += char/ + +# i810fb depends on char/agp/ +obj-$(CONFIG_FB_I810) += video/i810/ + +# we also need input/serio early so serio bus is initialized by the time +# serial drivers start registering their serio ports +obj-$(CONFIG_SERIO) += input/serio/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ net/ media/ @@ -26,7 +34,7 @@ obj-$(CONFIG_SCSI) += scsi/ obj-$(CONFIG_FUSION) += message/ obj-$(CONFIG_IEEE1394) += ieee1394/ -obj-y += cdrom/ video/ +obj-y += cdrom/ obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_DIO) += dio/ @@ -39,7 +47,6 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ -obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_W1) += w1/ @@ -50,4 +57,5 @@ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_MMC) += mmc/ obj-y += firmware/ diff -Nru a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig --- a/drivers/acpi/Kconfig 2004-10-18 14:57:04 -07:00 +++ b/drivers/acpi/Kconfig 2004-10-18 14:57:04 -07:00 @@ -204,6 +204,32 @@ If you have a legacy free Toshiba laptop (such as the Libretto L1 series), say Y. +config ACPI_CUSTOM_DSDT + bool "Include Custom DSDT" + depends on X86 && ACPI_INTERPRETER && !STANDALONE + default n + help + Thist option is to load a custom ACPI DSDT + If you don't know what that is, say N. + +config ACPI_CUSTOM_DSDT_FILE + string "Custom DSDT Table file to include" + depends on ACPI_CUSTOM_DSDT + default "" + help + Enter the full path name to the file wich includes the AmlCode declaration. + +config ACPI_BLACKLIST_YEAR + int "Disable ACPI for systems before Jan 1st this year" + default 0 + help + enter a 4-digit year, eg. 2001 to disable ACPI by default + on platforms with DMI BIOS date before January 1st that year. + "acpi=force" can be used to override this mechanism. + + Enter 0 to disable this mechanism and allow ACPI to + run by default no matter what the year. (default) + config ACPI_DEBUG bool "Debug Statements" depends on ACPI_INTERPRETER diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile --- a/drivers/acpi/Makefile 2004-10-18 14:57:04 -07:00 +++ b/drivers/acpi/Makefile 2004-10-18 14:57:04 -07:00 @@ -47,4 +47,4 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o -obj-$(CONFIG_ACPI_BUS) += scan.o +obj-$(CONFIG_ACPI_BUS) += scan.o motherboard.o diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c --- a/drivers/acpi/acpi_ksyms.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/acpi/acpi_ksyms.c 2004-10-18 14:57:19 -07:00 @@ -84,6 +84,8 @@ EXPORT_SYMBOL(acpi_enable_event); EXPORT_SYMBOL(acpi_disable_event); EXPORT_SYMBOL(acpi_clear_event); +EXPORT_SYMBOL(acpi_set_gpe_type); +EXPORT_SYMBOL(acpi_enable_gpe); EXPORT_SYMBOL(acpi_get_timer_duration); EXPORT_SYMBOL(acpi_get_timer); EXPORT_SYMBOL(acpi_get_sleep_type_data); diff -Nru a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c --- a/drivers/acpi/asus_acpi.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/acpi/asus_acpi.c 2004-10-18 14:56:28 -07:00 @@ -42,7 +42,7 @@ #include #include -#define ASUS_ACPI_VERSION "0.28" +#define ASUS_ACPI_VERSION "0.29" #define PROC_ASUS "asus" //the directory #define PROC_MLED "mled" @@ -123,14 +123,18 @@ L3C, //L3800C L3D, //L3400D L3H, //L3H, but also L2000E + L4R, //L4500R L5x, //L5800C L8L, //L8400L M1A, //M1300A M2E, //M2400E, L4400L + M6N, //M6800N + M6R, //M6700R P30, //Samsung P30 S1x, //S1300A, but also L1400B and M2400A (L84F) S2x, //S200 (J1 reported), Victor MP-XP7210 - xxN, //M2400N, M3700N, M6800N, S1300N, S5200N (Centrino) + xxN, //M2400N, M3700N, M5200N, S1300N, S5200N, W1OOON + //(Centrino) END_MODEL } model; //Models currently supported u16 event_count[128]; //count for each event TODO make this better @@ -247,6 +251,19 @@ }, { + .name = "L4R", + .mt_mled = "MLED", + .mt_wled = "WLED", + .wled_status = "\\_SB.PCI0.SBRG.SG13", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\_SB.PCI0.SBSM.SEO4", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\_SB.PCI0.P0P1.VGA.GETD" + }, + + { .name = "L5x", .mt_mled = "MLED", /* WLED present, but not controlled by ACPI */ @@ -289,6 +306,31 @@ }, { + .name = "M6N", + .mt_mled = "MLED", + .mt_wled = "WLED", + .wled_status = "\\_SB.PCI0.SBRG.SG13", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\_SB.BKLT", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\SSTE" + }, + { + .name = "M6R", + .mt_mled = "MLED", + .mt_wled = "WLED", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\_SB.PCI0.SBSM.SEO4", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\SSTE" + }, + + + { .name = "P30", .mt_wled = "WLED", .mt_lcd_switch = P30_PREFIX "_Q0E", @@ -344,6 +386,9 @@ */ static struct acpi_table_header *asus_info; +/* The actual device the driver binds to */ +static struct asus_hotk *hotk; + /* * The hotkey driver declaration */ @@ -408,7 +453,6 @@ { int len = 0; int temp; - struct asus_hotk *hotk = (struct asus_hotk *) data; char buf[16]; //enough for all info /* * We use the easy way, we don't care of off and count, so we don't set eof @@ -428,7 +472,7 @@ len += sprintf(page + len, "SFUN value : 0x%04x\n", temp); /* * Another value for userspace: the ASYM method returns 0x02 for - * battery low and 0x04 for battery critical, it's readings tend to be + * battery low and 0x04 for battery critical, its readings tend to be * more accurate than those provided by _BST. * Note: since not all the laptops provide this method, errors are * silently ignored. @@ -467,7 +511,7 @@ /* Generic LED functions */ static int -read_led(struct asus_hotk *hotk, const char *ledname, int ledmask) +read_led(const char *ledname, int ledmask) { if (ledname) { int led_status; @@ -498,7 +542,7 @@ /* FIXME: kill extraneous args so it can be called independently */ static int -write_led(const char __user *buffer, unsigned long count, struct asus_hotk *hotk, +write_led(const char __user *buffer, unsigned long count, char *ledname, int ledmask, int invert) { int value; @@ -528,8 +572,7 @@ proc_read_mled(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_led(hotk, hotk->methods->mled_status, MLED_ON)); + return sprintf(page, "%d\n", read_led(hotk->methods->mled_status, MLED_ON)); } @@ -537,8 +580,7 @@ proc_write_mled(struct file *file, const char __user *buffer, unsigned long count, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return write_led(buffer, count, hotk, hotk->methods->mt_mled, MLED_ON, 1); + return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1); } /* @@ -548,16 +590,14 @@ proc_read_wled(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_led(hotk, hotk->methods->wled_status, WLED_ON)); + return sprintf(page, "%d\n", read_led(hotk->methods->wled_status, WLED_ON)); } static int proc_write_wled(struct file *file, const char __user *buffer, unsigned long count, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return write_led(buffer, count, hotk, hotk->methods->mt_wled, WLED_ON, 0); + return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0); } /* @@ -567,21 +607,18 @@ proc_read_tled(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_led(hotk, hotk->methods->tled_status, TLED_ON)); + return sprintf(page, "%d\n", read_led(hotk->methods->tled_status, TLED_ON)); } static int proc_write_tled(struct file *file, const char __user *buffer, unsigned long count, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return write_led(buffer, count, hotk, hotk->methods->mt_tled, TLED_ON, 0); + return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0); } - -static int get_lcd_state(struct asus_hotk *hotk) +static int get_lcd_state(void) { int lcd = 0; @@ -622,13 +659,13 @@ return (lcd & 1); } -static int set_lcd_state(struct asus_hotk *hotk, int value) +static int set_lcd_state(int value) { int lcd = 0; acpi_status status = 0; lcd = value ? 1 : 0; - if (lcd != get_lcd_state(hotk)) { + if (lcd != get_lcd_state()) { /* switch */ if (hotk->model != L3H) { status = @@ -651,7 +688,7 @@ proc_read_lcd(char *page, char **start, off_t off, int count, int *eof, void *data) { - return sprintf(page, "%d\n", get_lcd_state((struct asus_hotk *) data)); + return sprintf(page, "%d\n", get_lcd_state()); } @@ -660,16 +697,15 @@ unsigned long count, void *data) { int value; - struct asus_hotk *hotk = (struct asus_hotk *) data; count = parse_arg(buffer, count, &value); if (count > 0) - set_lcd_state(hotk, value); + set_lcd_state(value); return count; } -static int read_brightness(struct asus_hotk *hotk) +static int read_brightness(void) { int value; @@ -689,7 +725,7 @@ /* * Change the brightness level */ -static void set_brightness(int value, struct asus_hotk *hotk) +static void set_brightness(int value) { acpi_status status = 0; @@ -702,7 +738,7 @@ } /* No SPLV method if we are here, act as appropriate */ - value -= read_brightness(hotk); + value -= read_brightness(); while (value != 0) { status = acpi_evaluate_object(NULL, (value > 0) ? hotk->methods->brightness_up : @@ -719,8 +755,7 @@ proc_read_brn(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_brightness(hotk)); + return sprintf(page, "%d\n", read_brightness()); } static int @@ -728,13 +763,12 @@ unsigned long count, void *data) { int value; - struct asus_hotk *hotk = (struct asus_hotk *) data; count = parse_arg(buffer, count, &value); if (count > 0) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ - set_brightness(value, hotk); + set_brightness(value); } else if (count < 0) { printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); } @@ -742,7 +776,7 @@ return count; } -static void set_display(int value, struct asus_hotk *hotk) +static void set_display(int value) { /* no sanity check needed for now */ if (!write_acpi_int(hotk->handle, hotk->methods->display_set, @@ -760,10 +794,10 @@ void *data) { int value = 0; - struct asus_hotk *hotk = (struct asus_hotk *) data; if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value)) printk(KERN_WARNING "Asus ACPI: Error reading display status\n"); + value &= 0x07; /* needed for some models, shouldn't hurt others */ return sprintf(page, "%d\n", value); } @@ -778,11 +812,10 @@ unsigned long count, void *data) { int value; - struct asus_hotk *hotk = (struct asus_hotk *) data; count = parse_arg(buffer, count, &value); if (count > 0) - set_display(value, hotk); + set_display(value); else if (count < 0) printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); @@ -817,7 +850,6 @@ static int __init asus_hotk_add_fs(struct acpi_device *device) { struct proc_dir_entry *proc; - struct asus_hotk *hotk = acpi_driver_data(device); mode_t mode; /* @@ -869,13 +901,12 @@ } if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || - (hotk->methods->brightness_get && hotk->methods->brightness_get)) { + (hotk->methods->brightness_get && hotk->methods->brightness_set)) { asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode, device); } if (hotk->methods->display_set) { asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp, mode, device); - } return 0; @@ -883,10 +914,7 @@ static int asus_hotk_remove_fs(struct acpi_device* device) { - struct asus_hotk* hotk = acpi_driver_data(device); - - - if(acpi_device_dir(device)){ + if(acpi_device_dir(device)) { remove_proc_entry(PROC_INFO,acpi_device_dir(device)); if (hotk->methods->mt_wled) remove_proc_entry(PROC_WLED,acpi_device_dir(device)); @@ -894,11 +922,12 @@ remove_proc_entry(PROC_MLED,acpi_device_dir(device)); if (hotk->methods->mt_tled) remove_proc_entry(PROC_TLED,acpi_device_dir(device)); - if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) + if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) remove_proc_entry(PROC_LCD, acpi_device_dir(device)); - if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || (hotk->methods->brightness_get && hotk->methods->brightness_get)) + if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || + (hotk->methods->brightness_get && hotk->methods->brightness_set)) remove_proc_entry(PROC_BRN, acpi_device_dir(device)); - if (hotk->methods->display_set) + if (hotk->methods->display_set) remove_proc_entry(PROC_DISP, acpi_device_dir(device)); } return 0; @@ -907,11 +936,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) { - /* TODO Find a better way to handle events count. Here, in data, we receive - * the hotk, so we can do anything! - */ - struct asus_hotk *hotk = (struct asus_hotk *) data; - + /* TODO Find a better way to handle events count.*/ if (!hotk) return; @@ -931,7 +956,7 @@ * This function is used to initialize the hotk with right values. In this * method, we can make all the detection we want, and modify the hotk struct */ -static int __init asus_hotk_get_info(struct asus_hotk *hotk) +static int __init asus_hotk_get_info(void) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -998,11 +1023,19 @@ hotk->model = L3C; else if (strncmp(model->string.pointer, "L8L", 3) == 0) hotk->model = L8L; + else if (strncmp(model->string.pointer, "L4R", 3) == 0) + hotk->model = L4R; + else if (strncmp(model->string.pointer, "M6N", 3) == 0) + hotk->model = M6N; + else if (strncmp(model->string.pointer, "M6R", 3) == 0) + hotk->model = M6R; else if (strncmp(model->string.pointer, "M2N", 3) == 0 || strncmp(model->string.pointer, "M3N", 3) == 0 || + strncmp(model->string.pointer, "M5N", 3) == 0 || strncmp(model->string.pointer, "M6N", 3) == 0 || strncmp(model->string.pointer, "S1N", 3) == 0 || - strncmp(model->string.pointer, "S5N", 3) == 0) + strncmp(model->string.pointer, "S5N", 3) == 0 || + strncmp(model->string.pointer, "W1N", 3) == 0) hotk->model = xxN; else if (strncmp(model->string.pointer, "M1", 2) == 0) hotk->model = M1A; @@ -1025,7 +1058,6 @@ hotk->model = L5x; if (hotk->model == END_MODEL) { - /* By default use the same values, as I don't know others */ printk("unsupported, trying default values, supply the " "developers with your DSDT\n"); hotk->model = M2E; @@ -1040,16 +1072,14 @@ hotk->methods->lcd_status = NULL; /* L2B is similar enough to L3C to use its settings, with this only exception */ - else if (strncmp(model->string.pointer, "S5N", 3) == 0) + else if (strncmp(model->string.pointer, "S5N", 3) == 0 || + strncmp(model->string.pointer, "M5N", 3) == 0) hotk->methods->mt_mled = NULL; - /* S5N has no MLED */ - else if (strncmp(model->string.pointer, "M6N", 3) == 0) { - hotk->methods->display_get = NULL; //TODO - hotk->methods->lcd_status = "\\_SB.BKLT"; - hotk->methods->mt_wled = "WLED"; - hotk->methods->wled_status = "\\_SB.PCI0.SBRG.SG13"; - /* M6N differs slightly and has a usable WLED */ - } + /* S5N and M5N have no MLED */ + else if (strncmp(model->string.pointer, "M2N", 3) == 0 || + strncmp(model->string.pointer, "W1N", 3) == 0) + hotk->methods->mt_wled = "WLED"; + /* M2N and W1N have a usable WLED */ else if (asus_info) { if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) hotk->methods->mled_status = NULL; @@ -1062,20 +1092,16 @@ } - -static int __init asus_hotk_check(struct asus_hotk *hotk) +static int __init asus_hotk_check(void) { int result = 0; - if (!hotk) - return(-EINVAL); - result = acpi_bus_get_status(hotk->device); if (result) return(result); if (hotk->device->status.present) { - result = asus_hotk_get_info(hotk); + result = asus_hotk_get_info(); } else { printk(KERN_ERR " Hotkey device not present, aborting\n"); return(-EINVAL); @@ -1085,10 +1111,8 @@ } - static int __init asus_hotk_add(struct acpi_device *device) { - struct asus_hotk *hotk = NULL; acpi_status status = AE_OK; int result; @@ -1111,7 +1135,7 @@ hotk->device = device; - result = asus_hotk_check(hotk); + result = asus_hotk_check(); if (result) goto end; @@ -1152,16 +1176,14 @@ return(result); } + static int asus_hotk_remove(struct acpi_device *device, int type) { acpi_status status = 0; - struct asus_hotk *hotk = NULL; if (!device || !acpi_driver_data(device)) return(-EINVAL); - hotk = (struct asus_hotk *) acpi_driver_data(device); - status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, asus_hotk_notify); if (ACPI_FAILURE(status)) @@ -1179,20 +1201,24 @@ { int result; + if (acpi_disabled) + return -ENODEV; + asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); - return(-ENODEV); + return -ENODEV; } asus_proc_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&asus_hotk_driver); - if (result < 0) { + if (result < 1) { + acpi_bus_unregister_driver(&asus_hotk_driver); remove_proc_entry(PROC_ASUS, acpi_root_dir); - return(-ENODEV); + return -ENODEV; } - return(0); + return 0; } diff -Nru a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c --- a/drivers/acpi/blacklist.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/blacklist.c 2004-10-18 14:55:54 -07:00 @@ -2,7 +2,9 @@ * blacklist.c * * Check to see if the given machine has a known bad ACPI BIOS + * or if the BIOS is too old. * + * Copyright (C) 2004 Len Brown * Copyright (C) 2002 Andy Grover * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -30,6 +32,7 @@ #include #include #include +#include enum acpi_blacklist_predicates { @@ -56,20 +59,6 @@ */ static struct acpi_blacklist_item acpi_blacklist[] __initdata = { - /* Portege 7020, BIOS 8.10 */ - {"TOSHIB", "7020CT ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0}, - /* Portege 4030 */ - {"TOSHIB", "4030 ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0}, - /* Portege 310/320, BIOS 7.1 */ - {"TOSHIB", "310 ", 0x19990511, ACPI_DSDT, all_versions, "Implicit Return", 0}, - /* Seattle 2, old bios rev. */ - {"INTEL ", "440BX ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* ASUS K7M */ - {"ASUS ", "K7M ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* Intel 810 Motherboard? */ - {"MNTRAL", "MO81010A", 0x00000012, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* Compaq Presario 711FR */ - {"COMAPQ", "EAGLES", 0x06040000, ACPI_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0}, /* Compaq Presario 1700 */ {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal, "Multiple problems", 1}, /* Sony FX120, FX140, FX150? */ @@ -84,6 +73,45 @@ }; +#if CONFIG_ACPI_BLACKLIST_YEAR + +static int __init +blacklist_by_year(void) +{ + int year; + char *s = dmi_get_system_info(DMI_BIOS_DATE); + + if (!s) + return 0; + if (!*s) + return 0; + + s = strrchr(s, '/'); + if (!s) + return 0; + + s += 1; + + year = simple_strtoul(s,NULL,0); + + if (year < 100) { /* 2-digit year */ + year += 1900; + if (year < 1996) /* no dates < spec 1.0 */ + year += 100; + } + + if (year < CONFIG_ACPI_BLACKLIST_YEAR) { + printk(KERN_ERR PREFIX "BIOS age (%d) fails cutoff (%d), " + "acpi=force is required to enable ACPI\n", + year, CONFIG_ACPI_BLACKLIST_YEAR); + return 1; + } + return 0; +} +#else +static inline int blacklist_by_year(void) { return 0; } +#endif + int __init acpi_blacklisted(void) { @@ -133,6 +161,8 @@ i++; } } + + blacklisted += blacklist_by_year(); return blacklisted; } diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c --- a/drivers/acpi/bus.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/acpi/bus.c 2004-10-18 14:56:33 -07:00 @@ -590,14 +590,20 @@ } -static int __init -acpi_bus_init (void) +void __init +acpi_early_init (void) { - int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = {sizeof(acpi_fadt), &acpi_fadt}; - ACPI_FUNCTION_TRACE("acpi_bus_init"); + ACPI_FUNCTION_TRACE("acpi_early_init"); + + if (acpi_disabled) + return; + + /* enable workarounds, unless strict ACPI spec. compliance */ + if (!acpi_strict) + acpi_gbl_enable_interpreter_slack = TRUE; status = acpi_initialize_subsystem(); if (ACPI_FAILURE(status)) { @@ -617,7 +623,7 @@ status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to get the FADT\n"); - goto error1; + goto error0; } #ifdef CONFIG_X86 @@ -640,12 +646,40 @@ } #endif - status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION); + status = acpi_enable_subsystem(~(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE)); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to enable ACPI\n"); + goto error0; + } + + return; + +error0: + disable_acpi(); + return; +} + +static int __init +acpi_bus_init (void) +{ + int result = 0; + acpi_status status = AE_OK; + extern acpi_status acpi_os_initialize1(void); + + ACPI_FUNCTION_TRACE("acpi_bus_init"); + + status = acpi_os_initialize1(); + + status = acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); goto error1; } + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to initialize ACPI OS objects\n"); + goto error1; + } #ifdef CONFIG_ACPI_EC /* * ACPI 2.0 requires the EC driver to be loaded and work before @@ -693,7 +727,6 @@ /* Mimic structured exception handling */ error1: acpi_terminate(); -error0: return_VALUE(-ENODEV); } @@ -707,9 +740,6 @@ printk(KERN_INFO PREFIX "Subsystem revision %08x\n", ACPI_CA_VERSION); - - /* Initial core debug level excludes drivers, so include them now */ - acpi_set_debug(ACPI_DEBUG_LOW); if (acpi_disabled) { printk(KERN_INFO PREFIX "Interpreter disabled.\n"); diff -Nru a/drivers/acpi/button.c b/drivers/acpi/button.c --- a/drivers/acpi/button.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/button.c 2004-10-18 14:55:54 -07:00 @@ -456,6 +456,15 @@ goto end; } + if (device->wakeup.flags.valid) { + /* Button's GPE is run-wake GPE */ + acpi_set_gpe_type(device->wakeup.gpe_device, + device->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN); + acpi_enable_gpe(device->wakeup.gpe_device, + device->wakeup.gpe_number, ACPI_NOT_ISR); + device->wakeup.state.enabled = 1; + } + printk(KERN_INFO PREFIX "%s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); diff -Nru a/drivers/acpi/debug.c b/drivers/acpi/debug.c --- a/drivers/acpi/debug.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/acpi/debug.c 2004-10-18 14:56:48 -07:00 @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -13,6 +14,81 @@ #define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" #define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif + +#define MODULE_PARAM_PREFIX +module_param(acpi_dbg_layer, uint, 0400); +module_param(acpi_dbg_level, uint, 0400); + +struct acpi_dlayer { + const char *name; + unsigned long value; +}; +struct acpi_dlevel { + const char *name; + unsigned long value; +}; +#define ACPI_DEBUG_INIT(v) { .name = #v, .value = v } + +const struct acpi_dlayer acpi_debug_layers[] = +{ + ACPI_DEBUG_INIT(ACPI_UTILITIES), + ACPI_DEBUG_INIT(ACPI_HARDWARE), + ACPI_DEBUG_INIT(ACPI_EVENTS), + ACPI_DEBUG_INIT(ACPI_TABLES), + ACPI_DEBUG_INIT(ACPI_NAMESPACE), + ACPI_DEBUG_INIT(ACPI_PARSER), + ACPI_DEBUG_INIT(ACPI_DISPATCHER), + ACPI_DEBUG_INIT(ACPI_EXECUTER), + ACPI_DEBUG_INIT(ACPI_RESOURCES), + ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER), + ACPI_DEBUG_INIT(ACPI_OS_SERVICES), + ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER), + ACPI_DEBUG_INIT(ACPI_COMPILER), + ACPI_DEBUG_INIT(ACPI_TOOLS), +}; + +const struct acpi_dlevel acpi_debug_levels[] = +{ + ACPI_DEBUG_INIT(ACPI_LV_ERROR), + ACPI_DEBUG_INIT(ACPI_LV_WARN), + ACPI_DEBUG_INIT(ACPI_LV_INIT), + ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), + ACPI_DEBUG_INIT(ACPI_LV_INFO), + + ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), + ACPI_DEBUG_INIT(ACPI_LV_PARSE), + ACPI_DEBUG_INIT(ACPI_LV_LOAD), + ACPI_DEBUG_INIT(ACPI_LV_DISPATCH), + ACPI_DEBUG_INIT(ACPI_LV_EXEC), + ACPI_DEBUG_INIT(ACPI_LV_NAMES), + ACPI_DEBUG_INIT(ACPI_LV_OPREGION), + ACPI_DEBUG_INIT(ACPI_LV_BFIELD), + ACPI_DEBUG_INIT(ACPI_LV_TABLES), + ACPI_DEBUG_INIT(ACPI_LV_VALUES), + ACPI_DEBUG_INIT(ACPI_LV_OBJECTS), + ACPI_DEBUG_INIT(ACPI_LV_RESOURCES), + ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS), + ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), + + ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS), + ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS), + ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), + + ACPI_DEBUG_INIT(ACPI_LV_MUTEX), + ACPI_DEBUG_INIT(ACPI_LV_THREADS), + ACPI_DEBUG_INIT(ACPI_LV_IO), + ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), + + ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE), + ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO), + ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES), + ACPI_DEBUG_INIT(ACPI_LV_EVENTS), +}; +#define NUM_OF(v) ( sizeof(v)/sizeof(v[0]) ) + static int acpi_system_read_debug ( char *page, @@ -24,16 +100,41 @@ { char *p = page; int size = 0; + int i; if (off != 0) goto end; + p += sprintf(p, "%-25s\tHex SET\n", "Description"); + switch ((unsigned long) data) { case 0: - p += sprintf(p, "0x%08x\n", acpi_dbg_layer); + for (i = 0; i < NUM_OF(acpi_debug_layers); i++) { + p += sprintf(p, "%-25s\t0x%08lX [%c]\n", + acpi_debug_layers[i].name, + acpi_debug_layers[i].value, + (acpi_dbg_layer & acpi_debug_layers[i].value) ? + '*' : ' '); + } + p += sprintf(p, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", + ACPI_ALL_DRIVERS, + (acpi_dbg_layer & ACPI_ALL_DRIVERS) == ACPI_ALL_DRIVERS? + '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 0 ? + ' ' : '-'); + p += sprintf(p, + "--\ndebug_layer = 0x%08X (* = enabled, - = partial)\n", + acpi_dbg_layer); break; case 1: - p += sprintf(p, "0x%08x\n", acpi_dbg_level); + for (i = 0; i < NUM_OF(acpi_debug_levels); i++) { + p += sprintf(p, "%-25s\t0x%08lX [%c]\n", + acpi_debug_levels[i].name, + acpi_debug_levels[i].value, + (acpi_dbg_level & acpi_debug_levels[i].value) ? + '*' : ' '); + } + p += sprintf(p, "--\ndebug_level = 0x%08X (* = enabled)\n", + acpi_dbg_level); break; default: p += sprintf(p, "Invalid debug option\n"); diff -Nru a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c --- a/drivers/acpi/dispatcher/dsmethod.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/acpi/dispatcher/dsmethod.c 2004-10-18 14:56:31 -07:00 @@ -58,15 +58,12 @@ * * FUNCTION: acpi_ds_parse_method * - * PARAMETERS: obj_handle - Node of the method - * Level - Current nesting level - * Context - Points to a method counter - * return_value - Not used + * PARAMETERS: obj_handle - Method node * * RETURN: Status * - * DESCRIPTION: Call the parser and parse the AML that is - * associated with the method. + * DESCRIPTION: Call the parser and parse the AML that is associated with the + * method. * * MUTEX: Assumes parser is locked * @@ -145,8 +142,9 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, op, node, obj_desc->method.aml_start, - obj_desc->method.aml_length, NULL, NULL, 1); + status = acpi_ds_init_aml_walk (walk_state, op, node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); @@ -190,8 +188,6 @@ * increments the thread count, and waits at the method semaphore * for clearance to execute. * - * MUTEX: Locks/unlocks parser. - * ******************************************************************************/ acpi_status @@ -250,7 +246,8 @@ * * FUNCTION: acpi_ds_call_control_method * - * PARAMETERS: walk_state - Current state of the walk + * PARAMETERS: Thread - Info for this thread + * this_walk_state - Current walk state * Op - Current Op to be walked * * RETURN: Status @@ -267,8 +264,9 @@ { acpi_status status; struct acpi_namespace_node *method_node; - union acpi_operand_object *obj_desc; struct acpi_walk_state *next_walk_state; + union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; u32 i; @@ -309,7 +307,6 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - /* Create and init a Root Node */ op = acpi_ps_create_scope_op (); @@ -320,7 +317,7 @@ status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, - NULL, NULL, 1); + NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (next_walk_state); goto cleanup; @@ -348,9 +345,12 @@ */ this_walk_state->operands [this_walk_state->num_operands] = NULL; + info.parameters = &this_walk_state->operands[0]; + info.parameter_type = ACPI_PARAM_ARGS; + status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, - &this_walk_state->operands[0], NULL, 3); + &info, 3); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -382,7 +382,7 @@ /* On error, we must delete the new walk state */ cleanup: - if (next_walk_state->method_desc) { + if (next_walk_state && (next_walk_state->method_desc)) { /* Decrement the thread count on the method parse tree */ next_walk_state->method_desc->method.thread_count--; @@ -397,12 +397,13 @@ * * FUNCTION: acpi_ds_restart_control_method * - * PARAMETERS: walk_state - State of the method when it was preempted - * Op - Pointer to new current op + * PARAMETERS: walk_state - State for preempted method (caller) + * return_desc - Return value from the called method * * RETURN: Status * - * DESCRIPTION: Restart a method that was preempted + * DESCRIPTION: Restart a method that was preempted by another (nested) method + * invocation. Handle the return value (if any) from the callee. * ******************************************************************************/ @@ -417,17 +418,35 @@ ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "****Restart [%4.4s] Op %p return_value_from_callee %p\n", + (char *) &walk_state->method_node->name, walk_state->method_call_op, + return_desc)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + " return_from_this_method_used?=%X res_stack %p Walk %p\n", + walk_state->return_used, + walk_state->results, walk_state)); + + /* Did the called method return a value? */ + if (return_desc) { + /* Are we actually going to use the return value? */ + if (walk_state->return_used) { - /* - * Get the return value (if any) from the previous method. - * NULL if no return value - */ + /* Save the return value from the previous method */ + status = acpi_ds_result_push (return_desc, walk_state); if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (return_desc); return_ACPI_STATUS (status); } + + /* + * Save as THIS method's return value in case it is returned + * immediately to yet another method + */ + walk_state->return_desc = return_desc; } else { /* @@ -437,11 +456,6 @@ acpi_ut_remove_reference (return_desc); } } - - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "Method=%p Return=%p return_used?=%X res_stack=%p State=%p\n", - walk_state->method_call_op, return_desc, walk_state->return_used, - walk_state->results, walk_state)); return_ACPI_STATUS (AE_OK); } diff -Nru a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c --- a/drivers/acpi/dispatcher/dsmthdat.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/acpi/dispatcher/dsmthdat.c 2004-10-18 14:56:28 -07:00 @@ -656,11 +656,13 @@ new_obj_desc, current_obj_desc)); /* - * Store this object to the Node - * (perform the indirect store) + * Store this object to the Node (perform the indirect store) + * NOTE: No implicit conversion is performed, as per the ACPI + * specification rules on storing to Locals/Args. */ status = acpi_ex_store_object_to_node (new_obj_desc, - current_obj_desc->reference.object, walk_state); + current_obj_desc->reference.object, walk_state, + ACPI_NO_IMPLICIT_CONVERSION); /* Remove local reference if we copied the object above */ diff -Nru a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c --- a/drivers/acpi/dispatcher/dsopcode.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/dispatcher/dsopcode.c 2004-10-18 14:56:49 -07:00 @@ -79,7 +79,6 @@ acpi_status status; union acpi_parse_object *op; struct acpi_walk_state *walk_state; - union acpi_parse_object *arg; ACPI_FUNCTION_TRACE ("ds_execute_arguments"); @@ -105,7 +104,7 @@ } status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, - aml_length, NULL, NULL, 1); + aml_length, NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); @@ -126,9 +125,7 @@ /* Get and init the Op created above */ - arg = op->common.value.arg; op->common.node = node; - arg->common.node = node; acpi_ps_delete_parse_tree (op); /* Evaluate the deferred arguments */ @@ -150,7 +147,7 @@ /* Execute the opcode and arguments */ status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, - aml_length, NULL, NULL, 3); + aml_length, NULL, 3); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); diff -Nru a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c --- a/drivers/acpi/dispatcher/dsutils.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/acpi/dispatcher/dsutils.c 2004-10-18 14:56:29 -07:00 @@ -60,11 +60,10 @@ * * FUNCTION: acpi_ds_is_result_used * - * PARAMETERS: Op - * result_obj - * walk_state + * PARAMETERS: Op - Current Op + * walk_state - Current State * - * RETURN: Status + * RETURN: TRUE if result is used, FALSE otherwise * * DESCRIPTION: Check if a result object will be used by the parent * @@ -89,18 +88,39 @@ } /* - * If there is no parent, the result can't possibly be used! - * (An executing method typically has no parent, since each - * method is parsed separately) However, a method that is - * invoked from another method has a parent. + * If there is no parent, we are executing at the method level. + * An executing method typically has no parent, since each method + * is parsed separately. */ if (!op->common.parent) { + /* + * If this is the last statement in the method, we know it is not a + * Return() operator (would not come here.) The following code is the + * optional support for a so-called "implicit return". Some AML code + * assumes that the last value of the method is "implicitly" returned + * to the caller. Just save the last result as the return value. + * NOTE: this is optional because the ASL language does not actually + * support this behavior. + */ + if ((acpi_gbl_enable_interpreter_slack) && + (walk_state->parser_state.aml >= walk_state->parser_state.aml_end)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] will be implicitly returned\n", + acpi_ps_get_opcode_name (op->common.aml_opcode))); + + /* Use the top of the result stack as the implicit return value */ + + walk_state->return_desc = walk_state->results->results.obj_desc[0]; + return_VALUE (TRUE); + } + + /* No parent, the return value cannot possibly be used */ + return_VALUE (FALSE); } - /* - * Get info on the parent. The root Op is AML_SCOPE - */ + /* Get info on the parent. The root_op is AML_SCOPE */ + parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); if (parent_info->class == AML_CLASS_UNKNOWN) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op)); @@ -204,9 +224,9 @@ * * FUNCTION: acpi_ds_delete_result_if_not_used * - * PARAMETERS: Op - * result_obj - * walk_state + * PARAMETERS: Op - Current parse Op + * result_obj - Result of the operation + * walk_state - Current state * * RETURN: Status * @@ -338,8 +358,9 @@ * * FUNCTION: acpi_ds_create_operand * - * PARAMETERS: walk_state - * Arg + * PARAMETERS: walk_state - Current walk state + * Arg - Parse object for the argument + * arg_index - Which argument (zero based) * * RETURN: Status * diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c --- a/drivers/acpi/dispatcher/dswload.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/dispatcher/dswload.c 2004-10-18 14:55:54 -07:00 @@ -50,6 +50,9 @@ #include #include +#ifdef _ACPI_ASL_COMPILER +#include +#endif #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dswload") @@ -180,7 +183,17 @@ status = acpi_ns_lookup (walk_state->scope_info, path, object_type, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); if (ACPI_FAILURE (status)) { +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + acpi_dm_add_to_external_list (path); + status = AE_OK; + } + else { + ACPI_REPORT_NSERROR (path, status); + } +#else ACPI_REPORT_NSERROR (path, status); +#endif return (status); } @@ -529,7 +542,16 @@ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); if (ACPI_FAILURE (status)) { +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + status = AE_OK; + } + else { + ACPI_REPORT_NSERROR (buffer_ptr, status); + } +#else ACPI_REPORT_NSERROR (buffer_ptr, status); +#endif return_ACPI_STATUS (status); } /* diff -Nru a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c --- a/drivers/acpi/dispatcher/dswstate.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/acpi/dispatcher/dswstate.c 2004-10-18 14:56:50 -07:00 @@ -906,8 +906,7 @@ struct acpi_namespace_node *method_node, u8 *aml_start, u32 aml_length, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc, + struct acpi_parameter_info *info, u32 pass_number) { acpi_status status; @@ -926,8 +925,17 @@ /* The next_op of the next_walk will be the beginning of the method */ walk_state->next_op = NULL; - walk_state->params = params; - walk_state->caller_return_desc = return_obj_desc; + + if (info) { + if (info->parameter_type == ACPI_PARAM_GPE) { + walk_state->gpe_event_info = ACPI_CAST_PTR (struct acpi_gpe_event_info, + info->parameters); + } + else { + walk_state->params = info->parameters; + walk_state->caller_return_desc = &info->return_object; + } + } status = acpi_ps_init_scope (&walk_state->parser_state, op); if (ACPI_FAILURE (status)) { @@ -949,7 +957,7 @@ /* Init the method arguments */ - status = acpi_ds_method_data_init_args (params, ACPI_METHOD_NUM_ARGS, walk_state); + status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c --- a/drivers/acpi/ec.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/acpi/ec.c 2004-10-18 14:56:32 -07:00 @@ -381,7 +381,7 @@ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } -static void +static u32 acpi_ec_gpe_handler ( void *data) { @@ -389,12 +389,17 @@ struct acpi_ec *ec = (struct acpi_ec *) data; if (!ec) - return; + return ACPI_INTERRUPT_NOT_HANDLED; acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_ec_gpe_query, ec); + + if (status == AE_OK) + return ACPI_INTERRUPT_HANDLED; + else + return ACPI_INTERRUPT_NOT_HANDLED; } /* -------------------------------------------------------------------------- @@ -729,6 +734,8 @@ if (ACPI_FAILURE(status)) { return_VALUE(-ENODEV); } + acpi_set_gpe_type (NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe (NULL, ec->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler (ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -814,6 +821,8 @@ if (ACPI_FAILURE(status)) { goto error; } + acpi_set_gpe_type (NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe (NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler (ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, diff -Nru a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c --- a/drivers/acpi/events/evevent.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/acpi/events/evevent.c 2004-10-18 14:56:50 -07:00 @@ -50,7 +50,7 @@ /******************************************************************************* * - * FUNCTION: acpi_ev_initialize + * FUNCTION: acpi_ev_initialize_events * * PARAMETERS: None * @@ -61,13 +61,13 @@ ******************************************************************************/ acpi_status -acpi_ev_initialize ( +acpi_ev_initialize_events ( void) { acpi_status status; - ACPI_FUNCTION_TRACE ("ev_initialize"); + ACPI_FUNCTION_TRACE ("ev_initialize_events"); /* Make sure we have ACPI tables */ @@ -104,7 +104,7 @@ /******************************************************************************* * - * FUNCTION: acpi_ev_handler_initialize + * FUNCTION: acpi_ev_install_xrupt_handlers * * PARAMETERS: None * @@ -115,13 +115,13 @@ ******************************************************************************/ acpi_status -acpi_ev_handler_initialize ( +acpi_ev_install_xrupt_handlers ( void) { acpi_status status; - ACPI_FUNCTION_TRACE ("ev_handler_initialize"); + ACPI_FUNCTION_TRACE ("ev_install_xrupt_handlers"); /* Install the SCI handler */ diff -Nru a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c --- a/drivers/acpi/events/evgpe.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/acpi/events/evgpe.c 2004-10-18 14:56:33 -07:00 @@ -51,6 +51,253 @@ /******************************************************************************* * + * FUNCTION: acpi_ev_set_gpe_type + * + * PARAMETERS: gpe_event_info - GPE to set + * Type - New type + * + * RETURN: Status + * + * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run) + * + ******************************************************************************/ + +acpi_status +acpi_ev_set_gpe_type ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_set_gpe_type"); + + + /* Validate type and update register enable masks */ + + switch (type) { + case ACPI_GPE_TYPE_WAKE: + case ACPI_GPE_TYPE_RUNTIME: + case ACPI_GPE_TYPE_WAKE_RUN: + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Disable the GPE if currently enabled */ + + status = acpi_ev_disable_gpe (gpe_event_info); + + /* Type was validated above */ + + gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK; /* Clear type bits */ + gpe_event_info->flags |= type; /* Insert type */ + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_update_gpe_enable_masks + * + * PARAMETERS: gpe_event_info - GPE to update + * Type - What to do: ACPI_GPE_DISABLE or + * ACPI_GPE_ENABLE + * + * RETURN: Status + * + * DESCRIPTION: Updates GPE register enable masks based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_update_gpe_enable_masks ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type) +{ + struct acpi_gpe_register_info *gpe_register_info; + u8 register_bit; + + + ACPI_FUNCTION_TRACE ("ev_update_gpe_enable_masks"); + + + gpe_register_info = gpe_event_info->register_info; + if (!gpe_register_info) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + register_bit = gpe_event_info->register_bit; + + /* 1) Disable case. Simply clear all enable bits */ + + if (type == ACPI_GPE_DISABLE) { + ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit); + return_ACPI_STATUS (AE_OK); + } + + /* 2) Enable case. Set/Clear the appropriate enable bits */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + case ACPI_GPE_TYPE_RUNTIME: + ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_enable_gpe + * + * PARAMETERS: gpe_event_info - GPE to enable + * write_to_hardware - Enable now, or just mark data structs + * (WAKE GPEs should be deferred) + * + * RETURN: Status + * + * DESCRIPTION: Enable a GPE based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_enable_gpe ( + struct acpi_gpe_event_info *gpe_event_info, + u8 write_to_hardware) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_enable_gpe"); + + + /* Make sure HW enable masks are updated */ + + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_ENABLE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Mark wake-enabled or HW enable, or both */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + + /*lint -fallthrough */ + + case ACPI_GPE_TYPE_RUNTIME: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); + + if (write_to_hardware) { + /* Clear the GPE (of stale events), then enable it */ + + status = acpi_hw_clear_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Enable the requested runtime GPE */ + + status = acpi_hw_write_gpe_enable_reg (gpe_event_info); + } + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_disable_gpe + * + * PARAMETERS: gpe_event_info - GPE to disable + * + * RETURN: Status + * + * DESCRIPTION: Disable a GPE based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_disable_gpe ( + struct acpi_gpe_event_info *gpe_event_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_disable_gpe"); + + + if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) { + return_ACPI_STATUS (AE_OK); + } + + /* Make sure HW enable masks are updated */ + + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Mark wake-disabled or HW disable, or both */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + + /*lint -fallthrough */ + + case ACPI_GPE_TYPE_RUNTIME: + + /* Disable the requested runtime GPE */ + + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); + status = acpi_hw_write_gpe_enable_reg (gpe_event_info); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ev_get_gpe_event_info * * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 @@ -139,11 +386,12 @@ u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; struct acpi_gpe_register_info *gpe_register_info; - u32 in_value; + u32 status_reg; + u32 enable_reg; acpi_status status; struct acpi_gpe_block_info *gpe_block; - u32 i; - u32 j; + acpi_native_uint i; + acpi_native_uint j; ACPI_FUNCTION_NAME ("ev_gpe_detect"); @@ -171,33 +419,32 @@ /* Read the Status Register */ - status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &status_reg, &gpe_register_info->status_address); - gpe_register_info->status = (u8) in_value; if (ACPI_FAILURE (status)) { goto unlock_and_exit; } /* Read the Enable Register */ - status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &enable_reg, &gpe_register_info->enable_address); - gpe_register_info->enable = (u8) in_value; if (ACPI_FAILURE (status)) { goto unlock_and_exit; } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n", - ACPI_FORMAT_UINT64 (gpe_register_info->status_address.address), - gpe_register_info->status, - ACPI_FORMAT_UINT64 (gpe_register_info->enable_address.address), - gpe_register_info->enable)); + ACPI_FORMAT_UINT64 ( + gpe_register_info->status_address.address), + status_reg, + ACPI_FORMAT_UINT64 ( + gpe_register_info->enable_address.address), + enable_reg)); /* First check if there is anything active at all in this register */ - enabled_status_byte = (u8) (gpe_register_info->status & - gpe_register_info->enable); + enabled_status_byte = (u8) (status_reg & enable_reg); if (!enabled_status_byte) { /* No active GPEs in this register, move on */ @@ -216,7 +463,7 @@ */ int_status |= acpi_ev_gpe_dispatch ( &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], - j + gpe_register_info->base_gpe_number); + (u32) j + gpe_register_info->base_gpe_number); } } } @@ -255,6 +502,7 @@ u32 gpe_number = 0; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; + struct acpi_parameter_info info; ACPI_FUNCTION_TRACE ("ev_asynch_execute_gpe_method"); @@ -272,6 +520,10 @@ return_VOID; } + /* Set the GPE flags for return to enabled state */ + + (void) acpi_ev_enable_gpe (gpe_event_info, FALSE); + /* * Take a snapshot of the GPE info for this level - we copy the * info to prevent a race condition with remove_handler/remove_block. @@ -283,23 +535,33 @@ return_VOID; } - if (local_gpe_event_info.method_node) { + /* + * Must check for control method type dispatch one more + * time to avoid race with ev_gpe_install_handler + */ + if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { /* - * Invoke the GPE Method (_Lxx, _Exx): - * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) + * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx + * control method that corresponds to this GPE */ - status = acpi_ns_evaluate_by_handle (local_gpe_event_info.method_node, NULL, NULL); + info.node = local_gpe_event_info.dispatch.method_node; + info.parameters = ACPI_CAST_PTR (union acpi_operand_object *, gpe_event_info); + info.parameter_type = ACPI_PARAM_GPE; + + status = acpi_ns_evaluate_by_handle (&info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n", + ACPI_REPORT_ERROR (( + "%s while evaluating method [%4.4s] for GPE[%2X]\n", acpi_format_exception (status), - acpi_ut_get_node_name (local_gpe_event_info.method_node), gpe_number)); + acpi_ut_get_node_name (local_gpe_event_info.dispatch.method_node), + gpe_number)); } } if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* - * GPE is level-triggered, we clear the GPE status bit after handling - * the event. + * GPE is level-triggered, we clear the GPE status bit after + * handling the event. */ status = acpi_hw_clear_gpe (&local_gpe_event_info); if (ACPI_FAILURE (status)) { @@ -309,7 +571,7 @@ /* Enable this GPE */ - (void) acpi_hw_enable_gpe (&local_gpe_event_info); + (void) acpi_hw_write_gpe_enable_reg (&local_gpe_event_info); return_VOID; } @@ -354,6 +616,15 @@ } } + /* Save current system state */ + + if (acpi_gbl_system_awake_and_running) { + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + } + else { + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + } + /* * Dispatch the GPE to either an installed handler, or the control * method associated with this GPE (_Lxx or _Exx). @@ -361,10 +632,15 @@ * If there is neither a handler nor a method, we disable the level to * prevent further events from coming in here. */ - if (gpe_event_info->handler) { - /* Invoke the installed handler (at interrupt level) */ + switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + case ACPI_GPE_DISPATCH_HANDLER: - gpe_event_info->handler (gpe_event_info->context); + /* + * Invoke the installed handler (at interrupt level) + * Ignore return status for now. TBD: leave GPE disabled on error? + */ + (void) gpe_event_info->dispatch.handler->address ( + gpe_event_info->dispatch.handler->context); /* It is now safe to clear level-triggered events. */ @@ -377,13 +653,15 @@ return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } } - } - else if (gpe_event_info->method_node) { + break; + + case ACPI_GPE_DISPATCH_METHOD: + /* * Disable GPE, so it doesn't keep firing before the method has a * chance to run. */ - status = acpi_hw_disable_gpe (gpe_event_info); + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", @@ -402,8 +680,10 @@ "acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%2X], event is disabled\n", gpe_number)); } - } - else { + break; + + default: + /* No handler or method to run! */ ACPI_REPORT_ERROR (( @@ -414,15 +694,68 @@ * Disable the GPE. The GPE will remain disabled until the ACPI * Core Subsystem is restarted, or a handler is installed. */ - status = acpi_hw_disable_gpe (gpe_event_info); + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } + break; } return_VALUE (ACPI_INTERRUPT_HANDLED); } + + +#ifdef ACPI_GPE_NOTIFY_CHECK + +/******************************************************************************* + * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED + * + * FUNCTION: acpi_ev_check_for_wake_only_gpe + * + * PARAMETERS: gpe_event_info - info for this GPE + * + * RETURN: Status + * + * DESCRIPTION: Determine if a a GPE is "wake-only". + * + * Called from Notify() code in interpreter when a "device_wake" + * Notify comes in. + * + ******************************************************************************/ + +acpi_status +acpi_ev_check_for_wake_only_gpe ( + struct acpi_gpe_event_info *gpe_event_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_check_for_wake_only_gpe"); + + + if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */ + ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) /* System state at GPE time */ { + /* This must be a wake-only GPE, disable it */ + + status = acpi_ev_disable_gpe (gpe_event_info); + + /* Set GPE to wake-only. Do not change wake disabled/enabled status */ + + acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE); + + ACPI_REPORT_INFO (("GPE %p was updated from wake/run to wake-only\n", + gpe_event_info)); + + /* This was a wake-only GPE */ + + return_ACPI_STATUS (AE_WAKE_ONLY_GPE); + } + + return_ACPI_STATUS (AE_OK); +} +#endif + diff -Nru a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c --- a/drivers/acpi/events/evgpeblk.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/acpi/events/evgpeblk.c 2004-10-18 14:56:32 -07:00 @@ -53,7 +53,7 @@ * * FUNCTION: acpi_ev_valid_gpe_event * - * PARAMETERS: gpe_event_info - Info for this GPE + * PARAMETERS: gpe_event_info - Info for this GPE * * RETURN: TRUE if the gpe_event is valid * @@ -105,17 +105,18 @@ * FUNCTION: acpi_ev_walk_gpe_list * * PARAMETERS: gpe_walk_callback - Routine called for each GPE block + * Flags - ACPI_NOT_ISR or ACPI_ISR * * RETURN: Status * * DESCRIPTION: Walk the GPE lists. - * FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ acpi_status acpi_ev_walk_gpe_list ( - ACPI_GPE_CALLBACK gpe_walk_callback) + ACPI_GPE_CALLBACK gpe_walk_callback, + u32 flags) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; @@ -125,7 +126,7 @@ ACPI_FUNCTION_TRACE ("ev_walk_gpe_list"); - acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_ISR); + acpi_os_acquire_lock (acpi_gbl_gpe_lock, flags); /* Walk the interrupt level descriptor list */ @@ -149,11 +150,58 @@ } unlock_and_exit: - acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_ISR); + acpi_os_release_lock (acpi_gbl_gpe_lock, flags); return_ACPI_STATUS (status); } +/****************************************************************************** + * + * FUNCTION: acpi_ev_delete_gpe_handlers + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Delete all Handler objects found in the GPE data structs. + * Used only prior to termination. + * + ******************************************************************************/ + +acpi_status +acpi_ev_delete_gpe_handlers ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_native_uint i; + acpi_native_uint j; + + + ACPI_FUNCTION_TRACE ("ev_delete_gpe_handlers"); + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + /* Now look at the individual GPEs in this byte register */ + + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { + gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; + + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { + ACPI_MEM_FREE (gpe_event_info->dispatch.handler); + gpe_event_info->dispatch.handler = NULL; + gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; + } + } + } + + return_ACPI_STATUS (AE_OK); +} + + /******************************************************************************* * * FUNCTION: acpi_ev_save_method_info @@ -188,6 +236,7 @@ u32 gpe_number; char name[ACPI_NAME_SIZE + 1]; u8 type; + acpi_status status; ACPI_FUNCTION_TRACE ("ev_save_method_info"); @@ -206,16 +255,16 @@ * 2) Edge/Level determination is based on the 2nd character * of the method name * - * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE if a - * _PRW object is found that points to this GPE. + * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE + * if a _PRW object is found that points to this GPE. */ switch (name[1]) { case 'L': - type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; + type = ACPI_GPE_LEVEL_TRIGGERED; break; case 'E': - type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; + type = ACPI_GPE_EDGE_TRIGGERED; break; default: @@ -253,27 +302,35 @@ /* * Now we can add this information to the gpe_event_info block - * for use during dispatch of this GPE. + * for use during dispatch of this GPE. Default type is RUNTIME, although + * this may change when the _PRW methods are executed later. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->flags = type; - gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; + gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD | + ACPI_GPE_TYPE_RUNTIME); + + gpe_event_info->dispatch.method_node = (struct acpi_namespace_node *) obj_handle; + + /* Update enable mask, but don't enable the HW GPE as of yet */ + + status = acpi_ev_enable_gpe (gpe_event_info, FALSE); ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: acpi_ev_get_gpe_type + * FUNCTION: acpi_ev_match_prw_and_gpe * * PARAMETERS: Callback from walk_namespace * - * RETURN: Status + * RETURN: Status. NOTE: We ignore errors so that the _PRW walk is + * not aborted on a single _PRW failure. * * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a * Device. Run the _PRW method. If present, extract the GPE @@ -282,7 +339,7 @@ ******************************************************************************/ static acpi_status -acpi_ev_get_gpe_type ( +acpi_ev_match_prw_and_gpe ( acpi_handle obj_handle, u32 level, void *info, @@ -299,19 +356,18 @@ acpi_status status; - ACPI_FUNCTION_TRACE ("ev_get_gpe_type"); + ACPI_FUNCTION_TRACE ("ev_match_prw_and_gpe"); /* Check for a _PRW method under this device */ status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW, ACPI_BTYPE_PACKAGE, &pkg_desc); - if (status == AE_NOT_FOUND) { + if (ACPI_FAILURE (status)) { + /* Ignore all errors from _PRW, we don't want to abort the subsystem */ + return_ACPI_STATUS (AE_OK); } - else if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } /* The returned _PRW package must have at least two elements */ @@ -370,16 +426,21 @@ if ((gpe_device == target_gpe_device) && (gpe_number >= gpe_block->block_base_number) && (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { - /* Mark GPE for WAKE but DISABLED (even for wake) */ - gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->flags |= ACPI_GPE_TYPE_WAKE; + + /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */ + + gpe_event_info->flags &= ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED); + status = acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE); } cleanup: acpi_ut_remove_reference (pkg_desc); - - return_ACPI_STATUS (status); + return_ACPI_STATUS (AE_OK); } @@ -742,7 +803,7 @@ /* Init the event_info for each GPE within this register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { - this_event->bit_mask = acpi_gbl_decode_to8bit[j]; + this_event->register_bit = acpi_gbl_decode_to8bit[j]; this_event->register_info = this_register; this_event++; } @@ -817,6 +878,7 @@ acpi_status status; struct acpi_gpe_walk_info gpe_info; + ACPI_FUNCTION_TRACE ("ev_create_gpe_block"); @@ -835,6 +897,7 @@ gpe_block->register_count = register_count; gpe_block->block_base_number = gpe_block_base_number; + gpe_block->node = gpe_device; ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, sizeof (struct acpi_generic_address)); @@ -854,18 +917,6 @@ return_ACPI_STATUS (status); } - /* Dump info about this GPE block */ - - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, - "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n", - gpe_block->block_base_number, - (u32) (gpe_block->block_base_number + - ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), - gpe_device->name.ascii, - gpe_block->register_count, - ACPI_FORMAT_UINT64 (gpe_block->block_address.address), - interrupt_level)); - /* Find all GPE methods (_Lxx, _Exx) for this block */ status = acpi_ns_walk_namespace (ACPI_TYPE_METHOD, gpe_device, @@ -873,27 +924,28 @@ gpe_block, NULL); /* - * Runtime option: Should Wake GPEs be enabled at runtime? The default is - * No,they should only be enabled just as the machine goes to sleep. + * Runtime option: Should Wake GPEs be enabled at runtime? The default + * is No,they should only be enabled just as the machine goes to sleep. */ if (acpi_gbl_leave_wake_gpes_disabled) { /* - * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. (Each - * GPE that has one or more _PRWs that reference it is by definition a - * WAKE GPE and will not be enabled while the machine is running.) + * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. + * (Each GPE that has one or more _PRWs that reference it is by + * definition a WAKE GPE and will not be enabled while the machine + * is running.) */ gpe_info.gpe_block = gpe_block; gpe_info.gpe_device = gpe_device; status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_get_gpe_type, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_match_prw_and_gpe, &gpe_info, NULL); } /* - * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have - * a corresponding _Lxx or _Exx method. All other GPEs must be enabled via - * the acpi_enable_gpe() external interface. + * Enable all GPEs in this block that are 1) "runtime" or "run/wake" GPEs, + * and 2) have a corresponding _Lxx or _Exx method. All other GPEs must + * be enabled via the acpi_enable_gpe() external interface. */ wake_gpe_count = 0; gpe_enabled_count = 0; @@ -903,23 +955,35 @@ /* Get the info block for this particular GPE */ gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; - if ((gpe_event_info->method_node) && - ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) { - /* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */ - - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + + if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) && + (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) { gpe_enabled_count++; } - if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) { + if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) { wake_gpe_count++; } } } + /* Dump info about this GPE block */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "GPE %02X to %02X [%4.4s] %u regs at %8.8X%8.8X on int 0x%X\n", + (u32) gpe_block->block_base_number, + (u32) (gpe_block->block_base_number + + ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), + gpe_device->name.ascii, + gpe_block->register_count, + ACPI_FORMAT_UINT64 (gpe_block->block_address.address), + interrupt_level)); + + + /* Enable all valid GPEs found above */ + + status = acpi_hw_enable_runtime_gpe_block (NULL, gpe_block); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Found %u Wake, Enabled %u Runtime GPEs in this block\n", wake_gpe_count, gpe_enabled_count)); @@ -1056,7 +1120,8 @@ if ((register_count0 + register_count1) == 0) { /* GPEs are not required by ACPI, this is OK */ - ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "There are no GPE blocks defined in the FADT\n")); status = AE_OK; goto cleanup; } diff -Nru a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c --- a/drivers/acpi/events/evmisc.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/acpi/events/evmisc.c 2004-10-18 14:56:33 -07:00 @@ -88,9 +88,10 @@ * * FUNCTION: acpi_ev_queue_notify_request * - * PARAMETERS: + * PARAMETERS: Node - NS node for the notified object + * notify_value - Value from the Notify() request * - * RETURN: None. + * RETURN: Status * * DESCRIPTION: Dispatch a device notification event to a previously * installed handler. @@ -139,14 +140,12 @@ acpi_notify_value_names[notify_value])); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "notify value: 0x%2.2x **Device Specific**\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n", notify_value)); } - /* - * Get the notify object attached to the NS Node - */ + /* Get the notify object attached to the NS Node */ + obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { /* We have the notify object, Get the right handler */ @@ -194,11 +193,13 @@ } if (!handler_obj) { - /* There is no per-device notify handler for this device */ - + /* + * There is no per-device notify handler for this device. + * This may or may not be a problem. + */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "No notify handler for [%4.4s] node %p\n", - acpi_ut_get_node_name (node), node)); + "No notify handler for Notify(%4.4s, %X) node %p\n", + acpi_ut_get_node_name (node), notify_value, node)); } return (status); @@ -209,7 +210,7 @@ * * FUNCTION: acpi_ev_notify_dispatch * - * PARAMETERS: + * PARAMETERS: Context - To be passsed to the notify handler * * RETURN: None. * @@ -276,6 +277,8 @@ * * FUNCTION: acpi_ev_global_lock_thread * + * PARAMETERS: Context - From thread interface, not used + * * RETURN: None * * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the @@ -309,7 +312,9 @@ * * FUNCTION: acpi_ev_global_lock_handler * - * RETURN: Status + * PARAMETERS: Context - From thread interface, not used + * + * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED * * DESCRIPTION: Invoked directly from the SCI handler when a global lock * release interrupt occurs. Grab the global lock and queue @@ -356,6 +361,8 @@ * * FUNCTION: acpi_ev_init_global_lock_handler * + * PARAMETERS: None + * * RETURN: Status * * DESCRIPTION: Install a handler for the global lock release event @@ -395,6 +402,8 @@ * * FUNCTION: acpi_ev_acquire_global_lock * + * PARAMETERS: Timeout - Max time to wait for the lock, in millisec. + * * RETURN: Status * * DESCRIPTION: Attempt to gain ownership of the Global Lock. @@ -462,6 +471,10 @@ * * FUNCTION: acpi_ev_release_global_lock * + * PARAMETERS: None + * + * RETURN: Status + * * DESCRIPTION: Releases ownership of the Global Lock. * ******************************************************************************/ @@ -548,7 +561,7 @@ /* Disable all GPEs in all GPE blocks */ - status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block); + status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, ACPI_NOT_ISR); /* Remove SCI handler */ @@ -557,6 +570,10 @@ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n")); } } + + /* Deallocate all handler objects installed within GPE info structs */ + + status = acpi_ev_walk_gpe_list (acpi_ev_delete_gpe_handlers, ACPI_NOT_ISR); /* Return to original mode if necessary */ diff -Nru a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c --- a/drivers/acpi/events/evregion.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/acpi/events/evregion.c 2004-10-18 14:56:48 -07:00 @@ -61,7 +61,7 @@ /******************************************************************************* * - * FUNCTION: acpi_ev_init_address_spaces + * FUNCTION: acpi_ev_install_region_handlers * * PARAMETERS: None * @@ -72,15 +72,20 @@ ******************************************************************************/ acpi_status -acpi_ev_init_address_spaces ( +acpi_ev_install_region_handlers ( void) { acpi_status status; acpi_native_uint i; - ACPI_FUNCTION_TRACE ("ev_init_address_spaces"); + ACPI_FUNCTION_TRACE ("ev_install_region_handlers"); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* * All address spaces (PCI Config, EC, SMBus) are scope dependent * and registration must occur for a specific device. @@ -99,9 +104,8 @@ * has already been installed (via acpi_install_address_space_handler). * Similar for AE_SAME_HANDLER. */ - for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { - status = acpi_install_address_space_handler ((acpi_handle) acpi_gbl_root_node, + status = acpi_ev_install_space_handler (acpi_gbl_root_node, acpi_gbl_default_address_spaces[i], ACPI_DEFAULT_HANDLER, NULL, NULL); switch (status) { @@ -111,15 +115,63 @@ /* These exceptions are all OK */ + status = AE_OK; break; default: - return_ACPI_STATUS (status); + goto unlock_and_exit; } } - return_ACPI_STATUS (AE_OK); +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_initialize_op_regions + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Execute _REG methods for all Operation Regions that have + * an installed default region handler. + * + ******************************************************************************/ + +acpi_status +acpi_ev_initialize_op_regions ( + void) +{ + acpi_status status; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ev_initialize_op_regions"); + + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Run the _REG methods for op_regions in each default address space + */ + for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* TBD: Make sure handler is the DEFAULT handler, otherwise + * _REG will have already been run. + */ + status = acpi_ev_execute_reg_methods (acpi_gbl_root_node, + acpi_gbl_default_address_spaces[i]); + } + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); } @@ -128,7 +180,7 @@ * FUNCTION: acpi_ev_execute_reg_method * * PARAMETERS: region_obj - Object structure - * Function - On (1) or Off (0) + * Function - Passed to _REG: On (1) or Off (0) * * RETURN: Status * @@ -138,11 +190,12 @@ acpi_status acpi_ev_execute_reg_method ( - union acpi_operand_object *region_obj, + union acpi_operand_object *region_obj, u32 function) { - union acpi_operand_object *params[3]; - union acpi_operand_object *region_obj2; + struct acpi_parameter_info info; + union acpi_operand_object *params[3]; + union acpi_operand_object *region_obj2; acpi_status status; @@ -159,10 +212,11 @@ } /* - * _REG method has two arguments - * Arg0: Integer: Operation region space ID + * The _REG method has two arguments: + * + * Arg0, Integer: Operation region space ID * Same value as region_obj->Region.space_id - * Arg1: Integer: connection status + * Arg1, Integer: connection status * 1 for connecting the handler, * 0 for disconnecting the handler * Passed as a parameter @@ -178,16 +232,21 @@ goto cleanup; } - /* Set up the parameter objects */ + /* Setup the parameter objects */ params[0]->integer.value = region_obj->region.space_id; params[1]->integer.value = function; params[2] = NULL; + info.node = region_obj2->extra.method_REG; + info.parameters = params; + info.parameter_type = ACPI_PARAM_ARGS; + /* Execute the method, no return value */ - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, region_obj2->extra.method_REG, NULL)); - status = acpi_ns_evaluate_by_handle (region_obj2->extra.method_REG, params, NULL); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname ( + ACPI_TYPE_METHOD, info.node, NULL)); + status = acpi_ns_evaluate_by_handle (&info); acpi_ut_remove_reference (params[1]); @@ -203,7 +262,6 @@ * FUNCTION: acpi_ev_address_space_dispatch * * PARAMETERS: region_obj - Internal region object - * space_id - ID of the address space (0-255) * Function - Read or Write operation * Address - Where in the space to read or write * bit_width - Field width in bits (8, 16, 32, or 64) @@ -326,7 +384,7 @@ ACPI_FORMAT_UINT64 (address), acpi_ut_get_region_name (region_obj->region.space_id))); - if (!(handler_desc->address_space.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * For handlers other than the default (supplied) handlers, we must * exit the interpreter because the handler *might* block -- we don't @@ -347,7 +405,7 @@ acpi_format_exception (status))); } - if (!(handler_desc->address_space.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * We just returned from a non-default handler, we must re-enter the * interpreter @@ -366,8 +424,8 @@ * * FUNCTION: acpi_ev_detach_region * - * PARAMETERS: region_obj - Region Object - * acpi_ns_is_locked - Namespace Region Already Locked? + * PARAMETERS: region_obj - Region Object + * acpi_ns_is_locked - Namespace Region Already Locked? * * RETURN: None * @@ -501,9 +559,9 @@ * * FUNCTION: acpi_ev_attach_region * - * PARAMETERS: handler_obj - Handler Object - * region_obj - Region Object - * acpi_ns_is_locked - Namespace Region Already Locked? + * PARAMETERS: handler_obj - Handler Object + * region_obj - Region Object + * acpi_ns_is_locked - Namespace Region Already Locked? * * RETURN: None * @@ -676,6 +734,273 @@ return (status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ev_install_space_handler + * + * PARAMETERS: Node - Namespace node for the device + * space_id - The address space ID + * Handler - Address of the handler + * Setup - Address of the setup function + * Context - Value passed to the handler on each access + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for all op_regions of a given space_id. + * Assumes namespace is locked + * + ******************************************************************************/ + +acpi_status +acpi_ev_install_space_handler ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup, + void *context) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object *handler_obj; + acpi_status status; + acpi_object_type type; + u16 flags = 0; + + + ACPI_FUNCTION_TRACE ("ev_install_space_handler"); + + + /* + * This registration is valid for only the types below + * and the root. This is where the default handlers + * get placed. + */ + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR) && + (node->type != ACPI_TYPE_THERMAL) && + (node != acpi_gbl_root_node)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + if (handler == ACPI_DEFAULT_HANDLER) { + flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; + + switch (space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + handler = acpi_ex_system_memory_space_handler; + setup = acpi_ev_system_memory_region_setup; + break; + + case ACPI_ADR_SPACE_SYSTEM_IO: + handler = acpi_ex_system_io_space_handler; + setup = acpi_ev_io_space_region_setup; + break; + + case ACPI_ADR_SPACE_PCI_CONFIG: + handler = acpi_ex_pci_config_space_handler; + setup = acpi_ev_pci_config_region_setup; + break; + + case ACPI_ADR_SPACE_CMOS: + handler = acpi_ex_cmos_space_handler; + setup = acpi_ev_cmos_region_setup; + break; + + case ACPI_ADR_SPACE_PCI_BAR_TARGET: + handler = acpi_ex_pci_bar_space_handler; + setup = acpi_ev_pci_bar_region_setup; + break; + + case ACPI_ADR_SPACE_DATA_TABLE: + handler = acpi_ex_data_table_space_handler; + setup = NULL; + break; + + default: + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + + /* If the caller hasn't specified a setup routine, use the default */ + + if (!setup) { + setup = acpi_ev_default_region_setup; + } + + /* Check for an existing internal object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { + /* + * The attached device object already exists. + * Make sure the handler is not already installed. + */ + handler_obj = obj_desc->device.handler; + + /* Walk the handler list for this device */ + + while (handler_obj) { + /* Same space_id indicates a handler already installed */ + + if (handler_obj->address_space.space_id == space_id) { + if (handler_obj->address_space.handler == handler) { + /* + * It is (relatively) OK to attempt to install the SAME + * handler twice. This can easily happen with PCI_Config space. + */ + status = AE_SAME_HANDLER; + goto unlock_and_exit; + } + else { + /* A handler is already installed */ + + status = AE_ALREADY_EXISTS; + } + goto unlock_and_exit; + } + + /* Walk the linked list of handlers */ + + handler_obj = handler_obj->address_space.next; + } + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Creating object on Device %p while installing handler\n", node)); + + /* obj_desc does not exist, create one */ + + if (node->type == ACPI_TYPE_ANY) { + type = ACPI_TYPE_DEVICE; + } + else { + type = node->type; + } + + obj_desc = acpi_ut_create_internal_object (type); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* Init new descriptor */ + + obj_desc->common.type = (u8) type; + + /* Attach the new object to the Node */ + + status = acpi_ns_attach_object (node, obj_desc, type); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", + acpi_ut_get_region_name (space_id), space_id, + acpi_ut_get_node_name (node), node, obj_desc)); + + /* + * Install the handler + * + * At this point there is no existing handler. + * Just allocate the object for the handler and link it + * into the list. + */ + handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); + if (!handler_obj) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* Init handler obj */ + + handler_obj->address_space.space_id = (u8) space_id; + handler_obj->address_space.hflags = flags; + handler_obj->address_space.region_list = NULL; + handler_obj->address_space.node = node; + handler_obj->address_space.handler = handler; + handler_obj->address_space.context = context; + handler_obj->address_space.setup = setup; + + /* Install at head of Device.address_space list */ + + handler_obj->address_space.next = obj_desc->device.handler; + + /* + * The Device object is the first reference on the handler_obj. + * Each region that uses the handler adds a reference. + */ + obj_desc->device.handler = handler_obj; + + /* + * Walk the namespace finding all of the regions this + * handler will manage. + * + * Start at the device and search the branch toward + * the leaf nodes until either the leaf is encountered or + * a device is detected that has an address handler of the + * same type. + * + * In either case, back up and search down the remainder + * of the branch + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, + handler_obj, NULL); + +unlock_and_exit: + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_execute_reg_methods + * + * PARAMETERS: Node - Namespace node for the device + * space_id - The address space ID + * + * RETURN: Status + * + * DESCRIPTION: Run all _REG methods for the input Space ID; + * Note: assumes namespace is locked, or system init time. + * + ******************************************************************************/ + +acpi_status +acpi_ev_execute_reg_methods ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_execute_reg_methods"); + + + /* + * Run all _REG methods for all Operation Regions for this + * space ID. This is a separate walk in order to handle any + * interdependencies between regions and _REG methods. (i.e. handlers + * must be installed for all regions of this Space ID before we + * can run any _REG methods) + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, + &space_id, NULL); + + return_ACPI_STATUS (status); +} + + /******************************************************************************* * * FUNCTION: acpi_ev_reg_run @@ -693,19 +1018,13 @@ void *context, void **return_value) { - union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; + acpi_adr_space_type space_id; acpi_status status; - handler_obj = (union acpi_operand_object *) context; - - /* Parameter validation */ - - if (!handler_obj) { - return (AE_OK); - } + space_id = *ACPI_CAST_PTR (acpi_adr_space_type, context); /* Convert and validate the device handle */ @@ -732,10 +1051,9 @@ return (AE_OK); } - /* Object is a Region */ - if (obj_desc->region.space_id != handler_obj->address_space.space_id) { + if (obj_desc->region.space_id != space_id) { /* * This region is for a different address space * -- just ignore it diff -Nru a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c --- a/drivers/acpi/events/evrgnini.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/events/evrgnini.c 2004-10-18 14:55:54 -07:00 @@ -54,7 +54,7 @@ * * FUNCTION: acpi_ev_system_memory_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -108,7 +108,7 @@ * * FUNCTION: acpi_ev_io_space_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -144,7 +144,7 @@ * * FUNCTION: acpi_ev_pci_config_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -317,7 +317,7 @@ * * FUNCTION: acpi_ev_pci_bar_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -348,7 +348,7 @@ * * FUNCTION: acpi_ev_cmos_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -379,7 +379,7 @@ * * FUNCTION: acpi_ev_default_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context diff -Nru a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c --- a/drivers/acpi/events/evxface.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/acpi/events/evxface.c 2004-10-18 14:56:33 -07:00 @@ -188,6 +188,7 @@ * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) + * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * Context - Value passed to the handler on each GPE * @@ -243,20 +244,21 @@ if (device == ACPI_ROOT_OBJECT) { /* Make sure the handler is not already installed */ - if (((handler_type == ACPI_SYSTEM_NOTIFY) && - acpi_gbl_system_notify.handler) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && + acpi_gbl_system_notify.handler) || + ((handler_type & ACPI_DEVICE_NOTIFY) && acpi_gbl_device_notify.handler)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = node; acpi_gbl_system_notify.handler = handler; acpi_gbl_system_notify.context = context; } - else /* ACPI_DEVICE_NOTIFY */ { + + if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = node; acpi_gbl_device_notify.handler = handler; acpi_gbl_device_notify.context = context; @@ -284,9 +286,9 @@ if (obj_desc) { /* Object exists - make sure there's no handler */ - if (((handler_type == ACPI_SYSTEM_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && obj_desc->common_notify.system_notify) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + ((handler_type & ACPI_DEVICE_NOTIFY) && obj_desc->common_notify.device_notify)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; @@ -308,7 +310,6 @@ /* Remove local reference to the object */ acpi_ut_remove_reference (obj_desc); - if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -326,12 +327,19 @@ notify_obj->notify.handler = handler; notify_obj->notify.context = context; - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { obj_desc->common_notify.system_notify = notify_obj; } - else /* ACPI_DEVICE_NOTIFY */ { + + if (handler_type & ACPI_DEVICE_NOTIFY) { obj_desc->common_notify.device_notify = notify_obj; } + + if (handler_type == ACPI_ALL_NOTIFY) { + /* Extra ref if installed in both */ + + acpi_ut_add_reference (notify_obj); + } } @@ -349,7 +357,9 @@ * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) + * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler + * * RETURN: Status * * DESCRIPTION: Remove a handler for notifies on an ACPI device @@ -392,15 +402,14 @@ goto unlock_and_exit; } - /* - * Root Object - */ + /* Root Object */ + if (device == ACPI_ROOT_OBJECT) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n")); - if (((handler_type == ACPI_SYSTEM_NOTIFY) && - !acpi_gbl_system_notify.handler) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && + !acpi_gbl_system_notify.handler) || + ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; @@ -415,21 +424,21 @@ return_ACPI_STATUS (status); } - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } - else { + + if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; } } - /* - * All Other Objects - */ + /* All Other Objects */ + else { /* Notifies allowed on this object? */ @@ -448,38 +457,47 @@ /* Object exists - make sure there's an existing handler */ - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; - } - else { - notify_obj = obj_desc->common_notify.device_notify; - } + if ((!notify_obj) || + (notify_obj->notify.handler != handler)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ - if ((!notify_obj) || - (notify_obj->notify.handler != handler)) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + acpi_os_wait_events_complete(NULL); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - /* Make sure all deferred tasks are completed */ + /* Remove the handler */ + obj_desc->common_notify.system_notify = NULL; + acpi_ut_remove_reference (notify_obj); + } - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - acpi_os_wait_events_complete(NULL); - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + if (handler_type & ACPI_DEVICE_NOTIFY) { + notify_obj = obj_desc->common_notify.device_notify; + if ((!notify_obj) || + (notify_obj->notify.handler != handler)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ - /* Remove the handler */ + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + acpi_os_wait_events_complete(NULL); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - if (handler_type == ACPI_SYSTEM_NOTIFY) { - obj_desc->common_notify.system_notify = NULL; - } - else { + /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; + acpi_ut_remove_reference (notify_obj); } - - acpi_ut_remove_reference (notify_obj); } @@ -497,7 +515,7 @@ * gpe_block - GPE block (NULL == FADT GPEs) * Type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. - * Handler - Address of the handler + * Address - Address of the handler * Context - Value passed to the handler on each GPE * * RETURN: Status @@ -511,11 +529,12 @@ acpi_handle gpe_device, u32 gpe_number, u32 type, - acpi_gpe_handler handler, + acpi_event_handler address, void *context) { - acpi_status status; struct acpi_gpe_event_info *gpe_event_info; + struct acpi_handler_info *handler; + acpi_status status; ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler"); @@ -523,7 +542,7 @@ /* Parameter validation */ - if (!handler) { + if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -542,27 +561,41 @@ /* Make sure that there isn't a handler there already */ - if (gpe_event_info->handler) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } - /* Install the handler */ + /* Allocate and init handler object */ - acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); - gpe_event_info->handler = handler; - gpe_event_info->context = context; - gpe_event_info->flags = (u8) type; - acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + handler = ACPI_MEM_CALLOCATE (sizeof (struct acpi_handler_info)); + if (!handler) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } - /* Clear the GPE (of stale events), the enable it */ + handler->address = address; + handler->context = context; + handler->method_node = gpe_event_info->dispatch.method_node; - status = acpi_hw_clear_gpe (gpe_event_info); + /* Disable the GPE before installing the handler */ + + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - status = acpi_hw_enable_gpe (gpe_event_info); + /* Install the handler */ + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + gpe_event_info->dispatch.handler = handler; + + /* Setup up dispatch flags to indicate handler (vs. method) */ + + gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */ + gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); + + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); unlock_and_exit: @@ -577,7 +610,7 @@ * * PARAMETERS: gpe_number - The event to remove a handler * gpe_block - GPE block (NULL == FADT GPEs) - * Handler - Address of the handler + * Address - Address of the handler * * RETURN: Status * @@ -589,10 +622,11 @@ acpi_remove_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, - acpi_gpe_handler handler) + acpi_event_handler address) { - acpi_status status; struct acpi_gpe_event_info *gpe_event_info; + struct acpi_handler_info *handler; + acpi_status status; ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler"); @@ -600,7 +634,7 @@ /* Parameter validation */ - if (!handler) { + if (!address) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -617,21 +651,27 @@ goto unlock_and_exit; } - /* Disable the GPE before removing the handler */ + /* Make sure that a handler is indeed installed */ - status = acpi_hw_disable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != ACPI_GPE_DISPATCH_HANDLER) { + status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure that the installed handler is the same */ - if (gpe_event_info->handler != handler) { - (void) acpi_hw_enable_gpe (gpe_event_info); + if (gpe_event_info->dispatch.handler->address != address) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } + /* Disable the GPE before removing the handler */ + + status = acpi_ev_disable_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); @@ -644,9 +684,20 @@ /* Remove the handler */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); - gpe_event_info->handler = NULL; - gpe_event_info->context = NULL; + handler = gpe_event_info->dispatch.handler; + + /* Restore Method node (if any), set dispatch flags */ + + gpe_event_info->dispatch.method_node = handler->method_node; + gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */ + if (handler->method_node) { + gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD; + } acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + + /* Now we can free the handler object */ + + ACPI_MEM_FREE (handler); unlock_and_exit: diff -Nru a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c --- a/drivers/acpi/events/evxfevnt.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/acpi/events/evxfevnt.c 2004-10-18 14:56:27 -07:00 @@ -204,12 +204,11 @@ /******************************************************************************* * - * FUNCTION: acpi_enable_gpe + * FUNCTION: acpi_set_gpe_type * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just enable, or also wake enable? - * Called from ISR or not + * Type - New GPE type * * RETURN: Status * @@ -218,26 +217,17 @@ ******************************************************************************/ acpi_status -acpi_enable_gpe ( +acpi_set_gpe_type ( acpi_handle gpe_device, u32 gpe_number, - u32 flags) + u8 type) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE ("acpi_enable_gpe"); - - - /* Use semaphore lock if not executing at interrupt level */ + ACPI_FUNCTION_TRACE ("acpi_set_gpe_type"); - if (flags & ACPI_NOT_ISR) { - status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - } /* Ensure that we have a valid GPE number */ @@ -247,91 +237,72 @@ goto unlock_and_exit; } - /* Check for Wake vs Runtime GPE */ - - if (flags & ACPI_EVENT_WAKE_ENABLE) { - /* Ensure the requested wake GPE is disabled */ - - status = acpi_hw_disable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - - /* Defer Enable of Wake GPE until sleep time */ - - acpi_hw_enable_gpe_for_wakeup (gpe_event_info); + if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) { + return_ACPI_STATUS (AE_OK); } - else { - /* Enable the requested runtime GPE */ - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } + /* Set the new type (will disable GPE if currently enabled) */ + status = acpi_ev_set_gpe_type (gpe_event_info, type); unlock_and_exit: - if (flags & ACPI_NOT_ISR) { - (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); - } return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: acpi_disable_event + * FUNCTION: acpi_enable_gpe * - * PARAMETERS: Event - The fixed eventto be enabled - * Flags - Reserved + * PARAMETERS: gpe_device - Parent GPE Device + * gpe_number - GPE level within the GPE block + * Flags - Just enable, or also wake enable? + * Called from ISR or not * * RETURN: Status * - * DESCRIPTION: Disable an ACPI event (fixed) + * DESCRIPTION: Enable an ACPI event (general purpose) * ******************************************************************************/ acpi_status -acpi_disable_event ( - u32 event, +acpi_enable_gpe ( + acpi_handle gpe_device, + u32 gpe_number, u32 flags) { acpi_status status = AE_OK; - u32 value; + struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE ("acpi_disable_event"); + ACPI_FUNCTION_TRACE ("acpi_enable_gpe"); - /* Decode the Fixed Event */ + /* Use semaphore lock if not executing at interrupt level */ - if (event > ACPI_EVENT_MAX) { - return_ACPI_STATUS (AE_BAD_PARAMETER); + if (flags & ACPI_NOT_ISR) { + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - /* - * Disable the requested fixed event (by writing a zero to the - * enable register bit) - */ - status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, - 0, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + /* Ensure that we have a valid GPE number */ - status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, - &value, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; } - if (value != 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not disable %s events\n", acpi_ut_get_event_name (event))); - return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); - } + /* Perform the enable */ + + status = acpi_ev_enable_gpe (gpe_event_info, TRUE); +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } return_ACPI_STATUS (status); } @@ -342,7 +313,7 @@ * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just enable, or also wake enable? + * Flags - Just disable, or also wake disable? * Called from ISR or not * * RETURN: Status @@ -381,21 +352,69 @@ goto unlock_and_exit; } + status = acpi_ev_disable_gpe (gpe_event_info); + +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_disable_event + * + * PARAMETERS: Event - The fixed eventto be enabled + * Flags - Reserved + * + * RETURN: Status + * + * DESCRIPTION: Disable an ACPI event (fixed) + * + ******************************************************************************/ + +acpi_status +acpi_disable_event ( + u32 event, + u32 flags) +{ + acpi_status status = AE_OK; + u32 value; + + + ACPI_FUNCTION_TRACE ("acpi_disable_event"); + + + /* Decode the Fixed Event */ + + if (event > ACPI_EVENT_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + /* - * Only disable the requested GPE number for wake if specified. - * Otherwise, turn it totally off + * Disable the requested fixed event (by writing a zero to the + * enable register bit) */ - if (flags & ACPI_EVENT_WAKE_DISABLE) { - acpi_hw_disable_gpe_for_wakeup (gpe_event_info); + status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - else { - status = acpi_hw_disable_gpe (gpe_event_info); + + status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, + &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } -unlock_and_exit: - if (flags & ACPI_NOT_ISR) { - (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + if (value != 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not disable %s events\n", acpi_ut_get_event_name (event))); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); } + return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c --- a/drivers/acpi/events/evxfregn.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/acpi/events/evxfregn.c 2004-10-18 14:56:13 -07:00 @@ -46,7 +46,6 @@ #include #include #include -#include #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evxfregn") @@ -76,12 +75,8 @@ acpi_adr_space_setup setup, void *context) { - union acpi_operand_object *obj_desc; - union acpi_operand_object *handler_obj; struct acpi_namespace_node *node; acpi_status status; - acpi_object_type type; - u16 flags = 0; ACPI_FUNCTION_TRACE ("acpi_install_address_space_handler"); @@ -106,202 +101,16 @@ goto unlock_and_exit; } - /* - * This registration is valid for only the types below - * and the root. This is where the default handlers - * get placed. - */ - if ((node->type != ACPI_TYPE_DEVICE) && - (node->type != ACPI_TYPE_PROCESSOR) && - (node->type != ACPI_TYPE_THERMAL) && - (node != acpi_gbl_root_node)) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - if (handler == ACPI_DEFAULT_HANDLER) { - flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - handler = acpi_ex_system_memory_space_handler; - setup = acpi_ev_system_memory_region_setup; - break; - - case ACPI_ADR_SPACE_SYSTEM_IO: - handler = acpi_ex_system_io_space_handler; - setup = acpi_ev_io_space_region_setup; - break; - - case ACPI_ADR_SPACE_PCI_CONFIG: - handler = acpi_ex_pci_config_space_handler; - setup = acpi_ev_pci_config_region_setup; - break; - - case ACPI_ADR_SPACE_CMOS: - handler = acpi_ex_cmos_space_handler; - setup = acpi_ev_cmos_region_setup; - break; - - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - handler = acpi_ex_pci_bar_space_handler; - setup = acpi_ev_pci_bar_region_setup; - break; - - case ACPI_ADR_SPACE_DATA_TABLE: - handler = acpi_ex_data_table_space_handler; - setup = NULL; - break; - - default: - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - } - - /* If the caller hasn't specified a setup routine, use the default */ - - if (!setup) { - setup = acpi_ev_default_region_setup; - } - - /* Check for an existing internal object */ - - obj_desc = acpi_ns_get_attached_object (node); - if (obj_desc) { - /* - * The attached device object already exists. - * Make sure the handler is not already installed. - */ - handler_obj = obj_desc->device.handler; - - /* Walk the handler list for this device */ - - while (handler_obj) { - /* Same space_id indicates a handler already installed */ - - if(handler_obj->address_space.space_id == space_id) { - if (handler_obj->address_space.handler == handler) { - /* - * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen with PCI_Config space. - */ - status = AE_SAME_HANDLER; - goto unlock_and_exit; - } - else { - /* A handler is already installed */ - - status = AE_ALREADY_EXISTS; - } - goto unlock_and_exit; - } - - /* Walk the linked list of handlers */ - - handler_obj = handler_obj->address_space.next; - } - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Creating object on Device %p while installing handler\n", node)); - - /* obj_desc does not exist, create one */ - - if (node->type == ACPI_TYPE_ANY) { - type = ACPI_TYPE_DEVICE; - } - else { - type = node->type; - } - - obj_desc = acpi_ut_create_internal_object (type); - if (!obj_desc) { - status = AE_NO_MEMORY; - goto unlock_and_exit; - } - - /* Init new descriptor */ - - obj_desc->common.type = (u8) type; - - /* Attach the new object to the Node */ + /* Install the handler for all Regions for this Space ID */ - status = acpi_ns_attach_object (node, obj_desc, type); - - /* Remove local reference to the object */ - - acpi_ut_remove_reference (obj_desc); - - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", - acpi_ut_get_region_name (space_id), space_id, - acpi_ut_get_node_name (node), node, obj_desc)); - - /* - * Install the handler - * - * At this point there is no existing handler. - * Just allocate the object for the handler and link it - * into the list. - */ - handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); - if (!handler_obj) { - status = AE_NO_MEMORY; + status = acpi_ev_install_space_handler (node, space_id, handler, setup, context); + if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - /* Init handler obj */ + /* Run all _REG methods for this address space */ - handler_obj->address_space.space_id = (u8) space_id; - handler_obj->address_space.hflags = flags; - handler_obj->address_space.region_list = NULL; - handler_obj->address_space.node = node; - handler_obj->address_space.handler = handler; - handler_obj->address_space.context = context; - handler_obj->address_space.setup = setup; - - /* Install at head of Device.address_space list */ - - handler_obj->address_space.next = obj_desc->device.handler; - - /* - * The Device object is the first reference on the handler_obj. - * Each region that uses the handler adds a reference. - */ - obj_desc->device.handler = handler_obj; - - /* - * Walk the namespace finding all of the regions this - * handler will manage. - * - * Start at the device and search the branch toward - * the leaf nodes until either the leaf is encountered or - * a device is detected that has an address handler of the - * same type. - * - * In either case, back up and search down the remainder - * of the branch - */ - status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, - handler_obj, NULL); - - /* - * Now we can run the _REG methods for all Regions for this - * space ID. This is a separate walk in order to handle any - * interdependencies between regions and _REG methods. (i.e. handlers - * must be installed for all regions of this Space ID before we - * can run any _REG methods. - */ - status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, - handler_obj, NULL); + status = acpi_ev_execute_reg_methods (node, space_id); unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); diff -Nru a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c --- a/drivers/acpi/executer/exconfig.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/acpi/executer/exconfig.c 2004-10-18 14:56:33 -07:00 @@ -48,6 +48,7 @@ #include #include #include +#include #define _COMPONENT ACPI_EXECUTER @@ -285,7 +286,7 @@ union acpi_operand_object *ddb_handle; union acpi_operand_object *buffer_desc = NULL; struct acpi_table_header *table_ptr = NULL; - u8 *table_data_ptr; + acpi_physical_address address; struct acpi_table_header table_header; u32 i; @@ -300,18 +301,39 @@ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Region %p %s\n", obj_desc, acpi_ut_get_object_type_name (obj_desc))); - /* Get the table header */ + /* + * If the Region Address and Length have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_region_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Get the base physical address of the region */ + + address = obj_desc->region.address; + + /* Get the table length from the table header */ table_header.length = 0; - for (i = 0; i < sizeof (struct acpi_table_header); i++) { + for (i = 0; i < 8; i++) { status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, - (acpi_physical_address) i, 8, + (acpi_physical_address) (i + address), 8, ((u8 *) &table_header) + i); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } + /* Sanity check the table length */ + + if (table_header.length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } + /* Allocate a buffer for the entire table */ table_ptr = ACPI_MEM_ALLOCATE (table_header.length); @@ -319,17 +341,12 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - /* Copy the header to the buffer */ - - ACPI_MEMCPY (table_ptr, &table_header, sizeof (struct acpi_table_header)); - table_data_ptr = ACPI_PTR_ADD (u8, table_ptr, sizeof (struct acpi_table_header)); - - /* Get the table from the op region */ + /* Get the entire table from the op region */ for (i = 0; i < table_header.length; i++) { status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, - (acpi_physical_address) i, 8, - ((u8 *) table_data_ptr + i)); + (acpi_physical_address) (i + address), 8, + ((u8 *) table_ptr + i)); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -355,6 +372,12 @@ } table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer); + + /* Sanity check the table length */ + + if (table_ptr->length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } break; diff -Nru a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c --- a/drivers/acpi/executer/exfldio.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/acpi/executer/exfldio.c 2004-10-18 14:56:28 -07:00 @@ -130,6 +130,21 @@ if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + field_datum_byte_offset + obj_desc->common_field.access_byte_width)) { + if (acpi_gbl_enable_interpreter_slack) { + /* + * Slack mode only: We will go ahead and allow access to this + * field if it is within the region length rounded up to the next + * access width boundary. + */ + if (ACPI_ROUND_UP (rgn_desc->region.length, + obj_desc->common_field.access_byte_width) >= + (obj_desc->common_field.base_byte_offset + + obj_desc->common_field.access_byte_width + + field_datum_byte_offset)) { + return_ACPI_STATUS (AE_OK); + } + } + if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { /* * This is the case where the access_type (acc_word, etc.) is wider @@ -154,40 +169,7 @@ field_datum_byte_offset, obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); - if (!acpi_strict) { - /* - * Allow access to the field if it is within the region size - * rounded up to a multiple of the access byte width. This - * overcomes "off-by-one" programming errors in the AML often - * found in Toshiba laptops. These errors were allowed by - * the Microsoft ASL compiler. - */ - u32 rounded_length = ACPI_ROUND_UP(rgn_desc->region.length, - obj_desc->common_field.access_byte_width); - - if (rounded_length < (obj_desc->common_field.base_byte_offset - + field_datum_byte_offset - + obj_desc->common_field.access_byte_width)) { - return_ACPI_STATUS (AE_AML_REGION_LIMIT); - } else { - static int warn_once = 1; - if (warn_once) { - // Could also associate a flag with each field, and - // warn once for each field. - ACPI_REPORT_WARNING(( - "The ACPI AML in your computer contains errors, " - "please nag the manufacturer to correct it.\n")); - ACPI_REPORT_WARNING(( - "Allowing relaxed access to fields; " - "turn on CONFIG_ACPI_DEBUG for details.\n")); - warn_once = 0; - } - return_ACPI_STATUS (AE_OK); - } - } - else { - return_ACPI_STATUS (AE_AML_REGION_LIMIT); - } + return_ACPI_STATUS (AE_AML_REGION_LIMIT); } return_ACPI_STATUS (AE_OK); @@ -277,7 +259,7 @@ rgn_desc->region.space_id)); } else if (status == AE_NOT_EXIST) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + ACPI_REPORT_ERROR (( "Region %s(%X) has no handler\n", acpi_ut_get_region_name (rgn_desc->region.space_id), rgn_desc->region.space_id)); @@ -766,14 +748,83 @@ /******************************************************************************* * + * FUNCTION: acpi_ex_common_buffer_setup + * + * PARAMETERS: obj_desc - Field object + * buffer_length - Length of caller's buffer + * datum_count - Where the datum_count is returned + * + * RETURN: Status, datum_count + * + * DESCRIPTION: Common code to validate the incoming buffer size and compute + * the number of field "datums" that must be read or written. + * A "datum" is the smallest unit that can be read or written + * to the field, it is either 1,2,4, or 8 bytes. + * + ******************************************************************************/ + +acpi_status +acpi_ex_common_buffer_setup ( + union acpi_operand_object *obj_desc, + u32 buffer_length, + u32 *datum_count) +{ + u32 byte_field_length; + u32 actual_byte_field_length; + + + ACPI_FUNCTION_TRACE ("ex_common_buffer_setup"); + + + /* + * Incoming buffer must be at least as long as the field, we do not + * allow "partial" field reads/writes. We do not care if the buffer is + * larger than the field, this typically happens when an integer is + * read/written to a field that is actually smaller than an integer. + */ + byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length); + if (byte_field_length > buffer_length) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field size %X (bytes) is too large for buffer (%X)\n", + byte_field_length, buffer_length)); + + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + } + + /* + * Create "actual" field byte count (minimum number of bytes that + * must be read), then convert to datum count (minimum number + * of datum-sized units that must be read) + */ + actual_byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.start_field_bit_offset + + obj_desc->common_field.bit_length); + + + *datum_count = ACPI_ROUND_UP_TO (actual_byte_field_length, + obj_desc->common_field.access_byte_width); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "buffer_bytes %X, actual_bytes %X, Datums %X, byte_gran %X\n", + byte_field_length, actual_byte_field_length, + *datum_count, obj_desc->common_field.access_byte_width)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ex_extract_from_field * - * PARAMETERS: *obj_desc - Field to be read - * *Value - Where to store value + * PARAMETERS: obj_desc - Field to be read + * Buffer - Where to store the field data + * buffer_length - Length of Buffer * * RETURN: Status * - * DESCRIPTION: Retrieve the value of the given field + * DESCRIPTION: Retrieve the current value of the given field * ******************************************************************************/ @@ -789,7 +840,6 @@ acpi_integer previous_raw_datum = 0; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; - u32 byte_field_length; u32 datum_count; u32 i; @@ -797,39 +847,13 @@ ACPI_FUNCTION_TRACE ("ex_extract_from_field"); - /* - * The field must fit within the caller's buffer - */ - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); - if (byte_field_length > buffer_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Field size %X (bytes) too large for buffer (%X)\n", - byte_field_length, buffer_length)); - - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); - } - - /* Convert field byte count to datum count, round up if necessary */ - - datum_count = ACPI_ROUND_UP_TO (byte_field_length, - obj_desc->common_field.access_byte_width); + /* Validate buffer, compute number of datums */ - /* - * If the field is not aligned on a datum boundary and does not - * fit within a single datum, we must read an extra datum. - * - * We could just split the aligned and non-aligned cases since the - * aligned case is so very simple, but this would require more code. - */ - if ((obj_desc->common_field.end_field_valid_bits != 0) && - (!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) { - datum_count++; + status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "byte_len %X, datum_len %X, byte_gran %X\n", - byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); - /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where the buffer @@ -942,12 +966,13 @@ * * FUNCTION: acpi_ex_insert_into_field * - * PARAMETERS: *obj_desc - Field to be set - * Buffer - Value to store + * PARAMETERS: obj_desc - Field to be written + * Buffer - Data to be written + * buffer_length - Length of Buffer * * RETURN: Status * - * DESCRIPTION: Store the value into the given field + * DESCRIPTION: Store the Buffer contents into the given field * ******************************************************************************/ @@ -964,41 +989,18 @@ acpi_integer merged_datum; acpi_integer previous_raw_datum; acpi_integer this_raw_datum; - u32 byte_field_length; u32 datum_count; ACPI_FUNCTION_TRACE ("ex_insert_into_field"); - /* - * Incoming buffer must be at least as long as the field, we do not - * allow "partial" field writes. We do not care if the buffer is - * larger than the field, this typically happens when an integer is - * written to a field that is actually smaller than an integer. - */ - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( - obj_desc->common_field.bit_length); - if (buffer_length < byte_field_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Buffer length %X too small for field %X\n", - buffer_length, byte_field_length)); + /* Validate buffer, compute number of datums */ - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( - obj_desc->common_field.start_field_bit_offset + - obj_desc->common_field.bit_length); - - /* Convert byte count to datum count, round up if necessary */ - - datum_count = ACPI_ROUND_UP_TO (byte_field_length, - obj_desc->common_field.access_byte_width); - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Bytes %X, Datums %X, byte_gran %X\n", - byte_field_length, datum_count, obj_desc->common_field.access_byte_width)); /* * Break the request into up to three parts (similar to an I/O request): diff -Nru a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c --- a/drivers/acpi/executer/exmisc.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/acpi/executer/exmisc.c 2004-10-18 14:56:50 -07:00 @@ -389,6 +389,8 @@ acpi_integer operand1) { + ACPI_FUNCTION_ENTRY (); + switch (opcode) { case AML_ADD_OP: /* Add (Operand0, Operand1, Result) */ @@ -452,15 +454,17 @@ * FUNCTION: acpi_ex_do_logical_op * * PARAMETERS: Opcode - AML opcode - * Operand0 - Integer operand #0 - * Operand1 - Integer operand #1 + * obj_desc0 - operand #0 + * obj_desc1 - operand #1 * * RETURN: TRUE/FALSE result of the operation * * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the * functions here is to prevent a lot of pointer dereferencing * to obtain the operands and to simplify the generation of the - * logical value. + * logical value. Both operands must already be validated as + * 1) Both the same type, and + * 2) Either Integer, Buffer, or String type. * * Note: cleanest machine code seems to be produced by the code * below, rather than using statements of the form: @@ -471,54 +475,137 @@ u8 acpi_ex_do_logical_op ( u16 opcode, - acpi_integer operand0, - acpi_integer operand1) + union acpi_operand_object *obj_desc0, + union acpi_operand_object *obj_desc1) { + acpi_integer operand0; + acpi_integer operand1; + u8 *ptr0; + u8 *ptr1; + u32 length0; + u32 length1; + u32 i; - switch (opcode) { + ACPI_FUNCTION_ENTRY (); - case AML_LAND_OP: /* LAnd (Operand0, Operand1) */ - if (operand0 && operand1) { - return (TRUE); - } - break; + if (ACPI_GET_OBJECT_TYPE (obj_desc0) == ACPI_TYPE_INTEGER) { + /* Both operands are of type integer */ + operand0 = obj_desc0->integer.value; + operand1 = obj_desc1->integer.value; - case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + switch (opcode) { + case AML_LAND_OP: /* LAnd (Operand0, Operand1) */ - if (operand0 == operand1) { - return (TRUE); - } - break; + if (operand0 && operand1) { + return (TRUE); + } + break; + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ - case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + if (operand0 == operand1) { + return (TRUE); + } + break; - if (operand0 > operand1) { - return (TRUE); - } - break; + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + if (operand0 > operand1) { + return (TRUE); + } + break; - case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ - if (operand0 < operand1) { - return (TRUE); - } - break; + if (operand0 < operand1) { + return (TRUE); + } + break; + case AML_LOR_OP: /* LOr (Operand0, Operand1) */ - case AML_LOR_OP: /* LOr (Operand0, Operand1) */ + if (operand0 || operand1) { + return (TRUE); + } + break; - if (operand0 || operand1) { - return (TRUE); + default: + break; } - break; + } + else { + /* + * Case for Buffer/String objects. + * NOTE: takes advantage of common Buffer/String object fields + */ + length0 = obj_desc0->buffer.length; + ptr0 = obj_desc0->buffer.pointer; + + length1 = obj_desc1->buffer.length; + ptr1 = obj_desc1->buffer.pointer; + + switch (opcode) { + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + + /* Length and all bytes must be equal */ + + if (length0 != length1) { + return (FALSE); + } + + for (i = 0; i < length0; i++) { + if (ptr0[i] != ptr1[i]) { + return (FALSE); + } + } + return (TRUE); - default: - break; + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + /* Lexicographic compare: Scan the 1-to-1 data */ + + for (i = 0; (i < length0) && (i < length1); i++) { + if (ptr0[i] > ptr1[i]) { + return (TRUE); + } + } + + /* Bytes match, now check lengths */ + + if (length0 > length1) { + return (TRUE); + } + + /* Length0 <= Length1 */ + + return (FALSE); + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + + /* Lexicographic compare: Scan the 1-to-1 data */ + + for (i = 0; (i < length0) && (i < length1); i++) { + if (ptr0[i] < ptr1[i]) { + return (TRUE); + } + } + + /* Bytes match, now check lengths */ + + if (length0 < length1) { + return (TRUE); + } + + /* Length0 >= Length1 */ + + return (FALSE); + + default: + break; + } } return (FALSE); diff -Nru a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c --- a/drivers/acpi/executer/exmutex.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/executer/exmutex.c 2004-10-18 14:56:49 -07:00 @@ -54,7 +54,7 @@ * * FUNCTION: acpi_ex_unlink_mutex * - * PARAMETERS: *obj_desc - The mutex to be unlinked + * PARAMETERS: obj_desc - The mutex to be unlinked * * RETURN: Status * @@ -73,6 +73,8 @@ return; } + /* Doubly linked list */ + if (obj_desc->mutex.next) { (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; } @@ -90,8 +92,8 @@ * * FUNCTION: acpi_ex_link_mutex * - * PARAMETERS: *obj_desc - The mutex to be linked - * *list_head - head of the "acquired_mutex" list + * PARAMETERS: obj_desc - The mutex to be linked + * list_head - head of the "acquired_mutex" list * * RETURN: Status * @@ -130,8 +132,8 @@ * * FUNCTION: acpi_ex_acquire_mutex * - * PARAMETERS: *time_desc - The 'time to delay' object descriptor - * *obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op * * RETURN: Status * @@ -173,9 +175,8 @@ return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* - * Support for multiple acquires by the owning thread - */ + /* Support for multiple acquires by the owning thread */ + if (obj_desc->mutex.owner_thread) { /* Special case for Global Lock, allow all threads */ @@ -199,10 +200,11 @@ return_ACPI_STATUS (status); } - /* Have the mutex, update mutex and walk info */ + /* Have the mutex: update mutex and walk info and save the sync_level */ - obj_desc->mutex.owner_thread = walk_state->thread; + obj_desc->mutex.owner_thread = walk_state->thread; obj_desc->mutex.acquisition_depth = 1; + obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level; walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; @@ -218,7 +220,7 @@ * * FUNCTION: acpi_ex_release_mutex * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * * RETURN: Status * @@ -281,9 +283,8 @@ return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* - * Match multiple Acquires with multiple Releases - */ + /* Match multiple Acquires with multiple Releases */ + obj_desc->mutex.acquisition_depth--; if (obj_desc->mutex.acquisition_depth != 0) { /* Just decrement the depth and return */ @@ -299,10 +300,10 @@ status = acpi_ex_system_release_mutex (obj_desc); - /* Update the mutex and walk state */ + /* Update the mutex and walk state, restore sync_level before acquire */ obj_desc->mutex.owner_thread = NULL; - walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; + walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; return_ACPI_STATUS (status); } @@ -312,7 +313,7 @@ * * FUNCTION: acpi_ex_release_all_mutexes * - * PARAMETERS: *mutex_list - Head of the mutex list + * PARAMETERS: mutex_list - Head of the mutex list * * RETURN: Status * @@ -332,9 +333,8 @@ ACPI_FUNCTION_ENTRY (); - /* - * Traverse the list of owned mutexes, releasing each one. - */ + /* Traverse the list of owned mutexes, releasing each one */ + while (next) { this = next; next = this->mutex.next; @@ -352,7 +352,11 @@ /* Mark mutex unowned */ - this->mutex.owner_thread = NULL; + this->mutex.owner_thread = NULL; + + /* Update Thread sync_level (Last mutex is the important one) */ + + thread->current_sync_level = this->mutex.original_sync_level; } } diff -Nru a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c --- a/drivers/acpi/executer/exoparg2.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/acpi/executer/exoparg2.c 2004-10-18 14:56:32 -07:00 @@ -97,6 +97,7 @@ { union acpi_operand_object **operand = &walk_state->operands[0]; struct acpi_namespace_node *node; + u32 value; acpi_status status = AE_OK; @@ -113,16 +114,46 @@ node = (struct acpi_namespace_node *) operand[0]; + /* Second value is the notify value */ + + value = (u32) operand[1]->integer.value; + /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object (node)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unexpected notify object type [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unexpected notify object type [%s]\n", acpi_ut_get_type_name (node->type))); status = AE_AML_OPERAND_TYPE; break; } +#ifdef ACPI_GPE_NOTIFY_CHECK + /* + * GPE method wake/notify check. Here, we want to ensure that we + * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx + * GPE method during system runtime. If we do, the GPE is marked + * as "wake-only" and disabled. + * + * 1) Is the Notify() value == device_wake? + * 2) Is this a GPE deferred method? (An _Lxx or _Exx method) + * 3) Did the original GPE happen at system runtime? + * (versus during wake) + * + * If all three cases are true, this is a wake-only GPE that should + * be disabled at runtime. + */ + if (value == 2) /* device_wake */ { + status = acpi_ev_check_for_wake_only_gpe (walk_state->gpe_event_info); + if (ACPI_FAILURE (status)) { + /* AE_WAKE_ONLY_GPE only error, means ignore this notify */ + + return_ACPI_STATUS (AE_OK) + } + } +#endif + /* * Dispatch the notify to the appropriate handler * NOTE: the request is queued for execution after this method @@ -130,8 +161,7 @@ * from this thread -- because handlers may in turn run other * control methods. */ - status = acpi_ev_queue_notify_request (node, - (u32) operand[1]->integer.value); + status = acpi_ev_queue_notify_request (node, value); break; @@ -543,9 +573,17 @@ * Execute the Opcode */ if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ { + /* Both operands must be of the same type */ + + if (ACPI_GET_OBJECT_TYPE (operand[0]) != + ACPI_GET_OBJECT_TYPE (operand[1])) { + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + logical_result = acpi_ex_do_logical_op (walk_state->opcode, - operand[0]->integer.value, - operand[1]->integer.value); + operand[0], + operand[1]); goto store_logical_result; } diff -Nru a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c --- a/drivers/acpi/executer/exresolv.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/acpi/executer/exresolv.c 2004-10-18 14:56:28 -07:00 @@ -187,15 +187,15 @@ return_ACPI_STATUS (status); } + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] value_obj is %p\n", + stack_desc->reference.offset, obj_desc)); + /* * Now we can delete the original Reference Object and - * replace it with the resolve value + * replace it with the resolved value */ acpi_ut_remove_reference (stack_desc); *stack_ptr = obj_desc; - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %d] value_obj is %p\n", - stack_desc->reference.offset, obj_desc)); break; diff -Nru a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c --- a/drivers/acpi/executer/exstore.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/acpi/executer/exstore.c 2004-10-18 14:56:29 -07:00 @@ -102,7 +102,8 @@ * Storing an object into a Named node. */ status = acpi_ex_store_object_to_node (source_desc, - (struct acpi_namespace_node *) dest_desc, walk_state); + (struct acpi_namespace_node *) dest_desc, walk_state, + ACPI_IMPLICIT_CONVERSION); return_ACPI_STATUS (status); } @@ -153,7 +154,7 @@ /* Storing an object into a Name "container" */ status = acpi_ex_store_object_to_node (source_desc, ref_desc->reference.object, - walk_state); + walk_state, ACPI_IMPLICIT_CONVERSION); break; @@ -399,6 +400,7 @@ * PARAMETERS: source_desc - Value to be stored * Node - Named object to receive the value * walk_state - Current walk state + * implicit_conversion - Perform implicit conversion (yes/no) * * RETURN: Status * @@ -421,7 +423,8 @@ acpi_ex_store_object_to_node ( union acpi_operand_object *source_desc, struct acpi_namespace_node *node, - struct acpi_walk_state *walk_state) + struct acpi_walk_state *walk_state, + u8 implicit_conversion) { acpi_status status = AE_OK; union acpi_operand_object *target_desc; @@ -449,6 +452,14 @@ status = acpi_ex_resolve_object (&source_desc, target_type, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); + } + + /* If no implicit conversion, drop into the default case below */ + + if (!implicit_conversion) { + /* Force execution of default (no implicit conversion) */ + + target_type = ACPI_TYPE_ANY; } /* diff -Nru a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c --- a/drivers/acpi/hardware/hwgpe.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/hardware/hwgpe.c 2004-10-18 14:55:54 -07:00 @@ -51,104 +51,24 @@ /****************************************************************************** * - * FUNCTION: acpi_hw_enable_gpe + * FUNCTION: acpi_hw_write_gpe_enable_reg * * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled * * RETURN: Status * - * DESCRIPTION: Enable a single GPE. + * DESCRIPTION: Write a GPE enable register. Note: The bit for this GPE must + * already be cleared or set in the parent register + * enable_for_run mask. * ******************************************************************************/ acpi_status -acpi_hw_enable_gpe ( - struct acpi_gpe_event_info *gpe_event_info) -{ - u32 in_byte; - acpi_status status; - - - ACPI_FUNCTION_ENTRY (); - - - /* - * Read the current value of the register, set the appropriate bit - * to enable the GPE, and write out the new register. - */ - status = acpi_hw_low_level_read (8, &in_byte, - &gpe_event_info->register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Write with the new GPE bit enabled */ - - status = acpi_hw_low_level_write (8, (in_byte | gpe_event_info->bit_mask), - &gpe_event_info->register_info->enable_address); - - return (status); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_enable_gpe_for_wakeup - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled - * - * RETURN: None - * - * DESCRIPTION: Keep track of which GPEs the OS has requested not be - * disabled when going to sleep. - * - ******************************************************************************/ - -void -acpi_hw_enable_gpe_for_wakeup ( +acpi_hw_write_gpe_enable_reg ( struct acpi_gpe_event_info *gpe_event_info) { struct acpi_gpe_register_info *gpe_register_info; - - - ACPI_FUNCTION_ENTRY (); - - - /* Get the info block for the entire GPE register */ - - gpe_register_info = gpe_event_info->register_info; - if (!gpe_register_info) { - return; - } - - /* - * Set the bit so we will not enable this GPE when sleeping (and disable - * it upon wake) - */ - gpe_register_info->wake_enable |= gpe_event_info->bit_mask; - gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_disable_gpe - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled - * - * RETURN: Status - * - * DESCRIPTION: Disable a single GPE. - * - ******************************************************************************/ - -acpi_status -acpi_hw_disable_gpe ( - struct acpi_gpe_event_info *gpe_event_info) -{ - u32 in_byte; acpi_status status; - struct acpi_gpe_register_info *gpe_register_info; ACPI_FUNCTION_ENTRY (); @@ -158,67 +78,15 @@ gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { - return (AE_BAD_PARAMETER); - } - - /* - * Read the current value of the register, clear the appropriate bit, - * and write out the new register value to disable the GPE. - */ - status = acpi_hw_low_level_read (8, &in_byte, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); + return (AE_NOT_EXIST); } - /* Write the byte with this GPE bit cleared */ + /* Write the entire GPE (runtime) enable register */ - status = acpi_hw_low_level_write (8, (in_byte & ~(gpe_event_info->bit_mask)), + status = acpi_hw_low_level_write (8, gpe_register_info->enable_for_run, &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Make sure this GPE is disabled for wake, also */ - - acpi_hw_disable_gpe_for_wakeup (gpe_event_info); - return (AE_OK); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_disable_gpe_for_wakeup - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled - * - * RETURN: None - * - * DESCRIPTION: Keep track of which GPEs the OS has requested not be - * disabled when going to sleep. - * - ******************************************************************************/ -void -acpi_hw_disable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info) -{ - struct acpi_gpe_register_info *gpe_register_info; - - - ACPI_FUNCTION_ENTRY (); - - - /* Get the info block for the entire GPE register */ - - gpe_register_info = gpe_event_info->register_info; - if (!gpe_register_info) { - return; - } - - /* Clear the bit so we will disable this when sleeping */ - - gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask); + return (status); } @@ -228,7 +96,7 @@ * * PARAMETERS: gpe_event_info - Info block for the GPE to be cleared * - * RETURN: status_status + * RETURN: Status * * DESCRIPTION: Clear the status bit for a single GPE. * @@ -248,7 +116,7 @@ * Write a one to the appropriate bit in the status register to * clear this GPE. */ - status = acpi_hw_low_level_write (8, gpe_event_info->bit_mask, + status = acpi_hw_low_level_write (8, gpe_event_info->register_bit, &gpe_event_info->register_info->status_address); return (status); @@ -274,7 +142,7 @@ acpi_event_status *event_status) { u32 in_byte; - u8 bit_mask; + u8 register_bit; struct acpi_gpe_register_info *gpe_register_info; acpi_status status; acpi_event_status local_event_status = 0; @@ -293,33 +161,28 @@ /* Get the register bitmask for this GPE */ - bit_mask = gpe_event_info->bit_mask; - - /* GPE Enabled? */ + register_bit = gpe_event_info->register_bit; - status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } + /* GPE currently enabled? (enabled for runtime?) */ - if (bit_mask & in_byte) { + if (register_bit & gpe_register_info->enable_for_run) { local_event_status |= ACPI_EVENT_FLAG_ENABLED; } - /* GPE Enabled for wake? */ + /* GPE enabled for wake? */ - if (bit_mask & gpe_register_info->wake_enable) { + if (register_bit & gpe_register_info->enable_for_wake) { local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED; } - /* GPE active (set)? */ + /* GPE currently active (status bit == 1)? */ status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - if (bit_mask & in_byte) { + if (register_bit & in_byte) { local_event_status |= ACPI_EVENT_FLAG_SET; } @@ -411,64 +274,43 @@ /****************************************************************************** * - * FUNCTION: acpi_hw_prepare_gpe_block_for_sleep + * FUNCTION: acpi_hw_enable_runtime_gpe_block * * PARAMETERS: gpe_xrupt_info - GPE Interrupt info * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within - * a single GPE block + * DESCRIPTION: Enable all "runtime" GPEs within a GPE block. (Includes + * combination wake/run GPEs.) * ******************************************************************************/ -static acpi_status -acpi_hw_prepare_gpe_block_for_sleep ( +acpi_status +acpi_hw_enable_runtime_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block) { u32 i; - struct acpi_gpe_register_info *gpe_register_info; - u32 in_value; acpi_status status; - /* Get the register info for the entire GPE block */ - - gpe_register_info = gpe_block->register_info; + /* NOTE: assumes that all GPEs are currently disabled */ /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { - /* - * Read the enabled/disabled status of all GPEs. We - * will be using it to restore all the GPEs later. - * - * NOTE: Wake GPEs are are ALL disabled at this time, so when we wake - * and restore this register, they will be automatically disabled. - */ - status = acpi_hw_low_level_read (8, &in_value, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); + if (!gpe_block->register_info[i].enable_for_run) { + continue; } - gpe_register_info->enable = (u8) in_value; + /* Enable all "runtime" GPEs in this register */ - /* - * 1) Disable all runtime GPEs - * 2) Enable all wakeup GPEs - */ - status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable, - &gpe_register_info->enable_address); + status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_run, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE (status)) { return (status); } - - /* Point to next GPE register */ - - gpe_register_info++; } return (AE_OK); @@ -477,122 +319,125 @@ /****************************************************************************** * - * FUNCTION: acpi_hw_prepare_gpes_for_sleep + * FUNCTION: acpi_hw_enable_wakeup_gpe_block * - * PARAMETERS: None + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs. - * Called with interrupts disabled. The interrupt handler also - * modifies gpe_register_info->Enable, so it should not be - * given the chance to run until after the runtime GPEs are - * re-enabled. + * DESCRIPTION: Enable all "wake" GPEs within a GPE block. (Includes + * combination wake/run GPEs.) * ******************************************************************************/ acpi_status -acpi_hw_prepare_gpes_for_sleep ( - void) +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) { + u32 i; acpi_status status; - ACPI_FUNCTION_ENTRY (); + /* Examine each GPE Register within the block */ + for (i = 0; i < gpe_block->register_count; i++) { + if (!gpe_block->register_info[i].enable_for_wake) { + continue; + } - status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep); - return (status); + /* Enable all "wake" GPEs in this register */ + + status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_wake, + &gpe_block->register_info[i].enable_address); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + return (AE_OK); } /****************************************************************************** * - * FUNCTION: acpi_hw_restore_gpe_block_on_wake + * FUNCTION: acpi_hw_disable_all_gpes * - * PARAMETERS: gpe_xrupt_info - GPE Interrupt info - * gpe_block - Gpe Block info + * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR * * RETURN: Status * - * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one - * GPE block + * DESCRIPTION: Disable and clear all GPEs * ******************************************************************************/ -static acpi_status -acpi_hw_restore_gpe_block_on_wake ( - struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block) +acpi_status +acpi_hw_disable_all_gpes ( + u32 flags) { - u32 i; - struct acpi_gpe_register_info *gpe_register_info; acpi_status status; - /* This callback processes one entire GPE block */ + ACPI_FUNCTION_TRACE ("hw_disable_all_gpes"); - /* Get the register info for the entire GPE block */ - gpe_register_info = gpe_block->register_info; + status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, flags); + status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, flags); + return_ACPI_STATUS (status); +} - /* Examine each GPE register within the block */ - for (i = 0; i < gpe_block->register_count; i++) { - /* Clear the entire status register */ +/****************************************************************************** + * + * FUNCTION: acpi_hw_enable_all_runtime_gpes + * + * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR + * + * RETURN: Status + * + * DESCRIPTION: Enable all GPEs of the given type + * + ******************************************************************************/ - status = acpi_hw_low_level_write (8, 0xFF, - &gpe_block->register_info[i].status_address); - if (ACPI_FAILURE (status)) { - return (status); - } +acpi_status +acpi_hw_enable_all_runtime_gpes ( + u32 flags) +{ + acpi_status status; - /* - * Restore the GPE Enable register, which will do the following: - * - * 1) Disable all wakeup GPEs - * 2) Enable all runtime GPEs - * - * (On sleep, we saved the enabled status of all GPEs) - */ - status = acpi_hw_low_level_write (8, gpe_register_info->enable, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - /* Point to next GPE register */ + ACPI_FUNCTION_TRACE ("hw_enable_all_runtime_gpes"); - gpe_register_info++; - } - return (AE_OK); + status = acpi_ev_walk_gpe_list (acpi_hw_enable_runtime_gpe_block, flags); + return_ACPI_STATUS (status); } /****************************************************************************** * - * FUNCTION: acpi_hw_restore_gpes_on_wake + * FUNCTION: acpi_hw_enable_all_wakeup_gpes * - * PARAMETERS: None + * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR * * RETURN: Status * - * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all - * GPE blocks + * DESCRIPTION: Enable all GPEs of the given type * ******************************************************************************/ acpi_status -acpi_hw_restore_gpes_on_wake ( - void) +acpi_hw_enable_all_wakeup_gpes ( + u32 flags) { acpi_status status; - ACPI_FUNCTION_ENTRY (); + ACPI_FUNCTION_TRACE ("hw_enable_all_wakeup_gpes"); - status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake); - return (status); + status = acpi_ev_walk_gpe_list (acpi_hw_enable_wakeup_gpe_block, flags); + return_ACPI_STATUS (status); } + diff -Nru a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c --- a/drivers/acpi/hardware/hwregs.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/acpi/hardware/hwregs.c 2004-10-18 14:56:50 -07:00 @@ -61,6 +61,7 @@ * RETURN: none * * DESCRIPTION: Clears all fixed and general purpose status bits + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ @@ -103,7 +104,7 @@ /* Clear the GPE Bits in all GPE registers in all GPE blocks */ - status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block); + status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, ACPI_ISR); unlock_and_exit: if (flags & ACPI_MTX_LOCK) { @@ -135,7 +136,7 @@ u8 *sleep_type_b) { acpi_status status = AE_OK; - union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data"); @@ -152,8 +153,9 @@ /* * Evaluate the namespace object containing the values for this state */ + info.parameters = NULL; status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], - NULL, &obj_desc); + &info); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); @@ -163,48 +165,50 @@ /* Must have a return object */ - if (!obj_desc) { + if (!info.return_object) { ACPI_REPORT_ERROR (("Missing Sleep State object\n")); status = AE_NOT_EXIST; } /* It must be of type Package */ - else if (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_PACKAGE) { + else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) { ACPI_REPORT_ERROR (("Sleep State object not a Package\n")); status = AE_AML_OPERAND_TYPE; } /* The package must have at least two elements */ - else if (obj_desc->package.count < 2) { + else if (info.return_object->package.count < 2) { ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n")); status = AE_AML_NO_OPERAND; } /* The first two elements must both be of type Integer */ - else if ((ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) { + else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) != ACPI_TYPE_INTEGER) || + (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) { ACPI_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n", - acpi_ut_get_object_type_name (obj_desc->package.elements[0]), - acpi_ut_get_object_type_name (obj_desc->package.elements[1]))); + acpi_ut_get_object_type_name (info.return_object->package.elements[0]), + acpi_ut_get_object_type_name (info.return_object->package.elements[1]))); status = AE_AML_OPERAND_TYPE; } else { /* * Valid _Sx_ package size, type, and value */ - *sleep_type_a = (u8) (obj_desc->package.elements[0])->integer.value; - *sleep_type_b = (u8) (obj_desc->package.elements[1])->integer.value; + *sleep_type_a = (u8) (info.return_object->package.elements[0])->integer.value; + *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value; } if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", - acpi_gbl_sleep_state_names[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", + acpi_gbl_sleep_state_names[sleep_state], info.return_object, + acpi_ut_get_object_type_name (info.return_object))); } - acpi_ut_remove_reference (obj_desc); + acpi_ut_remove_reference (info.return_object); return_ACPI_STATUS (status); } @@ -245,8 +249,8 @@ * return_value - Value that was read from the register * Flags - Lock the hardware or not * - * RETURN: Value is read from specified Register. Value returned is - * normalized to bit0 (is shifted all the way right) + * RETURN: Status and the value read from specified Register. Value + * returned is normalized to bit0 (is shifted all the way right) * * DESCRIPTION: ACPI bit_register read function. * @@ -280,6 +284,8 @@ } } + /* Read from the register */ + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, bit_reg_info->parent_register, ®ister_value); @@ -309,10 +315,10 @@ * * PARAMETERS: register_id - ID of ACPI bit_register to access * Value - (only used on write) value to write to the - * Register, NOT pre-normalized to the bit pos. + * Register, NOT pre-normalized to the bit pos * Flags - Lock the hardware or not * - * RETURN: None + * RETURN: Status * * DESCRIPTION: ACPI Bit Register write function. * @@ -457,10 +463,11 @@ * * FUNCTION: acpi_hw_register_read * - * PARAMETERS: use_lock - Mutex hw access. - * register_id - register_iD + Offset. + * PARAMETERS: use_lock - Mutex hw access + * register_id - register_iD + Offset + * return_value - Value that was read from the register * - * RETURN: Value read or written. + * RETURN: Status and the value read. * * DESCRIPTION: Acpi register read function. Registers are read at the * given offset. @@ -568,10 +575,11 @@ * * FUNCTION: acpi_hw_register_write * - * PARAMETERS: use_lock - Mutex hw access. - * register_id - register_iD + Offset. + * PARAMETERS: use_lock - Mutex hw access + * register_id - register_iD + Offset + * Value - The value to write * - * RETURN: Value read or written. + * RETURN: Status * * DESCRIPTION: Acpi register Write function. Registers are written at the * given offset. @@ -687,11 +695,11 @@ * * PARAMETERS: Width - 8, 16, or 32 * Value - Where the value is returned - * Register - GAS register structure + * Reg - GAS register structure * * RETURN: Status * - * DESCRIPTION: Read from either memory, IO, or PCI config space. + * DESCRIPTION: Read from either memory or IO space. * ******************************************************************************/ @@ -701,8 +709,6 @@ u32 *value, struct acpi_generic_address *reg) { - struct acpi_pci_id pci_id; - u16 pci_register; acpi_status status; @@ -721,8 +727,8 @@ *value = 0; /* - * Three address spaces supported: - * Memory, IO, or PCI_Config. + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient */ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: @@ -740,19 +746,6 @@ break; - case ACPI_ADR_SPACE_PCI_CONFIG: - - pci_id.segment = 0; - pci_id.bus = 0; - pci_id.device = ACPI_PCI_DEVICE (reg->address); - pci_id.function = ACPI_PCI_FUNCTION (reg->address); - pci_register = (u16) ACPI_PCI_REGISTER (reg->address); - - status = acpi_os_read_pci_configuration (&pci_id, pci_register, - value, width); - break; - - default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); @@ -774,11 +767,11 @@ * * PARAMETERS: Width - 8, 16, or 32 * Value - To be written - * Register - GAS register structure + * Reg - GAS register structure * * RETURN: Status * - * DESCRIPTION: Write to either memory, IO, or PCI config space. + * DESCRIPTION: Write to either memory or IO space. * ******************************************************************************/ @@ -788,8 +781,6 @@ u32 value, struct acpi_generic_address *reg) { - struct acpi_pci_id pci_id; - u16 pci_register; acpi_status status; @@ -807,8 +798,8 @@ } /* - * Three address spaces supported: - * Memory, IO, or PCI_Config. + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient */ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: @@ -823,19 +814,6 @@ status = acpi_os_write_port ((acpi_io_address) reg->address, value, width); - break; - - - case ACPI_ADR_SPACE_PCI_CONFIG: - - pci_id.segment = 0; - pci_id.bus = 0; - pci_id.device = ACPI_PCI_DEVICE (reg->address); - pci_id.function = ACPI_PCI_FUNCTION (reg->address); - pci_register = (u16) ACPI_PCI_REGISTER (reg->address); - - status = acpi_os_write_pci_configuration (&pci_id, pci_register, - (acpi_integer) value, width); break; diff -Nru a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c --- a/drivers/acpi/hardware/hwsleep.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/hardware/hwsleep.c 2004-10-18 14:55:54 -07:00 @@ -265,19 +265,21 @@ sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); - if (sleep_state != ACPI_STATE_S5) { - /* Clear wake status */ + /* Clear wake status */ - status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + /* Clear all fixed and general purpose status bits */ + status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (sleep_state != ACPI_STATE_S5) { /* Disable BM arbitration */ status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); @@ -287,10 +289,16 @@ } /* - * 1) Disable all runtime GPEs + * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_prepare_gpes_for_sleep (); + status = acpi_hw_disable_all_gpes (ACPI_ISR); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = FALSE; + + status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -420,10 +428,16 @@ } /* - * 1) Disable all runtime GPEs + * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_prepare_gpes_for_sleep (); + status = acpi_hw_disable_all_gpes (ACPI_ISR); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = FALSE; + + status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -453,6 +467,7 @@ * RETURN: Status * * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. * ******************************************************************************/ @@ -540,19 +555,25 @@ /* * Restore the GPEs: - * 1) Disable all wakeup GPEs + * 1) Disable/Clear all GPEs * 2) Enable all runtime GPEs */ - status = acpi_hw_restore_gpes_on_wake (); + status = acpi_hw_disable_all_gpes (ACPI_NOT_ISR); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = TRUE; + + status = acpi_hw_enable_all_runtime_gpes (ACPI_NOT_ISR); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Enable power button */ - acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, + (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, 1, ACPI_MTX_DO_NOT_LOCK); - acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, + (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, 1, ACPI_MTX_DO_NOT_LOCK); /* Enable BM arbitration */ diff -Nru a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c --- a/drivers/acpi/hardware/hwtimer.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/acpi/hardware/hwtimer.c 2004-10-18 14:55:55 -07:00 @@ -52,11 +52,11 @@ * * FUNCTION: acpi_get_timer_resolution * - * PARAMETERS: none + * PARAMETERS: Resolution - Where the resolution is returned * - * RETURN: Number of bits of resolution in the PM Timer (24 or 32). + * RETURN: Status and timer resolution * - * DESCRIPTION: Obtains resolution of the ACPI PM Timer. + * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits). * ******************************************************************************/ @@ -86,11 +86,11 @@ * * FUNCTION: acpi_get_timer * - * PARAMETERS: none + * PARAMETERS: Ticks - Where the timer value is returned * - * RETURN: Current value of the ACPI PM Timer (in ticks). + * RETURN: Status and current ticks * - * DESCRIPTION: Obtains current value of ACPI PM Timer. + * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). * ******************************************************************************/ @@ -118,11 +118,11 @@ * * FUNCTION: acpi_get_timer_duration * - * PARAMETERS: start_ticks - * end_ticks - * time_elapsed + * PARAMETERS: start_ticks - Starting timestamp + * end_ticks - End timestamp + * time_elapsed - Where the elapsed time is returned * - * RETURN: time_elapsed + * RETURN: Status and time_elapsed * * DESCRIPTION: Computes the time elapsed (in microseconds) between two * PM Timer time stamps, taking into account the possibility of @@ -136,7 +136,7 @@ * Note that this function accommodates only a single timer * rollover. Thus for 24-bit timers, this function should only * be used for calculating durations less than ~4.6 seconds - * (~20 minutes for 32-bit timers) -- calculations below + * (~20 minutes for 32-bit timers) -- calculations below: * * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes @@ -164,7 +164,6 @@ /* * Compute Tick Delta: - * ------------------- * Handle (max one) timer rollovers on 24- versus 32-bit timers. */ if (start_ticks < end_ticks) { @@ -188,10 +187,7 @@ } /* - * Compute Duration: - * ----------------- - * - * Requires a 64-bit divide: + * Compute Duration (Requires a 64-bit divide): * * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY; */ diff -Nru a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/acpi/motherboard.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,177 @@ +/* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +/* Purpose: Prevent PCMCIA cards from using motherboard resources. */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("acpi_motherboard") + +/* Dell use PNP0C01 instead of PNP0C02 */ +#define ACPI_MB_HID1 "PNP0C01" +#define ACPI_MB_HID2 "PNP0C02" + +/** + * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved + * Doesn't care about the failure of 'request_region', since other may reserve + * the io ports as well + */ +#define IS_RESERVED_ADDR(base, len) \ + (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \ + && ((base) + (len) > PCIBIOS_MIN_IO)) + +/* + * Clearing the flag (IORESOURCE_BUSY) allows drivers to use + * the io ports if they really know they can use it, while + * still preventing hotplug PCI devices from using it. + */ + +static acpi_status +acpi_reserve_io_ranges (struct acpi_resource *res, void *data) +{ + struct resource *requested_res = NULL; + + ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges"); + + if (res->id == ACPI_RSTYPE_IO) { + struct acpi_resource_io *io_res = &res->data.io; + + if (io_res->min_base_address != io_res->max_base_address) + return AE_OK; + if (IS_RESERVED_ADDR(io_res->min_base_address, io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + io_res->min_base_address, + io_res->min_base_address + io_res->range_length)); + requested_res = request_region(io_res->min_base_address, + io_res->range_length, "motherboard"); + } + } else if (res->id == ACPI_RSTYPE_FIXED_IO) { + struct acpi_resource_fixed_io *fixed_io_res = &res->data.fixed_io; + + if (IS_RESERVED_ADDR(fixed_io_res->base_address, fixed_io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + fixed_io_res->base_address, + fixed_io_res->base_address + fixed_io_res->range_length)); + requested_res = request_region(fixed_io_res->base_address, + fixed_io_res->range_length, "motherboard"); + } + } else { + /* Memory mapped IO? */ + } + + if (requested_res) + requested_res->flags &= ~IORESOURCE_BUSY; + return AE_OK; +} + +static int acpi_motherboard_add (struct acpi_device *device) +{ + if (!device) + return -EINVAL; + acpi_walk_resources(device->handle, METHOD_NAME__CRS, + acpi_reserve_io_ranges, NULL); + + return 0; +} + +static struct acpi_driver acpi_motherboard_driver1 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID1, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static struct acpi_driver acpi_motherboard_driver2 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID2, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static void __init +acpi_reserve_resources (void) +{ + if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1a_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1b_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK"); + + if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK"); + + if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4) + request_region(acpi_gbl_FADT->xpm_tmr_blk.address, + 4, "PM_TMR"); + + if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len) + request_region(acpi_gbl_FADT->xpm2_cnt_blk.address, + acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK"); + + /* Length of GPE blocks must be a non-negative multiple of 2 */ + + if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len && + !(acpi_gbl_FADT->gpe0_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe0_blk.address, + acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK"); + + if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len && + !(acpi_gbl_FADT->gpe1_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe1_blk.address, + acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK"); +} + +static int __init acpi_motherboard_init(void) +{ + acpi_bus_register_driver(&acpi_motherboard_driver1); + acpi_bus_register_driver(&acpi_motherboard_driver2); + /* + * Guarantee motherboard IO reservation first + * This module must run after scan.c + */ + if (!acpi_disabled) + acpi_reserve_resources (); + return 0; +} + +/** + * Reserve motherboard resources after PCI claim BARs, + * but before PCI assign resources for uninitialized PCI devices + */ +fs_initcall(acpi_motherboard_init); diff -Nru a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c --- a/drivers/acpi/namespace/nsaccess.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/acpi/namespace/nsaccess.c 2004-10-18 14:57:04 -07:00 @@ -193,7 +193,7 @@ case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; - obj_desc->mutex.sync_level = (u16) ACPI_STRTOUL + obj_desc->mutex.sync_level = (u8) ACPI_STRTOUL (val, NULL, 10); if (ACPI_STRCMP (init_val->name, "_GL_") == 0) { diff -Nru a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c --- a/drivers/acpi/namespace/nsalloc.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/acpi/namespace/nsalloc.c 2004-10-18 14:56:32 -07:00 @@ -267,7 +267,7 @@ else { #ifdef ACPI_ALPHABETIC_NAMESPACE /* - * Walk the list whilst searching for the the correct + * Walk the list whilst searching for the correct * alphabetic placement. */ previous_child_node = NULL; diff -Nru a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c --- a/drivers/acpi/namespace/nseval.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/acpi/namespace/nseval.c 2004-10-18 14:56:29 -07:00 @@ -77,13 +77,10 @@ acpi_status acpi_ns_evaluate_relative ( - struct acpi_namespace_node *handle, char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { acpi_status status; - struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *node = NULL; union acpi_generic_state *scope_info; char *internal_path = NULL; @@ -95,7 +92,7 @@ /* * Must have a valid object handle */ - if (!handle) { + if (!info || !info->node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -118,8 +115,8 @@ goto cleanup; } - prefix_node = acpi_ns_map_handle_to_node (handle); - if (!prefix_node) { + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); status = AE_BAD_PARAMETER; goto cleanup; @@ -127,7 +124,7 @@ /* Lookup the name in the namespace */ - scope_info->scope.node = prefix_node; + scope_info->scope.node = info->node; status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, &node); @@ -147,7 +144,8 @@ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", pathname, node, acpi_ns_get_attached_object (node))); - status = acpi_ns_evaluate_by_handle (node, params, return_object); + info->node = node; + status = acpi_ns_evaluate_by_handle (info); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); @@ -166,6 +164,7 @@ * FUNCTION: acpi_ns_evaluate_by_name * * PARAMETERS: Pathname - Fully qualified pathname to the object + * Info - Contains: * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * Params - List of parameters to pass to the method, @@ -184,11 +183,9 @@ acpi_status acpi_ns_evaluate_by_name ( char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { acpi_status status; - struct acpi_namespace_node *node = NULL; char *internal_path = NULL; @@ -211,7 +208,7 @@ status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, - &node); + &info->node); (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); @@ -226,9 +223,9 @@ * to evaluate it. */ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", - pathname, node, acpi_ns_get_attached_object (node))); + pathname, info->node, acpi_ns_get_attached_object (info->node))); - status = acpi_ns_evaluate_by_handle (node, params, return_object); + status = acpi_ns_evaluate_by_handle (info); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); @@ -254,6 +251,7 @@ * Params - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. + * param_type - Type of Parameter list * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * @@ -267,13 +265,9 @@ acpi_status acpi_ns_evaluate_by_handle ( - struct acpi_namespace_node *handle, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { - struct acpi_namespace_node *node; acpi_status status; - union acpi_operand_object *local_return_object; ACPI_FUNCTION_TRACE ("ns_evaluate_by_handle"); @@ -287,15 +281,13 @@ /* Parameter Validation */ - if (!handle) { + if (!info) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - if (return_object) { - /* Initialize the return value to an invalid object */ + /* Initialize the return value to an invalid object */ - *return_object = NULL; - } + info->return_object = NULL; /* Get the prefix handle and Node */ @@ -304,8 +296,8 @@ return_ACPI_STATUS (status); } - node = acpi_ns_map_handle_to_node (handle); - if (!node) { + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -315,8 +307,8 @@ * so that proper scoping context will be established * before execution. */ - if (acpi_ns_get_type (node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { - node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object); + if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { + info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object); } /* @@ -328,19 +320,18 @@ * In both cases, the namespace is unlocked by the * acpi_ns* procedure */ - if (acpi_ns_get_type (node) == ACPI_TYPE_METHOD) { + if (acpi_ns_get_type (info->node) == ACPI_TYPE_METHOD) { /* * Case 1) We have an actual control method to execute */ - status = acpi_ns_execute_control_method (node, params, - &local_return_object); + status = acpi_ns_execute_control_method (info); } else { /* * Case 2) Object is NOT a method, just return its * current value */ - status = acpi_ns_get_object_value (node, &local_return_object); + status = acpi_ns_get_object_value (info); } /* @@ -348,20 +339,6 @@ * be dealt with */ if (status == AE_CTRL_RETURN_VALUE) { - /* - * If the Method returned a value and the caller - * provided a place to store a returned value, Copy - * the returned value to the object descriptor provided - * by the caller. - */ - if (return_object) { - /* - * Valid return object, copy the pointer to - * the returned object - */ - *return_object = local_return_object; - } - /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ status = AE_OK; @@ -396,9 +373,7 @@ acpi_status acpi_ns_execute_control_method ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status; union acpi_operand_object *obj_desc; @@ -409,7 +384,7 @@ /* Verify that there is a method associated with this object */ - obj_desc = acpi_ns_get_attached_object (method_node); + obj_desc = acpi_ns_get_attached_object (info->node); if (!obj_desc) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No attached method object\n")); @@ -417,7 +392,7 @@ return_ACPI_STATUS (AE_NULL_OBJECT); } - ACPI_DUMP_PATHNAME (method_node, "Execute Method:", + ACPI_DUMP_PATHNAME (info->node, "Execute Method:", ACPI_LV_INFO, _COMPONENT); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %X\n", @@ -444,7 +419,7 @@ return_ACPI_STATUS (status); } - status = acpi_psx_execute (method_node, params, return_obj_desc); + status = acpi_psx_execute (info); acpi_ex_exit_interpreter (); return_ACPI_STATUS (status); @@ -468,11 +443,10 @@ acpi_status acpi_ns_get_object_value ( - struct acpi_namespace_node *node, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status = AE_OK; - struct acpi_namespace_node *resolved_node = node; + struct acpi_namespace_node *resolved_node = info->node; ACPI_FUNCTION_TRACE ("ns_get_object_value"); @@ -518,9 +492,9 @@ if (ACPI_SUCCESS (status)) { status = AE_CTRL_RETURN_VALUE; - *return_obj_desc = ACPI_CAST_PTR (union acpi_operand_object, resolved_node); + info->return_object = ACPI_CAST_PTR (union acpi_operand_object, resolved_node); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n", - *return_obj_desc, acpi_ut_get_object_type_name (*return_obj_desc))); + info->return_object, acpi_ut_get_object_type_name (info->return_object))); } } diff -Nru a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c --- a/drivers/acpi/namespace/nsinit.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/acpi/namespace/nsinit.c 2004-10-18 14:56:28 -07:00 @@ -149,7 +149,7 @@ return_ACPI_STATUS (status); } - /* Walk namespace for all objects of type Device or Processor */ + /* Walk namespace for all objects */ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL); @@ -337,25 +337,29 @@ void *context, void **return_value) { - acpi_status status; - struct acpi_namespace_node *node; - u32 flags; struct acpi_device_walk_info *info = (struct acpi_device_walk_info *) context; + struct acpi_parameter_info pinfo; + u32 flags; + acpi_status status; ACPI_FUNCTION_TRACE ("ns_init_one_device"); - node = acpi_ns_map_handle_to_node (obj_handle); - if (!node) { + pinfo.parameters = NULL; + pinfo.parameter_type = ACPI_PARAM_ARGS; + + pinfo.node = acpi_ns_map_handle_to_node (obj_handle); + if (!pinfo.node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* - * We will run _STA/_INI on Devices and Processors only + * We will run _STA/_INI on Devices, Processors and thermal_zones only */ - if ((node->type != ACPI_TYPE_DEVICE) && - (node->type != ACPI_TYPE_PROCESSOR)) { + if ((pinfo.node->type != ACPI_TYPE_DEVICE) && + (pinfo.node->type != ACPI_TYPE_PROCESSOR) && + (pinfo.node->type != ACPI_TYPE_THERMAL)) { return_ACPI_STATUS (AE_OK); } @@ -368,17 +372,17 @@ /* * Run _STA to determine if we can run _INI on the device. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, node, "_STA")); - status = acpi_ut_execute_STA (node, &flags); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA")); + status = acpi_ut_execute_STA (pinfo.node, &flags); if (ACPI_FAILURE (status)) { - if (node->type == ACPI_TYPE_DEVICE) { + if (pinfo.node->type == ACPI_TYPE_DEVICE) { /* Ignore error and move on to next device */ return_ACPI_STATUS (AE_OK); } - /* _STA is not required for Processor objects */ + /* _STA is not required for Processor or thermal_zone objects */ } else { info->num_STA++; @@ -393,22 +397,22 @@ /* * The device is present. Run _INI. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, obj_handle, "_INI")); - status = acpi_ns_evaluate_relative (obj_handle, "_INI", NULL, NULL); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI")); + status = acpi_ns_evaluate_relative ("_INI", &pinfo); if (ACPI_FAILURE (status)) { /* No _INI (AE_NOT_FOUND) means device requires no initialization */ if (status != AE_NOT_FOUND) { /* Ignore error and move on to next device */ - #ifdef ACPI_DEBUG_OUTPUT - char *scope_name = acpi_ns_get_external_pathname (obj_handle); +#ifdef ACPI_DEBUG_OUTPUT + char *scope_name = acpi_ns_get_external_pathname (pinfo.node); ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n", scope_name, acpi_format_exception (status))); ACPI_MEM_FREE (scope_name); - #endif +#endif } status = AE_OK; @@ -422,7 +426,7 @@ if (acpi_gbl_init_handler) { /* External initialization handler is present, call it */ - status = acpi_gbl_init_handler (obj_handle, ACPI_INIT_DEVICE_INI); + status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI); } diff -Nru a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c --- a/drivers/acpi/namespace/nsparse.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/acpi/namespace/nsparse.c 2004-10-18 14:55:55 -07:00 @@ -94,8 +94,9 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL, table_desc->aml_start, - table_desc->aml_length, NULL, NULL, pass_number); + status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL, + table_desc->aml_start, table_desc->aml_length, + NULL, pass_number); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); diff -Nru a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c --- a/drivers/acpi/namespace/nsxfeval.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/acpi/namespace/nsxfeval.c 2004-10-18 14:57:04 -07:00 @@ -174,8 +174,7 @@ { acpi_status status; acpi_status status2; - union acpi_operand_object **internal_params = NULL; - union acpi_operand_object *internal_return_obj = NULL; + struct acpi_parameter_info info; acpi_size buffer_space_needed; u32 i; @@ -183,6 +182,11 @@ ACPI_FUNCTION_TRACE ("acpi_evaluate_object"); + info.node = handle; + info.parameters = NULL; + info.return_object = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + /* * If there are parameters to be passed to the object * (which must be a control method), the external objects @@ -193,9 +197,10 @@ * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ - internal_params = ACPI_MEM_CALLOCATE (((acpi_size) external_params->count + 1) * - sizeof (void *)); - if (!internal_params) { + info.parameters = ACPI_MEM_CALLOCATE ( + ((acpi_size) external_params->count + 1) * + sizeof (void *)); + if (!info.parameters) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -205,15 +210,16 @@ */ for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], - &internal_params[i]); + &info.parameters[i]); if (ACPI_FAILURE (status)) { - acpi_ut_delete_internal_object_list (internal_params); + acpi_ut_delete_internal_object_list (info.parameters); return_ACPI_STATUS (status); } } - internal_params[external_params->count] = NULL; + info.parameters[external_params->count] = NULL; } + /* * Three major cases: * 1) Fully qualified pathname @@ -225,8 +231,7 @@ /* * The path is fully qualified, just evaluate by name */ - status = acpi_ns_evaluate_by_name (pathname, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_by_name (pathname, &info); } else if (!handle) { /* @@ -256,15 +261,13 @@ * The null pathname case means the handle is for * the actual object to be evaluated */ - status = acpi_ns_evaluate_by_handle (handle, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_by_handle (&info); } else { /* * Both a Handle and a relative Pathname */ - status = acpi_ns_evaluate_relative (handle, pathname, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_relative (pathname, &info); } } @@ -274,11 +277,11 @@ * copy the return value to an external object. */ if (return_buffer) { - if (!internal_return_obj) { + if (!info.return_object) { return_buffer->length = 0; } else { - if (ACPI_GET_DESCRIPTOR_TYPE (internal_return_obj) == ACPI_DESC_TYPE_NAMED) { + if (ACPI_GET_DESCRIPTOR_TYPE (info.return_object) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to @@ -288,7 +291,7 @@ * support for various types at a later date if necessary. */ status = AE_TYPE; - internal_return_obj = NULL; /* No need to delete a NS Node */ + info.return_object = NULL; /* No need to delete a NS Node */ return_buffer->length = 0; } @@ -297,7 +300,7 @@ * Find out how large a buffer is needed * to contain the returned object */ - status = acpi_ut_get_object_size (internal_return_obj, + status = acpi_ut_get_object_size (info.return_object, &buffer_space_needed); if (ACPI_SUCCESS (status)) { /* Validate/Allocate/Clear caller buffer */ @@ -309,13 +312,14 @@ */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Needed buffer size %X, %s\n", - (u32) buffer_space_needed, acpi_format_exception (status))); + (u32) buffer_space_needed, + acpi_format_exception (status))); } else { /* * We have enough space for the object, build it */ - status = acpi_ut_copy_iobject_to_eobject (internal_return_obj, + status = acpi_ut_copy_iobject_to_eobject (info.return_object, return_buffer); } } @@ -323,7 +327,7 @@ } } - if (internal_return_obj) { + if (info.return_object) { /* * Delete the internal return object. NOTE: Interpreter * must be locked to avoid race condition. @@ -334,7 +338,7 @@ * Delete the internal return object. (Or at least * decrement the reference count by one) */ - acpi_ut_remove_reference (internal_return_obj); + acpi_ut_remove_reference (info.return_object); acpi_ex_exit_interpreter (); } } @@ -342,10 +346,10 @@ /* * Free the input parameter list (if we created one), */ - if (internal_params) { + if (info.parameters) { /* Free the allocated parameter block */ - acpi_ut_delete_internal_object_list (internal_params); + acpi_ut_delete_internal_object_list (info.parameters); } return_ACPI_STATUS (status); diff -Nru a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c --- a/drivers/acpi/namespace/nsxfname.c 2004-10-18 14:56:19 -07:00 +++ b/drivers/acpi/namespace/nsxfname.c 2004-10-18 14:56:19 -07:00 @@ -281,7 +281,7 @@ if (info.type == ACPI_TYPE_DEVICE) { /* * Get extra info for ACPI Devices objects only: - * Run the Device _HID, _UID, _CID, _STA, and _ADR methods. + * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info.Valid bitfield is used @@ -330,7 +330,7 @@ status = acpi_ut_execute_sxds (node, info.highest_dstates); if (ACPI_SUCCESS (status)) { - info.valid |= ACPI_VALID_STA; + info.valid |= ACPI_VALID_SXDS; } status = AE_OK; diff -Nru a/drivers/acpi/numa.c b/drivers/acpi/numa.c --- a/drivers/acpi/numa.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/numa.c 2004-10-18 14:56:49 -07:00 @@ -51,6 +51,7 @@ switch (header->type) { case ACPI_SRAT_PROCESSOR_AFFINITY: +#ifdef ACPI_DEBUG_OUTPUT { struct acpi_table_processor_affinity *p = (struct acpi_table_processor_affinity*) header; @@ -58,9 +59,11 @@ p->apic_id, p->lsapic_eid, p->proximity_domain, p->flags.enabled?"enabled":"disabled")); } +#endif /* ACPI_DEBUG_OUTPUT */ break; case ACPI_SRAT_MEMORY_AFFINITY: +#ifdef ACPI_DEBUG_OUTPUT { struct acpi_table_memory_affinity *p = (struct acpi_table_memory_affinity*) header; @@ -70,6 +73,7 @@ p->flags.enabled ? "enabled" : "disabled", p->flags.hot_pluggable ? " hot-pluggable" : "")); } +#endif /* ACPI_DEBUG_OUTPUT */ break; default: @@ -94,8 +98,6 @@ /* downcast just for %llu vs %lu for i386/ia64 */ localities = (u32) slit->localities; - printk(KERN_INFO PREFIX "SLIT localities %ux%u\n", localities, localities); - acpi_numa_slit_init(slit); return 0; @@ -103,7 +105,9 @@ static int __init -acpi_parse_processor_affinity (acpi_table_entry_header *header) +acpi_parse_processor_affinity ( + acpi_table_entry_header *header, + const unsigned long end) { struct acpi_table_processor_affinity *processor_affinity; @@ -121,7 +125,9 @@ static int __init -acpi_parse_memory_affinity (acpi_table_entry_header *header) +acpi_parse_memory_affinity ( + acpi_table_entry_header *header, + const unsigned long end) { struct acpi_table_memory_affinity *memory_affinity; @@ -147,8 +153,6 @@ return -EINVAL; srat = (struct acpi_table_srat *) __va(phys_addr); - - printk(KERN_INFO PREFIX "SRAT revision %d\n", srat->table_revision); return 0; } diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c --- a/drivers/acpi/osl.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/osl.c 2004-10-18 14:56:49 -07:00 @@ -51,10 +51,13 @@ struct acpi_os_dpc { - OSD_EXECUTION_CALLBACK function; + acpi_osd_exec_callback function; void *context; }; +#ifdef CONFIG_ACPI_CUSTOM_DSDT +#include CONFIG_ACPI_CUSTOM_DSDT_FILE +#endif #ifdef ENABLE_DEBUGGER #include @@ -64,13 +67,19 @@ #endif /*ENABLE_DEBUGGER*/ static unsigned int acpi_irq_irq; -static OSD_HANDLER acpi_irq_handler; +static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; acpi_status acpi_os_initialize(void) { + return AE_OK; +} + +acpi_status +acpi_os_initialize1(void) +{ /* * Initialize PCI configuration space access, as we'll need to access * it while walking the namespace (bus 0 and root bridges w/ _BBNs). @@ -165,11 +174,11 @@ } acpi_status -acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void **virt) +acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void __iomem **virt) { if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys)) { - *virt = phys_to_virt(phys); + *virt = (void __iomem *) phys_to_virt(phys); } else { *virt = ioremap(phys, size); } @@ -191,7 +200,7 @@ } void -acpi_os_unmap_memory(void *virt, acpi_size size) +acpi_os_unmap_memory(void __iomem *virt, acpi_size size) { iounmap(virt); } @@ -235,7 +244,14 @@ if (!existing_table || !new_table) return AE_BAD_PARAMETER; +#ifdef CONFIG_ACPI_CUSTOM_DSDT + if (strncmp(existing_table->signature, "DSDT", 4) == 0) + *new_table = (struct acpi_table_header*)AmlCode; + else + *new_table = NULL; +#else *new_table = NULL; +#endif return AE_OK; } @@ -246,7 +262,7 @@ } acpi_status -acpi_os_install_interrupt_handler(u32 gsi, OSD_HANDLER handler, void *context) +acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *context) { unsigned int irq; @@ -274,7 +290,7 @@ } acpi_status -acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler) +acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) { if (irq) { free_irq(irq, acpi_irq); @@ -370,30 +386,31 @@ u32 width) { u32 dummy; - void *virt_addr; + void __iomem *virt_addr; int iomem = 0; if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { - virt_addr = phys_to_virt(phys_addr); + /* HACK ALERT! We can use readb/w/l on real memory too.. */ + virt_addr = (void __iomem *) phys_to_virt(phys_addr); } else { iomem = 1; virt_addr = ioremap(phys_addr, width); } } else - virt_addr = phys_to_virt(phys_addr); + virt_addr = (void __iomem *) phys_to_virt(phys_addr); if (!value) value = &dummy; switch (width) { case 8: - *(u8*) value = *(u8*) virt_addr; + *(u8*) value = readb(virt_addr); break; case 16: - *(u16*) value = *(u16*) virt_addr; + *(u16*) value = readw(virt_addr); break; case 32: - *(u32*) value = *(u32*) virt_addr; + *(u32*) value = readl(virt_addr); break; default: BUG(); @@ -413,28 +430,29 @@ u32 value, u32 width) { - void *virt_addr; + void __iomem *virt_addr; int iomem = 0; if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { - virt_addr = phys_to_virt(phys_addr); + /* HACK ALERT! We can use writeb/w/l on real memory too */ + virt_addr = (void __iomem *) phys_to_virt(phys_addr); } else { iomem = 1; virt_addr = ioremap(phys_addr, width); } } else - virt_addr = phys_to_virt(phys_addr); + virt_addr = (void __iomem *) phys_to_virt(phys_addr); switch (width) { case 8: - *(u8*) virt_addr = value; + writeb(value, virt_addr); break; case 16: - *(u16*) virt_addr = value; + writew(value, virt_addr); break; case 32: - *(u32*) virt_addr = value; + writel(value, virt_addr); break; default: BUG(); @@ -470,6 +488,8 @@ return AE_ERROR; } + BUG_ON(!raw_pci_ops); + result = raw_pci_ops->read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value); @@ -496,6 +516,8 @@ return AE_ERROR; } + BUG_ON(!raw_pci_ops); + result = raw_pci_ops->write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value); @@ -624,7 +646,7 @@ acpi_status acpi_os_queue_for_execution( u32 priority, - OSD_EXECUTION_CALLBACK function, + acpi_osd_exec_callback function, void *context) { acpi_status status = AE_OK; @@ -952,7 +974,7 @@ { #if defined(__i386__) || defined(__x86_64__) char tmp; - return !__get_user(tmp, (char *)ptr) && !__get_user(tmp, (char *)ptr + len - 1); + return !__get_user(tmp, (char __user *)ptr) && !__get_user(tmp, (char __user *)ptr + len - 1); #endif return 1; } @@ -1066,15 +1088,15 @@ * Run-time events on the same GPE this flag is available * to tell Linux to keep the wake-time GPEs enabled at run-time. */ -static int __init -acpi_leave_gpes_disabled_setup(char *str) +int __init +acpi_wake_gpes_always_on_setup(char *str) { - printk(KERN_INFO PREFIX "leave wake GPEs disabled\n"); + printk(KERN_INFO PREFIX "wake GPEs not disabled\n"); - acpi_gbl_leave_wake_gpes_disabled = TRUE; + acpi_gbl_leave_wake_gpes_disabled = FALSE; return 1; } -__setup("acpi_leave_gpes_disabled", acpi_leave_gpes_disabled_setup); +__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); diff -Nru a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c --- a/drivers/acpi/parser/psopcode.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/acpi/parser/psopcode.c 2004-10-18 14:56:13 -07:00 @@ -251,7 +251,7 @@ #define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) #define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) #define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) +#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) #define ARGI_DEBUG_OP ARG_NONE #define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) #define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) @@ -270,10 +270,10 @@ #define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE #define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) #define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) #define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE #define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE diff -Nru a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c --- a/drivers/acpi/parser/psxface.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/parser/psxface.c 2004-10-18 14:56:49 -07:00 @@ -57,7 +57,7 @@ * * FUNCTION: acpi_psx_execute * - * PARAMETERS: method_node - A method object containing both the AML + * PARAMETERS: Info->Node - A method object containing both the AML * address and length. * **Params - List of parameters to pass to method, * terminated by NULL. Params itself may be @@ -73,9 +73,7 @@ acpi_status acpi_psx_execute ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status; union acpi_operand_object *obj_desc; @@ -89,29 +87,30 @@ /* Validate the Node and get the attached object */ - if (!method_node) { + if (!info || !info->node) { return_ACPI_STATUS (AE_NULL_ENTRY); } - obj_desc = acpi_ns_get_attached_object (method_node); + obj_desc = acpi_ns_get_attached_object (info->node); if (!obj_desc) { return_ACPI_STATUS (AE_NULL_OBJECT); } /* Init for new method, wait on concurrency semaphore */ - status = acpi_ds_begin_method_execution (method_node, obj_desc, NULL); + status = acpi_ds_begin_method_execution (info->node, obj_desc, NULL); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - if (params) { + if ((info->parameter_type == ACPI_PARAM_ARGS) && + (info->parameters)) { /* * The caller "owns" the parameters, so give each one an extra * reference */ - for (i = 0; params[i]; i++) { - acpi_ut_add_reference (params[i]); + for (i = 0; info->parameters[i]; i++) { + acpi_ut_add_reference (info->parameters[i]); } } @@ -121,7 +120,7 @@ */ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Parse **** Entry=%p obj=%p\n", - method_node, obj_desc)); + info->node, obj_desc)); /* Create and init a Root Node */ @@ -147,8 +146,9 @@ goto cleanup2; } - status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, NULL, NULL, 1); + status = acpi_ds_init_aml_walk (walk_state, op, info->node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE (status)) { goto cleanup3; } @@ -159,7 +159,6 @@ acpi_ps_delete_parse_tree (op); if (ACPI_FAILURE (status)) { goto cleanup1; /* Walk state is already deleted */ - } /* @@ -167,7 +166,7 @@ */ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Execution **** Entry=%p obj=%p\n", - method_node, obj_desc)); + info->node, obj_desc)); /* Create and init a Root Node */ @@ -179,8 +178,8 @@ /* Init new op with the method name and pointer back to the NS node */ - acpi_ps_set_name (op, method_node->name.integer); - op->common.node = method_node; + acpi_ps_set_name (op, info->node->name.integer); + op->common.node = info->node; /* Create and initialize a new walk state */ @@ -190,8 +189,9 @@ goto cleanup2; } - status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, params, return_obj_desc, 3); + status = acpi_ds_init_aml_walk (walk_state, op, info->node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, info, 3); if (ACPI_FAILURE (status)) { goto cleanup3; } @@ -210,13 +210,14 @@ acpi_ps_delete_parse_tree (op); cleanup1: - if (params) { + if ((info->parameter_type == ACPI_PARAM_ARGS) && + (info->parameters)) { /* Take away the extra reference that we gave the parameters above */ - for (i = 0; params[i]; i++) { + for (i = 0; info->parameters[i]; i++) { /* Ignore errors, just do them all */ - (void) acpi_ut_update_object_reference (params[i], REF_DECREMENT); + (void) acpi_ut_update_object_reference (info->parameters[i], REF_DECREMENT); } } @@ -228,10 +229,10 @@ * If the method has returned an object, signal this to the caller with * a control exception code */ - if (*return_obj_desc) { + if (info->return_object) { ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned obj_desc=%p\n", - *return_obj_desc)); - ACPI_DUMP_STACK_ENTRY (*return_obj_desc); + info->return_object)); + ACPI_DUMP_STACK_ENTRY (info->return_object); status = AE_CTRL_RETURN_VALUE; } diff -Nru a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c --- a/drivers/acpi/pci_link.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/pci_link.c 2004-10-18 14:55:54 -07:00 @@ -29,6 +29,7 @@ * for IRQ management (e.g. start()->_SRS). */ +#include #include #include #include @@ -71,7 +72,7 @@ u8 active; /* Current IRQ */ u8 edge_level; /* All IRQs */ u8 active_high_low; /* All IRQs */ - u8 setonboot; + u8 initialized; u8 resource_type; u8 possible_count; u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; @@ -447,7 +448,7 @@ #define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) #define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) -static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = { +static int acpi_irq_penalty[ACPI_MAX_IRQS] = { PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ @@ -467,7 +468,7 @@ /* >IRQ15 */ }; -int +int __init acpi_irq_penalty_init(void) { struct list_head *node = NULL; @@ -517,7 +518,7 @@ ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); - if (link->irq.setonboot) + if (link->irq.initialized) return_VALUE(0); /* @@ -571,7 +572,7 @@ acpi_device_bid(link->device), link->irq.active); } - link->irq.setonboot = 1; + link->irq.initialized = 1; return_VALUE(0); } @@ -695,6 +696,42 @@ static int +acpi_pci_link_resume ( + struct acpi_pci_link *link) +{ + ACPI_FUNCTION_TRACE("acpi_pci_link_resume"); + + if (link->irq.active && link->irq.initialized) + return_VALUE(acpi_pci_link_set(link, link->irq.active)); + else + return_VALUE(0); +} + + +static int +irqrouter_resume( + struct sys_device *dev) +{ + struct list_head *node = NULL; + struct acpi_pci_link *link = NULL; + + ACPI_FUNCTION_TRACE("irqrouter_resume"); + + list_for_each(node, &acpi_link.entries) { + + link = list_entry(node, struct acpi_pci_link, node); + if (!link) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); + continue; + } + + acpi_pci_link_resume(link); + } + return_VALUE(0); +} + + +static int acpi_pci_link_remove ( struct acpi_device *device, int type) @@ -786,11 +823,42 @@ __setup("acpi_irq_balance", acpi_irq_balance_set); +static struct sysdev_class irqrouter_sysdev_class = { + set_kset_name("irqrouter"), + .resume = irqrouter_resume, +}; + + +static struct sys_device device_irqrouter = { + .id = 0, + .cls = &irqrouter_sysdev_class, +}; + + +static int __init irqrouter_init_sysfs(void) +{ + int error; + + ACPI_FUNCTION_TRACE("irqrouter_init_sysfs"); + + if (acpi_disabled || acpi_noirq) + return_VALUE(0); + + error = sysdev_class_register(&irqrouter_sysdev_class); + if (!error) + error = sysdev_register(&device_irqrouter); + + return_VALUE(error); +} + +device_initcall(irqrouter_init_sysfs); + + static int __init acpi_pci_link_init (void) { ACPI_FUNCTION_TRACE("acpi_pci_link_init"); - if (acpi_pci_disabled) + if (acpi_noirq) return_VALUE(0); acpi_link.count = 0; diff -Nru a/drivers/acpi/power.c b/drivers/acpi/power.c --- a/drivers/acpi/power.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/acpi/power.c 2004-10-18 14:56:32 -07:00 @@ -288,6 +288,86 @@ return_VALUE(0); } +/* + * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): + * 1. Power on the power resources required for the wakeup device + * 2. Enable _PSW (power state wake) for the device if present + */ +int acpi_enable_wakeup_device_power (struct acpi_device *dev) +{ + union acpi_object arg = {ACPI_TYPE_INTEGER}; + struct acpi_object_list arg_list = {1, &arg}; + acpi_status status = AE_OK; + int i; + int ret = 0; + + ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_power"); + if (!dev || !dev->wakeup.flags.valid) + return -1; + + arg.integer.value = 1; + /* Open power resource */ + for (i = 0; i < dev->wakeup.resources.count; i++) { + ret = acpi_power_on(dev->wakeup.resources.handles[i]); + if (ret) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error transition power state\n")); + dev->wakeup.flags.valid = 0; + return -1; + } + } + + /* Execute PSW */ + status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); + if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n")); + dev->wakeup.flags.valid = 0; + ret = -1; + } + + return ret; +} + +/* + * Shutdown a wakeup device, counterpart of above method + * 1. Disable _PSW (power state wake) + * 2. Shutdown down the power resources + */ +int acpi_disable_wakeup_device_power (struct acpi_device *dev) +{ + union acpi_object arg = {ACPI_TYPE_INTEGER}; + struct acpi_object_list arg_list = {1, &arg}; + acpi_status status = AE_OK; + int i; + int ret = 0; + + ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device_power"); + + if (!dev || !dev->wakeup.flags.valid) + return -1; + + arg.integer.value = 0; + /* Execute PSW */ + status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); + if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n")); + dev->wakeup.flags.valid = 0; + return -1; + } + + /* Close power resource */ + for (i = 0; i < dev->wakeup.resources.count; i++) { + ret = acpi_power_off_device(dev->wakeup.resources.handles[i]); + if (ret) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error transition power state\n")); + dev->wakeup.flags.valid = 0; + return -1; + } + } + + return ret; +} /* -------------------------------------------------------------------------- Device Power Management diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/acpi/processor.c 2004-10-18 14:56:48 -07:00 @@ -44,6 +44,9 @@ #include #include #include +#include +#include +#include #include #include @@ -859,7 +862,6 @@ * _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; @@ -1047,6 +1049,8 @@ if (!pr || !pr->performance || !pr->handle) return_VALUE(-EINVAL); + acpi_processor_set_pdc(pr); + status = acpi_get_handle(pr->handle, "_PCT", &handle); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -1054,8 +1058,6 @@ return_VALUE(-ENODEV); } - acpi_processor_set_pdc(pr); - result = acpi_processor_get_performance_control(pr); if (result) return_VALUE(result); @@ -1121,7 +1123,7 @@ PDE(inode)->data); } -static int +static ssize_t acpi_processor_write_performance ( struct file *file, const char __user *buffer, @@ -2146,6 +2148,37 @@ return_VALUE(0); } +/* Use the acpiid in MADT to map cpus in case of SMP */ +#ifndef CONFIG_SMP +#define convert_acpiid_to_cpu(acpi_id) (0xff) +#else + +#ifdef CONFIG_IA64 +#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid +#define arch_cpu_to_apicid ia64_cpu_to_sapicid +#define ARCH_BAD_APICID (0xffff) +#else +#define arch_acpiid_to_apicid x86_acpiid_to_apicid +#define arch_cpu_to_apicid x86_cpu_to_apicid +#define ARCH_BAD_APICID (0xff) +#endif + +static u8 convert_acpiid_to_cpu(u8 acpi_id) +{ + u16 apic_id; + int i; + + apic_id = arch_acpiid_to_apicid[acpi_id]; + if (apic_id == ARCH_BAD_APICID) + return -1; + + for (i = 0; i < NR_CPUS; i++) { + if (arch_cpu_to_apicid[i] == apic_id) + return i; + } + return -1; +} +#endif /* -------------------------------------------------------------------------- Driver Interface @@ -2158,7 +2191,8 @@ acpi_status status = 0; union acpi_object object = {0}; struct acpi_buffer buffer = {sizeof(union acpi_object), &object}; - static int cpu_index = 0; + u8 cpu_index; + static int cpu0_initialized; ACPI_FUNCTION_TRACE("acpi_processor_get_info"); @@ -2168,13 +2202,6 @@ if (num_online_cpus() > 1) errata.smp = TRUE; - /* - * Extra Processor objects may be enumerated on MP systems with - * less than the max # of CPUs. They should be ignored. - */ - if ((cpu_index + 1) > num_online_cpus()) - return_VALUE(-ENODEV); - acpi_processor_errata(pr); /* @@ -2206,9 +2233,27 @@ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c */ - pr->id = cpu_index++; pr->acpi_id = object.processor.proc_id; + cpu_index = convert_acpiid_to_cpu(pr->acpi_id); + + if ( !cpu0_initialized && (cpu_index == 0xff)) { + /* Handle UP system running SMP kernel, with no LAPIC in MADT */ + cpu_index = 0; + } else if (cpu_index > num_online_cpus()) { + /* + * Extra Processor objects may be enumerated on MP systems with + * less than the max # of CPUs. They should be ignored. + */ + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error getting cpuindex for acpiid 0x%x\n", + pr->acpi_id)); + return_VALUE(-ENODEV); + } + cpu0_initialized = 1; + + pr->id = cpu_index; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, pr->acpi_id)); @@ -2234,7 +2279,6 @@ * (In particular, allocating the IO range for Cardbus) */ request_region(pr->throttling.address, 6, "ACPI CPU throttle"); - request_region(acpi_fadt.xpm_tmr_blk.address, 4, "ACPI timer"); } acpi_processor_get_power_info(pr); @@ -2373,8 +2417,15 @@ pr = (struct acpi_processor *) acpi_driver_data(device); /* Unregister the idle handler when processor #0 is removed. */ - if (pr->id == 0) + if (pr->id == 0) { pm_idle = pm_idle_save; + /* + * We are about to unload the current idle thread pm callback + * (pm_idle), Wait for all processors to update cached/local + * copies of pm_idle before proceeding. + */ + synchronize_kernel(); + } status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify); diff -Nru a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c --- a/drivers/acpi/resources/rsutils.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/resources/rsutils.c 2004-10-18 14:55:54 -07:00 @@ -289,6 +289,7 @@ acpi_handle handle, struct acpi_buffer *in_buffer) { + struct acpi_parameter_info info; union acpi_operand_object *params[2]; acpi_status status; struct acpi_buffer buffer; @@ -329,10 +330,14 @@ params[0]->common.flags = AOPOBJ_DATA_VALID; params[1] = NULL; + info.node = handle; + info.parameters = params; + info.parameter_type = ACPI_PARAM_ARGS; + /* * Execute the method, no return value */ - status = acpi_ns_evaluate_relative (handle, "_SRS", params, NULL); + status = acpi_ns_evaluate_relative ("_SRS", &info); /* * Clean up and return the status from acpi_ns_evaluate_relative diff -Nru a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c --- a/drivers/acpi/resources/rsxface.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/acpi/resources/rsxface.c 2004-10-18 14:56:48 -07:00 @@ -259,7 +259,8 @@ /* Setup pointers */ resource = (struct acpi_resource *) buffer.pointer; - buffer_end = (struct acpi_resource *) ((u8 *) buffer.pointer + buffer.length); + buffer_end = ACPI_CAST_PTR (struct acpi_resource, + ((u8 *) buffer.pointer + buffer.length)); /* Walk the resource list */ diff -Nru a/drivers/acpi/scan.c b/drivers/acpi/scan.c --- a/drivers/acpi/scan.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/acpi/scan.c 2004-10-18 14:56:29 -07:00 @@ -23,7 +23,8 @@ #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); -static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED; +spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED; +LIST_HEAD(acpi_wakeup_device_list); static void acpi_device_release(struct kobject * kobj) { @@ -115,9 +116,6 @@ status = acpi_get_handle(device->handle, "_IRC", &handle); if (ACPI_SUCCESS(status)) device->power.flags.inrush_current = 1; - status = acpi_get_handle(device->handle, "_PRW", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.wake_capable = 1; /* * Enumerate supported power management states @@ -163,6 +161,127 @@ return 0; } +static int +acpi_match_ids ( + struct acpi_device *device, + char *ids) +{ + int error = 0; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + + if (device->flags.hardware_id) + if (strstr(ids, device->pnp.hardware_id)) + goto Done; + + if (device->flags.compatible_ids) { + struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; + int i; + + /* compare multiple _CID entries against driver ids */ + for (i = 0; i < cid_list->count; i++) + { + if (strstr(ids, cid_list->id[i].value)) + goto Done; + } + } + error = -ENOENT; + + Done: + if (buffer.pointer) + acpi_os_free(buffer.pointer); + return error; +} + +static acpi_status +acpi_bus_extract_wakeup_device_power_package ( + struct acpi_device *device, + union acpi_object *package) +{ + int i = 0; + union acpi_object *element = NULL; + + if (!device || !package || (package->package.count < 2)) + return AE_BAD_PARAMETER; + + element = &(package->package.elements[0]); + if (!element) + return AE_BAD_PARAMETER; + if (element->type == ACPI_TYPE_PACKAGE) { + if ((element->package.count < 2) || + (element->package.elements[0].type != ACPI_TYPE_LOCAL_REFERENCE) || + (element->package.elements[1].type != ACPI_TYPE_INTEGER)) + return AE_BAD_DATA; + device->wakeup.gpe_device = element->package.elements[0].reference.handle; + device->wakeup.gpe_number = (u32)element->package.elements[1].integer.value; + }else if (element->type == ACPI_TYPE_INTEGER) { + device->wakeup.gpe_number = element->integer.value; + }else + return AE_BAD_DATA; + + element = &(package->package.elements[1]); + if (element->type != ACPI_TYPE_INTEGER) { + return AE_BAD_DATA; + } + device->wakeup.sleep_state = element->integer.value; + + if ((package->package.count - 2) > ACPI_MAX_HANDLES) { + return AE_NO_MEMORY; + } + device->wakeup.resources.count = package->package.count - 2; + for (i=0; i < device->wakeup.resources.count; i++) { + element = &(package->package.elements[i + 2]); + if (element->type != ACPI_TYPE_ANY ) { + return AE_BAD_DATA; + } + + device->wakeup.resources.handles[i] = element->reference.handle; + } + + return AE_OK; +} + +static int +acpi_bus_get_wakeup_device_flags ( + struct acpi_device *device) +{ + acpi_status status = 0; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *package = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_get_wakeup_flags"); + + /* _PRW */ + status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRW\n")); + goto end; + } + + package = (union acpi_object *) buffer.pointer; + status = acpi_bus_extract_wakeup_device_power_package(device, package); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _PRW package\n")); + goto end; + } + + acpi_os_free(buffer.pointer); + + device->wakeup.flags.valid = 1; + /* Power button, Lid switch always enable wakeup*/ + if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E")) + device->wakeup.flags.run_wake = 1; + + /* TBD: lock */ + INIT_LIST_HEAD(&device->wakeup_list); + spin_lock(&acpi_device_lock); + list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); + spin_unlock(&acpi_device_lock); + +end: + if (ACPI_FAILURE(status)) + device->flags.wake_capable = 0; + return 0; +} /* -------------------------------------------------------------------------- Performance Management @@ -195,30 +314,7 @@ struct acpi_device *device, struct acpi_driver *driver) { - int error = 0; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - - if (device->flags.hardware_id) - if (strstr(driver->ids, device->pnp.hardware_id)) - goto Done; - - if (device->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; - int i; - - /* compare multiple _CID entries against driver ids */ - for (i = 0; i < cid_list->count; i++) - { - if (strstr(driver->ids, cid_list->id[i].value)) - goto Done; - } - } - error = -ENOENT; - - Done: - if (buffer.pointer) - acpi_os_free(buffer.pointer); - return error; + return acpi_match_ids(device, driver->ids); } @@ -276,6 +372,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) { struct list_head * node, * next; + int count = 0; ACPI_FUNCTION_TRACE("acpi_driver_attach"); @@ -290,6 +387,7 @@ if (!acpi_bus_match(dev, drv)) { if (!acpi_bus_driver_init(dev, drv)) { atomic_inc(&drv->references); + count++; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", drv->name, dev->pnp.bus_id)); } @@ -297,7 +395,7 @@ spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); - return_VALUE(0); + return_VALUE(count); } static int acpi_driver_detach(struct acpi_driver * drv) @@ -328,28 +426,30 @@ * acpi_bus_register_driver * ------------------------ * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. + * devices that match the driver's criteria and binds. Returns the + * number of devices that were claimed by the driver, or a negative + * error status for failure. */ int acpi_bus_register_driver ( struct acpi_driver *driver) { - int error = 0; + int count; ACPI_FUNCTION_TRACE("acpi_bus_register_driver"); if (acpi_disabled) return_VALUE(-ENODEV); - if (driver) { - spin_lock(&acpi_device_lock); - list_add_tail(&driver->node, &acpi_bus_drivers); - spin_unlock(&acpi_device_lock); - acpi_driver_attach(driver); - } else - error = -EINVAL; + if (!driver) + return_VALUE(-EINVAL); - return_VALUE(error); + spin_lock(&acpi_device_lock); + list_add_tail(&driver->node, &acpi_bus_drivers); + spin_unlock(&acpi_device_lock); + count = acpi_driver_attach(driver); + + return_VALUE(count); } @@ -469,6 +569,11 @@ if (ACPI_SUCCESS(status)) device->flags.power_manageable = 1; + /* Presence of _PRW indicates wake capable */ + status = acpi_get_handle(device->handle, "_PRW", &temp); + if (ACPI_SUCCESS(status)) + device->flags.wake_capable = 1; + /* TBD: Peformance management */ return_VALUE(0); @@ -736,6 +841,16 @@ */ if (device->flags.power_manageable) { result = acpi_bus_get_power_flags(device); + if (result) + goto end; + } + + /* + * Wakeup device management + *----------------------- + */ + if (device->flags.wake_capable) { + result = acpi_bus_get_wakeup_device_flags(device); if (result) goto end; } diff -Nru a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile --- a/drivers/acpi/sleep/Makefile 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/sleep/Makefile 2004-10-18 14:56:49 -07:00 @@ -1,5 +1,5 @@ obj-y := poweroff.o -obj-$(CONFIG_ACPI_SLEEP) += main.o +obj-$(CONFIG_ACPI_SLEEP) += main.o wakeup.o obj-$(CONFIG_ACPI_SLEEP_PROC_FS) += proc.o EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nru a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c --- a/drivers/acpi/sleep/main.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/sleep/main.c 2004-10-18 14:55:54 -07:00 @@ -35,16 +35,16 @@ /** * acpi_pm_prepare - Do preliminary suspend work. - * @state: suspend state we're entering. + * @pm_state: suspend state we're entering. * * Make sure we support the state. If we do, and we need it, set the * firmware waking vector and do arch-specific nastiness to get the * wakeup code to the waking vector. */ -static int acpi_pm_prepare(u32 state) +static int acpi_pm_prepare(u32 pm_state) { - u32 acpi_state = acpi_suspend_states[state]; + u32 acpi_state = acpi_suspend_states[pm_state]; if (!sleep_states[acpi_state]) return -EPERM; @@ -52,13 +52,14 @@ /* do we have a wakeup address for S2 and S3? */ /* Here, we support only S4BIOS, those we set the wakeup address */ /* S4OS is only supported for now via swsusp.. */ - if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_DISK) { + if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) { if (!acpi_wakeup_address) return -EFAULT; acpi_set_firmware_waking_vector( (acpi_physical_address) acpi_wakeup_address); } ACPI_FLUSH_CPU_CACHE(); + acpi_enable_wakeup_device_prep(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -66,23 +67,23 @@ /** * acpi_pm_enter - Actually enter a sleep state. - * @state: State we're entering. + * @pm_state: State we're entering. * * Flush caches and go to sleep. For STR or STD, we have to call * arch-specific assembly, which in turn call acpi_enter_sleep_state(). * It's unfortunate, but it works. Please fix if you're feeling frisky. */ -static int acpi_pm_enter(u32 state) +static int acpi_pm_enter(u32 pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; - u32 acpi_state = acpi_suspend_states[state]; + u32 acpi_state = acpi_suspend_states[pm_state]; ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ - if (state > PM_SUSPEND_STANDBY) { + if (pm_state > PM_SUSPEND_STANDBY) { int error = acpi_save_state_mem(); if (error) return error; @@ -90,7 +91,8 @@ local_irq_save(flags); - switch (state) + acpi_enable_wakeup_device(acpi_state); + switch (pm_state) { case PM_SUSPEND_STANDBY: barrier(); @@ -118,7 +120,7 @@ * And, in the case of the latter, the memory image should have already * been loaded from disk. */ - if (state > PM_SUSPEND_STANDBY) + if (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); @@ -128,15 +130,18 @@ /** * acpi_pm_finish - Finish up suspend sequence. - * @state: State we're coming out of. + * @pm_state: State we're coming out of. * * This is called after we wake back up (or if entering the sleep state * failed). */ -static int acpi_pm_finish(u32 state) +static int acpi_pm_finish(u32 pm_state) { - acpi_leave_sleep_state(state); + u32 acpi_state = acpi_suspend_states[pm_state]; + + acpi_leave_sleep_state(acpi_state); + acpi_disable_wakeup_device(acpi_state); /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); @@ -199,7 +204,7 @@ return 0; printk(KERN_INFO PREFIX "(supports"); - for (i=0; iwakeup.flags.valid) + continue; + spin_unlock(&acpi_device_lock); + if (dev->wakeup.flags.run_wake) + seq_printf(seq, "%4s %4d %8s\n", + dev->pnp.bus_id, (u32) dev->wakeup.sleep_state, + dev->wakeup.state.enabled ? "*enabled" : "*disabled"); + else + seq_printf(seq, "%4s %4d %8s\n", + dev->pnp.bus_id, (u32) dev->wakeup.sleep_state, + dev->wakeup.state.enabled ? "enabled" : "disabled"); + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); + return 0; +} + +static ssize_t +acpi_system_write_wakeup_device ( + struct file *file, + const char __user *buffer, + size_t count, + loff_t *ppos) +{ + struct list_head * node, * next; + char strbuf[5]; + char str[5] = ""; + int len = count; + + if (len > 4) len = 4; + + if (copy_from_user(strbuf, buffer, len)) + return -EFAULT; + strbuf[len] = '\0'; + sscanf(strbuf, "%s", str); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list); + if (!dev->wakeup.flags.valid) + continue; + + if (!strncmp(dev->pnp.bus_id, str, 4)) { + dev->wakeup.state.enabled = dev->wakeup.state.enabled ? 0:1; + break; + } + } + spin_unlock(&acpi_device_lock); + return count; +} + +static int +acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_system_wakeup_device_seq_show, PDE(inode)->data); +} + +static struct file_operations acpi_system_wakeup_device_fops = { + .open = acpi_system_wakeup_device_open_fs, + .read = seq_read, + .write = acpi_system_write_wakeup_device, + .llseek = seq_lseek, + .release = single_release, +}; static struct file_operations acpi_system_sleep_fops = { .open = acpi_system_sleep_open_fs, @@ -388,6 +467,13 @@ S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); if (entry) entry->proc_fops = &acpi_system_alarm_fops; + + /* 'wakeup device' [R/W]*/ + entry = create_proc_entry(ACPI_SYSTEM_FILE_WAKEUP_DEVICE, + S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); + if (entry) + entry->proc_fops = &acpi_system_wakeup_device_fops; + return 0; } diff -Nru a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h --- a/drivers/acpi/sleep/sleep.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/sleep/sleep.h 2004-10-18 14:56:49 -07:00 @@ -2,3 +2,6 @@ extern u8 sleep_states[]; extern int acpi_suspend (u32 state); +extern void acpi_enable_wakeup_device_prep(u8 sleep_state); +extern void acpi_enable_wakeup_device(u8 sleep_state); +extern void acpi_disable_wakeup_device(u8 sleep_state); diff -Nru a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/acpi/sleep/wakeup.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,181 @@ +/* + * wakeup.c - support wakeup devices + */ + +#include +#include +#include +#include +#include +#include +#include "sleep.h" + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("wakeup_devices") + +/** + * acpi_enable_wakeup_device_prep - prepare wakeup devices + * @sleep_state: ACPI state + * Enable all wakup devices power if the devices' wakeup level + * is higher than requested sleep level + */ +extern struct list_head acpi_wakeup_device_list; +extern spinlock_t acpi_device_lock; + +void +acpi_enable_wakeup_device_prep( + u8 sleep_state) +{ + struct list_head * node, * next; + + ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + if (!dev->wakeup.flags.valid || + !dev->wakeup.state.enabled || + (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + + spin_unlock(&acpi_device_lock); + acpi_enable_wakeup_device_power(dev); + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); +} + +/** + * acpi_enable_wakeup_device - enable wakeup devices + * @sleep_state: ACPI state + * Enable all wakup devices's GPE + */ +void +acpi_enable_wakeup_device( + u8 sleep_state) +{ + struct list_head * node, * next; + + /* + * Caution: this routine must be invoked when interrupt is disabled + * Refer ACPI2.0: P212 + */ + ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device"); + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + /* If users want to disable run-wake GPE, + * we only disable it for wake and leave it for runtime + */ + if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME); + /* Re-enable it, since set_gpe_type will disable it */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_ISR); + spin_lock(&acpi_device_lock); + continue; + } + + if (!dev->wakeup.flags.valid || + !dev->wakeup.state.enabled || + (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + + spin_unlock(&acpi_device_lock); + /* run-wake GPE has been enabled */ + if (!dev->wakeup.flags.run_wake) + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_ISR); + dev->wakeup.state.active = 1; + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); +} + +/** + * acpi_disable_wakeup_device - disable devices' wakeup capability + * @sleep_state: ACPI state + * Disable all wakup devices's GPE and wakeup capability + */ +void +acpi_disable_wakeup_device ( + u8 sleep_state) +{ + struct list_head * node, * next; + + ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN); + /* Re-enable it, since set_gpe_type will disable it */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + spin_lock(&acpi_device_lock); + continue; + } + + if (!dev->wakeup.flags.valid || + !dev->wakeup.state.active || + (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + + spin_unlock(&acpi_device_lock); + acpi_disable_wakeup_device_power(dev); + /* Never disable run-wake GPE */ + if (!dev->wakeup.flags.run_wake) { + acpi_disable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + acpi_clear_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + } + dev->wakeup.state.active = 0; + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); +} + +static int __init acpi_wakeup_device_init(void) +{ + struct list_head * node, * next; + + if (acpi_disabled) + return 0; + printk("ACPI wakeup devices: \n"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + /* In case user doesn't load button driver */ + if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN); + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + dev->wakeup.state.enabled = 1; + spin_lock(&acpi_device_lock); + } + printk("%4s ", dev->pnp.bus_id); + } + spin_unlock(&acpi_device_lock); + printk("\n"); + + return 0; +} + +late_initcall(acpi_wakeup_device_init); diff -Nru a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c --- a/drivers/acpi/tables/tbxfroot.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/acpi/tables/tbxfroot.c 2004-10-18 14:56:49 -07:00 @@ -115,17 +115,14 @@ * Instance - the non zero instance of the table, allows * support for multiple tables of the same type * Flags - Physical/Virtual support - * ret_buffer - pointer to a structure containing a buffer to - * receive the table + * table_pointer - Where a buffer containing the table is + * returned * * RETURN: Status * - * DESCRIPTION: This function is called to get an ACPI table. The caller - * supplies an out_buffer large enough to contain the entire ACPI - * table. Upon completion - * the out_buffer->Length field will indicate the number of bytes - * copied into the out_buffer->buf_ptr buffer. This table will be - * a complete table including the header. + * DESCRIPTION: This function is called to get an ACPI table. A buffer is + * allocated for the table and returned in table_pointer. + * This table will be a complete table including the header. * ******************************************************************************/ @@ -136,12 +133,11 @@ u32 flags, struct acpi_table_header **table_pointer) { - struct acpi_pointer rsdp_address; - struct acpi_pointer address; acpi_status status; - struct acpi_table_header header; - struct acpi_table_desc table_info; - struct acpi_table_desc rsdt_info; + struct acpi_pointer address; + struct acpi_table_header *header = NULL; + struct acpi_table_desc *table_info = NULL; + struct acpi_table_desc *rsdt_info; u32 table_count; u32 i; u32 j; @@ -152,45 +148,41 @@ /* * Ensure that at least the table manager is initialized. We don't - * require that the entire ACPI subsystem is up for this interface - */ - - /* - * If we have a buffer, we must have a length too + * require that the entire ACPI subsystem is up for this interface. + * If we have a buffer, we must have a length too */ - if ((instance == 0) || - (!signature) || + if ((instance == 0) || + (!signature) || (!table_pointer)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - rsdt_info.pointer = NULL; + /* Ensure that we have a RSDP */ if (!acpi_gbl_RSDP) { /* Get the RSDP */ - status = acpi_os_get_root_pointer (flags, &rsdp_address); + status = acpi_os_get_root_pointer (flags, &address); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } /* Map and validate the RSDP */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - status = acpi_os_map_memory (rsdp_address.pointer.physical, sizeof (struct rsdp_descriptor), + status = acpi_os_map_memory (address.pointer.physical, sizeof (struct rsdp_descriptor), (void *) &acpi_gbl_RSDP); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } else { - acpi_gbl_RSDP = rsdp_address.pointer.logical; + acpi_gbl_RSDP = address.pointer.logical; } - /* - * The signature and checksum must both be correct - */ + /* The signature and checksum must both be correct */ + if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { /* Nope, BAD Signature */ @@ -204,10 +196,9 @@ } } - /* Get the RSDT and validate it */ + /* Get the RSDT address via the RSDP */ acpi_tb_get_rsdt_address (&address); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", acpi_gbl_RSDP, @@ -217,20 +208,40 @@ address.pointer_type |= flags; - status = acpi_tb_get_table (&address, &rsdt_info); + /* Get and validate the RSDT */ + + rsdt_info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_table_desc)); + if (!rsdt_info) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + status = acpi_tb_get_table (&address, rsdt_info); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } - status = acpi_tb_validate_rsdt (rsdt_info.pointer); + status = acpi_tb_validate_rsdt (rsdt_info->pointer); if (ACPI_FAILURE (status)) { goto cleanup; } - /* Get the number of table pointers within the RSDT */ + /* Allocate a scratch table header and table descriptor */ - table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info.pointer); + header = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_header)); + if (!header) { + status = AE_NO_MEMORY; + goto cleanup; + } + table_info = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_desc)); + if (!table_info) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Get the number of table pointers within the RSDT */ + + table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info->pointer); address.pointer_type = acpi_gbl_table_flags | flags; /* @@ -241,35 +252,36 @@ /* Get the next table pointer, handle RSDT vs. XSDT */ if (acpi_gbl_RSDP->revision < 2) { - address.pointer.value = (ACPI_CAST_PTR (RSDT_DESCRIPTOR, rsdt_info.pointer))->table_offset_entry[i]; + address.pointer.value = (ACPI_CAST_PTR ( + RSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; } else { - address.pointer.value = - (ACPI_CAST_PTR (XSDT_DESCRIPTOR, rsdt_info.pointer))->table_offset_entry[i]; + address.pointer.value = (ACPI_CAST_PTR ( + XSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; } /* Get the table header */ - status = acpi_tb_get_table_header (&address, &header); + status = acpi_tb_get_table_header (&address, header); if (ACPI_FAILURE (status)) { goto cleanup; } /* Compare table signatures and table instance */ - if (!ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) { + if (!ACPI_STRNCMP (header->signature, signature, ACPI_NAME_SIZE)) { /* An instance of the table was found */ j++; if (j >= instance) { /* Found the correct instance, get the entire table */ - status = acpi_tb_get_table_body (&address, &header, &table_info); + status = acpi_tb_get_table_body (&address, header, table_info); if (ACPI_FAILURE (status)) { goto cleanup; } - *table_pointer = table_info.pointer; + *table_pointer = table_info->pointer; goto cleanup; } } @@ -281,7 +293,15 @@ cleanup: - acpi_os_unmap_memory (rsdt_info.pointer, (acpi_size) rsdt_info.pointer->length); + acpi_os_unmap_memory (rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length); + ACPI_MEM_FREE (rsdt_info); + + if (header) { + ACPI_MEM_FREE (header); + } + if (table_info) { + ACPI_MEM_FREE (table_info); + } return_ACPI_STATUS (status); } @@ -389,14 +409,17 @@ * Flags - Current memory mode (logical vs. * physical addressing) * - * RETURN: Status + * RETURN: Status, RSDP physical address * * DESCRIPTION: search lower 1_mbyte of memory for the root system descriptor * pointer structure. If it is found, set *RSDP to point to it. * - * NOTE: The RSDp must be either in the first 1_k of the Extended - * BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section - * 5.2.2; assertion #421). + * NOTE1: The RSDp must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) + * Only a 32-bit physical address is necessary. + * + * NOTE2: This function is always available, regardless of the + * initialization state of the rest of ACPI. * ******************************************************************************/ @@ -407,8 +430,8 @@ { u8 *table_ptr; u8 *mem_rover; - u64 phys_addr; - acpi_status status = AE_OK; + u32 physical_address; + acpi_status status; ACPI_FUNCTION_TRACE ("tb_find_rsdp"); @@ -419,36 +442,57 @@ */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { /* - * 1) Search EBDA (low memory) paragraphs + * 1a) Get the location of the EBDA */ - status = acpi_os_map_memory ((u64) ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE, + status = acpi_os_map_memory ((acpi_physical_address) ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH, (void *) &table_ptr); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", - ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", + ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); return_ACPI_STATUS (status); } - mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE); - acpi_os_unmap_memory (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE); + ACPI_MOVE_16_TO_32 (&physical_address, table_ptr); + physical_address <<= 4; /* Convert segment to physical address */ + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH); + + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + status = acpi_os_map_memory ((acpi_physical_address) physical_address, + ACPI_EBDA_WINDOW_SIZE, + (void *) &table_ptr); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", + physical_address, ACPI_EBDA_WINDOW_SIZE)); + return_ACPI_STATUS (status); + } - if (mem_rover) { - /* Found it, return the physical address */ + mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE); + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_WINDOW_SIZE); - phys_addr = ACPI_LO_RSDP_WINDOW_BASE; - phys_addr += ACPI_PTR_DIFF (mem_rover,table_ptr); + if (mem_rover) { + /* Found it, return the physical address */ - table_info->physical_address = phys_addr; - return_ACPI_STATUS (AE_OK); + physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr); + + table_info->physical_address = (acpi_physical_address) physical_address; + return_ACPI_STATUS (AE_OK); + } } /* - * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ - status = acpi_os_map_memory ((u64) ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE, + status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE, (void *) &table_ptr); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); return_ACPI_STATUS (status); } @@ -459,10 +503,9 @@ if (mem_rover) { /* Found it, return the physical address */ - phys_addr = ACPI_HI_RSDP_WINDOW_BASE; - phys_addr += ACPI_PTR_DIFF (mem_rover, table_ptr); + physical_address = ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); - table_info->physical_address = phys_addr; + table_info->physical_address = (acpi_physical_address) physical_address; return_ACPI_STATUS (AE_OK); } } @@ -472,19 +515,29 @@ */ else { /* - * 1) Search EBDA (low memory) paragraphs + * 1a) Get the location of the EBDA */ - mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_LO_RSDP_WINDOW_BASE), - ACPI_LO_RSDP_WINDOW_SIZE); - if (mem_rover) { - /* Found it, return the physical address */ + ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION); + physical_address <<= 4; /* Convert segment to physical address */ - table_info->physical_address = ACPI_TO_INTEGER (mem_rover); - return_ACPI_STATUS (AE_OK); + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (physical_address), + ACPI_EBDA_WINDOW_SIZE); + if (mem_rover) { + /* Found it, return the physical address */ + + table_info->physical_address = ACPI_TO_INTEGER (mem_rover); + return_ACPI_STATUS (AE_OK); + } } /* - * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), ACPI_HI_RSDP_WINDOW_SIZE); diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c --- a/drivers/acpi/tables.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/acpi/tables.c 2004-10-18 14:56:28 -07:00 @@ -101,7 +101,7 @@ else name = header->signature; - printk(KERN_INFO PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name, header->revision, header->oem_id, header->oem_table_id, header->oem_revision, header->asl_compiler_id, header->asl_compiler_revision, @@ -587,7 +587,7 @@ return -ENODEV; } - printk(KERN_INFO PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", rsdp->revision, rsdp->oem_id, (void *) rsdp_phys); if (rsdp->revision < 2) diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c --- a/drivers/acpi/thermal.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/acpi/thermal.c 2004-10-18 14:56:50 -07:00 @@ -60,6 +60,7 @@ #define ACPI_THERMAL_NOTIFY_HOT 0xF1 #define ACPI_THERMAL_MODE_ACTIVE 0x00 #define ACPI_THERMAL_MODE_PASSIVE 0x01 +#define ACPI_THERMAL_MODE_CRT 0xff #define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" #define ACPI_THERMAL_MAX_ACTIVE 10 @@ -160,6 +161,7 @@ unsigned long last_temperature; unsigned long polling_frequency; u8 cooling_mode; + volatile u8 zombie; struct acpi_thermal_flags flags; struct acpi_thermal_state state; struct acpi_thermal_trips trips; @@ -289,13 +291,6 @@ status = acpi_get_handle(tz->handle, "_SCP", &handle); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n")); - status = acpi_get_handle(tz->handle, "_PSV", &handle); - if(!ACPI_FAILURE(status)) { - tz->cooling_mode = 1; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n", - mode?"passive":"active")); - return_VALUE(0); - } return_VALUE(-ENODEV); } @@ -653,7 +648,10 @@ acpi_thermal_run ( unsigned long data) { - acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_thermal_check, (void *) data); + struct acpi_thermal *tz = (struct acpi_thermal *)data; + if (!tz->zombie) + acpi_os_queue_for_execution(OSD_PRIORITY_GPE, + acpi_thermal_check, (void *) data); } @@ -665,7 +663,7 @@ struct acpi_thermal *tz = (struct acpi_thermal *) data; unsigned long sleep_time = 0; int i = 0; - struct acpi_thermal_state state = tz->state; + struct acpi_thermal_state state; ACPI_FUNCTION_TRACE("acpi_thermal_check"); @@ -674,6 +672,8 @@ return_VOID; } + state = tz->state; + result = acpi_thermal_get_temperature(tz); if (result) return_VOID; @@ -899,8 +899,10 @@ struct seq_file *m = (struct seq_file *)file->private_data; struct acpi_thermal *tz = (struct acpi_thermal *)m->private; - char limit_string[25] = {'\0'}; - int critical, hot, passive, active0, active1; + char limit_string[65] = {'\0'}; + int num, critical, hot, passive; + int active[ACPI_THERMAL_MAX_ACTIVE]; + int i = 0; ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points"); @@ -916,7 +918,11 @@ limit_string[count] = '\0'; - if (sscanf(limit_string, "%d:%d:%d:%d:%d", &critical, &hot, &passive, &active0, &active1) != 5) { + num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &critical, &hot, &passive, + &active[0], &active[1], &active[2], &active[3], &active[4], + &active[5], &active[6], &active[7], &active[8], &active[9]); + if(!(num >=5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n")); return_VALUE(-EINVAL); } @@ -924,8 +930,11 @@ tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical); tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot); tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive); - tz->trips.active[0].temperature = CELSIUS_TO_KELVIN(active0); - tz->trips.active[1].temperature = CELSIUS_TO_KELVIN(active1); + for (i = 0; i < num - 3; i++) { + if (!(tz->trips.active[i].flags.valid)) + break; + tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]); + } return_VALUE(count); } @@ -941,12 +950,14 @@ goto end; if (!tz->flags.cooling_mode) { - seq_puts(seq, "\n"); - goto end; + seq_puts(seq, "\n"); } - seq_printf(seq, "cooling mode: %s\n", - tz->cooling_mode?"passive":"active"); + if ( tz->cooling_mode == ACPI_THERMAL_MODE_CRT ) + seq_printf(seq, "cooling mode: critical\n"); + else + seq_printf(seq, "cooling mode: %s\n", + tz->cooling_mode?"passive":"active"); end: return 0; @@ -988,6 +999,8 @@ if (result) return_VALUE(result); + acpi_thermal_check(tz); + return_VALUE(count); } @@ -1225,16 +1238,34 @@ if (result) return_VALUE(result); - /* Set the cooling mode [_SCP] to active cooling (default) */ - result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); - if (!result) - tz->flags.cooling_mode = 1; - /* Get trip points [_CRT, _PSV, etc.] (required) */ result = acpi_thermal_get_trip_points(tz); if (result) return_VALUE(result); + /* Set the cooling mode [_SCP] to active cooling (default) */ + result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); + if (!result) + tz->flags.cooling_mode = 1; + else { + /* Oh,we have not _SCP method. + Generally show cooling_mode by _ACx, _PSV,spec 12.2*/ + tz->flags.cooling_mode = 0; + if ( tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) { + if ( tz->trips.passive.temperature > tz->trips.active[0].temperature ) + tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE; + else + tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE; + } else if ( !tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) { + tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE; + } else if ( tz->trips.active[0].flags.valid && !tz->trips.passive.flags.valid ) { + tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE; + } else { + /* _ACx and _PSV are optional, but _CRT is required */ + tz->cooling_mode = ACPI_THERMAL_MODE_CRT; + } + } + /* Get default polling frequency [_TZP] (optional) */ if (tzp) tz->polling_frequency = tzp; @@ -1324,8 +1355,14 @@ tz = (struct acpi_thermal *) acpi_driver_data(device); - if (timer_pending(&(tz->timer))) - del_timer(&(tz->timer)); + /* avoid timer adding new defer task */ + tz->zombie = 1; + /* wait for running timer (on other CPUs) finish */ + del_timer_sync(&(tz->timer)); + /* synchronize deferred task */ + acpi_os_wait_events_complete(NULL); + /* deferred task may reinsert timer */ + del_timer_sync(&(tz->timer)); status = acpi_remove_notify_handler(tz->handle, ACPI_DEVICE_NOTIFY, acpi_thermal_notify); @@ -1347,6 +1384,7 @@ acpi_thermal_remove_fs(device); + kfree(tz); return_VALUE(0); } diff -Nru a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c --- a/drivers/acpi/utilities/utalloc.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/acpi/utilities/utalloc.c 2004-10-18 14:55:55 -07:00 @@ -259,8 +259,8 @@ * * FUNCTION: acpi_ut_initialize_buffer * - * PARAMETERS: required_length - Length needed - * Buffer - Buffer to be validated + * PARAMETERS: Buffer - Buffer to be validated + * required_length - Length needed * * RETURN: Status * @@ -603,7 +603,8 @@ * * FUNCTION: acpi_ut_find_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * * RETURN: A list element if found; NULL otherwise. * @@ -646,7 +647,8 @@ * * FUNCTION: acpi_ut_track_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * Size - Size of the allocation * alloc_type - MEM_MALLOC or MEM_CALLOC * Component - Component type of caller @@ -733,7 +735,8 @@ * * FUNCTION: acpi_ut_remove_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * Component - Component type of caller * Module - Source file name of caller * Line - Line number of caller diff -Nru a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c --- a/drivers/acpi/utilities/uteval.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/acpi/utilities/uteval.c 2004-10-18 14:55:54 -07:00 @@ -133,7 +133,7 @@ u32 expected_return_btypes, union acpi_operand_object **return_desc) { - union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; acpi_status status; u32 return_btype; @@ -141,9 +141,13 @@ ACPI_FUNCTION_TRACE ("ut_evaluate_object"); + info.node = prefix_node; + info.parameters = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + /* Evaluate the object/method */ - status = acpi_ns_evaluate_relative (prefix_node, path, NULL, &obj_desc); + status = acpi_ns_evaluate_relative (path, &info); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", @@ -159,7 +163,7 @@ /* Did we get a return object? */ - if (!obj_desc) { + if (!info.return_object) { if (expected_return_btypes) { ACPI_REPORT_METHOD_ERROR ("No object was returned from", prefix_node, path, AE_NOT_EXIST); @@ -172,7 +176,7 @@ /* Map the return object type to the bitmapped type */ - switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + switch (ACPI_GET_OBJECT_TYPE (info.return_object)) { case ACPI_TYPE_INTEGER: return_btype = ACPI_BTYPE_INTEGER; break; @@ -202,17 +206,17 @@ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Type returned from %s was incorrect: %X\n", - path, ACPI_GET_OBJECT_TYPE (obj_desc))); + path, ACPI_GET_OBJECT_TYPE (info.return_object))); /* On error exit, we must delete the return object */ - acpi_ut_remove_reference (obj_desc); + acpi_ut_remove_reference (info.return_object); return_ACPI_STATUS (AE_TYPE); } /* Object type is OK, return it */ - *return_desc = obj_desc; + *return_desc = info.return_object; return_ACPI_STATUS (AE_OK); } diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c --- a/drivers/acpi/utilities/utglobal.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/acpi/utilities/utglobal.c 2004-10-18 14:55:55 -07:00 @@ -142,16 +142,11 @@ */ /* Debug switch - level and trace mask */ - -#ifdef ACPI_DEBUG_OUTPUT -u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; -#else -u32 acpi_dbg_level = ACPI_NORMAL_DEFAULT; -#endif +u32 acpi_dbg_level = 0; /* Debug switch - layer (component) mask */ -u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT; +u32 acpi_dbg_layer = 0; u32 acpi_gbl_nesting_level = 0; @@ -171,27 +166,40 @@ const u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; -const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { - "\\_S0_", - "\\_S1_", - "\\_S2_", - "\\_S3_", - "\\_S4_", - "\\_S5_"}; - -const char *acpi_gbl_highest_dstate_names[4] = { - "_S1D", - "_S2D", - "_S3D", - "_S4D"}; - -/* Strings supported by the _OSI predefined (internal) method */ - -const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = { - "Linux", - "Windows 2000", - "Windows 2001", - "Windows 2001.1"}; +const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = +{ + "\\_S0_", + "\\_S1_", + "\\_S2_", + "\\_S3_", + "\\_S4_", + "\\_S5_" +}; + +const char *acpi_gbl_highest_dstate_names[4] = +{ + "_S1D", + "_S2D", + "_S3D", + "_S4D" +}; + +/* + * Strings supported by the _OSI predefined (internal) method. + * When adding strings, be sure to update ACPI_NUM_OSI_STRINGS. + */ +const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = +{ + "Linux", + "Windows 2000", + "Windows 2001", + "Windows 2001.1", + "Windows 2001 SP0", + "Windows 2001 SP1", + "Windows 2001 SP2", + "Windows 2001 SP3", + "Windows 2001 SP4" +}; /****************************************************************************** @@ -213,7 +221,7 @@ {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_SB_", ACPI_TYPE_DEVICE, NULL}, {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, - {"_TZ_", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_TZ_", ACPI_TYPE_THERMAL, NULL}, {"_REV", ACPI_TYPE_INTEGER, "2"}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, "0"}, @@ -561,26 +569,37 @@ struct acpi_namespace_node *node = (struct acpi_namespace_node *) object; + /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ + if (!object) { - return ("NULL NODE"); + return ("NULL"); } - if (object == ACPI_ROOT_OBJECT) + /* Check for Root node */ + + if ((object == ACPI_ROOT_OBJECT) || + (object == acpi_gbl_root_node)) { - node = acpi_gbl_root_node; + return ("\"\\\" "); } + /* Descriptor must be a namespace node */ + if (node->descriptor != ACPI_DESC_TYPE_NAMED) { - return ("****"); + return ("####"); } + /* Name must be a valid ACPI name */ + if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii)) { - return ("----"); + return ("????"); } + /* Return the name */ + return (node->name.ascii); } @@ -783,10 +802,6 @@ ACPI_FUNCTION_TRACE ("ut_init_globals"); - /* Runtime configuration */ - - acpi_gbl_create_osi_method = TRUE; - acpi_gbl_all_methods_serialized = FALSE; /* Memory allocation and cache lists */ @@ -880,6 +895,7 @@ /* Hardware oriented */ acpi_gbl_events_initialized = FALSE; + acpi_gbl_system_awake_and_running = TRUE; /* Namespace */ diff -Nru a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c --- a/drivers/acpi/utilities/utxface.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/acpi/utilities/utxface.c 2004-10-18 14:55:55 -07:00 @@ -157,9 +157,8 @@ } } - /* - * Enable ACPI mode - */ + /* Enable ACPI mode */ + if (!(flags & ACPI_NO_ACPI_ENABLE)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Going into ACPI mode\n")); @@ -173,7 +172,21 @@ } /* - * Initialize ACPI Event handling + * Install the default op_region handlers. These are installed unless + * other handlers have already been installed via the + * install_address_space_handler interface. + */ + if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + + status = acpi_ev_install_region_handlers (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Initialize ACPI Event handling (Fixed and General Purpose) * * NOTE: We must have the hardware AND events initialized before we can execute * ANY control methods SAFELY. Any control method can require ACPI hardware @@ -182,18 +195,18 @@ if (!(flags & ACPI_NO_EVENT_INIT)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n")); - status = acpi_ev_initialize (); + status = acpi_ev_initialize_events (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } - /* Install the SCI handler, Global Lock handler, and GPE handlers */ + /* Install the SCI handler and Global Lock handler */ if (!(flags & ACPI_NO_HANDLER_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL/GPE handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n")); - status = acpi_ev_handler_initialize (); + status = acpi_ev_install_xrupt_handlers (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -226,18 +239,16 @@ /* - * Install the default op_region handlers. These are installed unless - * other handlers have already been installed via the - * install_address_space_handler interface. + * Run all _REG methods * - * NOTE: This will cause _REG methods to be run. Any objects accessed + * NOTE: Any objects accessed * by the _REG methods will be automatically initialized, even if they * contain executable AML (see call to acpi_ns_initialize_objects below). */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG op_region methods\n")); - status = acpi_ev_init_address_spaces (); + status = acpi_ev_initialize_op_regions (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -249,7 +260,7 @@ * objects: operation_regions, buffer_fields, Buffers, and Packages. */ if (!(flags & ACPI_NO_OBJECT_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Objects\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of ACPI Objects\n")); status = acpi_ns_initialize_objects (); if (ACPI_FAILURE (status)) { diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile --- a/drivers/atm/Makefile 2004-10-18 14:55:54 -07:00 +++ b/drivers/atm/Makefile 2004-10-18 14:55:54 -07:00 @@ -3,7 +3,7 @@ # fore_200e-objs := fore200e.o -host-progs := fore200e_mkfirm +hostprogs-y := fore200e_mkfirm # Files generated that shall be removed upon make clean clean-files := atmsar11.bin atmsar11.bin1 atmsar11.bin2 pca200e.bin \ diff -Nru a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c --- a/drivers/atm/ambassador.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/atm/ambassador.c 2004-10-18 14:55:55 -07:00 @@ -2291,11 +2291,10 @@ // read resources from PCI configuration space u8 irq = pci_dev->irq; - u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 0)); - u32 iobase = pci_resource_start (pci_dev, 1); PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at" - " IO %x, IRQ %u, MEM %p", iobase, irq, membase); + " IO %x, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1), + irq, bus_to_virt(pci_resource_start(pci_dev, 0))); // check IO region err = pci_request_region(pci_dev, 1, DEV_LABEL); diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c --- a/drivers/atm/eni.c 2004-10-18 14:56:18 -07:00 +++ b/drivers/atm/eni.c 2004-10-18 14:56:18 -07:00 @@ -173,7 +173,7 @@ int i; for (i = 0; i < eni_dev->free_len; i++) - printk(KERN_DEBUG " %d: 0x%lx %d\n",i, + printk(KERN_DEBUG " %d: %p %d\n",i, eni_dev->free_list[i].start, 1 << eni_dev->free_list[i].order); } @@ -191,19 +191,19 @@ printk(KERN_NOTICE "TX buffers\n"); for (i = 0; i < NR_CHAN; i++) if (eni_dev->tx[i].send) - printk(KERN_NOTICE " TX %d @ 0x%lx: %ld\n",i, + printk(KERN_NOTICE " TX %d @ %p: %ld\n",i, eni_dev->tx[i].send,eni_dev->tx[i].words*4); printk(KERN_NOTICE "RX buffers\n"); for (i = 0; i < 1024; i++) if (eni_dev->rx_map[i] && ENI_VCC(eni_dev->rx_map[i])->rx) - printk(KERN_NOTICE " RX %d @ 0x%lx: %ld\n",i, + printk(KERN_NOTICE " RX %d @ %p: %ld\n",i, ENI_VCC(eni_dev->rx_map[i])->recv, ENI_VCC(eni_dev->rx_map[i])->words*4); printk(KERN_NOTICE "----\n"); } -static void eni_put_free(struct eni_dev *eni_dev,unsigned long start, +static void eni_put_free(struct eni_dev *eni_dev, void __iomem *start, unsigned long size) { struct eni_free *list; @@ -215,17 +215,17 @@ len = eni_dev->free_len; while (size) { if (len >= eni_dev->free_list_size) { - printk(KERN_CRIT "eni_put_free overflow (0x%lx,%ld)\n", + printk(KERN_CRIT "eni_put_free overflow (%p,%ld)\n", start,size); break; } - for (order = 0; !((start | size) & (1 << order)); order++); + for (order = 0; !(((unsigned long)start | size) & (1 << order)); order++); if (MID_MIN_BUF_SIZE > (1 << order)) { printk(KERN_CRIT "eni_put_free: order %d too small\n", order); break; } - list[len].start = start; + list[len].start = (void __iomem *) start; list[len].order = order; len++; start += 1 << order; @@ -236,10 +236,10 @@ } -static unsigned long eni_alloc_mem(struct eni_dev *eni_dev,unsigned long *size) +static void __iomem *eni_alloc_mem(struct eni_dev *eni_dev, unsigned long *size) { struct eni_free *list; - unsigned long start; + void __iomem *start; int len,i,order,best_order,index; list = eni_dev->free_list; @@ -273,7 +273,7 @@ } -static void eni_free_mem(struct eni_dev *eni_dev,unsigned long start, +static void eni_free_mem(struct eni_dev *eni_dev, void __iomem *start, unsigned long size) { struct eni_free *list; @@ -283,20 +283,20 @@ list = eni_dev->free_list; len = eni_dev->free_len; for (order = -1; size; order++) size >>= 1; - DPRINTK("eni_free_mem: 0x%lx+0x%lx (order %d)\n",start,size,order); + DPRINTK("eni_free_mem: %p+0x%lx (order %d)\n",start,size,order); for (i = 0; i < len; i++) - if (list[i].start == (start^(1 << order)) && + if (((unsigned long) list[i].start) == ((unsigned long)start^(1 << order)) && list[i].order == order) { DPRINTK("match[%d]: 0x%lx/0x%lx(0x%x), %d/%d\n",i, list[i].start,start,1 << order,list[i].order,order); list[i] = list[--len]; - start &= ~(unsigned long) (1 << order); + start = (void __iomem *) ((unsigned long) start & ~(unsigned long) (1 << order)); order++; i = -1; continue; } if (len >= eni_dev->free_list_size) { - printk(KERN_ALERT "eni_free_mem overflow (0x%lx,%d)\n",start, + printk(KERN_ALERT "eni_free_mem overflow (%p,%d)\n",start, order); return; } @@ -333,7 +333,7 @@ printk(KERN_ALERT " host descr 0x%lx, rx pos 0x%lx, descr value " "0x%x\n",eni_vcc->descr,eni_vcc->rx_pos, (unsigned) readl(eni_vcc->recv+eni_vcc->descr*4)); - printk(KERN_ALERT " last 0x%p, servicing %d\n",eni_vcc->last, + printk(KERN_ALERT " last %p, servicing %d\n",eni_vcc->last, eni_vcc->servicing); EVENT("---dump ends here---\n",0,0); printk(KERN_NOTICE "---recent events---\n"); @@ -617,7 +617,8 @@ static inline int rx_vcc(struct atm_vcc *vcc) { - unsigned long vci_dsc,tmp; + void __iomem *vci_dsc; + unsigned long tmp; struct eni_vcc *eni_vcc; eni_vcc = ENI_VCC(vcc); @@ -728,7 +729,7 @@ struct eni_vcc *eni_vcc; struct atm_vcc *vcc; struct sk_buff *skb; - unsigned long vci_dsc; + void __iomem *vci_dsc; int first; eni_dev = ENI_DEV(dev); @@ -808,7 +809,7 @@ static int open_rx_second(struct atm_vcc *vcc) { - unsigned long here; + void __iomem *here; struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; unsigned long size; @@ -840,7 +841,7 @@ static void close_rx(struct atm_vcc *vcc) { DECLARE_WAITQUEUE(wait,current); - unsigned long here; + void __iomem *here; struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; @@ -1289,7 +1290,8 @@ struct eni_dev *eni_dev = ENI_DEV(vcc->dev); struct eni_vcc *eni_vcc = ENI_VCC(vcc); struct eni_tx *tx; - unsigned long size,mem; + unsigned long size; + void __iomem *mem; int rate,ubr,unlimited,new_tx; int pre,res,order; int error; @@ -1687,9 +1689,9 @@ #undef GET_SEPROM -static int __devinit get_esi_fpga(struct atm_dev *dev,unsigned long base) +static int __devinit get_esi_fpga(struct atm_dev *dev, void __iomem *base) { - unsigned long mac_base; + void __iomem *mac_base; int i; mac_base = base+EPROM_SIZE-sizeof(struct midway_eprom); @@ -1703,7 +1705,8 @@ struct midway_eprom *eprom; struct eni_dev *eni_dev; struct pci_dev *pci_dev; - unsigned long real_base,base; + unsigned long real_base; + void __iomem *base; unsigned char revision; int error,i,last; @@ -1730,13 +1733,13 @@ } printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", dev->number,revision,real_base,eni_dev->irq); - if (!(base = (unsigned long) ioremap_nocache(real_base,MAP_MAX_SIZE))) { + if (!(base = ioremap_nocache(real_base,MAP_MAX_SIZE))) { printk("\n"); printk(KERN_ERR DEV_LABEL "(itf %d): can't set up page " "mapping\n",dev->number); return error; } - eni_dev->base_diff = real_base-base; + eni_dev->base_diff = real_base - (unsigned long) base; /* id may not be present in ASIC Tonga boards - check this @@@ */ if (!eni_dev->asic) { eprom = (struct midway_eprom *) (base+EPROM_SIZE-sizeof(struct @@ -1790,7 +1793,9 @@ static int __devinit eni_start(struct atm_dev *dev) { struct eni_dev *eni_dev; - unsigned long buf,buffer_mem; + + void __iomem *buf; + unsigned long buffer_mem; int error; DPRINTK(">eni_start\n"); @@ -1828,7 +1833,7 @@ tasklet_init(&eni_dev->task,eni_tasklet,(unsigned long) dev); eni_dev->events = 0; /* initialize memory management */ - buffer_mem = eni_dev->mem-(buf-eni_dev->ram); + buffer_mem = eni_dev->mem - (buf - eni_dev->ram); eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2; eni_dev->free_list = (struct eni_free *) kmalloc( sizeof(struct eni_free)*(eni_dev->free_list_size+1),GFP_KERNEL); @@ -1955,7 +1960,7 @@ */ tasklet_disable(&eni_dev->task); skb_queue_walk(&eni_dev->tx_queue, skb) { - unsigned long dsc; + void __iomem *dsc; if (ATM_SKB(skb)->vcc != vcc) continue; dsc = tx->send+ENI_PRV_POS(skb)*4; @@ -2136,9 +2141,9 @@ if (!tx->send) continue; if (!--left) { - return sprintf(page,"tx[%d]: 0x%06lx-0x%06lx " + return sprintf(page,"tx[%d]: 0x%ld-0x%ld " "(%6ld bytes), rsv %d cps, shp %d cps%s\n",i, - tx->send-eni_dev->ram, + (unsigned long) (tx->send - eni_dev->ram), tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, tx->reserved,tx->shaping, tx == eni_dev->ubr ? " (UBR)" : ""); @@ -2162,9 +2167,9 @@ if (--left) continue; length = sprintf(page,"vcc %4d: ",vcc->vci); if (eni_vcc->rx) { - length += sprintf(page+length,"0x%06lx-0x%06lx " + length += sprintf(page+length,"0x%ld-0x%ld " "(%6ld bytes)", - eni_vcc->recv-eni_dev->ram, + (unsigned long) (eni_vcc->recv - eni_dev->ram), eni_vcc->recv-eni_dev->ram+eni_vcc->words*4-1, eni_vcc->words*4); if (eni_vcc->tx) length += sprintf(page+length,", "); @@ -2183,8 +2188,8 @@ unsigned long offset; if (--left) continue; - offset = eni_dev->ram+eni_dev->base_diff; - return sprintf(page,"free 0x%06lx-0x%06lx (%6d bytes)\n", + offset = (unsigned long) eni_dev->ram+eni_dev->base_diff; + return sprintf(page,"free %p-%p (%6d bytes)\n", fe->start-offset,fe->start-offset+(1 << fe->order)-1, 1 << fe->order); } diff -Nru a/drivers/atm/eni.h b/drivers/atm/eni.h --- a/drivers/atm/eni.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/atm/eni.h 2004-10-18 14:56:33 -07:00 @@ -33,12 +33,12 @@ struct eni_free { - unsigned long start; /* counting in bytes */ + void __iomem *start; /* counting in bytes */ int order; }; struct eni_tx { - unsigned long send; /* base, 0 if unused */ + void __iomem *send; /* base, 0 if unused */ int prescaler; /* shaping prescaler */ int resolution; /* shaping divider */ unsigned long tx_pos; /* current TX write position */ @@ -51,7 +51,7 @@ struct eni_vcc { int (*rx)(struct atm_vcc *vcc); /* RX function, NULL if none */ - unsigned long recv; /* receive buffer */ + void __iomem *recv; /* receive buffer */ unsigned long words; /* its size in words */ unsigned long descr; /* next descriptor (RX) */ unsigned long rx_pos; /* current RX descriptor pos */ @@ -72,13 +72,13 @@ u32 events; /* pending events */ /*-------------------------------- base pointers into Midway address space */ - unsigned long phy; /* PHY interface chip registers */ - unsigned long reg; /* register base */ - unsigned long ram; /* RAM base */ - unsigned long vci; /* VCI table */ - unsigned long rx_dma; /* RX DMA queue */ - unsigned long tx_dma; /* TX DMA queue */ - unsigned long service; /* service list */ + void __iomem *phy; /* PHY interface chip registers */ + void __iomem *reg; /* register base */ + void __iomem *ram; /* RAM base */ + void __iomem *vci; /* VCI table */ + void __iomem *rx_dma; /* RX DMA queue */ + void __iomem *tx_dma; /* TX DMA queue */ + void __iomem *service; /* service list */ /*-------------------------------- TX part */ struct eni_tx tx[NR_CHAN]; /* TX channels */ struct eni_tx *ubr; /* UBR channel */ diff -Nru a/drivers/atm/firestream.c b/drivers/atm/firestream.c --- a/drivers/atm/firestream.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/atm/firestream.c 2004-10-18 14:55:55 -07:00 @@ -1667,7 +1667,7 @@ dev->hw_base = pci_resource_start(pci_dev, 0); - dev->base = (ulong) ioremap(dev->hw_base, 0x1000); + dev->base = ioremap(dev->hw_base, 0x1000); reset_chip (dev); @@ -1704,8 +1704,7 @@ } /* Try again after 10ms. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout ((HZ+99)/100); + msleep(10); } if (!to) { diff -Nru a/drivers/atm/firestream.h b/drivers/atm/firestream.h --- a/drivers/atm/firestream.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/atm/firestream.h 2004-10-18 14:56:49 -07:00 @@ -477,7 +477,7 @@ struct timer_list timer; unsigned long hw_base; /* mem base address */ - unsigned long base; /* Mapping of base address */ + void __iomem *base; /* Mapping of base address */ int channo; unsigned long channel_mask; diff -Nru a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h --- a/drivers/atm/fore200e.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/atm/fore200e.h 2004-10-18 14:56:32 -07:00 @@ -565,7 +565,7 @@ typedef struct chunk { void* alloc_addr; /* base address of allocated chunk */ void* align_addr; /* base address of aligned chunk */ - u32 dma_addr; /* DMA address of aligned chunk */ + dma_addr_t dma_addr; /* DMA address of aligned chunk */ int direction; /* direction of DMA mapping */ u32 alloc_size; /* length of allocated chunk */ u32 align_size; /* length of aligned chunk */ diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c --- a/drivers/atm/he.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/atm/he.c 2004-10-18 14:56:13 -07:00 @@ -1007,6 +1007,7 @@ { struct he_dev *he_dev; struct pci_dev *pci_dev; + unsigned long membase; u16 command; u32 gen_cntl_0, host_cntl, lb_swap; @@ -1019,8 +1020,8 @@ he_dev = HE_DEV(dev); pci_dev = he_dev->pci_dev; - he_dev->membase = pci_dev->resource[0].start; - HPRINTK("membase = 0x%lx irq = %d.\n", he_dev->membase, pci_dev->irq); + membase = pci_resource_start(pci_dev, 0); + HPRINTK("membase = 0x%lx irq = %d.\n", membase, pci_dev->irq); /* * pci bus controller initialization @@ -1080,7 +1081,7 @@ hprintk("can't set latency timer to %d\n", timer); } - if (!(he_dev->membase = (unsigned long) ioremap(he_dev->membase, HE_REGMAP_SIZE))) { + if (!(he_dev->membase = ioremap(membase, HE_REGMAP_SIZE))) { hprintk("can't set up page mapping\n"); return -EINVAL; } @@ -1962,7 +1963,7 @@ struct he_tpd *tpd; int slot, updated = 0; #ifdef USE_TPD_POOL - struct list_head *p; + struct he_tpd *__tpd; #endif /* 2.1.6 transmit buffer return queue */ @@ -1977,8 +1978,7 @@ TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : ""); #ifdef USE_TPD_POOL tpd = NULL; - list_for_each(p, &he_dev->outstanding_tpds) { - struct he_tpd *__tpd = list_entry(p, struct he_tpd, entry); + list_for_each_entry(__tpd, &he_dev->outstanding_tpds, entry) { if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) { tpd = __tpd; list_del(&__tpd->entry); @@ -2595,9 +2595,8 @@ while (((tx_inuse = atomic_read(&vcc->sk->sk_wmem_alloc)) > 0) && (retry < MAX_RETRY)) { - set_current_state(TASK_UNINTERRUPTIBLE); - (void) schedule_timeout(sleep); - if (sleep < HZ) + msleep(sleep); + if (sleep < 250) sleep = sleep * 2; ++retry; diff -Nru a/drivers/atm/he.h b/drivers/atm/he.h --- a/drivers/atm/he.h 2004-10-18 14:56:31 -07:00 +++ b/drivers/atm/he.h 2004-10-18 14:56:31 -07:00 @@ -265,7 +265,7 @@ struct he_dev { unsigned int number; unsigned int irq; - unsigned long membase; + void __iomem *membase; char prod_id[30]; char mac_addr[6]; diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c --- a/drivers/atm/idt77252.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/atm/idt77252.c 2004-10-18 14:56:29 -07:00 @@ -2516,7 +2516,7 @@ struct vc_map *vc = vcc->dev_data; unsigned long flags; unsigned long addr; - int timeout; + unsigned long timeout; down(&card->mutex); @@ -2566,9 +2566,9 @@ } spin_unlock_irqrestore(&vc->lock, flags); - timeout = 5 * HZ; + timeout = 5 * 1000; while (atomic_read(&vc->scq->used) > 0) { - timeout = schedule_timeout(timeout); + timeout = msleep_interruptible(timeout); if (!timeout) break; } @@ -3164,7 +3164,7 @@ for (i = 0; i < 4; i++) { if (card->fbq[i]) - iounmap((void *) card->fbq[i]); + iounmap(card->fbq[i]); } if (card->membase) @@ -3681,18 +3681,25 @@ struct idt77252_dev *card; struct atm_dev *dev; ushort revision = 0; - int i; + int i, err; + + if (pci_enable_device(pcidev)) { + printk("idt77252: can't enable PCI device at %s\n", pci_name(pcidev)); + return -ENODEV; + } if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) { printk("idt77252-%d: can't read PCI_REVISION_ID\n", index); - return -ENODEV; + err = -ENODEV; + goto err_out_disable_pdev; } card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL); if (!card) { printk("idt77252-%d: can't allocate private data\n", index); - return -ENOMEM; + err = -ENOMEM; + goto err_out_disable_pdev; } memset(card, 0, sizeof(struct idt77252_dev)); @@ -3715,26 +3722,24 @@ card->tst_timer.function = tst_timer; /* Do the I/O remapping... */ - card->membase = (unsigned long) ioremap(membase, 1024); + card->membase = ioremap(membase, 1024); if (!card->membase) { printk("%s: can't ioremap() membase\n", card->name); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_free_card; } if (idt77252_preset(card)) { printk("%s: preset failed\n", card->name); - iounmap((void *) card->membase); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_iounmap; } dev = atm_dev_register("idt77252", &idt77252_ops, -1, NULL); if (!dev) { printk("%s: can't register atm device\n", card->name); - iounmap((void *) card->membase); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_iounmap; } dev->dev_data = card; card->atmdev = dev; @@ -3743,22 +3748,19 @@ suni_init(dev); if (!dev->phy) { printk("%s: can't init SUNI\n", card->name); - deinit_card(card); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_deinit_card; } #endif /* CONFIG_ATM_IDT77252_USE_SUNI */ card->sramsize = probe_sram(card); for (i = 0; i < 4; i++) { - card->fbq[i] = (unsigned long) - ioremap(srambase | 0x200000 | (i << 18), 4); + card->fbq[i] = ioremap(srambase | 0x200000 | (i << 18), 4); if (!card->fbq[i]) { printk("%s: can't ioremap() FBQ%d\n", card->name, i); - deinit_card(card); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_deinit_card; } } @@ -3769,9 +3771,8 @@ if (init_card(dev)) { printk("%s: init_card failed\n", card->name); - deinit_card(card); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_deinit_card; } dev->ci_range.vpi_bits = card->vpibits; @@ -3783,12 +3784,8 @@ if (idt77252_dev_open(card)) { printk("%s: dev_open failed\n", card->name); - - if (dev->phy->stop) - dev->phy->stop(dev); - deinit_card(card); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_stop; } *last = card; @@ -3796,6 +3793,23 @@ index++; return 0; + +err_out_stop: + if (dev->phy->stop) + dev->phy->stop(dev); + +err_out_deinit_card: + deinit_card(card); + +err_out_iounmap: + iounmap((void *) card->membase); + +err_out_free_card: + kfree(card); + +err_out_disable_pdev: + pci_disable_device(pcidev); + return err; } static struct pci_device_id idt77252_pci_tbl[] = @@ -3848,6 +3862,7 @@ if (dev->phy->stop) dev->phy->stop(dev); deinit_card(card); + pci_disable_device(card->pcidev); kfree(card); } diff -Nru a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h --- a/drivers/atm/idt77252.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/atm/idt77252.h 2004-10-18 14:56:49 -07:00 @@ -355,9 +355,9 @@ struct pci_dev *pcidev; /* PCI handle (desriptor) */ struct atm_dev *atmdev; /* ATM device desriptor */ - unsigned long membase; /* SAR's memory base address */ + void __iomem *membase; /* SAR's memory base address */ unsigned long srambase; /* SAR's sram base address */ - unsigned long fbq[4]; /* FBQ fill addresses */ + void __iomem *fbq[4]; /* FBQ fill addresses */ struct semaphore mutex; spinlock_t cmd_lock; /* for r/w utility/sram */ diff -Nru a/drivers/atm/lanai.c b/drivers/atm/lanai.c --- a/drivers/atm/lanai.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/atm/lanai.c 2004-10-18 14:56:27 -07:00 @@ -191,7 +191,7 @@ #define LANAI_EEPROM_SIZE (128) typedef int vci_t; -typedef unsigned long bus_addr_t; +typedef void __iomem *bus_addr_t; /* DMA buffer in host memory for TX, RX, or service list. */ struct lanai_buffer { @@ -471,7 +471,7 @@ static inline bus_addr_t reg_addr(const struct lanai_dev *lanai, enum lanai_register reg) { - return lanai->base + (bus_addr_t) reg; + return lanai->base + reg; } static inline u32 reg_read(const struct lanai_dev *lanai, @@ -651,7 +651,7 @@ { u32 val; APRINTK(lvcc->vbase != 0, "cardvcc_read: unbound vcc!\n"); - val= readl(lvcc->vbase + (bus_addr_t) offset); + val= readl(lvcc->vbase + offset); RWDEBUG("VR vci=%04d 0x%02X = 0x%08X\n", lvcc->vci, (int) offset, val); return val; @@ -666,7 +666,7 @@ (unsigned int) val, lvcc->vci, (unsigned int) offset); RWDEBUG("VW vci=%04d 0x%02X > 0x%08X\n", lvcc->vci, (unsigned int) offset, (unsigned int) val); - writel(val, lvcc->vbase + (bus_addr_t) offset); + writel(val, lvcc->vbase + offset); } /* -------------------- COMPUTE SIZE OF AN AAL5 PDU: */ @@ -813,7 +813,7 @@ DPRINTK("read, write = %d, %d\n", read, write); break; } - schedule_timeout(HZ / 25); + msleep(40); } /* 15.2.2 - clear out all tx registers */ cardvcc_write(lvcc, 0, vcc_txreadptr); @@ -2177,7 +2177,7 @@ /* 3.2: PCI initialization */ if ((result = lanai_pci_start(lanai)) != 0) goto error; - raw_base = (bus_addr_t) lanai->pci->resource[0].start; + raw_base = lanai->pci->resource[0].start; lanai->base = (bus_addr_t) ioremap(raw_base, LANAI_MAPPING_SIZE); if (lanai->base == 0) { printk(KERN_ERR DEV_LABEL ": couldn't remap I/O space\n"); diff -Nru a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c --- a/drivers/atm/nicstar.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/atm/nicstar.c 2004-10-18 14:56:17 -07:00 @@ -467,6 +467,7 @@ u32 u32d[4]; u32 ns_cfg_rctsize; int bcount; + unsigned long membase; error = 0; @@ -494,8 +495,8 @@ card->index = i; card->atmdev = NULL; card->pcidev = pcidev; - card->membase = pci_resource_start(pcidev, 1); - card->membase = (unsigned long) ioremap(card->membase, NS_IOREMAP_SIZE); + membase = pci_resource_start(pcidev, 1); + card->membase = ioremap(membase, NS_IOREMAP_SIZE); if (card->membase == 0) { printk("nicstar%d: can't ioremap() membase.\n",i); diff -Nru a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h --- a/drivers/atm/nicstar.h 2004-10-18 14:56:27 -07:00 +++ b/drivers/atm/nicstar.h 2004-10-18 14:56:27 -07:00 @@ -763,7 +763,7 @@ { int index; /* Card ID to the device driver */ int sram_size; /* In k x 32bit words. 32 or 128 */ - unsigned long membase; /* Card's memory base address */ + void __iomem *membase; /* Card's memory base address */ unsigned long max_pcr; int rct_size; /* Number of entries */ int vpibits; diff -Nru a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c --- a/drivers/atm/nicstarmac.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/atm/nicstarmac.c 2004-10-18 14:57:04 -07:00 @@ -162,7 +162,7 @@ */ static u_int8_t -read_eprom_byte(u_int32_t base, u_int8_t offset) +read_eprom_byte(virt_addr_t base, u_int8_t offset) { u_int32_t val = 0; int i,j=0; diff -Nru a/drivers/atm/nicstarmac.h b/drivers/atm/nicstarmac.h --- a/drivers/atm/nicstarmac.h 2004-10-18 14:55:55 -07:00 +++ b/drivers/atm/nicstarmac.h 2004-10-18 14:55:55 -07:00 @@ -7,7 +7,7 @@ ******************************************************************************/ -typedef unsigned int virt_addr_t; +typedef void __iomem *virt_addr_t; u_int32_t nicstar_read_eprom_status( virt_addr_t base ); void nicstar_init_eprom( virt_addr_t base ); diff -Nru a/drivers/base/class.c b/drivers/base/class.c --- a/drivers/base/class.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/base/class.c 2004-10-18 14:57:04 -07:00 @@ -349,13 +349,18 @@ int class_device_add(struct class_device *class_dev) { - struct class * parent; + struct class * parent = NULL; struct class_interface * class_intf; int error; class_dev = class_device_get(class_dev); - if (!class_dev || !strlen(class_dev->class_id)) + if (!class_dev) return -EINVAL; + + if (!strlen(class_dev->class_id)) { + error = -EINVAL; + goto register_done; + } parent = class_get(class_dev->class); diff -Nru a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c --- a/drivers/base/firmware_class.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/base/firmware_class.c 2004-10-18 14:55:53 -07:00 @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -235,6 +235,8 @@ struct firmware *fw; ssize_t retval; + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; down(&fw_lock); fw = fw_priv->fw; if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { diff -Nru a/drivers/base/node.c b/drivers/base/node.c --- a/drivers/base/node.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/base/node.c 2004-10-18 14:56:13 -07:00 @@ -19,7 +19,7 @@ static ssize_t node_read_cpumap(struct sys_device * dev, char * buf) { struct node *node_dev = to_node(dev); - cpumask_t mask = node_dev->cpumap; + cpumask_t mask = node_to_cpumask(node_dev->sysdev.id); int len; /* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */ @@ -38,11 +38,19 @@ int n; int nid = dev->id; struct sysinfo i; + unsigned long inactive; + unsigned long active; + unsigned long free; + si_meminfo_node(&i, nid); + __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid)); + n = sprintf(buf, "\n" "Node %d MemTotal: %8lu kB\n" "Node %d MemFree: %8lu kB\n" "Node %d MemUsed: %8lu kB\n" + "Node %d Active: %8lu kB\n" + "Node %d Inactive: %8lu kB\n" "Node %d HighTotal: %8lu kB\n" "Node %d HighFree: %8lu kB\n" "Node %d LowTotal: %8lu kB\n" @@ -50,6 +58,8 @@ nid, K(i.totalram), nid, K(i.freeram), nid, K(i.totalram - i.freeram), + nid, K(active), + nid, K(inactive), nid, K(i.totalhigh), nid, K(i.freehigh), nid, K(i.totalram - i.totalhigh), @@ -111,7 +121,6 @@ { int error; - node->cpumap = node_to_cpumask(num); node->sysdev.id = num; node->sysdev.cls = &node_class; error = sysdev_register(&node->sysdev); diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/block/DAC960.c 2004-10-18 14:56:49 -07:00 @@ -288,12 +288,17 @@ Controller->PCIDevice, DAC960_V2_ScatterGatherLimit * sizeof(DAC960_V2_ScatterGatherSegment_T), sizeof(DAC960_V2_ScatterGatherSegment_T), 0); + if (ScatterGatherPool == NULL) + return DAC960_Failure(Controller, + "AUXILIARY STRUCTURE CREATION (SG)"); RequestSensePool = pci_pool_create("DAC960_V2_RequestSense", Controller->PCIDevice, sizeof(DAC960_SCSI_RequestSense_T), sizeof(int), 0); - if (ScatterGatherPool == NULL || RequestSensePool == NULL) + if (RequestSensePool == NULL) { + pci_pool_destroy(ScatterGatherPool); return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION (SG)"); + } Controller->ScatterGatherPool = ScatterGatherPool; Controller->V2.RequestSensePool = RequestSensePool; } @@ -535,7 +540,7 @@ static void DAC960_BA_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_CommandMailbox_T *NextCommandMailbox = Controller->V2.NextCommandMailbox; @@ -560,7 +565,7 @@ static void DAC960_LP_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_CommandMailbox_T *NextCommandMailbox = Controller->V2.NextCommandMailbox; @@ -586,7 +591,7 @@ static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -612,7 +617,7 @@ static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -638,7 +643,7 @@ static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -664,7 +669,7 @@ static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -689,7 +694,7 @@ static void DAC960_PD_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; while (DAC960_PD_MailboxFullP(ControllerBaseAddress)) @@ -706,7 +711,7 @@ static void DAC960_P_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; switch (CommandMailbox->Common.CommandOpcode) @@ -1127,7 +1132,7 @@ static boolean DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_HardwareType_T hw_type = Controller->HardwareType; struct pci_dev *PCI_Device = Controller->PCIDevice; struct dma_loaf *DmaPages = &Controller->DmaPages; @@ -1333,7 +1338,7 @@ static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; struct pci_dev *PCI_Device = Controller->PCIDevice; struct dma_loaf *DmaPages = &Controller->DmaPages; size_t DmaPagesSize; @@ -2674,7 +2679,7 @@ unsigned char DeviceFunction = PCI_Device->devfn; unsigned char ErrorStatus, Parameter0, Parameter1; unsigned int IRQ_Channel = PCI_Device->irq; - void *BaseAddress; + void __iomem *BaseAddress; int i; Controller = (DAC960_Controller_T *) @@ -5196,7 +5201,7 @@ struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5239,7 +5244,7 @@ struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5282,7 +5287,7 @@ struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5321,7 +5326,7 @@ struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5360,7 +5365,7 @@ struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; unsigned long flags; spin_lock_irqsave(&Controller->queue_lock, flags); @@ -5399,7 +5404,7 @@ struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; unsigned long flags; spin_lock_irqsave(&Controller->queue_lock, flags); diff -Nru a/drivers/block/DAC960.h b/drivers/block/DAC960.h --- a/drivers/block/DAC960.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/block/DAC960.h 2004-10-18 14:56:49 -07:00 @@ -2282,8 +2282,8 @@ typedef struct DAC960_Controller { - void *BaseAddress; - void *MemoryMappedAddress; + void __iomem *BaseAddress; + void __iomem *MemoryMappedAddress; DAC960_FirmwareType_T FirmwareType; DAC960_HardwareType_T HardwareType; DAC960_IO_Address_T IO_Address; @@ -2527,7 +2527,7 @@ * dma_addr_t. */ static inline -void dma_addr_writeql(dma_addr_t addr, void *write_address) +void dma_addr_writeql(dma_addr_t addr, void __iomem *write_address) { union { u64 wq; @@ -2643,7 +2643,7 @@ */ static inline -void DAC960_BA_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_BA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2653,7 +2653,7 @@ } static inline -void DAC960_BA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2663,7 +2663,7 @@ } static inline -void DAC960_BA_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_BA_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2673,7 +2673,7 @@ } static inline -void DAC960_BA_ControllerReset(void *ControllerBaseAddress) +void DAC960_BA_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2683,7 +2683,7 @@ } static inline -void DAC960_BA_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_BA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2693,7 +2693,7 @@ } static inline -boolean DAC960_BA_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -2702,7 +2702,7 @@ } static inline -boolean DAC960_BA_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -2711,7 +2711,7 @@ } static inline -void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -2721,7 +2721,7 @@ } static inline -void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -2731,7 +2731,7 @@ } static inline -void DAC960_BA_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -2742,7 +2742,7 @@ } static inline -boolean DAC960_BA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -2751,7 +2751,7 @@ } static inline -boolean DAC960_BA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -2760,7 +2760,7 @@ } static inline -void DAC960_BA_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_BA_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -2771,7 +2771,7 @@ } static inline -void DAC960_BA_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_BA_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -2782,7 +2782,7 @@ } static inline -boolean DAC960_BA_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -2805,7 +2805,7 @@ static inline -void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_BA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, dma_addr_t CommandMailboxDMA) { dma_addr_writeql(CommandMailboxDMA, @@ -2814,19 +2814,19 @@ } static inline DAC960_V2_CommandIdentifier_T -DAC960_BA_ReadCommandIdentifier(void *ControllerBaseAddress) +DAC960_BA_ReadCommandIdentifier(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset); } static inline DAC960_V2_CommandStatus_T -DAC960_BA_ReadCommandStatus(void *ControllerBaseAddress) +DAC960_BA_ReadCommandStatus(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset + 2); } static inline boolean -DAC960_BA_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_BA_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -2948,7 +2948,7 @@ */ static inline -void DAC960_LP_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LP_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2958,7 +2958,7 @@ } static inline -void DAC960_LP_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2968,7 +2968,7 @@ } static inline -void DAC960_LP_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_LP_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2978,7 +2978,7 @@ } static inline -void DAC960_LP_ControllerReset(void *ControllerBaseAddress) +void DAC960_LP_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2988,7 +2988,7 @@ } static inline -void DAC960_LP_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LP_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2998,7 +2998,7 @@ } static inline -boolean DAC960_LP_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3007,7 +3007,7 @@ } static inline -boolean DAC960_LP_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3016,7 +3016,7 @@ } static inline -void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3026,7 +3026,7 @@ } static inline -void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3036,7 +3036,7 @@ } static inline -void DAC960_LP_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3047,7 +3047,7 @@ } static inline -boolean DAC960_LP_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3056,7 +3056,7 @@ } static inline -boolean DAC960_LP_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3065,7 +3065,7 @@ } static inline -void DAC960_LP_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_LP_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3075,7 +3075,7 @@ } static inline -void DAC960_LP_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_LP_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3085,7 +3085,7 @@ } static inline -boolean DAC960_LP_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3107,7 +3107,7 @@ } static inline -void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_LP_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, dma_addr_t CommandMailboxDMA) { dma_addr_writeql(CommandMailboxDMA, @@ -3116,19 +3116,19 @@ } static inline DAC960_V2_CommandIdentifier_T -DAC960_LP_ReadCommandIdentifier(void *ControllerBaseAddress) +DAC960_LP_ReadCommandIdentifier(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset); } static inline DAC960_V2_CommandStatus_T -DAC960_LP_ReadCommandStatus(void *ControllerBaseAddress) +DAC960_LP_ReadCommandStatus(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset + 2); } static inline boolean -DAC960_LP_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_LP_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -3262,7 +3262,7 @@ */ static inline -void DAC960_LA_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3272,7 +3272,7 @@ } static inline -void DAC960_LA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3282,7 +3282,7 @@ } static inline -void DAC960_LA_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_LA_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3292,7 +3292,7 @@ } static inline -void DAC960_LA_ControllerReset(void *ControllerBaseAddress) +void DAC960_LA_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3302,7 +3302,7 @@ } static inline -void DAC960_LA_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3312,7 +3312,7 @@ } static inline -boolean DAC960_LA_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3321,7 +3321,7 @@ } static inline -boolean DAC960_LA_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3330,7 +3330,7 @@ } static inline -void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3340,7 +3340,7 @@ } static inline -void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3350,7 +3350,7 @@ } static inline -void DAC960_LA_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3361,7 +3361,7 @@ } static inline -boolean DAC960_LA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3370,7 +3370,7 @@ } static inline -boolean DAC960_LA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3379,7 +3379,7 @@ } static inline -void DAC960_LA_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_LA_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3389,7 +3389,7 @@ } static inline -void DAC960_LA_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_LA_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3399,7 +3399,7 @@ } static inline -boolean DAC960_LA_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3422,7 +3422,7 @@ } static inline -void DAC960_LA_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_LA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, DAC960_V1_CommandMailbox_T *CommandMailbox) { writel(CommandMailbox->Words[0], @@ -3436,20 +3436,20 @@ } static inline DAC960_V1_CommandIdentifier_T -DAC960_LA_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +DAC960_LA_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) { return readb(ControllerBaseAddress + DAC960_LA_StatusCommandIdentifierRegOffset); } static inline DAC960_V1_CommandStatus_T -DAC960_LA_ReadStatusRegister(void *ControllerBaseAddress) +DAC960_LA_ReadStatusRegister(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_LA_StatusRegisterOffset); } static inline boolean -DAC960_LA_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_LA_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -3583,7 +3583,7 @@ */ static inline -void DAC960_PG_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_PG_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3593,7 +3593,7 @@ } static inline -void DAC960_PG_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3603,7 +3603,7 @@ } static inline -void DAC960_PG_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_PG_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3613,7 +3613,7 @@ } static inline -void DAC960_PG_ControllerReset(void *ControllerBaseAddress) +void DAC960_PG_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3623,7 +3623,7 @@ } static inline -void DAC960_PG_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_PG_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3633,7 +3633,7 @@ } static inline -boolean DAC960_PG_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3642,7 +3642,7 @@ } static inline -boolean DAC960_PG_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3651,7 +3651,7 @@ } static inline -void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3661,7 +3661,7 @@ } static inline -void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3671,7 +3671,7 @@ } static inline -void DAC960_PG_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3682,7 +3682,7 @@ } static inline -boolean DAC960_PG_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3691,7 +3691,7 @@ } static inline -boolean DAC960_PG_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3700,7 +3700,7 @@ } static inline -void DAC960_PG_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_PG_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0; @@ -3712,7 +3712,7 @@ } static inline -void DAC960_PG_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_PG_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0; @@ -3724,7 +3724,7 @@ } static inline -boolean DAC960_PG_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3747,7 +3747,7 @@ } static inline -void DAC960_PG_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_PG_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, DAC960_V1_CommandMailbox_T *CommandMailbox) { writel(CommandMailbox->Words[0], @@ -3761,20 +3761,20 @@ } static inline DAC960_V1_CommandIdentifier_T -DAC960_PG_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +DAC960_PG_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) { return readb(ControllerBaseAddress + DAC960_PG_StatusCommandIdentifierRegOffset); } static inline DAC960_V1_CommandStatus_T -DAC960_PG_ReadStatusRegister(void *ControllerBaseAddress) +DAC960_PG_ReadStatusRegister(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_PG_StatusRegisterOffset); } static inline boolean -DAC960_PG_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_PG_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -3903,7 +3903,7 @@ */ static inline -void DAC960_PD_NewCommand(void *ControllerBaseAddress) +void DAC960_PD_NewCommand(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3913,7 +3913,7 @@ } static inline -void DAC960_PD_AcknowledgeStatus(void *ControllerBaseAddress) +void DAC960_PD_AcknowledgeStatus(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3923,7 +3923,7 @@ } static inline -void DAC960_PD_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_PD_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3933,7 +3933,7 @@ } static inline -void DAC960_PD_ControllerReset(void *ControllerBaseAddress) +void DAC960_PD_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3943,7 +3943,7 @@ } static inline -boolean DAC960_PD_MailboxFullP(void *ControllerBaseAddress) +boolean DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3952,7 +3952,7 @@ } static inline -boolean DAC960_PD_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3961,7 +3961,7 @@ } static inline -void DAC960_PD_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_PD_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3971,7 +3971,7 @@ } static inline -boolean DAC960_PD_StatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3980,7 +3980,7 @@ } static inline -void DAC960_PD_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_PD_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; InterruptEnableRegister.All = 0; @@ -3990,7 +3990,7 @@ } static inline -void DAC960_PD_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_PD_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; InterruptEnableRegister.All = 0; @@ -4000,7 +4000,7 @@ } static inline -boolean DAC960_PD_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; InterruptEnableRegister.All = @@ -4009,7 +4009,7 @@ } static inline -void DAC960_PD_WriteCommandMailbox(void *ControllerBaseAddress, +void DAC960_PD_WriteCommandMailbox(void __iomem *ControllerBaseAddress, DAC960_V1_CommandMailbox_T *CommandMailbox) { writel(CommandMailbox->Words[0], @@ -4023,20 +4023,20 @@ } static inline DAC960_V1_CommandIdentifier_T -DAC960_PD_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +DAC960_PD_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) { return readb(ControllerBaseAddress + DAC960_PD_StatusCommandIdentifierRegOffset); } static inline DAC960_V1_CommandStatus_T -DAC960_PD_ReadStatusRegister(void *ControllerBaseAddress) +DAC960_PD_ReadStatusRegister(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_PD_StatusRegisterOffset); } static inline boolean -DAC960_PD_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_PD_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) diff -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig --- a/drivers/block/Kconfig 2004-10-18 14:56:18 -07:00 +++ b/drivers/block/Kconfig 2004-10-18 14:56:18 -07:00 @@ -166,7 +166,7 @@ config CISS_SCSI_TAPE bool "SCSI tape drive support for Smart Array 5xxx" - depends on BLK_CPQ_CISS_DA && SCSI + depends on BLK_CPQ_CISS_DA && SCSI && PROC_FS help When enabled (Y), this option allows SCSI tape drives and SCSI medium changers (tape robots) to be accessed via a Compaq 5xxx array @@ -300,6 +300,15 @@ Promise SATA SX8 controllers. Use devices /dev/sx8/$N and /dev/sx8/$Np$M. + +config BLK_DEV_UB + tristate "Low Performance USB Block driver" + depends on USB + help + This driver supports certain USB attached storage devices + such as flash keys. + + If unsure, say N. config BLK_DEV_RAM tristate "RAM disk support" diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile --- a/drivers/block/Makefile 2004-10-18 14:56:49 -07:00 +++ b/drivers/block/Makefile 2004-10-18 14:56:49 -07:00 @@ -42,4 +42,5 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o +obj-$(CONFIG_BLK_DEV_UB) += ub.o diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c --- a/drivers/block/amiflop.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/block/amiflop.c 2004-10-18 14:56:29 -07:00 @@ -386,16 +386,6 @@ fd_select(drive); udelay (1); fd_deselect(drive); - -#ifdef MODULE -/* - this is the last interrupt for any drive access, happens after - release (from floppy_off). So we have to wait until now to decrease - the use count. -*/ - if (decusecount) - MOD_DEC_USE_COUNT; -#endif } static void floppy_off (unsigned int nr) @@ -1590,10 +1580,6 @@ local_irq_save(flags); fd_ref[drive]++; fd_device[drive] = system; -#ifdef MODULE - if (unit[drive].motor == 0) - MOD_INC_USE_COUNT; -#endif local_irq_restore(flags); unit[drive].dtype=&data_types[system]; @@ -1839,6 +1825,7 @@ return amiga_floppy_init(); } +#if 0 /* not safe to unload */ void cleanup_module(void) { int i; @@ -1859,4 +1846,5 @@ release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(FLOPPY_MAJOR, "fd"); } +#endif #endif diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/block/cciss.c 2004-10-18 14:57:04 -07:00 @@ -46,14 +46,14 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq CISS Driver (v 2.6.2)" +#define DRIVER_NAME "HP CISS Driver (v 2.6.2)" #define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,2) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.2"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i"); + " SA6i V100"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -82,7 +82,7 @@ 0x0E11, 0x4091, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409E, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS, 0x103C, 0x3211, 0, 0, 0}, {0,} }; @@ -115,7 +115,7 @@ /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 -#define READ_AHEAD 256 +#define READ_AHEAD 1024 #define NR_CMDS 384 /* #commands that can be outstanding */ #define MAX_CTLR 8 @@ -192,10 +192,10 @@ /* * Report information about this controller. */ -#define ENG_GIG 1048576000 +#define ENG_GIG 1000000000 #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", +static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG", "UNKNOWN"}; static struct proc_dir_entry *proc_cciss; @@ -209,7 +209,7 @@ ctlr_info_t *h = (ctlr_info_t*)data; drive_info_struct *drv; unsigned long flags; - unsigned int vol_sz, vol_sz_frac; + sector_t vol_sz, vol_sz_frac; ctlr = h->ctlr; @@ -246,32 +246,21 @@ pos += size; len += size; cciss_proc_tape_report(ctlr, buffer, &pos, &len); for(i=0; i<=h->highest_lun; i++) { - sector_t tmp; drv = &h->drv[i]; if (drv->block_size == 0) continue; - 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 = drv->nr_blocks; + vol_sz_frac = sector_div(vol_sz, 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, + "\t%4u.%02uGB\tRAID %s\n", + ctlr, i, (int)vol_sz, (int)vol_sz_frac, raid_label[drv->raid_level]); pos += size; len += size; } @@ -578,7 +567,7 @@ err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) p); if (err) return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -610,7 +599,7 @@ err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) p); if (err) return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -866,6 +855,8 @@ kfree(buff); return -EFAULT; } + } else { + memset(buff, 0, iocommand.buf_size); } if ((c = cmd_alloc(host , 0)) == NULL) { @@ -1012,6 +1003,8 @@ copy_from_user(buff[sg_used], data_ptr, sz)) { status = -ENOMEM; goto cleanup1; + } else { + memset(buff[sg_used], 0, sz); } left -= sz; data_ptr += sz; @@ -1477,12 +1470,19 @@ drv->sectors = 32; // Sectors per track drv->cylinders = total_size / 255 / 32; } else { + unsigned int t; + drv->block_size = block_size; drv->nr_blocks = total_size; drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8; drv->cylinders += inq_buff->data_byte[5]; + drv->raid_level = inq_buff->data_byte[8]; + t = drv->heads * drv->sectors; + if (t > 1) { + drv->cylinders = total_size/t; + } } } else { /* Get geometry failed */ printk(KERN_WARNING "cciss: reading geometry failed, " @@ -1509,8 +1509,8 @@ return_code = sendcmd(CCISS_READ_CAPACITY, ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD); if (return_code == IO_OK) { - *total_size = be32_to_cpu(*((__u32 *) &buf->total_size[0]))+1; - *block_size = be32_to_cpu(*((__u32 *) &buf->block_size[0])); + *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1; + *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0])); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; @@ -1844,13 +1844,13 @@ /* * Map (physical) PCI mem into (virtual) kernel space */ -static ulong remap_pci_mem(ulong base, ulong size) +static void __iomem *remap_pci_mem(ulong base, ulong size) { ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; - ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + void __iomem *page_remapped = ioremap(page_base, page_offs+size); - return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); + return page_remapped ? (page_remapped + page_offs) : NULL; } /* @@ -2300,7 +2300,6 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort subsystem_vendor_id, subsystem_device_id, command; - unchar irq = pdev->irq; __u32 board_id, scratchpad = 0; __u64 cfg_offset; __u32 cfg_base_addr; @@ -2359,11 +2358,11 @@ #ifdef CCISS_DEBUG printk("command = %x\n", command); - printk("irq = %x\n", irq); + printk("irq = %x\n", pdev->irq); printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ - c->intr = irq; + c->intr = pdev->irq; /* * Memory base addr is first addr , the second points to the config @@ -2411,9 +2410,9 @@ #ifdef CCISS_DEBUG printk("cfg offset = %x\n", cfg_offset); #endif /* CCISS_DEBUG */ - c->cfgtable = (CfgTable_struct *) - remap_pci_mem(pci_resource_start(pdev, cfg_base_addr_index) - + cfg_offset, sizeof(CfgTable_struct)); + c->cfgtable = remap_pci_mem(pci_resource_start(pdev, + cfg_base_addr_index) + cfg_offset, + sizeof(CfgTable_struct)); c->board_id = board_id; #ifdef CCISS_DEBUG @@ -2825,7 +2824,7 @@ } free_irq(hba[i]->intr, hba[i]); pci_set_drvdata(pdev, NULL); - iounmap((void*)hba[i]->vaddr); + iounmap(hba[i]->vaddr); cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); diff -Nru a/drivers/block/cciss.h b/drivers/block/cciss.h --- a/drivers/block/cciss.h 2004-10-18 14:55:53 -07:00 +++ b/drivers/block/cciss.h 2004-10-18 14:55:53 -07:00 @@ -43,12 +43,12 @@ char firm_ver[4]; // Firmware version struct pci_dev *pdev; __u32 board_id; - unsigned long vaddr; + void __iomem *vaddr; unsigned long paddr; unsigned long io_mem_addr; unsigned long io_mem_length; - CfgTable_struct *cfgtable; - int intr; + CfgTable_struct __iomem *cfgtable; + unsigned int intr; int interrupts_enabled; int max_commands; int commands_outstanding; diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c --- a/drivers/block/cpqarray.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/block/cpqarray.c 2004-10-18 14:55:55 -07:00 @@ -138,7 +138,7 @@ int cpqarray_init_step2(void); static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev); -static void *remap_pci_mem(ulong base, ulong size); +static void __iomem *remap_pci_mem(ulong base, ulong size); static int cpqarray_eisa_detect(void); static int pollcomplete(int ctlr); static void getgeometry(int ctlr); @@ -551,10 +551,10 @@ } static struct pci_driver cpqarray_pci_driver = { - name: "cpqarray", - probe: cpqarray_init_one, - remove: __devexit_p(cpqarray_remove_one_pci), - id_table: cpqarray_pci_device_id, + .name = "cpqarray", + .probe = cpqarray_init_one, + .remove = __devexit_p(cpqarray_remove_one_pci), + .id_table = cpqarray_pci_device_id, }; /* @@ -722,11 +722,11 @@ /* * Map (physical) PCI mem into (virtual) kernel space */ -static void *remap_pci_mem(ulong base, ulong size) +static void __iomem *remap_pci_mem(ulong base, ulong size) { ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; - void *page_remapped = ioremap(page_base, page_offs+size); + void __iomem *page_remapped = ioremap(page_base, page_offs+size); return (page_remapped ? (page_remapped + page_offs) : NULL); } diff -Nru a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h --- a/drivers/block/cpqarray.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/block/cpqarray.h 2004-10-18 14:56:33 -07:00 @@ -90,7 +90,7 @@ __u32 board_id; char *product_name; - void *vaddr; + void __iomem *vaddr; unsigned long paddr; unsigned long io_mem_addr; unsigned long io_mem_length; diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c --- a/drivers/block/genhd.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/block/genhd.c 2004-10-18 14:56:29 -07:00 @@ -365,7 +365,9 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page) { + preempt_disable(); disk_round_stats(disk); + preempt_enable(); return sprintf(page, "%8u %8u %8llu %8u " "%8u %8u %8llu %8u " @@ -494,7 +496,9 @@ "\n\n"); */ + preempt_disable(); disk_round_stats(gp); + preempt_enable(); seq_printf(s, "%4d %4d %s %u %u %llu %u %u %u %llu %u %u %u %u\n", gp->major, n + gp->first_minor, disk_name(gp, n, buf), disk_stat_read(gp, reads), disk_stat_read(gp, read_merges), diff -Nru a/drivers/block/ioctl.c b/drivers/block/ioctl.c --- a/drivers/block/ioctl.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/block/ioctl.c 2004-10-18 14:55:54 -07:00 @@ -194,7 +194,8 @@ return -EACCES; if (disk->fops->ioctl) { ret = disk->fops->ioctl(inode, file, cmd, arg); - if (ret != -EINVAL) + /* -EINVAL to handle old uncorrected drivers */ + if (ret != -EINVAL && ret != -ENOTTY) return ret; } fsync_bdev(bdev); diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/block/ll_rw_blk.c 2004-10-18 14:55:54 -07:00 @@ -154,6 +154,8 @@ return ret; } +EXPORT_SYMBOL(blk_get_backing_dev_info); + void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) { q->activity_fn = fn; @@ -263,6 +265,45 @@ EXPORT_SYMBOL(blk_queue_make_request); /** + * blk_queue_ordered - does this queue support ordered writes + * @q: the request queue + * @flag: see below + * + * Description: + * For journalled file systems, doing ordered writes on a commit + * block instead of explicitly doing wait_on_buffer (which is bad + * for performance) can be a big win. Block drivers supporting this + * feature should call this function and indicate so. + * + **/ +void blk_queue_ordered(request_queue_t *q, int flag) +{ + if (flag) + set_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); + else + clear_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); +} + +EXPORT_SYMBOL(blk_queue_ordered); + +/** + * blk_queue_issue_flush_fn - set function for issuing a flush + * @q: the request queue + * @iff: the function to be called issuing the flush + * + * Description: + * If a driver supports issuing a flush command, the support is notified + * to the block layer by defining it through this call. + * + **/ +void blk_queue_issue_flush_fn(request_queue_t *q, issue_flush_fn *iff) +{ + q->issue_flush_fn = iff; +} + +EXPORT_SYMBOL(blk_queue_issue_flush_fn); + +/** * blk_queue_bounce_limit - set bounce buffer limit for queue * @q: the request queue for the device * @dma_addr: bus address limit @@ -311,7 +352,7 @@ printk("%s: set to minimum %d\n", __FUNCTION__, max_sectors); } - q->max_sectors = max_sectors; + q->max_sectors = q->max_hw_sectors = max_sectors; } EXPORT_SYMBOL(blk_queue_max_sectors); @@ -413,7 +454,8 @@ void blk_queue_stack_limits(request_queue_t *t, request_queue_t *b) { /* zero is "infinity" */ - t->max_sectors = min_not_zero(t->max_sectors,b->max_sectors); + t->max_sectors = t->max_hw_sectors = + min_not_zero(t->max_sectors,b->max_sectors); t->max_phys_segments = min(t->max_phys_segments,b->max_phys_segments); t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments); @@ -482,15 +524,14 @@ EXPORT_SYMBOL(blk_queue_find_tag); /** - * blk_queue_free_tags - release tag maintenance info + * __blk_queue_free_tags - release tag maintenance info * @q: the request queue for the device * * Notes: * blk_cleanup_queue() will take care of calling this function, if tagging - * has been used. So there's usually no need to call this directly, unless - * tagging is just being disabled but the queue remains in function. + * has been used. So there's no need to call this directly. **/ -void blk_queue_free_tags(request_queue_t *q) +static void __blk_queue_free_tags(request_queue_t *q) { struct blk_queue_tag *bqt = q->queue_tags; @@ -514,12 +555,27 @@ q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED); } +/** + * blk_queue_free_tags - release tag maintenance info + * @q: the request queue for the device + * + * Notes: + * This is used to disabled tagged queuing to a device, yet leave + * queue in function. + **/ +void blk_queue_free_tags(request_queue_t *q) +{ + clear_bit(QUEUE_FLAG_QUEUED, &q->queue_flags); +} + EXPORT_SYMBOL(blk_queue_free_tags); static int init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth) { int bits, i; + struct request **tag_index; + unsigned long *tag_map; if (depth > q->nr_requests * 2) { depth = q->nr_requests * 2; @@ -527,32 +583,31 @@ __FUNCTION__, depth); } - tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); - if (!tags->tag_index) + tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); + if (!tag_index) goto fail; bits = (depth / BLK_TAGS_PER_LONG) + 1; - tags->tag_map = kmalloc(bits * sizeof(unsigned long), GFP_ATOMIC); - if (!tags->tag_map) + tag_map = kmalloc(bits * sizeof(unsigned long), GFP_ATOMIC); + if (!tag_map) goto fail; - memset(tags->tag_index, 0, depth * sizeof(struct request *)); - memset(tags->tag_map, 0, bits * sizeof(unsigned long)); + memset(tag_index, 0, depth * sizeof(struct request *)); + memset(tag_map, 0, bits * sizeof(unsigned long)); tags->max_depth = depth; tags->real_max_depth = bits * BITS_PER_LONG; + tags->tag_index = tag_index; + tags->tag_map = tag_map; /* * set the upper bits if the depth isn't a multiple of the word size */ for (i = depth; i < bits * BLK_TAGS_PER_LONG; i++) - __set_bit(i, tags->tag_map); + __set_bit(i, tag_map); - INIT_LIST_HEAD(&tags->busy_list); - tags->busy = 0; - atomic_set(&tags->refcnt, 1); return 0; fail: - kfree(tags->tag_index); + kfree(tag_index); return -ENOMEM; } @@ -564,13 +619,26 @@ int blk_queue_init_tags(request_queue_t *q, int depth, struct blk_queue_tag *tags) { - if (!tags) { + int rc; + + BUG_ON(tags && q->queue_tags && tags != q->queue_tags); + + if (!tags && !q->queue_tags) { tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC); if (!tags) goto fail; if (init_tag_map(q, tags, depth)) goto fail; + + INIT_LIST_HEAD(&tags->busy_list); + tags->busy = 0; + atomic_set(&tags->refcnt, 1); + } else if (q->queue_tags) { + if ((rc = blk_queue_resize_tags(q, depth))) + return rc; + set_bit(QUEUE_FLAG_QUEUED, &q->queue_flags); + return 0; } else atomic_inc(&tags->refcnt); @@ -1335,8 +1403,8 @@ if (rl->rq_pool) mempool_destroy(rl->rq_pool); - if (blk_queue_tagged(q)) - blk_queue_free_tags(q); + if (q->queue_tags) + __blk_queue_free_tags(q); kmem_cache_free(requestq_cachep, q); } @@ -1925,10 +1993,11 @@ } rq->flags |= REQ_NOMERGE; - rq->waiting = &wait; + if (!rq->waiting) + rq->waiting = &wait; elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); generic_unplug_device(q); - wait_for_completion(&wait); + wait_for_completion(rq->waiting); rq->waiting = NULL; if (rq->errors) @@ -1939,6 +2008,72 @@ EXPORT_SYMBOL(blk_execute_rq); +/** + * blkdev_issue_flush - queue a flush + * @bdev: blockdev to issue flush for + * @error_sector: error sector + * + * Description: + * Issue a flush for the block device in question. Caller can supply + * room for storing the error offset in case of a flush error, if they + * wish to. Caller must run wait_for_completion() on its own. + */ +int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) +{ + request_queue_t *q; + + if (bdev->bd_disk == NULL) + return -ENXIO; + + q = bdev_get_queue(bdev); + if (!q) + return -ENXIO; + if (!q->issue_flush_fn) + return -EOPNOTSUPP; + + return q->issue_flush_fn(q, bdev->bd_disk, error_sector); +} + +EXPORT_SYMBOL(blkdev_issue_flush); + +/** + * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices + * @q: device queue + * @disk: gendisk + * @error_sector: error offset + * + * Description: + * Devices understanding the SCSI command set, can use this function as + * a helper for issuing a cache flush. Note: driver is required to store + * the error offset (in case of error flushing) in ->sector of struct + * request. + */ +int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT); + int ret; + + rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; + rq->sector = 0; + memset(rq->cmd, 0, sizeof(rq->cmd)); + rq->cmd[0] = 0x35; + rq->cmd_len = 12; + rq->data = NULL; + rq->data_len = 0; + rq->timeout = 60 * HZ; + + ret = blk_execute_rq(q, disk, rq); + + if (ret && error_sector) + *error_sector = rq->sector; + + blk_put_request(rq); + return ret; +} + +EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn); + void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { int rw = rq_data_dir(rq); @@ -2192,7 +2327,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; - int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra; + int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err; sector_t sector; sector = bio->bi_sector; @@ -2210,9 +2345,11 @@ spin_lock_prefetch(q->queue_lock); - barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); - - ra = bio->bi_rw & (1 << BIO_RW_AHEAD); + barrier = bio_barrier(bio); + if (barrier && !(q->queue_flags & (1 << QUEUE_FLAG_ORDERED))) { + err = -EOPNOTSUPP; + goto end_io; + } again: spin_lock_irq(q->queue_lock); @@ -2292,7 +2429,8 @@ /* * READA bit set */ - if (ra) + err = -EWOULDBLOCK; + if (bio_rw_ahead(bio)) goto end_io; freereq = get_request_wait(q, rw); @@ -2303,10 +2441,9 @@ req->flags |= REQ_CMD; /* - * inherit FAILFAST from bio and don't stack up - * retries for read ahead + * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST) */ - if (ra || test_bit(BIO_RW_FAILFAST, &bio->bi_rw)) + if (bio_rw_ahead(bio) || bio_failfast(bio)) req->flags |= REQ_FAILFAST; /* @@ -2340,7 +2477,7 @@ return 0; end_io: - bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK); + bio_endio(bio, nr_sectors << 9, err); return 0; } @@ -2399,6 +2536,7 @@ sector_t maxsector; int ret, nr_sectors = bio_sectors(bio); + might_sleep(); /* Test device or partition size, when known. */ maxsector = bio->bi_bdev->bd_inode->i_size >> 9; if (maxsector) { @@ -2446,11 +2584,11 @@ break; } - if (unlikely(bio_sectors(bio) > q->max_sectors)) { + if (unlikely(bio_sectors(bio) > q->max_hw_sectors)) { printk("bio too big device %s (%u > %u)\n", bdevname(bio->bi_bdev, b), bio_sectors(bio), - q->max_sectors); + q->max_hw_sectors); goto end_io; } @@ -2647,10 +2785,17 @@ static int __end_that_request_first(struct request *req, int uptodate, int nr_bytes) { - int total_bytes, bio_nbytes, error = 0, next_idx = 0; + int total_bytes, bio_nbytes, error, next_idx = 0; struct bio *bio; /* + * extend uptodate bool to allow < 0 value to be direct io error + */ + error = 0; + if (end_io_error(uptodate)) + error = !uptodate ? -EIO : uptodate; + + /* * for a REQ_BLOCK_PC request, we want to carry any eventual * sense key with us all the way through */ @@ -2658,7 +2803,6 @@ req->errors = 0; if (!uptodate) { - error = -EIO; if (blk_fs_request(req) && !(req->flags & REQ_QUIET)) printk("end_request: I/O error, dev %s, sector %llu\n", req->rq_disk ? req->rq_disk->disk_name : "?", @@ -2741,7 +2885,7 @@ /** * end_that_request_first - end I/O on a request * @req: the request being processed - * @uptodate: 0 for I/O error + * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error * @nr_sectors: number of sectors to end I/O on * * Description: @@ -2762,7 +2906,7 @@ /** * end_that_request_chunk - end I/O on a request * @req: the request being processed - * @uptodate: 0 for I/O error + * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error * @nr_bytes: number of bytes to complete * * Description: @@ -3063,13 +3207,61 @@ unsigned long ra_kb; ssize_t ret = queue_var_store(&ra_kb, page, count); + spin_lock_irq(q->queue_lock); if (ra_kb > (q->max_sectors >> 1)) ra_kb = (q->max_sectors >> 1); q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10); + spin_unlock_irq(q->queue_lock); + + return ret; +} + +static ssize_t queue_max_sectors_show(struct request_queue *q, char *page) +{ + int max_sectors_kb = q->max_sectors >> 1; + + return queue_var_show(max_sectors_kb, (page)); +} + +static ssize_t +queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) +{ + unsigned long max_sectors_kb, + max_hw_sectors_kb = q->max_hw_sectors >> 1, + page_kb = 1 << (PAGE_CACHE_SHIFT - 10); + ssize_t ret = queue_var_store(&max_sectors_kb, page, count); + int ra_kb; + + if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) + return -EINVAL; + /* + * Take the queue lock to update the readahead and max_sectors + * values synchronously: + */ + spin_lock_irq(q->queue_lock); + /* + * Trim readahead window as well, if necessary: + */ + ra_kb = q->backing_dev_info.ra_pages << (PAGE_CACHE_SHIFT - 10); + if (ra_kb > max_sectors_kb) + q->backing_dev_info.ra_pages = + max_sectors_kb >> (PAGE_CACHE_SHIFT - 10); + + q->max_sectors = max_sectors_kb << 1; + spin_unlock_irq(q->queue_lock); + return ret; } +static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page) +{ + int max_hw_sectors_kb = q->max_hw_sectors >> 1; + + return queue_var_show(max_hw_sectors_kb, (page)); +} + + static struct queue_sysfs_entry queue_requests_entry = { .attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR }, .show = queue_requests_show, @@ -3082,9 +3274,22 @@ .store = queue_ra_store, }; +static struct queue_sysfs_entry queue_max_sectors_entry = { + .attr = {.name = "max_sectors_kb", .mode = S_IRUGO | S_IWUSR }, + .show = queue_max_sectors_show, + .store = queue_max_sectors_store, +}; + +static struct queue_sysfs_entry queue_max_hw_sectors_entry = { + .attr = {.name = "max_hw_sectors_kb", .mode = S_IRUGO }, + .show = queue_max_hw_sectors_show, +}; + static struct attribute *default_attrs[] = { &queue_requests_entry.attr, &queue_ra_entry.attr, + &queue_max_hw_sectors_entry.attr, + &queue_max_sectors_entry.attr, NULL, }; diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c --- a/drivers/block/nbd.c 2004-10-18 14:56:19 -07:00 +++ b/drivers/block/nbd.c 2004-10-18 14:56:19 -07:00 @@ -128,23 +128,11 @@ { int uptodate = (req->errors == 0) ? 1 : 0; request_queue_t *q = req->q; - struct nbd_device *lo = req->rq_disk->private_data; unsigned long flags; dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name, req, uptodate? "done": "failed"); - spin_lock(&lo->queue_lock); - while (req->ref_count > 1) { /* still in send */ - spin_unlock(&lo->queue_lock); - printk(KERN_DEBUG "%s: request %p still in use (%d), waiting\n", - lo->disk->disk_name, req, req->ref_count); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); /* wait a second */ - spin_lock(&lo->queue_lock); - } - spin_unlock(&lo->queue_lock); - spin_lock_irqsave(q->queue_lock, flags); if (!end_that_request_first(req, uptodate, req->nr_sectors)) { end_that_request_last(req); @@ -228,7 +216,7 @@ return result; } -void nbd_send_req(struct nbd_device *lo, struct request *req) +static int nbd_send_req(struct nbd_device *lo, struct request *req) { int result, i, flags; struct nbd_request request; @@ -288,11 +276,11 @@ } } up(&lo->tx_lock); - return; + return 0; error_out: up(&lo->tx_lock); - req->errors++; + return 1; } static struct request *nbd_find_request(struct nbd_device *lo, char *handle) @@ -477,26 +465,19 @@ } list_add(&req->queuelist, &lo->queue_head); - req->ref_count++; /* make sure req does not get freed */ spin_unlock(&lo->queue_lock); - nbd_send_req(lo, req); - - if (req->errors) { + if (nbd_send_req(lo, req) != 0) { printk(KERN_ERR "%s: Request send failed\n", lo->disk->disk_name); - spin_lock(&lo->queue_lock); - list_del_init(&req->queuelist); - req->ref_count--; - spin_unlock(&lo->queue_lock); - nbd_end_request(req); - spin_lock_irq(q->queue_lock); - continue; + if (nbd_find_request(lo, (char *)&req) != NULL) { + /* we still own req */ + req->errors++; + nbd_end_request(req); + } else /* we're racing with nbd_clear_que */ + printk(KERN_DEBUG "nbd: can't find req\n"); } - spin_lock(&lo->queue_lock); - req->ref_count--; - spin_unlock(&lo->queue_lock); spin_lock_irq(q->queue_lock); continue; diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c --- a/drivers/block/rd.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/block/rd.c 2004-10-18 14:56:33 -07:00 @@ -349,13 +349,17 @@ if (rd_bdev[unit] == NULL) { struct block_device *bdev = inode->i_bdev; struct address_space *mapping; + unsigned bsize; int gfp_mask; inode = igrab(bdev->bd_inode); rd_bdev[unit] = bdev; bdev->bd_openers++; - bdev->bd_block_size = rd_blocksize; - inode->i_size = get_capacity(rd_disks[unit])<<9; + bsize = bdev_hardsect_size(bdev); + bdev->bd_block_size = bsize; + inode->i_blkbits = blksize_bits(bsize); + inode->i_size = get_capacity(bdev->bd_disk)<<9; + mapping = inode->i_mapping; mapping->a_ops = &ramdisk_aops; mapping->backing_dev_info = &rd_backing_dev_info; @@ -449,6 +453,7 @@ goto out_queue; blk_queue_make_request(rd_queue[i], &rd_make_request); + blk_queue_hardsect_size(rd_queue[i], rd_blocksize); /* rd_size is given in kB */ disk->major = RAMDISK_MAJOR; diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c --- a/drivers/block/scsi_ioctl.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/block/scsi_ioctl.c 2004-10-18 14:57:04 -07:00 @@ -127,12 +127,16 @@ safe_for_read(MODE_SENSE), safe_for_read(MODE_SENSE_10), safe_for_read(START_STOP), + safe_for_read(GPCMD_VERIFY_10), + safe_for_read(VERIFY_16), + safe_for_read(READ_BUFFER), /* Audio CD commands */ safe_for_read(GPCMD_PLAY_CD), safe_for_read(GPCMD_PLAY_AUDIO_10), safe_for_read(GPCMD_PLAY_AUDIO_MSF), safe_for_read(GPCMD_PLAY_AUDIO_TI), + safe_for_read(GPCMD_PAUSE_RESUME), /* CD/DVD data reading */ safe_for_read(GPCMD_READ_CD), @@ -146,6 +150,12 @@ safe_for_read(GPCMD_READ_TOC_PMA_ATIP), safe_for_read(GPCMD_REPORT_KEY), safe_for_read(GPCMD_SCAN), + safe_for_read(GPCMD_GET_CONFIGURATION), + safe_for_read(GPCMD_READ_FORMAT_CAPACITIES), + safe_for_read(GPCMD_GET_EVENT_STATUS_NOTIFICATION), + safe_for_read(GPCMD_GET_PERFORMANCE), + safe_for_read(GPCMD_SEEK), + safe_for_read(GPCMD_STOP_PLAY_SCAN), /* Basic writing commands */ safe_for_write(WRITE_6), @@ -154,8 +164,25 @@ safe_for_write(WRITE_12), safe_for_write(WRITE_VERIFY_12), safe_for_write(WRITE_16), - safe_for_write(WRITE_BUFFER), safe_for_write(WRITE_LONG), + safe_for_write(ERASE), + safe_for_write(GPCMD_MODE_SELECT_10), + safe_for_write(MODE_SELECT), + safe_for_write(GPCMD_BLANK), + safe_for_write(GPCMD_CLOSE_TRACK), + safe_for_write(GPCMD_FLUSH_CACHE), + safe_for_write(GPCMD_FORMAT_UNIT), + safe_for_write(GPCMD_REPAIR_RZONE_TRACK), + safe_for_write(GPCMD_RESERVE_RZONE_TRACK), + safe_for_write(GPCMD_SEND_DVD_STRUCTURE), + safe_for_write(GPCMD_SEND_EVENT), + safe_for_write(GPCMD_SEND_KEY), + safe_for_write(GPCMD_SEND_OPC), + safe_for_write(GPCMD_SEND_CUE_SHEET), + safe_for_write(GPCMD_SET_SPEED), + safe_for_write(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL), + safe_for_write(GPCMD_LOAD_UNLOAD), + safe_for_write(GPCMD_SET_STREAMING), }; unsigned char type = cmd_type[cmd[0]]; @@ -511,6 +538,7 @@ * old junk scsi send command ioctl */ case SCSI_IOCTL_SEND_COMMAND: + printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); err = -EINVAL; if (!arg) break; diff -Nru a/drivers/block/sx8.c b/drivers/block/sx8.c --- a/drivers/block/sx8.c 2004-10-18 14:57:20 -07:00 +++ b/drivers/block/sx8.c 2004-10-18 14:57:20 -07:00 @@ -242,7 +242,7 @@ struct carm_host { unsigned long flags; - void *mmio; + void __iomem *mmio; void *shm; dma_addr_t shm_dma; @@ -283,13 +283,13 @@ }; struct carm_response { - u32 ret_handle; - u32 status; + __le32 ret_handle; + __le32 status; } __attribute__((packed)); struct carm_msg_sg { - u32 start; - u32 len; + __le32 start; + __le32 len; } __attribute__((packed)); struct carm_msg_rw { @@ -297,10 +297,10 @@ u8 id; u8 sg_count; u8 sg_type; - u32 handle; - u32 lba; - u16 lba_count; - u16 lba_high; + __le32 handle; + __le32 lba; + __le16 lba_count; + __le16 lba_high; struct carm_msg_sg sg[32]; } __attribute__((packed)); @@ -309,15 +309,15 @@ u8 subtype; u8 n_sg; u8 sg_type; - u32 handle; - u32 addr; - u32 len; - u32 evt_pool; - u32 n_evt; - u32 rbuf_pool; - u32 n_rbuf; - u32 msg_pool; - u32 n_msg; + __le32 handle; + __le32 addr; + __le32 len; + __le32 evt_pool; + __le32 n_evt; + __le32 rbuf_pool; + __le32 n_rbuf; + __le32 msg_pool; + __le32 n_msg; struct carm_msg_sg sg[8]; } __attribute__((packed)); @@ -326,8 +326,8 @@ u8 subtype; u8 array_id; u8 reserved1; - u32 handle; - u32 data_addr; + __le32 handle; + __le32 data_addr; u32 reserved2; } __attribute__((packed)); @@ -335,48 +335,48 @@ u8 type; u8 subtype; u16 reserved1; - u32 handle; + __le32 handle; u32 reserved2; - u32 timestamp; + __le32 timestamp; } __attribute__((packed)); struct carm_msg_get_fw_ver { u8 type; u8 subtype; u16 reserved1; - u32 handle; - u32 data_addr; + __le32 handle; + __le32 data_addr; u32 reserved2; } __attribute__((packed)); struct carm_fw_ver { - u32 version; + __le32 version; u8 features; u8 reserved1; u16 reserved2; } __attribute__((packed)); struct carm_array_info { - u32 size; + __le32 size; - u16 size_hi; - u16 stripe_size; + __le16 size_hi; + __le16 stripe_size; - u32 mode; + __le32 mode; - u16 stripe_blk_sz; - u16 reserved1; + __le16 stripe_blk_sz; + __le16 reserved1; - u16 cyl; - u16 head; + __le16 cyl; + __le16 head; - u16 sect; + __le16 sect; u8 array_id; u8 reserved2; char name[40]; - u32 array_status; + __le32 array_status; /* device list continues beyond this point? */ } __attribute__((packed)); @@ -451,7 +451,7 @@ return -ENOENT; } -static void carm_init_buckets(void *mmio) +static void carm_init_buckets(void __iomem *mmio) { unsigned int i; @@ -474,7 +474,7 @@ static int carm_send_msg(struct carm_host *host, struct carm_request *crq) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; u32 msg = (u32) carm_ref_msg_dma(host, crq->tag); u32 cm_bucket = crq->msg_bucket; u32 tmp; @@ -965,7 +965,7 @@ port = &host->port[cur_port]; lo = (u64) le32_to_cpu(desc->size); - hi = (u64) le32_to_cpu(desc->size_hi); + hi = (u64) le16_to_cpu(desc->size_hi); port->capacity = lo | (hi << 32); port->dev_geom_head = le16_to_cpu(desc->head); @@ -1060,7 +1060,7 @@ } static inline void carm_handle_resp(struct carm_host *host, - u32 ret_handle_le, u32 status) + __le32 ret_handle_le, u32 status) { u32 handle = le32_to_cpu(ret_handle_le); unsigned int msg_idx; @@ -1158,7 +1158,7 @@ static inline void carm_handle_responses(struct carm_host *host) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; struct carm_response *resp = (struct carm_response *) host->shm; unsigned int work = 0; unsigned int idx = host->resp_idx % RMSG_Q_LEN; @@ -1176,7 +1176,7 @@ else if ((status & (1 << 31)) == 0) { VPRINTK("handling msg response on index %u\n", idx); carm_handle_resp(host, resp[idx].ret_handle, status); - resp[idx].status = 0xffffffff; + resp[idx].status = cpu_to_le32(0xffffffff); } /* asynchronous events the hardware throws our way */ @@ -1185,7 +1185,7 @@ u8 evt_type = *evt_type_ptr; printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n", pci_name(host->pdev), (int) evt_type); - resp[idx].status = 0xffffffff; + resp[idx].status = cpu_to_le32(0xffffffff); } idx = NEXT_RESP(idx); @@ -1199,7 +1199,7 @@ static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) { struct carm_host *host = __host; - void *mmio; + void __iomem *mmio; u32 mask; int handled = 0; unsigned long flags; @@ -1364,7 +1364,7 @@ schedule_work(&host->fsm_task); } -static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit) +static int carm_init_wait(void __iomem *mmio, u32 bits, unsigned int test_bit) { unsigned int i; @@ -1390,19 +1390,19 @@ static void carm_init_responses(struct carm_host *host) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; unsigned int i; struct carm_response *resp = (struct carm_response *) host->shm; for (i = 0; i < RMSG_Q_LEN; i++) - resp[i].status = 0xffffffff; + resp[i].status = cpu_to_le32(0xffffffff); writel(0, mmio + CARM_RESP_IDX); } static int carm_init_host(struct carm_host *host) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; u32 tmp; u8 tmp8; int rc; @@ -1414,7 +1414,7 @@ tmp8 = readb(mmio + CARM_INITC); if (tmp8 & 0x01) { tmp8 &= ~0x01; - writeb(tmp8, CARM_INITC); + writeb(tmp8, mmio + CARM_INITC); readb(mmio + CARM_INITC); /* flush */ DPRINTK("snooze...\n"); diff -Nru a/drivers/block/ub.c b/drivers/block/ub.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/block/ub.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,2097 @@ +/* + * The low performance USB storage driver (ub). + * + * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com) + * + * This work is a part of Linux kernel, is derived from it, + * and is not licensed separately. See file COPYING for details. + * + * TODO (sorted by decreasing priority) + * -- ZIP does "ub: resid 18 len 0 act 0" and whole transport quits (toggles?) + * -- set readonly flag for CDs, set removable flag for CF readers + * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) + * -- support pphaneuf's SDDR-75 with two LUNs (also broken capacity...) + * -- special case some senses, e.g. 3a/0 -> no media present, reduce retries + * -- do something about spin-down devices, they are extremely dangerous + * (ZIP is one. Needs spin-up command as well.) + * -- verify the 13 conditions and do bulk resets + * -- normal pool of commands instead of cmdv[]? + * -- kill last_pipe and simply do two-state clearing on both pipes + * -- verify protocol (bulk) from USB descriptors (maybe...) + * -- highmem and sg + * -- move top_sense and work_bcs into separate allocations (if they survive) + * for cache purists and esoteric architectures. + * -- prune comments, they are too volumnous + * -- Exterminate P3 printks + * -- Resove XXX's + */ +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "ub" +#define DEVFS_NAME DRV_NAME + +#define UB_MAJOR 125 /* Stolen from Experimental range for a week - XXX */ + +/* + * Definitions which have to be scattered once we understand the layout better. + */ + +/* Transport (despite PR in the name) */ +#define US_PR_BULK 0x50 /* bulk only */ + +/* Protocol */ +#define US_SC_SCSI 0x06 /* Transparent */ + +/* + */ +#define UB_MINORS_PER_MAJOR 8 + +#define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */ + +#define UB_SENSE_SIZE 18 + +/* + */ + +/* command block wrapper */ +struct bulk_cb_wrap { + u32 Signature; /* contains 'USBC' */ + u32 Tag; /* unique per command id */ + u32 DataTransferLength; /* size of data */ + u8 Flags; /* direction in bit 0 */ + u8 Lun; /* LUN normally 0 */ + u8 Length; /* of of the CDB */ + u8 CDB[UB_MAX_CDB_SIZE]; /* max command */ +}; + +#define US_BULK_CB_WRAP_LEN 31 +#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */ +#define US_BULK_FLAG_IN 1 +#define US_BULK_FLAG_OUT 0 + +/* command status wrapper */ +struct bulk_cs_wrap { + u32 Signature; /* should = 'USBS' */ + u32 Tag; /* same as original command */ + u32 Residue; /* amount not transferred */ + u8 Status; /* see below */ +}; + +#define US_BULK_CS_WRAP_LEN 13 +#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */ +/* This is for Olympus Camedia digital cameras */ +#define US_BULK_CS_OLYMPUS_SIGN 0x55425355 /* spells out 'USBU' */ +#define US_BULK_STAT_OK 0 +#define US_BULK_STAT_FAIL 1 +#define US_BULK_STAT_PHASE 2 + +/* bulk-only class specific requests */ +#define US_BULK_RESET_REQUEST 0xff +#define US_BULK_GET_MAX_LUN 0xfe + +/* + */ +struct ub_dev; + +#define UB_MAX_REQ_SG 1 +#define UB_MAX_SECTORS 64 + +/* + * A second ought to be enough for a 32K transfer (UB_MAX_SECTORS) + * even if a webcam hogs the bus (famous last words). + * Some CDs need a second to spin up though. + * ZIP drive rejects commands when it's not spinning, + * so it does not need long timeouts either. + */ +#define UB_URB_TIMEOUT (HZ*2) +#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ + +/* + * An instance of a SCSI command in transit. + */ +#define UB_DIR_NONE 0 +#define UB_DIR_READ 1 +#define UB_DIR_ILLEGAL2 2 +#define UB_DIR_WRITE 3 + +#define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ + (((c)==UB_DIR_READ)? 'r': 'n')) + +enum ub_scsi_cmd_state { + UB_CMDST_INIT, /* Initial state */ + UB_CMDST_CMD, /* Command submitted */ + UB_CMDST_DATA, /* Data phase */ + UB_CMDST_CLR2STS, /* Clearing before requesting status */ + UB_CMDST_STAT, /* Status phase */ + UB_CMDST_CLEAR, /* Clearing a stall (halt, actually) */ + UB_CMDST_SENSE, /* Sending Request Sense */ + UB_CMDST_DONE /* Final state */ +}; + +static char *ub_scsi_cmd_stname[] = { + ". ", + "Cmd", + "dat", + "c2s", + "sts", + "clr", + "Sen", + "fin" +}; + +struct ub_scsi_cmd { + unsigned char cdb[UB_MAX_CDB_SIZE]; + unsigned char cdb_len; + + unsigned char dir; /* 0 - none, 1 - read, 3 - write. */ + unsigned char trace_index; + enum ub_scsi_cmd_state state; + unsigned int tag; + struct ub_scsi_cmd *next; + + int error; /* Return code - valid upon done */ + int act_len; /* Return size */ + + int stat_count; /* Retries getting status. */ + + /* + * We do not support transfers from highmem pages + * because the underlying USB framework does not do what we need. + */ + char *data; /* Requested buffer */ + unsigned int len; /* Requested length */ + // struct scatterlist sgv[UB_MAX_REQ_SG]; + + void (*done)(struct ub_dev *, struct ub_scsi_cmd *); + void *back; +}; + +/* + */ +struct ub_capacity { + unsigned long nsec; /* Linux size - 512 byte sectors */ + unsigned int bsize; /* Linux hardsect_size */ + unsigned int bshift; /* Shift between 512 and hard sects */ +}; + +/* + * The SCSI command tracing structure. + */ + +#define SCMD_ST_HIST_SZ 8 +#define SCMD_TRACE_SZ 15 /* No more than 256 (trace_index) */ + +struct ub_scsi_cmd_trace { + int hcur; + unsigned int tag; + unsigned int req_size, act_size; + unsigned char op; + unsigned char dir; + unsigned char key, asc, ascq; + char st_hst[SCMD_ST_HIST_SZ]; +}; + +struct ub_scsi_trace { + int cur; + struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ]; +}; + +/* + * This is a direct take-off from linux/include/completion.h + * The difference is that I do not wait on this thing, just poll. + * When I want to wait (ub_probe), I just use the stock completion. + * + * Note that INIT_COMPLETION takes no lock. It is correct. But why + * in the bloody hell that thing takes struct instead of pointer to struct + * is quite beyond me. I just copied it from the stock completion. + */ +struct ub_completion { + unsigned int done; + spinlock_t lock; +}; + +static inline void ub_init_completion(struct ub_completion *x) +{ + x->done = 0; + spin_lock_init(&x->lock); +} + +#define UB_INIT_COMPLETION(x) ((x).done = 0) + +static void ub_complete(struct ub_completion *x) +{ + unsigned long flags; + + spin_lock_irqsave(&x->lock, flags); + x->done++; + spin_unlock_irqrestore(&x->lock, flags); +} + +static int ub_is_completed(struct ub_completion *x) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&x->lock, flags); + ret = x->done; + spin_unlock_irqrestore(&x->lock, flags); + return ret; +} + +/* + */ +struct ub_scsi_cmd_queue { + int qlen, qmax; + struct ub_scsi_cmd *head, *tail; +}; + +/* + * The UB device instance. + */ +struct ub_dev { + spinlock_t lock; + int id; /* Number among ub's */ + atomic_t poison; /* The USB device is disconnected */ + int openc; /* protected by ub_lock! */ + /* kref is too implicit for our taste */ + unsigned int tagcnt; + int changed; /* Media was changed */ + int removable; + int readonly; + char name[8]; + struct usb_device *dev; + struct usb_interface *intf; + + struct ub_capacity capacity; + struct gendisk *disk; + + unsigned int send_bulk_pipe; /* cached pipe values */ + unsigned int recv_bulk_pipe; + unsigned int send_ctrl_pipe; + unsigned int recv_ctrl_pipe; + + struct tasklet_struct tasklet; + + /* XXX Use Ingo's mempool (once we have more than one) */ + int cmda[1]; + struct ub_scsi_cmd cmdv[1]; + + struct ub_scsi_cmd_queue cmd_queue; + struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */ + unsigned char top_sense[UB_SENSE_SIZE]; + + struct ub_completion work_done; + struct urb work_urb; + struct timer_list work_timer; + int last_pipe; /* What might need clearing */ + struct bulk_cb_wrap work_bcb; + struct bulk_cs_wrap work_bcs; + struct usb_ctrlrequest work_cr; + + struct ub_scsi_trace tr; +}; + +/* + */ +static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_end_rq(struct request *rq, int uptodate); +static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_urb_complete(struct urb *urb, struct pt_regs *pt); +static void ub_scsi_action(unsigned long _dev); +static void ub_scsi_dispatch(struct ub_dev *sc); +static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + int stalled_pipe); +static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); +static int ub_sync_tur(struct ub_dev *sc); +static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret); + +/* + */ +static struct usb_device_id ub_usb_ids[] = { + // { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) }, /* SDDR-31 */ + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, ub_usb_ids); + +/* + * Find me a way to identify "next free minor" for add_disk(), + * and the array disappears the next day. However, the number of + * hosts has something to do with the naming and /proc/partitions. + * This has to be thought out in detail before changing. + * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure. + */ +#define UB_MAX_HOSTS 26 +static char ub_hostv[UB_MAX_HOSTS]; +static spinlock_t ub_lock = SPIN_LOCK_UNLOCKED; /* Locks globals and ->openc */ + +/* + * The SCSI command tracing procedures. + */ + +static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int n; + struct ub_scsi_cmd_trace *t; + + if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0; + t = &sc->tr.vec[n]; + + memset(t, 0, sizeof(struct ub_scsi_cmd_trace)); + t->tag = cmd->tag; + t->op = cmd->cdb[0]; + t->dir = cmd->dir; + t->req_size = cmd->len; + t->st_hst[0] = cmd->state; + + sc->tr.cur = n; + cmd->trace_index = n; +} + +static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int n; + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) { + if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0; + t->st_hst[n] = cmd->state; + t->hcur = n; + } +} + +static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) + t->act_size = cmd->act_len; +} + +static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + unsigned char *sense) +{ + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) { + t->key = sense[2] & 0x0F; + t->asc = sense[12]; + t->ascq = sense[13]; + } +} + +static ssize_t ub_diag_show(struct device *dev, char *page) +{ + struct usb_interface *intf; + struct ub_dev *sc; + int cnt; + unsigned long flags; + int nc, nh; + int i, j; + struct ub_scsi_cmd_trace *t; + + intf = to_usb_interface(dev); + sc = usb_get_intfdata(intf); + if (sc == NULL) + return 0; + + cnt = 0; + spin_lock_irqsave(&sc->lock, flags); + + cnt += sprintf(page + cnt, + "qlen %d qmax %d changed %d removable %d readonly %d\n", + sc->cmd_queue.qlen, sc->cmd_queue.qmax, + sc->changed, sc->removable, sc->readonly); + + if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0; + for (j = 0; j < SCMD_TRACE_SZ; j++) { + t = &sc->tr.vec[nc]; + + cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op); + if (t->op == REQUEST_SENSE) { + cnt += sprintf(page + cnt, " [sense %x %02x %02x]", + t->key, t->asc, t->ascq); + } else { + cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir)); + cnt += sprintf(page + cnt, " [%5d %5d]", + t->req_size, t->act_size); + } + if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0; + for (i = 0; i < SCMD_ST_HIST_SZ; i++) { + cnt += sprintf(page + cnt, " %s", + ub_scsi_cmd_stname[(int)t->st_hst[nh]]); + if (++nh == SCMD_ST_HIST_SZ) nh = 0; + } + cnt += sprintf(page + cnt, "\n"); + + if (++nc == SCMD_TRACE_SZ) nc = 0; + } + + spin_unlock_irqrestore(&sc->lock, flags); + return cnt; +} + +static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */ + +/* + * The id allocator. + * + * This also stores the host for indexing by minor, which is somewhat dirty. + */ +static int ub_id_get(void) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&ub_lock, flags); + for (i = 0; i < UB_MAX_HOSTS; i++) { + if (ub_hostv[i] == 0) { + ub_hostv[i] = 1; + spin_unlock_irqrestore(&ub_lock, flags); + return i; + } + } + spin_unlock_irqrestore(&ub_lock, flags); + return -1; +} + +static void ub_id_put(int id) +{ + + if (id < 0 || id >= UB_MAX_HOSTS) { + printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id); + return; + } + if (ub_hostv[id] == 0) { + printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id); + return; + } + ub_hostv[id] = 0; +} + +/* + * Final cleanup and deallocation. + * This must be called with ub_lock taken. + */ +static void ub_cleanup(struct ub_dev *sc) +{ + ub_id_put(sc->id); + kfree(sc); +} + +/* + * The "command allocator". + */ +static struct ub_scsi_cmd *ub_get_cmd(struct ub_dev *sc) +{ + struct ub_scsi_cmd *ret; + + if (sc->cmda[0]) + return NULL; + ret = &sc->cmdv[0]; + sc->cmda[0] = 1; + return ret; +} + +static void ub_put_cmd(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + if (cmd != &sc->cmdv[0]) { + printk(KERN_WARNING "%s: releasing a foreign cmd %p\n", + sc->name, cmd); + return; + } + if (!sc->cmda[0]) { + printk(KERN_WARNING "%s: releasing a free cmd\n", sc->name); + return; + } + sc->cmda[0] = 0; +} + +/* + * The command queue. + */ +static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + + if (t->qlen++ == 0) { + t->head = cmd; + t->tail = cmd; + } else { + t->tail->next = cmd; + t->tail = cmd; + } + + if (t->qlen > t->qmax) + t->qmax = t->qlen; +} + +static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + + if (t->qlen++ == 0) { + t->head = cmd; + t->tail = cmd; + } else { + cmd->next = t->head; + t->head = cmd; + } + + if (t->qlen > t->qmax) + t->qmax = t->qlen; +} + +static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + struct ub_scsi_cmd *cmd; + + if (t->qlen == 0) + return NULL; + if (--t->qlen == 0) + t->tail = NULL; + cmd = t->head; + t->head = cmd->next; + cmd->next = NULL; + return cmd; +} + +#define ub_cmdq_peek(sc) ((sc)->cmd_queue.head) + +/* + * The request function is our main entry point + */ + +static inline int ub_bd_rq_fn_1(request_queue_t *q) +{ +#if 0 + int writing = 0, pci_dir, i, n_elem; + u32 tmp; + unsigned int msg_size; +#endif + struct ub_dev *sc = q->queuedata; + struct request *rq; +#if 0 /* We use rq->buffer for now */ + struct scatterlist *sg; + int n_elem; +#endif + struct ub_scsi_cmd *cmd; + int ub_dir; + unsigned int block, nblks; + int rc; + + if ((rq = elv_next_request(q)) == NULL) + return 1; + + if (atomic_read(&sc->poison) || sc->changed) { + blkdev_dequeue_request(rq); + ub_end_rq(rq, 0); + return 0; + } + + if ((cmd = ub_get_cmd(sc)) == NULL) { + blk_stop_queue(q); + return 1; + } + + blkdev_dequeue_request(rq); + + if (rq_data_dir(rq) == WRITE) + ub_dir = UB_DIR_WRITE; + else + ub_dir = UB_DIR_READ; + + /* + * get scatterlist from block layer + */ +#if 0 /* We use rq->buffer for now */ + sg = &cmd->sgv[0]; + n_elem = blk_rq_map_sg(q, rq, sg); + if (n_elem <= 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; /* request with no s/g entries? */ + } + + if (n_elem != 1) { /* Paranoia */ + printk(KERN_WARNING "%s: request with %d segments\n", + sc->name, n_elem); + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } +#endif + /* + * XXX Unfortunately, this check does not work. It is quite possible + * to get bogus non-null rq->buffer if you allow sg by mistake. + */ + if (rq->buffer == NULL) { + /* + * This must not happen if we set the queue right. + * The block level must create bounce buffers for us. + */ + static int do_print = 1; + if (do_print) { + printk(KERN_WARNING "%s: unmapped request\n", sc->name); + do_print = 0; + } + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } + + /* + * build the command + */ + block = rq->sector; + nblks = rq->nr_sectors; + + memset(cmd, 0, sizeof(struct ub_scsi_cmd)); + cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10; + /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ + cmd->cdb[2] = block >> 24; + cmd->cdb[3] = block >> 16; + cmd->cdb[4] = block >> 8; + cmd->cdb[5] = block; + cmd->cdb[7] = nblks >> 8; + cmd->cdb[8] = nblks; + cmd->cdb_len = 10; + cmd->dir = ub_dir; + cmd->state = UB_CMDST_INIT; + cmd->data = rq->buffer; + cmd->len = nblks * 512; + cmd->done = ub_rw_cmd_done; + cmd->back = rq; + + cmd->tag = sc->tagcnt++; + if ((rc = ub_submit_scsi(sc, cmd)) != 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } + + return 0; +} + +static void ub_bd_rq_fn(request_queue_t *q) +{ + do { } while (ub_bd_rq_fn_1(q) == 0); +} + +static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct request *rq = cmd->back; + struct gendisk *disk = sc->disk; + request_queue_t *q = disk->queue; + int uptodate; + + if (cmd->error == 0) + uptodate = 1; + else + uptodate = 0; + + ub_put_cmd(sc, cmd); + ub_end_rq(rq, uptodate); + blk_start_queue(q); +} + +static void ub_end_rq(struct request *rq, int uptodate) +{ + int rc; + + rc = end_that_request_first(rq, uptodate, rq->hard_nr_sectors); + // assert(rc == 0); + end_that_request_last(rq); +} + +/* + * Submit a regular SCSI operation (not an auto-sense). + * + * The Iron Law of Good Submit Routine is: + * Zero return - callback is done, Nonzero return - callback is not done. + * No exceptions. + * + * Host is assumed locked. + * + * XXX We only support Bulk for the moment. + */ +static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + + if (cmd->state != UB_CMDST_INIT || + (cmd->dir != UB_DIR_NONE && cmd->len == 0)) { + return -EINVAL; + } + + ub_cmdq_add(sc, cmd); + /* + * We can call ub_scsi_dispatch(sc) right away here, but it's a little + * safer to jump to a tasklet, in case upper layers do something silly. + */ + tasklet_schedule(&sc->tasklet); + return 0; +} + +/* + * Submit the first URB for the queued command. + * This function does not deal with queueing in any way. + */ +static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct bulk_cb_wrap *bcb; + int rc; + + bcb = &sc->work_bcb; + + /* set up the command wrapper */ + bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); + bcb->Tag = cmd->tag; /* Endianness is not important */ + bcb->DataTransferLength = cpu_to_le32(cmd->len); + bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0; + bcb->Lun = 0; /* No multi-LUN yet */ + bcb->Length = cmd->cdb_len; + + /* copy the command payload */ + memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE); + + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->send_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, + bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + + /* Fill what we shouldn't be filling, because usb-storage did so. */ + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + return rc; + } + + cmd->state = UB_CMDST_CMD; + ub_cmdtr_state(sc, cmd); + return 0; +} + +/* + * Timeout handler. + */ +static void ub_urb_timeout(unsigned long arg) +{ + struct ub_dev *sc = (struct ub_dev *) arg; + unsigned long flags; + + spin_lock_irqsave(&sc->lock, flags); + usb_unlink_urb(&sc->work_urb); + spin_unlock_irqrestore(&sc->lock, flags); +} + +/* + * Completion routine for the work URB. + * + * This can be called directly from usb_submit_urb (while we have + * the sc->lock taken) and from an interrupt (while we do NOT have + * the sc->lock taken). Therefore, bounce this off to a tasklet. + */ +static void ub_urb_complete(struct urb *urb, struct pt_regs *pt) +{ + struct ub_dev *sc = urb->context; + + ub_complete(&sc->work_done); + tasklet_schedule(&sc->tasklet); +} + +static void ub_scsi_action(unsigned long _dev) +{ + struct ub_dev *sc = (struct ub_dev *) _dev; + unsigned long flags; + + spin_lock_irqsave(&sc->lock, flags); + ub_scsi_dispatch(sc); + spin_unlock_irqrestore(&sc->lock, flags); +} + +static void ub_scsi_dispatch(struct ub_dev *sc) +{ + struct ub_scsi_cmd *cmd; + int rc; + + while ((cmd = ub_cmdq_peek(sc)) != NULL) { + if (cmd->state == UB_CMDST_DONE) { + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + } else if (cmd->state == UB_CMDST_INIT) { + ub_cmdtr_new(sc, cmd); + if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0) + break; + cmd->error = rc; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + } else { + if (!ub_is_completed(&sc->work_done)) + break; + ub_scsi_urb_compl(sc, cmd); + } + } +} + +static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct urb *urb = &sc->work_urb; + struct bulk_cs_wrap *bcs; + int pipe; + int rc; + +/* P3 */ /** printk("ub: urb status %d pipe 0x%08x len %d act %d\n", + urb->status, urb->pipe, urb->transfer_buffer_length, urb->actual_length); **/ + + if (atomic_read(&sc->poison)) { + /* A little too simplistic, I feel... */ + goto Bad_End; + } + + if (cmd->state == UB_CMDST_CLEAR) { + if (urb->status == -EPIPE) { + /* + * STALL while clearning STALL. + * A STALL is illegal on a control pipe! + * XXX Might try to reset the device here and retry. + */ + printk(KERN_NOTICE "%s: " + "stall on control pipe for device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * We ignore the result for the halt clear. + */ + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), + usb_pipeout(sc->last_pipe), 0); + + ub_state_sense(sc, cmd); + + } else if (cmd->state == UB_CMDST_CLR2STS) { + if (urb->status == -EPIPE) { + /* + * STALL while clearning STALL. + * A STALL is illegal on a control pipe! + * XXX Might try to reset the device here and retry. + */ + printk(KERN_NOTICE "%s: " + "stall on control pipe for device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * We ignore the result for the halt clear. + */ + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), + usb_pipeout(sc->last_pipe), 0); + + ub_state_stat(sc, cmd); + + } else if (cmd->state == UB_CMDST_CMD) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLEAR; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status != 0) + goto Bad_End; + if (urb->actual_length != US_BULK_CB_WRAP_LEN) { + /* XXX Must do reset here to unconfuse the device */ + goto Bad_End; + } + + if (cmd->dir == UB_DIR_NONE) { + ub_state_stat(sc, cmd); + return; + } + + UB_INIT_COMPLETION(sc->work_done); + + if (cmd->dir == UB_DIR_READ) + pipe = sc->recv_bulk_pipe; + else + pipe = sc->send_bulk_pipe; + sc->last_pipe = pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, + cmd->data, cmd->len, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + + cmd->state = UB_CMDST_DATA; + ub_cmdtr_state(sc, cmd); + + } else if (cmd->state == UB_CMDST_DATA) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLR2STS; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status == -EOVERFLOW) { + /* + * A babble? Failure, but we must transfer CSW now. + */ + cmd->error = -EOVERFLOW; /* A cheap trick... */ + } else { + if (urb->status != 0) + goto Bad_End; + } + + cmd->act_len = urb->actual_length; + ub_cmdtr_act_len(sc, cmd); + + ub_state_stat(sc, cmd); + + } else if (cmd->state == UB_CMDST_STAT) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLEAR; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status != 0) + goto Bad_End; + + if (urb->actual_length == 0) { + /* + * Some broken devices add unnecessary zero-length + * packets to the end of their data transfers. + * Such packets show up as 0-length CSWs. If we + * encounter such a thing, try to read the CSW again. + */ + if (++cmd->stat_count >= 4) { + printk(KERN_NOTICE "%s: " + "unable to get CSW on device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * ub_state_stat only not dropping the count... + */ + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->recv_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, + sc->recv_bulk_pipe, &sc->work_bcs, + US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC); + if (rc != 0) { + /* XXX Clear stalls */ + printk("%s: CSW #%d submit failed (%d)\n", + sc->name, cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + return; + } + + /* + * Check the returned Bulk protocol status. + */ + + bcs = &sc->work_bcs; + rc = le32_to_cpu(bcs->Residue); + if (rc != cmd->len - cmd->act_len) { + /* + * It is all right to transfer less, the caller has + * to check. But it's not all right if the device + * counts disagree with our counts. + */ + /* P3 */ printk("%s: resid %d len %d act %d\n", + sc->name, rc, cmd->len, cmd->act_len); + goto Bad_End; + } + + if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && + bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) { + /* XXX Rate-limit, even for P3 tagged */ + /* P3 */ printk("ub: signature 0x%x\n", bcs->Signature); + /* Windows ignores signatures, so do we. */ + } + + if (bcs->Tag != cmd->tag) { + /* P3 */ printk("%s: tag orig 0x%x reply 0x%x\n", + sc->name, cmd->tag, bcs->Tag); + goto Bad_End; + } + + switch (bcs->Status) { + case US_BULK_STAT_OK: + break; + case US_BULK_STAT_FAIL: + ub_state_sense(sc, cmd); + return; + case US_BULK_STAT_PHASE: + /* XXX We must reset the transport here */ + /* P3 */ printk("%s: status PHASE\n", sc->name); + goto Bad_End; + default: + printk(KERN_INFO "%s: unknown CSW status 0x%x\n", + sc->name, bcs->Status); + goto Bad_End; + } + + /* Not zeroing error to preserve a babble indicator */ + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + + } else if (cmd->state == UB_CMDST_SENSE) { + /* + * We do not look at sense, because even if there was no sense, + * we get into UB_CMDST_SENSE from a STALL or CSW FAIL only. + * We request sense because we want to clear CHECK CONDITION + * on devices with delusions of SCSI, and not because we + * are curious in any way about the sense itself. + */ + /* if ((cmd->top_sense[2] & 0x0F) == NO_SENSE) { foo } */ + + ub_state_done(sc, cmd, -EIO); + } else { + printk(KERN_WARNING "%s: " + "wrong command state %d on device %u\n", + sc->name, cmd->state, sc->dev->devnum); + goto Bad_End; + } + return; + +Bad_End: /* Little Excel is dead */ + ub_state_done(sc, cmd, -EIO); +} + +/* + * Factorization helper for the command state machine: + * Finish the command. + */ +static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc) +{ + + cmd->error = rc; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); +} + +/* + * Factorization helper for the command state machine: + * Submit a CSW read and go to STAT state. + */ +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int rc; + + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->recv_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, + &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + + cmd->stat_count = 0; + cmd->state = UB_CMDST_STAT; + ub_cmdtr_state(sc, cmd); +} + +/* + * Factorization helper for the command state machine: + * Submit a REQUEST SENSE and go to SENSE state. + */ +static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd *scmd; + int rc; + + if (cmd->cdb[0] == REQUEST_SENSE) { + rc = -EPIPE; + goto error; + } + + memset(&sc->top_sense, 0, UB_SENSE_SIZE); + scmd = &sc->top_rqs_cmd; + scmd->cdb[0] = REQUEST_SENSE; + scmd->cdb_len = 6; + scmd->dir = UB_DIR_READ; + scmd->state = UB_CMDST_INIT; + scmd->data = sc->top_sense; + scmd->len = UB_SENSE_SIZE; + scmd->done = ub_top_sense_done; + scmd->back = cmd; + + scmd->tag = sc->tagcnt++; + + cmd->state = UB_CMDST_SENSE; + ub_cmdtr_state(sc, cmd); + + ub_cmdq_insert(sc, scmd); + return; + +error: + ub_state_done(sc, cmd, rc); +} + +/* + * A helper for the command's state machine: + * Submit a stall clear. + */ +static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + int stalled_pipe) +{ + int endp; + struct usb_ctrlrequest *cr; + int rc; + + endp = usb_pipeendpoint(stalled_pipe); + if (usb_pipein (stalled_pipe)) + endp |= USB_DIR_IN; + + cr = &sc->work_cr; + cr->bRequestType = USB_RECIP_ENDPOINT; + cr->bRequest = USB_REQ_CLEAR_FEATURE; + cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); + cr->wIndex = cpu_to_le16(endp); + cr->wLength = cpu_to_le16(0); + + UB_INIT_COMPLETION(sc->work_done); + + usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, + (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + return rc; + } + return 0; +} + +/* + */ +static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) +{ + unsigned char *sense = scmd->data; + struct ub_scsi_cmd *cmd; + + ub_cmdtr_sense(sc, scmd, sense); + + if ((cmd = ub_cmdq_peek(sc)) == NULL) { + printk(KERN_WARNING "%s: sense done while idle\n", sc->name); + return; + } + if (cmd != scmd->back) { + printk(KERN_WARNING "%s: " + "sense done for wrong command 0x%x on device %u\n", + sc->name, cmd->tag, sc->dev->devnum); + return; + } + if (cmd->state != UB_CMDST_SENSE) { + printk(KERN_WARNING "%s: " + "sense done with bad cmd state %d on device %u\n", + sc->name, cmd->state, sc->dev->devnum); + return; + } + + ub_scsi_urb_compl(sc, cmd); +} + +#if 0 +/* Determine what the maximum LUN supported is */ +int usb_stor_Bulk_max_lun(struct us_data *us) +{ + int result; + + /* issue the command */ + result = usb_stor_control_msg(us, us->recv_ctrl_pipe, + US_BULK_GET_MAX_LUN, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + 0, us->ifnum, us->iobuf, 1, HZ); + + /* + * Some devices (i.e. Iomega Zip100) need this -- apparently + * the bulk pipes get STALLed when the GetMaxLUN request is + * processed. This is, in theory, harmless to all other devices + * (regardless of if they stall or not). + */ + if (result < 0) { + usb_stor_clear_halt(us, us->recv_bulk_pipe); + usb_stor_clear_halt(us, us->send_bulk_pipe); + } + + US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", + result, us->iobuf[0]); + + /* if we have a successful request, return the result */ + if (result == 1) + return us->iobuf[0]; + + /* return the default -- no LUNs */ + return 0; +} +#endif + +/* + * This is called from a process context. + */ +static void ub_revalidate(struct ub_dev *sc) +{ + + sc->readonly = 0; /* XXX Query this from the device */ + + /* + * XXX sd.c sets capacity to zero in such case. However, it doesn't + * work for us. In case of zero capacity, block layer refuses to + * have the /dev/uba opened (why?) Set capacity to some random value. + */ + sc->capacity.nsec = 50; + sc->capacity.bsize = 512; + sc->capacity.bshift = 0; + + if (ub_sync_tur(sc) != 0) + return; /* Not ready */ + sc->changed = 0; + + if (ub_sync_read_cap(sc, &sc->capacity) != 0) { + /* + * The retry here means something is wrong, either with the + * device, with the transport, or with our code. + * We keep this because sd.c has retries for capacity. + */ + if (ub_sync_read_cap(sc, &sc->capacity) != 0) { + sc->capacity.nsec = 100; + sc->capacity.bsize = 512; + sc->capacity.bshift = 0; + } + } +} + +/* + * The open funcion. + * This is mostly needed to keep refcounting, but also to support + * media checks on removable media drives. + */ +static int ub_bd_open(struct inode *inode, struct file *filp) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ub_dev *sc; + unsigned long flags; + int rc; + + if ((sc = disk->private_data) == NULL) + return -ENXIO; + spin_lock_irqsave(&ub_lock, flags); + if (atomic_read(&sc->poison)) { + spin_unlock_irqrestore(&ub_lock, flags); + return -ENXIO; + } + sc->openc++; + spin_unlock_irqrestore(&ub_lock, flags); + + if (sc->removable || sc->readonly) + check_disk_change(inode->i_bdev); + + /* XXX sd.c and floppy.c bail on open if media is not present. */ + + if (sc->readonly && (filp->f_mode & FMODE_WRITE)) { + rc = -EROFS; + goto err_open; + } + + return 0; + +err_open: + spin_lock_irqsave(&ub_lock, flags); + --sc->openc; + if (sc->openc == 0 && atomic_read(&sc->poison)) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); + return rc; +} + +/* + */ +static int ub_bd_release(struct inode *inode, struct file *filp) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ub_dev *sc = disk->private_data; + unsigned long flags; + + spin_lock_irqsave(&ub_lock, flags); + --sc->openc; + if (sc->openc == 0 && atomic_read(&sc->poison)) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); + return 0; +} + +/* + * The ioctl interface. + */ +static int ub_bd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ +// void __user *usermem = (void *) arg; +// struct carm_port *port = ino->i_bdev->bd_disk->private_data; +// struct hd_geometry geom; + +#if 0 + switch (cmd) { + case HDIO_GETGEO: + if (usermem == NULL) // XXX Bizzare. Why? + return -EINVAL; + + geom.heads = (u8) port->dev_geom_head; + geom.sectors = (u8) port->dev_geom_sect; + geom.cylinders = port->dev_geom_cyl; + geom.start = get_start_sect(ino->i_bdev); + + if (copy_to_user(usermem, &geom, sizeof(geom))) + return -EFAULT; + return 0; + + default: ; + } +#endif + + return -ENOTTY; +} + +/* + * This is called once a new disk was seen by the block layer or by ub_probe(). + * The main onjective here is to discover the features of the media such as + * the capacity, read-only status, etc. USB storage generally does not + * need to be spun up, but if we needed it, this would be the place. + * + * This call can sleep. + * + * The return code is not used. + */ +static int ub_bd_revalidate(struct gendisk *disk) +{ + struct ub_dev *sc = disk->private_data; + + ub_revalidate(sc); + /* This is pretty much a long term P3 */ + printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n", + sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize); + + set_capacity(disk, sc->capacity.nsec); + // set_disk_ro(sdkp->disk, sc->readonly); + return 0; +} + +/* + * The check is called by the block layer to verify if the media + * is still available. It is supposed to be harmless, lightweight and + * non-intrusive in case the media was not changed. + * + * This call can sleep. + * + * The return code is bool! + */ +static int ub_bd_media_changed(struct gendisk *disk) +{ + struct ub_dev *sc = disk->private_data; + + if (!sc->removable) + return 0; + + /* + * We clean checks always after every command, so this is not + * as dangerous as it looks. If the TEST_UNIT_READY fails here, + * the device is actually not ready with operator or software + * intervention required. One dangerous item might be a drive which + * spins itself down, and come the time to write dirty pages, this + * will fail, then block layer discards the data. Since we never + * spin drives up, such devices simply cannot be used with ub anyway. + */ + if (ub_sync_tur(sc) != 0) { + sc->changed = 1; + /* P3 */ printk("%s: made changed\n", sc->name); + return 1; + } + + /* The sd.c clears this before returning (one-shot flag). Why? */ + /* P3 */ printk("%s: %s changed\n", sc->name, + sc->changed? "is": "was not"); + return sc->changed; +} + +static struct block_device_operations ub_bd_fops = { + .owner = THIS_MODULE, + .open = ub_bd_open, + .release = ub_bd_release, + .ioctl = ub_bd_ioctl, + .media_changed = ub_bd_media_changed, + .revalidate_disk = ub_bd_revalidate, +}; + +/* + * Common ->done routine for commands executed synchronously. + */ +static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct completion *cop = cmd->back; + complete(cop); +} + +/* + * Test if the device has a check condition on it, synchronously. + */ +static int ub_sync_tur(struct ub_dev *sc) +{ + struct ub_scsi_cmd *cmd; + enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) }; + unsigned long flags; + struct completion compl; + int rc; + + init_completion(&compl); + + rc = -ENOMEM; + if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) + goto err_alloc; + memset(cmd, 0, ALLOC_SIZE); + + cmd->cdb[0] = TEST_UNIT_READY; + cmd->cdb_len = 6; + cmd->dir = UB_DIR_NONE; + cmd->state = UB_CMDST_INIT; + cmd->done = ub_probe_done; + cmd->back = &compl; + + spin_lock_irqsave(&sc->lock, flags); + cmd->tag = sc->tagcnt++; + + rc = ub_submit_scsi(sc, cmd); + spin_unlock_irqrestore(&sc->lock, flags); + + if (rc != 0) { + printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */ + goto err_submit; + } + + wait_for_completion(&compl); + + rc = cmd->error; + +err_submit: + kfree(cmd); +err_alloc: + return rc; +} + +/* + * Read the SCSI capacity synchronously (for probing). + */ +static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret) +{ + struct ub_scsi_cmd *cmd; + char *p; + enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 }; + unsigned long flags; + unsigned int bsize, shift; + unsigned long nsec; + struct completion compl; + int rc; + + init_completion(&compl); + + rc = -ENOMEM; + if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) + goto err_alloc; + memset(cmd, 0, ALLOC_SIZE); + p = (char *)cmd + sizeof(struct ub_scsi_cmd); + + cmd->cdb[0] = 0x25; + cmd->cdb_len = 10; + cmd->dir = UB_DIR_READ; + cmd->state = UB_CMDST_INIT; + cmd->data = p; + cmd->len = 8; + cmd->done = ub_probe_done; + cmd->back = &compl; + + spin_lock_irqsave(&sc->lock, flags); + cmd->tag = sc->tagcnt++; + + rc = ub_submit_scsi(sc, cmd); + spin_unlock_irqrestore(&sc->lock, flags); + + if (rc != 0) { + printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */ + goto err_submit; + } + + wait_for_completion(&compl); + + if (cmd->error != 0) { + printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */ + rc = -EIO; + goto err_read; + } + if (cmd->act_len != 8) { + printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */ + rc = -EIO; + goto err_read; + } + + /* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */ + nsec = be32_to_cpu(*(u32 *)p) + 1; + bsize = be32_to_cpu(*(u32 *)(p + 4)); + switch (bsize) { + case 512: shift = 0; break; + case 1024: shift = 1; break; + case 2048: shift = 2; break; + case 4096: shift = 3; break; + default: + printk("ub: Bad sector size %u\n", bsize); /* P3 */ + rc = -EDOM; + goto err_inv_bsize; + } + + ret->bsize = bsize; + ret->bshift = shift; + ret->nsec = nsec << shift; + rc = 0; + +err_inv_bsize: +err_read: +err_submit: + kfree(cmd); +err_alloc: + return rc; +} + +/* + */ +static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt) +{ + struct completion *cop = urb->context; + complete(cop); +} + +static void ub_probe_timeout(unsigned long arg) +{ + struct completion *cop = (struct completion *) arg; + complete(cop); +} + +/* + * Clear initial stalls. + */ +static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) +{ + int endp; + struct usb_ctrlrequest *cr; + struct completion compl; + struct timer_list timer; + int rc; + + init_completion(&compl); + + endp = usb_pipeendpoint(stalled_pipe); + if (usb_pipein (stalled_pipe)) + endp |= USB_DIR_IN; + + cr = &sc->work_cr; + cr->bRequestType = USB_RECIP_ENDPOINT; + cr->bRequest = USB_REQ_CLEAR_FEATURE; + cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); + cr->wIndex = cpu_to_le16(endp); + cr->wLength = cpu_to_le16(0); + + usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, + (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); + sc->work_urb.transfer_flags = 0; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + init_timer(&timer); + timer.function = ub_probe_timeout; + timer.data = (unsigned long) &compl; + timer.expires = jiffies + UB_CTRL_TIMEOUT; + add_timer(&timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { + printk(KERN_WARNING + "%s: Unable to submit a probe clear (%d)\n", sc->name, rc); + del_timer_sync(&timer); + return rc; + } + + wait_for_completion(&compl); + + del_timer_sync(&timer); + /* + * Most of the time, URB was done and dev set to NULL, and so + * the unlink bounces out with ENODEV. We do not call usb_kill_urb + * because we still think about a backport to 2.4. + */ + usb_unlink_urb(&sc->work_urb); + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); + + return 0; +} + +/* + * Get the pipe settings. + */ +static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, + struct usb_interface *intf) +{ + struct usb_host_interface *altsetting = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_out = NULL; + struct usb_endpoint_descriptor *ep; + int i; + + /* + * Find the endpoints we need. + * We are expecting a minimum of 2 endpoints - in and out (bulk). + * We will ignore any others. + */ + for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { + ep = &altsetting->endpoint[i].desc; + + /* Is it a BULK endpoint? */ + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) { + /* BULK in or out? */ + if (ep->bEndpointAddress & USB_DIR_IN) + ep_in = ep; + else + ep_out = ep; + } + } + + if (ep_in == NULL || ep_out == NULL) { + printk(KERN_NOTICE "%s: device %u failed endpoint check\n", + sc->name, sc->dev->devnum); + return -EIO; + } + + /* Calculate and store the pipe values */ + sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0); + sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0); + sc->send_bulk_pipe = usb_sndbulkpipe(dev, + ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, + ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + + return 0; +} + +/* + * Probing is done in the process context, which allows us to cheat + * and not to build a state machine for the discovery. + */ +static int ub_probe(struct usb_interface *intf, + const struct usb_device_id *dev_id) +{ + struct ub_dev *sc; + request_queue_t *q; + struct gendisk *disk; + int rc; + + rc = -ENOMEM; + if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL) + goto err_core; + memset(sc, 0, sizeof(struct ub_dev)); + spin_lock_init(&sc->lock); + usb_init_urb(&sc->work_urb); + tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); + atomic_set(&sc->poison, 0); + + init_timer(&sc->work_timer); + sc->work_timer.data = (unsigned long) sc; + sc->work_timer.function = ub_urb_timeout; + + ub_init_completion(&sc->work_done); + sc->work_done.done = 1; /* A little yuk, but oh well... */ + + rc = -ENOSR; + if ((sc->id = ub_id_get()) == -1) + goto err_id; + snprintf(sc->name, 8, DRV_NAME "%c", sc->id + 'a'); + + sc->dev = interface_to_usbdev(intf); + sc->intf = intf; + // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + + usb_set_intfdata(intf, sc); + usb_get_dev(sc->dev); + // usb_get_intf(sc->intf); /* Do we need this? */ + + /* XXX Verify that we can handle the device (from descriptors) */ + + ub_get_pipes(sc, sc->dev, intf); + + if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0) + goto err_diag; + + /* + * At this point, all USB initialization is done, do upper layer. + * We really hate halfway initialized structures, so from the + * invariants perspective, this ub_dev is fully constructed at + * this point. + */ + + /* + * This is needed to clear toggles. It is a problem only if we do + * `rmmod ub && modprobe ub` without disconnects, but we like that. + */ + ub_probe_clear_stall(sc, sc->recv_bulk_pipe); + ub_probe_clear_stall(sc, sc->send_bulk_pipe); + + /* + * The way this is used by the startup code is a little specific. + * A SCSI check causes a USB stall. Our common case code sees it + * and clears the check, after which the device is ready for use. + * But if a check was not present, any command other than + * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE). + * + * If we neglect to clear the SCSI check, the first real command fails + * (which is the capacity readout). We clear that and retry, but why + * causing spurious retries for no reason. + * + * Revalidation may start with its own TEST_UNIT_READY, but that one + * has to succeed, so we clear checks with an additional one here. + * In any case it's not our business how revaliadation is implemented. + */ + ub_sync_tur(sc); + + sc->removable = 1; /* XXX Query this from the device */ + + ub_revalidate(sc); + /* This is pretty much a long term P3 */ + printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n", + sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize); + + /* + * Just one disk per sc currently, but maybe more. + */ + rc = -ENOMEM; + if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL) + goto err_diskalloc; + + sc->disk = disk; + sprintf(disk->disk_name, DRV_NAME "%c", sc->id + 'a'); + sprintf(disk->devfs_name, DEVFS_NAME "/%c", sc->id + 'a'); + disk->major = UB_MAJOR; + disk->first_minor = sc->id * UB_MINORS_PER_MAJOR; + disk->fops = &ub_bd_fops; + disk->private_data = sc; + disk->driverfs_dev = &intf->dev; + + rc = -ENOMEM; + if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL) + goto err_blkqinit; + + disk->queue = q; + + // blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); + blk_queue_max_hw_segments(q, UB_MAX_REQ_SG); + blk_queue_max_phys_segments(q, UB_MAX_REQ_SG); + // blk_queue_segment_boundary(q, CARM_SG_BOUNDARY); + blk_queue_max_sectors(q, UB_MAX_SECTORS); + // blk_queue_hardsect_size(q, xxxxx); + + /* + * This is a serious infraction, caused by a deficiency in the + * USB sg interface (usb_sg_wait()). We plan to remove this once + * we get mileage on the driver and can justify a change to USB API. + * See blk_queue_bounce_limit() to understand this part. + * + * XXX And I still need to be aware of the DMA mask in the HC. + */ + q->bounce_pfn = blk_max_low_pfn; + q->bounce_gfp = GFP_NOIO; + + q->queuedata = sc; + + set_capacity(disk, sc->capacity.nsec); + if (sc->removable) + disk->flags |= GENHD_FL_REMOVABLE; + + add_disk(disk); + + return 0; + +err_blkqinit: + put_disk(disk); +err_diskalloc: + device_remove_file(&sc->intf->dev, &dev_attr_diag); +err_diag: + usb_set_intfdata(intf, NULL); + // usb_put_intf(sc->intf); + usb_put_dev(sc->dev); + spin_lock_irq(&ub_lock); + ub_id_put(sc->id); + spin_unlock_irq(&ub_lock); +err_id: + kfree(sc); +err_core: + return rc; +} + +static void ub_disconnect(struct usb_interface *intf) +{ + struct ub_dev *sc = usb_get_intfdata(intf); + struct gendisk *disk = sc->disk; + request_queue_t *q = disk->queue; + unsigned long flags; + + /* + * Fence stall clearnings, operations triggered by unlinkings and so on. + * We do not attempt to unlink any URBs, because we do not trust the + * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway. + */ + atomic_set(&sc->poison, 1); + + /* + * Blow away queued commands. + * + * Actually, this never works, because before we get here + * the HCD terminates outstanding URB(s). It causes our + * SCSI command queue to advance, commands fail to submit, + * and the whole queue drains. So, we just use this code to + * print warnings. + */ + spin_lock_irqsave(&sc->lock, flags); + { + struct ub_scsi_cmd *cmd; + int cnt = 0; + while ((cmd = ub_cmdq_pop(sc)) != NULL) { + cmd->error = -ENOTCONN; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + cnt++; + } + if (cnt != 0) { + printk(KERN_WARNING "%s: " + "%d was queued after shutdown\n", sc->name, cnt); + } + } + spin_unlock_irqrestore(&sc->lock, flags); + + /* + * Unregister the upper layer, this waits for all commands to end. + */ + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (q) + blk_cleanup_queue(q); + + /* + * If we zero disk->private_data BEFORE put_disk, we have to check + * for NULL all over the place in open, release, check_media and + * revalidate, because the block level semaphore is well inside the + * put_disk. But we cannot zero after the call, because *disk is gone. + * The sd.c is blatantly racy in this area. + */ + /* disk->private_data = NULL; */ + put_disk(disk); + sc->disk = NULL; + + /* + * We really expect blk_cleanup_queue() to wait, so no amount + * of paranoya is too much. + * + * Taking a lock on a structure which is about to be freed + * is very nonsensual. Here it is largely a way to do a debug freeze, + * and a bracket which shows where the nonsensual code segment ends. + * + * Testing for -EINPROGRESS is always a bug, so we are bending + * the rules a little. + */ + spin_lock_irqsave(&sc->lock, flags); + if (sc->work_urb.status == -EINPROGRESS) { /* janitors: ignore */ + printk(KERN_WARNING "%s: " + "URB is active after disconnect\n", sc->name); + } + spin_unlock_irqrestore(&sc->lock, flags); + + /* + * At this point there must be no commands coming from anyone + * and no URBs left in transit. + */ + + device_remove_file(&sc->intf->dev, &dev_attr_diag); + usb_set_intfdata(intf, NULL); + // usb_put_intf(sc->intf); + sc->intf = NULL; + usb_put_dev(sc->dev); + sc->dev = NULL; + + spin_lock_irqsave(&ub_lock, flags); + if (sc->openc == 0) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); +} + +struct usb_driver ub_driver = { + .owner = THIS_MODULE, + .name = "ub", + .probe = ub_probe, + .disconnect = ub_disconnect, + .id_table = ub_usb_ids, +}; + +static int __init ub_init(void) +{ + int rc; + + /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu\n", + sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev)); + + if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) + goto err_regblkdev; + devfs_mk_dir(DEVFS_NAME); + + if ((rc = usb_register(&ub_driver)) != 0) + goto err_register; + + return 0; + +err_register: + devfs_remove(DEVFS_NAME); + unregister_blkdev(UB_MAJOR, DRV_NAME); +err_regblkdev: + return rc; +} + +static void __exit ub_exit(void) +{ + usb_deregister(&ub_driver); + + devfs_remove(DEVFS_NAME); + unregister_blkdev(UB_MAJOR, DRV_NAME); +} + +module_init(ub_init); +module_exit(ub_exit); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c --- a/drivers/block/umem.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/block/umem.c 2004-10-18 14:57:04 -07:00 @@ -108,11 +108,11 @@ int irq; unsigned long csr_base; - unsigned char *csr_remap; + unsigned char __iomem *csr_remap; unsigned long csr_len; #ifdef CONFIG_MM_MAP_MEMORY unsigned long mem_base; - unsigned char *mem_remap; + unsigned char __iomem *mem_remap; unsigned long mem_len; #endif @@ -926,7 +926,7 @@ goto failed_req_mem; } - if (!(card->mem_remap = (unsigned char *)ioremap(card->mem_base, cards->mem_len))) { + if (!(card->mem_remap = ioremap(card->mem_base, cards->mem_len))) { printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); ret = -ENOMEM; @@ -1107,12 +1107,12 @@ card->mm_pages[1].page_dma); failed_magic: #ifdef CONFIG_MM_MAP_MEMORY - iounmap((void *) card->mem_remap); + iounmap(card->mem_remap); failed_remap_mem: release_mem_region(card->mem_base, card->mem_len); failed_req_mem: #endif - iounmap((void *) card->csr_remap); + iounmap(card->csr_remap); failed_remap_csr: release_mem_region(card->csr_base, card->csr_len); failed_req_csr: diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c --- a/drivers/bluetooth/hci_ldisc.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/bluetooth/hci_ldisc.c 2004-10-18 14:56:49 -07:00 @@ -188,9 +188,7 @@ } /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + tty_ldisc_flush(tty); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); @@ -280,7 +278,9 @@ spin_lock_init(&hu->rx_lock); - /* Flush any pending characters in the driver and line discipline */ + /* Flush any pending characters in the driver and line discipline. */ + /* FIXME: why is this needed. Note don't use ldisc_ref here as the + open path is before the ldisc is referencable */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/bluetooth/hci_usb.c 2004-10-18 14:57:04 -07:00 @@ -96,7 +96,7 @@ { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET }, + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, /* ISSC Bluetooth Adapter v3.1 */ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c --- a/drivers/cdrom/cdrom.c 2004-10-18 14:56:11 -07:00 +++ b/drivers/cdrom/cdrom.c 2004-10-18 14:56:11 -07:00 @@ -354,6 +354,19 @@ #endif /* CONFIG_SYSCTL */ static struct cdrom_device_info *topCdromPtr; +static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) +{ + if (cgc->sense) { + cgc->sense->sense_key = 0x05; + cgc->sense->asc = 0x20; + cgc->sense->ascq = 0x00; + } + + cgc->stat = -EIO; + return -EIO; +} + /* This macro makes sure we don't have to check on cdrom_device_ops * existence in the run-time routines below. Change_capability is a * hack to have the capability flags defined const, while we can still @@ -411,6 +424,9 @@ else cdi->cdda_method = CDDA_OLD; + if (!cdo->generic_packet) + cdo->generic_packet = cdrom_dummy_generic_packet; + cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); spin_lock(&cdrom_lock); cdi->next = topCdromPtr; @@ -472,6 +488,9 @@ if (be16_to_cpu(eh->data_len) < sizeof(*med)) return 1; + if (eh->nea || eh->notification_class != 0x4) + return 1; + memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); return 0; } @@ -605,13 +624,16 @@ static int cdrom_mrw_exit(struct cdrom_device_info *cdi) { disc_information di; - int ret = 0; + int ret; - if (cdrom_get_disc_info(cdi, &di)) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < (int)offsetof(typeof(di),disc_type)) return 1; + ret = 0; if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) { - printk(KERN_INFO "cdrom: issuing MRW back ground format suspend\n"); + printk(KERN_INFO "cdrom: issuing MRW back ground " + "format suspend\n"); ret = cdrom_mrw_bgformat_susp(cdi, 0); } @@ -715,8 +737,10 @@ static int cdrom_media_erasable(struct cdrom_device_info *cdi) { disc_information di; + int ret; - if (cdrom_get_disc_info(cdi, &di)) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < offsetof(typeof(di), n_first_track)) return -1; return di.erasable; @@ -752,7 +776,8 @@ return 1; } - if (cdrom_get_disc_info(cdi, &di)) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < offsetof(typeof(di),disc_type)) return 1; if (!di.erasable) @@ -766,10 +791,12 @@ * 3 - MRW formatting complete */ ret = 0; - printk(KERN_INFO "cdrom open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]); + printk(KERN_INFO "cdrom open: mrw_status '%s'\n", + mrw_format_status[di.mrw_status]); if (!di.mrw_status) ret = 1; - else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && mrw_format_restart) + else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && + mrw_format_restart) ret = cdrom_mrw_bgformat(cdi, 1); return ret; @@ -1922,7 +1949,8 @@ int lba, int nframes) { struct packet_command cgc; - int nr, ret; + int ret = 0; + int nr; cdi->last_sense = 0; @@ -1944,8 +1972,8 @@ return -ENOMEM; if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) { - kfree(cgc.buffer); - return -EFAULT; + ret = -EFAULT; + goto out; } cgc.data_direction = CGC_DATA_READ; @@ -1956,13 +1984,17 @@ ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); if (ret) break; - __copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr); + if (__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) { + ret = -EFAULT; + break; + } ubuf += CD_FRAMESIZE_RAW * nr; nframes -= nr; lba += nr; } +out: kfree(cgc.buffer); - return 0; + return ret; } static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, @@ -2504,7 +2536,7 @@ struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; struct request_sense sense; - char buffer[32]; + unsigned char buffer[32]; int ret = 0; memset(&cgc, 0, sizeof(cgc)); @@ -2631,8 +2663,9 @@ case CDROMVOLCTRL: case CDROMVOLREAD: { struct cdrom_volctrl volctrl; - char mask[32]; + char mask[sizeof(buffer)]; unsigned short offset; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); IOCTL_IN(arg, struct cdrom_volctrl, volctrl); @@ -2642,17 +2675,27 @@ if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0))) return ret; - /* some drives have longer pages, adjust and reread. */ - if (buffer[1] > cgc.buflen) { - cgc.buflen = buffer[1] + 2; - if ((ret = cdrom_mode_sense(cdi, &cgc, - GPMODE_AUDIO_CTL_PAGE, 0))) - return ret; + /* originally the code depended on buffer[1] to determine + how much data is available for transfer. buffer[1] is + unfortunately ambigious and the only reliable way seem + to be to simply skip over the block descriptor... */ + offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6)); + + if (offset + 16 > sizeof(buffer)) + return -E2BIG; + + if (offset + 16 > cgc.buflen) { + cgc.buflen = offset+16; + ret = cdrom_mode_sense(cdi, &cgc, + GPMODE_AUDIO_CTL_PAGE, 0); + if (ret) + return ret; } - - /* get the offset from the length of the page. length - is measure from byte 2 an on, thus the 14. */ - offset = buffer[1] - 14; + + /* sanity check */ + if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || + buffer[offset+1] < 14) + return -EINVAL; /* now we have the current volume settings. if it was only a CDROMVOLREAD, return these values */ @@ -2677,7 +2720,8 @@ buffer[offset+15] = volctrl.channel3 & mask[offset+15]; /* set volume */ - cgc.buffer = buffer; + cgc.buffer = buffer + offset - 8; + memset(cgc.buffer, 0, 8); return cdrom_mode_select(cdi, &cgc); } @@ -2760,7 +2804,7 @@ { struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; - int ret; + int ret, buflen; init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; @@ -2773,14 +2817,18 @@ if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; - cgc.buflen = be16_to_cpu(ti->track_information_length) + + buflen = be16_to_cpu(ti->track_information_length) + sizeof(ti->track_information_length); - if (cgc.buflen > sizeof(track_information)) - cgc.buflen = sizeof(track_information); + if (buflen > sizeof(track_information)) + buflen = sizeof(track_information); - cgc.cmd[8] = cgc.buflen; - return cdo->generic_packet(cdi, &cgc); + cgc.cmd[8] = cgc.buflen = buflen; + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* return actual fill size */ + return buflen; } /* requires CD R/RW */ @@ -2788,7 +2836,7 @@ { struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; - int ret; + int ret, buflen; /* set up command and get the disc info */ init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); @@ -2802,14 +2850,18 @@ /* not all drives have the same disc_info length, so requeue * packet with the length the drive tells us it can supply */ - cgc.buflen = be16_to_cpu(di->disc_information_length) + + buflen = be16_to_cpu(di->disc_information_length) + sizeof(di->disc_information_length); - if (cgc.buflen > sizeof(disc_information)) - cgc.buflen = sizeof(disc_information); + if (buflen > sizeof(disc_information)) + buflen = sizeof(disc_information); - cgc.cmd[8] = cgc.buflen; - return cdo->generic_packet(cdi, &cgc); + cgc.cmd[8] = cgc.buflen = buflen; + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* return actual fill size */ + return buflen; } /* return the last written block on the CD-R media. this is for the udf @@ -2820,27 +2872,37 @@ disc_information di; track_information ti; __u32 last_track; - int ret = -1; + int ret = -1, ti_size; if (!CDROM_CAN(CDC_GENERIC_PACKET)) goto use_toc; - if ((ret = cdrom_get_disc_info(cdi, &di))) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < (int)(offsetof(typeof(di), last_track_lsb) + + sizeof(di.last_track_lsb))) goto use_toc; + /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ last_track = (di.last_track_msb << 8) | di.last_track_lsb; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < (int)offsetof(typeof(ti), track_start)) goto use_toc; /* if this track is blank, try the previous. */ if (ti.blank) { - last_track--; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + if (last_track==1) goto use_toc; + last_track--; + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); } + if (ti_size < (int)(offsetof(typeof(ti), track_size) + + sizeof(ti.track_size))) + goto use_toc; + /* if last recorded field is valid, return it. */ - if (ti.lra_v) { + if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) + + sizeof(ti.last_rec_address))) { *last_written = be32_to_cpu(ti.last_rec_address); } else { /* make it up instead */ @@ -2853,11 +2915,12 @@ /* this is where we end up if the drive either can't do a GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if - it fails. then we return the toc contents. */ + it doesn't give enough information or fails. then we return + the toc contents. */ use_toc: toc.cdte_format = CDROM_MSF; toc.cdte_track = CDROM_LEADOUT; - if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)) + if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) return ret; sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); *last_written = toc.cdte_addr.lba; @@ -2870,32 +2933,38 @@ disc_information di; track_information ti; __u16 last_track; - int ret = -1; + int ret, ti_size; if (!CDROM_CAN(CDC_GENERIC_PACKET)) goto use_last_written; - if ((ret = cdrom_get_disc_info(cdi, &di))) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) + + sizeof(di.last_track_lsb)) goto use_last_written; + /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ last_track = (di.last_track_msb << 8) | di.last_track_lsb; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) goto use_last_written; /* if this track is blank, try the previous. */ if (ti.blank) { + if (last_track == 1) + goto use_last_written; last_track--; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < 0) goto use_last_written; } /* if next recordable address field is valid, use it. */ - if (ti.nwa_v) + if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) + + sizeof(ti.next_writable)) { *next_writable = be32_to_cpu(ti.next_writable); - else - goto use_last_written; - - return 0; + return 0; + } use_last_written: if ((ret = cdrom_get_last_written(cdi, next_writable))) { diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c --- a/drivers/cdrom/cdu31a.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/cdrom/cdu31a.c 2004-10-18 14:56:48 -07:00 @@ -729,8 +729,7 @@ res_reg[1]); } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2 * HZ); + msleep(2000); sony_get_toc(); } @@ -960,8 +959,7 @@ if (((result_buffer[0] & 0xf0) == 0x20) && (num_retries < MAX_CDU31A_RETRIES)) { num_retries++; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ / 10); /* Wait .1 seconds on retries */ + msleep(100); goto retry_cd_operation; } diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c --- a/drivers/cdrom/mcd.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/cdrom/mcd.c 2004-10-18 14:56:33 -07:00 @@ -1021,10 +1021,9 @@ st = statusCmd(); /* check drive status */ if (st == -1) goto err_out; /* drive doesn't respond */ - if ((st & MST_READY) == 0) { /* no disk? wait a sec... */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ); - } + if ((st & MST_READY) == 0) /* no disk? wait a sec... */ + msleep(1000); + } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); if (updateToc() < 0) diff -Nru a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c --- a/drivers/cdrom/viocd.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/cdrom/viocd.c 2004-10-18 14:57:04 -07:00 @@ -121,7 +121,10 @@ }; static struct capability_entry capability_table[] __initdata = { - { "6330", CDC_LOCK | CDC_DVD_RAM }, + { "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, { "6321", CDC_LOCK }, { "632B", 0 }, { NULL , CDC_LOCK }, @@ -332,10 +335,19 @@ struct disk_info *diskinfo = req->rq_disk->private_data; u64 len; dma_addr_t dmaaddr; + int direction; + u16 cmd; struct scatterlist sg; BUG_ON(req->nr_phys_segments > 1); - BUG_ON(rq_data_dir(req) != READ); + + if (rq_data_dir(req) == READ) { + direction = DMA_FROM_DEVICE; + cmd = viomajorsubtype_cdio | viocdread; + } else { + direction = DMA_TO_DEVICE; + cmd = viomajorsubtype_cdio | viocdwrite; + } if (blk_rq_map_sg(req->q, req, &sg) == 0) { printk(VIOCD_KERN_WARNING @@ -343,7 +355,7 @@ return -1; } - if (dma_map_sg(diskinfo->dev, &sg, 1, DMA_FROM_DEVICE) == 0) { + if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) { printk(VIOCD_KERN_WARNING "error allocating sg tce\n"); return -1; } @@ -351,8 +363,7 @@ len = sg_dma_len(&sg); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_cdio | viocdread, + HvLpEvent_Type_VirtualIo, cmd, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), @@ -457,6 +468,41 @@ return 0; } +static int viocd_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) +{ + unsigned int buflen = cgc->buflen; + int ret = -EIO; + + switch (cgc->cmd[0]) { + case GPCMD_READ_DISC_INFO: + { + disc_information *di = (disc_information *)cgc->buffer; + + if (buflen >= 2) { + di->disc_information_length = cpu_to_be16(1); + ret = 0; + } + if (buflen >= 3) + di->erasable = + (cdi->ops->capability & ~cdi->mask + & (CDC_DVD_RAM | CDC_RAM)) != 0; + } + break; + default: + if (cgc->sense) { + /* indicate Unknown code */ + cgc->sense->sense_key = 0x05; + cgc->sense->asc = 0x20; + cgc->sense->ascq = 0x00; + } + break; + } + + cgc->stat = ret; + return ret; +} + /* This routine handles incoming CD LP events */ static void vio_handle_cd_event(struct HvLpEvent *event) { @@ -510,6 +556,7 @@ case viocdclose: break; + case viocdwrite: case viocdread: /* * Since this is running in interrupt mode, we need to @@ -518,7 +565,8 @@ di = &viocd_diskinfo[bevent->disk]; spin_lock_irqsave(&viocd_reqlock, flags); dma_unmap_single(di->dev, bevent->token, bevent->len, - DMA_FROM_DEVICE); + ((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread) + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); req = (struct request *)bevent->event.xCorrelationToken; rwreq--; @@ -555,7 +603,8 @@ .release = viocd_release, .media_changed = viocd_media_changed, .lock_door = viocd_lock_door, - .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM + .generic_packet = viocd_packet, + .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM }; static int __init find_capability(const char *type) diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig --- a/drivers/char/Kconfig 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/Kconfig 2004-10-18 14:55:54 -07:00 @@ -59,7 +59,7 @@ config HW_CONSOLE bool - depends on VT && !S390 && !UM + depends on VT && !S390 && !USERMODE default y config SERIAL_NONSTANDARD @@ -424,6 +424,14 @@ will also be built as a module. This has to be loaded before "ser_a2232". If you want to do this, answer M here. +config SGI_SNSC + bool "SGI Altix system controller communication support" + depends on (IA64_SGI_SN2 || IA64_GENERIC) + help + If you have an SGI Altix and you want to enable system + controller communication from user space (you want this!), + say Y. Otherwise, say N. + source "drivers/serial/Kconfig" config UNIX98_PTYS @@ -587,39 +595,6 @@ which will also be compiled when this driver is built as a module. -config QIC02_TAPE - tristate "QIC-02 tape support" - help - If you have a non-SCSI tape drive like that, say Y. - - To compile this driver as a module, choose M here: the - module will be called tpqic02. - -config QIC02_DYNCONF - bool "Do you want runtime configuration for QIC-02" - depends on QIC02_TAPE - help - You can either configure this driver once and for all by editing a - header file (), in which case you - should say N, or you can fetch a program via anonymous FTP which is - able to configure this driver during runtime. The program to do - this is called 'qic02conf' and it is part of the - tpqic02-support-X.Y.tar.gz support package. - - If you want to use the qic02conf program, say Y. - -comment "Edit configuration parameters in ./include/linux/tpqic02.h!" - depends on QIC02_TAPE && !QIC02_DYNCONF - -comment "Setting runtime QIC-02 configuration is done with qic02conf" - depends on QIC02_TAPE && QIC02_DYNCONF - -comment "from the tpqic02-support package. It is available at" - depends on QIC02_TAPE && QIC02_DYNCONF - -comment "metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/" - depends on QIC02_TAPE && QIC02_DYNCONF - source "drivers/char/ipmi/Kconfig" source "drivers/char/watchdog/Kconfig" @@ -778,7 +753,7 @@ config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 + depends on RTC!=y && !IA64 && !ARM ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -1005,6 +980,14 @@ The hangcheck-timer module detects when the system has gone out to lunch past a certain margin. It can reboot the system or merely print a warning. + +config MMTIMER + tristate "MMTIMER Memory mapped RTC for SGI Altix" + depends on IA64_GENERIC || IA64_SGI_SN2 + default y + help + The mmtimer device allows direct userspace access to the + Altix system timer. endmenu diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/Makefile 2004-10-18 14:57:04 -07:00 @@ -7,8 +7,11 @@ # FONTMAPFILE = cp437.uni -obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o +obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o +obj-$(CONFIG_LEGACY_PTYS) += pty.o +obj-$(CONFIG_UNIX98_PTYS) += pty.o +obj-y += misc.o obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \ consolemap_deftbl.o selection.o keyboard.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o @@ -39,8 +42,10 @@ obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o -obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o +obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o obj-$(CONFIG_RAW_DRIVER) += raw.o +obj-$(CONFIG_SGI_SNSC) += snsc.o +obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_VIOCONS) += viocons.o obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_HVCS) += hvcs.o diff -Nru a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig --- a/drivers/char/agp/Kconfig 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/agp/Kconfig 2004-10-18 14:56:33 -07:00 @@ -1,5 +1,5 @@ config AGP - tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU && !M68K + tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU && !M68K && !ARM default y if GART_IOMMU ---help--- AGP (Accelerated Graphics Port) is a bus system mainly used to @@ -130,7 +130,7 @@ depends on AGP && X86 && !X86_64 help This option gives you AGP support for the GLX component of - XFree86 4.x on VIA MPV3/Apollo Pro chipsets. + XFree86 4.x on VIA MVP3/Apollo Pro chipsets. You should say Y here if you use XFree86 3.3.6 or 4.x and want to use GLX or DRI. If unsure, say N. diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h --- a/drivers/char/agp/agp.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/agp/agp.h 2004-10-18 14:56:29 -07:00 @@ -123,7 +123,7 @@ void *current_size; void *dev_private_data; struct pci_dev *dev; - u32 *gatt_table; + u32 __iomem *gatt_table; u32 *gatt_table_real; unsigned long scratch_page; unsigned long scratch_page_real; diff -Nru a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c --- a/drivers/char/agp/amd-k7-agp.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/agp/amd-k7-agp.c 2004-10-18 14:57:05 -07:00 @@ -24,11 +24,11 @@ struct amd_page_map { unsigned long *real; - unsigned long *remapped; + unsigned long __iomem *remapped; }; static struct _amd_irongate_private { - volatile u8 *registers; + volatile u8 __iomem *registers; struct amd_page_map **gatt_pages; int num_tables; } amd_irongate_private; @@ -54,7 +54,7 @@ global_cache_flush(); for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) - page_map->remapped[i] = agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, page_map->remapped+i); return 0; } @@ -151,7 +151,7 @@ } agp_bridge->gatt_table_real = (u32 *)page_dir.real; - agp_bridge->gatt_table = (u32 *)page_dir.remapped; + agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped; agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); /* Get the address for the gart region. @@ -165,9 +165,8 @@ /* Calculate the agp offset */ for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = - virt_to_phys(amd_irongate_private.gatt_pages[i]->real); - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + writel(virt_to_phys(amd_irongate_private.gatt_pages[i]->real) | 1, + page_dir.remapped+GET_PAGE_DIR_OFF(addr)); } return 0; @@ -178,7 +177,7 @@ struct amd_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; - page_dir.remapped = (unsigned long *)agp_bridge->gatt_table; + page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; amd_free_gatt_pages(); amd_free_page_map(&page_dir); @@ -218,7 +217,7 @@ /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp); temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); - amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096); + amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); /* Write out the address of the gatt table */ OUTREG32(amd_irongate_private.registers, AMD_ATTBASE, @@ -263,7 +262,7 @@ pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp); temp = ((temp & ~(0x0000000f)) | previous_size->size_value); pci_write_config_dword(agp_bridge->dev, AMD_APSIZE, temp); - iounmap((void *) amd_irongate_private.registers); + iounmap((void __iomem *) amd_irongate_private.registers); } /* @@ -282,7 +281,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; @@ -297,7 +296,7 @@ while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)])) + if (!PGE_EMPTY(agp_bridge, readl(cur_gatt+GET_GATT_OFF(addr)))) return -EBUSY; j++; } @@ -310,8 +309,7 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - agp_generic_mask_memory(mem->memory[i], mem->type); + writel(agp_generic_mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } amd_irongate_tlbflush(mem); return 0; @@ -320,7 +318,7 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { int i; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; if (type != 0 || mem->type != 0) @@ -329,8 +327,7 @@ for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } amd_irongate_tlbflush(mem); diff -Nru a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c --- a/drivers/char/agp/amd64-agp.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/agp/amd64-agp.c 2004-10-18 14:56:48 -07:00 @@ -73,7 +73,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; - long tmp; + long long tmp; u32 pte; num_entries = agp_num_entries(); @@ -90,7 +90,7 @@ /* gatt table should be empty. */ while (j < (pg_start + mem->page_count)) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY; j++; } @@ -108,7 +108,7 @@ pte |=(tmp & 0x00000000fffff000ULL); pte |= GPTE_VALID | GPTE_COHERENT; - agp_bridge->gatt_table[j] = pte; + writel(pte, agp_bridge->gatt_table+j); } amd64_tlbflush(mem); return 0; @@ -675,4 +675,4 @@ MODULE_AUTHOR("Dave Jones , Andi Kleen"); MODULE_PARM(agp_try_unsupported, "1i"); -MODULE_LICENSE("GPL and additional rights"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c --- a/drivers/char/agp/ati-agp.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/agp/ati-agp.c 2004-10-18 14:56:48 -07:00 @@ -42,11 +42,11 @@ typedef struct _ati_page_map { unsigned long *real; - unsigned long *remapped; + unsigned long __iomem *remapped; } ati_page_map; static struct _ati_generic_private { - volatile u8 *registers; + volatile u8 __iomem *registers; ati_page_map **gatt_pages; int num_tables; } ati_generic_private; @@ -76,7 +76,7 @@ global_cache_flush(); for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) - page_map->remapped[i] = agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, page_map->remapped+i); return 0; } @@ -206,7 +206,7 @@ temp = ((temp & ~(0x0000000f)) | previous_size->size_value); pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp); } - iounmap((void *) ati_generic_private.registers); + iounmap((volatile u8 __iomem *)ati_generic_private.registers); } @@ -217,7 +217,7 @@ /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp); temp = (temp & 0xfffff000); - ati_generic_private.registers = (volatile u8 *) ioremap(temp, 4096); + ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (is_r200()) pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); @@ -261,7 +261,7 @@ off_t pg_start, int type) { int i, j, num_entries; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; @@ -276,7 +276,7 @@ while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - if (!PGE_EMPTY(agp_bridge,cur_gatt[GET_GATT_OFF(addr)])) + if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr)))) return -EBUSY; j++; } @@ -290,8 +290,7 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - agp_bridge->driver->mask_memory(mem->memory[i], mem->type); + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } agp_bridge->driver->tlb_flush(mem); return 0; @@ -301,7 +300,7 @@ int type) { int i; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; if (type != 0 || mem->type != 0) { @@ -310,8 +309,7 @@ for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } agp_bridge->driver->tlb_flush(mem); @@ -340,7 +338,7 @@ } agp_bridge->gatt_table_real = (u32 *)page_dir.real; - agp_bridge->gatt_table = (u32 *)page_dir.remapped; + agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped; agp_bridge->gatt_bus_addr = virt_to_bus(page_dir.real); /* Write out the size register */ @@ -371,9 +369,8 @@ /* Calculate the agp offset */ for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = - virt_to_bus(ati_generic_private.gatt_pages[i]->real); - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + writel(virt_to_bus(ati_generic_private.gatt_pages[i]->real) | 1, + page_dir.remapped+GET_PAGE_DIR_OFF(addr)); } return 0; @@ -384,7 +381,7 @@ ati_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; - page_dir.remapped = (unsigned long *)agp_bridge->gatt_table; + page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; ati_free_gatt_pages(); ati_free_page_map(&page_dir); diff -Nru a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c --- a/drivers/char/agp/generic.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/agp/generic.c 2004-10-18 14:56:28 -07:00 @@ -35,6 +35,7 @@ #include #include #include +#include #include "agp.h" __u32 *agp_gatt_table; @@ -737,7 +738,7 @@ /* AK: bogus, should encode addresses > 4GB */ for (i = 0; i < num_entries; i++) - agp_bridge->gatt_table[i] = (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i); return 0; } @@ -843,9 +844,8 @@ j = pg_start; while (j < (pg_start + mem->page_count)) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) { + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY; - } j++; } @@ -855,9 +855,7 @@ } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - agp_bridge->gatt_table[j] = - agp_bridge->driver->mask_memory( - mem->memory[i], mem->type); + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), agp_bridge->gatt_table+j); agp_bridge->driver->tlb_flush(mem); return 0; @@ -875,10 +873,8 @@ } /* AK: bogus, should encode addresses > 4GB */ - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - agp_bridge->gatt_table[i] = - (unsigned long) agp_bridge->scratch_page; - } + for (i = pg_start; i < (mem->page_count + pg_start); i++) + writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i); agp_bridge->driver->tlb_flush(mem); return 0; diff -Nru a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c --- a/drivers/char/agp/hp-agp.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/char/agp/hp-agp.c 2004-10-18 14:56:49 -07:00 @@ -59,8 +59,8 @@ }; static struct _hp_private { - volatile u8 *ioc_regs; - volatile u8 *lba_regs; + volatile u8 __iomem *ioc_regs; + volatile u8 __iomem *lba_regs; int lba_cap_offset; u64 *io_pdir; // PDIR for entire IOVA u64 *gatt; // PDIR just for GART (subset of above) @@ -97,7 +97,7 @@ default: printk(KERN_ERR PFX "Invalid IOTLB page size " "configuration 0x%x\n", hp->io_tlb_ps); - hp->gatt = 0; + hp->gatt = NULL; hp->gatt_entries = 0; return -ENODEV; } @@ -115,7 +115,7 @@ if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { /* Normal case when no AGP device in system */ - hp->gatt = 0; + hp->gatt = NULL; hp->gatt_entries = 0; printk(KERN_ERR PFX "No reserved IO PDIR entry found; " "GART disabled\n"); @@ -183,7 +183,7 @@ } static int -hp_zx1_lba_find_capability (volatile u8 *hpa, int cap) +hp_zx1_lba_find_capability (volatile u8 __iomem *hpa, int cap) { u16 status; u8 pos, id; @@ -267,10 +267,10 @@ if (hp->ioc_regs) { if (hp->io_pdir_owner) OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0); - iounmap((void *) hp->ioc_regs); + iounmap(hp->ioc_regs); } if (hp->lba_regs) - iounmap((void *) hp->lba_regs); + iounmap(hp->lba_regs); } static void @@ -294,7 +294,7 @@ if (!hp->io_pdir) { printk(KERN_ERR PFX "Couldn't allocate contiguous " "memory for I/O PDIR\n"); - hp->gatt = 0; + hp->gatt = NULL; hp->gatt_entries = 0; return -ENOMEM; } diff -Nru a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c --- a/drivers/char/agp/intel-agp.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/char/agp/intel-agp.c 2004-10-18 14:56:31 -07:00 @@ -69,7 +69,7 @@ static struct _intel_i810_private { struct pci_dev *i810_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; int num_dcache_entries; } intel_i810_private; @@ -111,7 +111,7 @@ pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); temp &= 0xfff80000; - intel_i810_private.registers = (volatile u8 *) ioremap(temp, 128 * 4096); + intel_i810_private.registers = ioremap(temp, 128 * 4096); if (!intel_i810_private.registers) { printk(KERN_ERR PFX "Unable to remap memory.\n"); return -ENOMEM; @@ -142,7 +142,7 @@ static void intel_i810_cleanup(void) { OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); - iounmap((void *) intel_i810_private.registers); + iounmap(intel_i810_private.registers); } static void intel_i810_tlbflush(struct agp_memory *mem) @@ -162,11 +162,11 @@ page = alloc_pages(GFP_KERNEL, 2); if (page == NULL) { - return 0; + return NULL; } if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { - __free_page(page); - return 0; + __free_page(page); + return NULL; } get_page(page); SetPageLocked(page); @@ -180,7 +180,7 @@ if (addr == NULL) return; - + page = virt_to_page(addr); change_page_attr(page, 4, PAGE_KERNEL); put_page(page); @@ -202,7 +202,7 @@ return -EINVAL; } for (j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY; } @@ -330,7 +330,7 @@ if (curr->page_count == 4) i8xx_destroy_pages(phys_to_virt(curr->memory[0])); else - agp_bridge->driver->agp_destroy_page( + agp_bridge->driver->agp_destroy_page( phys_to_virt(curr->memory[0])); vfree(curr->memory); } @@ -353,8 +353,8 @@ static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ - volatile u8 *registers; - volatile u32 *gtt; /* I915G */ + volatile u8 __iomem *registers; + volatile u32 __iomem *gtt; /* I915G */ int gtt_entries; } intel_i830_private; @@ -371,7 +371,7 @@ /* We obtain the size of the GTT, which is also stored (for some * reason) at the top of stolen memory. Then we add 4KB to that - * for the video BIOS popup, which is also stored in there. */ + * for the video BIOS popup, which is also stored in there. */ size = agp_bridge->driver->fetch_size() + 4; if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || @@ -461,7 +461,7 @@ pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); temp &= 0xfff80000; - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + intel_i830_private.registers = ioremap(temp,128 * 4096); if (!intel_i830_private.registers) return (-ENOMEM); @@ -544,7 +544,7 @@ static void intel_i830_cleanup(void) { - iounmap((void *) intel_i830_private.registers); + iounmap(intel_i830_private.registers); } static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -649,8 +649,8 @@ static void intel_i915_cleanup(void) { - iounmap((void *) intel_i830_private.gtt); - iounmap((void *) intel_i830_private.registers); + iounmap(intel_i830_private.gtt); + iounmap(intel_i830_private.registers); } static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -746,18 +746,18 @@ size = agp_bridge->current_size; page_order = size->page_order; num_entries = size->num_entries; - agp_bridge->gatt_table_real = 0; + agp_bridge->gatt_table_real = NULL; pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); pci_read_config_dword(intel_i830_private.i830_dev, I915_PTEADDR,&temp2); - intel_i830_private.gtt = (volatile u32 *) ioremap(temp2, 256 * 1024); - if (!intel_i830_private.gtt) + intel_i830_private.gtt = ioremap(temp2, 256 * 1024); + if (!intel_i830_private.gtt) return (-ENOMEM); temp &= 0xfff80000; - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + intel_i830_private.registers = ioremap(temp,128 * 4096); if (!intel_i830_private.registers) return (-ENOMEM); @@ -921,7 +921,7 @@ /* aperture size */ pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, - current_size->size_value); + current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); @@ -933,7 +933,7 @@ pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* apcont */ pci_read_config_byte(agp_bridge->dev, INTEL_815_APCONT, &temp2); @@ -956,7 +956,7 @@ previous_size = A_SIZE_8(agp_bridge->previous_size); pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp); - pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, + pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp & ~(1 << 1)); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value); @@ -966,23 +966,23 @@ static int intel_820_configure(void) { u32 temp; - u8 temp2; + u8 temp2; struct aper_size_info_8 *current_size; current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* global enable aperture access */ /* This flag is not accessed through MCHCFG register as in */ @@ -990,7 +990,7 @@ pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp2); pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp2 | (1 << 1)); /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c); return 0; } @@ -1003,23 +1003,23 @@ current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* mcgcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, temp2 | (1 << 9)); /* clear any possible error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000); + pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000); return 0; } @@ -1032,23 +1032,23 @@ current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* agpm */ pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2); pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1)); /* clear any possible error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); return 0; } @@ -1061,23 +1061,23 @@ current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* mcgcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, temp2 | (1 << 9)); /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c); return 0; } @@ -1163,7 +1163,7 @@ /* mchcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, temp2 | (1 << 9)); - + return 0; } @@ -1178,7 +1178,7 @@ {64, 16384, 4, 0}, {32, 8192, 3, 8}, }; - + static struct aper_size_info_8 intel_8xx_sizes[7] = { {256, 65536, 6, 0}, @@ -1201,7 +1201,7 @@ {4, 1024, 0, 63} }; -static struct aper_size_info_8 intel_830mp_sizes[4] = +static struct aper_size_info_8 intel_830mp_sizes[4] = { {256, 65536, 6, 0}, {128, 32768, 5, 32}, @@ -1283,7 +1283,7 @@ .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 3, + .num_aperture_sizes = 3, .needs_scratch_page = TRUE, .configure = intel_i830_configure, .fetch_size = intel_i830_fetch_size, @@ -1445,7 +1445,7 @@ .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 3, + .num_aperture_sizes = 3, .needs_scratch_page = TRUE, .configure = intel_i915_configure, .fetch_size = intel_i915_fetch_size, @@ -1489,18 +1489,13 @@ .agp_destroy_page = agp_generic_destroy_page, }; -static int find_i810(u16 device, const char *name) +static int find_i810(u16 device) { struct pci_dev *i810_dev; i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (!i810_dev) { - printk(KERN_ERR PFX "Detected an Intel %s Chipset, " - "but could not find the secondary device.\n", - name); + if (!i810_dev) return 0; - } - intel_i810_private.i810_dev = i810_dev; return 1; } @@ -1550,29 +1545,29 @@ name = "440GX"; break; case PCI_DEVICE_ID_INTEL_82810_MC1: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1, "i810")) + name = "i810"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1)) goto fail; bridge->driver = &intel_810_driver; - name = "i810"; break; case PCI_DEVICE_ID_INTEL_82810_MC3: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3, "i810 DC100")) + name = "i810 DC100"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3)) goto fail; bridge->driver = &intel_810_driver; - name = "i810 DC100"; break; case PCI_DEVICE_ID_INTEL_82810E_MC: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG, "i810 E")) + name = "i810 E"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG)) goto fail; bridge->driver = &intel_810_driver; - name = "i810 E"; break; case PCI_DEVICE_ID_INTEL_82815_MC: /* * The i815 can operate either as an i810 style * integrated device, or as an AGP4X motherboard. */ - if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC, "i815")) + if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC)) bridge->driver = &intel_810_driver; else bridge->driver = &intel_815_driver; @@ -1708,7 +1703,10 @@ pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); - fail: + +fail: + printk(KERN_ERR PFX "Detected an Intel %s chipset, " + "but could not find the secondary device.\n", name); agp_put_bridge(bridge); return -ENODEV; } @@ -1724,7 +1722,7 @@ static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - + pci_restore_state(pdev, pdev->saved_config_space); if (bridge->driver == &intel_generic_driver) @@ -1741,7 +1739,7 @@ static struct pci_device_id agp_intel_pci_table[] = { #define ID(x) \ - { \ + { \ .class = (PCI_CLASS_BRIDGE_HOST << 8), \ .class_mask = ~0, \ .vendor = PCI_VENDOR_ID_INTEL, \ @@ -1769,7 +1767,8 @@ ID(PCI_DEVICE_ID_INTEL_82865_HB), ID(PCI_DEVICE_ID_INTEL_82875_HB), ID(PCI_DEVICE_ID_INTEL_7505_0), - ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_82915G_HB), { } }; @@ -1779,7 +1778,7 @@ .name = "agpgart-intel", .id_table = agp_intel_pci_table, .probe = agp_intel_probe, - .remove = agp_intel_remove, + .remove = __devexit_p(agp_intel_remove), .resume = agp_intel_resume, }; diff -Nru a/drivers/char/agp/intel-mch-agp.c b/drivers/char/agp/intel-mch-agp.c --- a/drivers/char/agp/intel-mch-agp.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/char/agp/intel-mch-agp.c 2004-10-18 14:55:55 -07:00 @@ -84,7 +84,7 @@ static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; int gtt_entries; } intel_i830_private; @@ -172,7 +172,7 @@ pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); temp &= 0xfff80000; - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + intel_i830_private.registers = (volatile u8 __iomem*) ioremap(temp,128 * 4096); if (!intel_i830_private.registers) return (-ENOMEM); @@ -255,7 +255,7 @@ static void intel_i830_cleanup(void) { - iounmap((void *) intel_i830_private.registers); + iounmap((void __iomem *) intel_i830_private.registers); } static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -633,5 +633,5 @@ module_exit(agp_intelmch_cleanup); MODULE_AUTHOR("Dave Jones "); -MODULE_LICENSE("GPL and additional rights"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c --- a/drivers/char/agp/nvidia-agp.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/agp/nvidia-agp.c 2004-10-18 14:56:17 -07:00 @@ -28,7 +28,7 @@ struct pci_dev *dev_1; struct pci_dev *dev_2; struct pci_dev *dev_3; - volatile u32 *aperture; + volatile u32 __iomem *aperture; int num_active_entries; off_t pg_offset; u32 wbc_mask; @@ -154,7 +154,7 @@ /* map aperture */ nvidia_private.aperture = - (volatile u32 *) ioremap(apbase, 33 * PAGE_SIZE); + (volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE); return 0; } @@ -173,7 +173,7 @@ pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp & ~(0x11)); /* unmap aperture */ - iounmap((void *) nvidia_private.aperture); + iounmap((void __iomem *) nvidia_private.aperture); /* restore previous aperture size */ previous_size = A_SIZE_8(agp_bridge->previous_size); @@ -206,7 +206,7 @@ return -EINVAL; for(j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[nvidia_private.pg_offset + j])) + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+nvidia_private.pg_offset+j))) return -EBUSY; } @@ -215,9 +215,8 @@ mem->is_flushed = TRUE; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - agp_bridge->gatt_table[nvidia_private.pg_offset + j] = - agp_bridge->driver->mask_memory(mem->memory[i], mem->type); - + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), + agp_bridge->gatt_table+nvidia_private.pg_offset+j); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -229,11 +228,9 @@ if ((type != 0) || (mem->type != 0)) return -EINVAL; - - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - agp_bridge->gatt_table[nvidia_private.pg_offset + i] = - (unsigned long) agp_bridge->scratch_page; - } + + for (i = pg_start; i < (mem->page_count + pg_start); i++) + writel(agp_bridge->scratch_page, agp_bridge->gatt_table+nvidia_private.pg_offset+i); agp_bridge->driver->tlb_flush(mem); return 0; @@ -265,9 +262,9 @@ /* flush TLB entries */ for(i = 0; i < 32 + 1; i++) - temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)]; + temp = readl(nvidia_private.aperture+(i * PAGE_SIZE / sizeof(u32))); for(i = 0; i < 32 + 1; i++) - temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)]; + temp = readl(nvidia_private.aperture+(i * PAGE_SIZE / sizeof(u32))); } diff -Nru a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c --- a/drivers/char/agp/sis-agp.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/agp/sis-agp.c 2004-10-18 14:55:54 -07:00 @@ -169,6 +169,10 @@ .chipset_name = "630", }, { + .device_id = PCI_DEVICE_ID_SI_635, + .chipset_name = "635", + }, + { .device_id = PCI_DEVICE_ID_SI_645, .chipset_name = "645", }, diff -Nru a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c --- a/drivers/char/agp/sworks-agp.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/agp/sworks-agp.c 2004-10-18 14:56:28 -07:00 @@ -27,12 +27,12 @@ struct serverworks_page_map { unsigned long *real; - unsigned long *remapped; + unsigned long __iomem *remapped; }; static struct _serverworks_private { struct pci_dev *svrwrks_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; struct serverworks_page_map **gatt_pages; int num_tables; struct serverworks_page_map scratch_dir; @@ -61,9 +61,8 @@ } global_cache_flush(); - for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { - page_map->remapped[i] = agp_bridge->scratch_page; - } + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) + writel(agp_bridge->scratch_page, page_map->remapped+i); return 0; } @@ -162,10 +161,8 @@ } /* Create a fake scratch directory */ for(i = 0; i < 1024; i++) { - serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge->scratch_page; - page_dir.remapped[i] = - virt_to_phys(serverworks_private.scratch_dir.real); - page_dir.remapped[i] |= 0x00000001; + writel(agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i); + writel(virt_to_phys(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i); } retval = serverworks_create_gatt_pages(value->num_entries / 1024); @@ -176,7 +173,7 @@ } agp_bridge->gatt_table_real = (u32 *)page_dir.real; - agp_bridge->gatt_table = (u32 *)page_dir.remapped; + agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped; agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); /* Get the address for the gart region. @@ -189,11 +186,8 @@ /* Calculate the agp offset */ - for(i = 0; i < value->num_entries / 1024; i++) { - page_dir.remapped[i] = - virt_to_phys(serverworks_private.gatt_pages[i]->real); - page_dir.remapped[i] |= 0x00000001; - } + for(i = 0; i < value->num_entries / 1024; i++) + writel(virt_to_phys(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i); return 0; } @@ -203,7 +197,7 @@ struct serverworks_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; - page_dir.remapped = (unsigned long *)agp_bridge->gatt_table; + page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; serverworks_free_gatt_pages(); serverworks_free_page_map(&page_dir); @@ -269,7 +263,7 @@ /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp); temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); - serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096); + serverworks_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (!serverworks_private.registers) { printk (KERN_ERR PFX "Unable to ioremap() memory.\n"); return -ENOMEM; @@ -311,14 +305,14 @@ static void serverworks_cleanup(void) { - iounmap((void *) serverworks_private.registers); + iounmap((void __iomem *) serverworks_private.registers); } static int serverworks_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; @@ -334,9 +328,8 @@ while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)])) { + if (!PGE_EMPTY(agp_bridge, readl(cur_gatt+GET_GATT_OFF(addr)))) return -EBUSY; - } j++; } @@ -348,8 +341,7 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - agp_bridge->driver->mask_memory(mem->memory[i], mem->type); + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } serverworks_tlbflush(mem); return 0; @@ -359,7 +351,7 @@ int type) { int i; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; if (type != 0 || mem->type != 0) { @@ -372,8 +364,7 @@ for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } serverworks_tlbflush(mem); diff -Nru a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c --- a/drivers/char/agp/via-agp.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/agp/via-agp.c 2004-10-18 14:56:50 -07:00 @@ -438,6 +438,33 @@ agp_put_bridge(bridge); } +#ifdef CONFIG_PM + +static int agp_via_suspend(struct pci_dev *pdev, u32 state) +{ + pci_save_state (pdev, pdev->saved_config_space); + pci_set_power_state (pdev, 3); + + return 0; +} + +static int agp_via_resume(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + pci_set_power_state (pdev, 0); + pci_restore_state(pdev, pdev->saved_config_space); + + if (bridge->driver == &via_agp3_driver) + return via_configure_agp3(); + else if (bridge->driver == &via_driver) + return via_configure(); + + return 0; +} + +#endif /* CONFIG_PM */ + /* must be the same order as name table above */ static struct pci_device_id agp_via_pci_table[] = { #define ID(x) \ @@ -487,6 +514,10 @@ .id_table = agp_via_pci_table, .probe = agp_via_probe, .remove = agp_via_remove, +#ifdef CONFIG_PM + .suspend = agp_via_suspend, + .resume = agp_via_resume, +#endif }; @@ -503,5 +534,5 @@ module_init(agp_via_init); module_exit(agp_via_cleanup); -MODULE_LICENSE("GPL and additional rights"); +MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dave Jones "); diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c --- a/drivers/char/amiserial.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/amiserial.c 2004-10-18 14:57:05 -07:00 @@ -118,10 +118,6 @@ #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -430,7 +426,7 @@ if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) - printk("ttyS%02d CD now %s...", info->line, + printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); #endif if (!(status & SER_DCD)) @@ -557,9 +553,7 @@ return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } @@ -1023,9 +1017,7 @@ info->xmit.head = info->xmit.tail = 0; local_irq_restore(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1564,8 +1556,8 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; @@ -1610,7 +1602,7 @@ if (char_time == 0) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); /* * If the transmitter hasn't cleared in twice the approximate * amount of time to send the entire FIFO, it probably won't @@ -2095,7 +2087,7 @@ continue; */ - printk(KERN_INFO "ttyS%02d is the amiga builtin serial port\n", + printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", state->line); /* Hardware set up */ diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c --- a/drivers/char/applicom.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/applicom.c 2004-10-18 14:57:04 -07:00 @@ -89,7 +89,7 @@ static struct applicom_board { unsigned long PhysIO; - unsigned long RamIO; + void __iomem *RamIO; wait_queue_head_t FlagSleepSend; long irq; spinlock_t mutex; @@ -127,7 +127,7 @@ static int dummy; /* dev_id for request_irq() */ -static int ac_register_board(unsigned long physloc, unsigned long loc, +static int ac_register_board(unsigned long physloc, void __iomem *loc, unsigned char boardno) { volatile unsigned char byte_reset_it; @@ -179,11 +179,11 @@ if (!apbs[i].RamIO) continue; - - iounmap((void *) apbs[i].RamIO); if (apbs[i].irq) free_irq(apbs[i].irq, &dummy); + + iounmap(apbs[i].RamIO); } } @@ -193,7 +193,7 @@ { int i, numisa = 0; struct pci_dev *dev = NULL; - void *RamIO; + void __iomem *RamIO; int boardno; printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n"); @@ -223,8 +223,8 @@ applicom_pci_devnames[dev->device-1], dev->resource[0].start, dev->irq); - if (!(boardno = ac_register_board(dev->resource[0].start, - (unsigned long)RamIO,0))) { + boardno = ac_register_board(dev->resource[0].start, RamIO,0); + if (!boardno) { printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); iounmap(RamIO); pci_disable_device(dev); @@ -235,7 +235,7 @@ printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); iounmap(RamIO); pci_disable_device(dev); - apbs[boardno - 1].RamIO = 0; + apbs[boardno - 1].RamIO = NULL; continue; } @@ -270,7 +270,7 @@ } if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i), - (unsigned long)RamIO,i+1))) { + RamIO,i+1))) { iounmap(RamIO); continue; } @@ -280,8 +280,8 @@ if (!numisa) { if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &dummy)) { printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq); - iounmap((void *) RamIO); - apbs[boardno - 1].RamIO = 0; + iounmap(RamIO); + apbs[boardno - 1].RamIO = NULL; } else apbs[boardno - 1].irq = irq; @@ -449,7 +449,7 @@ because it works with 2.2 still */ { unsigned char *from = (unsigned char *) &tmpmailbox; - unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC; + void __iomem *to = apbs[IndexCard].RamIO + RAM_FROM_PC; int c; for (c = 0; c < sizeof(struct mailbox); c++) @@ -470,7 +470,7 @@ static int do_ac_read(int IndexCard, char __user *buf, struct st_ram_io *st_loc, struct mailbox *mailbox) { - unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC; + void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC; unsigned char *to = (unsigned char *)&mailbox; #ifdef DEBUG int c; @@ -685,7 +685,7 @@ { /* @ ADG ou ATO selon le cas */ int i; unsigned char IndexCard; - unsigned long pmem; + void __iomem *pmem; int ret = 0; volatile unsigned char byte_reset_it; struct st_ram_io *adgl; diff -Nru a/drivers/char/busmouse.c b/drivers/char/busmouse.c --- a/drivers/char/busmouse.c 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,456 +0,0 @@ -/* - * linux/drivers/char/busmouse.c - * - * Copyright (C) 1995 - 1998 Russell King - * Protocol taken from original busmouse.c - * read() waiting taken from psaux.c - * - * Medium-level interface for quadrature or bus mice. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "busmouse.h" - -/* Uncomment this if your mouse drivers expect the kernel to - * return with EAGAIN if the mouse does not have any events - * available, even if the mouse is opened in blocking mode. - * Please report use of this "feature" to the author using the - * above address. - */ -/*#define BROKEN_MOUSE*/ - -struct busmouse_data { - struct miscdevice miscdev; - struct busmouse *ops; - spinlock_t lock; - - wait_queue_head_t wait; - struct fasync_struct *fasyncptr; - char active; - char buttons; - char ready; - int dxpos; - int dypos; -}; - -#define NR_MICE 15 -#define FIRST_MOUSE 0 -#define DEV_TO_MOUSE(inode) MINOR_TO_MOUSE(iminor(inode)) -#define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE) - -/* - * List of mice and guarding semaphore. You must take the semaphore - * before you take the misc device semaphore if you need both - */ - -static struct busmouse_data *busmouse_data[NR_MICE]; -static DECLARE_MUTEX(mouse_sem); - -/** - * busmouse_add_movement - notification of a change of mouse position - * @mousedev: mouse number - * @dx: delta X movement - * @dy: delta Y movement - * @buttons: new button state - * - * Updates the mouse position and button information. The mousedev - * parameter is the value returned from register_busmouse. The - * movement information is updated, and the new button state is - * saved. A waiting user thread is woken. - */ - -void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons) -{ - struct busmouse_data *mse = busmouse_data[mousedev]; - int changed; - - spin_lock(&mse->lock); - changed = (dx != 0 || dy != 0 || mse->buttons != buttons); - - if (changed) { - add_mouse_randomness((buttons << 16) + (dy << 8) + dx); - - mse->buttons = buttons; - mse->dxpos += dx; - mse->dypos += dy; - mse->ready = 1; - - /* - * keep dx/dy reasonable, but still able to track when X (or - * whatever) must page or is busy (i.e. long waits between - * reads) - */ - if (mse->dxpos < -2048) - mse->dxpos = -2048; - if (mse->dxpos > 2048) - mse->dxpos = 2048; - if (mse->dypos < -2048) - mse->dypos = -2048; - if (mse->dypos > 2048) - mse->dypos = 2048; - } - - spin_unlock(&mse->lock); - - if (changed) { - wake_up(&mse->wait); - - kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN); - } -} - -/** - * busmouse_add_movement - notification of a change of mouse position - * @mousedev: mouse number - * @dx: delta X movement - * @dy: delta Y movement - * - * Updates the mouse position. The mousedev parameter is the value - * returned from register_busmouse. The movement information is - * updated, and a waiting user thread is woken. - */ - -void busmouse_add_movement(int mousedev, int dx, int dy) -{ - struct busmouse_data *mse = busmouse_data[mousedev]; - - busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons); -} - -/** - * busmouse_add_buttons - notification of a change of button state - * @mousedev: mouse number - * @clear: mask of buttons to clear - * @eor: mask of buttons to change - * - * Updates the button state. The mousedev parameter is the value - * returned from register_busmouse. The buttons are updated by: - * new_state = (old_state & ~clear) ^ eor - * A waiting user thread is woken up. - */ - -void busmouse_add_buttons(int mousedev, int clear, int eor) -{ - struct busmouse_data *mse = busmouse_data[mousedev]; - - busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor); -} - -static int busmouse_fasync(int fd, struct file *filp, int on) -{ - struct busmouse_data *mse = (struct busmouse_data *)filp->private_data; - int retval; - - retval = fasync_helper(fd, filp, on, &mse->fasyncptr); - if (retval < 0) - return retval; - return 0; -} - -static int busmouse_release(struct inode *inode, struct file *file) -{ - struct busmouse_data *mse = (struct busmouse_data *)file->private_data; - int ret = 0; - - lock_kernel(); - busmouse_fasync(-1, file, 0); - - down(&mouse_sem); /* to protect mse->active */ - if (--mse->active == 0) { - if (mse->ops->release) - ret = mse->ops->release(inode, file); - module_put(mse->ops->owner); - mse->ready = 0; - } - unlock_kernel(); - up( &mouse_sem); - - return ret; -} - -static int busmouse_open(struct inode *inode, struct file *file) -{ - struct busmouse_data *mse; - unsigned int mousedev; - int ret; - - mousedev = DEV_TO_MOUSE(inode); - if (mousedev >= NR_MICE) - return -EINVAL; - - down(&mouse_sem); - mse = busmouse_data[mousedev]; - ret = -ENODEV; - if (!mse || !mse->ops) /* shouldn't happen, but... */ - goto end; - - if (!try_module_get(mse->ops->owner)) - goto end; - - ret = 0; - if (mse->ops->open) { - ret = mse->ops->open(inode, file); - if (ret) - module_put(mse->ops->owner); - } - - if (ret) - goto end; - - file->private_data = mse; - - if (mse->active++) - goto end; - - spin_lock_irq(&mse->lock); - - mse->ready = 0; - mse->dxpos = 0; - mse->dypos = 0; - mse->buttons = mse->ops->init_button_state; - - spin_unlock_irq(&mse->lock); -end: - up(&mouse_sem); - return ret; -} - -static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -{ - struct busmouse_data *mse = (struct busmouse_data *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - int dxpos, dypos, buttons; - - if (count < 3) - return -EINVAL; - - spin_lock_irq(&mse->lock); - - if (!mse->ready) { -#ifdef BROKEN_MOUSE - spin_unlock_irq(&mse->lock); - return -EAGAIN; -#else - if (file->f_flags & O_NONBLOCK) { - spin_unlock_irq(&mse->lock); - return -EAGAIN; - } - - add_wait_queue(&mse->wait, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (!mse->ready && !signal_pending(current)) { - spin_unlock_irq(&mse->lock); - schedule(); - spin_lock_irq(&mse->lock); - goto repeat; - } - - current->state = TASK_RUNNING; - remove_wait_queue(&mse->wait, &wait); - - if (signal_pending(current)) { - spin_unlock_irq(&mse->lock); - return -ERESTARTSYS; - } -#endif - } - - dxpos = mse->dxpos; - dypos = mse->dypos; - buttons = mse->buttons; - - if (dxpos < -127) - dxpos =- 127; - if (dxpos > 127) - dxpos = 127; - if (dypos < -127) - dypos =- 127; - if (dypos > 127) - dypos = 127; - - mse->dxpos -= dxpos; - mse->dypos -= dypos; - - /* This is something that many drivers have apparantly - * forgotten... If the X and Y positions still contain - * information, we still have some info ready for the - * user program... - */ - mse->ready = mse->dxpos || mse->dypos; - - spin_unlock_irq(&mse->lock); - - /* Write out data to the user. Format is: - * byte 0 - identifer (0x80) and (inverted) mouse buttons - * byte 1 - X delta position +/- 127 - * byte 2 - Y delta position +/- 127 - */ - if (put_user((char)buttons | 128, buffer) || - put_user((char)dxpos, buffer + 1) || - put_user((char)dypos, buffer + 2)) - return -EFAULT; - - if (count > 3 && clear_user(buffer + 3, count - 3)) - return -EFAULT; - - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - - return count; -} - -/* No kernel lock held - fine */ -static unsigned int busmouse_poll(struct file *file, poll_table *wait) -{ - struct busmouse_data *mse = (struct busmouse_data *)file->private_data; - - poll_wait(file, &mse->wait, wait); - - if (mse->ready) - return POLLIN | POLLRDNORM; - - return 0; -} - -struct file_operations busmouse_fops= -{ - .owner = THIS_MODULE, - .read = busmouse_read, - .write = busmouse_write, - .poll = busmouse_poll, - .open = busmouse_open, - .release = busmouse_release, - .fasync = busmouse_fasync, -}; - -/** - * register_busmouse - register a bus mouse interface - * @ops: busmouse structure for the mouse - * - * Registers a mouse with the driver. The return is mouse number on - * success and a negative errno code on an error. The passed ops - * structure most not be freed until the mouser is unregistered - */ - -int register_busmouse(struct busmouse *ops) -{ - unsigned int msedev = MINOR_TO_MOUSE(ops->minor); - struct busmouse_data *mse; - int ret = -EINVAL; - - if (msedev >= NR_MICE) { - printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n", - ops->minor); - goto out; - } - - ret = -ENOMEM; - mse = kmalloc(sizeof(*mse), GFP_KERNEL); - if (!mse) - goto out; - - down(&mouse_sem); - ret = -EBUSY; - if (busmouse_data[msedev]) - goto freemem; - - memset(mse, 0, sizeof(*mse)); - - mse->miscdev.minor = ops->minor; - mse->miscdev.name = ops->name; - mse->miscdev.fops = &busmouse_fops; - mse->ops = ops; - mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED; - init_waitqueue_head(&mse->wait); - - - ret = misc_register(&mse->miscdev); - - if (ret < 0) - goto freemem; - - busmouse_data[msedev] = mse; - ret = msedev; -out: - up(&mouse_sem); - return ret; - - -freemem: - kfree(mse); - goto out; -} - -/** - * unregister_busmouse - unregister a bus mouse interface - * @mousedev: Mouse number to release - * - * Unregister a previously installed mouse handler. The mousedev - * passed is the return code from a previous call to register_busmouse - */ - - -int unregister_busmouse(int mousedev) -{ - int err = -EINVAL; - - if (mousedev < 0) - return 0; - if (mousedev >= NR_MICE) { - printk(KERN_ERR "busmouse: trying to free mouse on" - " mousedev %d\n", mousedev); - return -EINVAL; - } - - down(&mouse_sem); - - if (!busmouse_data[mousedev]) { - printk(KERN_WARNING "busmouse: trying to free free mouse" - " on mousedev %d\n", mousedev); - goto fail; - } - - if (busmouse_data[mousedev]->active) { - printk(KERN_ERR "busmouse: trying to free active mouse" - " on mousedev %d\n", mousedev); - goto fail; - } - - err = misc_deregister(&busmouse_data[mousedev]->miscdev); - - kfree(busmouse_data[mousedev]); - busmouse_data[mousedev] = NULL; -fail: - up(&mouse_sem); - return err; -} - -EXPORT_SYMBOL(busmouse_add_movementbuttons); -EXPORT_SYMBOL(busmouse_add_movement); -EXPORT_SYMBOL(busmouse_add_buttons); -EXPORT_SYMBOL(register_busmouse); -EXPORT_SYMBOL(unregister_busmouse); - -MODULE_ALIAS_MISCDEV(BUSMOUSE_MINOR); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/char/busmouse.h b/drivers/char/busmouse.h --- a/drivers/char/busmouse.h 2004-10-18 14:55:54 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,27 +0,0 @@ -/* - * linux/drivers/char/busmouse.h - * - * Copyright (C) 1995 - 1998 Russell King - * - * Prototypes for generic busmouse interface - */ -#ifndef BUSMOUSE_H -#define BUSMOUSE_H - -struct busmouse { - int minor; - const char *name; - struct module *owner; - int (*open)(struct inode * inode, struct file * file); - int (*release)(struct inode * inode, struct file * file); - int init_button_state; -}; - -extern void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons); -extern void busmouse_add_movement(int mousedev, int dx, int dy); -extern void busmouse_add_buttons(int mousedev, int clear, int eor); - -extern int register_busmouse(struct busmouse *ops); -extern int unregister_busmouse(int mousedev); - -#endif diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c --- a/drivers/char/cyclades.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/cyclades.c 2004-10-18 14:56:17 -07:00 @@ -682,13 +682,13 @@ #define IS_CYC_Z(card) ((card).num_chips == -1) #define Z_FPGA_CHECK(card) \ - ((cy_readl(&((struct RUNTIME_9060 *) \ + ((cy_readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) -#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 *) \ +#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->mail_box_0)) || \ Z_FPGA_CHECK(card)) && \ - (ZFIRM_ID==cy_readl(&((struct FIRM_ID *) \ + (ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \ ((card).base_addr+ID_ADDRESS))->signature))) #ifndef SERIAL_XMIT_SIZE @@ -712,16 +712,16 @@ boot options line. The form is "cyclades=address,address..." */ -static unsigned char *cy_isa_addresses[] = { - (unsigned char *) 0xD0000, - (unsigned char *) 0xD2000, - (unsigned char *) 0xD4000, - (unsigned char *) 0xD6000, - (unsigned char *) 0xD8000, - (unsigned char *) 0xDA000, - (unsigned char *) 0xDC000, - (unsigned char *) 0xDE000, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL +static unsigned int cy_isa_addresses[] = { + 0xD0000, + 0xD2000, + 0xD4000, + 0xD6000, + 0xD8000, + 0xDA000, + 0xDC000, + 0xDE000, + 0,0,0,0,0,0,0,0 }; #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*)) @@ -854,7 +854,7 @@ static void set_line_char(struct cyclades_port *); static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong); #ifdef CONFIG_ISA -static unsigned detect_isa_irq (volatile ucchar *); +static unsigned detect_isa_irq(void __iomem *); #endif /* CONFIG_ISA */ static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *); @@ -970,10 +970,7 @@ wake_up_interruptible(&info->delta_msr_wait); } if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } #ifdef Z_WAKE @@ -995,7 +992,7 @@ This function is only called from inside spinlock-protected code. */ static int -cyy_issue_cmd(volatile ucchar *base_addr, u_char cmd, int index) +cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index) { volatile int i; @@ -1011,7 +1008,7 @@ if (i == 100) return (-1); /* Issue the new command */ - cy_writeb((u_long)base_addr+(CyCCR< 0)? irq : 0; @@ -1079,7 +1076,7 @@ int status; struct cyclades_card *cinfo; struct cyclades_port *info; - volatile unsigned char *base_addr, *card_base_addr; + void __iomem *base_addr, *card_base_addr; int chip; int save_xir, channel, save_car; char data; @@ -1098,7 +1095,7 @@ return IRQ_NONE; /* spurious interrupt */ } - card_base_addr = (unsigned char *)cinfo->base_addr; + card_base_addr = cinfo->base_addr; index = cinfo->bus_index; @@ -1110,8 +1107,7 @@ do{ had_work = 0; for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) { - base_addr = (unsigned char *) - (cinfo->base_addr + (cy_chip_offset[chip]<base_addr + (cy_chip_offset[chip]<last_active = jiffies; save_car = cy_readb(base_addr+(CyCAR<tty == 0){ @@ -1264,8 +1260,8 @@ schedule_delayed_work(&tty->flip.work, 1); } /* end of service */ - cy_writeb((u_long)base_addr+(CyRIR<card_lock); } @@ -1284,18 +1280,18 @@ channel = (u_short ) (save_xir & CyIRChannel); i = channel + chip * 4 + cinfo->first_line; save_car = cy_readb(base_addr+(CyCAR<last_active = jiffies; if(info->tty == 0){ - cy_writeb((u_long)base_addr+(CySRER<x_char) { /* send special char */ outch = info->x_char; - cy_writeb((u_long)base_addr+(CyTDR<icount.tx++; info->x_char = 0; @@ -1313,14 +1309,14 @@ if (info->breakon || info->breakoff) { if (info->breakon) { - cy_writeb((u_long)base_addr + (CyTDR<breakon = 0; char_count -= 2; } if (info->breakoff) { - cy_writeb((u_long)base_addr + (CyTDR<breakoff = 0; char_count -= 2; } @@ -1329,11 +1325,11 @@ while (char_count-- > 0){ if (!info->xmit_cnt){ if (cy_readb(base_addr+(CySRER<xmit_buf == 0){ - cy_writeb((u_long)base_addr+(CySRER<tty->stopped || info->tty->hw_stopped){ - cy_writeb((u_long)base_addr+(CySRER<xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); - cy_writeb((u_long)base_addr+(CyTDR<icount.tx++; }else{ if(char_count > 1){ info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); - cy_writeb((u_long)base_addr+(CyTDR<icount.tx++; char_count--; }else{ @@ -1391,9 +1387,9 @@ } txend: /* end of service */ - cy_writeb((u_long)base_addr+(CyTIR<card_lock); } @@ -1407,7 +1403,7 @@ + cinfo->first_line]; info->last_active = jiffies; save_car = cy_readb(base_addr+(CyCAR<tty->hw_stopped = 0; - cy_writeb((u_long)base_addr+(CySRER<tty->hw_stopped = 1; - cy_writeb((u_long)base_addr+(CySRER<card_lock); } } /* end while status != 0 */ @@ -1476,7 +1472,7 @@ /* clear interrupts */ spin_lock(&cinfo->card_lock); - cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<card_lock); return IRQ_HANDLED; @@ -1491,27 +1487,25 @@ cyz_fetch_msg( struct cyclades_card *cinfo, uclong *channel, ucchar *cmd, uclong *param) { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; unsigned long loc_doorbell; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)){ return (-1); } - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; - loc_doorbell = cy_readl(&((struct RUNTIME_9060 *) + loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->loc_doorbell); if (loc_doorbell){ *cmd = (char)(0xff & loc_doorbell); *channel = cy_readl(&board_ctrl->fwcmd_channel); *param = (uclong)cy_readl(&board_ctrl->fwcmd_param); - cy_writel(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->loc_doorbell, + cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->loc_doorbell, 0xffffffff); return 1; } @@ -1522,40 +1516,38 @@ cyz_issue_cmd( struct cyclades_card *cinfo, uclong channel, ucchar cmd, uclong param) { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - volatile uclong *pci_doorbell; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + unsigned long __iomem *pci_doorbell; int index; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)){ return (-1); } - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; index = 0; - pci_doorbell = (uclong *)(&((struct RUNTIME_9060 *) - (cinfo->ctl_addr))->pci_doorbell); + pci_doorbell = &((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->pci_doorbell; while( (cy_readl(pci_doorbell) & 0xff) != 0){ if (index++ == 1000){ return((int)(cy_readl(pci_doorbell) & 0xff)); } udelay(50L); } - cy_writel((u_long)&board_ctrl->hcmd_channel, channel); - cy_writel((u_long)&board_ctrl->hcmd_param , param); - cy_writel((u_long)pci_doorbell, (long)cmd); + cy_writel(&board_ctrl->hcmd_channel, channel); + cy_writel(&board_ctrl->hcmd_param , param); + cy_writel(pci_doorbell, (long)cmd); return(0); } /* cyz_issue_cmd */ static void -cyz_handle_rx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, - volatile struct BUF_CTRL *buf_ctrl) +cyz_handle_rx(struct cyclades_port *info, + volatile struct CH_CTRL __iomem *ch_ctrl, + volatile struct BUF_CTRL __iomem *buf_ctrl) { struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; @@ -1652,8 +1644,9 @@ } static void -cyz_handle_tx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, - volatile struct BUF_CTRL *buf_ctrl) +cyz_handle_tx(struct cyclades_port *info, + volatile struct CH_CTRL __iomem *ch_ctrl, + volatile struct BUF_CTRL __iomem *buf_ctrl) { struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; @@ -1740,11 +1733,11 @@ { struct tty_struct *tty; struct cyclades_port *info; - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct BOARD_CTRL *board_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; + static volatile struct FIRM_ID __iomem *firm_id; + static volatile struct ZFW_CTRL __iomem *zfw_ctrl; + static volatile struct BOARD_CTRL __iomem *board_ctrl; + static volatile struct CH_CTRL __iomem *ch_ctrl; + static volatile struct BUF_CTRL __iomem *buf_ctrl; uclong channel; ucchar cmd; uclong param; @@ -1752,13 +1745,11 @@ int special_count; int delta_count; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); - board_ctrl = &(zfw_ctrl->board_ctrl); + firm_id = cinfo->base_addr + ID_ADDRESS; + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; fw_ver = cy_readl(&board_ctrl->fw_version); - hw_ver = cy_readl(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->mail_box_0); + hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->mail_box_0); while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { @@ -1925,10 +1916,8 @@ if (!IS_CYC_Z(*cinfo)) continue; if (!ISZLOADED(*cinfo)) continue; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + firm_id = cinfo->base_addr + ID_ADDRESS; + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &(zfw_ctrl->board_ctrl); /* Skip first polling cycle to avoid racing conditions with the FW */ @@ -1972,7 +1961,7 @@ { unsigned long flags; int retval = 0; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; unsigned long page; @@ -2011,8 +2000,7 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<default_timeout + cy_writeb(base_addr+(CyRTPR<default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index); - cy_writeb((ulong)base_addr+(CyCAR<flags |= ASYNC_INITIALIZED; @@ -2056,22 +2044,20 @@ CY_UNLOCK(info, flags); } else { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = (unsigned char*) (cy_card[card].base_addr); + base_addr = cy_card[card].base_addr; - firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); + firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(cy_card[card])){ return -ENODEV; } - zfw_ctrl = (struct ZFW_CTRL *) - (cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; @@ -2163,7 +2149,7 @@ start_xmit( struct cyclades_port *info ) { unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; card = info->card; @@ -2172,13 +2158,11 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<flags & ASYNC_INITIALIZED)){ @@ -2219,9 +2203,7 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<xmit_buf = NULL; free_page((unsigned long) temp); } - cy_writeb((u_long)base_addr+(CyCAR<tty || (info->tty->termios->c_cflag & HUPCL)) { - cy_writeb((u_long)base_addr+(CyMSVR1<flags &= ~ASYNC_INITIALIZED; CY_UNLOCK(info, flags); } else { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = (unsigned char*) (cy_card[card].base_addr); + base_addr = cy_card[card].base_addr; #ifdef CY_DEBUG_OPEN printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n", card, channel, (long)base_addr); #endif - firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); + firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(cy_card[card])) { return; } - zfw_ctrl = (struct ZFW_CTRL *) - (cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); - board_ctrl = &(zfw_ctrl->board_ctrl); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; CY_LOCK(info, flags); @@ -2293,7 +2273,7 @@ } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { - cy_writel((u_long)&ch_ctrl[channel].rs_control, + cy_writel(&ch_ctrl[channel].rs_control, (uclong)(cy_readl(&ch_ctrl[channel].rs_control) & ~(C_RS_RTS | C_RS_DTR))); retval = cyz_issue_cmd(&cy_card[info->card], @@ -2337,7 +2317,7 @@ unsigned long flags; int chip, channel,index; int retval; - char *base_addr; + void __iomem *base_addr; cinfo = &cy_card[info->card]; channel = info->line - cinfo->first_line; @@ -2390,15 +2370,14 @@ chip = channel>>2; channel &= 0x03; index = cinfo->bus_index; - base_addr = (char *)(cinfo->base_addr - + (cy_chip_offset[chip]<base_addr + (cy_chip_offset[chip]<termios->c_cflag & CBAUD)){ - cy_writeb((u_long)base_addr+(CyCAR<flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (cy_readb(base_addr+(CyMSVR1<base_addr); - firm_id = (struct FIRM_ID *) - (base_addr + ID_ADDRESS); + base_addr = cinfo->base_addr; + firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)){ current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); return -EINVAL; } - zfw_ctrl = (struct ZFW_CTRL *) - (base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; @@ -2543,11 +2520,10 @@ */ if (IS_CYC_Z(cy_card[info->card])) { struct cyclades_card *cinfo = &cy_card[info->card]; - struct FIRM_ID *firm_id = (struct FIRM_ID *) - (cinfo->base_addr + ID_ADDRESS); + struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { - if (((ZE_V1 ==cy_readl(&((struct RUNTIME_9060 *) + if (((ZE_V1 ==cy_readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->mail_box_0)) && Z_FPGA_CHECK (*cinfo)) && (ZFIRM_HLT == cy_readl (&firm_id->signature))) @@ -2564,12 +2540,10 @@ interrupts should be enabled as soon as the first open happens to one of its ports. */ if (!cinfo->intr_enabled) { - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl (&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cinfo->base_addr + (cy_readl (&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; @@ -2661,7 +2635,7 @@ cy_wait_until_sent(struct tty_struct *tty, int timeout) { struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; unsigned long orig_jiffies; int char_time; @@ -2711,8 +2685,7 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char *) - (cy_card[card].base_addr + (cy_chip_offset[chip]<card])) { int channel = info->line - cy_card[info->card].first_line; int index = cy_card[info->card].bus_index; - unsigned char *base_addr = (unsigned char *) - (cy_card[info->card].base_addr + - (cy_chip_offset[channel>>2] <card].base_addr + (cy_chip_offset[channel>>2] << index); /* Stop accepting input */ channel &= 0x03; - cy_writeb((ulong)base_addr+(CyCAR<flags & ASYNC_INITIALIZED) { /* Waiting for on-board buffers to be empty before closing @@ -2823,12 +2794,10 @@ } else { #ifdef Z_WAKE /* Waiting for on-board buffers to be empty before closing the port */ - unsigned char *base_addr = (unsigned char *) - cy_card[info->card].base_addr; - struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); - struct ZFW_CTRL *zfw_ctrl = (struct ZFW_CTRL *) - (base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); - struct CH_CTRL *ch_ctrl = zfw_ctrl->ch_ctrl; + void __iomem *base_addr = cy_card[info->card].base_addr; + struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS; + struct ZFW_CTRL __iomem *zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl; int channel = info->line - cy_card[info->card].first_line; int retval; @@ -2850,8 +2819,7 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); CY_LOCK(info, flags); tty->closing = 0; @@ -3088,10 +3056,8 @@ int char_count; volatile uclong tx_put, tx_get, tx_bufsize; - firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) - (cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + firm_id = cy_card[card].base_addr + ID_ADDRESS; + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); @@ -3151,7 +3117,7 @@ set_line_char(struct cyclades_port * info) { unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; unsigned cflag, iflag; unsigned short chip_number; @@ -3303,76 +3269,74 @@ chip = channel>>2; channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<tco); - cy_writeb((u_long)base_addr+(CyTBPR<tbpr); - cy_writeb((u_long)base_addr+(CyRCOR<rco); - cy_writeb((u_long)base_addr+(CyRBPR<rbpr); + cy_writeb(base_addr+(CyTCOR<tco); + cy_writeb(base_addr+(CyTBPR<tbpr); + cy_writeb(base_addr+(CyRCOR<rco); + cy_writeb(base_addr+(CyRBPR<rbpr); /* set line characteristics according configuration */ - cy_writeb((u_long)base_addr+(CySCHR1<tty)); - cy_writeb((u_long)base_addr+(CySCHR2<tty)); - cy_writeb((u_long)base_addr+(CyCOR1<cor1); - cy_writeb((u_long)base_addr+(CyCOR2<cor2); - cy_writeb((u_long)base_addr+(CyCOR3<cor3); - cy_writeb((u_long)base_addr+(CyCOR4<cor4); - cy_writeb((u_long)base_addr+(CyCOR5<cor5); + cy_writeb(base_addr+(CyCOR1<cor1); + cy_writeb(base_addr+(CyCOR2<cor2); + cy_writeb(base_addr+(CyCOR3<cor3); + cy_writeb(base_addr+(CyCOR4<cor4); + cy_writeb(base_addr+(CyCOR5<cor5); cyy_issue_cmd(base_addr, CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index); - cy_writeb((u_long)base_addr+(CyCAR<default_timeout + cy_writeb(base_addr+(CyRTPR<default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ if (C_CLOCAL(info->tty)) { /* without modem intr */ - cy_writeb((u_long)base_addr+(CySRER<0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { - cy_writeb((u_long)base_addr+(CyMCOR1<1 modem transitions */ - cy_writeb((u_long)base_addr+(CyMCOR2<0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { - cy_writeb((u_long)base_addr+(CyMCOR1<1 modem transitions */ - cy_writeb((u_long)base_addr+(CyMCOR2<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; @@ -3617,7 +3578,7 @@ unsigned char status; unsigned int result; unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; card = info->card; channel = (info->line) - (cy_card[card].first_line); @@ -3625,8 +3586,7 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char *) - (cy_card[card].base_addr + (cy_chip_offset[chip]<driver_data; int card,chip,channel,index; - unsigned char *base_addr; + void __iomem *base_addr; unsigned long flags; unsigned char status; unsigned long lstatus; unsigned int result; - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; @@ -3663,12 +3623,10 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; lstatus = cy_readl(&ch_ctrl[channel].rs_status); @@ -3722,12 +3677,12 @@ { struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int card,chip,channel,index; - unsigned char *base_addr; + void __iomem *base_addr; unsigned long flags; - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; int retval; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) @@ -3739,37 +3694,35 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (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+(CyMSVR2<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; @@ -3930,7 +3880,7 @@ static int set_threshold(struct cyclades_port * info, unsigned long value) { - unsigned char *base_addr; + void __iomem *base_addr; int card,channel,chip,index; unsigned long flags; @@ -3940,15 +3890,13 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<cor3 &= ~CyREC_FIFO; info->cor3 |= value & CyREC_FIFO; CY_LOCK(info, flags); - cy_writeb((u_long)base_addr+(CyCOR3<cor3); + cy_writeb(base_addr+(CyCOR3<cor3); cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index); CY_UNLOCK(info, flags); } else { @@ -3961,7 +3909,7 @@ static int get_threshold(struct cyclades_port * info, unsigned long __user *value) { - unsigned char *base_addr; + void __iomem *base_addr; int card,channel,chip,index; unsigned long tmp; @@ -3971,9 +3919,7 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<driver_data; unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; #ifdef CY_DEBUG_THROTTLE @@ -4359,16 +4301,14 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<driver_data; unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; #ifdef CY_DEBUG_THROTTLE @@ -4419,16 +4359,14 @@ chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<driver_data; - unsigned char *base_addr; + void __iomem *base_addr; int chip,channel,index; unsigned long flags; @@ -4465,14 +4403,12 @@ index = cinfo->bus_index; chip = channel>>2; channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[info->card].base_addr - + (cy_chip_offset[chip]<card].base_addr + (cy_chip_offset[chip]<driver_data; - unsigned char *base_addr; + void __iomem *base_addr; int chip,channel,index; unsigned long flags; @@ -4505,14 +4441,12 @@ if (!IS_CYC_Z(*cinfo)) { chip = channel>>2; channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[info->card].base_addr - + (cy_chip_offset[chip]<card].base_addr + (cy_chip_offset[chip]<write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); } /* cy_flush_buffer */ @@ -4600,20 +4532,19 @@ /* initialize chips on Cyclom-Y card -- return number of valid chips (which is number of ports/4) */ static unsigned short __init -cyy_init_card(volatile ucchar *true_base_addr,int index) +cyy_init_card(void __iomem *true_base_addr,int index) { unsigned int chip_number; - volatile ucchar* base_addr; + void __iomem *base_addr; - cy_writeb((u_long)true_base_addr+(Cy_HwReset<= CD1400_REV_J){ /* It is a CD1400 rev. J or later */ /* Impossible to reach 5ms with this chip. Changed to 2ms instead (f = 500 Hz). */ - cy_writeb((u_long)base_addr+(CyPPR<mail_box_0); if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { @@ -5037,7 +4967,7 @@ } if (mailbox == ZE_V1) { - cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); + cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ze_win); if (ZeIndex == NR_CARDS) { printk("Cyclades-Ze/PCI found at 0x%lx ", (ulong)cy_pci_phys2); @@ -5055,7 +4985,7 @@ i--; continue; } else { - cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Zwin); + cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Zwin); } #ifdef CY_PCI_DEBUG @@ -5082,7 +5012,7 @@ */ PAUSE if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) - cy_writel((ulong)(cy_pci_addr2+ID_ADDRESS), 0L); + cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L); /* This must be a Cyclades-8Zo/PCI. The extendable version will have a different device_id and will @@ -5172,7 +5102,7 @@ Ze_pdev[j] = Ze_pdev[j+1]; } ZeIndex--; - mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) + mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *) cy_pci_addr0)->mail_box_0); #ifdef CY_PCI_DEBUG printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n", @@ -5413,7 +5343,7 @@ for (i = 0; i < NR_CARDS; i++) { /* base_addr=0 indicates board not found */ - cy_card[i].base_addr = 0; + cy_card[i].base_addr = NULL; } /* the code below is responsible to find the boards. Each different @@ -5435,7 +5365,7 @@ for (i = 0 ; i < NR_CARDS ; i++) { if (cy_card[i].base_addr == 0) { cy_card[i].first_line = -1; - cy_card[i].ctl_addr = 0; + cy_card[i].ctl_addr = NULL; cy_card[i].irq = 0; cy_card[i].bus_index = 0; cy_card[i].first_line = 0; @@ -5453,7 +5383,7 @@ cinfo = &cy_card[board]; if (cinfo->num_chips == -1) { /* Cyclades-Z */ number_z_boards++; - mailbox = cy_readl(&((struct RUNTIME_9060 *) + mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *) cy_card[board].ctl_addr)->mail_box_0); nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; cinfo->intr_enabled = 0; @@ -5623,10 +5553,10 @@ put_tty_driver(cy_serial_driver); for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr != 0) { - iounmap((void *)cy_card[i].base_addr); - if (cy_card[i].ctl_addr != 0) - iounmap((void *)cy_card[i].ctl_addr); + if (cy_card[i].base_addr) { + iounmap(cy_card[i].base_addr); + if (cy_card[i].ctl_addr) + iounmap(cy_card[i].ctl_addr); if (cy_card[i].irq #ifndef CONFIG_CYZ_INTR && cy_card[i].num_chips != -1 /* not a Z card */ diff -Nru a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig --- a/drivers/char/drm/Kconfig 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/drm/Kconfig 2004-10-18 14:56:50 -07:00 @@ -24,14 +24,14 @@ config DRM_GAMMA tristate "3dlabs GMX 2000" - depends on DRM + depends on DRM && BROKEN help This is the old gamma driver, please tell me if it might actually work. config DRM_R128 tristate "ATI Rage 128" - depends on DRM + depends on DRM && PCI help Choose this option if you have an ATI Rage 128 graphics card. If M is selected, the module will be called r128. AGP support for @@ -39,7 +39,7 @@ config DRM_RADEON tristate "ATI Radeon" - depends on DRM + depends on DRM && PCI help Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to @@ -55,14 +55,29 @@ selected, the module will be called i810. AGP support is required for this driver to work. -config DRM_I830 - tristate "Intel 830M, 845G, 852GM, 855GM, 865G" +choice + prompt "Intel 830M, 845G, 852GM, 855GM, 865G" depends on DRM && AGP && AGP_INTEL + optional + +config DRM_I830 + tristate "i830 driver" help Choose this option if you have a system that has Intel 830M, 845G, 852GM, 855GM or 865G integrated graphics. If M is selected, the module will be called i830. AGP support is required for this driver - to work. + to work. This driver will eventually be replaced by the i915 one. + +config DRM_I915 + tristate "i915 driver" + help + Choose this option if you have a system that has Intel 830M, 845G, + 852GM, 855GM 865G or 915G integrated graphics. If M is selected, the + module will be called i915. AGP support is required for this driver + to work. This driver will eventually replace the I830 driver, when + later release of X start to use the new DDX and DRI. + +endchoice config DRM_MGA tristate "Matrox g200/g400" diff -Nru a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile --- a/drivers/char/drm/Makefile 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/drm/Makefile 2004-10-18 14:57:04 -07:00 @@ -8,6 +8,7 @@ mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o ffb-objs := ffb_drv.o ffb_context.o sis-objs := sis_drv.o sis_ds.o sis_mm.o @@ -19,6 +20,7 @@ obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_I830) += i830.o +obj-$(CONFIG_DRM_I915) += i915.o obj-$(CONFIG_DRM_FFB) += ffb.o obj-$(CONFIG_DRM_SIS) += sis.o diff -Nru a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h --- a/drivers/char/drm/drmP.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/char/drm/drmP.h 2004-10-18 14:56:49 -07:00 @@ -73,42 +73,26 @@ #include #include "drm.h" -#include "drm_os_linux.h" +#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) +#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) +#include "drm_os_linux.h" /***********************************************************************/ /** \name DRM template customization defaults */ /*@{*/ -#ifndef __HAVE_AGP -#define __HAVE_AGP 0 -#endif -#ifndef __HAVE_MTRR -#define __HAVE_MTRR 0 -#endif -#ifndef __HAVE_CTX_BITMAP -#define __HAVE_CTX_BITMAP 0 -#endif -#ifndef __HAVE_DMA -#define __HAVE_DMA 0 -#endif -#ifndef __HAVE_IRQ -#define __HAVE_IRQ 0 -#endif -#ifndef __HAVE_DMA_WAITLIST -#define __HAVE_DMA_WAITLIST 0 -#endif -#ifndef __HAVE_DMA_FREELIST -#define __HAVE_DMA_FREELIST 0 -#endif - -#define __REALLY_HAVE_AGP (__HAVE_AGP && (defined(CONFIG_AGP) || \ - defined(CONFIG_AGP_MODULE))) -#define __REALLY_HAVE_MTRR (__HAVE_MTRR && defined(CONFIG_MTRR)) -#define __REALLY_HAVE_SG (__HAVE_SG) - -/*@}*/ - +/* driver capabilities and requirements mask */ +#define DRIVER_USE_AGP 0x1 +#define DRIVER_REQUIRE_AGP 0x2 +#define DRIVER_USE_MTRR 0x4 +#define DRIVER_PCI_DMA 0x8 +#define DRIVER_SG 0x10 +#define DRIVER_HAVE_DMA 0x20 +#define DRIVER_HAVE_IRQ 0x40 +#define DRIVER_IRQ_SHARED 0x80 +#define DRIVER_IRQ_VBL 0x100 +#define DRIVER_DMA_QUEUE 0x200 /***********************************************************************/ /** \name Begin the DRM... */ @@ -266,54 +250,6 @@ /***********************************************************************/ -/** \name Mapping helper macros */ -/*@{*/ - -#define DRM_IOREMAP(map, dev) \ - (map)->handle = DRM(ioremap)( (map)->offset, (map)->size, (dev) ) - -#define DRM_IOREMAP_NOCACHE(map, dev) \ - (map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size, (dev)) - -#define DRM_IOREMAPFREE(map, dev) \ - do { \ - if ( (map)->handle && (map)->size ) \ - DRM(ioremapfree)( (map)->handle, (map)->size, (dev) ); \ - } while (0) - -/** - * Find mapping. - * - * \param _map matching mapping if found, untouched otherwise. - * \param _o offset. - * - * Expects the existence of a local variable named \p dev pointing to the - * drm_device structure. - */ -#define DRM_FIND_MAP(_map, _o) \ -do { \ - struct list_head *_list; \ - list_for_each( _list, &dev->maplist->head ) { \ - drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); \ - if ( _entry->map && \ - _entry->map->offset == (_o) ) { \ - (_map) = _entry->map; \ - break; \ - } \ - } \ -} while(0) - -/** - * Drop mapping. - * - * \sa #DRM_FIND_MAP. - */ -#define DRM_DROP_MAP(_map) - -/*@}*/ - - -/***********************************************************************/ /** \name Internal types and structures */ /*@{*/ @@ -473,9 +409,7 @@ struct drm_device *dev; int remove_auth_on_close; unsigned long lock_count; -#ifdef DRIVER_FILE_FIELDS - DRIVER_FILE_FIELDS; -#endif + void *driver_priv; } drm_file_t; /** Wait queue */ @@ -524,16 +458,8 @@ _DRM_DMA_USE_SG = 0x02 } flags; - /** \name DMA support */ - /*@{*/ - drm_buf_t *this_buffer; /**< Buffer being sent */ - drm_buf_t *next_buffer; /**< Selected buffer to send */ - drm_queue_t *next_queue; /**< Queue from which buffer selected*/ - wait_queue_head_t waiting; /**< Processes waiting on free bufs */ - /*@}*/ } drm_device_dma_t; -#if __REALLY_HAVE_AGP /** * AGP memory entry. Stored as a doubly linked list. */ @@ -562,7 +488,6 @@ int cant_use_aperture; unsigned long page_mask; } drm_agp_head_t; -#endif /** * Scatter-gather memory. @@ -599,7 +524,6 @@ drm_file_t *tag; /**< associated fd private data */ } drm_ctx_list_t; -#ifdef __HAVE_VBL_IRQ typedef struct drm_vbl_sig { struct list_head head; @@ -608,8 +532,40 @@ struct task_struct *task; } drm_vbl_sig_t; -#endif +/** + * DRM device functions structure + */ +struct drm_device; + +struct drm_driver_fn { + int (*preinit)(struct drm_device *); + int (*postinit)(struct drm_device *); + void (*prerelease)(struct drm_device *, struct file *filp); + void (*pretakedown)(struct drm_device *); + int (*postcleanup)(struct drm_device *); + int (*presetup)(struct drm_device *); + int (*postsetup)(struct drm_device *); + int (*open_helper)(struct drm_device *, drm_file_t *); + void (*free_filp_priv)(struct drm_device *, drm_file_t *); + void (*release)(struct drm_device *, struct file *filp); + void (*dma_ready)(struct drm_device *); + int (*dma_quiescent)(struct drm_device *); + int (*context_ctor)(struct drm_device *dev, int context); + int (*context_dtor)(struct drm_device *dev, int context); + int (*kernel_context_switch)(struct drm_device *dev, int old, int new); + void (*kernel_context_switch_unlock)(struct drm_device *dev, drm_lock_t *lock); + int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence); + /* these have to be filled in */ + irqreturn_t (*irq_handler)( DRM_IRQ_ARGS ); + void (*irq_preinstall)(struct drm_device *dev); + void (*irq_postinstall)(struct drm_device *dev); + void (*irq_uninstall)(struct drm_device *dev); + void (*reclaim_buffers)(struct file *filp); + unsigned long (*get_map_ofs)(drm_map_t *map); + unsigned long (*get_reg_ofs)(struct drm_device *dev); + void (*set_version)(struct drm_device *dev, drm_set_version_t *sv); +}; /** * DRM device structure. */ @@ -698,13 +654,13 @@ struct work_struct work; /** \name VBLANK IRQ support */ /*@{*/ -#ifdef __HAVE_VBL_IRQ + wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ atomic_t vbl_received; spinlock_t vbl_lock; drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ unsigned int vbl_pending; -#endif + /*@}*/ cycles_t ctx_start; cycles_t lck_start; @@ -717,9 +673,7 @@ wait_queue_head_t buf_readers; /**< Processes waiting to read */ wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ -#if __REALLY_HAVE_AGP drm_agp_head_t *agp; /**< AGP data */ -#endif struct pci_dev *pdev; /**< PCI device structure */ int pci_domain; /**< PCI bus domain number */ @@ -738,8 +692,37 @@ void *dev_private; /**< device private data */ drm_sigdata_t sigdata; /**< For block_all_signals */ sigset_t sigmask; + + struct drm_driver_fn fn_tbl; + drm_local_map_t *agp_buffer_map; + int dev_priv_size; + u32 driver_features; } drm_device_t; +static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) +{ + return ((dev->driver_features & feature) ? 1 : 0); +} + +#if __OS_HAS_AGP +static inline int drm_core_has_AGP(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_AGP); +} +#else +#define drm_core_has_AGP(dev) (0) +#endif + +#if __OS_HAS_MTRR +static inline int drm_core_has_MTRR(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_MTRR); +} +#else +#define drm_core_has_MTRR(dev) (0) +#endif + +extern void DRM(driver_register_fns)(struct drm_device *dev); /******************************************************************/ /** \name Internal function definitions */ @@ -795,12 +778,10 @@ drm_device_t *dev); extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); -#if __REALLY_HAVE_AGP extern DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type); extern int DRM(free_agp)(DRM_AGP_MEM *handle, int pages); extern int DRM(bind_agp)(DRM_AGP_MEM *handle, unsigned int start); extern int DRM(unbind_agp)(DRM_AGP_MEM *handle); -#endif /* Misc. IOCTL support (drm_ioctl.h) */ extern int DRM(irq_by_busid)(struct inode *inode, struct file *filp, @@ -837,10 +818,8 @@ extern int DRM(context_switch)(drm_device_t *dev, int old, int new); extern int DRM(context_switch_complete)(drm_device_t *dev, int new); -#if __HAVE_CTX_BITMAP extern int DRM(ctxbitmap_init)( drm_device_t *dev ); extern void DRM(ctxbitmap_cleanup)( drm_device_t *dev ); -#endif extern int DRM(setsareactx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -884,7 +863,6 @@ unsigned int cmd, unsigned long arg ); extern int DRM(rmmap)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -#if __HAVE_DMA extern int DRM(addbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int DRM(infobufs)( struct inode *inode, struct file *filp, @@ -901,33 +879,22 @@ 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 ); -#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 ); -#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(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 ); -#ifdef __HAVE_VBL_IRQ + extern int DRM(wait_vblank)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); extern void DRM(vbl_send_signals)( drm_device_t *dev ); -#endif -#ifdef __HAVE_IRQ_BH -extern void DRM(irq_immediate_bh)( void *dev ); -#endif -#endif - -#if __REALLY_HAVE_AGP /* AGP/GART support (drm_agpsupport.h) */ extern drm_agp_head_t *DRM(agp_init)(void); extern void DRM(agp_uninit)(void); @@ -952,7 +919,6 @@ extern int DRM(agp_free_memory)(DRM_AGP_MEM *handle); extern int DRM(agp_bind_memory)(DRM_AGP_MEM *handle, off_t start); extern int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle); -#endif /* Stub support (drm_stub.h) */ int DRM(stub_register)(const char *name, @@ -969,14 +935,12 @@ struct proc_dir_entry *root, struct proc_dir_entry *dev_root); -#ifdef __HAVE_SG /* Scatter Gather Support (drm_scatter.h) */ extern void DRM(sg_cleanup)(drm_sg_mem_t *entry); extern int DRM(sg_alloc)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int DRM(sg_free)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -#endif /* ATI PCIGART support (ati_pcigart.h) */ extern int DRM(ati_pcigart_init)(drm_device_t *dev, @@ -986,7 +950,44 @@ unsigned long addr, dma_addr_t bus_addr); + +/* Inline replacements for DRM_IOREMAP macros */ +static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) +{ + map->handle = DRM(ioremap)( map->offset, map->size, dev ); +} + +static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) +{ + map->handle = DRM(ioremap_nocache)(map->offset, map->size, dev); +} + +static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) +{ + if ( map->handle && map->size ) + DRM(ioremapfree)( map->handle, map->size, dev ); +} + +static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset) +{ + struct list_head *_list; + list_for_each( _list, &dev->maplist->head ) { + drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); + if ( _entry->map && + _entry->map->offset == offset ) { + return _entry->map; + } + } + return NULL; +} + +static __inline__ void drm_core_dropmap(struct drm_map *map) +{ +} /*@}*/ + +extern unsigned long DRM(core_get_map_ofs)(drm_map_t *map); +extern unsigned long DRM(core_get_reg_ofs)(struct drm_device *dev); #endif /* __KERNEL__ */ #endif diff -Nru a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h --- a/drivers/char/drm/drm_agpsupport.h 2004-10-18 14:55:46 -07:00 +++ b/drivers/char/drm/drm_agpsupport.h 2004-10-18 14:55:46 -07:00 @@ -34,8 +34,7 @@ #include "drmP.h" #include -#if __REALLY_HAVE_AGP - +#if __OS_HAS_AGP #define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp") #define DRM_AGP_PUT inter_module_put("drm_agp") @@ -466,4 +465,4 @@ return drm_agp->unbind_memory(handle); } -#endif /* __REALLY_HAVE_AGP */ +#endif /* __OS_HAS_AGP */ diff -Nru a/drivers/char/drm/drm_bufs.h b/drivers/char/drm/drm_bufs.h --- a/drivers/char/drm/drm_bufs.h 2004-10-18 14:56:19 -07:00 +++ b/drivers/char/drm/drm_bufs.h 2004-10-18 14:56:19 -07:00 @@ -36,26 +36,6 @@ #include #include "drmP.h" -#ifndef __HAVE_PCI_DMA -#define __HAVE_PCI_DMA 0 -#endif - -#ifndef __HAVE_SG -#define __HAVE_SG 0 -#endif - -#ifndef DRIVER_BUF_PRIV_T -#define DRIVER_BUF_PRIV_T u32 -#endif -#ifndef DRIVER_AGP_BUFFERS_MAP -#if __HAVE_AGP && __HAVE_DMA -#error "You must define DRIVER_AGP_BUFFERS_MAP()" -#else -#define DRIVER_AGP_BUFFERS_MAP( dev ) NULL -#endif -#endif - - /** * Compute size order. Returns the exponent of the smaller power of two which * is greater or equal to given number. @@ -142,13 +122,13 @@ #ifdef __alpha__ map->offset += dev->hose->mem_space->start; #endif -#if __REALLY_HAVE_MTRR - if ( map->type == _DRM_FRAME_BUFFER || - (map->flags & _DRM_WRITE_COMBINING) ) { - map->mtrr = mtrr_add( map->offset, map->size, - MTRR_TYPE_WRCOMB, 1 ); + if (drm_core_has_MTRR(dev)) { + if ( map->type == _DRM_FRAME_BUFFER || + (map->flags & _DRM_WRITE_COMBINING) ) { + map->mtrr = mtrr_add( map->offset, map->size, + MTRR_TYPE_WRCOMB, 1 ); + } } -#endif if (map->type == _DRM_REGISTERS) map->handle = DRM(ioremap)( map->offset, map->size, dev ); @@ -174,15 +154,15 @@ dev->lock.hw_lock = map->handle; /* Pointer to lock */ } break; -#if __REALLY_HAVE_AGP case _DRM_AGP: + if (drm_core_has_AGP(dev)) { #ifdef __alpha__ - map->offset += dev->hose->mem_space->start; + map->offset += dev->hose->mem_space->start; #endif - map->offset += dev->agp->base; - map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + map->offset += dev->agp->base; + map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + } break; -#endif case _DRM_SCATTER_GATHER: if (!dev->sg) { DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); @@ -282,15 +262,15 @@ switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if __REALLY_HAVE_MTRR - if (map->mtrr >= 0) { - int retcode; - retcode = mtrr_del(map->mtrr, - map->offset, - map->size); - DRM_DEBUG("mtrr_del = %d\n", retcode); + if (drm_core_has_MTRR(dev)) { + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } } -#endif DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: @@ -306,8 +286,6 @@ return 0; } -#if __HAVE_DMA - /** * Cleanup after an error on one of the addbufs() functions. * @@ -348,15 +326,11 @@ sizeof(*entry->buflist), DRM_MEM_BUFS); -#if __HAVE_DMA_FREELIST - DRM(freelist_destroy)(&entry->freelist); -#endif - entry->buf_count = 0; } } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP /** * Add AGP buffers for DMA transfers (ioctl). * @@ -473,8 +447,8 @@ init_waitqueue_head( &buf->dma_wait ); buf->filp = NULL; - buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); - buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = DRM(alloc)( buf->dev_priv_size, DRM_MEM_BUFS ); if(!buf->dev_private) { /* Set count correctly so we free the proper amount. */ @@ -520,12 +494,6 @@ DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); -#if __HAVE_DMA_FREELIST - DRM(freelist_create)( &entry->freelist, entry->buf_count ); - for ( i = 0 ; i < entry->buf_count ; i++ ) { - DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); - } -#endif up( &dev->struct_sem ); request.count = entry->buf_count; @@ -539,9 +507,8 @@ atomic_dec( &dev->buf_alloc ); return 0; } -#endif /* __REALLY_HAVE_AGP */ +#endif /* __OS_HAS_AGP */ -#if __HAVE_PCI_DMA int DRM(addbufs_pci)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -566,6 +533,7 @@ drm_buf_t **temp_buflist; drm_buf_desc_t __user *argp = (void __user *)arg; + if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) return -EINVAL; if ( !dma ) return -EINVAL; if ( copy_from_user( &request, argp, sizeof(request) ) ) @@ -697,8 +665,8 @@ init_waitqueue_head( &buf->dma_wait ); buf->filp = NULL; - buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); - buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = DRM(alloc)( dev->dev_priv_size, DRM_MEM_BUFS ); if(!buf->dev_private) { /* Set count correctly so we free the proper amount. */ @@ -758,12 +726,6 @@ dma->page_count += entry->seg_count << page_order; dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); -#if __HAVE_DMA_FREELIST - DRM(freelist_create)( &entry->freelist, entry->buf_count ); - for ( i = 0 ; i < entry->buf_count ; i++ ) { - DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); - } -#endif up( &dev->struct_sem ); request.count = entry->buf_count; @@ -776,9 +738,7 @@ return 0; } -#endif /* __HAVE_PCI_DMA */ -#if __HAVE_SG int DRM(addbufs_sg)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -801,6 +761,8 @@ int i; drm_buf_t **temp_buflist; + if (!drm_core_check_feature(dev, DRIVER_SG)) return -EINVAL; + if ( !dma ) return -EINVAL; if ( copy_from_user( &request, argp, sizeof(request) ) ) @@ -881,8 +843,8 @@ init_waitqueue_head( &buf->dma_wait ); buf->filp = NULL; - buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); - buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = DRM(alloc)( dev->dev_priv_size, DRM_MEM_BUFS ); if(!buf->dev_private) { /* Set count correctly so we free the proper amount. */ @@ -929,12 +891,6 @@ DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); -#if __HAVE_DMA_FREELIST - DRM(freelist_create)( &entry->freelist, entry->buf_count ); - for ( i = 0 ; i < entry->buf_count ; i++ ) { - DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); - } -#endif up( &dev->struct_sem ); request.count = entry->buf_count; @@ -948,7 +904,6 @@ atomic_dec( &dev->buf_alloc ); return 0; } -#endif /* __HAVE_SG */ /** * Add buffers for DMA transfers (ioctl). @@ -968,26 +923,25 @@ unsigned int cmd, unsigned long arg ) { drm_buf_desc_t request; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; if ( copy_from_user( &request, (drm_buf_desc_t __user *)arg, sizeof(request) ) ) return -EFAULT; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( request.flags & _DRM_AGP_BUFFER ) return DRM(addbufs_agp)( inode, filp, cmd, arg ); else #endif -#if __HAVE_SG if ( request.flags & _DRM_SG_BUFFER ) return DRM(addbufs_sg)( inode, filp, cmd, arg ); else -#endif -#if __HAVE_PCI_DMA return DRM(addbufs_pci)( inode, filp, cmd, arg ); -#else - return -EINVAL; -#endif } @@ -1019,6 +973,9 @@ int i; int count; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; spin_lock( &dev->count_lock ); @@ -1100,6 +1057,9 @@ int order; drm_buf_entry_t *entry; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; if ( copy_from_user( &request, @@ -1147,6 +1107,9 @@ int idx; drm_buf_t *buf; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; if ( copy_from_user( &request, @@ -1204,6 +1167,9 @@ drm_buf_map_t request; int i; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; spin_lock( &dev->count_lock ); @@ -1218,9 +1184,9 @@ return -EFAULT; if ( request.count >= dma->buf_count ) { - if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) || - (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) { - drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev ); + if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || + (drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG)) ) { + drm_map_t *map = dev->agp_buffer_map; if ( !map ) { retcode = -EINVAL; @@ -1301,4 +1267,3 @@ return retcode; } -#endif /* __HAVE_DMA */ diff -Nru a/drivers/char/drm/drm_context.h b/drivers/char/drm/drm_context.h --- a/drivers/char/drm/drm_context.h 2004-10-18 14:55:46 -07:00 +++ b/drivers/char/drm/drm_context.h 2004-10-18 14:55:46 -07:00 @@ -42,11 +42,6 @@ #include "drmP.h" -#if !__HAVE_CTX_BITMAP -#error "__HAVE_CTX_BITMAP must be defined" -#endif - - /******************************************************************/ /** \name Context bitmap support */ /*@{*/ @@ -419,10 +414,13 @@ /* Should this return -EBUSY instead? */ return -ENOMEM; } -#ifdef DRIVER_CTX_CTOR + if ( ctx.handle != DRM_KERNEL_CONTEXT ) - DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */ -#endif + { + if (dev->fn_tbl.context_ctor) + dev->fn_tbl.context_ctor(dev, ctx.handle); + } + ctx_entry = DRM(alloc)( sizeof(*ctx_entry), DRM_MEM_CTXLIST ); if ( !ctx_entry ) { DRM_DEBUG("out of memory\n"); @@ -554,9 +552,8 @@ priv->remove_auth_on_close = 1; } if ( ctx.handle != DRM_KERNEL_CONTEXT ) { -#ifdef DRIVER_CTX_DTOR - DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */ -#endif + if (dev->fn_tbl.context_dtor) + dev->fn_tbl.context_dtor(dev, ctx.handle); DRM(ctxbitmap_free)( dev, ctx.handle ); } @@ -578,3 +575,4 @@ } /*@}*/ + diff -Nru a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/drm_core.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,40 @@ +/* + * Copyright 2004 Jon Smirl + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "drm_auth.h" +#include "drm_agpsupport.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_irq.h" +#include "drm_drawable.h" +#include "drm_drv.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" +#include "drm_scatter.h" diff -Nru a/drivers/char/drm/drm_dma.h b/drivers/char/drm/drm_dma.h --- a/drivers/char/drm/drm_dma.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/drm/drm_dma.h 2004-10-18 14:56:33 -07:00 @@ -35,16 +35,6 @@ #include "drmP.h" - -#ifndef __HAVE_DMA_WAITQUEUE -#define __HAVE_DMA_WAITQUEUE 0 -#endif -#ifndef __HAVE_DMA_RECLAIM -#define __HAVE_DMA_RECLAIM 0 -#endif - -#if __HAVE_DMA - /** * Initialize the DMA data. * @@ -116,9 +106,6 @@ dma->bufs[i].buf_count * sizeof(*dma->bufs[0].buflist), DRM_MEM_BUFS); -#if __HAVE_DMA_FREELIST - DRM(freelist_destroy)(&dma->bufs[i].freelist); -#endif } } @@ -155,22 +142,11 @@ buf->filp = NULL; buf->used = 0; - if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) { + if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && waitqueue_active(&buf->dma_wait)) { wake_up_interruptible(&buf->dma_wait); } -#if __HAVE_DMA_FREELIST - else { - drm_device_dma_t *dma = dev->dma; - /* If processes are waiting, the last one - to wake will put the buffer on the free - list. If no processes are waiting, we - put the buffer on the freelist here. */ - DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf); - } -#endif } -#if !__HAVE_DMA_RECLAIM /** * Reclaim the buffers. * @@ -178,7 +154,7 @@ * * Frees each buffer associated with \p filp not already on the hardware. */ -void DRM(reclaim_buffers)( struct file *filp ) +void DRM(core_reclaim_buffers)( struct file *filp ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -202,29 +178,4 @@ } } } -#endif - -#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. - */ -int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_control_t ctl; - - if ( copy_from_user( &ctl, (drm_control_t __user *)arg, sizeof(ctl) ) ) - return -EFAULT; - - switch ( ctl.func ) { - case DRM_INST_HANDLER: - case DRM_UNINST_HANDLER: - return 0; - default: - return -EINVAL; - } -} -#endif -#endif /* __HAVE_DMA */ diff -Nru a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h --- a/drivers/char/drm/drm_drv.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/char/drm/drm_drv.h 2004-10-18 14:56:49 -07:00 @@ -52,97 +52,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef __MUST_HAVE_AGP -#define __MUST_HAVE_AGP 0 -#endif -#ifndef __HAVE_CTX_BITMAP -#define __HAVE_CTX_BITMAP 0 -#endif -#ifndef __HAVE_IRQ -#define __HAVE_IRQ 0 -#endif -#ifndef __HAVE_DMA_QUEUE -#define __HAVE_DMA_QUEUE 0 -#endif -#ifndef __HAVE_MULTIPLE_DMA_QUEUES -#define __HAVE_MULTIPLE_DMA_QUEUES 0 -#endif -#ifndef __HAVE_DMA_SCHEDULE -#define __HAVE_DMA_SCHEDULE 0 -#endif -#ifndef __HAVE_DMA_FLUSH -#define __HAVE_DMA_FLUSH 0 -#endif -#ifndef __HAVE_DMA_READY -#define __HAVE_DMA_READY 0 -#endif -#ifndef __HAVE_DMA_QUIESCENT -#define __HAVE_DMA_QUIESCENT 0 -#endif -#ifndef __HAVE_RELEASE -#define __HAVE_RELEASE 0 -#endif -#ifndef __HAVE_COUNTERS -#define __HAVE_COUNTERS 0 -#endif -#ifndef __HAVE_SG -#define __HAVE_SG 0 -#endif -/* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the drm modules in - * the DRI cvs tree, but it is required by the kernel tree's sparc - * driver. - */ -#ifndef __HAVE_KERNEL_CTX_SWITCH -#define __HAVE_KERNEL_CTX_SWITCH 0 -#endif -#ifndef __HAVE_DRIVER_FOPS_READ -#define __HAVE_DRIVER_FOPS_READ 0 -#endif -#ifndef __HAVE_DRIVER_FOPS_POLL -#define __HAVE_DRIVER_FOPS_POLL 0 -#endif - -#ifndef DRIVER_PREINIT -#define DRIVER_PREINIT() -#endif -#ifndef DRIVER_POSTINIT -#define DRIVER_POSTINIT() -#endif -#ifndef DRIVER_PRERELEASE -#define DRIVER_PRERELEASE() -#endif -#ifndef DRIVER_PRETAKEDOWN -#define DRIVER_PRETAKEDOWN() -#endif -#ifndef DRIVER_POSTCLEANUP -#define DRIVER_POSTCLEANUP() -#endif -#ifndef DRIVER_PRESETUP -#define DRIVER_PRESETUP() -#endif -#ifndef DRIVER_POSTSETUP -#define DRIVER_POSTSETUP() -#endif #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) = { \ - .owner = THIS_MODULE, \ - .open = DRM(open), \ - .flush = DRM(flush), \ - .release = DRM(release), \ - .ioctl = DRM(ioctl), \ - .mmap = DRM(mmap), \ - .fasync = DRM(fasync), \ - .poll = DRM(poll), \ - .read = DRM(read), \ -} -#endif #ifndef MODULE /** Use an additional macro to avoid preprocessor troubles */ @@ -166,16 +78,24 @@ static drm_device_t DRM(device)[MAX_DEVICES]; static int DRM(numdevs) = 0; -DRIVER_FOPS; +struct file_operations DRM(fops) = { + .owner = THIS_MODULE, + .open = DRM(open), + .flush = DRM(flush), + .release = DRM(release), + .ioctl = DRM(ioctl), + .mmap = DRM(mmap), + .fasync = DRM(fasync), + .poll = DRM(poll), + .read = DRM(read), +}; /** Ioctl table */ -static drm_ioctl_desc_t DRM(ioctls)[] = { +drm_ioctl_desc_t DRM(ioctls)[] = { [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 }, -#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 }, @@ -189,10 +109,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 }, -#if __HAVE_CTX_BITMAP [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 }, -#endif [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { DRM(addctx), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 }, @@ -208,26 +126,18 @@ [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 }, -#if __HAVE_DMA_FLUSH - /* Gamma only, really */ - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 }, -#else [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(noop), 1, 0 }, -#endif -#if __HAVE_DMA [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, /* 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 -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, @@ -238,14 +148,10 @@ [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, #endif -#if __HAVE_SG [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 }, -#endif -#ifdef __HAVE_VBL_IRQ [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank), 0, 0 }, -#endif DRIVER_IOCTLS }; @@ -264,56 +170,26 @@ static int DRM(setup)( drm_device_t *dev ) { int i; + int ret; + + if (dev->fn_tbl.presetup) + { + ret=dev->fn_tbl.presetup(dev); + if (ret!=0) + return ret; + } - DRIVER_PRESETUP(); atomic_set( &dev->ioctl_count, 0 ); atomic_set( &dev->vma_count, 0 ); dev->buf_use = 0; atomic_set( &dev->buf_alloc, 0 ); -#if __HAVE_DMA - i = DRM(dma_setup)( dev ); - if ( i < 0 ) - return i; -#endif - - dev->counters = 6 + __HAVE_COUNTERS; - dev->types[0] = _DRM_STAT_LOCK; - dev->types[1] = _DRM_STAT_OPENS; - dev->types[2] = _DRM_STAT_CLOSES; - dev->types[3] = _DRM_STAT_IOCTLS; - dev->types[4] = _DRM_STAT_LOCKS; - dev->types[5] = _DRM_STAT_UNLOCKS; -#ifdef __HAVE_COUNTER6 - dev->types[6] = __HAVE_COUNTER6; -#endif -#ifdef __HAVE_COUNTER7 - dev->types[7] = __HAVE_COUNTER7; -#endif -#ifdef __HAVE_COUNTER8 - dev->types[8] = __HAVE_COUNTER8; -#endif -#ifdef __HAVE_COUNTER9 - dev->types[9] = __HAVE_COUNTER9; -#endif -#ifdef __HAVE_COUNTER10 - dev->types[10] = __HAVE_COUNTER10; -#endif -#ifdef __HAVE_COUNTER11 - dev->types[11] = __HAVE_COUNTER11; -#endif -#ifdef __HAVE_COUNTER12 - dev->types[12] = __HAVE_COUNTER12; -#endif -#ifdef __HAVE_COUNTER13 - dev->types[13] = __HAVE_COUNTER13; -#endif -#ifdef __HAVE_COUNTER14 - dev->types[14] = __HAVE_COUNTER14; -#endif -#ifdef __HAVE_COUNTER15 - dev->types[14] = __HAVE_COUNTER14; -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + { + i = DRM(dma_setup)( dev ); + if ( i < 0 ) + return i; + } for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ ) atomic_set( &dev->counts[i], 0 ); @@ -371,7 +247,9 @@ * drm_select_queue fails between the time the interrupt is * initialized and the time the queues are initialized. */ - DRIVER_POSTSETUP(); + if (dev->fn_tbl.postsetup) + dev->fn_tbl.postsetup(dev); + return 0; } @@ -396,10 +274,10 @@ DRM_DEBUG( "\n" ); - DRIVER_PRETAKEDOWN(); -#if __HAVE_IRQ + if (dev->fn_tbl.pretakedown) + dev->fn_tbl.pretakedown(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)( dev ); -#endif down( &dev->struct_sem ); del_timer( &dev->timer ); @@ -425,9 +303,8 @@ dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } -#if __REALLY_HAVE_AGP /* Clear AGP information */ - if ( dev->agp ) { + if (drm_core_has_AGP(dev) && dev->agp) { drm_agp_mem_t *entry; drm_agp_mem_t *nexte; @@ -446,7 +323,6 @@ dev->agp->acquired = 0; dev->agp->enabled = 0; } -#endif /* Clear vma list (only built for debugging) */ if ( dev->vmalist ) { @@ -465,15 +341,15 @@ switch ( map->type ) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if __REALLY_HAVE_MTRR - if ( map->mtrr >= 0 ) { - int retcode; - retcode = mtrr_del( map->mtrr, - map->offset, - map->size ); - DRM_DEBUG( "mtrr_del=%d\n", retcode ); + if (drm_core_has_MTRR(dev)) { + if ( map->mtrr >= 0 ) { + int retcode; + retcode = mtrr_del( map->mtrr, + map->offset, + map->size ); + DRM_DEBUG( "mtrr_del=%d\n", retcode ); + } } -#endif DRM(ioremapfree)( map->handle, map->size, dev ); break; case _DRM_SHM: @@ -486,15 +362,11 @@ */ break; case _DRM_SCATTER_GATHER: - /* Handle it, but do nothing, if HAVE_SG - * isn't defined. - */ -#if __HAVE_SG - if(dev->sg) { + /* Handle it */ + if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) { DRM(sg_cleanup)(dev->sg); dev->sg = NULL; } -#endif break; } DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); @@ -506,12 +378,8 @@ dev->maplist = NULL; } -#if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES - if ( dev->queuelist ) { + if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist ) { for ( i = 0 ; i < dev->queue_count ; i++ ) { -#if __HAVE_DMA_WAITLIST - DRM(waitlist_destroy)( &dev->queuelist[i]->waitlist ); -#endif if ( dev->queuelist[i] ) { DRM(free)( dev->queuelist[i], sizeof(*dev->queuelist[0]), @@ -525,11 +393,10 @@ dev->queuelist = NULL; } dev->queue_count = 0; -#endif -#if __HAVE_DMA - DRM(dma_takedown)( dev ); -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + DRM(dma_takedown)( dev ); + if ( dev->lock.hw_lock ) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ dev->lock.filp = NULL; @@ -540,6 +407,13 @@ return 0; } +static void DRM(init_fn_table)(struct drm_device *dev) +{ + dev->fn_tbl.reclaim_buffers = DRM(core_reclaim_buffers); + dev->fn_tbl.get_map_ofs = DRM(core_get_map_ofs); + dev->fn_tbl.get_reg_ofs = DRM(core_get_reg_ofs); +} + #include "drm_pciids.h" static struct pci_device_id DRM(pciidlist)[] = { @@ -549,9 +423,7 @@ static int DRM(probe)(struct pci_dev *pdev) { drm_device_t *dev; -#if __HAVE_CTX_BITMAP int retcode; -#endif int i; int is_compat = 0; @@ -569,6 +441,9 @@ if (DRM(numdevs) >= MAX_DEVICES) return -ENODEV; + if ((retcode=pci_enable_device(pdev))) + return retcode; + dev = &(DRM(device)[DRM(numdevs)]); memset( (void *)dev, 0, sizeof(*dev) ); @@ -594,36 +469,51 @@ dev->pci_func = PCI_FUNC(pdev->devfn); dev->irq = pdev->irq; - DRIVER_PREINIT(); + /* dev_priv_size can be changed by a driver in driver_register_fns */ + dev->dev_priv_size = sizeof(u32); -#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 -EINVAL; + /* the DRM has 6 basic counters - drivers add theirs in register_fns */ + dev->counters = 6; + dev->types[0] = _DRM_STAT_LOCK; + dev->types[1] = _DRM_STAT_OPENS; + dev->types[2] = _DRM_STAT_CLOSES; + dev->types[3] = _DRM_STAT_IOCTLS; + dev->types[4] = _DRM_STAT_LOCKS; + dev->types[5] = _DRM_STAT_UNLOCKS; + + DRM(init_fn_table)(dev); + + DRM(driver_register_fns)(dev); + + if (dev->fn_tbl.preinit) + dev->fn_tbl.preinit(dev); + + if (drm_core_has_AGP(dev)) + { + dev->agp = DRM(agp_init)(); + if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) { + DRM_ERROR( "Cannot initialize the agpgart module.\n" ); + DRM(stub_unregister)(dev->minor); + DRM(takedown)( dev ); + return -EINVAL; + } + if (drm_core_has_MTRR(dev)) { + 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 -#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(numdevs)++; /* no errors, mark it reserved */ DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n", @@ -635,7 +525,8 @@ dev->minor, pci_pretty_name(pdev)); - DRIVER_POSTINIT(); + if (dev->fn_tbl.postinit) + dev->fn_tbl.postinit(dev); return 0; } @@ -695,31 +586,30 @@ DRM_INFO( "Module unloaded\n" ); } } -#if __HAVE_CTX_BITMAP + DRM(ctxbitmap_cleanup)( dev ); -#endif -#if __REALLY_HAVE_AGP && __REALLY_HAVE_MTRR - if ( dev->agp && dev->agp->agp_mtrr >= 0) { + if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && + dev->agp && dev->agp->agp_mtrr >= 0) { int retval; retval = mtrr_del( dev->agp->agp_mtrr, dev->agp->agp_info.aper_base, dev->agp->agp_info.aper_size*1024*1024 ); DRM_DEBUG( "mtrr_del=%d\n", retval ); } -#endif DRM(takedown)( dev ); -#if __REALLY_HAVE_AGP - if ( dev->agp ) { + if (drm_core_has_AGP(dev) && dev->agp ) { DRM(agp_uninit)(); DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); dev->agp = NULL; } -#endif + + if (dev->fn_tbl.postcleanup) + dev->fn_tbl.postcleanup(dev); + } - DRIVER_POSTCLEANUP(); DRM(numdevs) = 0; } @@ -834,7 +724,8 @@ DRM_DEBUG( "open_count = %d\n", dev->open_count ); - DRIVER_PRERELEASE(); + if (dev->fn_tbl.prerelease) + dev->fn_tbl.prerelease(dev, filp); /* ======================================================== * Begin inline drm_release @@ -849,9 +740,10 @@ DRM_DEBUG( "File %p released, freeing lock for context %d\n", filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); -#if __HAVE_RELEASE - DRIVER_RELEASE(); -#endif + + if (dev->fn_tbl.release) + dev->fn_tbl.release(dev, filp); + DRM(lock_free)( dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); @@ -860,14 +752,13 @@ processed via a callback to the X server. */ } -#if __HAVE_RELEASE - else if ( priv->lock_count && dev->lock.hw_lock ) { + else if ( dev->fn_tbl.release && priv->lock_count && dev->lock.hw_lock ) { /* The lock is required to reclaim buffers */ DECLARE_WAITQUEUE( entry, current ); add_wait_queue( &dev->lock.lock_queue, &entry ); for (;;) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); if ( !dev->lock.hw_lock ) { /* Device has been unregistered */ retcode = -EINTR; @@ -887,17 +778,20 @@ break; } } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue( &dev->lock.lock_queue, &entry ); if( !retcode ) { - DRIVER_RELEASE(); + if (dev->fn_tbl.release) + dev->fn_tbl.release(dev, filp); DRM(lock_free)( dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT ); } } -#elif __HAVE_DMA - DRM(reclaim_buffers)( filp ); -#endif + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + { + dev->fn_tbl.reclaim_buffers(filp); + } DRM(fasync)( -1, filp, 0 ); @@ -908,14 +802,14 @@ list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) { if ( pos->tag == priv && pos->handle != DRM_KERNEL_CONTEXT ) { -#ifdef DRIVER_CTX_DTOR - DRIVER_CTX_DTOR(pos->handle); -#endif -#if __HAVE_CTX_BITMAP + if (dev->fn_tbl.context_dtor) + dev->fn_tbl.context_dtor(dev, pos->handle); + DRM(ctxbitmap_free)( dev, pos->handle ); -#endif + list_del( &pos->head ); DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST ); + --dev->ctx_count; } } } @@ -941,6 +835,9 @@ } up( &dev->struct_sem ); + if (dev->fn_tbl.free_filp_priv) + dev->fn_tbl.free_filp_priv(dev, priv); + DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES ); /* ======================================================== @@ -1039,9 +936,6 @@ DECLARE_WAITQUEUE( entry, current ); drm_lock_t lock; int ret = 0; -#if __HAVE_MULTIPLE_DMA_QUEUES - drm_queue_t *q; -#endif ++priv->lock_count; @@ -1058,83 +952,61 @@ lock.context, current->pid, dev->lock.hw_lock->lock, lock.flags ); -#if __HAVE_DMA_QUEUE - if ( lock.context < 0 ) - return -EINVAL; -#elif __HAVE_MULTIPLE_DMA_QUEUES - if ( lock.context < 0 || lock.context >= dev->queue_count ) - return -EINVAL; - q = dev->queuelist[lock.context]; -#endif - -#if __HAVE_DMA_FLUSH - ret = DRM(flush_block_and_flush)( dev, lock.context, lock.flags ); -#endif - if ( !ret ) { - add_wait_queue( &dev->lock.lock_queue, &entry ); - for (;;) { - current->state = TASK_INTERRUPTIBLE; - if ( !dev->lock.hw_lock ) { - /* Device has been unregistered */ - ret = -EINTR; - break; - } - if ( DRM(lock_take)( &dev->lock.hw_lock->lock, - lock.context ) ) { - dev->lock.filp = filp; - dev->lock.lock_time = jiffies; - atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); - break; /* Got lock */ - } - - /* Contention */ - schedule(); - if ( signal_pending( current ) ) { - ret = -ERESTARTSYS; - break; - } - } - current->state = TASK_RUNNING; - remove_wait_queue( &dev->lock.lock_queue, &entry ); - } - -#if __HAVE_DMA_FLUSH - DRM(flush_unblock)( dev, lock.context, lock.flags ); /* cleanup phase */ -#endif - - if ( !ret ) { - sigemptyset( &dev->sigmask ); - sigaddset( &dev->sigmask, SIGSTOP ); - sigaddset( &dev->sigmask, SIGTSTP ); - sigaddset( &dev->sigmask, SIGTTIN ); - sigaddset( &dev->sigmask, SIGTTOU ); - dev->sigdata.context = lock.context; - dev->sigdata.lock = dev->lock.hw_lock; - block_all_signals( DRM(notifier), - &dev->sigdata, &dev->sigmask ); - -#if __HAVE_DMA_READY - if ( lock.flags & _DRM_LOCK_READY ) { - DRIVER_DMA_READY(); - } -#endif -#if __HAVE_DMA_QUIESCENT - if ( lock.flags & _DRM_LOCK_QUIESCENT ) { - DRIVER_DMA_QUIESCENT(); + if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) + if ( lock.context < 0 ) + return -EINVAL; + + add_wait_queue( &dev->lock.lock_queue, &entry ); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + if ( !dev->lock.hw_lock ) { + /* Device has been unregistered */ + ret = -EINTR; + break; } -#endif - /* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the - * drm modules in the DRI cvs tree, but it is required - * by the Sparc driver. - */ -#if __HAVE_KERNEL_CTX_SWITCH - if ( dev->last_context != lock.context ) { - DRM(context_switch)(dev, dev->last_context, - lock.context); + if ( DRM(lock_take)( &dev->lock.hw_lock->lock, + lock.context ) ) { + dev->lock.filp = filp; + dev->lock.lock_time = jiffies; + atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); + break; /* Got lock */ + } + + /* Contention */ + schedule(); + if ( signal_pending( current ) ) { + ret = -ERESTARTSYS; + break; } -#endif - } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue( &dev->lock.lock_queue, &entry ); + sigemptyset( &dev->sigmask ); + sigaddset( &dev->sigmask, SIGSTOP ); + sigaddset( &dev->sigmask, SIGTSTP ); + sigaddset( &dev->sigmask, SIGTTIN ); + sigaddset( &dev->sigmask, SIGTTOU ); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals( DRM(notifier), + &dev->sigdata, &dev->sigmask ); + + if (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY)) + dev->fn_tbl.dma_ready(dev); + + if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) + return dev->fn_tbl.dma_quiescent(dev); + + /* dev->fn_tbl.kernel_context_switch isn't used by any of the x86 + * drivers but is used by the Sparc driver. + */ + + if (dev->fn_tbl.kernel_context_switch && + dev->last_context != lock.context) { + dev->fn_tbl.kernel_context_switch(dev, dev->last_context, + lock.context); + } DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); return ret; @@ -1169,40 +1041,20 @@ atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] ); - /* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the drm - * modules in the DRI cvs tree, but it is required by the - * Sparc driver. - */ -#if __HAVE_KERNEL_CTX_SWITCH - /* We no longer really hold it, but if we are the next - * agent to request it then we should just be able to - * take it immediately and not eat the ioctl. + /* kernel_context_switch isn't used by any of the x86 drm + * modules but is required by the Sparc driver. */ - dev->lock.filp = NULL; - { - __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; - unsigned int old, new, prev, ctx; - - ctx = lock.context; - do { - old = *plock; - new = ctx; - prev = cmpxchg(plock, old, new); - } while (prev != old); - } - wake_up_interruptible(&dev->lock.lock_queue); -#else - DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT ); -#if __HAVE_DMA_SCHEDULE - DRM(dma_schedule)( dev, 1 ); -#endif - - if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT ) ) { - DRM_ERROR( "\n" ); + if (dev->fn_tbl.kernel_context_switch_unlock) + dev->fn_tbl.kernel_context_switch_unlock(dev, &lock); + else { + DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT ); + + if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT ) ) { + DRM_ERROR( "\n" ); + } } -#endif /* !__HAVE_KERNEL_CTX_SWITCH */ unblock_all_signals(); return 0; diff -Nru a/drivers/char/drm/drm_fops.h b/drivers/char/drm/drm_fops.h --- a/drivers/char/drm/drm_fops.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/drm/drm_fops.h 2004-10-18 14:56:32 -07:00 @@ -53,6 +53,7 @@ { int minor = iminor(inode); drm_file_t *priv; + int ret; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ if (!DRM(cpu_valid)()) return -EINVAL; @@ -72,7 +73,11 @@ priv->authenticated = capable(CAP_SYS_ADMIN); priv->lock_count = 0; - DRIVER_OPEN_HELPER( priv, dev ); + if (dev->fn_tbl.open_helper) { + ret=dev->fn_tbl.open_helper(dev, priv); + if (ret < 0) + goto out_free; + } down(&dev->struct_sem); if (!dev->file_last) { @@ -104,6 +109,10 @@ #endif return 0; +out_free: + DRM(free)(priv, sizeof(*priv), DRM_MEM_FILES); + filp->private_data=NULL; + return ret; } /** No-op. */ @@ -130,19 +139,15 @@ return 0; } -#if !__HAVE_DRIVER_FOPS_POLL /** No-op. */ unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) { return 0; } -#endif -#if !__HAVE_DRIVER_FOPS_READ /** No-op. */ ssize_t DRM(read)(struct file *filp, char __user *buf, size_t count, loff_t *off) { return 0; } -#endif diff -Nru a/drivers/char/drm/drm_ioctl.h b/drivers/char/drm/drm_ioctl.h --- a/drivers/char/drm/drm_ioctl.h 2004-10-18 14:56:20 -07:00 +++ b/drivers/char/drm/drm_ioctl.h 2004-10-18 14:56:20 -07:00 @@ -341,9 +341,9 @@ 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 + + if (dev->fn_tbl.set_version) + dev->fn_tbl.set_version(dev, &sv); } return 0; } diff -Nru a/drivers/char/drm/drm_irq.h b/drivers/char/drm/drm_irq.h --- a/drivers/char/drm/drm_irq.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/drm/drm_irq.h 2004-10-18 14:56:33 -07:00 @@ -37,16 +37,6 @@ #include /* For task queue support */ -#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 - /** * Get interrupt from bus id. * @@ -68,6 +58,9 @@ drm_irq_busid_t __user *argp = (void __user *)arg; drm_irq_busid_t p; + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + if (copy_from_user(&p, argp, sizeof(p))) return -EFAULT; @@ -86,8 +79,6 @@ return 0; } -#if __HAVE_IRQ - /** * Install IRQ handler. * @@ -101,7 +92,11 @@ int DRM(irq_install)( drm_device_t *dev ) { int ret; - + unsigned long sh_flags=0; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + if ( dev->irq == 0 ) return -EINVAL; @@ -122,32 +117,25 @@ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); -#if __HAVE_DMA - dev->dma->next_buffer = NULL; - dev->dma->next_queue = NULL; - dev->dma->this_buffer = NULL; -#endif - -#ifdef __HAVE_IRQ_BH - INIT_WORK(&dev->work, DRM(irq_immediate_bh), dev); -#endif - -#ifdef __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 + if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { + init_waitqueue_head(&dev->vbl_queue); + + spin_lock_init( &dev->vbl_lock ); + + INIT_LIST_HEAD( &dev->vbl_sigs.head ); + + dev->vbl_pending = 0; + } /* Before installing handler */ - DRM(driver_irq_preinstall)(dev); + dev->fn_tbl.irq_preinstall(dev); /* Install handler */ - ret = request_irq( dev->irq, DRM(irq_handler), - DRM_IRQ_TYPE, dev->devname, dev ); + if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) + sh_flags = SA_SHIRQ; + + ret = request_irq( dev->irq, dev->fn_tbl.irq_handler, + sh_flags, dev->devname, dev ); if ( ret < 0 ) { down( &dev->struct_sem ); dev->irq_enabled = 0; @@ -156,7 +144,7 @@ } /* After installing handler */ - DRM(driver_irq_postinstall)(dev); + dev->fn_tbl.irq_postinstall(dev); return 0; } @@ -172,6 +160,9 @@ { int irq_enabled; + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + down( &dev->struct_sem ); irq_enabled = dev->irq_enabled; dev->irq_enabled = 0; @@ -182,7 +173,7 @@ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); - DRM(driver_irq_uninstall)( dev ); + dev->fn_tbl.irq_uninstall(dev); free_irq( dev->irq, dev ); @@ -206,25 +197,29 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_control_t ctl; + + /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */ if ( copy_from_user( &ctl, (drm_control_t __user *)arg, sizeof(ctl) ) ) return -EFAULT; switch ( ctl.func ) { case DRM_INST_HANDLER: + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return 0; if (dev->if_version < DRM_IF_VERSION(1, 2) && ctl.irq != dev->irq) return -EINVAL; return DRM(irq_install)( dev ); case DRM_UNINST_HANDLER: + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return 0; return DRM(irq_uninstall)( dev ); default: return -EINVAL; } } -#ifdef __HAVE_VBL_IRQ - /** * Wait for VBLANK. * @@ -254,6 +249,9 @@ int ret = 0; unsigned int flags; + if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL)) + return -EINVAL; + if (!dev->irq) return -EINVAL; @@ -318,7 +316,8 @@ spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); } else { - ret = DRM(vblank_wait)( dev, &vblwait.request.sequence ); + if (dev->fn_tbl.vblank_wait) + ret = dev->fn_tbl.vblank_wait( dev, &vblwait.request.sequence ); do_gettimeofday( &now ); vblwait.reply.tval_sec = now.tv_sec; @@ -366,6 +365,4 @@ spin_unlock_irqrestore( &dev->vbl_lock, flags ); } -#endif /* __HAVE_VBL_IRQ */ -#endif /* __HAVE_IRQ */ diff -Nru a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h --- a/drivers/char/drm/drm_memory.h 2004-10-18 14:56:16 -07:00 +++ b/drivers/char/drm/drm_memory.h 2004-10-18 14:56:16 -07:00 @@ -44,7 +44,7 @@ */ #define DEBUG_MEMORY 0 -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP #include @@ -130,46 +130,56 @@ return pte_pfn(*ptep) << PAGE_SHIFT; } -#endif /* __REALLY_HAVE_AGP */ +#else /* __OS_HAS_AGP */ + +static inline drm_map_t *drm_lookup_map(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + return NULL; +} + +static inline void *agp_remap(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + return NULL; +} + +static inline unsigned long drm_follow_page (void *vaddr) +{ + return 0; +} + +#endif static inline void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev) { -#if __REALLY_HAVE_AGP - if (dev->agp && dev->agp->cant_use_aperture) { + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { drm_map_t *map = drm_lookup_map(offset, size, dev); if (map && map->type == _DRM_AGP) return agp_remap(offset, size, dev); } -#endif - return ioremap(offset, size); } static inline void *drm_ioremap_nocache(unsigned long offset, unsigned long size, drm_device_t *dev) { -#if __REALLY_HAVE_AGP - if (dev->agp && dev->agp->cant_use_aperture) { + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { drm_map_t *map = drm_lookup_map(offset, size, dev); if (map && map->type == _DRM_AGP) return agp_remap(offset, size, dev); } -#endif - return ioremap_nocache(offset, size); } static inline void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev) { -#if __REALLY_HAVE_AGP /* * This is a bit ugly. It would be much cleaner if the DRM API would use separate * routines for handling mappings in the AGP space. Hopefully this can be done in * a future revision of the interface... */ - if (dev->agp && dev->agp->cant_use_aperture + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture && ((unsigned long) pt >= VMALLOC_START && (unsigned long) pt < VMALLOC_END)) { unsigned long offset; @@ -182,11 +192,11 @@ return; } } -#endif iounmap(pt); } + #if DEBUG_MEMORY #include "drm_memory_debug.h" #else @@ -331,7 +341,7 @@ drm_ioremapfree(pt, size, dev); } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP /** Wrapper around agp_allocate_memory() */ DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type) { diff -Nru a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h --- a/drivers/char/drm/drm_memory_debug.h 2004-10-18 14:56:13 -07:00 +++ b/drivers/char/drm/drm_memory_debug.h 2004-10-18 14:56:13 -07:00 @@ -352,7 +352,7 @@ } } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type) { diff -Nru a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h --- a/drivers/char/drm/drm_os_linux.h 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/drm/drm_os_linux.h 2004-10-18 14:57:03 -07:00 @@ -16,13 +16,17 @@ #define DRM_CURRENTPID current->pid #define DRM_UDELAY(d) udelay(d) /** Read a byte from a MMIO region */ -#define DRM_READ8(map, offset) readb(((unsigned long)(map)->handle) + (offset)) +#define DRM_READ8(map, offset) readb(((void __iomem *)(map)->handle) + (offset)) +/** Read a word from a MMIO region */ +#define DRM_READ16(map, offset) readw(((void __iomem *)(map)->handle) + (offset)) /** Read a dword from a MMIO region */ -#define DRM_READ32(map, offset) readl(((unsigned long)(map)->handle) + (offset)) +#define DRM_READ32(map, offset) readl(((void __iomem *)(map)->handle) + (offset)) /** Write a byte into a MMIO region */ -#define DRM_WRITE8(map, offset, val) writeb(val, ((unsigned long)(map)->handle) + (offset)) +#define DRM_WRITE8(map, offset, val) writeb(val, ((void __iomem *)(map)->handle) + (offset)) +/** Write a word into a MMIO region */ +#define DRM_WRITE16(map, offset, val) writew(val, ((void __iomem *)(map)->handle) + (offset)) /** Write a dword into a MMIO region */ -#define DRM_WRITE32(map, offset, val) writel(val, ((unsigned long)(map)->handle) + (offset)) +#define DRM_WRITE32(map, offset, val) writel(val, ((void __iomem *)(map)->handle) + (offset)) /** Read memory barrier */ #define DRM_READMEMORYBARRIER() rmb() /** Write memory barrier */ @@ -37,8 +41,34 @@ #define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs /** AGP types */ +#if __OS_HAS_AGP #define DRM_AGP_MEM struct agp_memory #define DRM_AGP_KERN struct agp_kern_info +#else +/* define some dummy types for non AGP supporting kernels */ +struct no_agp_kern { + unsigned long aper_base; + unsigned long aper_size; +}; +#define DRM_AGP_MEM int +#define DRM_AGP_KERN struct no_agp_kern +#endif + +#if !(__OS_HAS_MTRR) +static __inline__ int mtrr_add (unsigned long base, unsigned long size, + unsigned int type, char increment) +{ + return -ENODEV; +} + +static __inline__ int mtrr_del (int reg, unsigned long base, + unsigned long size) +{ + return -ENODEV; +} +#define MTRR_TYPE_WRCOMB 1 + +#endif /** Task queue handler arguments */ #define DRM_TASKQUEUE_ARGS void *arg @@ -104,7 +134,7 @@ add_wait_queue(&(queue), &entry); \ \ for (;;) { \ - current->state = TASK_INTERRUPTIBLE; \ + __set_current_state(TASK_INTERRUPTIBLE); \ if (condition) \ break; \ if (time_after_eq(jiffies, end)) { \ @@ -117,7 +147,7 @@ break; \ } \ } \ - current->state = TASK_RUNNING; \ + __set_current_state(TASK_RUNNING); \ remove_wait_queue(&(queue), &entry); \ } while (0) diff -Nru a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h --- a/drivers/char/drm/drm_pciids.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/drm/drm_pciids.h 2004-10-18 14:56:29 -07:00 @@ -201,3 +201,11 @@ #define ffb_PCI_IDS \ {0, 0, 0} +#define i915_PCI_IDS \ + {0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + diff -Nru a/drivers/char/drm/drm_scatter.h b/drivers/char/drm/drm_scatter.h --- a/drivers/char/drm/drm_scatter.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/drm/drm_scatter.h 2004-10-18 14:56:33 -07:00 @@ -73,6 +73,9 @@ DRM_DEBUG( "%s\n", __FUNCTION__ ); + if (!drm_core_check_feature(dev, DRIVER_SG)) + return -EINVAL; + if ( dev->sg ) return -EINVAL; @@ -205,6 +208,9 @@ drm_device_t *dev = priv->dev; drm_scatter_gather_t request; drm_sg_mem_t *entry; + + if (!drm_core_check_feature(dev, DRIVER_SG)) + return -EINVAL; if ( copy_from_user( &request, (drm_scatter_gather_t __user *)arg, diff -Nru a/drivers/char/drm/drm_vm.h b/drivers/char/drm/drm_vm.h --- a/drivers/char/drm/drm_vm.h 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/drm/drm_vm.h 2004-10-18 14:57:05 -07:00 @@ -46,10 +46,10 @@ * Find the right map and if it's AGP memory find the real physical page to * map, get the page, increment the use count and return it. */ +#if __OS_HAS_AGP static __inline__ struct page *DRM(do_vm_nopage)(struct vm_area_struct *vma, unsigned long address) { -#if __REALLY_HAVE_AGP drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; drm_map_t *map = NULL; @@ -59,6 +59,8 @@ /* * Find the right map */ + if (!drm_core_has_AGP(dev)) + goto vm_nopage_error; if(!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; @@ -107,10 +109,15 @@ return page; } vm_nopage_error: -#endif /* __REALLY_HAVE_AGP */ - return NOPAGE_SIGBUS; /* Disallow mremap */ } +#else /* __OS_HAS_AGP */ +static __inline__ struct page *DRM(do_vm_nopage)(struct vm_area_struct *vma, + unsigned long address) +{ + return NOPAGE_SIGBUS; +} +#endif /* __OS_HAS_AGP */ /** * \c nopage method for shared virtual memory. @@ -201,15 +208,13 @@ switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if __REALLY_HAVE_MTRR - if (map->mtrr >= 0) { + if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { int retcode; retcode = mtrr_del(map->mtrr, map->offset, map->size); DRM_DEBUG("mtrr_del = %d\n", retcode); } -#endif DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: @@ -488,18 +493,19 @@ return 0; } -#ifndef DRIVER_GET_MAP_OFS -#define DRIVER_GET_MAP_OFS() (map->offset) -#endif +unsigned long DRM(core_get_map_ofs)(drm_map_t *map) +{ + return map->offset; +} -#ifndef DRIVER_GET_REG_OFS +unsigned long DRM(core_get_reg_ofs)(struct drm_device *dev) +{ #ifdef __alpha__ -#define DRIVER_GET_REG_OFS() (dev->hose->dense_mem_base - \ - dev->hose->mem_space->start) + return dev->hose->dense_mem_base - dev->hose->mem_space->start; #else -#define DRIVER_GET_REG_OFS() 0 -#endif + return 0; #endif +} /** * mmap DMA memory. @@ -533,7 +539,7 @@ * --BenH. */ if (!VM_OFFSET(vma) -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP && (!dev->agp || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) #endif ) @@ -552,7 +558,7 @@ r_list = list_entry(list, drm_map_list_t, head); map = r_list->map; if (!map) continue; - off = DRIVER_GET_MAP_OFS(); + off = dev->fn_tbl.get_map_ofs(map); if (off == VM_OFFSET(vma)) break; } @@ -577,8 +583,7 @@ switch (map->type) { case _DRM_AGP: -#if __REALLY_HAVE_AGP - if (dev->agp->cant_use_aperture) { + if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) { /* * On some platforms we can't talk to bus dma address from the CPU, so for * memory of type DRM_AGP, we'll deal with sorting out the real physical @@ -590,7 +595,6 @@ vma->vm_ops = &DRM(vm_ops); break; } -#endif /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: @@ -609,7 +613,7 @@ if (map->type != _DRM_AGP) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #endif - offset = DRIVER_GET_REG_OFS(); + offset = dev->fn_tbl.get_reg_ofs(dev); #ifdef __sparc__ if (io_remap_page_range(DRM_RPR_ARG(vma) vma->vm_start, VM_OFFSET(vma) + offset, diff -Nru a/drivers/char/drm/ffb.h b/drivers/char/drm/ffb.h --- a/drivers/char/drm/ffb.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/drm/ffb.h 2004-10-18 14:56:33 -07:00 @@ -8,9 +8,5 @@ */ #define DRM(x) ffb_##x -/* General customization: - */ -#define __HAVE_KERNEL_CTX_SWITCH 1 -#define __HAVE_RELEASE 1 #endif diff -Nru a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c --- a/drivers/char/drm/ffb_context.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/drm/ffb_context.c 2004-10-18 14:56:33 -07:00 @@ -354,7 +354,7 @@ } while (--limit); } -int DRM(context_switch)(drm_device_t *dev, int old, int new) +int ffb_driver_context_switch(drm_device_t *dev, int old, int new) { ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; @@ -380,7 +380,7 @@ return 0; } -int DRM(resctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_resctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_ctx_res_t res; @@ -407,7 +407,7 @@ } -int DRM(addctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_addctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -428,7 +428,7 @@ return 0; } -int DRM(modctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_modctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -457,7 +457,7 @@ return 0; } -int DRM(getctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_getctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -489,7 +489,7 @@ return 0; } -int DRM(switchctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -499,10 +499,10 @@ if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx))) return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); - return DRM(context_switch)(dev, dev->last_context, ctx.handle); + return ffb_driver_context_switch(dev, dev->last_context, ctx.handle); } -int DRM(newctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_newctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_ctx_t ctx; @@ -514,7 +514,7 @@ return 0; } -int DRM(rmctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_ctx_t ctx; @@ -536,4 +536,16 @@ fpriv->hw_state[idx] = NULL; } return 0; +} + +void ffb_set_context_ioctls(void) +{ + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)].func = ffb_driver_addctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)].func = ffb_driver_rmctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)].func = ffb_driver_modctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)].func = ffb_driver_getctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)].func = ffb_driver_switchctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)].func = ffb_driver_newctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)].func = ffb_driver_resctx; + } diff -Nru a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c --- a/drivers/char/drm/ffb_drv.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/drm/ffb_drv.c 2004-10-18 14:57:05 -07:00 @@ -26,58 +26,6 @@ #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 1 -#define DRIVER_FOPS \ -static struct file_operations DRM(fops) = { \ - .owner = THIS_MODULE, \ - .open = DRM(open), \ - .flush = DRM(flush), \ - .release = DRM(release), \ - .ioctl = DRM(ioctl), \ - .mmap = DRM(mmap), \ - .read = DRM(read), \ - .fasync = DRM(fasync), \ - .poll = DRM(poll), \ - .get_unmapped_area = ffb_get_unmapped_area, \ -} - -#define DRIVER_COUNT_CARDS() ffb_count_card_instances() -/* Allocate private structure and fill it */ -#define DRIVER_PRESETUP() do { \ - int _ret; \ - _ret = ffb_presetup(dev); \ - if (_ret != 0) return _ret; \ -} while(0) - -/* Free private structure */ -#define DRIVER_PRETAKEDOWN() do { \ - if (dev->dev_private) kfree(dev->dev_private); \ -} while(0) - -#define DRIVER_POSTCLEANUP() do { \ - if (ffb_position != NULL) kfree(ffb_position); \ -} while(0) - -/* We have to free up the rogue hw context state holding error or - * else we will leak it. - */ -#define DRIVER_RELEASE() do { \ - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; \ - int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); \ - int idx; \ - \ - idx = context - 1; \ - if (fpriv && \ - context != DRM_KERNEL_CONTEXT && \ - fpriv->hw_state[idx] != NULL) { \ - kfree(fpriv->hw_state[idx]); \ - fpriv->hw_state[idx] = NULL; \ - } \ -} while(0) - -/* For mmap customization */ -#define DRIVER_GET_MAP_OFS() (map->offset & 0xffffffff) -#define DRIVER_GET_REG_OFS() ffb_get_reg_offset(dev) - typedef struct _ffb_position_t { int node; int root; @@ -192,63 +140,6 @@ return 0; } -static int __init ffb_count_siblings(int root) -{ - int node, child, count = 0; - - child = prom_getchild(root); - for (node = prom_searchsiblings(child, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) - count++; - - return count; -} - -static int __init ffb_scan_siblings(int root, int instance) -{ - int node, child; - - child = prom_getchild(root); - for (node = prom_searchsiblings(child, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { - ffb_position[instance].node = node; - ffb_position[instance].root = root; - instance++; - } - - return instance; -} - -static int ffb_presetup(drm_device_t *); - -static int __init ffb_count_card_instances(void) -{ - int root, total, instance; - - total = ffb_count_siblings(prom_root_node); - root = prom_getchild(prom_root_node); - for (root = prom_searchsiblings(root, "upa"); root; - root = prom_searchsiblings(prom_getsibling(root), "upa")) - total += ffb_count_siblings(root); - - ffb_position = kmalloc(sizeof(ffb_position_t) * total, GFP_KERNEL); - - /* Actual failure will be caught during ffb_presetup b/c we can't catch - * it easily here. - */ - if (!ffb_position) - return -ENOMEM; - - instance = ffb_scan_siblings(prom_root_node, 0); - - root = prom_getchild(prom_root_node); - for (root = prom_searchsiblings(root, "upa"); root; - root = prom_searchsiblings(prom_getsibling(root), "upa")) - instance = ffb_scan_siblings(root, instance); - - return total; -} - static drm_map_t *ffb_find_map(struct file *filp, unsigned long off) { drm_file_t *priv = filp->private_data; @@ -275,11 +166,11 @@ return NULL; } -static unsigned long ffb_get_unmapped_area(struct file *filp, - unsigned long hint, - unsigned long len, - unsigned long pgoff, - unsigned long flags) +unsigned long ffb_get_unmapped_area(struct file *filp, + unsigned long hint, + unsigned long len, + unsigned long pgoff, + unsigned long flags) { drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT); unsigned long addr = -ENOMEM; @@ -319,21 +210,7 @@ return addr; } -static unsigned long ffb_get_reg_offset(drm_device_t *dev) -{ - ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private; - - if (ffb_priv) - return ffb_priv->card_phys_base; - - return 0; -} - -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" +#include "drm_core.h" /* This functions must be here since it references DRM(numdevs) * which drm_drv.h declares. @@ -372,11 +249,74 @@ return ret; } -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +static void ffb_driver_release(drm_device_t *dev, struct file *filp) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; + int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); + int idx; + + idx = context - 1; + if (fpriv && + context != DRM_KERNEL_CONTEXT && + fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } +} + +static void ffb_driver_pretakedown(drm_device_t *dev) +{ + if (dev->dev_private) kfree(dev->dev_private); +} + +static int ffb_driver_postcleanup(drm_device_t *dev) +{ + if (ffb_position != NULL) kfree(ffb_position); + return 0; +} + +static void ffb_driver_kernel_context_switch_unlock(struct drm_device *dev, drm_lock_t *lock) +{ + dev->lock.filp = 0; + { + __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; + unsigned int old, new, prev, ctx; + + ctx = lock->context; + do { + old = *plock; + new = ctx; + prev = cmpxchg(plock, old, new); + } while (prev != old); + } + wake_up_interruptible(&dev->lock.lock_queue); +} + +static unsigned long ffb_driver_get_map_ofs(drm_map_t *map) +{ + return (map->offset & 0xffffffff); +} + +static unsigned long ffb_driver_get_reg_ofs(drm_device_t *dev) +{ + ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private; + + if (ffb_priv) + return ffb_priv->card_phys_base; + + return 0; +} + +void ffb_driver_register_fns(drm_device_t *dev) +{ + ffb_set_context_ioctls(); + DRM(fops).get_unmapped_area = ffb_get_unmapped_area; + dev->fn_tbl.release = ffb_driver_release; + dev->fn_tbl.presetup = ffb_presetup; + dev->fn_tbl.pretakedown = ffb_driver_pretakedown; + dev->fn_tbl.postcleanup = ffb_driver_postcleanup; + dev->fn_tbl.kernel_context_switch = ffb_context_switch; + dev->fn_tbl.kernel_context_switch_unlock = ffb_driver_kernel_context_switch_unlock; + dev->fn_tbl.get_map_ofs = ffb_driver_get_map_ofs; + dev->fn_tbl.get_reg_ofs = ffb_driver_get_reg_ofs; +} diff -Nru a/drivers/char/drm/ffb_drv.h b/drivers/char/drm/ffb_drv.h --- a/drivers/char/drm/ffb_drv.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/drm/ffb_drv.h 2004-10-18 14:56:17 -07:00 @@ -274,3 +274,13 @@ /* Context table. */ struct ffb_hw_context *hw_state[FFB_MAX_CTXS]; } ffb_dev_priv_t; + +extern struct file_operations DRM(fops); +extern unsigned long ffb_get_unmapped_area(struct file *filp, + unsigned long hint, + unsigned long len, + unsigned long pgoff, + unsigned long flags); +extern void ffb_set_context_ioctls(void); +extern drm_ioctl_desc_t DRM(ioctls)[]; + diff -Nru a/drivers/char/drm/gamma.h b/drivers/char/drm/gamma.h --- a/drivers/char/drm/gamma.h 2004-10-18 14:55:53 -07:00 +++ b/drivers/char/drm/gamma.h 2004-10-18 14:55:53 -07:00 @@ -36,8 +36,6 @@ /* General customization: */ -#define __HAVE_MTRR 1 - #define DRIVER_AUTHOR "VA Linux Systems Inc." #define DRIVER_NAME "gamma" @@ -71,44 +69,9 @@ /* DMA customization: */ -#define __HAVE_DMA 1 -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_OLD_DMA 1 -#define __HAVE_PCI_DMA 1 - -#define __HAVE_DRIVER_FOPS_READ 1 -#define __HAVE_DRIVER_FOPS_POLL 1 - #define __HAVE_MULTIPLE_DMA_QUEUES 1 #define __HAVE_DMA_WAITQUEUE 1 -#define __HAVE_DMA_WAITLIST 1 -#define __HAVE_DMA_FREELIST 1 - -#define __HAVE_DMA_FLUSH 1 -#define __HAVE_DMA_SCHEDULE 1 - -#define __HAVE_DMA_READY 1 -#define DRIVER_DMA_READY() do { \ - gamma_dma_ready(dev); \ -} while (0) - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - drm_gamma_private_t *dev_priv = \ - (drm_gamma_private_t *)dev->dev_private; \ - if (dev_priv->num_rast == 2) \ - gamma_dma_quiescent_dual(dev); \ - else gamma_dma_quiescent_single(dev); \ - return 0; \ -} while (0) - -#define __HAVE_IRQ 1 -#define __HAVE_IRQ_BH 1 - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_gamma_private_t *)((dev)->dev_private))->buffers - +/* removed from DRM HAVE_DMA_FREELIST & HAVE_DMA_SCHEDULE */ #endif /* __GAMMA_H__ */ diff -Nru a/drivers/char/drm/gamma_context.h b/drivers/char/drm/gamma_context.h --- a/drivers/char/drm/gamma_context.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/drm/gamma_context.h 2004-10-18 14:56:28 -07:00 @@ -42,7 +42,7 @@ the circular buffer), is based on Alessandro Rubini's LINUX DEVICE DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */ -ssize_t DRM(read)(struct file *filp, char __user *buf, size_t count, loff_t *off) +ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -128,7 +128,7 @@ return 0; } -unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) +unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; diff -Nru a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c --- a/drivers/char/drm/gamma_dma.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/drm/gamma_dma.c 2004-10-18 14:57:03 -07:00 @@ -116,7 +116,7 @@ return (!GAMMA_READ(GAMMA_DMACOUNT)); } -irqreturn_t gamma_irq_handler( DRM_IRQ_ARGS ) +irqreturn_t gamma_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *)arg; drm_device_dma_t *dma = dev->dma; @@ -639,12 +639,12 @@ break; } } - - DRM_FIND_MAP( dev_priv->mmio0, init->mmio0 ); - DRM_FIND_MAP( dev_priv->mmio1, init->mmio1 ); - DRM_FIND_MAP( dev_priv->mmio2, init->mmio2 ); - DRM_FIND_MAP( dev_priv->mmio3, init->mmio3 ); - + + dev_priv->mmio0 = drm_core_findmap(dev, init->mmio0); + dev_priv->mmio1 = drm_core_findmap(dev, init->mmio1); + dev_priv->mmio2 = drm_core_findmap(dev, init->mmio2); + dev_priv->mmio3 = drm_core_findmap(dev, init->mmio3); + dev_priv->sarea_priv = (drm_gamma_sarea_t *) ((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); @@ -661,9 +661,8 @@ buf = dma->buflist[GLINT_DRI_BUF_COUNT]; } else { - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - - DRM_IOREMAP( dev_priv->buffers, dev ); + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + drm_core_ioremap( dev->agp_buffer_map, dev); buf = dma->buflist[GLINT_DRI_BUF_COUNT]; pgt = buf->address; @@ -690,19 +689,18 @@ { DRM_DEBUG( "%s\n", __FUNCTION__ ); -#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_enabled ) DRM(irq_uninstall)(dev); -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + if ( dev->irq_enabled ) + DRM(irq_uninstall)(dev); if ( dev->dev_private ) { - drm_gamma_private_t *dev_priv = dev->dev_private; - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t), DRM_MEM_DRIVER ); @@ -868,7 +866,7 @@ return 0; } -void DRM(driver_irq_preinstall)( drm_device_t *dev ) { +void gamma_driver_irq_preinstall( drm_device_t *dev ) { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; @@ -879,7 +877,7 @@ GAMMA_WRITE( GAMMA_GDMACONTROL, 0x00000000 ); } -void DRM(driver_irq_postinstall)( drm_device_t *dev ) { +void gamma_driver_irq_postinstall( drm_device_t *dev ) { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; @@ -891,7 +889,7 @@ GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00039090 ); } -void DRM(driver_irq_uninstall)( drm_device_t *dev ) { +void gamma_driver_irq_uninstall( drm_device_t *dev ) { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; if (!dev_priv) @@ -903,4 +901,46 @@ GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00000000 ); GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000000 ); GAMMA_WRITE( GAMMA_GINTENABLE, 0x00000000 ); +} + +extern drm_ioctl_desc_t DRM(ioctls)[]; + +static int gamma_driver_preinit(drm_device_t *dev) +{ + /* reset the finish ioctl */ + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_FINISH)].func = DRM(finish); + return 0; +} + +static void gamma_driver_pretakedown(drm_device_t *dev) +{ + gamma_do_cleanup_dma(dev); +} + +static void gamma_driver_dma_ready(drm_device_t *dev) +{ + gamma_dma_ready(dev); +} + +static int gamma_driver_dma_quiescent(drm_device_t *dev) +{ + drm_gamma_private_t *dev_priv = ( + drm_gamma_private_t *)dev->dev_private; + if (dev_priv->num_rast == 2) + gamma_dma_quiescent_dual(dev); + else gamma_dma_quiescent_single(dev); + return 0; +} + +void gamma_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ; + DRM(fops).read = gamma_fops_read; + DRM(fops).poll = gamma_fops_poll; + dev->fn_tbl.preinit = gamma_driver_preinit; + dev->fn_tbl.pretakedown = gamma_driver_pretakedown; + dev->fn_tbl.dma_ready = gamma_driver_dma_ready; + dev->fn_tbl.dma_quiescent = gamma_driver_dma_quiescent; + dev->fn_tbl.dma_flush_block_and_flush = gamma_flush_block_and_flush; + dev->fn_tbl.dma_flush_unblock = gamma_flush_unblock; } diff -Nru a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c --- a/drivers/char/drm/gamma_drv.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/drm/gamma_drv.c 2004-10-18 14:57:03 -07:00 @@ -56,3 +56,4 @@ #include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" +#include "drm_scatter.h" diff -Nru a/drivers/char/drm/gamma_drv.h b/drivers/char/drm/gamma_drv.h --- a/drivers/char/drm/gamma_drv.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/drm/gamma_drv.h 2004-10-18 14:56:29 -07:00 @@ -35,7 +35,6 @@ typedef struct drm_gamma_private { drm_gamma_sarea_t *sarea_priv; drm_map_t *sarea; - drm_map_t *buffers; drm_map_t *mmio0; drm_map_t *mmio1; drm_map_t *mmio2; @@ -91,6 +90,10 @@ drm_buf_t *buf); extern drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block); +/* externs for gamma changes to the ops */ +extern struct file_operations DRM(fops); +extern unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait); +extern ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off); #define GLINT_DRI_BUF_COUNT 256 diff -Nru a/drivers/char/drm/i810.h b/drivers/char/drm/i810.h --- a/drivers/char/drm/i810.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/drm/i810.h 2004-10-18 14:56:28 -07:00 @@ -36,10 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "VA Linux Systems Inc." @@ -77,48 +73,5 @@ [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 __HAVE_COUNTERS 4 -#define __HAVE_COUNTER6 _DRM_STAT_IRQ -#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY -#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY -#define __HAVE_COUNTER9 _DRM_STAT_DMA - -/* Driver customization: - */ -#define __HAVE_RELEASE 1 -#define DRIVER_RELEASE() do { \ - i810_reclaim_buffers( filp ); \ -} while (0) - -#define DRIVER_PRETAKEDOWN() do { \ - i810_dma_cleanup( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_DMA_QUEUE 1 -#define __HAVE_DMA_WAITLIST 0 -#define __HAVE_DMA_RECLAIM 1 - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - i810_dma_quiescent( dev ); \ -} while (0) - -/* Don't need an irq any more. The template code will make sure that - * a noop stub is generated for compatibility. - */ -/* XXX: Add vblank support? */ -#define __HAVE_IRQ 0 - -/* Buffer customization: - */ - -#define DRIVER_BUF_PRIV_T drm_i810_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_i810_private_t *)((dev)->dev_private))->buffer_map #endif diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c --- a/drivers/char/drm/i810_dma.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/drm/i810_dma.c 2004-10-18 14:56:28 -07:00 @@ -232,13 +232,12 @@ { drm_device_dma_t *dma = dev->dma; -#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_enabled ) DRM(irq_uninstall)(dev); -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ) && dev->irq_enabled) + DRM(irq_uninstall)(dev); if (dev->dev_private) { int i; @@ -364,15 +363,15 @@ DRM_ERROR("can not find sarea!\n"); return -EINVAL; } - DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); + dev_priv->mmio_map = drm_core_findmap(dev, 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; } - DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset ); - if (!dev_priv->buffer_map) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if (!dev->agp_buffer_map) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not find dma buffer map!\n"); @@ -844,13 +843,10 @@ if (buf_priv->currently_mapped == I810_BUF_MAPPED) { unsigned int prim = (sarea_priv->vertex_prim & PR_MASK); - put_user((GFX_OP_PRIMITIVE | prim | - ((used/4)-2)), - (u32 __user *)buf_priv->virtual); + *(u32 *)buf_priv->kernel_virtual = ((GFX_OP_PRIMITIVE | prim | ((used/4)-2))); if (used & 4) { - put_user(0, - (u32 __user *)((u32)buf_priv->virtual + used)); + *(u32 *)((u32)buf_priv->kernel_virtual + used) = 0; used += 4; } @@ -1391,3 +1387,36 @@ i810_dma_dispatch_flip( dev ); return 0; } + +static void i810_driver_pretakedown(drm_device_t *dev) +{ + i810_dma_cleanup( dev ); +} + +static void i810_driver_release(drm_device_t *dev, struct file *filp) +{ + i810_reclaim_buffers(filp); +} + +static int i810_driver_dma_quiescent(drm_device_t *dev) +{ + i810_dma_quiescent( dev ); + return 0; +} + +void i810_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE; + dev->dev_priv_size = sizeof(drm_i810_buf_priv_t); + dev->fn_tbl.pretakedown = i810_driver_pretakedown; + dev->fn_tbl.release = i810_driver_release; + dev->fn_tbl.dma_quiescent = i810_driver_dma_quiescent; + dev->fn_tbl.reclaim_buffers = i810_reclaim_buffers; + + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; +} + diff -Nru a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c --- a/drivers/char/drm/i810_drv.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/drm/i810_drv.c 2004-10-18 14:57:04 -07:00 @@ -37,19 +37,4 @@ #include "i810_drm.h" #include "i810_drv.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" - -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff -Nru a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h --- a/drivers/char/drm/i810_drv.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/drm/i810_drv.h 2004-10-18 14:57:04 -07:00 @@ -53,7 +53,6 @@ typedef struct drm_i810_private { drm_map_t *sarea_map; - drm_map_t *buffer_map; drm_map_t *mmio_map; drm_i810_sarea_t *sarea_priv; diff -Nru a/drivers/char/drm/i830.h b/drivers/char/drm/i830.h --- a/drivers/char/drm/i830.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/drm/i830.h 2004-10-18 14:56:28 -07:00 @@ -36,10 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "VA Linux Systems Inc." @@ -77,57 +73,11 @@ [DRM_IOCTL_NR(DRM_IOCTL_I830_GETPARAM)] = { i830_getparam, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I830_SETPARAM)] = { i830_setparam, 1, 0 } -#define __HAVE_COUNTERS 4 -#define __HAVE_COUNTER6 _DRM_STAT_IRQ -#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY -#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY -#define __HAVE_COUNTER9 _DRM_STAT_DMA - -/* Driver customization: - */ -#define __HAVE_RELEASE 1 -#define DRIVER_RELEASE() do { \ - i830_reclaim_buffers( filp ); \ -} while (0) - -#define DRIVER_PRETAKEDOWN() do { \ - i830_dma_cleanup( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_DMA_QUEUE 1 -#define __HAVE_DMA_WAITLIST 0 -#define __HAVE_DMA_RECLAIM 1 - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - i830_dma_quiescent( dev ); \ -} while (0) - - /* Driver will work either way: IRQ's save cpu time when waiting for * the card, but are subject to subtle interactions between bios, * hardware and the driver. */ /* XXX: Add vblank support? */ #define USE_IRQS 0 - -#if USE_IRQS -#define __HAVE_IRQ 1 -#define __HAVE_SHARED_IRQ 1 -#else -#define __HAVE_IRQ 0 -#endif - - -/* Buffer customization: - */ - -#define DRIVER_BUF_PRIV_T drm_i830_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_i830_private_t *)((dev)->dev_private))->buffer_map #endif diff -Nru a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c --- a/drivers/char/drm/i830_dma.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/drm/i830_dma.c 2004-10-18 14:55:54 -07:00 @@ -233,13 +233,11 @@ { drm_device_dma_t *dma = dev->dma; -#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_enabled ) DRM(irq_uninstall)(dev); -#endif if (dev->dev_private) { int i; @@ -371,15 +369,15 @@ DRM_ERROR("can not find sarea!\n"); return -EINVAL; } - DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio_map) { dev->dev_private = (void *)dev_priv; i830_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->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { dev->dev_private = (void *)dev_priv; i830_dma_cleanup(dev); DRM_ERROR("can not find dma buffer map!\n"); @@ -1166,19 +1164,19 @@ DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); if (buf_priv->currently_mapped == I830_BUF_MAPPED) { - u32 __user *vp = buf_priv->virtual; + u32 *vp = buf_priv->kernel_virtual; - put_user( (GFX_OP_PRIMITIVE | - sarea_priv->vertex_prim | - ((used/4)-2)), &vp[0]); + vp[0] = (GFX_OP_PRIMITIVE | + sarea_priv->vertex_prim | + ((used/4)-2)); if (dev_priv->use_mi_batchbuffer_start) { - put_user(MI_BATCH_BUFFER_END, &vp[used/4]); + vp[used/4] = MI_BATCH_BUFFER_END; used += 4; } if (used & 4) { - put_user(0, &vp[used/4]); + vp[used/4] = 0; used += 4; } @@ -1582,3 +1580,45 @@ return 0; } + + +static void i830_driver_pretakedown(drm_device_t *dev) +{ + i830_dma_cleanup( dev ); +} + +static void i830_driver_release(drm_device_t *dev, struct file *filp) +{ + i830_reclaim_buffers(filp); +} + +static int i830_driver_dma_quiescent(drm_device_t *dev) +{ + i830_dma_quiescent( dev ); + return 0; +} + +void i830_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE; +#if USE_IRQS + dev->driver_features |= DRIVER_HAVE_IRQ | DRIVER_SHARED_IRQ; +#endif + dev->dev_priv_size = sizeof(drm_i830_buf_priv_t); + dev->fn_tbl.pretakedown = i830_driver_pretakedown; + dev->fn_tbl.release = i830_driver_release; + dev->fn_tbl.dma_quiescent = i830_driver_dma_quiescent; + dev->fn_tbl.reclaim_buffers = i830_reclaim_buffers; +#if USE_IRQS + dev->fn_tbl.irq_preinstall = i830_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = i830_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = i830_driver_irq_uninstall; + dev->fn_tbl.irq_handler = i830_driver_irq_handler; +#endif + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; +} + diff -Nru a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c --- a/drivers/char/drm/i830_drv.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/drm/i830_drv.c 2004-10-18 14:56:28 -07:00 @@ -39,20 +39,4 @@ #include "i830_drm.h" #include "i830_drv.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" - -#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" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff -Nru a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h --- a/drivers/char/drm/i830_drv.h 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/drm/i830_drv.h 2004-10-18 14:56:48 -07:00 @@ -53,7 +53,6 @@ typedef struct drm_i830_private { drm_map_t *sarea_map; - drm_map_t *buffer_map; drm_map_t *mmio_map; drm_i830_sarea_t *sarea_priv; @@ -137,6 +136,10 @@ extern int i830_wait_irq(drm_device_t *dev, int irq_nr); extern int i830_emit_irq(drm_device_t *dev); +extern irqreturn_t i830_driver_irq_handler( DRM_IRQ_ARGS ); +extern void i830_driver_irq_preinstall( drm_device_t *dev ); +extern void i830_driver_irq_postinstall( drm_device_t *dev ); +extern void i830_driver_irq_uninstall( drm_device_t *dev ); #define I830_BASE(reg) ((unsigned long) \ dev_priv->mmio_map->handle) diff -Nru a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c --- a/drivers/char/drm/i830_irq.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/char/drm/i830_irq.c 2004-10-18 14:56:49 -07:00 @@ -35,7 +35,7 @@ #include -irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) +irqreturn_t i830_driver_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; @@ -92,7 +92,7 @@ add_wait_queue(&dev_priv->irq_queue, &entry); for (;;) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); if (atomic_read(&dev_priv->irq_received) >= irq_nr) break; if((signed)(end - jiffies) <= 0) { @@ -112,7 +112,7 @@ } } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&dev_priv->irq_queue, &entry); return ret; } @@ -178,7 +178,7 @@ /* drm_dma.h hooks */ -void DRM(driver_irq_preinstall)( drm_device_t *dev ) { +void i830_driver_irq_preinstall( drm_device_t *dev ) { drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; @@ -190,14 +190,14 @@ init_waitqueue_head(&dev_priv->irq_queue); } -void DRM(driver_irq_postinstall)( drm_device_t *dev ) { +void i830_driver_irq_postinstall( drm_device_t *dev ) { drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; I830_WRITE16( I830REG_INT_ENABLE_R, 0x2 ); } -void DRM(driver_irq_uninstall)( drm_device_t *dev ) { +void i830_driver_irq_uninstall( drm_device_t *dev ) { drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; if (!dev_priv) diff -Nru a/drivers/char/drm/i915.h b/drivers/char/drm/i915.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/i915.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,53 @@ +/* i915.h -- Intel I915 DRM template customization -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef __I915_H__ +#define __I915_H__ + +/* This remains constant for all DRM template files. + */ +#define DRM(x) i915_##x + +/* General customization: + */ + +#define DRIVER_AUTHOR "Tungsten Graphics, Inc." + +#define DRIVER_NAME "i915" +#define DRIVER_DESC "Intel Graphics" +#define DRIVER_DATE "20040405" + +/* Interface history: + * + * 1.1: Original. + */ +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 1 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_INIT)] = { i915_dma_init, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_FLUSH)] = { i915_flush_ioctl, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_FLIP)] = { i915_flip_bufs, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_BATCHBUFFER)] = { i915_batchbuffer, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_EMIT)] = { i915_irq_emit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_WAIT)] = { i915_irq_wait, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_GETPARAM)] = { i915_getparam, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_SETPARAM)] = { i915_setparam, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_ALLOC)] = { i915_mem_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_FREE)] = { i915_mem_free, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_INIT_HEAP)] = { i915_mem_init_heap, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_CMDBUFFER)] = { i915_cmdbuffer, 1, 0 } + +/* We use our own dma mechanisms, not the drm template code. However, + * the shared IRQ code is useful to us: + */ +#define __HAVE_PM 1 + +#endif diff -Nru a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/i915_dma.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,755 @@ +/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +static inline void i915_print_status_page(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 *temp = dev_priv->hw_status_page; + + if (!temp) { + DRM_DEBUG("no status page\n"); + return; + } + + 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: Driver Counter : %d\n", temp[5]); + +} + +/* Really want an OS-independent resettable timer. Would like to have + * this loop run for (eg) 3 sec, but have the timer reset every time + * the head pointer changes, so that EBUSY only happens if the ring + * actually stalls for (eg) 3 seconds. + */ +int i915_wait_ring(drm_device_t * dev, int n, const char *caller) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + int i; + + for (i = 0; i < 10000; i++) { + ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + if (ring->space >= n) + return 0; + + dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + + if (ring->head != last_head) + i = 0; + + last_head = ring->head; + } + + return DRM_ERR(EBUSY); +} + +void i915_kernel_lost_context(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + + ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR; + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + + if (ring->head == ring->tail) + dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; +} + +int i915_dma_cleanup(drm_device_t * dev) +{ + /* 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->dev_private) { + drm_i915_private_t *dev_priv = + (drm_i915_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree( &dev_priv->ring.map, dev); + } + + 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 */ + I915_WRITE(0x02080, 0x1ffff000); + } + + DRM(free) (dev->dev_private, sizeof(drm_i915_private_t), + DRM_MEM_DRIVER); + + dev->dev_private = NULL; + } + + return 0; +} + +static int i915_initialize(drm_device_t * dev, + drm_i915_private_t * dev_priv, + drm_i915_init_t * init) +{ + memset(dev_priv, 0, sizeof(drm_i915_private_t)); + + DRM_GETSAREA(); + if (!dev_priv->sarea) { + DRM_ERROR("can not find sarea!\n"); + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + return DRM_ERR(EINVAL); + } + + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio_map) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("can not find mmio map!\n"); + return DRM_ERR(EINVAL); + } + + dev_priv->sarea_priv = (drm_i915_sarea_t *) + ((u8 *) dev_priv->sarea->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.tail_mask = dev_priv->ring.Size - 1; + + dev_priv->ring.map.offset = init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = 0; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + + drm_core_ioremap( &dev_priv->ring.map, dev ); + + if (dev_priv->ring.map.handle == NULL) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return DRM_ERR(ENOMEM); + } + + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + + dev_priv->back_offset = init->back_offset; + dev_priv->front_offset = init->front_offset; + dev_priv->current_page = 0; + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + + /* We are using separate values as placeholders for mechanisms for + * private backbuffer/depthbuffer usage. + */ + dev_priv->use_mi_batchbuffer_start = 0; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->allow_batchbuffer = 1; + + /* 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) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return DRM_ERR(ENOMEM); + } + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + + I915_WRITE(0x02080, dev_priv->dma_status_page); + DRM_DEBUG("Enabled hardware status page\n"); + + dev->dev_private = (void *)dev_priv; + + return 0; +} + +static int i915_resume(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (!dev_priv->sarea) { + DRM_ERROR("can not find sarea!\n"); + return DRM_ERR(EINVAL); + } + + if (!dev_priv->mmio_map) { + DRM_ERROR("can not find mmio map!\n"); + return DRM_ERR(EINVAL); + } + + if (dev_priv->ring.map.handle == NULL) { + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return DRM_ERR(ENOMEM); + } + + /* Program Hardware Status Page */ + if (!dev_priv->hw_status_page) { + DRM_ERROR("Can not find hardware status page\n"); + return DRM_ERR(EINVAL); + } + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + + I915_WRITE(0x02080, dev_priv->dma_status_page); + DRM_DEBUG("Enabled hardware status page\n"); + + return 0; +} + +int i915_dma_init(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv; + drm_i915_init_t init; + int retcode = 0; + + DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data, + sizeof(init)); + + switch (init.func) { + case I915_INIT_DMA: + dev_priv = DRM(alloc) (sizeof(drm_i915_private_t), + DRM_MEM_DRIVER); + if (dev_priv == NULL) + return DRM_ERR(ENOMEM); + retcode = i915_initialize(dev, dev_priv, &init); + break; + case I915_CLEANUP_DMA: + retcode = i915_dma_cleanup(dev); + break; + case I915_RESUME_DMA: + retcode = i915_resume(dev); + break; + default: + retcode = -EINVAL; + break; + } + + return retcode; +} + +/* Implement basically the same security restrictions as hardware does + * for MI_BATCH_NON_SECURE. These can be made stricter at any time. + * + * Most of the calculations below involve calculating the size of a + * particular instruction. It's important to get the size right as + * that tells us where the next instruction to check is. Any illegal + * instruction detected will be given a size of zero, which is a + * signal to abort the rest of the buffer. + */ +static int do_validate_cmd(int cmd) +{ + switch (((cmd >> 29) & 0x7)) { + case 0x0: + switch ((cmd >> 23) & 0x3f) { + case 0x0: + return 1; /* MI_NOOP */ + case 0x4: + return 1; /* MI_FLUSH */ + default: + return 0; /* disallow everything else */ + } + break; + case 0x1: + return 0; /* reserved */ + case 0x2: + return (cmd & 0xff) + 2; /* 2d commands */ + case 0x3: + if (((cmd >> 24) & 0x1f) <= 0x18) + return 1; + + switch ((cmd >> 24) & 0x1f) { + case 0x1c: + return 1; + case 0x1d: + switch ((cmd>>16)&0xff) { + case 0x3: + return (cmd & 0x1f) + 2; + case 0x4: + return (cmd & 0xf) + 2; + default: + return (cmd & 0xffff) + 2; + } + case 0x1e: + if (cmd & (1 << 23)) + return (cmd & 0xffff) + 1; + else + return 1; + case 0x1f: + if ((cmd & (1 << 23)) == 0) /* inline vertices */ + return (cmd & 0x1ffff) + 2; + else if (cmd & (1 << 17)) /* indirect random */ + if ((cmd & 0xffff) == 0) + return 0; /* unknown length, too hard */ + else + return (((cmd & 0xffff) + 1) / 2) + 1; + else + return 2; /* indirect sequential */ + default: + return 0; + } + default: + return 0; + } + + return 0; +} + +static int validate_cmd(int cmd) +{ + int ret = do_validate_cmd(cmd); + +/* printk("validate_cmd( %x ): %d\n", cmd, ret); */ + + return ret; +} + +static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int i; + RING_LOCALS; + + for (i = 0; i < dwords;) { + int cmd, sz; + + if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) + return DRM_ERR(EINVAL); + +/* printk("%d/%d ", i, dwords); */ + + if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) + return DRM_ERR(EINVAL); + + BEGIN_LP_RING(sz); + OUT_RING(cmd); + + while (++i, --sz) { + if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], + sizeof(cmd))) { + return DRM_ERR(EINVAL); + } + OUT_RING(cmd); + } + ADVANCE_LP_RING(); + } + + return 0; +} + +static int i915_emit_box(drm_device_t * dev, + drm_clip_rect_t __user * boxes, + int i, int DR1, int DR4) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_clip_rect_t box; + RING_LOCALS; + + if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { + return EFAULT; + } + + if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { + DRM_ERROR("Bad box %d,%d..%d,%d\n", + box.x1, box.y1, box.x2, box.y2); + return DRM_ERR(EINVAL); + } + + BEGIN_LP_RING(6); + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(DR1); + OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); + OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); + OUT_RING(DR4); + OUT_RING(0); + ADVANCE_LP_RING(); + + return 0; +} + +static int i915_dispatch_cmdbuffer(drm_device_t * dev, + drm_i915_cmdbuffer_t * cmd) +{ + int nbox = cmd->num_cliprects; + int i = 0, count, ret; + + if (cmd->sz & 0x3) { + DRM_ERROR("alignment"); + return DRM_ERR(EINVAL); + } + + i915_kernel_lost_context(dev); + + count = nbox ? nbox : 1; + + for (i = 0; i < count; i++) { + if (i < nbox) { + ret = i915_emit_box(dev, cmd->cliprects, i, + cmd->DR1, cmd->DR4); + if (ret) + return ret; + } + + ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4); + if (ret) + return ret; + } + + return 0; +} + +static int i915_dispatch_batchbuffer(drm_device_t * dev, + drm_i915_batchbuffer_t * batch) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_clip_rect_t __user *boxes = batch->cliprects; + int nbox = batch->num_cliprects; + int i = 0, count; + RING_LOCALS; + + if ((batch->start | batch->used) & 0x7) { + DRM_ERROR("alignment"); + return DRM_ERR(EINVAL); + } + + i915_kernel_lost_context(dev); + + count = nbox ? nbox : 1; + + for (i = 0; i < count; i++) { + if (i < nbox) { + int ret = i915_emit_box(dev, boxes, i, + batch->DR1, batch->DR4); + if (ret) + return ret; + } + + if (dev_priv->use_mi_batchbuffer_start) { + BEGIN_LP_RING(2); + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + OUT_RING(batch->start + batch->used - 4); + OUT_RING(0); + ADVANCE_LP_RING(); + } + } + + dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; + + BEGIN_LP_RING(4); + OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(20); + OUT_RING(dev_priv->counter); + OUT_RING(0); + ADVANCE_LP_RING(); + + return 0; +} + +static int i915_dispatch_flip(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", + __FUNCTION__, + dev_priv->current_page, + dev_priv->sarea_priv->pf_current_page); + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(2); + OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING(0); + ADVANCE_LP_RING(); + + BEGIN_LP_RING(6); + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); + OUT_RING(0); + if (dev_priv->current_page == 0) { + OUT_RING(dev_priv->back_offset); + dev_priv->current_page = 1; + } else { + OUT_RING(dev_priv->front_offset); + dev_priv->current_page = 0; + } + OUT_RING(0); + ADVANCE_LP_RING(); + + BEGIN_LP_RING(2); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); + OUT_RING(0); + ADVANCE_LP_RING(); + + dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; + + BEGIN_LP_RING(4); + OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(20); + OUT_RING(dev_priv->counter); + OUT_RING(0); + ADVANCE_LP_RING(); + + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + return 0; +} + +static int i915_quiescent(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + i915_kernel_lost_context(dev); + return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); +} + +int i915_flush_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_flush_ioctl called without lock held\n"); + return DRM_ERR(EINVAL); + } + + return i915_quiescent(dev); +} + +int i915_batchbuffer(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + dev_priv->sarea_priv; + drm_i915_batchbuffer_t batch; + int ret; + + if (!dev_priv->allow_batchbuffer) { + DRM_ERROR("Batchbuffer ioctl disabled\n"); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data, + sizeof(batch)); + + DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", + batch.start, batch.used, batch.num_cliprects); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_batchbuffer called without lock held\n"); + return DRM_ERR(EINVAL); + } + + if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects, + batch.num_cliprects * + sizeof(drm_clip_rect_t))) + return DRM_ERR(EFAULT); + + ret = i915_dispatch_batchbuffer(dev, &batch); + + sarea_priv->last_dispatch = (int)hw_status[5]; + return ret; +} + +int i915_cmdbuffer(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + dev_priv->sarea_priv; + drm_i915_cmdbuffer_t cmdbuf; + int ret; + + DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data, + sizeof(cmdbuf)); + + DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", + cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_cmdbuffer called without lock held\n"); + return DRM_ERR(EINVAL); + } + + if (cmdbuf.num_cliprects && + DRM_VERIFYAREA_READ(cmdbuf.cliprects, + cmdbuf.num_cliprects * + sizeof(drm_clip_rect_t))) { + DRM_ERROR("Fault accessing cliprects\n"); + return DRM_ERR(EFAULT); + } + + ret = i915_dispatch_cmdbuffer(dev, &cmdbuf); + if (ret) { + DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); + return ret; + } + + sarea_priv->last_dispatch = (int)hw_status[5]; + return 0; +} + +int i915_do_cleanup_pageflip(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + if (dev_priv->current_page != 0) + i915_dispatch_flip(dev); + + return 0; +} + +int i915_flip_bufs(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + DRM_DEBUG("%s\n", __FUNCTION__); + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_flip_buf called without lock held\n"); + return DRM_ERR(EINVAL); + } + + return i915_dispatch_flip(dev); +} + +int i915_getparam(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_getparam_t param; + int value; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data, + sizeof(param)); + + switch (param.param) { + case I915_PARAM_IRQ_ACTIVE: + value = dev->irq ? 1 : 0; + break; + case I915_PARAM_ALLOW_BATCHBUFFER: + value = dev_priv->allow_batchbuffer ? 1 : 0; + break; + default: + DRM_ERROR("Unkown parameter %d\n", param.param); + return DRM_ERR(EINVAL); + } + + if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { + DRM_ERROR("DRM_COPY_TO_USER failed\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + +int i915_setparam(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_setparam_t param; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data, + sizeof(param)); + + switch (param.param) { + case I915_SETPARAM_USE_MI_BATCHBUFFER_START: + dev_priv->use_mi_batchbuffer_start = param.value; + break; + case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: + dev_priv->tex_lru_log_granularity = param.value; + break; + case I915_SETPARAM_ALLOW_BATCHBUFFER: + dev_priv->allow_batchbuffer = param.value; + break; + default: + DRM_ERROR("unknown parameter %d\n", param.param); + return DRM_ERR(EINVAL); + } + + return 0; +} + +static void i915_driver_pretakedown(drm_device_t *dev) +{ + if ( dev->dev_private ) { + drm_i915_private_t *dev_priv = dev->dev_private; + i915_mem_takedown( &(dev_priv->agp_heap) ); + } + i915_dma_cleanup( dev ); +} + +static void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp) +{ + if ( dev->dev_private ) { + drm_i915_private_t *dev_priv = dev->dev_private; + i915_mem_release( dev, filp, dev_priv->agp_heap ); + } +} + +void i915_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED; + dev->fn_tbl.pretakedown = i915_driver_pretakedown; + dev->fn_tbl.prerelease = i915_driver_prerelease; + dev->fn_tbl.irq_preinstall = i915_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = i915_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = i915_driver_irq_uninstall; + dev->fn_tbl.irq_handler = i915_driver_irq_handler; + + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; +} diff -Nru a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/i915_drm.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,154 @@ +#ifndef _I915_DRM_H_ +#define _I915_DRM_H_ + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +#include "drm.h" + +/* Each region is a minimum of 16k, and there are at most 255 of them. + */ +#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use + * of chars for next/prev indices */ +#define I915_LOG_MIN_TEX_REGION_SIZE 14 + +typedef struct _drm_i915_init { + enum { + I915_INIT_DMA = 0x01, + I915_CLEANUP_DMA = 0x02, + I915_RESUME_DMA = 0x03 + } func; + unsigned int mmio_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; + unsigned int back_pitch; + unsigned int depth_pitch; + unsigned int cpp; + unsigned int chipset; +} drm_i915_init_t; + +typedef struct _drm_i915_sarea { + drm_tex_region_t texList[I915_NR_TEX_REGIONS + 1]; + int last_upload; /* last time texture was uploaded */ + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int ctxOwner; /* last context to upload state */ + int texAge; + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; + int pf_current_page; /* which buffer is being displayed? */ + int perf_boxes; /* performance boxes to be displayed */ +} drm_i915_sarea_t; + +/* Flags for perf_boxes + */ +#define I915_BOX_RING_EMPTY 0x1 +#define I915_BOX_FLIP 0x2 +#define I915_BOX_WAIT 0x4 +#define I915_BOX_TEXTURE_LOAD 0x8 +#define I915_BOX_LOST_CONTEXT 0x10 + +/* I915 specific ioctls + * The device specific ioctl range is 0x40 to 0x79. + */ +#define DRM_IOCTL_I915_INIT DRM_IOW( 0x40, drm_i915_init_t) +#define DRM_IOCTL_I915_FLUSH DRM_IO ( 0x41) +#define DRM_IOCTL_I915_FLIP DRM_IO ( 0x42) +#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( 0x43, drm_i915_batchbuffer_t) +#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(0x44, drm_i915_irq_emit_t) +#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( 0x45, drm_i915_irq_wait_t) +#define DRM_IOCTL_I915_GETPARAM DRM_IOWR(0x46, drm_i915_getparam_t) +#define DRM_IOCTL_I915_SETPARAM DRM_IOW( 0x47, drm_i915_setparam_t) +#define DRM_IOCTL_I915_ALLOC DRM_IOWR(0x48, drm_i915_mem_alloc_t) +#define DRM_IOCTL_I915_FREE DRM_IOW( 0x49, drm_i915_mem_free_t) +#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( 0x4a, drm_i915_mem_init_heap_t) +#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( 0x4b, drm_i915_cmdbuffer_t) + +/* Allow drivers to submit batchbuffers directly to hardware, relying + * on the security mechanisms provided by hardware. + */ +typedef struct _drm_i915_batchbuffer { + int start; /* agp offset */ + int used; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */ +} drm_i915_batchbuffer_t; + +/* As above, but pass a pointer to userspace buffer which can be + * validated by the kernel prior to sending to hardware. + */ +typedef struct _drm_i915_cmdbuffer { + char __user *buf; /* pointer to userspace command buffer */ + int sz; /* nr bytes in buf */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */ +} drm_i915_cmdbuffer_t; + +/* Userspace can request & wait on irq's: + */ +typedef struct drm_i915_irq_emit { + int __user *irq_seq; +} drm_i915_irq_emit_t; + +typedef struct drm_i915_irq_wait { + int irq_seq; +} drm_i915_irq_wait_t; + +/* Ioctl to query kernel params: + */ +#define I915_PARAM_IRQ_ACTIVE 1 +#define I915_PARAM_ALLOW_BATCHBUFFER 2 + +typedef struct drm_i915_getparam { + int param; + int __user *value; +} drm_i915_getparam_t; + +/* Ioctl to set kernel params: + */ +#define I915_SETPARAM_USE_MI_BATCHBUFFER_START 1 +#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2 +#define I915_SETPARAM_ALLOW_BATCHBUFFER 3 + +typedef struct drm_i915_setparam { + int param; + int value; +} drm_i915_setparam_t; + +/* A memory manager for regions of shared memory: + */ +#define I915_MEM_REGION_AGP 1 + +typedef struct drm_i915_mem_alloc { + int region; + int alignment; + int size; + int __user *region_offset; /* offset from start of fb or agp */ +} drm_i915_mem_alloc_t; + +typedef struct drm_i915_mem_free { + int region; + int region_offset; +} drm_i915_mem_free_t; + +typedef struct drm_i915_mem_init_heap { + int region; + int size; + int start; +} drm_i915_mem_init_heap_t; + +#endif /* _I915_DRM_H_ */ diff -Nru a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/i915_drv.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,17 @@ +/* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*- + */ + +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +#include "drm_core.h" diff -Nru a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/i915_drv.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,219 @@ +/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef _I915_DRV_H_ +#define _I915_DRV_H_ + +typedef struct _drm_i915_ring_buffer { + int tail_mask; + unsigned long Start; + unsigned long End; + unsigned long Size; + u8 *virtual_start; + int head; + int tail; + int space; + drm_local_map_t map; +} drm_i915_ring_buffer_t; + +struct mem_block { + struct mem_block *next; + struct mem_block *prev; + int start; + int size; + DRMFILE filp; /* 0: free, -1: heap, other: real files */ +}; + +typedef struct drm_i915_private { + drm_local_map_t *sarea; + drm_local_map_t *mmio_map; + + drm_i915_sarea_t *sarea_priv; + drm_i915_ring_buffer_t ring; + + void *hw_status_page; + unsigned long counter; + dma_addr_t dma_status_page; + + int back_offset; + int front_offset; + int current_page; + int page_flipping; + int use_mi_batchbuffer_start; + + wait_queue_head_t irq_queue; + atomic_t irq_received; + atomic_t irq_emitted; + + int tex_lru_log_granularity; + int allow_batchbuffer; + struct mem_block *agp_heap; +} drm_i915_private_t; + + /* i915_dma.c */ +extern int i915_dma_init(DRM_IOCTL_ARGS); +extern int i915_dma_cleanup(drm_device_t * dev); +extern int i915_flush_ioctl(DRM_IOCTL_ARGS); +extern int i915_batchbuffer(DRM_IOCTL_ARGS); +extern int i915_flip_bufs(DRM_IOCTL_ARGS); +extern int i915_getparam(DRM_IOCTL_ARGS); +extern int i915_setparam(DRM_IOCTL_ARGS); +extern int i915_cmdbuffer(DRM_IOCTL_ARGS); +extern void i915_kernel_lost_context(drm_device_t * dev); + +/* i915_irq.c */ +extern int i915_irq_emit(DRM_IOCTL_ARGS); +extern int i915_irq_wait(DRM_IOCTL_ARGS); +extern int i915_wait_irq(drm_device_t * dev, int irq_nr); +extern int i915_emit_irq(drm_device_t * dev); + +extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); +extern void i915_driver_irq_preinstall(drm_device_t *dev); +extern void i915_driver_irq_postinstall(drm_device_t *dev); +extern void i915_driver_irq_uninstall(drm_device_t *dev); + +/* i915_mem.c */ +extern int i915_mem_alloc(DRM_IOCTL_ARGS); +extern int i915_mem_free(DRM_IOCTL_ARGS); +extern int i915_mem_init_heap(DRM_IOCTL_ARGS); +extern void i915_mem_takedown(struct mem_block **heap); +extern void i915_mem_release(drm_device_t * dev, + DRMFILE filp, struct mem_block *heap); + +#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) +#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val) +#define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg) +#define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val) + +#define I915_VERBOSE 0 + +#define RING_LOCALS unsigned int outring, ringmask, outcount; \ + volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I915_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i915_wait_ring(dev, n*4, __FUNCTION__); \ + outcount = 0; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define OUT_RING(n) do { \ + if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outcount++; \ + outring += 4; \ + outring &= ringmask; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \ + dev_priv->ring.tail = outring; \ + dev_priv->ring.space -= outcount * 4; \ + I915_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD (7<<23) +#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + +#define BB1_START_ADDR_MASK (~0x7) +#define BB1_PROTECTED (1<<0) +#define BB1_UNPROTECTED (0<<0) +#define BB2_END_ADDR_MASK (~0x7) + +#define I915REG_HWSTAM 0x02098 +#define I915REG_INT_IDENTITY_R 0x020a4 +#define I915REG_INT_MASK_R 0x020a8 +#define I915REG_INT_ENABLE_R 0x020a0 + +#define SRX_INDEX 0x3c4 +#define SRX_DATA 0x3c5 +#define SR01 1 +#define SR01_SCREEN_OFF (1<<5) + +#define PPCR 0x61204 +#define PPCR_ON (1<<0) + +#define ADPA 0x61100 +#define ADPA_DPMS_MASK (~(3<<10)) +#define ADPA_DPMS_ON (0<<10) +#define ADPA_DPMS_SUSPEND (1<<10) +#define ADPA_DPMS_STANDBY (2<<10) +#define ADPA_DPMS_OFF (3<<10) + +#define NOPID 0x2094 +#define LP_RING 0x2030 +#define HP_RING 0x2040 +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x001FFFF8 +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_START 0x08 +#define START_ADDR 0x0xFFFFF000 +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x001FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) + +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) + +#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) + +#define MI_BATCH_BUFFER ((0x30<<23)|1) +#define MI_BATCH_BUFFER_START (0x31<<23) +#define MI_BATCH_BUFFER_END (0xA<<23) +#define MI_BATCH_NON_SECURE (1) + +#define MI_WAIT_FOR_EVENT ((0x3<<23)) +#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) +#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) + +#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23)) + +#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) +#define ASYNC_FLIP (1<<22) + +#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) + +#endif diff -Nru a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/i915_irq.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,165 @@ +/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +#define USER_INT_FLAG 0x2 +#define MAX_NOPID ((u32)~0) +#define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5]) + +irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) +{ + drm_device_t *dev = (drm_device_t *) arg; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u16 temp; + + temp = I915_READ16(I915REG_INT_IDENTITY_R); + temp &= USER_INT_FLAG; + + DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); + + if (temp == 0) + return IRQ_NONE; + + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + DRM_WAKEUP(&dev_priv->irq_queue); + + return IRQ_HANDLED; +} + +int i915_emit_irq(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 ret; + RING_LOCALS; + + i915_kernel_lost_context(dev); + + DRM_DEBUG("%s\n", __FUNCTION__); + + ret = dev_priv->counter; + + BEGIN_LP_RING(2); + OUT_RING(0); + OUT_RING(GFX_OP_USER_INTERRUPT); + ADVANCE_LP_RING(); + + return ret; +} + +int i915_wait_irq(drm_device_t * dev, int irq_nr) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int ret = 0; + + DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr, + READ_BREADCRUMB(dev_priv)); + + if (READ_BREADCRUMB(dev_priv) >= irq_nr) + return 0; + + dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + + DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, + READ_BREADCRUMB(dev_priv) >= irq_nr); + + if (ret == DRM_ERR(EBUSY)) { + DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", + __FUNCTION__, + READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); + } + + dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + return ret; +} + +/* Needs the lock as it touches the ring. + */ +int i915_irq_emit(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_emit_t emit; + int result; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_irq_emit called without lock held\n"); + return DRM_ERR(EINVAL); + } + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data, + sizeof(emit)); + + result = i915_emit_irq(dev); + + if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + +/* Doesn't need the hardware lock. + */ +int i915_irq_wait(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_wait_t irqwait; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data, + sizeof(irqwait)); + + return i915_wait_irq(dev, irqwait.irq_seq); +} + +/* drm_dma.h hooks +*/ +void i915_driver_irq_preinstall(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + I915_WRITE16(I915REG_HWSTAM, 0xfffe); + I915_WRITE16(I915REG_INT_MASK_R, 0x0); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); +} + +void i915_driver_irq_postinstall(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG); + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); +} + +void i915_driver_irq_uninstall(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (!dev_priv) + return; + + I915_WRITE16(I915REG_HWSTAM, 0xffff); + I915_WRITE16(I915REG_INT_MASK_R, 0xffff); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); +} diff -Nru a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/drm/i915_mem.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,347 @@ +/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* This memory manager is integrated into the global/local lru + * mechanisms used by the clients. Specifically, it operates by + * setting the 'in_use' fields of the global LRU to indicate whether + * this region is privately allocated to a client. + * + * This does require the client to actually respect that field. + * + * Currently no effort is made to allocate 'private' memory in any + * clever way - the LRU information isn't used to determine which + * block to allocate, and the ring is drained prior to allocations -- + * in other words allocation is expensive. + */ +static void mark_block(drm_device_t * dev, struct mem_block *p, int in_use) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_tex_region_t *list; + unsigned shift, nr; + unsigned start; + unsigned end; + unsigned i; + int age; + + shift = dev_priv->tex_lru_log_granularity; + nr = I915_NR_TEX_REGIONS; + + start = p->start >> shift; + end = (p->start + p->size - 1) >> shift; + + age = ++sarea_priv->texAge; + list = sarea_priv->texList; + + /* Mark the regions with the new flag and update their age. Move + * them to head of list to preserve LRU semantics. + */ + for (i = start; i <= end; i++) { + list[i].in_use = in_use; + list[i].age = age; + + /* remove_from_list(i) + */ + list[(unsigned)list[i].next].prev = list[i].prev; + list[(unsigned)list[i].prev].next = list[i].next; + + /* insert_at_head(list, i) + */ + list[i].prev = nr; + list[i].next = list[nr].next; + list[(unsigned)list[nr].next].prev = i; + list[nr].next = i; + } +} + +/* Very simple allocator for agp memory, working on a static range + * already mapped into each client's address space. + */ + +static struct mem_block *split_block(struct mem_block *p, int start, int size, + DRMFILE filp) +{ + /* Maybe cut off the start of an existing block */ + if (start > p->start) { + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); + if (!newblock) + goto out; + newblock->start = start; + newblock->size = p->size - (start - p->start); + newblock->filp = NULL; + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + p->size -= newblock->size; + p = newblock; + } + + /* Maybe cut off the end of an existing block */ + if (size < p->size) { + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); + if (!newblock) + goto out; + newblock->start = start + size; + newblock->size = p->size - size; + newblock->filp = NULL; + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + p->size = size; + } + + out: + /* Our block is in the middle */ + p->filp = filp; + return p; +} + +static struct mem_block *alloc_block(struct mem_block *heap, int size, + int align2, DRMFILE filp) +{ + struct mem_block *p; + int mask = (1 << align2) - 1; + + for (p = heap->next; p != heap; p = p->next) { + int start = (p->start + mask) & ~mask; + if (p->filp == NULL && start + size <= p->start + p->size) + return split_block(p, start, size, filp); + } + + return NULL; +} + +static struct mem_block *find_block(struct mem_block *heap, int start) +{ + struct mem_block *p; + + for (p = heap->next; p != heap; p = p->next) + if (p->start == start) + return p; + + return NULL; +} + +static void free_block(struct mem_block *p) +{ + p->filp = NULL; + + /* Assumes a single contiguous range. Needs a special filp in + * 'heap' to stop it being subsumed. + */ + if (p->next->filp == NULL) { + struct mem_block *q = p->next; + p->size += q->size; + p->next = q->next; + p->next->prev = p; + DRM_FREE(q, sizeof(*q)); + } + + if (p->prev->filp == NULL) { + struct mem_block *q = p->prev; + q->size += p->size; + q->next = p->next; + q->next->prev = q; + DRM_FREE(p, sizeof(*q)); + } +} + +/* Initialize. How to check for an uninitialized heap? + */ +static int init_heap(struct mem_block **heap, int start, int size) +{ + struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks)); + + if (!blocks) + return -ENOMEM; + + *heap = DRM_MALLOC(sizeof(**heap)); + if (!*heap) { + DRM_FREE(blocks, sizeof(*blocks)); + return -ENOMEM; + } + + blocks->start = start; + blocks->size = size; + blocks->filp = NULL; + blocks->next = blocks->prev = *heap; + + memset(*heap, 0, sizeof(**heap)); + (*heap)->filp = (DRMFILE) - 1; + (*heap)->next = (*heap)->prev = blocks; + return 0; +} + +/* Free all blocks associated with the releasing file. + */ +void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap) +{ + struct mem_block *p; + + if (!heap || !heap->next) + return; + + for (p = heap->next; p != heap; p = p->next) { + if (p->filp == filp) { + p->filp = NULL; + mark_block(dev, p, 0); + } + } + + /* Assumes a single contiguous range. Needs a special filp in + * 'heap' to stop it being subsumed. + */ + for (p = heap->next; p != heap; p = p->next) { + while (p->filp == NULL && p->next->filp == NULL) { + struct mem_block *q = p->next; + p->size += q->size; + p->next = q->next; + p->next->prev = p; + DRM_FREE(q, sizeof(*q)); + } + } +} + +/* Shutdown. + */ +void i915_mem_takedown(struct mem_block **heap) +{ + struct mem_block *p; + + if (!*heap) + return; + + for (p = (*heap)->next; p != *heap;) { + struct mem_block *q = p; + p = p->next; + DRM_FREE(q, sizeof(*q)); + } + + DRM_FREE(*heap, sizeof(**heap)); + *heap = NULL; +} + +static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region) +{ + switch (region) { + case I915_MEM_REGION_AGP: + return &dev_priv->agp_heap; + default: + return NULL; + } +} + +/* IOCTL HANDLERS */ + +int i915_mem_alloc(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_mem_alloc_t alloc; + struct mem_block *block, **heap; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data, + sizeof(alloc)); + + heap = get_heap(dev_priv, alloc.region); + if (!heap || !*heap) + return DRM_ERR(EFAULT); + + /* Make things easier on ourselves: all allocations at least + * 4k aligned. + */ + if (alloc.alignment < 12) + alloc.alignment = 12; + + block = alloc_block(*heap, alloc.size, alloc.alignment, filp); + + if (!block) + return DRM_ERR(ENOMEM); + + mark_block(dev, block, 1); + + if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + +int i915_mem_free(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_mem_free_t memfree; + struct mem_block *block, **heap; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data, + sizeof(memfree)); + + heap = get_heap(dev_priv, memfree.region); + if (!heap || !*heap) + return DRM_ERR(EFAULT); + + block = find_block(*heap, memfree.region_offset); + if (!block) + return DRM_ERR(EFAULT); + + if (block->filp != filp) + return DRM_ERR(EPERM); + + mark_block(dev, block, 0); + free_block(block); + return 0; +} + +int i915_mem_init_heap(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_mem_init_heap_t initheap; + struct mem_block **heap; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(initheap, + (drm_i915_mem_init_heap_t __user *) data, + sizeof(initheap)); + + heap = get_heap(dev_priv, initheap.region); + if (!heap) + return DRM_ERR(EFAULT); + + if (*heap) { + DRM_ERROR("heap already initialized?"); + return DRM_ERR(EFAULT); + } + + return init_heap(heap, initheap.start, initheap.size); +} diff -Nru a/drivers/char/drm/mga.h b/drivers/char/drm/mga.h --- a/drivers/char/drm/mga.h 2004-10-18 14:57:19 -07:00 +++ b/drivers/char/drm/mga.h 2004-10-18 14:57:19 -07:00 @@ -36,10 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." @@ -63,36 +59,5 @@ [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_GETPARAM)]= { mga_getparam, 1, 0 }, - -#define __HAVE_COUNTERS 3 -#define __HAVE_COUNTER6 _DRM_STAT_IRQ -#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY -#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY - -/* Driver customization: - */ -#define DRIVER_PRETAKEDOWN() do { \ - mga_do_cleanup_dma( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - drm_mga_private_t *dev_priv = dev->dev_private; \ - return mga_do_wait_for_idle( dev_priv ); \ -} while (0) - -/* Buffer customization: - */ -#define DRIVER_BUF_PRIV_T drm_mga_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_mga_private_t *)((dev)->dev_private))->buffers #endif diff -Nru a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c --- a/drivers/char/drm/mga_dma.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/drm/mga_dma.c 2004-10-18 14:56:50 -07:00 @@ -500,7 +500,7 @@ return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio) { DRM_ERROR( "failed to find mmio region!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -508,7 +508,7 @@ mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->status, init->status_offset ); + dev_priv->status = drm_core_findmap(dev, init->status_offset); if(!dev_priv->status) { DRM_ERROR( "failed to find status page!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -516,8 +516,7 @@ mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - - DRM_FIND_MAP( dev_priv->warp, init->warp_offset ); + dev_priv->warp = drm_core_findmap(dev, init->warp_offset); if(!dev_priv->warp) { DRM_ERROR( "failed to find warp microcode region!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -525,7 +524,7 @@ mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->primary, init->primary_offset ); + dev_priv->primary = drm_core_findmap(dev, init->primary_offset); if(!dev_priv->primary) { DRM_ERROR( "failed to find primary dma region!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -533,8 +532,8 @@ mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - if(!dev_priv->buffers) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { DRM_ERROR( "failed to find dma buffer region!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; @@ -546,13 +545,13 @@ (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DRM_IOREMAP( dev_priv->warp, dev ); - DRM_IOREMAP( dev_priv->primary, dev ); - DRM_IOREMAP( dev_priv->buffers, dev ); + drm_core_ioremap( dev_priv->warp, dev ); + drm_core_ioremap( dev_priv->primary, dev ); + drm_core_ioremap( dev->agp_buffer_map, dev ); if(!dev_priv->warp->handle || !dev_priv->primary->handle || - !dev_priv->buffers->handle ) { + !dev->agp_buffer_map->handle ) { DRM_ERROR( "failed to ioremap agp regions!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; @@ -631,23 +630,21 @@ { DRM_DEBUG( "\n" ); -#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_enabled ) DRM(irq_uninstall)(dev); -#endif if ( dev->dev_private ) { drm_mga_private_t *dev_priv = dev->dev_private; if ( dev_priv->warp != NULL ) - DRM_IOREMAPFREE( dev_priv->warp, dev ); + drm_core_ioremapfree( dev_priv->warp, dev ); if ( dev_priv->primary != NULL ) - DRM_IOREMAPFREE( dev_priv->primary, dev ); - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + drm_core_ioremapfree( dev_priv->primary, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); if ( dev_priv->head != NULL ) { mga_freelist_cleanup( dev ); @@ -799,4 +796,32 @@ DRM_COPY_TO_USER_IOCTL( argp, d, sizeof(d) ); return ret; +} + +static void mga_driver_pretakedown(drm_device_t *dev) +{ + mga_do_cleanup_dma( dev ); +} + +static int mga_driver_dma_quiescent(drm_device_t *dev) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + return mga_do_wait_for_idle( dev_priv ); +} + +void mga_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL; + dev->fn_tbl.pretakedown = mga_driver_pretakedown; + dev->fn_tbl.dma_quiescent = mga_driver_dma_quiescent; + dev->fn_tbl.vblank_wait = mga_driver_vblank_wait; + dev->fn_tbl.irq_preinstall = mga_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = mga_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = mga_driver_irq_uninstall; + dev->fn_tbl.irq_handler = mga_driver_irq_handler; + + dev->counters += 3; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; } diff -Nru a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c --- a/drivers/char/drm/mga_drv.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/drm/mga_drv.c 2004-10-18 14:56:29 -07:00 @@ -35,19 +35,4 @@ #include "drm.h" #include "mga_drm.h" #include "mga_drv.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#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" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff -Nru a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h --- a/drivers/char/drm/mga_drv.h 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/drm/mga_drv.h 2004-10-18 14:57:03 -07:00 @@ -130,6 +130,12 @@ extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv ); extern int mga_warp_init( drm_mga_private_t *dev_priv ); +extern int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); +extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ); +extern void mga_driver_irq_preinstall( drm_device_t *dev ); +extern void mga_driver_irq_postinstall( drm_device_t *dev ); +extern void mga_driver_irq_uninstall( drm_device_t *dev ); + #define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER() #if defined(__linux__) && defined(__alpha__) diff -Nru a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c --- a/drivers/char/drm/mga_irq.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/char/drm/mga_irq.c 2004-10-18 14:55:53 -07:00 @@ -36,7 +36,7 @@ #include "mga_drm.h" #include "mga_drv.h" -irqreturn_t mga_irq_handler( DRM_IRQ_ARGS ) +irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_mga_private_t *dev_priv = @@ -56,7 +56,7 @@ return IRQ_NONE; } -int mga_vblank_wait(drm_device_t *dev, unsigned int *sequence) +int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) { unsigned int cur_vblank; int ret = 0; diff -Nru a/drivers/char/drm/r128.h b/drivers/char/drm/r128.h --- a/drivers/char/drm/r128.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/drm/r128.h 2004-10-18 14:56:28 -07:00 @@ -36,13 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 -#define __HAVE_SG 1 -#define __HAVE_PCI_DMA 1 - #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." #define DRIVER_NAME "r128" @@ -78,43 +71,5 @@ [DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_GETPARAM)] = { r128_getparam, 1, 0 }, - -/* Driver customization: - */ -#define DRIVER_PRERELEASE() do { \ - if ( dev->dev_private ) { \ - drm_r128_private_t *dev_priv = dev->dev_private; \ - if ( dev_priv->page_flipping ) { \ - r128_do_cleanup_pageflip( dev ); \ - } \ - } \ -} while (0) - -#define DRIVER_PRETAKEDOWN() do { \ - r128_do_cleanup_cce( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 - -#if 0 -/* GH: Remove this for now... */ -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - drm_r128_private_t *dev_priv = dev->dev_private; \ - return r128_do_cce_idle( dev_priv ); \ -} while (0) -#endif - -/* Buffer customization: - */ -#define DRIVER_BUF_PRIV_T drm_r128_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_r128_private_t *)((dev)->dev_private))->buffers #endif diff -Nru a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c --- a/drivers/char/drm/r128_cce.c 2004-10-18 14:56:11 -07:00 +++ b/drivers/char/drm/r128_cce.c 2004-10-18 14:56:11 -07:00 @@ -322,7 +322,7 @@ /* The manual (p. 2) says this address is in "VM space". This * means it's an offset from the start of AGP space. */ -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) ring_start = dev_priv->cce_ring->offset - dev->agp->base; else @@ -467,29 +467,29 @@ return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->cce_ring, init->ring_offset ); + dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset); if(!dev_priv->cce_ring) { DRM_ERROR("could not find cce ring region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); + dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); if(!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - if(!dev_priv->buffers) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); @@ -497,8 +497,7 @@ } if ( !dev_priv->is_pci ) { - DRM_FIND_MAP( dev_priv->agp_textures, - init->agp_textures_offset ); + dev_priv->agp_textures = drm_core_findmap(dev, init->agp_textures_offset); if(!dev_priv->agp_textures) { DRM_ERROR("could not find agp texture region!\n"); dev->dev_private = (void *)dev_priv; @@ -511,14 +510,14 @@ (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cce_ring, dev ); - DRM_IOREMAP( dev_priv->ring_rptr, dev ); - DRM_IOREMAP( dev_priv->buffers, dev ); + drm_core_ioremap( dev_priv->cce_ring, dev ); + drm_core_ioremap( dev_priv->ring_rptr, dev ); + drm_core_ioremap( dev->agp_buffer_map, dev ); if(!dev_priv->cce_ring->handle || !dev_priv->ring_rptr->handle || - !dev_priv->buffers->handle) { + !dev->agp_buffer_map->handle) { DRM_ERROR("Could not ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); @@ -531,10 +530,10 @@ (void *)dev_priv->cce_ring->offset; dev_priv->ring_rptr->handle = (void *)dev_priv->ring_rptr->offset; - dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; + dev->agp_buffer_map->handle = (void *)dev->agp_buffer_map->offset; } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) dev_priv->cce_buffers_offset = dev->agp->base; else @@ -559,7 +558,7 @@ R128_WRITE( R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( dev_priv->is_pci ) { #endif if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, @@ -570,7 +569,7 @@ return DRM_ERR(ENOMEM); } R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP } #endif @@ -587,25 +586,23 @@ int r128_do_cleanup_cce( drm_device_t *dev ) { -#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_enabled ) DRM(irq_uninstall)(dev); -#endif if ( dev->dev_private ) { drm_r128_private_t *dev_priv = dev->dev_private; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { if ( dev_priv->cce_ring != NULL ) - DRM_IOREMAPFREE( dev_priv->cce_ring, dev ); + drm_core_ioremapfree( dev_priv->cce_ring, dev ); if ( dev_priv->ring_rptr != NULL ) - DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + drm_core_ioremapfree( dev_priv->ring_rptr, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); } else #endif { diff -Nru a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c --- a/drivers/char/drm/r128_drv.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/char/drm/r128_drv.c 2004-10-18 14:56:27 -07:00 @@ -37,20 +37,4 @@ #include "r128_drv.h" #include "ati_pcigart.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#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" -#include "drm_vm.h" -#include "drm_stub.h" -#include "drm_scatter.h" +#include "drm_core.h" diff -Nru a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h --- a/drivers/char/drm/r128_drv.h 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/drm/r128_drv.h 2004-10-18 14:57:05 -07:00 @@ -100,7 +100,6 @@ drm_local_map_t *mmio; drm_local_map_t *cce_ring; drm_local_map_t *ring_rptr; - drm_local_map_t *buffers; drm_local_map_t *agp_textures; } drm_r128_private_t; @@ -143,6 +142,12 @@ extern int r128_cce_stipple( DRM_IOCTL_ARGS ); extern int r128_cce_indirect( DRM_IOCTL_ARGS ); +extern int r128_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); + +extern irqreturn_t r128_driver_irq_handler( DRM_IRQ_ARGS ); +extern void r128_driver_irq_preinstall( drm_device_t *dev ); +extern void r128_driver_irq_postinstall( drm_device_t *dev ); +extern void r128_driver_irq_uninstall( drm_device_t *dev ); /* Register definitions, register access macros and drmAddMap constants * for Rage 128 kernel driver. diff -Nru a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c --- a/drivers/char/drm/r128_irq.c 2004-10-18 14:57:18 -07:00 +++ b/drivers/char/drm/r128_irq.c 2004-10-18 14:57:18 -07:00 @@ -36,7 +36,7 @@ #include "r128_drm.h" #include "r128_drv.h" -irqreturn_t r128_irq_handler( DRM_IRQ_ARGS ) +irqreturn_t r128_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_r128_private_t *dev_priv = @@ -56,7 +56,7 @@ return IRQ_NONE; } -int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) +int r128_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) { unsigned int cur_vblank; int ret = 0; diff -Nru a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c --- a/drivers/char/drm/r128_state.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/char/drm/r128_state.c 2004-10-18 14:56:13 -07:00 @@ -667,7 +667,7 @@ */ if ( dwords & 1 ) { u32 *data = (u32 *) - ((char *)dev_priv->buffers->handle + ((char *)dev->agp_buffer_map->handle + buf->offset + start); data[dwords++] = cpu_to_le32( R128_CCE_PACKET2 ); } @@ -713,7 +713,7 @@ drm_r128_buf_priv_t *buf_priv = buf->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; int format = sarea_priv->vc_format; - int offset = dev_priv->buffers->offset - dev_priv->cce_buffers_offset; + int offset = dev->agp_buffer_map->offset - dev_priv->cce_buffers_offset; int prim = buf_priv->prim; u32 *data; int dwords; @@ -733,7 +733,7 @@ dwords = (end - start + 3) / sizeof(u32); - data = (u32 *)((char *)dev_priv->buffers->handle + data = (u32 *)((char *)dev->agp_buffer_map->handle + buf->offset + start); data[0] = cpu_to_le32( CCE_PACKET3( R128_3D_RNDR_GEN_INDX_PRIM, @@ -857,7 +857,7 @@ dwords = (blit->width * blit->height) >> dword_shift; - data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); + data = (u32 *)((char *)dev->agp_buffer_map->handle + buf->offset); data[0] = cpu_to_le32( CCE_PACKET3( R128_CNTL_HOSTDATA_BLT, dwords + 6 ) ); data[1] = cpu_to_le32( (R128_GMC_DST_PITCH_OFFSET_CNTL | @@ -1693,4 +1693,32 @@ } return 0; +} + +static void r128_driver_prerelease(drm_device_t *dev, DRMFILE filp) +{ + if ( dev->dev_private ) { + drm_r128_private_t *dev_priv = dev->dev_private; + if ( dev_priv->page_flipping ) { + r128_do_cleanup_pageflip( dev ); + } + } +} + +static void r128_driver_pretakedown(drm_device_t *dev) +{ + r128_do_cleanup_cce( dev ); +} + +void r128_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL; + dev->dev_priv_size = sizeof(drm_r128_buf_priv_t); + dev->fn_tbl.prerelease = r128_driver_prerelease; + dev->fn_tbl.pretakedown = r128_driver_pretakedown; + dev->fn_tbl.vblank_wait = r128_driver_vblank_wait; + dev->fn_tbl.irq_preinstall = r128_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = r128_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = r128_driver_irq_uninstall; + dev->fn_tbl.irq_handler = r128_driver_irq_handler; } diff -Nru a/drivers/char/drm/radeon.h b/drivers/char/drm/radeon.h --- a/drivers/char/drm/radeon.h 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/drm/radeon.h 2004-10-18 14:57:03 -07:00 @@ -37,12 +37,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 -#define __HAVE_SG 1 -#define __HAVE_PCI_DMA 1 #define DRIVER_AUTHOR "Gareth Hughes, Keith Whitwell, others." @@ -114,60 +108,5 @@ [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_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 - * - Free any alloced GART memory. - * - * DRM infrastructure takes care of reclaiming dma buffers. - */ -#define DRIVER_PRERELEASE() \ -do { \ - if ( dev->dev_private ) { \ - drm_radeon_private_t *dev_priv = dev->dev_private; \ - if ( dev_priv->page_flipping ) { \ - radeon_do_cleanup_pageflip( dev ); \ - } \ - radeon_mem_release( filp, dev_priv->gart_heap ); \ - radeon_mem_release( filp, dev_priv->fb_heap ); \ - } \ -} while (0) - -/* When the last client dies, shut down the CP and free dev->dev_priv. - */ -/* #define __HAVE_RELEASE 1 */ -#define DRIVER_PRETAKEDOWN() \ -do { \ - radeon_do_release( dev ); \ -} while (0) - - - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 - - -/* Buffer customization: - */ -#define DRIVER_BUF_PRIV_T drm_radeon_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_radeon_private_t *)((dev)->dev_private))->buffers #endif diff -Nru a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c --- a/drivers/char/drm/radeon_cp.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/drm/radeon_cp.c 2004-10-18 14:56:17 -07:00 @@ -858,7 +858,7 @@ ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 ) | ( dev_priv->fb_location >> 16 ) ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { RADEON_WRITE( RADEON_MC_AGP_LOCATION, (((dev_priv->gart_vm_start - 1 + @@ -885,7 +885,7 @@ SET_RING_HEAD( dev_priv, cur_read_ptr ); dev_priv->ring.tail = cur_read_ptr; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset @@ -1118,29 +1118,29 @@ return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->cp_ring, init->ring_offset ); + dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset); if(!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); + dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); if(!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - if(!dev_priv->buffers) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); @@ -1148,7 +1148,7 @@ } if ( init->gart_textures_offset ) { - DRM_FIND_MAP( dev_priv->gart_textures, init->gart_textures_offset ); + dev_priv->gart_textures = drm_core_findmap(dev, init->gart_textures_offset); if ( !dev_priv->gart_textures ) { DRM_ERROR("could not find GART texture region!\n"); dev->dev_private = (void *)dev_priv; @@ -1161,14 +1161,14 @@ (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cp_ring, dev ); - DRM_IOREMAP( dev_priv->ring_rptr, dev ); - DRM_IOREMAP( dev_priv->buffers, dev ); + drm_core_ioremap( dev_priv->cp_ring, dev ); + drm_core_ioremap( dev_priv->ring_rptr, dev ); + drm_core_ioremap( dev->agp_buffer_map, dev ); if(!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || - !dev_priv->buffers->handle) { + !dev->agp_buffer_map->handle) { DRM_ERROR("could not find ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); @@ -1181,14 +1181,14 @@ (void *)dev_priv->cp_ring->offset; dev_priv->ring_rptr->handle = (void *)dev_priv->ring_rptr->offset; - dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; + dev->agp_buffer_map->handle = (void *)dev->agp_buffer_map->offset; DRM_DEBUG( "dev_priv->cp_ring->handle %p\n", dev_priv->cp_ring->handle ); DRM_DEBUG( "dev_priv->ring_rptr->handle %p\n", dev_priv->ring_rptr->handle ); - DRM_DEBUG( "dev_priv->buffers->handle %p\n", - dev_priv->buffers->handle ); + DRM_DEBUG( "dev->agp_buffer_map->handle %p\n", + dev->agp_buffer_map->handle ); } dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION ) @@ -1211,14 +1211,14 @@ dev_priv->gart_vm_start = dev_priv->fb_location + RADEON_READ( RADEON_CONFIG_APER_SIZE ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) - dev_priv->gart_buffers_offset = (dev_priv->buffers->offset + dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - dev->agp->base + dev_priv->gart_vm_start); else #endif - dev_priv->gart_buffers_offset = (dev_priv->buffers->offset + dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - dev->sg->handle + dev_priv->gart_vm_start); @@ -1240,7 +1240,7 @@ dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { /* Turn off PCI GART */ radeon_set_pcigart( dev_priv, 0 ); @@ -1275,25 +1275,23 @@ { DRM_DEBUG( "\n" ); -#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_enabled ) DRM(irq_uninstall)(dev); -#endif if ( dev->dev_private ) { drm_radeon_private_t *dev_priv = dev->dev_private; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { if ( dev_priv->cp_ring != NULL ) - DRM_IOREMAPFREE( dev_priv->cp_ring, dev ); + drm_core_ioremapfree( dev_priv->cp_ring, dev ); if ( dev_priv->ring_rptr != NULL ) - DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + drm_core_ioremapfree( dev_priv->ring_rptr, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); } else #endif { @@ -1329,7 +1327,7 @@ DRM_DEBUG("Starting radeon_do_resume_cp()\n"); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { /* Turn off PCI GART */ radeon_set_pcigart( dev_priv, 0 ); diff -Nru a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c --- a/drivers/char/drm/radeon_drv.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/drm/radeon_drv.c 2004-10-18 14:56:48 -07:00 @@ -38,20 +38,4 @@ #include "radeon_drv.h" #include "ati_pcigart.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#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" -#include "drm_vm.h" -#include "drm_stub.h" -#include "drm_scatter.h" +#include "drm_core.h" diff -Nru a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h --- a/drivers/char/drm/radeon_drv.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/drm/radeon_drv.h 2004-10-18 14:56:32 -07:00 @@ -60,6 +60,9 @@ u32 se_cntl; } drm_radeon_depth_clear_t; +struct drm_radeon_driver_file_fields { + int64_t radeon_fb_delta; +}; struct mem_block { struct mem_block *next; @@ -138,7 +141,6 @@ drm_local_map_t *mmio; drm_local_map_t *cp_ring; drm_local_map_t *ring_rptr; - drm_local_map_t *buffers; drm_local_map_t *gart_textures; struct mem_block *gart_heap; @@ -203,6 +205,11 @@ extern int radeon_emit_irq(drm_device_t *dev); extern void radeon_do_release(drm_device_t *dev); +extern int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); +extern irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS ); +extern void radeon_driver_irq_preinstall( drm_device_t *dev ); +extern void radeon_driver_irq_postinstall( drm_device_t *dev ); +extern void radeon_driver_irq_uninstall( drm_device_t *dev ); /* Flags for stats.boxes */ diff -Nru a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c --- a/drivers/char/drm/radeon_irq.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/drm/radeon_irq.c 2004-10-18 14:57:04 -07:00 @@ -54,7 +54,7 @@ * tied to dma at all, this is just a hangover from dri prehistory. */ -irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) +irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_radeon_private_t *dev_priv = @@ -141,7 +141,7 @@ } -int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) +int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; diff -Nru a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c --- a/drivers/char/drm/radeon_state.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/drm/radeon_state.c 2004-10-18 14:56:50 -07:00 @@ -43,12 +43,14 @@ drm_file_t *filp_priv, u32 *offset ) { u32 off = *offset; + struct drm_radeon_driver_file_fields *radeon_priv; if ( off >= dev_priv->fb_location && off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) ) return 0; - off += filp_priv->radeon_fb_delta; + radeon_priv = filp_priv->driver_priv; + off += radeon_priv->radeon_fb_delta; DRM_DEBUG( "offset fixed up to 0x%x\n", off ); @@ -1247,7 +1249,7 @@ */ if ( dwords & 1 ) { u32 *data = (u32 *) - ((char *)dev_priv->buffers->handle + ((char *)dev->agp_buffer_map->handle + buf->offset + start); data[dwords++] = RADEON_CP_PACKET2; } @@ -1301,7 +1303,7 @@ dwords = (prim->finish - prim->start + 3) / sizeof(u32); - data = (u32 *)((char *)dev_priv->buffers->handle + + data = (u32 *)((char *)dev->agp_buffer_map->handle + elt_buf->offset + prim->start); data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 ); @@ -1445,7 +1447,7 @@ /* Dispatch the indirect buffer. */ - buffer = (u32*)((char*)dev_priv->buffers->handle + buf->offset); + buffer = (u32*)((char*)dev->agp_buffer_map->handle + buf->offset); dwords = size / 4; buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | @@ -1665,11 +1667,6 @@ LOCK_TEST_WITH_RETURN( dev, filp ); - 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( vertex, (drm_radeon_vertex_t __user *)data, @@ -2525,6 +2522,7 @@ drm_radeon_private_t *dev_priv = dev->dev_private; drm_file_t *filp_priv; drm_radeon_setparam_t sp; + struct drm_radeon_driver_file_fields *radeon_priv; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -2538,7 +2536,8 @@ switch( sp.param ) { case RADEON_SETPARAM_FB_LOCATION: - filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value; + radeon_priv = filp_priv->driver_priv; + radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value; break; default: DRM_DEBUG( "Invalid parameter %d\n", sp.param ); @@ -2546,4 +2545,68 @@ } return 0; +} + +/* When a client dies: + * - Check for and clean up flipped page state + * - Free any alloced GART memory. + * + * DRM infrastructure takes care of reclaiming dma buffers. + */ +static void radeon_driver_prerelease(drm_device_t *dev, DRMFILE filp) +{ + if ( dev->dev_private ) { + drm_radeon_private_t *dev_priv = dev->dev_private; + if ( dev_priv->page_flipping ) { + radeon_do_cleanup_pageflip( dev ); + } + radeon_mem_release( filp, dev_priv->gart_heap ); + radeon_mem_release( filp, dev_priv->fb_heap ); + } +} + +static void radeon_driver_pretakedown(drm_device_t *dev) +{ + radeon_do_release(dev); +} + +static int radeon_driver_open_helper(drm_device_t *dev, drm_file_t *filp_priv) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_driver_file_fields *radeon_priv; + + radeon_priv = (struct drm_radeon_driver_file_fields *)DRM(alloc)(sizeof(*radeon_priv), DRM_MEM_FILES); + + if (!radeon_priv) + return -ENOMEM; + + filp_priv->driver_priv = radeon_priv; + if ( dev_priv ) + radeon_priv->radeon_fb_delta = dev_priv->fb_location; + else + radeon_priv->radeon_fb_delta = 0; + return 0; +} + + +static void radeon_driver_free_filp_priv(drm_device_t *dev, drm_file_t *filp_priv) +{ + struct drm_radeon_driver_file_fields *radeon_priv = filp_priv->driver_priv; + + DRM(free)(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES); +} + +void radeon_driver_register_fns(struct drm_device *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL; + dev->dev_priv_size = sizeof(drm_radeon_buf_priv_t); + dev->fn_tbl.prerelease = radeon_driver_prerelease; + dev->fn_tbl.pretakedown = radeon_driver_pretakedown; + dev->fn_tbl.open_helper = radeon_driver_open_helper; + dev->fn_tbl.free_filp_priv = radeon_driver_free_filp_priv; + dev->fn_tbl.vblank_wait = radeon_driver_vblank_wait; + dev->fn_tbl.irq_preinstall = radeon_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = radeon_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = radeon_driver_irq_uninstall; + dev->fn_tbl.irq_handler = radeon_driver_irq_handler; } diff -Nru a/drivers/char/drm/sis.h b/drivers/char/drm/sis.h --- a/drivers/char/drm/sis.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/drm/sis.h 2004-10-18 14:57:04 -07:00 @@ -41,10 +41,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "SIS" #define DRIVER_NAME "sis" @@ -61,18 +57,5 @@ [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_ALLOC)] = { sis_ioctl_agp_alloc, 1, 0 }, \ [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 __HAVE_COUNTERS 5 - -/* Buffer customization: - */ -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_sis_private_t *)((dev)->dev_private))->buffers - -extern int sis_init_context(int context); -extern int sis_final_context(int context); - -#define DRIVER_CTX_CTOR sis_init_context -#define DRIVER_CTX_DTOR sis_final_context #endif diff -Nru a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c --- a/drivers/char/drm/sis_drv.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/char/drm/sis_drv.c 2004-10-18 14:55:53 -07:00 @@ -31,18 +31,4 @@ #include "sis_drm.h" #include "sis_drv.h" -#include "drm_auth.h" -#include "drm_agpsupport.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff -Nru a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h --- a/drivers/char/drm/sis_drv.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/drm/sis_drv.h 2004-10-18 14:56:17 -07:00 @@ -31,8 +31,6 @@ #include "sis_ds.h" typedef struct drm_sis_private { - drm_map_t *buffers; - memHeap_t *AGPHeap; memHeap_t *FBHeap; } drm_sis_private_t; diff -Nru a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c --- a/drivers/char/drm/sis_mm.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/drm/sis_mm.c 2004-10-18 14:56:48 -07:00 @@ -90,9 +90,10 @@ { drm_sis_mem_t fb; struct sis_memreq req; + drm_sis_mem_t __user *argp = (void __user *)data; int retval = 0; - DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb)); req.size = fb.size; sis_malloc(&req); @@ -111,7 +112,7 @@ fb.free = 0; } - DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb)); + DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb)); DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset); @@ -123,7 +124,7 @@ drm_sis_mem_t fb; int retval = 0; - DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *)data, sizeof(fb)); if (!fb.free) return DRM_ERR(EINVAL); @@ -325,7 +326,7 @@ return 0; } -int sis_init_context(int context) +int sis_init_context(struct drm_device *dev, int context) { int i; @@ -357,7 +358,7 @@ return 1; } -int sis_final_context(int context) +int sis_final_context(struct drm_device *dev, int context) { int i; @@ -402,4 +403,11 @@ } return 1; +} + +void DRM(driver_register_fns)(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR; + dev->fn_tbl.context_ctor = sis_init_context; + dev->fn_tbl.context_dtor = sis_final_context; } diff -Nru a/drivers/char/drm/tdfx.h b/drivers/char/drm/tdfx.h --- a/drivers/char/drm/tdfx.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/drm/tdfx.h 2004-10-18 14:56:32 -07:00 @@ -36,8 +36,6 @@ /* General customization: */ -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "VA Linux Systems Inc." diff -Nru a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c --- a/drivers/char/drm/tdfx_drv.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/drm/tdfx_drv.c 2004-10-18 14:56:32 -07:00 @@ -34,18 +34,10 @@ #include "tdfx.h" #include "drmP.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" +#include "drm_core.h" + +void DRM(driver_register_fns)(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_MTRR; +} -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" diff -Nru a/drivers/char/ds1620.c b/drivers/char/ds1620.c --- a/drivers/char/ds1620.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/ds1620.c 2004-10-18 14:55:54 -07:00 @@ -373,8 +373,7 @@ th_start.hi = 1; ds1620_write_state(&th_start); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2*HZ); + msleep(2000); ds1620_write_state(&th); diff -Nru a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c --- a/drivers/char/dsp56k.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/dsp56k.c 2004-10-18 14:56:32 -07:00 @@ -58,12 +58,6 @@ #define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE) #define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF) -#define wait_some(n) \ -{ \ - set_current_state(TASK_INTERRUPTIBLE); \ - schedule_timeout(n); \ -} - #define handshake(count, maxio, timeout, ENABLE, f) \ { \ long i, t, m; \ @@ -71,13 +65,13 @@ m = min_t(unsigned long, count, maxio); \ for (i = 0; i < m; i++) { \ for (t = 0; t < timeout && !ENABLE; t++) \ - wait_some(HZ/50); \ + msleep(20); \ if(!ENABLE) \ return -EIO; \ f; \ } \ count -= m; \ - if (m == maxio) wait_some(HZ/50); \ + if (m == maxio) msleep(20); \ } \ } @@ -85,7 +79,7 @@ { \ int t; \ for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \ - wait_some(HZ/100); \ + msleep(10); \ if(!DSP56K_TRANSMIT) { \ return -EIO; \ } \ @@ -95,7 +89,7 @@ { \ int t; \ for(t = 0; t < n && !DSP56K_RECEIVE; t++) \ - wait_some(HZ/100); \ + msleep(10); \ if(!DSP56K_RECEIVE) { \ return -EIO; \ } \ diff -Nru a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c --- a/drivers/char/ec3104_keyb.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/ec3104_keyb.c 2004-10-18 14:56:29 -07:00 @@ -412,7 +412,7 @@ k->last_msr = 0; for (;;) { - schedule_timeout(HZ/10); + msleep(100); msr = ctrl_inb(EC3104_SER4_MSR); diff -Nru a/drivers/char/efirtc.c b/drivers/char/efirtc.c --- a/drivers/char/efirtc.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/efirtc.c 2004-10-18 14:56:48 -07:00 @@ -155,7 +155,7 @@ efi_time_t eft; efi_time_cap_t cap; struct rtc_time wtime; - struct rtc_wkalrm *ewp; + struct rtc_wkalrm __user *ewp; unsigned char enabled, pending; switch (cmd) { @@ -189,13 +189,15 @@ convert_from_efi_time(&eft, &wtime); - return copy_to_user((void *)arg, &wtime, sizeof (struct rtc_time)) ? - EFAULT : 0; + return copy_to_user((void __user *)arg, &wtime, + sizeof (struct rtc_time)) ? - EFAULT : 0; case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EACCES; - if (copy_from_user(&wtime, (struct rtc_time *)arg, sizeof(struct rtc_time)) ) + if (copy_from_user(&wtime, (struct rtc_time __user *)arg, + sizeof(struct rtc_time)) ) return -EFAULT; convert_to_efi_time(&wtime, &eft); @@ -212,19 +214,19 @@ if (!capable(CAP_SYS_TIME)) return -EACCES; - ewp = (struct rtc_wkalrm *)arg; + ewp = (struct rtc_wkalrm __user *)arg; if ( get_user(enabled, &ewp->enabled) || copy_from_user(&wtime, &ewp->time, sizeof(struct rtc_time)) ) return -EFAULT; convert_to_efi_time(&wtime, &eft); - + spin_lock_irqsave(&efi_rtc_lock, flags); /* * XXX Fixme: * As of EFI 0.92 with the firmware I have on my - * machine this call does not seem to work quite + * machine this call does not seem to work quite * right */ status = efi.set_wakeup_time((efi_bool_t)enabled, &eft); @@ -243,14 +245,15 @@ if (status != EFI_SUCCESS) return -EINVAL; - ewp = (struct rtc_wkalrm *)arg; + ewp = (struct rtc_wkalrm __user *)arg; if ( put_user(enabled, &ewp->enabled) || put_user(pending, &ewp->pending)) return -EFAULT; convert_from_efi_time(&eft, &wtime); - return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time)) ? -EFAULT : 0; + return copy_to_user(&ewp->time, &wtime, + sizeof(struct rtc_time)) ? -EFAULT : 0; } return -EINVAL; } diff -Nru a/drivers/char/epca.c b/drivers/char/epca.c --- a/drivers/char/epca.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/epca.c 2004-10-18 14:56:33 -07:00 @@ -74,7 +74,6 @@ #define DIGIINFOMAJOR 35 /* For Digi specific ioctl */ -#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAXCARDS 7 #define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg) @@ -551,9 +550,7 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + tty_ldisc_flush(tty); shutdown(ch); tty->closing = 0; ch->event = 0; @@ -657,10 +654,7 @@ cli(); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + tty_ldisc_flush(tty); shutdown(ch); ch->tty = NULL; @@ -826,7 +820,7 @@ bytesAvailable will then take on this newly calculated value. ---------------------------------------------------------------------- */ - bytesAvailable = MIN(dataLen, bytesAvailable); + bytesAvailable = min(dataLen, bytesAvailable); /* First we read the data in from the file system into a temp buffer */ @@ -912,7 +906,7 @@ space; reduce the amount of data to fit the space. ---------------------------------------------------------------------- */ - bytesAvailable = MIN(remain, bytesAvailable); + bytesAvailable = min(remain, bytesAvailable); txwinon(ch); while (bytesAvailable > 0) @@ -923,7 +917,7 @@ data copy fills to the end of card buffer. ------------------------------------------------------------------- */ - dataLen = MIN(bytesAvailable, dataLen); + dataLen = min(bytesAvailable, dataLen); memcpy(ch->txptr + head, buf, dataLen); buf += dataLen; head += dataLen; @@ -1120,8 +1114,7 @@ restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* End pc_flush_buffer */ @@ -2262,9 +2255,7 @@ { /* Begin if LOWWAIT */ ch->statusflags &= ~LOWWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } /* End if LOWWAIT */ @@ -2281,9 +2272,7 @@ { /* Begin if EMPTYWAIT */ ch->statusflags &= ~EMPTYWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); @@ -3136,6 +3125,7 @@ } else { + /* ldisc lock already held in ioctl */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); } @@ -3307,7 +3297,6 @@ } } /* End EPCA_MAGIC */ - MOD_DEC_USE_COUNT; } /* End do_softint */ /* ------------------------------------------------------------ diff -Nru a/drivers/char/esp.c b/drivers/char/esp.c --- a/drivers/char/esp.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/char/esp.c 2004-10-18 14:55:53 -07:00 @@ -19,7 +19,7 @@ * * rs_set_termios fixed to look also for changes of the input * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK. - * Bernd Anhäupl 05/17/96. + * Bernd Anhďż˝pl 05/17/96. * * --- End of notices from serial.c --- * @@ -140,7 +140,7 @@ static void change_speed(struct esp_struct *info); static void rs_wait_until_sent(struct tty_struct *, int); - + /* * The ESP card has a clock rate of 14.7456 MHz (that is, 2**ESPC_SCALE * times the normal 1.8432 Mhz clock of most serial boards). @@ -150,10 +150,6 @@ /* Standard COM flags (except for COM4, because of the 8514 problem) */ #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the memcpy_fromfs blocks while swapping in a page, @@ -762,10 +758,7 @@ return; if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -1370,10 +1363,7 @@ cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -2069,8 +2059,7 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = NULL; diff -Nru a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c --- a/drivers/char/ftape/lowlevel/ftape-calibr.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/char/ftape/lowlevel/ftape-calibr.c 2004-10-18 14:56:27 -07:00 @@ -31,7 +31,10 @@ #include #if defined(__alpha__) # include -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__x86_64__) +# include +# include +#elif defined(__i386__) # include #endif #include @@ -45,7 +48,7 @@ # error Ftape is not implemented for this architecture! #endif -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) static unsigned long ps_per_cycle = 0; #endif @@ -72,7 +75,18 @@ asm volatile ("rpcc %0" : "=r" (r)); return r; -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__x86_64__) + unsigned long r; + rdtscl(r); + return r; +#elif defined(__i386__) + +/* + * Note that there is some time between counter underflowing and jiffies + * increasing, so the code below won't always give correct output. + * -Vojtech + */ + unsigned long flags; __u16 lo; __u16 hi; @@ -89,9 +103,9 @@ static unsigned int short_ftape_timestamp(void) { -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) return ftape_timestamp(); -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) unsigned int count; unsigned long flags; @@ -106,9 +120,9 @@ static unsigned int diff(unsigned int t0, unsigned int t1) { -#if defined(__alpha__) - return (t1 <= t0) ? t1 + (1UL << 32) - t0 : t1 - t0; -#elif defined(__i386__) || defined(__x86_64__) +#if defined(__alpha__) || defined(__x86_64__) + return (t1 - t0); +#elif defined(__i386__) /* * This is tricky: to work for both short and full ftape_timestamps * we'll have to discriminate between these. @@ -122,9 +136,9 @@ static unsigned int usecs(unsigned int count) { -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) return (ps_per_cycle * count) / 1000000UL; -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100); #endif } @@ -163,38 +177,13 @@ static void init_clock(void) { -#if defined(__i386__) || defined(__x86_64__) - unsigned int t; - int i; TRACE_FUN(ft_t_any); - /* Haven't studied on why, but there sometimes is a problem - * with the tick timer readout. The two bytes get swapped. - * This hack solves that problem by doing one extra input. - */ - for (i = 0; i < 1000; ++i) { - t = short_ftape_timestamp(); - if (t > LATCH) { - inb_p(0x40); /* get in sync again */ - TRACE(ft_t_warn, "clock counter fixed"); - break; - } - } +#if defined(__x86_64__) + ps_per_cycle = 1000000000UL / cpu_khz; #elif defined(__alpha__) -#if CONFIG_FT_ALPHA_CLOCK == 0 -#error You must define and set CONFIG_FT_ALPHA_CLOCK in 'make config' ! -#endif extern struct hwrpb_struct *hwrpb; - TRACE_FUN(ft_t_any); - - if (hwrpb->cycle_freq != 0) { - ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; - } else { - /* - * HELP: Linux 2.0.x doesn't set cycle_freq on my noname ! - */ - ps_per_cycle = (1000*1000*1000*1000UL) / CONFIG_FT_ALPHA_CLOCK; - } + ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; #endif TRACE_EXIT; } @@ -213,7 +202,7 @@ unsigned int tc = 0; unsigned int count; unsigned int time; -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) unsigned int old_tc = 0; unsigned int old_count = 1; unsigned int old_time = 1; @@ -255,7 +244,7 @@ tc = (1000 * time) / (count - 1); TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", usecs(once), count - 1, usecs(multiple), tc); -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) /* * Increase the calibration count exponentially until the * calibration time exceeds 100 ms. @@ -263,7 +252,7 @@ if (time >= 100*1000) { break; } -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) /* * increase the count until the resulting time nears 2/HZ, * then the tc will drop sharply because we lose LATCH counts. diff -Nru a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c --- a/drivers/char/generic_serial.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/generic_serial.c 2004-10-18 14:56:32 -07:00 @@ -436,9 +436,7 @@ restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); func_exit (); } @@ -578,9 +576,7 @@ if (!tty) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } func_exit (); @@ -694,7 +690,7 @@ { unsigned long flags; struct gs_port *port; - + func_enter (); if (!tty) return; @@ -760,8 +756,8 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; port->event = 0; diff -Nru a/drivers/char/hpet.c b/drivers/char/hpet.c --- a/drivers/char/hpet.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/hpet.c 2004-10-18 14:56:33 -07:00 @@ -60,8 +60,8 @@ struct hpet_dev { struct hpets *hd_hpets; - struct hpet *hd_hpet; - struct hpet_timer *hd_timer; + struct hpet __iomem *hd_hpet; + struct hpet_timer __iomem *hd_timer; unsigned long hd_ireqfreq; unsigned long hd_irqdata; wait_queue_head_t hd_waitqueue; @@ -75,7 +75,7 @@ struct hpets { struct hpets *hp_next; - struct hpet *hp_hpet; + struct hpet __iomem *hp_hpet; unsigned long hp_period; unsigned long hp_delta; unsigned int hp_ntimer; @@ -98,14 +98,14 @@ #endif #ifndef readq -static unsigned long long __inline readq(void *addr) +static unsigned long long __inline readq(void __iomem *addr) { return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL); } #endif #ifndef writeq -static void __inline writeq(unsigned long long v, void *addr) +static void __inline writeq(unsigned long long v, void __iomem *addr) { writel(v & 0xffffffff, addr); writel(v >> 32, addr + 4); @@ -300,7 +300,7 @@ static int hpet_release(struct inode *inode, struct file *file) { struct hpet_dev *devp; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; int irq = 0; devp = file->private_data; @@ -352,8 +352,8 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) { - struct hpet_timer *timer; - struct hpet *hpet; + struct hpet_timer __iomem *timer; + struct hpet __iomem *hpet; struct hpets *hpetp; int irq; unsigned long g, v, t, m; @@ -435,8 +435,8 @@ static int hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) { - struct hpet_timer *timer; - struct hpet *hpet; + struct hpet_timer __iomem *timer; + struct hpet __iomem *hpet; struct hpets *hpetp; int err; unsigned long v; @@ -547,7 +547,7 @@ { unsigned int i; u64 mask; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; struct hpet_dev *devp; struct hpets *hpetp; @@ -615,7 +615,7 @@ int hpet_unregister(struct hpet_task *tp) { struct hpet_dev *devp; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; int err; if ((err = hpet_tpcheck(tp))) @@ -662,40 +662,9 @@ #ifdef CONFIG_TIME_INTERPOLATION -static unsigned long hpet_offset, last_wall_hpet; -static long hpet_nsecs_per_cycle, hpet_cycles_per_sec; - -static unsigned long hpet_getoffset(void) -{ - return hpet_offset + (read_counter(&hpets->hp_hpet->hpet_mc) - - last_wall_hpet) * hpet_nsecs_per_cycle; -} - -static void hpet_update(long delta) -{ - unsigned long mc; - unsigned long offset; - - mc = read_counter(&hpets->hp_hpet->hpet_mc); - offset = hpet_offset + (mc - last_wall_hpet) * hpet_nsecs_per_cycle; - - if (delta < 0 || (unsigned long)delta < offset) - hpet_offset = offset - delta; - else - hpet_offset = 0; - last_wall_hpet = mc; -} - -static void hpet_reset(void) -{ - hpet_offset = 0; - last_wall_hpet = read_counter(&hpets->hp_hpet->hpet_mc); -} - static struct time_interpolator hpet_interpolator = { - .get_offset = hpet_getoffset, - .update = hpet_update, - .reset = hpet_reset + .source = TIME_SOURCE_MMIO64, + .shift = 10 }; #endif @@ -745,11 +714,11 @@ static unsigned long __init hpet_calibrate(struct hpets *hpetp) { - struct hpet_timer *timer = NULL; + struct hpet_timer __iomem *timer = NULL; unsigned long t, m, count, i, flags, start; struct hpet_dev *devp; int j; - struct hpet *hpet; + struct hpet __iomem *hpet; for (j = 0, devp = hpetp->hp_dev; j < hpetp->hp_ntimer; j++, devp++) if ((devp->hd_flags & HPET_OPEN) == 0) { @@ -787,8 +756,9 @@ u32 i, ntimer; struct hpets *hpetp; size_t siz; - struct hpet *hpet; + struct hpet __iomem *hpet; static struct hpets *last __initdata = (struct hpets *)0; + unsigned long ns; /* * hpet_alloc can be called by platform dependent code. @@ -796,7 +766,7 @@ * ACPI also reports hpet, then we catch it here. */ for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) - if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address)) + if (hpetp->hp_hpet == hdp->hd_address) return 0; siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) * @@ -810,7 +780,7 @@ memset(hpetp, 0, siz); hpetp->hp_which = hpet_nhpet++; - hpetp->hp_hpet = (struct hpet *)hdp->hd_address; + hpetp->hp_hpet = hdp->hd_address; hpetp->hp_ntimer = hdp->hd_nirqs; @@ -840,6 +810,18 @@ hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >> HPET_COUNTER_CLK_PERIOD_SHIFT; + printk(KERN_INFO "hpet%d: at MMIO 0x%p, IRQ%s", + hpetp->hp_which, hpet, hpetp->hp_ntimer > 1 ? "s" : ""); + for (i = 0; i < hpetp->hp_ntimer; i++) + printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); + printk("\n"); + + ns = hpetp->hp_period; /* femptoseconds, 10^-15 */ + do_div(ns, 1000000); /* convert to nanoseconds, 10^-9 */ + printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n", + hpetp->hp_which, ns, hpetp->hp_ntimer, + cap & HPET_COUNTER_SIZE_MASK ? 64 : 32); + mcfg = readq(&hpet->hpet_config); if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { write_counter(0L, &hpet->hpet_mc); @@ -850,7 +832,7 @@ for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; i++, hpet_ntimer++, devp++) { unsigned long v; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; timer = &hpet->hpet_timers[devp - hpetp->hp_dev]; v = readq(&timer->hpet_config); @@ -891,11 +873,10 @@ unsigned long size; size = addr.max_address_range - addr.min_address_range + 1; - hdp->hd_address = - (unsigned long)ioremap(addr.min_address_range, size); + hdp->hd_address = ioremap(addr.min_address_range, size); for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) - if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address)) + if (hpetp->hp_hpet == hdp->hd_address) return -EBUSY; } else if (res->id == ACPI_RSTYPE_EXT_IRQ) { struct acpi_resource_ext_irq *irqp; @@ -944,9 +925,8 @@ return 0; } -static struct acpi_driver hpet_acpi_driver __initdata = { +static struct acpi_driver hpet_acpi_driver = { .name = "hpet", - .class = "", .ids = "PNP0103", .ops = { .add = hpet_acpi_add, @@ -971,11 +951,10 @@ struct hpet *hpet; hpet = hpets->hp_hpet; - hpet_cycles_per_sec = hpet_time_div(hpets->hp_period); - hpet_interpolator.frequency = hpet_cycles_per_sec; - hpet_interpolator.drift = hpet_cycles_per_sec * + hpet_interpolator.addr = &hpets->hp_hpet->hpet_mc; + hpet_interpolator.frequency = hpet_time_div(hpets->hp_period); + hpet_interpolator.drift = hpet_interpolator.frequency * HPET_DRIFT / 1000000; - hpet_nsecs_per_cycle = 1000000000 / hpet_cycles_per_sec; register_time_interpolator(&hpet_interpolator); } #endif diff -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c --- a/drivers/char/hvc_console.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/hvc_console.c 2004-10-18 14:56:50 -07:00 @@ -1,6 +1,11 @@ /* * Copyright (C) 2001 Anton Blanchard , IBM * Copyright (C) 2001 Paul Mackerras , IBM + * Copyright (C) 2004 Benjamin Herrenschmidt , IBM Corp. + * Copyright (C) 2004 IBM Corporation + * + * Additional Author(s): + * Ryan S. Arnold * * 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 @@ -17,38 +22,51 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include #include +#include +#include +#include +#include +#include #include -#include #include -#include #include #include #include #include -#include -#include #include -#include - -extern int hvc_count(int *); -extern int hvc_get_chars(int index, char *buf, int count); -extern int hvc_put_chars(int index, const char *buf, int count); +#include +#include +#include #define HVC_MAJOR 229 #define HVC_MINOR 0 -#define MAX_NR_HVC_CONSOLES 4 - #define TIMEOUT ((HZ + 99) / 100) +/* + * Wait this long per iteration while trying to push buffered data to the + * hypervisor before allowing the tty to complete a close operation. + */ +#define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ + +/* + * The Linux TTY code does not support dynamic addition of tty derived devices + * so we need to know how many tty devices we might need when space is allocated + * for the tty device. Since this driver supports hotplug of vty adapters we + * need to make sure we have enough allocated. + */ +#define HVC_ALLOC_TTY_ADAPTERS 8 + static struct tty_driver *hvc_driver; -static int hvc_offset; #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; #endif #define N_OUTBUF 16 +#define N_INBUF 16 #define __ALIGNED__ __attribute__((__aligned__(8))) @@ -60,59 +78,249 @@ int do_wakeup; char outbuf[N_OUTBUF] __ALIGNED__; int n_outbuf; + uint32_t vtermno; + int irq_requested; + int irq; + struct list_head next; + struct kobject kobj; /* ref count & hvc_struct lifetime */ + struct vio_dev *vdev; }; -struct hvc_struct hvc_struct[MAX_NR_HVC_CONSOLES]; +/* dynamic list of hvc_struct instances */ +static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); -static int hvc_open(struct tty_struct *tty, struct file * filp) +/* + * Protect the list of hvc_struct instances from inserts and removals during + * list traversal. + */ +static spinlock_t hvc_structs_lock = SPIN_LOCK_UNLOCKED; + +/* + * Initial console vtermnos for console API usage prior to full console + * initialization. Any vty adapter outside this range will not have usable + * console interfaces but can still be used as a tty device. This has to be + * static because kmalloc will not work during early console init. + */ +static uint32_t vtermnos[MAX_NR_HVC_CONSOLES]; + +/* Used for accounting purposes */ +static int num_vterms = 0; + +static struct task_struct *hvc_task; + +/* + * This value is used to associate a tty->index value to a hvc_struct based + * upon order of exposure via hvc_probe(). + */ +static int hvc_count = -1; + +/* Picks up late kicks after list walk but before schedule() */ +static int hvc_kicked; + +/* Wake the sleeping khvcd */ +static void hvc_kick(void) +{ + hvc_kicked = 1; + wake_up_process(hvc_task); +} + +/* + * NOTE: This API isn't used if the console adapter doesn't support interrupts. + * In this case the console is poll driven. + */ +static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + hvc_kick(); + return IRQ_HANDLED; +} + +static void hvc_unthrottle(struct tty_struct *tty) +{ + hvc_kick(); +} + +/* + * Do not call this function with either the hvc_strucst_lock or the hvc_struct + * lock held. If successful, this function increments the kobject reference + * count against the target hvc_struct so it should be released when finished. + */ +struct hvc_struct *hvc_get_by_index(int index) { - int line = tty->index; struct hvc_struct *hp; unsigned long flags; - if (line < 0 || line >= MAX_NR_HVC_CONSOLES) + spin_lock(&hvc_structs_lock); + + list_for_each_entry(hp, &hvc_structs, next) { + spin_lock_irqsave(&hp->lock, flags); + if (hp->index == index) { + kobject_get(&hp->kobj); + spin_unlock_irqrestore(&hp->lock, flags); + spin_unlock(&hvc_structs_lock); + return hp; + } + spin_unlock_irqrestore(&hp->lock, flags); + } + hp = NULL; + + spin_unlock(&hvc_structs_lock); + return hp; +} + +/* + * The TTY interface won't be used until after the vio layer has exposed the vty + * adapter to the kernel. + */ +static int hvc_open(struct tty_struct *tty, struct file * filp) +{ + struct hvc_struct *hp; + unsigned long flags; + int irq = NO_IRQ; + int rc = 0; + struct kobject *kobjp; + + /* Auto increments kobject reference if found. */ + if (!(hp = hvc_get_by_index(tty->index))) { + printk(KERN_WARNING "hvc_console: tty open failed, no vty associated with tty.\n"); return -ENODEV; - hp = &hvc_struct[line]; + } - tty->driver_data = hp; spin_lock_irqsave(&hp->lock, flags); + /* Check and then increment for fast path open. */ + if (hp->count++ > 0) { + spin_unlock_irqrestore(&hp->lock, flags); + hvc_kick(); + return 0; + } /* else count == 0 */ + + tty->driver_data = hp; hp->tty = tty; - hp->count++; + /* Save for request_irq outside of spin_lock. */ + irq = hp->irq; + if (irq != NO_IRQ) + hp->irq_requested = 1; + + kobjp = &hp->kobj; + spin_unlock_irqrestore(&hp->lock, flags); + /* check error, fallback to non-irq */ + if (irq != NO_IRQ) + rc = request_irq(irq, hvc_handle_interrupt, SA_INTERRUPT, "hvc_console", hp); + + /* + * If the request_irq() fails and we return an error. The tty layer + * will call hvc_close() after a failed open but we don't want to clean + * up there so we'll clean up here and clear out the previously set + * tty fields and return the kobject reference. + */ + if (rc) { + spin_lock_irqsave(&hp->lock, flags); + hp->tty = NULL; + hp->irq_requested = 0; + spin_unlock_irqrestore(&hp->lock, flags); + tty->driver_data = NULL; + kobject_put(kobjp); + } + /* Force wakeup of the polling thread */ + hvc_kick(); - return 0; + return rc; } static void hvc_close(struct tty_struct *tty, struct file * filp) { - struct hvc_struct *hp = tty->driver_data; + struct hvc_struct *hp; + struct kobject *kobjp; + int irq = NO_IRQ; unsigned long flags; if (tty_hung_up_p(filp)) return; + + /* + * No driver_data means that this close was issued after a failed + * hvcs_open by the tty layer's release_dev() function and we can just + * exit cleanly because the kobject reference wasn't made. + */ + if (!tty->driver_data) + return; + + hp = tty->driver_data; spin_lock_irqsave(&hp->lock, flags); - if (--hp->count == 0) + + kobjp = &hp->kobj; + if (--hp->count == 0) { + if (hp->irq_requested) + irq = hp->irq; + hp->irq_requested = 0; + + /* We are done with the tty pointer now. */ hp->tty = NULL; - else if (hp->count < 0) - printk(KERN_ERR "hvc_close %lu: oops, count is %d\n", - hp - hvc_struct, hp->count); - spin_unlock_irqrestore(&hp->lock, flags); + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * Chain calls chars_in_buffer() and returns immediately if + * there is no buffered data otherwise sleeps on a wait queue + * waking periodically to check chars_in_buffer(). + */ + tty_wait_until_sent(tty, HVC_CLOSE_WAIT); + + /* + * Since the line disc doesn't block writes during tty close + * operations we'll set driver_data to NULL and then make sure + * to check tty->driver_data for NULL in hvc_write(). + */ + tty->driver_data = NULL; + + if (irq != NO_IRQ) + free_irq(irq, hp); + + } else { + if (hp->count < 0) + printk(KERN_ERR "hvc_close %X: oops, count is %d\n", + hp->vtermno, hp->count); + spin_unlock_irqrestore(&hp->lock, flags); + } + + kobject_put(kobjp); } static void hvc_hangup(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; + unsigned long flags; + int irq = NO_IRQ; + int temp_open_count; + struct kobject *kobjp; + spin_lock_irqsave(&hp->lock, flags); + kobjp = &hp->kobj; + temp_open_count = hp->count; hp->count = 0; + hp->n_outbuf = 0; hp->tty = NULL; + if (hp->irq_requested) + /* Saved for use outside of spin_lock. */ + irq = hp->irq; + hp->irq_requested = 0; + spin_unlock_irqrestore(&hp->lock, flags); + if (irq != NO_IRQ) + free_irq(irq, hp); + while(temp_open_count) { + --temp_open_count; + kobject_put(kobjp); + } } -/* called with hp->lock held */ +/* + * Push buffered characters whether they were just recently buffered or waiting + * on a blocked hypervisor. Call this function with hp->lock held. + */ static void hvc_push(struct hvc_struct *hp) { int n; - n = hvc_put_chars(hp->index + hvc_offset, hp->outbuf, hp->n_outbuf); + n = hvc_put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); if (n <= 0) { if (n == 0) return; @@ -127,77 +335,126 @@ hp->do_wakeup = 1; } -static int hvc_write(struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) +static inline int __hvc_write_user(struct hvc_struct *hp, + const unsigned char *buf, int count) { - struct hvc_struct *hp = tty->driver_data; char *tbuf, *p; int tbsize, rsize, written = 0; unsigned long flags; - if (from_user) { - tbsize = min(count, (int)PAGE_SIZE); - if (!(tbuf = kmalloc(tbsize, GFP_KERNEL))) - return -ENOMEM; - - while ((rsize = count - written) > 0) { - int wsize; - if (rsize > tbsize) - rsize = tbsize; - - p = tbuf; - rsize -= copy_from_user(p, buf, rsize); - if (!rsize) { - if (written == 0) - written = -EFAULT; - break; - } - buf += rsize; - written += rsize; - - spin_lock_irqsave(&hp->lock, flags); - for (wsize = N_OUTBUF - hp->n_outbuf; rsize && wsize; - wsize = N_OUTBUF - hp->n_outbuf) { - if (wsize > rsize) - wsize = rsize; - memcpy(hp->outbuf + hp->n_outbuf, p, wsize); - hp->n_outbuf += wsize; - hvc_push(hp); - rsize -= wsize; - p += wsize; - } - spin_unlock_irqrestore(&hp->lock, flags); - - if (rsize) - break; + tbsize = min(count, (int)PAGE_SIZE); + if (!(tbuf = kmalloc(tbsize, GFP_KERNEL))) + return -ENOMEM; - if (count < tbsize) - tbsize = count; + while ((rsize = count - written) > 0) { + int wsize; + if (rsize > tbsize) + rsize = tbsize; + + p = tbuf; + rsize -= copy_from_user(p, buf, rsize); + if (!rsize) { + if (written == 0) + written = -EFAULT; + break; } + buf += rsize; - kfree(tbuf); - } else { spin_lock_irqsave(&hp->lock, flags); - while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) { - if (rsize > count) - rsize = count; - memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); - count -= rsize; - buf += rsize; - hp->n_outbuf += rsize; - written += rsize; + + /* Push pending writes: make some room in buffer */ + if (hp->n_outbuf > 0) + hvc_push(hp); + + for (wsize = N_OUTBUF - hp->n_outbuf; rsize && wsize; + wsize = N_OUTBUF - hp->n_outbuf) { + if (wsize > rsize) + wsize = rsize; + memcpy(hp->outbuf + hp->n_outbuf, p, wsize); + hp->n_outbuf += wsize; hvc_push(hp); + rsize -= wsize; + p += wsize; + written += wsize; } spin_unlock_irqrestore(&hp->lock, flags); + + if (rsize) + break; + + if (count < tbsize) + tbsize = count; } + kfree(tbuf); + return written; } +static inline int __hvc_write_kernel(struct hvc_struct *hp, + const unsigned char *buf, int count) +{ + unsigned long flags; + int rsize, written = 0; + + spin_lock_irqsave(&hp->lock, flags); + + /* Push pending writes */ + if (hp->n_outbuf > 0) + hvc_push(hp); + + while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) { + if (rsize > count) + rsize = count; + memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); + count -= rsize; + buf += rsize; + hp->n_outbuf += rsize; + written += rsize; + hvc_push(hp); + } + spin_unlock_irqrestore(&hp->lock, flags); + + return written; +} +static int hvc_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + struct hvc_struct *hp = tty->driver_data; + int written; + + /* This write was probably executed during a tty close. */ + if (!hp) + return -EPIPE; + + if (from_user) + written = __hvc_write_user(hp, buf, count); + else + written = __hvc_write_kernel(hp, buf, count); + + /* + * Racy, but harmless, kick thread if there is still pending data. + * There really is nothing wrong with kicking the thread, even if there + * is no buffered data. + */ + if (hp->n_outbuf) + hvc_kick(); + + return written; +} + +/* + * This is actually a contract between the driver and the tty layer outlining + * how much write room the driver can guarentee will be sent OR BUFFERED. This + * driver MUST honor the return value. + */ static int hvc_write_room(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; + if (!hp) + return -1; + return N_OUTBUF - hp->n_outbuf; } @@ -205,57 +462,108 @@ { struct hvc_struct *hp = tty->driver_data; + if (!hp) + return -1; return hp->n_outbuf; } -static void hvc_poll(int index) +#define HVC_POLL_READ 0x00000001 +#define HVC_POLL_WRITE 0x00000002 +#define HVC_POLL_QUICK 0x00000004 + +static int hvc_poll(struct hvc_struct *hp) { - struct hvc_struct *hp = &hvc_struct[index]; struct tty_struct *tty; - int i, n; - char buf[16] __ALIGNED__; + int i, n, poll_mask = 0; + char buf[N_INBUF] __ALIGNED__; unsigned long flags; + int read_total = 0; spin_lock_irqsave(&hp->lock, flags); + /* Push pending writes */ if (hp->n_outbuf > 0) hvc_push(hp); + /* Reschedule us if still some write pending */ + if (hp->n_outbuf > 0) + poll_mask |= HVC_POLL_WRITE; + /* No tty attached, just skip */ tty = hp->tty; - if (tty) { - for (;;) { - if (TTY_FLIPBUF_SIZE - tty->flip.count < sizeof(buf)) - break; - n = hvc_get_chars(index + hvc_offset, buf, sizeof(buf)); - if (n <= 0) - break; - for (i = 0; i < n; ++i) { -#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ - if (buf[i] == '\x0f') { /* ^O -- should support a sequence */ - sysrq_pressed = 1; - continue; - } else if (sysrq_pressed) { - handle_sysrq(buf[i], NULL, tty); - sysrq_pressed = 0; - continue; - } -#endif - tty_insert_flip_char(tty, buf[i], 0); + if (tty == NULL) + goto bail; + + /* Now check if we can get data (are we throttled ?) */ + if (test_bit(TTY_THROTTLED, &tty->flags)) + goto throttled; + + /* If we aren't interrupt driven and aren't throttled, we always + * request a reschedule + */ + if (hp->irq == NO_IRQ) + poll_mask |= HVC_POLL_READ; + + /* Read data if any */ + for (;;) { + int count = N_INBUF; + if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) + count = TTY_FLIPBUF_SIZE - tty->flip.count; + + /* If flip is full, just reschedule a later read */ + if (count == 0) { + poll_mask |= HVC_POLL_READ; + break; + } + + n = hvc_get_chars(hp->vtermno, buf, count); + if (n <= 0) { + /* Hangup the tty when disconnected from host */ + if (n == -EPIPE) { + spin_unlock_irqrestore(&hp->lock, flags); + tty_hangup(tty); + spin_lock_irqsave(&hp->lock, flags); + } + break; + } + for (i = 0; i < n; ++i) { +#ifdef CONFIG_MAGIC_SYSRQ + /* Handle the SysRq Hack */ + if (buf[i] == '\x0f') { /* ^O -- should support a sequence */ + sysrq_pressed = 1; + continue; + } else if (sysrq_pressed) { + handle_sysrq(buf[i], NULL, tty); + sysrq_pressed = 0; + continue; } +#endif /* CONFIG_MAGIC_SYSRQ */ + tty_insert_flip_char(tty, buf[i], 0); } + if (tty->flip.count) tty_schedule_flip(tty); - if (hp->do_wakeup) { - hp->do_wakeup = 0; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + /* + * Account for the total amount read in one loop, and if above + * 64 bytes, we do a quick schedule loop to let the tty grok the + * data and eventually throttle us. + */ + read_total += n; + if (read_total >= 64) { + poll_mask |= HVC_POLL_QUICK; + break; } } - + throttled: + /* Wakeup write queue if necessary */ + if (hp->do_wakeup) { + hp->do_wakeup = 0; + tty_wakeup(tty); + } + bail: spin_unlock_irqrestore(&hp->lock, flags); + + return poll_mask; } #if defined(CONFIG_XMON) && defined(CONFIG_SMP) @@ -264,21 +572,47 @@ static const cpumask_t cpus_in_xmon = CPU_MASK_NONE; #endif - +/* + * This kthread is either polling or interrupt driven. This is determined by + * calling hvc_poll() who determines whether a console adapter support + * interrupts. + */ int khvcd(void *unused) { - int i; - - daemonize("khvcd"); + int poll_mask; + struct hvc_struct *hp; - for (;;) { + __set_current_state(TASK_RUNNING); + do { + poll_mask = 0; + hvc_kicked = 0; + wmb(); if (cpus_empty(cpus_in_xmon)) { - for (i = 0; i < MAX_NR_HVC_CONSOLES; ++i) - hvc_poll(i); + spin_lock(&hvc_structs_lock); + list_for_each_entry(hp, &hvc_structs, next) { + /*hp = list_entry(node, struct hvc_struct, * next); */ + poll_mask |= hvc_poll(hp); + } + spin_unlock(&hvc_structs_lock); + } else + poll_mask |= HVC_POLL_READ; + if (hvc_kicked) + continue; + if (poll_mask & HVC_POLL_QUICK) { + yield(); + continue; } set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(TIMEOUT); - } + if (!hvc_kicked) { + if (poll_mask == 0) + schedule(); + else + schedule_timeout(TIMEOUT); + } + __set_current_state(TASK_RUNNING); + } while (!kthread_should_stop()); + + return 0; } static struct tty_operations hvc_ops = { @@ -286,19 +620,124 @@ .close = hvc_close, .write = hvc_write, .hangup = hvc_hangup, + .unthrottle = hvc_unthrottle, .write_room = hvc_write_room, .chars_in_buffer = hvc_chars_in_buffer, }; -int __init hvc_init(void) +char hvc_driver_name[] = "hvc_console"; + +static struct vio_device_id hvc_driver_table[] __devinitdata= { + {"serial", "hvterm1"}, + { 0, } +}; +MODULE_DEVICE_TABLE(vio, hvc_driver_table); + +/* callback when the kboject ref count reaches zero. */ +static void destroy_hvc_struct(struct kobject *kobj) { - int num = hvc_count(&hvc_offset); - int i; + struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj); + unsigned long flags; - if (num > MAX_NR_HVC_CONSOLES) - num = MAX_NR_HVC_CONSOLES; + spin_lock(&hvc_structs_lock); - hvc_driver = alloc_tty_driver(num); + spin_lock_irqsave(&hp->lock, flags); + list_del(&(hp->next)); + spin_unlock_irqrestore(&hp->lock, flags); + + spin_unlock(&hvc_structs_lock); + + kfree(hp); +} + +static struct kobj_type hvc_kobj_type = { + .release = destroy_hvc_struct, +}; + +static int __devinit hvc_probe( + struct vio_dev *dev, + const struct vio_device_id *id) +{ + struct hvc_struct *hp; + + /* probed with invalid parameters. */ + if (!dev || !id) + return -EPERM; + + hp = kmalloc(sizeof(*hp), GFP_KERNEL); + if (!hp) + return -ENOMEM; + + memset(hp, 0x00, sizeof(*hp)); + hp->vtermno = dev->unit_address; + hp->vdev = dev; + hp->vdev->dev.driver_data = hp; + hp->irq = dev->irq; + + kobject_init(&hp->kobj); + hp->kobj.ktype = &hvc_kobj_type; + + hp->lock = SPIN_LOCK_UNLOCKED; + spin_lock(&hvc_structs_lock); + hp->index = ++hvc_count; + list_add_tail(&(hp->next), &hvc_structs); + spin_unlock(&hvc_structs_lock); + + return 0; +} + +static int __devexit hvc_remove(struct vio_dev *dev) +{ + struct hvc_struct *hp = dev->dev.driver_data; + unsigned long flags; + struct kobject *kobjp; + struct tty_struct *tty; + + spin_lock_irqsave(&hp->lock, flags); + tty = hp->tty; + kobjp = &hp->kobj; + + if (hp->index < MAX_NR_HVC_CONSOLES) + vtermnos[hp->index] = -1; + + /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ + + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * We 'put' the instance that was grabbed when the kobject instance + * was intialized using kobject_init(). Let the last holder of this + * kobject cause it to be removed, which will probably be the tty_hangup + * below. + */ + kobject_put(kobjp); + + /* + * This function call will auto chain call hvc_hangup. The tty should + * always be valid at this time unless a simultaneous tty close already + * cleaned up the hvc_struct. + */ + if (tty) + tty_hangup(tty); + return 0; +} + +static struct vio_driver hvc_vio_driver = { + .name = hvc_driver_name, + .id_table = hvc_driver_table, + .probe = hvc_probe, + .remove = hvc_remove, +}; + +/* Driver initialization. Follow console initialization. This is where the TTY + * interfaces start to become available. */ +int __init hvc_init(void) +{ + int rc; + + /* We need more than num_vterms adapters due to hotplug additions. */ + hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); + /* hvc_driver = alloc_tty_driver(num_vterms); */ if (!hvc_driver) return -ENOMEM; @@ -312,31 +751,73 @@ hvc_driver->init_termios = tty_std_termios; hvc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvc_driver, &hvc_ops); - for (i = 0; i < num; i++) { - hvc_struct[i].lock = SPIN_LOCK_UNLOCKED; - hvc_struct[i].index = i; - } if (tty_register_driver(hvc_driver)) panic("Couldn't register hvc console driver\n"); - if (num > 0) - kernel_thread(khvcd, NULL, CLONE_KERNEL); + /* Always start the kthread because there can be hotplug vty adapters + * added later. */ + hvc_task = kthread_run(khvcd, NULL, "khvcd"); + if (IS_ERR(hvc_task)) { + panic("Couldn't create kthread for console.\n"); + put_tty_driver(hvc_driver); + return -EIO; + } - return 0; + /* Register as a vio device to receive callbacks */ + rc = vio_register_driver(&hvc_vio_driver); + + return rc; } +/* This isn't particularily necessary due to this being a console driver but it + * is nice to be thorough */ static void __exit hvc_exit(void) { + kthread_stop(hvc_task); + + vio_unregister_driver(&hvc_vio_driver); + tty_unregister_driver(hvc_driver); + /* return tty_struct instances allocated in hvc_init(). */ + put_tty_driver(hvc_driver); +} + +/* + * Console APIs, NOT TTY. These APIs are available immediately when + * hvc_console_setup() finds adapters. + */ + +/* + * hvc_instantiate() is an early console discovery method which locates consoles + * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT + * get an hvc_instantiate() callback since the appear after early console init. + */ +int hvc_instantiate(uint32_t vtermno, int index) +{ + if (index < 0 || index >= MAX_NR_HVC_CONSOLES) + return -1; + + if (vtermnos[index] != -1) + return -1; + + vtermnos[index] = vtermno; + return 0; } void hvc_console_print(struct console *co, const char *b, unsigned count) { char c[16] __ALIGNED__; - unsigned i, n; + unsigned i = 0, n = 0; int r, donecr = 0; - i = n = 0; + /* Console access attempt outside of acceptable console range. */ + if (co->index >= MAX_NR_HVC_CONSOLES) + return; + + /* This console adapter was removed so it is not useable. */ + if (vtermnos[co->index] < 0) + return; + while (count > 0 || i > 0) { if (count > 0 && i < sizeof(c)) { if (b[n] == '\n' && !donecr) { @@ -348,7 +829,7 @@ --count; } } else { - r = hvc_put_chars(co->index + hvc_offset, c, i); + r = hvc_put_chars(vtermnos[co->index], c, i); if (r < 0) { /* throw away chars on error */ i = 0; @@ -369,9 +850,6 @@ static int __init hvc_console_setup(struct console *co, char *options) { - if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES - || co->index >= hvc_count(&hvc_offset)) - return -1; return 0; } @@ -384,8 +862,14 @@ .index = -1, }; +/* Early console initialization. Preceeds driver initialization. */ static int __init hvc_console_init(void) { + int i; + + for (i=0; i /* - * 1.0.0 -> 1.1.0 Added kernel_thread scheduling methodology to driver to - * replace wait_task constructs. + * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00). + * Removed braces around single statements following conditionals. Removed '= + * 0' after static int declarations since these default to zero. Removed + * list_for_each_safe() and replaced with list_for_each_entry() in + * hvcs_get_by_index(). The 'safe' version is un-needed now that the driver is + * using spinlocks. Changed spin_lock_irqsave() to spin_lock() when locking + * hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int + * handler. Initialized hvcs_structs_lock and hvcs_pi_lock to + * SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init(). + * Added spin_lock around list_del() in destroy_hvcs_struct() to protect the + * list traversals from a deletion. Removed '= NULL' from pointer declaration + * statements since they are initialized NULL by default. Removed wmb() + * instances from hvcs_try_write(). They probably aren't needed with locking in + * place. Added check and cleanup for hvcs_pi_buff = kmalloc() in + * hvcs_module_init(). Exposed hvcs_struct.index via a sysfs attribute so that + * the coupling between /dev/hvcs* and a vty-server can be automatically + * determined. Moved kobject_put() in hvcs_open outside of the + * spin_unlock_irqrestore(). * - * 1.1.0 -> 1.2.0 Moved pi_buff initialization out of arch code into driver code - * and added locking to share this buffer between hvcs_struct instances. This - * is because the page_size kmalloc can't be done with a spin_lock held. + * 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it + * align with how the tty layer always assigns the lowest index available. This + * change resulted in a list of ints that denotes which indexes are available. + * Device additions and removals use the new hvcs_get_index() and + * hvcs_return_index() helper functions. The list is created with + * hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list(). + * Without these fixes hotplug vty-server adapter support goes crazy with this + * driver if the user removes a vty-server adapter. Moved free_irq() outside of + * the hvcs_final_close() function in order to get it out of the spinlock. + * Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping + * on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from + * arch/ppc64/hvcserver.h. * - * Also added sysfs attribute to manually disconnect the vty-server from the vty - * due to stupid firmware behavior when opening the connection then sending data - * then then quickly closing the connection would cause data loss on the - * receiving side. This required some reordering of the termination code. - * - * Fixed the hangup scenario and fixed memory leaks on module_exit. - * - * 1.2.0 -> 1.3.0 Moved from manual kernel thread creation & execution to - * kthread construct which replaced in-kernel IPC for thread termination with - * kthread_stop and kthread_should_stop. Explicit wait_queue handling was - * removed because kthread handles this. Minor bug fix to postpone partner_info - * clearing on hvcs_close until adapter removal to preserve context data for - * printk on partner connection free. Added lock to protect hvcs_structs so - * that hvcs_struct instances aren't added or removed during list traversal. - * Cleaned up comment style, added spaces after commas, and broke function - * declaration lines to be under 80 columns. + * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to + * prevent possible lockup with realtime scheduling as similarily pointed out by + * akpm in hvc_console. Changed resulted in the removal of hvcs_final_close() + * to reorder cleanup operations and prevent discarding of pending data during + * an hvcs_close(). Removed spinlock protection of hvcs_struct data members in + * hvcs_write_room() and hvcs_chars_in_buffer() because they aren't needed. */ -#define HVCS_DRIVER_VERSION "1.3.0" + +#define HVCS_DRIVER_VERSION "1.3.3" MODULE_AUTHOR("Ryan S. Arnold "); MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver"); @@ -120,6 +136,12 @@ MODULE_VERSION(HVCS_DRIVER_VERSION); /* + * Wait this long per iteration while trying to push buffered data to the + * hypervisor before allowing the tty to complete a close operation. + */ +#define HVCS_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ + +/* * Since the Linux TTY code does not currently (2-04-2004) support dynamic * addition of tty derived devices and we shouldn't allocate thousands of * tty_device pointers when the number of vty-server & vty partner connections @@ -138,9 +160,9 @@ /* * We let Linux assign us a major number and we start the minors at zero. There - * is no intuitive mapping between minor number and the target partition. The - * mapping of minor number is related to the order the vty-servers are exposed - * to this driver via the hvcs_probe function. + * is no intuitive mapping between minor number and the target vty-server + * adapter except that each new vty-server adapter is always assigned to the + * smallest minor number available. */ #define HVCS_MINOR_START 0 @@ -152,9 +174,6 @@ */ #define __ALIGNED__ __attribute__((__aligned__(8))) -/* Converged location code string length + 1 null terminator */ -#define CLC_LENGTH 80 - /* * How much data can firmware send with each hvc_put_chars()? Maybe this * should be moved into an architecture specific area. @@ -194,27 +213,41 @@ = "IBM hvcs (Hypervisor Virtual Console Server) Driver"; /* Status of partner info rescan triggered via sysfs. */ -static int hvcs_rescan_status = 0; +static int hvcs_rescan_status; static struct tty_driver *hvcs_tty_driver; /* - * This is used to associate a vty-server, as it is exposed to this driver, with - * a preallocated tty_struct.index. The dev node and hvcs index numbers are not - * re-used after device removal otherwise removing and adding a new one would - * link a /dev/hvcs* entry to a different vty-server than it did before the - * removal. Incidentally, a newly exposed vty-server will always map to an - * incrementally higher /dev/hvcs* entry than the last exposed vty-server. + * In order to be somewhat sane this driver always associates the hvcs_struct + * index element with the numerically equal tty->index. This means that a + * hotplugged vty-server adapter will always map to the lowest index valued + * device node. If vty-servers were hotplug removed from the system and then + * new ones added the new vty-server may have the largest slot number of all + * the vty-server adapters in the partition but it may have the lowest dev node + * index of all the adapters due to the hole left by the hotplug removed + * adapter. There are a set of functions provided to get the lowest index for + * a new device as well as return the index to the list. This list is allocated + * with a number of elements equal to the number of device nodes requested when + * the module was inserted. + */ +static int *hvcs_index_list; + +/* + * How large is the list? This is kept for traversal since the list is + * dynamically created. */ -static int hvcs_struct_count = -1; +static int hvcs_index_count; /* * Used by the khvcsd to pick up I/O operations when the kernel_thread is * already awake but potentially shifted to TASK_INTERRUPTIBLE state. */ -static int hvcs_kicked = 0; +static int hvcs_kicked; -/* Used the the kthread construct for task operations */ +/* + * Use by the kthread construct for task operations like waking the sleeping + * thread and stopping the kthread. + */ static struct task_struct *hvcs_task; /* @@ -223,7 +256,8 @@ */ static unsigned long *hvcs_pi_buff; -static spinlock_t hvcs_pi_lock; +/* Only allow one hvcs_struct to use the hvcs_pi_buff at a time. */ +static spinlock_t hvcs_pi_lock = SPIN_LOCK_UNLOCKED; /* One vty-server per hvcs_struct */ struct hvcs_struct { @@ -263,9 +297,9 @@ */ struct kobject kobj; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ - unsigned int p_unit_address; /* partner unit address */ - unsigned int p_partition_ID; /* partner partition ID */ - char p_location_code[CLC_LENGTH]; + uint32_t p_unit_address; /* partner unit address */ + uint32_t p_partition_ID; /* partner partition ID */ + char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */ struct list_head next; /* list management */ struct vio_dev *vdev; }; @@ -274,7 +308,7 @@ #define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj) static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs); -static spinlock_t hvcs_structs_lock; +static spinlock_t hvcs_structs_lock = SPIN_LOCK_UNLOCKED; static void hvcs_unthrottle(struct tty_struct *tty); static void hvcs_throttle(struct tty_struct *tty); @@ -297,7 +331,6 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, unsigned int irq, struct vio_dev *dev); -static void hvcs_final_close(struct hvcs_struct *hvcsd); static void destroy_hvcs_struct(struct kobject *kobj); static int hvcs_open(struct tty_struct *tty, struct file *filp); @@ -357,12 +390,11 @@ struct pt_regs *regs) { struct hvcs_struct *hvcsd = dev_instance; - unsigned long flags; - spin_lock_irqsave(&hvcsd->lock, flags); + spin_lock(&hvcsd->lock); vio_disable_interrupts(hvcsd->vdev); hvcsd->todo_mask |= HVCS_SCHED_READ; - spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcsd->lock); hvcs_kick(); return IRQ_HANDLED; @@ -371,7 +403,7 @@ /* This function must be called with the hvcsd->lock held */ static void hvcs_try_write(struct hvcs_struct *hvcsd) { - unsigned int unit_address = hvcsd->vdev->unit_address; + uint32_t unit_address = hvcsd->vdev->unit_address; struct tty_struct *tty = hvcsd->tty; int sent; @@ -382,9 +414,9 @@ hvcsd->chars_in_buffer ); if (sent > 0) { hvcsd->chars_in_buffer = 0; - wmb(); + /* wmb(); */ hvcsd->todo_mask &= ~(HVCS_TRY_WRITE); - wmb(); + /* wmb(); */ /* * We are still obligated to deliver the data to the @@ -393,10 +425,7 @@ * a non-existent tty. */ if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } } @@ -404,11 +433,11 @@ static int hvcs_io(struct hvcs_struct *hvcsd) { - unsigned int unit_address; + uint32_t unit_address; struct tty_struct *tty; char buf[HVCS_BUFF_LEN] __ALIGNED__; unsigned long flags; - int got; + int got = 0; int i; spin_lock_irqsave(&hvcsd->lock, flags); @@ -461,11 +490,8 @@ static int khvcsd(void *unused) { - struct hvcs_struct *hvcsd = NULL; - struct list_head *element; - struct list_head *safe_temp; + struct hvcs_struct *hvcsd; int hvcs_todo_mask; - unsigned long structs_flags; __set_current_state(TASK_RUNNING); @@ -474,12 +500,11 @@ hvcs_kicked = 0; wmb(); - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); - list_for_each_safe(element, safe_temp, &hvcs_structs) { - hvcsd = list_entry(element, struct hvcs_struct, next); - hvcs_todo_mask |= hvcs_io(hvcsd); + spin_lock(&hvcs_structs_lock); + list_for_each_entry(hvcsd, &hvcs_structs, next) { + hvcs_todo_mask |= hvcs_io(hvcsd); } - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); /* * If any of the hvcs adapters want to try a write or quick read @@ -506,6 +531,19 @@ }; MODULE_DEVICE_TABLE(vio, hvcs_driver_table); +static void hvcs_return_index(int index) +{ + /* Paranoia check */ + if (!hvcs_index_list) + return; + if (index < 0 || index >= hvcs_index_count) + return; + if (hvcs_index_list[index] == -1) + return; + else + hvcs_index_list[index] = -1; +} + /* callback when the kboject ref count reaches zero */ static void destroy_hvcs_struct(struct kobject *kobj) { @@ -513,6 +551,7 @@ struct vio_dev *vdev; unsigned long flags; + spin_lock(&hvcs_structs_lock); spin_lock_irqsave(&hvcsd->lock, flags); /* the list_del poisons the pointers */ @@ -524,7 +563,7 @@ " partner vty@%X:%d connection.\n", hvcsd->vdev->unit_address, hvcsd->p_unit_address, - (unsigned int)hvcsd->p_partition_ID); + (uint32_t)hvcsd->p_partition_ID); } printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n", hvcsd->vdev->unit_address); @@ -534,55 +573,60 @@ hvcsd->p_unit_address = 0; hvcsd->p_partition_ID = 0; - memset(&hvcsd->p_location_code[0], 0x00, CLC_LENGTH); + hvcs_return_index(hvcsd->index); + memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1); spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcs_structs_lock); hvcs_remove_device_attrs(vdev); kfree(hvcsd); } -/* This function must be called with hvcsd->lock held. */ -static void hvcs_final_close(struct hvcs_struct *hvcsd) -{ - vio_disable_interrupts(hvcsd->vdev); - free_irq(hvcsd->vdev->irq, hvcsd); - - hvcsd->todo_mask = 0; - - /* These two may be redundant if the operation was a close. */ - if (hvcsd->tty) { - hvcsd->tty->driver_data = NULL; - hvcsd->tty = NULL; - } - - hvcsd->open_count = 0; - - memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); - hvcsd->chars_in_buffer = 0; -} - static struct kobj_type hvcs_kobj_type = { .release = destroy_hvcs_struct, }; +static int hvcs_get_index(void) +{ + int i; + /* Paranoia check */ + if (!hvcs_index_list) { + printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n"); + return -EFAULT; + } + /* Find the numerically lowest first free index. */ + for(i = 0; i < hvcs_index_count; i++) { + if (hvcs_index_list[i] == -1) { + hvcs_index_list[i] = 0; + return i; + } + } + return -1; +} + static int __devinit hvcs_probe( struct vio_dev *dev, const struct vio_device_id *id) { struct hvcs_struct *hvcsd; - unsigned long structs_flags; + int index; if (!dev || !id) { printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); return -EPERM; } + /* early to avoid cleanup on failure */ + index = hvcs_get_index(); + if (index < 0) { + return -EFAULT; + } + hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL); - if (!hvcsd) { + if (!hvcsd) return -ENODEV; - } /* hvcsd->tty is zeroed out with the memset */ memset(hvcsd, 0x00, sizeof(*hvcsd)); @@ -596,7 +640,9 @@ hvcsd->vdev = dev; dev->dev.driver_data = hvcsd; - hvcsd->index = ++hvcs_struct_count; + hvcsd->index = index; + + /* hvcsd->index = ++hvcs_struct_count; */ hvcsd->chars_in_buffer = 0; hvcsd->todo_mask = 0; hvcsd->connected = 0; @@ -617,15 +663,15 @@ * will get -ENODEV. */ - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); + spin_lock(&hvcs_structs_lock); list_add_tail(&(hvcsd->next), &hvcs_structs); - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); hvcs_create_device_attrs(hvcsd); - printk(KERN_INFO "HVCS: Added vty-server@%X.\n", dev->unit_address); + printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); /* * DON'T enable interrupts here because there is no user to receive the @@ -688,8 +734,8 @@ hvcsd->p_unit_address = pi->unit_address; hvcsd->p_partition_ID = pi->partition_ID; clclength = strlen(&pi->location_code[0]); - if (clclength > CLC_LENGTH - 1) - clclength = CLC_LENGTH - 1; + if (clclength > HVCS_CLC_LENGTH) + clclength = HVCS_CLC_LENGTH; /* copy the null-term char too */ strncpy(&hvcsd->p_location_code[0], @@ -711,20 +757,18 @@ */ static int hvcs_get_pi(struct hvcs_struct *hvcsd) { - /* struct hvcs_partner_info *head_pi = NULL; */ - struct hvcs_partner_info *pi = NULL; - unsigned int unit_address = hvcsd->vdev->unit_address; + struct hvcs_partner_info *pi; + uint32_t unit_address = hvcsd->vdev->unit_address; struct list_head head; - unsigned long flags; int retval; - spin_lock_irqsave(&hvcs_pi_lock, flags); + spin_lock(&hvcs_pi_lock); if (!hvcs_pi_buff) { - spin_unlock_irqrestore(&hvcs_pi_lock, flags); + spin_unlock(&hvcs_pi_lock); return -EFAULT; } retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff); - spin_unlock_irqrestore(&hvcs_pi_lock, flags); + spin_unlock(&hvcs_pi_lock); if (retval) { printk(KERN_ERR "HVCS: Failed to fetch partner" " info for vty-server@%x.\n", unit_address); @@ -748,11 +792,10 @@ */ static int hvcs_rescan_devices_list(void) { - struct hvcs_struct *hvcsd = NULL; + struct hvcs_struct *hvcsd; unsigned long flags; - unsigned long structs_flags; - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); + spin_lock(&hvcs_structs_lock); list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); @@ -760,7 +803,7 @@ spin_unlock_irqrestore(&hvcsd->lock, flags); } - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); return 0; } @@ -848,13 +891,14 @@ unsigned int irq, struct vio_dev *vdev) { unsigned long flags; + int rc; /* * It is possible that the vty-server was removed between the time that * the conn was registered and now. */ - if (!request_irq(irq, &hvcs_handle_interrupt, - SA_INTERRUPT, "ibmhvcs", hvcsd)) { + if (!(rc = request_irq(irq, &hvcs_handle_interrupt, + SA_INTERRUPT, "ibmhvcs", hvcsd))) { /* * It is possible the vty-server was removed after the irq was * requested but before we have time to enable interrupts. @@ -874,7 +918,7 @@ hvcs_partner_free(hvcsd); spin_unlock_irqrestore(&hvcsd->lock, flags); - return -ENODEV; + return rc; } @@ -888,22 +932,17 @@ struct hvcs_struct *hvcs_get_by_index(int index) { struct hvcs_struct *hvcsd = NULL; - struct list_head *element; - struct list_head *safe_temp; unsigned long flags; - unsigned long structs_flags; - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); + spin_lock(&hvcs_structs_lock); /* We can immediately discard OOB requests */ if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { - list_for_each_safe(element, safe_temp, &hvcs_structs) { - hvcsd = list_entry(element, struct hvcs_struct, next); + list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { kobject_get(&hvcsd->kobj); spin_unlock_irqrestore(&hvcsd->lock, flags); - spin_unlock_irqrestore(&hvcs_structs_lock, - structs_flags); + spin_unlock(&hvcs_structs_lock); return hvcsd; } spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -911,7 +950,7 @@ hvcsd = NULL; } - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); return hvcsd; } @@ -921,12 +960,13 @@ */ static int hvcs_open(struct tty_struct *tty, struct file *filp) { - struct hvcs_struct *hvcsd = NULL; - int retval = 0; + struct hvcs_struct *hvcsd; + int rc, retval = 0; unsigned long flags; unsigned int irq; struct vio_dev *vdev; unsigned long unit_address; + struct kobject *kobjp; if (tty->driver_data) goto fast_open; @@ -936,7 +976,8 @@ * This function increments the kobject index. */ if (!(hvcsd = hvcs_get_by_index(tty->index))) { - printk(KERN_WARNING "HVCS: open failed, no index.\n"); + printk(KERN_WARNING "HVCS: open failed, no device associated" + " with tty->index %d.\n", tty->index); return -ENODEV; } @@ -959,7 +1000,7 @@ */ tty->low_latency = 1; - memset(&hvcsd->buffer[0], 0x3F, HVCS_BUFF_LEN); + memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); /* * Save these in the spinlock for the enable operations that need them @@ -974,12 +1015,12 @@ /* * This must be done outside of the spinlock because it requests irqs - * and will grab the spinlcok and free the connection if it fails. + * and will grab the spinlock and free the connection if it fails. */ - if ((hvcs_enable_device(hvcsd, unit_address, irq, vdev))) { + if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { kobject_put(&hvcsd->kobj); printk(KERN_WARNING "HVCS: enable device failed.\n"); - return -ENODEV; + return rc; } goto open_success; @@ -1002,16 +1043,17 @@ open_success: hvcs_kick(); - printk(KERN_INFO "HVCS: vty-server@%X opened.\n", + printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", hvcsd->vdev->unit_address ); return 0; error_release: + kobjp = &hvcsd->kobj; spin_unlock_irqrestore(&hvcsd->lock, flags); kobject_put(&hvcsd->kobj); - printk(KERN_WARNING "HVCS: HVCS partner connect failed.\n"); + printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; } @@ -1020,6 +1062,7 @@ struct hvcs_struct *hvcsd; unsigned long flags; struct kobject *kobjp; + int irq = NO_IRQ; /* * Is someone trying to close the file associated with this device after @@ -1039,14 +1082,10 @@ hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); + kobjp = &hvcsd->kobj; if (--hvcsd->open_count == 0) { - /* - * This line is important because it tells hvcs_open that this - * device needs to be re-configured the next time hvcs_open is - * called. - */ - hvcsd->tty->driver_data = NULL; + vio_disable_interrupts(hvcsd->vdev); /* * NULL this early so that the kernel_thread doesn't try to @@ -1055,34 +1094,28 @@ */ hvcsd->tty = NULL; - /* - * Block the close until all the buffered data has been - * delivered. - */ - while(hvcsd->chars_in_buffer) { - spin_unlock_irqrestore(&hvcsd->lock, flags); + irq = hvcsd->vdev->irq; + spin_unlock_irqrestore(&hvcsd->lock, flags); - /* - * Give the kernel thread the hvcs_struct so that it can - * try to deliver the remaining data but block the close - * operation by spinning in this function so that other - * tty operations have to wait. - */ - yield(); - spin_lock_irqsave(&hvcsd->lock, flags); - } + tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); - hvcs_final_close(hvcsd); + /* + * This line is important because it tells hvcs_open that this + * device needs to be re-configured the next time hvcs_open is + * called. + */ + tty->driver_data = NULL; + free_irq(irq, hvcsd); + kobject_put(kobjp); + return; } else if (hvcsd->open_count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" " is missmanaged.\n", - hvcsd->vdev->unit_address, hvcsd->open_count); + hvcsd->vdev->unit_address, hvcsd->open_count); } - kobjp = &hvcsd->kobj; spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(kobjp); } @@ -1092,6 +1125,7 @@ unsigned long flags; int temp_open_count; struct kobject *kobjp; + int irq = NO_IRQ; spin_lock_irqsave(&hvcsd->lock, flags); /* Preserve this so that we know how many kobject refs to put */ @@ -1101,15 +1135,31 @@ * Don't kobject put inside the spinlock because the destruction * callback may use the spinlock and it may get called before the * spinlock has been released. Get a pointer to the kobject and - * kobject_put on that instead. + * kobject_put on that after releasing the spinlock. */ kobjp = &hvcsd->kobj; - /* Calling this will drop any buffered data on the floor. */ - hvcs_final_close(hvcsd); + vio_disable_interrupts(hvcsd->vdev); + + hvcsd->todo_mask = 0; + + /* I don't think the tty needs the hvcs_struct pointer after a hangup */ + hvcsd->tty->driver_data = NULL; + hvcsd->tty = NULL; + + hvcsd->open_count = 0; + + /* This will drop any buffered data on the floor which is OK in a hangup + * scenario. */ + memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); + hvcsd->chars_in_buffer = 0; + + irq = hvcsd->vdev->irq; spin_unlock_irqrestore(&hvcsd->lock, flags); + free_irq(irq, hvcsd); + /* * We need to kobject_put() for every open_count we have since the * tty_hangup() function doesn't invoke a close per open connection on a @@ -1259,28 +1309,18 @@ static int hvcs_write_room(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - unsigned long flags; - int retval; if (!hvcsd || hvcsd->open_count <= 0) return 0; - spin_lock_irqsave(&hvcsd->lock, flags); - retval = HVCS_BUFF_LEN - hvcsd->chars_in_buffer; - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; + return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; } static int hvcs_chars_in_buffer(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - unsigned long flags; - int retval; - spin_lock_irqsave(&hvcsd->lock, flags); - retval = hvcsd->chars_in_buffer; - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; + return hvcsd->chars_in_buffer; } static struct tty_operations hvcs_ops = { @@ -1294,6 +1334,28 @@ .throttle = hvcs_throttle, }; +static int hvcs_alloc_index_list(int n) +{ + int i; + hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); + if (!hvcs_index_list) + return -ENOMEM; + hvcs_index_count = n; + for(i = 0; i < hvcs_index_count; i++) + hvcs_index_list[i] = -1; + return 0; +} + +static void hvcs_free_index_list(void) +{ + /* Paranoia check to be thorough. */ + if (hvcs_index_list) { + kfree(hvcs_index_list); + hvcs_index_list = NULL; + hvcs_index_count = 0; + } +} + static int __init hvcs_module_init(void) { int rc; @@ -1312,6 +1374,9 @@ if (!hvcs_tty_driver) return -ENOMEM; + if (hvcs_alloc_index_list(num_ttys_to_alloc)) + return -ENOMEM; + hvcs_tty_driver->owner = THIS_MODULE; hvcs_tty_driver->driver_name = hvcs_driver_name; @@ -1342,19 +1407,25 @@ if (tty_register_driver(hvcs_tty_driver)) { printk(KERN_ERR "HVCS: registration " " as a tty driver failed.\n"); + hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); - return rc; + return -EIO; } - hvcs_structs_lock = SPIN_LOCK_UNLOCKED; - - hvcs_pi_lock = SPIN_LOCK_UNLOCKED; hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!hvcs_pi_buff) { + tty_unregister_driver(hvcs_tty_driver); + hvcs_free_index_list(); + put_tty_driver(hvcs_tty_driver); + return -ENOMEM; + } hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); if (IS_ERR(hvcs_task)) { - printk("khvcsd creation failed. Driver not loaded.\n"); + printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); kfree(hvcs_pi_buff); + tty_unregister_driver(hvcs_tty_driver); + hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); return -EIO; } @@ -1374,8 +1445,6 @@ static void __exit hvcs_module_exit(void) { - unsigned long flags; - /* * This driver receives hvcs_remove callbacks for each device upon * module removal. @@ -1387,10 +1456,10 @@ */ kthread_stop(hvcs_task); - spin_lock_irqsave(&hvcs_pi_lock, flags); + spin_lock(&hvcs_pi_lock); kfree(hvcs_pi_buff); hvcs_pi_buff = NULL; - spin_unlock_irqrestore(&hvcs_pi_lock, flags); + spin_unlock(&hvcs_pi_lock); hvcs_remove_driver_attrs(); @@ -1398,6 +1467,8 @@ tty_unregister_driver(hvcs_tty_driver); + hvcs_free_index_list(); + put_tty_driver(hvcs_tty_driver); printk(KERN_INFO "HVCS: driver module removed.\n"); @@ -1499,7 +1570,7 @@ " partner vty@%X:%d connection.\n", hvcsd->vdev->unit_address, hvcsd->p_unit_address, - (unsigned int)hvcsd->p_partition_ID); + (uint32_t)hvcsd->p_partition_ID); spin_unlock_irqrestore(&hvcsd->lock, flags); return count; @@ -1520,11 +1591,27 @@ static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, hvcs_vterm_state_show, hvcs_vterm_state_store); +static ssize_t hvcs_index_show(struct device *dev, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%d\n", hvcsd->index); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} + +static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); + static struct attribute *hvcs_attrs[] = { &dev_attr_partner_vtys.attr, &dev_attr_partner_clcs.attr, &dev_attr_current_vty.attr, &dev_attr_vterm_state.attr, + &dev_attr_index.attr, NULL, }; diff -Nru a/drivers/char/hvsi.c b/drivers/char/hvsi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/hvsi.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,1319 @@ +/* + * Copyright (C) 2004 Hollis Blanchard , IBM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Host Virtual Serial Interface (HVSI) is a protocol between the hosted OS + * and the service processor on IBM pSeries servers. On these servers, there + * are no serial ports under the OS's control, and sometimes there is no other + * console available either. However, the service processor has two standard + * serial ports, so this over-complicated protocol allows the OS to control + * those ports by proxy. + * + * Besides data, the procotol supports the reading/writing of the serial + * port's DTR line, and the reading of the CD line. This is to allow the OS to + * control a modem attached to the service processor's serial port. Note that + * the OS cannot change the speed of the port through this protocol. + */ + +/* TODO: + * test FSP reset + * add udbg support for xmon/kdb + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HVSI_MAJOR 229 +#define HVSI_MINOR 128 +#define MAX_NR_HVSI_CONSOLES 4 + +#define HVSI_TIMEOUT (5*HZ) +#define HVSI_VERSION 1 +#define HVSI_MAX_PACKET 256 +#define HVSI_MAX_READ 16 +#define HVSI_MAX_OUTGOING_DATA 12 +#define N_OUTBUF 12 + +/* + * we pass data via two 8-byte registers, so we would like our char arrays + * properly aligned for those loads. + */ +#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) + +struct hvsi_struct { + struct work_struct writer; + wait_queue_head_t emptyq; /* woken when outbuf is emptied */ + wait_queue_head_t stateq; /* woken when HVSI state changes */ + spinlock_t lock; + int index; + struct tty_struct *tty; + unsigned int count; + uint8_t throttle_buf[128]; + uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ + /* inbuf is for packet reassembly. leave a little room for leftovers. */ + uint8_t inbuf[HVSI_MAX_PACKET + HVSI_MAX_READ]; + uint8_t *inbuf_end; + int n_throttle; + int n_outbuf; + uint32_t vtermno; + uint32_t virq; + atomic_t seqno; /* HVSI packet sequence number */ + uint16_t mctrl; + uint8_t state; /* HVSI protocol state */ + uint8_t flags; +#ifdef CONFIG_MAGIC_SYSRQ + uint8_t sysrq; +#endif /* CONFIG_MAGIC_SYSRQ */ +}; +static struct hvsi_struct hvsi_ports[MAX_NR_HVSI_CONSOLES]; + +static struct tty_driver *hvsi_driver; +static int hvsi_count; +static int (*hvsi_wait)(struct hvsi_struct *hp, int state); + +enum HVSI_PROTOCOL_STATE { + HVSI_CLOSED, + HVSI_WAIT_FOR_VER_RESPONSE, + HVSI_WAIT_FOR_VER_QUERY, + HVSI_OPEN, + HVSI_WAIT_FOR_MCTRL_RESPONSE, +}; +#define HVSI_CONSOLE 0x1 + +#define VS_DATA_PACKET_HEADER 0xff +#define VS_CONTROL_PACKET_HEADER 0xfe +#define VS_QUERY_PACKET_HEADER 0xfd +#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc + +/* control verbs */ +#define VSV_SET_MODEM_CTL 1 /* to service processor only */ +#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */ +#define VSV_CLOSE_PROTOCOL 3 + +/* query verbs */ +#define VSV_SEND_VERSION_NUMBER 1 +#define VSV_SEND_MODEM_CTL_STATUS 2 + +/* yes, these masks are not consecutive. */ +#define HVSI_TSDTR 0x01 +#define HVSI_TSCD 0x20 + +struct hvsi_header { + uint8_t type; + uint8_t len; + uint16_t seqno; +} __attribute__((packed)); + +struct hvsi_data { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint8_t data[HVSI_MAX_OUTGOING_DATA]; +} __attribute__((packed)); + +struct hvsi_control { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; + /* optional depending on verb: */ + uint32_t word; + uint32_t mask; +} __attribute__((packed)); + +struct hvsi_query { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; +} __attribute__((packed)); + +struct hvsi_query_response { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; + uint16_t query_seqno; + union { + uint8_t version; + uint32_t mctrl_word; + } u; +} __attribute__((packed)); + +static inline int is_open(struct hvsi_struct *hp) +{ + /* if we're waiting for an mctrl then we're already open */ + return (hp->state == HVSI_OPEN) + || (hp->state == HVSI_WAIT_FOR_MCTRL_RESPONSE); +} + +static inline void print_state(struct hvsi_struct *hp) +{ +#ifdef DEBUG + static const char *state_names[] = { + "HVSI_CLOSED", + "HVSI_WAIT_FOR_VER_RESPONSE", + "HVSI_WAIT_FOR_VER_QUERY", + "HVSI_OPEN", + "HVSI_WAIT_FOR_MCTRL_RESPONSE", + }; + const char *name = state_names[hp->state]; + + if (hp->state > (sizeof(state_names)/sizeof(char*))) + name = "UNKNOWN"; + + pr_debug("hvsi%i: state = %s\n", hp->index, name); +#endif /* DEBUG */ +} + +static inline void __set_state(struct hvsi_struct *hp, int state) +{ + hp->state = state; + print_state(hp); + wake_up_all(&hp->stateq); +} + +static inline void set_state(struct hvsi_struct *hp, int state) +{ + unsigned long flags; + + spin_lock_irqsave(&hp->lock, flags); + __set_state(hp, state); + spin_unlock_irqrestore(&hp->lock, flags); +} + +static inline int len_packet(const uint8_t *packet) +{ + return (int)((struct hvsi_header *)packet)->len; +} + +static inline int is_header(const uint8_t *packet) +{ + struct hvsi_header *header = (struct hvsi_header *)packet; + return header->type >= VS_QUERY_RESPONSE_PACKET_HEADER; +} + +static inline int got_packet(const struct hvsi_struct *hp, uint8_t *packet) +{ + if (hp->inbuf_end < packet + sizeof(struct hvsi_header)) + return 0; /* don't even have the packet header */ + + if (hp->inbuf_end < (packet + len_packet(packet))) + return 0; /* don't have the rest of the packet */ + + return 1; +} + +/* shift remaining bytes in packetbuf down */ +static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to) +{ + int remaining = (int)(hp->inbuf_end - read_to); + + pr_debug("%s: %i chars remain\n", __FUNCTION__, remaining); + + if (read_to != hp->inbuf) + memmove(hp->inbuf, read_to, remaining); + + hp->inbuf_end = hp->inbuf + remaining; +} + +#ifdef DEBUG +#define dbg_dump_packet(packet) dump_packet(packet) +#define dbg_dump_hex(data, len) dump_hex(data, len) +#else +#define dbg_dump_packet(packet) do { } while (0) +#define dbg_dump_hex(data, len) do { } while (0) +#endif + +static void dump_hex(const uint8_t *data, int len) +{ + int i; + + printk(" "); + for (i=0; i < len; i++) + printk("%.2x", data[i]); + + printk("\n "); + for (i=0; i < len; i++) { + if (isprint(data[i])) + printk("%c", data[i]); + else + printk("."); + } + printk("\n"); +} + +static void dump_packet(uint8_t *packet) +{ + struct hvsi_header *header = (struct hvsi_header *)packet; + + printk("type 0x%x, len %i, seqno %i:\n", header->type, header->len, + header->seqno); + + dump_hex(packet, header->len); +} + +/* can't use hvc_get_chars because that strips CRs */ +static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) +{ + unsigned long got; + + if (plpar_hcall(H_GET_TERM_CHAR, hp->vtermno, 0, 0, 0, &got, + (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) + return got; + return 0; +} + +/* + * we can't call tty_hangup() directly here because we need to call that + * outside of our lock + */ +static struct tty_struct *hvsi_recv_control(struct hvsi_struct *hp, + uint8_t *packet) +{ + struct tty_struct *to_hangup = NULL; + struct hvsi_control *header = (struct hvsi_control *)packet; + + switch (header->verb) { + case VSV_MODEM_CTL_UPDATE: + if ((header->word & HVSI_TSCD) == 0) { + /* CD went away; no more connection */ + pr_debug("hvsi%i: CD dropped\n", hp->index); + hp->mctrl &= TIOCM_CD; + if (!(hp->tty->flags & CLOCAL)) + to_hangup = hp->tty; + } + break; + case VSV_CLOSE_PROTOCOL: + printk(KERN_DEBUG + "hvsi%i: service processor closed connection!\n", hp->index); + __set_state(hp, HVSI_CLOSED); + to_hangup = hp->tty; + hp->tty = NULL; + break; + default: + printk(KERN_WARNING "hvsi%i: unknown HVSI control packet: ", + hp->index); + dump_packet(packet); + break; + } + + return to_hangup; +} + +static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet) +{ + struct hvsi_query_response *resp = (struct hvsi_query_response *)packet; + + switch (hp->state) { + case HVSI_WAIT_FOR_VER_RESPONSE: + __set_state(hp, HVSI_WAIT_FOR_VER_QUERY); + break; + case HVSI_WAIT_FOR_MCTRL_RESPONSE: + hp->mctrl = 0; + if (resp->u.mctrl_word & HVSI_TSDTR) + hp->mctrl |= TIOCM_DTR; + if (resp->u.mctrl_word & HVSI_TSCD) + hp->mctrl |= TIOCM_CD; + __set_state(hp, HVSI_OPEN); + break; + default: + printk(KERN_ERR "hvsi%i: unexpected query response: ", hp->index); + dump_packet(packet); + break; + } +} + +/* respond to service processor's version query */ +static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) +{ + struct hvsi_query_response packet __ALIGNED__; + int wrote; + + packet.type = VS_QUERY_RESPONSE_PACKET_HEADER; + packet.len = sizeof(struct hvsi_query_response); + packet.seqno = atomic_inc_return(&hp->seqno); + packet.verb = VSV_SEND_VERSION_NUMBER; + packet.u.version = HVSI_VERSION; + packet.query_seqno = query_seqno+1; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't send query response!\n", + hp->index); + return -EIO; + } + + return 0; +} + +static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) +{ + struct hvsi_query *query = (struct hvsi_query *)packet; + + switch (hp->state) { + case HVSI_WAIT_FOR_VER_QUERY: + __set_state(hp, HVSI_OPEN); + hvsi_version_respond(hp, query->seqno); + break; + default: + printk(KERN_ERR "hvsi%i: unexpected query: ", hp->index); + dump_packet(packet); + break; + } +} + +static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) +{ + int i; + + for (i=0; i < len; i++) { + char c = buf[i]; +#ifdef CONFIG_MAGIC_SYSRQ + if (c == '\0') { + hp->sysrq = 1; + continue; + } else if (hp->sysrq) { + handle_sysrq(c, NULL, hp->tty); + hp->sysrq = 0; + continue; + } +#endif /* CONFIG_MAGIC_SYSRQ */ + tty_insert_flip_char(hp->tty, c, 0); + } +} + +/* + * We could get 252 bytes of data at once here. But the tty layer only + * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow + * it. Accordingly we won't send more than 128 bytes at a time to the flip + * buffer, which will give the tty buffer a chance to throttle us. Should the + * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be + * revisited. + */ +#define TTY_THRESHOLD_THROTTLE 128 +static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, + const uint8_t *packet) +{ + const struct hvsi_header *header = (const struct hvsi_header *)packet; + const uint8_t *data = packet + sizeof(struct hvsi_header); + int datalen = header->len - sizeof(struct hvsi_header); + int overflow = datalen - TTY_THRESHOLD_THROTTLE; + + pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); + + if (datalen == 0) + return NULL; + + if (overflow > 0) { + pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__); + datalen = TTY_THRESHOLD_THROTTLE; + } + + hvsi_insert_chars(hp, data, datalen); + + if (overflow > 0) { + /* + * we still have more data to deliver, so we need to save off the + * overflow and send it later + */ + pr_debug("%s: deferring overflow\n", __FUNCTION__); + memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow); + hp->n_throttle = overflow; + } + + return hp->tty; +} + +/* + * Returns true/false indicating data successfully read from hypervisor. + * Used both to get packets for tty connections and to advance the state + * machine during console handshaking (in which case tty = NULL and we ignore + * incoming data). + */ +static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, + struct tty_struct **hangup) +{ + uint8_t *packet = hp->inbuf; + int chunklen; + + *flip = NULL; + *hangup = NULL; + + chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); + if (chunklen == 0) + return 0; + + pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen); + dbg_dump_hex(hp->inbuf_end, chunklen); + + hp->inbuf_end += chunklen; + + /* handle all completed packets */ + while ((packet < hp->inbuf_end) && got_packet(hp, packet)) { + struct hvsi_header *header = (struct hvsi_header *)packet; + + if (!is_header(packet)) { + printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index); + /* skip bytes until we find a header or run out of data */ + while ((packet < hp->inbuf_end) && (!is_header(packet))) + packet++; + continue; + } + + pr_debug("%s: handling %i-byte packet\n", __FUNCTION__, + len_packet(packet)); + dbg_dump_packet(packet); + + switch (header->type) { + case VS_DATA_PACKET_HEADER: + if (!is_open(hp)) + break; + if (hp->tty == NULL) + break; /* no tty buffer to put data in */ + *flip = hvsi_recv_data(hp, packet); + break; + case VS_CONTROL_PACKET_HEADER: + *hangup = hvsi_recv_control(hp, packet); + break; + case VS_QUERY_RESPONSE_PACKET_HEADER: + hvsi_recv_response(hp, packet); + break; + case VS_QUERY_PACKET_HEADER: + hvsi_recv_query(hp, packet); + break; + default: + printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n", + hp->index, header->type); + dump_packet(packet); + break; + } + + packet += len_packet(packet); + + if (*hangup) { + pr_debug("%s: hangup\n", __FUNCTION__); + /* + * we need to send the hangup now before receiving any more data. + * If we get "data, hangup, data", we can't deliver the second + * data before the hangup. + */ + break; + } + } + + compact_inbuf(hp, packet); + + return 1; +} + +static void hvsi_send_overflow(struct hvsi_struct *hp) +{ + pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__, + hp->n_throttle); + + hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); + hp->n_throttle = 0; +} + +/* + * must get all pending data because we only get an irq on empty->non-empty + * transition + */ +static irqreturn_t hvsi_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct tty_struct *flip; + struct tty_struct *hangup; + unsigned long flags; + irqreturn_t handled = IRQ_NONE; + int again = 1; + + pr_debug("%s\n", __FUNCTION__); + + while (again) { + spin_lock_irqsave(&hp->lock, flags); + again = hvsi_load_chunk(hp, &flip, &hangup); + handled = IRQ_HANDLED; + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * we have to call tty_flip_buffer_push() and tty_hangup() outside our + * spinlock. But we also have to keep going until we've read all the + * available data. + */ + + if (flip) { + /* there was data put in the tty flip buffer */ + tty_flip_buffer_push(flip); + flip = NULL; + } + + if (hangup) { + tty_hangup(hangup); + } + } + + spin_lock_irqsave(&hp->lock, flags); + if (hp->tty && hp->n_throttle + && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { + /* we weren't hung up and we weren't throttled, so we can deliver the + * rest now */ + flip = hp->tty; + hvsi_send_overflow(hp); + } + spin_unlock_irqrestore(&hp->lock, flags); + + if (flip) { + tty_flip_buffer_push(flip); + } + + return handled; +} + +/* for boot console, before the irq handler is running */ +static int __init poll_for_state(struct hvsi_struct *hp, int state) +{ + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + + for (;;) { + hvsi_interrupt(hp->virq, (void *)hp, NULL); /* get pending data */ + + if (hp->state == state) + return 0; + + mdelay(5); + if (time_after(jiffies, end_jiffies)) + return -EIO; + } +} + +/* wait for irq handler to change our state */ +static int wait_for_state(struct hvsi_struct *hp, int state) +{ + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + unsigned long timeout; + int ret = 0; + + DECLARE_WAITQUEUE(myself, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&hp->stateq, &myself); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (hp->state == state) + break; + timeout = end_jiffies - jiffies; + if (time_after(jiffies, end_jiffies)) { + ret = -EIO; + break; + } + schedule_timeout(timeout); + } + remove_wait_queue(&hp->stateq, &myself); + set_current_state(TASK_RUNNING); + + return ret; +} + +static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) +{ + struct hvsi_query packet __ALIGNED__; + int wrote; + + packet.type = VS_QUERY_PACKET_HEADER; + packet.len = sizeof(struct hvsi_query); + packet.seqno = atomic_inc_return(&hp->seqno); + packet.verb = verb; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index, + wrote); + return -EIO; + } + + return 0; +} + +static int hvsi_get_mctrl(struct hvsi_struct *hp) +{ + int ret; + + set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE); + hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS); + + ret = hvsi_wait(hp, HVSI_OPEN); + if (ret < 0) { + printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index); + set_state(hp, HVSI_OPEN); + return ret; + } + + pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl); + + return 0; +} + +/* note that we can only set DTR */ +static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) +{ + struct hvsi_control packet __ALIGNED__; + int wrote; + + packet.type = VS_CONTROL_PACKET_HEADER, + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = sizeof(struct hvsi_control); + packet.verb = VSV_SET_MODEM_CTL; + packet.mask = HVSI_TSDTR; + + if (mctrl & TIOCM_DTR) + packet.word = HVSI_TSDTR; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index); + return -EIO; + } + + return 0; +} + +static void hvsi_drain_input(struct hvsi_struct *hp) +{ + uint8_t buf[HVSI_MAX_READ] __ALIGNED__; + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + + while (time_before(end_jiffies, jiffies)) + if (0 == hvsi_read(hp, buf, HVSI_MAX_READ)) + break; +} + +static int hvsi_handshake(struct hvsi_struct *hp) +{ + int ret; + + /* + * We could have a CLOSE or other data waiting for us before we even try + * to open; try to throw it all away so we don't get confused. (CLOSE + * is the first message sent up the pipe when the FSP comes online. We + * need to distinguish between "it came up a while ago and we're the first + * user" and "it was just reset before it saw our handshake packet".) + */ + hvsi_drain_input(hp); + + set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE); + ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER); + if (ret < 0) { + printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index); + return ret; + } + + ret = hvsi_wait(hp, HVSI_OPEN); + if (ret < 0) + return ret; + + return 0; +} + +static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count) +{ + struct hvsi_data packet __ALIGNED__; + int ret; + + BUG_ON(count > HVSI_MAX_OUTGOING_DATA); + + packet.type = VS_DATA_PACKET_HEADER; + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = count + sizeof(struct hvsi_header); + memcpy(&packet.data, buf, count); + + ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (ret == packet.len) { + /* return the number of chars written, not the packet length */ + return count; + } + return ret; /* return any errors */ +} + +static void hvsi_close_protocol(struct hvsi_struct *hp) +{ + struct hvsi_control packet __ALIGNED__; + + packet.type = VS_CONTROL_PACKET_HEADER; + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = 6; + packet.verb = VSV_CLOSE_PROTOCOL; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); +} + +static int hvsi_open(struct tty_struct *tty, struct file *filp) +{ + struct hvsi_struct *hp; + unsigned long flags; + int line = tty->index; + int ret; + + pr_debug("%s\n", __FUNCTION__); + + if (line < 0 || line >= hvsi_count) + return -ENODEV; + hp = &hvsi_ports[line]; + + tty->driver_data = hp; + tty->low_latency = 1; /* avoid throttle/tty_flip_buffer_push race */ + + spin_lock_irqsave(&hp->lock, flags); + hp->tty = tty; + hp->count++; + atomic_set(&hp->seqno, 0); + h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); + spin_unlock_irqrestore(&hp->lock, flags); + + if (hp->flags & HVSI_CONSOLE) + return 0; /* this has already been handshaked as the console */ + + ret = hvsi_handshake(hp); + if (ret < 0) { + printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name); + return ret; + } + + ret = hvsi_get_mctrl(hp); + if (ret < 0) { + printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name); + return ret; + } + + ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); + if (ret < 0) { + printk(KERN_ERR "%s: couldn't set DTR\n", tty->name); + return ret; + } + + return 0; +} + +/* wait for hvsi_write_worker to empty hp->outbuf */ +static void hvsi_flush_output(struct hvsi_struct *hp) +{ + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + unsigned long timeout; + + DECLARE_WAITQUEUE(myself, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&hp->emptyq, &myself); + + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (hp->n_outbuf <= 0) + break; + timeout = end_jiffies - jiffies; + if (time_after(jiffies, end_jiffies)) + break; + schedule_timeout(timeout); + } + remove_wait_queue(&hp->emptyq, &myself); + set_current_state(TASK_RUNNING); + + /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ + cancel_delayed_work(&hp->writer); + flush_scheduled_work(); + + /* + * it's also possible that our timeout expired and hvsi_write_worker + * didn't manage to push outbuf. poof. + */ + hp->n_outbuf = 0; +} + +static void hvsi_close(struct tty_struct *tty, struct file *filp) +{ + struct hvsi_struct *hp = tty->driver_data; + unsigned long flags; + + pr_debug("%s\n", __FUNCTION__); + + if (tty_hung_up_p(filp)) + return; + + spin_lock_irqsave(&hp->lock, flags); + + if (--hp->count == 0) { + hp->tty = NULL; + hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ + + /* only close down connection if it is not the console */ + if (!(hp->flags & HVSI_CONSOLE)) { + h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); /* no more irqs */ + __set_state(hp, HVSI_CLOSED); + /* + * any data delivered to the tty layer after this will be + * discarded (except for XON/XOFF) + */ + tty->closing = 1; + + spin_unlock_irqrestore(&hp->lock, flags); + + /* let any existing irq handlers finish. no more will start. */ + synchronize_irq(hp->virq); + + /* hvsi_write_worker will re-schedule until outbuf is empty. */ + hvsi_flush_output(hp); + + /* tell FSP to stop sending data */ + hvsi_close_protocol(hp); + + /* + * drain anything FSP is still in the middle of sending, and let + * hvsi_handshake drain the rest on the next open. + */ + hvsi_drain_input(hp); + + spin_lock_irqsave(&hp->lock, flags); + } + } else if (hp->count < 0) + printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", + hp - hvsi_ports, hp->count); + + spin_unlock_irqrestore(&hp->lock, flags); +} + +static void hvsi_hangup(struct tty_struct *tty) +{ + struct hvsi_struct *hp = tty->driver_data; + + pr_debug("%s\n", __FUNCTION__); + + hp->count = 0; + hp->tty = NULL; +} + +/* called with hp->lock held */ +static void hvsi_push(struct hvsi_struct *hp) +{ + int n; + + if (hp->n_outbuf <= 0) + return; + + n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf); + if (n != 0) { + /* + * either all data was sent or there was an error, and we throw away + * data on error. + */ + hp->n_outbuf = 0; + } +} + +/* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ +static void hvsi_write_worker(void *arg) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)arg; + unsigned long flags; +#ifdef DEBUG + static long start_j = 0; + + if (start_j == 0) + start_j = jiffies; +#endif /* DEBUG */ + + spin_lock_irqsave(&hp->lock, flags); + + hvsi_push(hp); + if (hp->n_outbuf > 0) + schedule_delayed_work(&hp->writer, 10); + else { +#ifdef DEBUG + pr_debug("%s: outbuf emptied after %li jiffies\n", __FUNCTION__, + jiffies - start_j); + start_j = 0; +#endif /* DEBUG */ + wake_up_all(&hp->emptyq); + if (test_bit(TTY_DO_WRITE_WAKEUP, &hp->tty->flags) + && hp->tty->ldisc.write_wakeup) + hp->tty->ldisc.write_wakeup(hp->tty); + wake_up_interruptible(&hp->tty->write_wait); + } + + spin_unlock_irqrestore(&hp->lock, flags); +} + +static int hvsi_write_room(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + return N_OUTBUF - hp->n_outbuf; +} + +static int hvsi_chars_in_buffer(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + return hp->n_outbuf; +} + +static int hvsi_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + struct hvsi_struct *hp = tty->driver_data; + const char *source = buf; + char *kbuf = NULL; + unsigned long flags; + int total = 0; + int origcount = count; + + if (from_user) { + kbuf = kmalloc(count, GFP_KERNEL); + if (kbuf == NULL) + return -ENOMEM; + if (copy_from_user(kbuf, buf, count)) { + kfree(kbuf); + return -EFAULT; + } + source = kbuf; + } + + spin_lock_irqsave(&hp->lock, flags); + + if (!is_open(hp)) { + /* we're either closing or not yet open; don't accept data */ + pr_debug("%s: not open\n", __FUNCTION__); + goto out; + } + + /* + * when the hypervisor buffer (16K) fills, data will stay in hp->outbuf + * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls + * will see there is no room in outbuf and return. + */ + while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { + int chunksize = min(count, hvsi_write_room(hp->tty)); + + BUG_ON(hp->n_outbuf < 0); + memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); + hp->n_outbuf += chunksize; + + total += chunksize; + source += chunksize; + count -= chunksize; + hvsi_push(hp); + } + + if (hp->n_outbuf > 0) { + /* + * we weren't able to write it all to the hypervisor. + * schedule another push attempt. + */ + schedule_delayed_work(&hp->writer, 10); + } + +out: + spin_unlock_irqrestore(&hp->lock, flags); + + if (from_user) + kfree(kbuf); + + if (total != origcount) + pr_debug("%s: wanted %i, only wrote %i\n", __FUNCTION__, origcount, + total); + + return total; +} + +/* + * I have never seen throttle or unthrottle called, so this little throttle + * buffering scheme may or may not work. + */ +static void hvsi_throttle(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + pr_debug("%s\n", __FUNCTION__); + + h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); +} + +static void hvsi_unthrottle(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + unsigned long flags; + int shouldflip = 0; + + pr_debug("%s\n", __FUNCTION__); + + spin_lock_irqsave(&hp->lock, flags); + if (hp->n_throttle) { + hvsi_send_overflow(hp); + shouldflip = 1; + } + spin_unlock_irqrestore(&hp->lock, flags); + + if (shouldflip) + tty_flip_buffer_push(hp->tty); + + h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); +} + +static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + hvsi_get_mctrl(hp); + return hp->mctrl; +} + +static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + unsigned long flags; + uint16_t new_mctrl; + + /* we can only alter DTR */ + clear &= TIOCM_DTR; + set &= TIOCM_DTR; + + spin_lock_irqsave(&hp->lock, flags); + + new_mctrl = (hp->mctrl & ~clear) | set; + + if (hp->mctrl != new_mctrl) { + hvsi_set_mctrl(hp, new_mctrl); + hp->mctrl = new_mctrl; + } + spin_unlock_irqrestore(&hp->lock, flags); + + return 0; +} + + +static struct tty_operations hvsi_ops = { + .open = hvsi_open, + .close = hvsi_close, + .write = hvsi_write, + .hangup = hvsi_hangup, + .write_room = hvsi_write_room, + .chars_in_buffer = hvsi_chars_in_buffer, + .throttle = hvsi_throttle, + .unthrottle = hvsi_unthrottle, + .tiocmget = hvsi_tiocmget, + .tiocmset = hvsi_tiocmset, +}; + +static int __init hvsi_init(void) +{ + int i; + + hvsi_driver = alloc_tty_driver(hvsi_count); + if (!hvsi_driver) + return -ENOMEM; + + hvsi_driver->owner = THIS_MODULE; + hvsi_driver->devfs_name = "hvsi/"; + hvsi_driver->driver_name = "hvsi"; + hvsi_driver->name = "hvsi"; + hvsi_driver->major = HVSI_MAJOR; + hvsi_driver->minor_start = HVSI_MINOR; + hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM; + hvsi_driver->init_termios = tty_std_termios; + hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; + hvsi_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(hvsi_driver, &hvsi_ops); + + for (i=0; i < hvsi_count; i++) { + struct hvsi_struct *hp = &hvsi_ports[i]; + int ret = 1; + + ret = request_irq(hp->virq, hvsi_interrupt, SA_INTERRUPT, "hvsi", hp); + if (ret) + printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", + hp->virq, ret); + } + hvsi_wait = wait_for_state; /* irqs active now */ + + if (tty_register_driver(hvsi_driver)) + panic("Couldn't register hvsi console driver\n"); + + printk(KERN_INFO "HVSI: registered %i devices\n", hvsi_count); + + return 0; +} +device_initcall(hvsi_init); + +/***** console (not tty) code: *****/ + +static void hvsi_console_print(struct console *console, const char *buf, + unsigned int count) +{ + struct hvsi_struct *hp = &hvsi_ports[console->index]; + char c[HVSI_MAX_OUTGOING_DATA] __ALIGNED__; + unsigned int i = 0, n = 0; + int ret, donecr = 0; + + mb(); + if (!is_open(hp)) + return; + + /* + * ugh, we have to translate LF -> CRLF ourselves, in place. + * copied from hvc_console.c: + */ + while (count > 0 || i > 0) { + if (count > 0 && i < sizeof(c)) { + if (buf[n] == '\n' && !donecr) { + c[i++] = '\r'; + donecr = 1; + } else { + c[i++] = buf[n++]; + donecr = 0; + --count; + } + } else { + ret = hvsi_put_chars(hp, c, i); + if (ret < 0) + i = 0; + i -= ret; + } + } +} + +static struct tty_driver *hvsi_console_device(struct console *console, + int *index) +{ + *index = console->index; + return hvsi_driver; +} + +static int __init hvsi_console_setup(struct console *console, char *options) +{ + struct hvsi_struct *hp = &hvsi_ports[console->index]; + int ret; + + if (console->index < 0 || console->index >= hvsi_count) + return -1; + + /* give the FSP a chance to change the baud rate when we re-open */ + hvsi_close_protocol(hp); + + ret = hvsi_handshake(hp); + if (ret < 0) + return ret; + + ret = hvsi_get_mctrl(hp); + if (ret < 0) + return ret; + + ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); + if (ret < 0) + return ret; + + hp->flags |= HVSI_CONSOLE; + + return 0; +} + +static struct console hvsi_con_driver = { + .name = "hvsi", + .write = hvsi_console_print, + .device = hvsi_console_device, + .setup = hvsi_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static int __init hvsi_console_init(void) +{ + struct device_node *vty; + + hvsi_wait = poll_for_state; /* no irqs yet; must poll */ + + /* search device tree for vty nodes */ + for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol"); + vty != NULL; + vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) { + struct hvsi_struct *hp; + uint32_t *vtermno; + uint32_t *irq; + + vtermno = (uint32_t *)get_property(vty, "reg", NULL); + irq = (uint32_t *)get_property(vty, "interrupts", NULL); + if (!vtermno || !irq) + continue; + + if (hvsi_count >= MAX_NR_HVSI_CONSOLES) { + of_node_put(vty); + break; + } + + hp = &hvsi_ports[hvsi_count]; + INIT_WORK(&hp->writer, hvsi_write_worker, hp); + init_waitqueue_head(&hp->emptyq); + init_waitqueue_head(&hp->stateq); + hp->lock = SPIN_LOCK_UNLOCKED; + hp->index = hvsi_count; + hp->inbuf_end = hp->inbuf; + hp->state = HVSI_CLOSED; + hp->vtermno = *vtermno; + hp->virq = virt_irq_create_mapping(irq[0]); + if (hp->virq == NO_IRQ) { + printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", + __FUNCTION__, hp->virq); + continue; + } else + hp->virq = irq_offset_up(hp->virq); + + hvsi_count++; + } + + if (hvsi_count) + register_console(&hvsi_con_driver); + return 0; +} +console_initcall(hvsi_console_init); diff -Nru a/drivers/char/ip2/ip2types.h b/drivers/char/ip2/ip2types.h --- a/drivers/char/ip2/ip2types.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/char/ip2/ip2types.h 2004-10-18 14:56:49 -07:00 @@ -49,6 +49,9 @@ short irq[IP2_MAX_BOARDS]; unsigned short addr[IP2_MAX_BOARDS]; int type[IP2_MAX_BOARDS]; +#ifdef CONFIG_PCI + struct pci_dev *pci_dev[IP2_MAX_BOARDS]; +#endif } ip2config_t; #endif diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c --- a/drivers/char/ip2main.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/ip2main.c 2004-10-18 14:57:05 -07:00 @@ -440,6 +440,12 @@ // free memory for (i = 0; i < IP2_MAX_BOARDS; i++) { void *pB; +#ifdef CONFIG_PCI + if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) { + pci_disable_device(ip2config.pci_dev[i]); + ip2config.pci_dev[i] = NULL; + } +#endif if ((pB = i2BoardPtrTable[i]) != 0 ) { kfree ( pB ); i2BoardPtrTable[i] = NULL; @@ -594,9 +600,14 @@ PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); if (pci_dev_i != NULL) { unsigned int addr; - unsigned char pci_irq; + if (pci_enable_device(pci_dev_i)) { + printk( KERN_ERR "IP2: can't enable PCI device at %s\n", + pci_name(pci_dev_i)); + break; + } ip2config.type[i] = PCI; + ip2config.pci_dev[i] = pci_dev_i; status = pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); if ( addr & 1 ) { @@ -604,8 +615,6 @@ } else { printk( KERN_ERR "IP2: PCI I/O address error\n"); } - status = - pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq); // If the PCI BIOS assigned it, lets try and use it. If we // can't acquire it or it screws up, deal with it then. @@ -614,7 +623,7 @@ // printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq); // pci_irq = 0; // } - ip2config.irq[i] = pci_irq; + ip2config.irq[i] = pci_dev_i->irq; } else { // ann error ip2config.addr[i] = 0; if (status == PCIBIOS_DEVICE_NOT_FOUND) { diff -Nru a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig --- a/drivers/char/ipmi/Kconfig 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/ipmi/Kconfig 2004-10-18 14:56:48 -07:00 @@ -57,4 +57,11 @@ help This enables the IPMI watchdog timer. +config IPMI_POWEROFF + tristate 'IPMI Poweroff' + depends on IPMI_HANDLER + help + This enables a function to power off the system with IPMI if + the IPMI management controller is capable of this. + endmenu diff -Nru a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile --- a/drivers/char/ipmi/Makefile 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/ipmi/Makefile 2004-10-18 14:57:03 -07:00 @@ -8,6 +8,7 @@ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_SI) += ipmi_si.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o +obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o ipmi_si.o: $(ipmi_si-objs) $(LD) -r -o $@ $(ipmi_si-objs) diff -Nru a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c --- a/drivers/char/ipmi/ipmi_bt_sm.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/ipmi/ipmi_bt_sm.c 2004-10-18 14:56:50 -07:00 @@ -31,7 +31,7 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_BT_VERSION "v32" +#define IPMI_BT_VERSION "v33" static int bt_debug = 0x00; /* Production value 0, see following flags */ diff -Nru a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c --- a/drivers/char/ipmi/ipmi_devintf.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/ipmi/ipmi_devintf.c 2004-10-18 14:56:50 -07:00 @@ -45,7 +45,7 @@ #include #include -#define IPMI_DEVINTF_VERSION "v32" +#define IPMI_DEVINTF_VERSION "v33" struct ipmi_file_private { diff -Nru a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c --- a/drivers/char/ipmi/ipmi_kcs_sm.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/char/ipmi/ipmi_kcs_sm.c 2004-10-18 14:55:55 -07:00 @@ -42,7 +42,7 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_KCS_VERSION "v32" +#define IPMI_KCS_VERSION "v33" /* Set this if you want a printout of why the state machine was hosed when it gets hosed. */ diff -Nru a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c --- a/drivers/char/ipmi/ipmi_msghandler.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/ipmi/ipmi_msghandler.c 2004-10-18 14:56:32 -07:00 @@ -46,7 +46,8 @@ #include #include -#define IPMI_MSGHANDLER_VERSION "v32" +#define PFX "IPMI message handler: " +#define IPMI_MSGHANDLER_VERSION "v33" struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -895,6 +896,12 @@ return rv; } +void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) +{ + user->intf->handlers->set_run_to_completion(user->intf->send_info, + val); +} + static unsigned char ipmb_checksum(unsigned char *data, int size) { @@ -1686,8 +1693,8 @@ intf->curr_channel = IPMI_MAX_CHANNELS; wake_up(&intf->waitq); - printk(KERN_WARNING "ipmi_msghandler: Error sending" - "channel information: %d\n", + printk(KERN_WARNING PFX + "Error sending channel information: %d\n", rv); } } @@ -2351,7 +2358,7 @@ } else { /* There's too many things in the queue, discard this message. */ - printk(KERN_WARNING "ipmi: Event queue full, discarding an" + printk(KERN_WARNING PFX "Event queue full, discarding an" " incoming event\n"); } @@ -2433,10 +2440,34 @@ #endif if (msg->rsp_size < 2) { /* Message is too small to be correct. */ - requeue = 0; - } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data != NULL)) + printk(KERN_WARNING PFX "BMC returned to small a message" + " for netfn %x cmd %x, got %d bytes\n", + (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); + + /* Generate an error response for the message. */ + msg->rsp[0] = msg->data[0] | (1 << 2); + msg->rsp[1] = msg->data[1]; + msg->rsp[2] = IPMI_ERR_UNSPECIFIED; + msg->rsp_size = 3; + } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */ + || (msg->rsp[1] != msg->data[1])) /* Command */ + { + /* The response is not even marginally correct. */ + printk(KERN_WARNING PFX "BMC returned incorrect response," + " expected netfn %x cmd %x, got netfn %x cmd %x\n", + (msg->data[0] >> 2) | 1, msg->data[1], + msg->rsp[0] >> 2, msg->rsp[1]); + + /* Generate an error response for the message. */ + msg->rsp[0] = msg->data[0] | (1 << 2); + msg->rsp[1] = msg->data[1]; + msg->rsp[2] = IPMI_ERR_UNSPECIFIED; + msg->rsp_size = 3; + } + + if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) + && (msg->rsp[1] == IPMI_SEND_MSG_CMD) + && (msg->user_data != NULL)) { /* It's a response to a response we sent. For this we deliver a send message response to the user. */ @@ -2502,7 +2533,9 @@ requeue = 0; } - } else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) { + } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) + && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) + { /* It's an asyncronous event. */ requeue = handle_read_event_rsp(intf, msg); } else { @@ -3114,7 +3147,7 @@ proc_ipmi_root = proc_mkdir("ipmi", NULL); if (!proc_ipmi_root) { - printk("Unable to create IPMI proc dir"); + printk(KERN_ERR PFX "Unable to create IPMI proc dir"); return -ENOMEM; } @@ -3166,11 +3199,11 @@ /* Check for buffer leaks. */ count = atomic_read(&smi_msg_inuse_count); if (count != 0) - printk("ipmi_msghandler: SMI message count %d at exit\n", + printk(KERN_WARNING PFX "SMI message count %d at exit\n", count); count = atomic_read(&recv_msg_inuse_count); if (count != 0) - printk("ipmi_msghandler: recv message count %d at exit\n", + printk(KERN_WARNING PFX "recv message count %d at exit\n", count); } module_exit(cleanup_ipmi); @@ -3207,3 +3240,4 @@ EXPORT_SYMBOL(ipmi_set_my_LUN); EXPORT_SYMBOL(ipmi_get_my_LUN); EXPORT_SYMBOL(ipmi_smi_add_proc_entry); +EXPORT_SYMBOL(ipmi_user_set_run_to_completion); diff -Nru a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/ipmi/ipmi_poweroff.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,543 @@ +/* + * ipmi_poweroff.c + * + * MontaVista IPMI Poweroff extension to sys_reboot + * + * Author: MontaVista Software, Inc. + * Steven Dake + * Corey Minyard + * source@mvista.com + * + * Copyright 2002,2004 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include + +#define PFX "IPMI poweroff: " +#define IPMI_POWEROFF_VERSION "v33" + +/* Where to we insert our poweroff function? */ +extern void (*pm_power_off)(void); + +/* Stuff from the get device id command. */ +unsigned int mfg_id; +unsigned int prod_id; +unsigned char capabilities; + +/* We use our own messages for this operation, we don't let the system + allocate them, since we may be in a panic situation. The whole + thing is single-threaded, anyway, so multiple messages are not + required. */ +static void dummy_smi_free(struct ipmi_smi_msg *msg) +{ +} +static void dummy_recv_free(struct ipmi_recv_msg *msg) +{ +} +static struct ipmi_smi_msg halt_smi_msg = +{ + .done = dummy_smi_free +}; +static struct ipmi_recv_msg halt_recv_msg = +{ + .done = dummy_recv_free +}; + + +/* + * Code to send a message and wait for the reponse. + */ + +static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) +{ + struct semaphore *sem = recv_msg->user_msg_data; + + if (sem) + up(sem); +} + +static struct ipmi_user_hndl ipmi_poweroff_handler = +{ + .ipmi_recv_hndl = receive_handler +}; + + +static int ipmi_request_wait_for_response(ipmi_user_t user, + struct ipmi_addr *addr, + struct kernel_ipmi_msg *send_msg) +{ + int rv; + struct semaphore sem; + + sema_init (&sem, 0); + + rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem, + &halt_smi_msg, &halt_recv_msg, 0); + if (rv) + return rv; + + down (&sem); + + return halt_recv_msg.msg.data[0]; +} + +/* We are in run-to-completion mode, no semaphore is desired. */ +static int ipmi_request_in_rc_mode(ipmi_user_t user, + struct ipmi_addr *addr, + struct kernel_ipmi_msg *send_msg) +{ + int rv; + + rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, + &halt_smi_msg, &halt_recv_msg, 0); + if (rv) + return rv; + + return halt_recv_msg.msg.data[0]; +} + +/* + * ATCA Support + */ + +#define IPMI_NETFN_ATCA 0x2c +#define IPMI_ATCA_SET_POWER_CMD 0x11 +#define IPMI_ATCA_GET_ADDR_INFO_CMD 0x01 +#define IPMI_PICMG_ID 0 + +static int ipmi_atca_detect (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[1]; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + /* + * Use get address info to check and see if we are ATCA + */ + send_msg.netfn = IPMI_NETFN_ATCA; + send_msg.cmd = IPMI_ATCA_GET_ADDR_INFO_CMD; + data[0] = IPMI_PICMG_ID; + send_msg.data = data; + send_msg.data_len = sizeof(data); + rv = ipmi_request_wait_for_response(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + return !rv; +} + +static void ipmi_poweroff_atca (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[4]; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "Powering down via ATCA power command\n"); + + /* + * Power down + */ + send_msg.netfn = IPMI_NETFN_ATCA; + send_msg.cmd = IPMI_ATCA_SET_POWER_CMD; + data[0] = IPMI_PICMG_ID; + data[1] = 0; /* FRU id */ + data[2] = 0; /* Power Level */ + data[3] = 0; /* Don't change saved presets */ + send_msg.data = data; + send_msg.data_len = sizeof (data); + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) { + printk(KERN_ERR PFX "Unable to send ATCA powerdown message," + " IPMI error 0x%x\n", rv); + goto out; + } + + out: + return; +} + +/* + * CPI1 Support + */ + +#define IPMI_NETFN_OEM_1 0xf8 +#define OEM_GRP_CMD_SET_RESET_STATE 0x84 +#define OEM_GRP_CMD_SET_POWER_STATE 0x82 +#define IPMI_NETFN_OEM_8 0xf8 +#define OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL 0x80 +#define OEM_GRP_CMD_GET_SLOT_GA 0xa3 +#define IPMI_NETFN_SENSOR_EVT 0x10 +#define IPMI_CMD_GET_EVENT_RECEIVER 0x01 + +#define IPMI_CPI1_PRODUCT_ID 0x000157 +#define IPMI_CPI1_MANUFACTURER_ID 0x0108 + +static int ipmi_cpi1_detect (ipmi_user_t user) +{ + return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID) + && (prod_id == IPMI_CPI1_PRODUCT_ID)); +} + +static void ipmi_poweroff_cpi1 (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct ipmi_ipmb_addr ipmb_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[1]; + int slot; + unsigned char hotswap_ipmb; + unsigned char aer_addr; + unsigned char aer_lun; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "Powering down via CPI1 power command\n"); + + /* + * Get IPMI ipmb address + */ + send_msg.netfn = IPMI_NETFN_OEM_8 >> 2; + send_msg.cmd = OEM_GRP_CMD_GET_SLOT_GA; + send_msg.data = NULL; + send_msg.data_len = 0; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + slot = halt_recv_msg.msg.data[1]; + hotswap_ipmb = (slot > 9) ? (0xb0 + 2 * slot) : (0xae + 2 * slot); + + /* + * Get active event receiver + */ + send_msg.netfn = IPMI_NETFN_SENSOR_EVT >> 2; + send_msg.cmd = IPMI_CMD_GET_EVENT_RECEIVER; + send_msg.data = NULL; + send_msg.data_len = 0; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + aer_addr = halt_recv_msg.msg.data[1]; + aer_lun = halt_recv_msg.msg.data[2]; + + /* + * Setup IPMB address target instead of local target + */ + ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE; + ipmb_addr.channel = 0; + ipmb_addr.slave_addr = aer_addr; + ipmb_addr.lun = aer_lun; + + /* + * Send request hotswap control to remove blade from dpv + */ + send_msg.netfn = IPMI_NETFN_OEM_8 >> 2; + send_msg.cmd = OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL; + send_msg.data = &hotswap_ipmb; + send_msg.data_len = 1; + ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &ipmb_addr, + &send_msg); + + /* + * Set reset asserted + */ + send_msg.netfn = IPMI_NETFN_OEM_1 >> 2; + send_msg.cmd = OEM_GRP_CMD_SET_RESET_STATE; + send_msg.data = data; + data[0] = 1; /* Reset asserted state */ + send_msg.data_len = 1; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + + /* + * Power down + */ + send_msg.netfn = IPMI_NETFN_OEM_1 >> 2; + send_msg.cmd = OEM_GRP_CMD_SET_POWER_STATE; + send_msg.data = data; + data[0] = 1; /* Power down state */ + send_msg.data_len = 1; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + + out: + return; +} + +/* + * Standard chassis support + */ + +#define IPMI_NETFN_CHASSIS_REQUEST 0 +#define IPMI_CHASSIS_CONTROL_CMD 0x02 + +static int ipmi_chassis_detect (ipmi_user_t user) +{ + /* Chassis support, use it. */ + return (capabilities & 0x80); +} + +static void ipmi_poweroff_chassis (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[1]; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n"); + + /* + * Power down + */ + send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; + send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; + data[0] = 0; /* Power down */ + send_msg.data = data; + send_msg.data_len = sizeof(data); + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) { + printk(KERN_ERR PFX "Unable to send chassis powerdown message," + " IPMI error 0x%x\n", rv); + goto out; + } + + out: + return; +} + + +/* Table of possible power off functions. */ +struct poweroff_function { + char *platform_type; + int (*detect)(ipmi_user_t user); + void (*poweroff_func)(ipmi_user_t user); +}; + +static struct poweroff_function poweroff_functions[] = { + { "ATCA", ipmi_atca_detect, ipmi_poweroff_atca }, + { "CPI1", ipmi_cpi1_detect, ipmi_poweroff_cpi1 }, + /* Chassis should generally be last, other things should override + it. */ + { "chassis", ipmi_chassis_detect, ipmi_poweroff_chassis }, +}; +#define NUM_PO_FUNCS (sizeof(poweroff_functions) \ + / sizeof(struct poweroff_function)) + + +/* Our local state. */ +static int ready = 0; +static ipmi_user_t ipmi_user; +static void (*specific_poweroff_func)(ipmi_user_t user) = NULL; + +/* Holds the old poweroff function so we can restore it on removal. */ +static void (*old_poweroff_func)(void); + + +/* Called on a powerdown request. */ +static void ipmi_poweroff_function (void) +{ + if (!ready) + return; + + /* Use run-to-completion mode, since interrupts may be off. */ + ipmi_user_set_run_to_completion(ipmi_user, 1); + specific_poweroff_func(ipmi_user); + ipmi_user_set_run_to_completion(ipmi_user, 0); +} + +/* Wait for an IPMI interface to be installed, the first one installed + will be grabbed by this code and used to perform the powerdown. */ +static void ipmi_po_new_smi(int if_num) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + int i; + + if (ready) + return; + + rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); + if (rv) { + printk(KERN_ERR PFX "could not create IPMI user, error %d\n", + rv); + return; + } + + /* + * Do a get device ide and store some results, since this is + * used by several functions. + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + send_msg.netfn = IPMI_NETFN_APP_REQUEST; + send_msg.cmd = IPMI_GET_DEVICE_ID_CMD; + send_msg.data = NULL; + send_msg.data_len = 0; + rv = ipmi_request_wait_for_response(ipmi_user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) { + printk(KERN_ERR PFX "Unable to send IPMI get device id info," + " IPMI error 0x%x\n", rv); + goto out_err; + } + + if (halt_recv_msg.msg.data_len < 12) { + printk(KERN_ERR PFX "(chassis) IPMI get device id info too," + " short, was %d bytes, needed %d bytes\n", + halt_recv_msg.msg.data_len, 12); + goto out_err; + } + + mfg_id = (halt_recv_msg.msg.data[7] + | (halt_recv_msg.msg.data[8] << 8) + | (halt_recv_msg.msg.data[9] << 16)); + prod_id = (halt_recv_msg.msg.data[10] + | (halt_recv_msg.msg.data[11] << 8)); + capabilities = halt_recv_msg.msg.data[6]; + + + /* Scan for a poweroff method */ + for (i=0; i -#define IPMI_SI_VERSION "v32" +#define IPMI_SI_VERSION "v33" /* Measure times between events in the driver. */ #undef DEBUG_TIMING @@ -146,6 +146,11 @@ /* The I/O port of an SI interface. */ int port; + /* The space between start addresses of the two ports. For + instance, if the first port is 0xca2 and the spacing is 4, then + the second port is 0xca6. */ + unsigned int spacing; + /* zero if no irq; */ int irq; @@ -452,14 +457,20 @@ /* Take off the event flag. */ smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; + handle_flags(smi_info); } else { spin_lock(&smi_info->count_lock); smi_info->events++; spin_unlock(&smi_info->count_lock); + /* Do this before we deliver the message + because delivering the message releases the + lock and something else can mess with the + state. */ + handle_flags(smi_info); + deliver_recv_msg(smi_info, msg); } - handle_flags(smi_info); break; } @@ -482,14 +493,20 @@ /* Take off the msg flag. */ smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL; + handle_flags(smi_info); } else { spin_lock(&smi_info->count_lock); smi_info->incoming_messages++; spin_unlock(&smi_info->count_lock); + /* Do this before we deliver the message + because delivering the message releases the + lock and something else can mess with the + state. */ + handle_flags(smi_info); + deliver_recv_msg(smi_info, msg); } - handle_flags(smi_info); break; } @@ -568,6 +585,9 @@ smi_info->hosed_count++; spin_unlock(&smi_info->count_lock); + /* Do the before return_hosed_msg, because that + releases the lock. */ + smi_info->si_state = SI_NORMAL; if (smi_info->curr_msg != NULL) { /* If we were handling a user message, format a response to send to the upper layer to @@ -575,7 +595,6 @@ return_hosed_msg(smi_info); } si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - smi_info->si_state = SI_NORMAL; } /* We prefer handling attn over new messages. */ @@ -872,9 +891,10 @@ #define DEVICE_NAME "ipmi_si" -#define DEFAULT_KCS_IO_PORT 0xca2 -#define DEFAULT_SMIC_IO_PORT 0xca9 -#define DEFAULT_BT_IO_PORT 0xe4 +#define DEFAULT_KCS_IO_PORT 0xca2 +#define DEFAULT_SMIC_IO_PORT 0xca9 +#define DEFAULT_BT_IO_PORT 0xe4 +#define DEFAULT_REGSPACING 1 static int si_trydefaults = 1; static char *si_type[SI_MAX_PARMS] = { NULL, NULL, NULL, NULL }; @@ -886,6 +906,12 @@ static int num_ports = 0; static int irqs[SI_MAX_PARMS] = { 0, 0, 0, 0 }; static int num_irqs = 0; +static int regspacings[SI_MAX_PARMS] = { 0, 0, 0, 0 }; +static int num_regspacings = 0; +static int regsizes[SI_MAX_PARMS] = { 0, 0, 0, 0 }; +static int num_regsizes = 0; +static int regshifts[SI_MAX_PARMS] = { 0, 0, 0, 0 }; +static int num_regshifts = 0; module_param_named(trydefaults, si_trydefaults, bool, 0); @@ -912,6 +938,23 @@ " addresses separated by commas. Only use if an interface" " has an interrupt. Otherwise, set it to zero or leave" " it blank."); +module_param_array(regspacings, int, num_regspacings, 0); +MODULE_PARM_DESC(regspacings, "The number of bytes between the start address" + " and each successive register used by the interface. For" + " instance, if the start address is 0xca2 and the spacing" + " is 2, then the second address is at 0xca4. Defaults" + " to 1."); +module_param_array(regsizes, int, num_regsizes, 0); +MODULE_PARM_DESC(regsizes, "The size of the specific IPMI register in bytes." + " This should generally be 1, 2, 4, or 8 for an 8-bit," + " 16-bit, 32-bit, or 64-bit register. Use this if you" + " the 8-bit IPMI register has to be read from a larger" + " register."); +module_param_array(regshifts, int, num_regshifts, 0); +MODULE_PARM_DESC(regshifts, "The amount to shift the data read from the." + " IPMI register, in bits. For instance, if the data" + " is read from a 32-bit word and the IPMI data is in" + " bit 8-15, then the shift would be 8"); #define IPMI_MEM_ADDR_SPACE 1 #define IPMI_IO_ADDR_SPACE 2 @@ -977,7 +1020,7 @@ { unsigned int *addr = io->info; - return inb((*addr)+offset); + return inb((*addr)+(offset*io->regspacing)); } static void port_outb(struct si_sm_io *io, unsigned int offset, @@ -985,30 +1028,97 @@ { unsigned int *addr = io->info; - outb(b, (*addr)+offset); + outb(b, (*addr)+(offset * io->regspacing)); } -static int port_setup(struct smi_info *info) +static unsigned char port_inw(struct si_sm_io *io, unsigned int offset) { - unsigned int *addr = info->io.info; + unsigned int *addr = io->info; - if (!addr || (!*addr)) - return -ENODEV; + return (inw((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; +} - if (request_region(*addr, info->io_size, DEVICE_NAME) == NULL) - return -EIO; - return 0; +static void port_outw(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + unsigned int *addr = io->info; + + outw(b << io->regshift, (*addr)+(offset * io->regspacing)); +} + +static unsigned char port_inl(struct si_sm_io *io, unsigned int offset) +{ + unsigned int *addr = io->info; + + return (inl((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; +} + +static void port_outl(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + unsigned int *addr = io->info; + + outl(b << io->regshift, (*addr)+(offset * io->regspacing)); } static void port_cleanup(struct smi_info *info) { unsigned int *addr = info->io.info; + int mapsize; - if (addr && (*addr)) - release_region (*addr, info->io_size); + if (addr && (*addr)) { + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + release_region (*addr, mapsize); + } kfree(info); } +static int port_setup(struct smi_info *info) +{ + unsigned int *addr = info->io.info; + int mapsize; + + if (!addr || (!*addr)) + return -ENODEV; + + info->io_cleanup = port_cleanup; + + /* Figure out the actual inb/inw/inl/etc routine to use based + upon the register size. */ + switch (info->io.regsize) { + case 1: + info->io.inputb = port_inb; + info->io.outputb = port_outb; + break; + case 2: + info->io.inputb = port_inw; + info->io.outputb = port_outw; + break; + case 4: + info->io.inputb = port_inl; + info->io.outputb = port_outl; + break; + default: + printk("ipmi_si: Invalid register size: %d\n", + info->io.regsize); + return -EINVAL; + } + + /* Calculate the total amount of memory to claim. This is an + * unusual looking calculation, but it avoids claiming any + * more memory than it has to. It will claim everything + * between the first address to the end of the last full + * register. */ + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + if (request_region(*addr, mapsize, DEVICE_NAME) == NULL) + return -EIO; + return 0; +} + static int try_init_port(int intf_num, struct smi_info **new_info) { struct smi_info *info; @@ -1028,11 +1138,15 @@ memset(info, 0, sizeof(*info)); info->io_setup = port_setup; - info->io_cleanup = port_cleanup; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); info->io.addr = NULL; + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = regsizes[intf_num]; + if (!info->io.regsize) + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; info->irq = 0; info->irq_setup = NULL; *new_info = info; @@ -1047,44 +1161,125 @@ static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset) { - return readb((io->addr)+offset); + return readb((io->addr)+(offset * io->regspacing)); } static void mem_outb(struct si_sm_io *io, unsigned int offset, unsigned char b) { - writeb(b, (io->addr)+offset); + writeb(b, (io->addr)+(offset * io->regspacing)); } -static int mem_setup(struct smi_info *info) +static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset) { - unsigned long *addr = info->io.info; + return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) + && 0xff; +} - if (!addr || (!*addr)) - return -ENODEV; +static void mem_outw(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); +} - if (request_mem_region(*addr, info->io_size, DEVICE_NAME) == NULL) - return -EIO; +static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset) +{ + return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) + && 0xff; +} - info->io.addr = ioremap(*addr, info->io_size); - if (info->io.addr == NULL) { - release_mem_region(*addr, info->io_size); - return -EIO; - } - return 0; +static void mem_outl(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); } +#ifdef readq +static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) +{ + return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) + && 0xff; +} + +static void mem_outq(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); +} +#endif + static void mem_cleanup(struct smi_info *info) { unsigned long *addr = info->io.info; + int mapsize; if (info->io.addr) { iounmap(info->io.addr); - release_mem_region(*addr, info->io_size); + + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + release_mem_region(*addr, mapsize); } kfree(info); } +static int mem_setup(struct smi_info *info) +{ + unsigned long *addr = info->io.info; + int mapsize; + + if (!addr || (!*addr)) + return -ENODEV; + + info->io_cleanup = mem_cleanup; + + /* Figure out the actual readb/readw/readl/etc routine to use based + upon the register size. */ + switch (info->io.regsize) { + case 1: + info->io.inputb = mem_inb; + info->io.outputb = mem_outb; + break; + case 2: + info->io.inputb = mem_inw; + info->io.outputb = mem_outw; + break; + case 4: + info->io.inputb = mem_inl; + info->io.outputb = mem_outl; + break; +#ifdef readq + case 8: + info->io.inputb = mem_inq; + info->io.outputb = mem_outq; + break; +#endif + default: + printk("ipmi_si: Invalid register size: %d\n", + info->io.regsize); + return -EINVAL; + } + + /* Calculate the total amount of memory to claim. This is an + * unusual looking calculation, but it avoids claiming any + * more memory than it has to. It will claim everything + * between the first address to the end of the last full + * register. */ + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + if (request_mem_region(*addr, mapsize, DEVICE_NAME) == NULL) + return -EIO; + + info->io.addr = ioremap(*addr, mapsize); + if (info->io.addr == NULL) { + release_mem_region(*addr, mapsize); + return -EIO; + } + return 0; +} + static int try_init_mem(int intf_num, struct smi_info **new_info) { struct smi_info *info; @@ -1104,11 +1299,15 @@ memset(info, 0, sizeof(*info)); info->io_setup = mem_setup; - info->io_cleanup = mem_cleanup; - info->io.inputb = mem_inb; - info->io.outputb = mem_outb; info->io.info = (void *) addrs[intf_num]; info->io.addr = NULL; + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = regsizes[intf_num]; + if (!info->io.regsize) + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; info->irq = 0; info->irq_setup = NULL; *new_info = info; @@ -1132,7 +1331,7 @@ static int acpi_failure = 0; /* For GPE-type interrupts. */ -void ipmi_acpi_gpe(void *context) +u32 ipmi_acpi_gpe(void *context) { struct smi_info *smi_info = context; unsigned long flags; @@ -1156,6 +1355,8 @@ smi_event_handler(smi_info, 0); out: spin_unlock_irqrestore(&(smi_info->si_lock), flags); + + return ACPI_INTERRUPT_HANDLED; } static int acpi_gpe_irq_setup(struct smi_info *info) @@ -1182,7 +1383,6 @@ printk(" Using ACPI GPE %d\n", info->irq); return 0; } - } static void acpi_gpe_irq_cleanup(struct smi_info *info) @@ -1310,21 +1510,22 @@ info->irq_setup = NULL; } + regspacings[intf_num] = spmi->addr.register_bit_width / 8; + info->io.regspacing = spmi->addr.register_bit_width / 8; + regsizes[intf_num] = regspacings[intf_num]; + info->io.regsize = regsizes[intf_num]; + regshifts[intf_num] = spmi->addr.register_bit_offset; + info->io.regshift = regshifts[intf_num]; + if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { io_type = "memory"; info->io_setup = mem_setup; - info->io_cleanup = mem_cleanup; addrs[intf_num] = spmi->addr.address; - info->io.inputb = mem_inb; - info->io.outputb = mem_outb; info->io.info = &(addrs[intf_num]); } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) { io_type = "I/O"; info->io_setup = port_setup; - info->io_cleanup = port_cleanup; ports[intf_num] = spmi->addr.address; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); } else { kfree(info); @@ -1348,6 +1549,7 @@ u8 addr_space; unsigned long base_addr; u8 irq; + u8 offset; }dmi_ipmi_data_t; typedef struct dmi_header @@ -1361,6 +1563,7 @@ { u8 *data = (u8 *)dm; unsigned long base_addr; + u8 reg_spacing; ipmi_data->type = data[0x04]; @@ -1375,7 +1578,27 @@ ipmi_data->addr_space = IPMI_MEM_ADDR_SPACE; } - ipmi_data->base_addr = base_addr; + /* The top two bits of byte 0x10 hold the register spacing. */ + reg_spacing = (data[0x10] & 0xC0) >> 6; + switch(reg_spacing){ + case 0x00: /* Byte boundaries */ + ipmi_data->offset = 1; + break; + case 0x01: /* 32-bit boundaries */ + ipmi_data->offset = 4; + break; + case 0x02: /* 16-bit boundaries */ + ipmi_data->offset = 2; + default: + printk("ipmi_si: Unknown SMBIOS IPMI Base Addr" + " Modifier: 0x%x\n", reg_spacing); + return -EIO; + } + + /* If bit 4 of byte 0x10 is set, then the lsb for the address + is odd. */ + ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); + ipmi_data->irq = data[0x11]; if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) @@ -1500,18 +1723,12 @@ if (ipmi_data.addr_space == 1) { io_type = "memory"; info->io_setup = mem_setup; - info->io_cleanup = mem_cleanup; addrs[intf_num] = ipmi_data.base_addr; - info->io.inputb = mem_inb; - info->io.outputb = mem_outb; info->io.info = &(addrs[intf_num]); } else if (ipmi_data.addr_space == 2) { io_type = "I/O"; info->io_setup = port_setup; - info->io_cleanup = port_cleanup; ports[intf_num] = ipmi_data.base_addr; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); } else { kfree(info); @@ -1519,6 +1736,13 @@ return -EIO; } + regspacings[intf_num] = ipmi_data.offset; + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; + irqs[intf_num] = ipmi_data.irq; *new_info = info; @@ -1596,11 +1820,13 @@ memset(info, 0, sizeof(*info)); info->io_setup = port_setup; - info->io_cleanup = port_cleanup; ports[intf_num] = base_addr; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; *new_info = info; @@ -1860,6 +2086,13 @@ new_smi->timer_stopped = 0; new_smi->stop_operation = 0; + /* Start clearing the flags before we enable interrupts or the + timer to avoid racing with the timer. */ + start_clear_flags(new_smi); + /* IRQ is defined to be set when non-zero. */ + if (new_smi->irq) + new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; + /* The ipmi_register_smi() code does some operations to determine the channel information, so we must be ready to handle operations before it is called. This means we have @@ -1903,12 +2136,6 @@ goto out_err_stop_timer; } - start_clear_flags(new_smi); - - /* IRQ is defined to be set when non-zero. */ - if (new_smi->irq) - new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; - *smi = new_smi; printk(" IPMI %s interface initialized\n", si_type[intf_num]); @@ -2049,6 +2276,13 @@ conditions removing the timer here. */ while (!to_clean->timer_stopped) { set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + /* Interrupts and timeouts are stopped, now make sure the + interface is in a clean state. */ + while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) { + poll(to_clean); schedule_timeout(1); } diff -Nru a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h --- a/drivers/char/ipmi/ipmi_si_sm.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/ipmi/ipmi_si_sm.h 2004-10-18 14:56:17 -07:00 @@ -52,6 +52,9 @@ state machine shouldn't touch these. */ void *info; void *addr; + int regspacing; + int regsize; + int regshift; }; /* Results of SMI events. */ diff -Nru a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c --- a/drivers/char/ipmi/ipmi_smic_sm.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/ipmi/ipmi_smic_sm.c 2004-10-18 14:56:29 -07:00 @@ -46,7 +46,7 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_SMIC_VERSION "v32" +#define IPMI_SMIC_VERSION "v33" /* smic_debug is a bit-field * SMIC_DEBUG_ENABLE - turned on for now diff -Nru a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c --- a/drivers/char/ipmi/ipmi_watchdog.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/ipmi/ipmi_watchdog.c 2004-10-18 14:57:04 -07:00 @@ -51,7 +51,9 @@ #include #endif -#define IPMI_WATCHDOG_VERSION "v32" +#define PFX "IPMI Watchdog: " + +#define IPMI_WATCHDOG_VERSION "v33" /* * The IPMI command/response information for the watchdog timer. @@ -160,6 +162,7 @@ static DECLARE_WAIT_QUEUE_HEAD(read_q); static struct fasync_struct *fasync_q = NULL; static char pretimeout_since_last_heartbeat = 0; +static char expect_close; /* If true, the driver will start running as soon as it is configured and ready. */ @@ -191,7 +194,7 @@ static int ipmi_ignore_heartbeat = 0; /* Is someone using the watchdog? Only one user is allowed. */ -static int ipmi_wdog_open = 0; +static unsigned long ipmi_wdog_open = 0; /* If set to 1, the heartbeat command will set the state to reset and start the timer. The timer doesn't normally run when the driver is @@ -287,7 +290,7 @@ recv_msg, 1); if (rv) { - printk(KERN_WARNING "IPMI Watchdog, set timeout error: %d\n", + printk(KERN_WARNING PFX "set timeout error: %d\n", rv); } @@ -464,7 +467,7 @@ 1); if (rv) { up(&heartbeat_lock); - printk(KERN_WARNING "IPMI Watchdog, heartbeat failure: %d\n", + printk(KERN_WARNING PFX "heartbeat failure: %d\n", rv); return rv; } @@ -599,6 +602,21 @@ int rv; if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } rv = ipmi_heartbeat(); if (rv) return rv; @@ -662,11 +680,9 @@ switch (iminor(ino)) { case WATCHDOG_MINOR: - if (ipmi_wdog_open) + if(test_and_set_bit(0, &ipmi_wdog_open)) return -EBUSY; - ipmi_wdog_open = 1; - /* Don't start the timer now, let it start on the first heartbeat. */ ipmi_start_timer_on_heartbeat = 1; @@ -704,14 +720,18 @@ { if (iminor(ino)==WATCHDOG_MINOR) { - if (!nowayout) { + if (expect_close == 42) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); + clear_bit(0, &ipmi_wdog_open); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + ipmi_heartbeat(); } - ipmi_wdog_open = 0; } ipmi_fasync (-1, filep, 0); + expect_close = 0; return 0; } @@ -739,7 +759,7 @@ void *handler_data) { if (msg->msg.data[0] != 0) { - printk(KERN_ERR "IPMI Watchdog response: Error %x on cmd %x\n", + printk(KERN_ERR PFX "response: Error %x on cmd %x\n", msg->msg.data[0], msg->msg.cmd); } @@ -784,7 +804,7 @@ rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); if (rv < 0) { - printk("IPMI watchdog: Unable to register with ipmi\n"); + printk(KERN_CRIT PFX "Unable to register with ipmi\n"); goto out; } @@ -796,7 +816,7 @@ if (rv < 0) { ipmi_destroy_user(watchdog_user); watchdog_user = NULL; - printk("IPMI watchdog: Unable to register misc device\n"); + printk(KERN_CRIT PFX "Unable to register misc device\n"); } out: @@ -807,7 +827,7 @@ start_now = 0; /* Disable this function after first startup. */ ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); - printk("Starting IPMI Watchdog now!\n"); + printk(KERN_INFO PFX "Starting now!\n"); } } @@ -818,7 +838,7 @@ /* If no one else handled the NMI, we assume it was the IPMI watchdog. */ if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) - panic("IPMI watchdog pre-timeout"); + panic(PFX "pre-timeout"); /* On some machines, the heartbeat will give an error and not work unless we re-enable @@ -924,7 +944,7 @@ { int rv; - printk(KERN_INFO "IPMI watchdog driver version " + printk(KERN_INFO PFX "driver version " IPMI_WATCHDOG_VERSION "\n"); if (strcmp(action, "reset") == 0) { @@ -937,7 +957,7 @@ action_val = WDOG_TIMEOUT_POWER_DOWN; } else { action_val = WDOG_TIMEOUT_RESET; - printk("ipmi_watchdog: Unknown action '%s', defaulting to" + printk(KERN_INFO PFX "Unknown action '%s', defaulting to" " reset\n", action); } @@ -953,7 +973,7 @@ preaction_val = WDOG_PRETIMEOUT_MSG_INT; } else { preaction_val = WDOG_PRETIMEOUT_NONE; - printk("ipmi_watchdog: Unknown preaction '%s', defaulting to" + printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to" " none\n", preaction); } @@ -965,23 +985,21 @@ preop_val = WDOG_PREOP_GIVE_DATA; } else { preop_val = WDOG_PREOP_NONE; - printk("ipmi_watchdog: Unknown preop '%s', defaulting to" + printk(KERN_INFO PFX "Unknown preop '%s', defaulting to" " none\n", preop); } #ifdef HAVE_NMI_HANDLER if (preaction_val == WDOG_PRETIMEOUT_NMI) { if (preop_val == WDOG_PREOP_GIVE_DATA) { - printk(KERN_WARNING - "ipmi_watchdog: Pretimeout op is to give data" + printk(KERN_WARNING PFX "Pretimeout op is to give data" " but NMI pretimeout is enabled, setting" " pretimeout op to none\n"); preop_val = WDOG_PREOP_NONE; } #ifdef CONFIG_X86_LOCAL_APIC if (nmi_watchdog == NMI_IO_APIC) { - printk(KERN_WARNING - "ipmi_watchdog: nmi_watchdog is set to IO APIC" + printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC" " mode (value is %d), that is incompatible" " with using NMI in the IPMI watchdog." " Disabling IPMI nmi pretimeout.\n", @@ -991,8 +1009,7 @@ #endif rv = request_nmi(&ipmi_nmi_handler); if (rv) { - printk(KERN_WARNING - "ipmi_watchdog: Can't register nmi handler\n"); + printk(KERN_WARNING PFX "Can't register nmi handler\n"); return rv; } #ifdef CONFIG_X86_LOCAL_APIC @@ -1007,8 +1024,7 @@ if (preaction_val == WDOG_PRETIMEOUT_NMI) release_nmi(&ipmi_nmi_handler); #endif - printk(KERN_WARNING - "ipmi_watchdog: can't register smi watcher\n"); + printk(KERN_WARNING PFX "can't register smi watcher\n"); return rv; } @@ -1053,8 +1069,7 @@ /* Disconnect from IPMI. */ rv = ipmi_destroy_user(watchdog_user); if (rv) { - printk(KERN_WARNING - "IPMI Watchdog, error unlinking from IPMI: %d\n", + printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", rv); } watchdog_user = NULL; diff -Nru a/drivers/char/isicom.c b/drivers/char/isicom.c --- a/drivers/char/isicom.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/isicom.c 2004-10-18 14:55:54 -07:00 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -389,7 +390,7 @@ tty = port->tty; save_flags(flags); cli(); - txcount = MIN(TX_SIZE, port->xmit_cnt); + txcount = min_t(short, TX_SIZE, port->xmit_cnt); if ((txcount <= 0) || tty->stopped || tty->hw_stopped) { restore_flags(flags); continue; @@ -421,7 +422,7 @@ residue = NO; wrd = 0; while (1) { - cnt = MIN(txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); + cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); if (residue == YES) { residue = NO; if (cnt > 0) { @@ -484,10 +485,8 @@ if (!tty) return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -650,7 +649,7 @@ } } else { /* Data Packet */ - count = MIN(byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count)); + count = min_t(unsigned short, byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count)); #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n", count, byte_count); @@ -1119,8 +1118,8 @@ isicom_shutdown_port(port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; port->tty = NULL; if (port->blocked_open) { @@ -1163,8 +1162,8 @@ save_flags(flags); while(1) { cli(); - cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); if (cnt <= 0) break; @@ -1180,8 +1179,8 @@ return -EFAULT; } cli(); - cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + cnt = min_t(int, cnt, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt); } else @@ -1563,9 +1562,7 @@ restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } @@ -1906,8 +1903,7 @@ void cleanup_module(void) { re_schedule = 0; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep(1000); #ifdef ISICOM_DEBUG printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count); diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c --- a/drivers/char/istallion.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/istallion.c 2004-10-18 14:56:33 -07:00 @@ -749,17 +749,13 @@ static stliport_t *stli_getport(int brdnr, int panelnr, int portnr); -static inline int stli_initbrds(void); -static inline int stli_initecp(stlibrd_t *brdp); -static inline int stli_initonb(stlibrd_t *brdp); -static inline int stli_findeisabrds(void); -static inline int stli_eisamemprobe(stlibrd_t *brdp); -static inline int stli_initports(stlibrd_t *brdp); -static inline int stli_getbrdnr(void); +static int stli_initecp(stlibrd_t *brdp); +static int stli_initonb(stlibrd_t *brdp); +static int stli_eisamemprobe(stlibrd_t *brdp); +static int stli_initports(stlibrd_t *brdp); #ifdef CONFIG_PCI -static inline int stli_findpcibrds(void); -static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp); +static int stli_initpcibrd(int brdtype, struct pci_dev *devp); #endif /*****************************************************************************/ @@ -2751,7 +2747,7 @@ * more chars to unload. */ -static inline void stli_read(stlibrd_t *brdp, stliport_t *portp) +static void stli_read(stlibrd_t *brdp, stliport_t *portp) { volatile cdkasyrq_t *rp; volatile char *shbuf; @@ -2819,7 +2815,7 @@ * difficult to deal with them here. */ -static inline void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp) +static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp) { int cmd; @@ -2867,7 +2863,7 @@ * then port is still busy, otherwise no longer busy. */ -static inline int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) +static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) { volatile cdkasy_t *ap; volatile cdkctrl_t *cp; @@ -3026,7 +3022,7 @@ * at the cdk header structure. */ -static inline void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp) +static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp) { stliport_t *portp; unsigned char hostbits[(STL_MAXCHANS / 8) + 1]; @@ -3299,7 +3295,7 @@ * we need to do here is set up the appropriate per port data structures. */ -static inline int stli_initports(stlibrd_t *brdp) +static int stli_initports(stlibrd_t *brdp) { stliport_t *portp; int i, panelnr, panelport; @@ -3911,7 +3907,7 @@ * board types. */ -static inline int stli_initecp(stlibrd_t *brdp) +static int stli_initecp(stlibrd_t *brdp) { cdkecpsig_t sig; cdkecpsig_t *sigsp; @@ -4072,7 +4068,7 @@ * This handles only these board types. */ -static inline int stli_initonb(stlibrd_t *brdp) +static int stli_initonb(stlibrd_t *brdp) { cdkonbsig_t sig; cdkonbsig_t *sigsp; @@ -4414,7 +4410,7 @@ * might be. This is a bit if hack, but it is the best we can do. */ -static inline int stli_eisamemprobe(stlibrd_t *brdp) +static int stli_eisamemprobe(stlibrd_t *brdp) { cdkecpsig_t ecpsig, *ecpsigp; cdkonbsig_t onbsig, *onbsigp; @@ -4506,7 +4502,7 @@ return(0); } -static inline int stli_getbrdnr(void) +static int stli_getbrdnr(void) { int i; @@ -4532,7 +4528,7 @@ * do is go probing around in the usual places hoping we can find it. */ -static inline int stli_findeisabrds(void) +static int stli_findeisabrds(void) { stlibrd_t *brdp; unsigned int iobase, eid; @@ -4616,7 +4612,7 @@ * configuration space. */ -static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp) +static int stli_initpcibrd(int brdtype, struct pci_dev *devp) { stlibrd_t *brdp; @@ -4662,7 +4658,7 @@ * one as it is found. */ -static inline int stli_findpcibrds(void) +static int stli_findpcibrds(void) { struct pci_dev *dev = NULL; int rc; @@ -4711,7 +4707,7 @@ * can find. */ -static inline int stli_initbrds(void) +static int stli_initbrds(void) { stlibrd_t *brdp, *nxtbrdp; stlconf_t *confp; diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c --- a/drivers/char/keyboard.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/char/keyboard.c 2004-10-18 14:57:19 -07:00 @@ -123,7 +123,7 @@ */ static struct input_handler kbd_handler; -static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static int dead_key_next; static int npadch = -1; /* -1 or number assembled on pad */ @@ -142,7 +142,7 @@ /* Simple translation table for the SysRq keys */ #ifdef CONFIG_MAGIC_SYSRQ -unsigned char kbd_sysrq_xlate[128] = +unsigned char kbd_sysrq_xlate[KEY_MAX] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ @@ -941,6 +941,9 @@ #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) +#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ + ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) + static unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -1007,6 +1010,8 @@ #else +#define HW_RAW(dev) 0 + #warning "Cannot generate rawmode keyboard for your architecture yet." static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) @@ -1019,7 +1024,15 @@ } #endif -void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) +void kbd_rawcode(unsigned char data) +{ + struct vc_data *vc = vc_cons[fg_console].d; + kbd = kbd_table + fg_console; + if (kbd->kbdmode == VC_RAW) + put_queue(vc, data); +} + +void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1053,7 +1066,7 @@ return; #endif /* CONFIG_MAC_EMUMOUSEBTN */ - if ((raw_mode = (kbd->kbdmode == VC_RAW))) + if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); @@ -1119,6 +1132,9 @@ return; } + if (keycode > NR_KEYS) + return; + keysym = key_map[keycode]; type = KTYP(keysym); @@ -1148,11 +1164,12 @@ } static void kbd_event(struct input_handle *handle, unsigned int event_type, - unsigned int keycode, int down) + unsigned int event_code, int value) { - if (event_type != EV_KEY) - return; - kbd_keycode(keycode, down, handle->dev->regs); + if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) + kbd_rawcode(value); + if (event_type == EV_KEY) + kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs); tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; schedule_console_callback(); diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c --- a/drivers/char/mem.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/mem.c 2004-10-18 14:56:32 -07:00 @@ -31,9 +31,6 @@ # include #endif -#ifdef CONFIG_FB -extern void fbmem_init(void); -#endif #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) extern void tapechar_init(void); #endif @@ -86,7 +83,7 @@ * above the IO hole... Ah, and of course, XFree86 doesn't pass * O_SYNC when mapping us to tap IO space. Surprised ? */ - return !page_is_ram(addr); + return !page_is_ram(addr >> PAGE_SHIFT); #else /* * Accessing memory above the top the kernel knows about or through a file pointer @@ -416,7 +413,7 @@ if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0) goto out_up; - if (vma->vm_flags & VM_SHARED) + if (vma->vm_flags & (VM_SHARED | VM_HUGETLB)) break; count = vma->vm_end - addr; if (count > size) @@ -730,9 +727,6 @@ S_IFCHR | devlist[i].mode, devlist[i].name); } -#if defined (CONFIG_FB) - fbmem_init(); -#endif return 0; } diff -Nru a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/mmtimer.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,216 @@ +/* + * Intel Multimedia Timer device implementation for SGI SN platforms. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. + * + * This driver exports an API that should be supportable by any HPET or IA-PC + * multimedia timer. The code below is currently specific to the SGI Altix + * SHub RTC, however. + * + * 11/01/01 - jbarnes - initial revision + * 9/10/04 - Christoph Lameter - remove interrupt support for kernel inclusion + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jesse Barnes "); +MODULE_DESCRIPTION("Multimedia timer support"); +MODULE_LICENSE("GPL"); + +/* name of the device, usually in /dev */ +#define MMTIMER_NAME "mmtimer" +#define MMTIMER_DESC "IA-PC Multimedia Timer" +#define MMTIMER_VERSION "1.0" + +#define RTC_BITS 55 /* 55 bits for this implementation */ + +static int mmtimer_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma); + +/* + * Period in femtoseconds (10^-15 s) + */ +static unsigned long mmtimer_femtoperiod = 0; + +static struct file_operations mmtimer_fops = { + .owner = THIS_MODULE, + .mmap = mmtimer_mmap, + .ioctl = mmtimer_ioctl, +}; + +/** + * mmtimer_ioctl - ioctl interface for /dev/mmtimer + * @inode: inode of the device + * @file: file structure for the device + * @cmd: command to execute + * @arg: optional argument to command + * + * Executes the command specified by @cmd. Returns 0 for success, < 0 for + * failure. + * + * Valid commands: + * + * %MMTIMER_GETOFFSET - Should return the offset (relative to the start + * of the page where the registers are mapped) for the counter in question. + * + * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15) + * seconds + * + * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address + * specified by @arg + * + * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter + * + * %MMTIMER_MMAPAVAIL - Returns 1 if the registers can be mmap'd into userspace + * + * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it + * in the address specified by @arg. + */ +static int mmtimer_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case MMTIMER_GETOFFSET: /* offset of the counter */ + /* + * SN RTC registers are on their own 64k page + */ + if(PAGE_SIZE <= (1 << 16)) + ret = (((long)RTC_COUNTER_ADDR) & (PAGE_SIZE-1)) / 8; + else + ret = -ENOSYS; + break; + + case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */ + if(copy_to_user((unsigned long *)arg, &mmtimer_femtoperiod, + sizeof(unsigned long))) + return -EFAULT; + break; + + case MMTIMER_GETFREQ: /* frequency in Hz */ + if(copy_to_user((unsigned long *)arg, + &sn_rtc_cycles_per_second, + sizeof(unsigned long))) + return -EFAULT; + ret = 0; + break; + + case MMTIMER_GETBITS: /* number of bits in the clock */ + ret = RTC_BITS; + break; + + case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */ + ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0; + break; + + case MMTIMER_GETCOUNTER: + if(copy_to_user((unsigned long *)arg, RTC_COUNTER_ADDR, + sizeof(unsigned long))) + return -EFAULT; + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} + +/** + * mmtimer_mmap - maps the clock's registers into userspace + * @file: file structure for the device + * @vma: VMA to map the registers into + * + * Calls remap_page_range() to map the clock's registers into + * the calling process' address space. + */ +static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long mmtimer_addr; + + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + + if (vma->vm_flags & VM_WRITE) + return -EPERM; + + if (PAGE_SIZE > (1 << 16)) + return -ENOSYS; + + vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED ); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + mmtimer_addr = __pa(RTC_COUNTER_ADDR); + mmtimer_addr &= ~(PAGE_SIZE - 1); + mmtimer_addr &= 0xfffffffffffffffUL; + + if (remap_page_range(vma, vma->vm_start, mmtimer_addr, PAGE_SIZE, + vma->vm_page_prot)) { + printk(KERN_ERR "remap_page_range failed in mmtimer.c\n"); + return -EAGAIN; + } + + return 0; +} + +static struct miscdevice mmtimer_miscdev = { + SGI_MMTIMER, + MMTIMER_NAME, + &mmtimer_fops +}; + +/** + * mmtimer_init - device initialization routine + * + * Does initial setup for the mmtimer device. + */ +static int __init mmtimer_init(void) +{ + if (!ia64_platform_is("sn2")) + return -1; + + /* + * Sanity check the cycles/sec variable + */ + if (sn_rtc_cycles_per_second < 100000) { + printk(KERN_ERR "%s: unable to determine clock frequency\n", + MMTIMER_NAME); + return -1; + } + + mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / + 2) / sn_rtc_cycles_per_second; + + strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME); + if (misc_register(&mmtimer_miscdev)) { + printk(KERN_ERR "%s: failed to register device\n", + MMTIMER_NAME); + return -1; + } + + printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION, + sn_rtc_cycles_per_second/(unsigned long)1E6); + + return 0; +} + +module_init(mmtimer_init); + diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c --- a/drivers/char/moxa.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/moxa.c 2004-10-18 14:57:04 -07:00 @@ -618,8 +618,8 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; ch->event = 0; ch->tty = NULL; @@ -693,9 +693,7 @@ if (ch == NULL) return; MoxaPortFlushData(ch->port, 1); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -954,9 +952,7 @@ if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { if (!tp->stopped) { ch->statusflags &= ~LOWWAIT; - if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tp->ldisc.write_wakeup) - (tp->ldisc.write_wakeup) (tp); + tty_wakeup(tp); wake_up_interruptible(&tp->write_wait); } } @@ -1123,9 +1119,7 @@ if (ch->tty && (ch->statusflags & EMPTYWAIT)) { if (MoxaPortTxQueue(ch->port) == 0) { ch->statusflags &= ~EMPTYWAIT; - if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - ch->tty->ldisc.write_wakeup) - (ch->tty->ldisc.write_wakeup) (ch->tty); + tty_wakeup(ch->tty); wake_up_interruptible(&ch->tty->write_wait); return; } diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c --- a/drivers/char/mxser.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/mxser.c 2004-10-18 14:56:48 -07:00 @@ -101,10 +101,6 @@ #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * Define the Moxa PCI vendor and device IDs. */ @@ -349,10 +345,10 @@ static void mxser_stop(struct tty_struct *); static void mxser_start(struct tty_struct *); static void mxser_hangup(struct tty_struct *); -static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *); static inline void mxser_receive_chars(struct mxser_struct *, int *); static inline void mxser_transmit_chars(struct mxser_struct *); static inline void mxser_check_modem_status(struct mxser_struct *, int); +static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *); static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *); static int mxser_startup(struct mxser_struct *); static void mxser_shutdown(struct mxser_struct *); @@ -678,9 +674,7 @@ tty = info->tty; if (tty) { if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) { @@ -817,8 +811,8 @@ mxser_shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; info->event = 0; info->tty = NULL; @@ -849,7 +843,7 @@ if (from_user) { down(&mxvar_tmp_buf_sem); while (1) { - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; @@ -862,7 +856,7 @@ } cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); @@ -877,7 +871,7 @@ } else { while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { restore_flags(flags); @@ -976,9 +970,7 @@ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); } static int mxser_ioctl(struct tty_struct *tty, struct file *file, @@ -1307,69 +1299,6 @@ wake_up_interruptible(&info->open_wait); } -/* - * This is the serial driver's generic interrupt routine - */ -static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int status, i; - struct mxser_struct *info; - struct mxser_struct *port; - int max, irqbits, bits, msr; - int pass_counter = 0; - int handled = 0; - - port = NULL; - for (i = 0; i < MXSER_BOARDS; i++) { - if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { - port = dev_id; - break; - } - } - - if (i == MXSER_BOARDS) - return IRQ_NONE; - if (port == 0) - return IRQ_NONE; - max = mxser_numports[mxsercfg[i].board_type]; - - while (1) { - irqbits = inb(port->vector) & port->vectormask; - if (irqbits == port->vectormask) - break; - handled = 1; - for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { - if (irqbits == port->vectormask) - break; - if (bits & irqbits) - continue; - info = port + i; - if (!info->tty || - (inb(info->base + UART_IIR) & UART_IIR_NO_INT)) - continue; - status = inb(info->base + UART_LSR) & info->read_status_mask; - if (status & UART_LSR_DR) - mxser_receive_chars(info, &status); - msr = inb(info->base + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(info, msr); - if (status & UART_LSR_THRE) { -/* 8-2-99 by William - if ( info->x_char || (info->xmit_cnt > 0) ) - */ - mxser_transmit_chars(info); - } - } - if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { -#if 0 - printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n"); -#endif - break; /* Prevent infinite loops */ - } - } - return IRQ_RETVAL(handled); -} - static inline void mxser_receive_chars(struct mxser_struct *info, int *status) { @@ -1488,6 +1417,69 @@ } } } +} + +/* + * This is the serial driver's generic interrupt routine + */ +static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int status, i; + struct mxser_struct *info; + struct mxser_struct *port; + int max, irqbits, bits, msr; + int pass_counter = 0; + int handled = 0; + + port = NULL; + for (i = 0; i < MXSER_BOARDS; i++) { + if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { + port = dev_id; + break; + } + } + + if (i == MXSER_BOARDS) + return IRQ_NONE; + if (port == 0) + return IRQ_NONE; + max = mxser_numports[mxsercfg[i].board_type]; + + while (1) { + irqbits = inb(port->vector) & port->vectormask; + if (irqbits == port->vectormask) + break; + handled = 1; + for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { + if (irqbits == port->vectormask) + break; + if (bits & irqbits) + continue; + info = port + i; + if (!info->tty || + (inb(info->base + UART_IIR) & UART_IIR_NO_INT)) + continue; + status = inb(info->base + UART_LSR) & info->read_status_mask; + if (status & UART_LSR_DR) + mxser_receive_chars(info, &status); + msr = inb(info->base + UART_MSR); + if (msr & UART_MSR_ANY_DELTA) + mxser_check_modem_status(info, msr); + if (status & UART_LSR_THRE) { +/* 8-2-99 by William + if ( info->x_char || (info->xmit_cnt > 0) ) + */ + mxser_transmit_chars(info); + } + } + if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { +#if 0 + printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + } + return IRQ_RETVAL(handled); } static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, diff -Nru a/drivers/char/n_tty.c b/drivers/char/n_tty.c --- a/drivers/char/n_tty.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/n_tty.c 2004-10-18 14:55:54 -07:00 @@ -99,11 +99,18 @@ spin_unlock_irqrestore(&tty->read_lock, flags); } -/* - * Check whether to call the driver.unthrottle function. - * We test the TTY_THROTTLED bit first so that it always - * indicates the current state. +/** + * check_unthrottle - allow new receive data + * @tty; tty device + * + * Check whether to call the driver.unthrottle function. + * We test the TTY_THROTTLED bit first so that it always + * indicates the current state. The decision about whether + * it is worth allowing more input has been taken by the caller. + * Can sleep, may be called under the atomic_read semaphore but + * this is not guaranteed. */ + static void check_unthrottle(struct tty_struct * tty) { if (tty->count && @@ -112,10 +119,13 @@ tty->driver->unthrottle(tty); } -/* - * Reset the read buffer counters, clear the flags, - * and make sure the driver is unthrottled. Called - * from n_tty_open() and n_tty_flush_buffer(). +/** + * reset_buffer_flags - reset buffer state + * @tty: terminal to reset + * + * Reset the read buffer counters, clear the flags, + * and make sure the driver is unthrottled. Called + * from n_tty_open() and n_tty_flush_buffer(). */ static void reset_buffer_flags(struct tty_struct *tty) { @@ -129,9 +139,19 @@ check_unthrottle(tty); } -/* - * Flush the input buffer +/** + * n_tty_flush_buffer - clean input queue + * @tty: terminal device + * + * Flush the input buffer. Called when the line discipline is + * being closed, when the tty layer wants the buffer flushed (eg + * at hangup) or when the N_TTY line discipline internally has to + * clean the pending queue (for example some signals). + * + * FIXME: tty->ctrl_status is not spinlocked and relies on + * lock_kernel() still. */ + void n_tty_flush_buffer(struct tty_struct * tty) { /* clear everything and unthrottle the driver */ @@ -146,9 +166,14 @@ } } -/* - * Return number of characters buffered to be delivered to user +/** + * n_tty_chars_in_buffer - report available bytes + * @tty: tty device + * + * Report the number of characters buffered to be delivered to user + * at this instant in time. */ + ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) { unsigned long flags; @@ -166,20 +191,47 @@ return n; } +/** + * is_utf8_continuation - utf8 multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character. We use this to correctly compute the on screen size + * of the character when printing + */ + static inline int is_utf8_continuation(unsigned char c) { return (c & 0xc0) == 0x80; } +/** + * is_continuation - multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character and the terminal is in unicode mode. + */ + static inline int is_continuation(unsigned char c, struct tty_struct *tty) { return I_IUTF8(tty) && is_utf8_continuation(c); } -/* - * Perform OPOST processing. Returns -1 when the output device is - * full and the character must be retried. +/** + * opost - output post processor + * @c: character (or partial unicode symbol) + * @tty: terminal device + * + * Perform OPOST processing. Returns -1 when the output device is + * full and the character must be retried. Note that Linux currently + * ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. They simply aren't + * relevant in the world today. If you ever need them, add them here. + * + * Called from both the receive and transmit sides and can be called + * re-entrantly. Relies on lock_kernel() still. */ + static int opost(unsigned char c, struct tty_struct *tty) { int space, spaces; @@ -239,10 +291,20 @@ return 0; } -/* - * opost_block --- to speed up block console writes, among other - * things. +/** + * opost_block - block postprocess + * @tty: terminal device + * @inbuf: user buffer + * @nr: number of bytes + * + * This path is used to speed up block console writes, among other + * things when processing blocks of output data. It handles only + * the simple cases normally found and helps to generate blocks of + * symbols for the console driver and thus improve performance. + * + * Called from write_chan under the tty layer write lock. */ + static ssize_t opost_block(struct tty_struct * tty, const unsigned char __user * inbuf, unsigned int nr) { @@ -304,13 +366,27 @@ } - +/** + * put_char - write character to driver + * @c: character (or part of unicode symbol) + * @tty: terminal device + * + * Queue a byte to the driver layer for output + */ + static inline void put_char(unsigned char c, struct tty_struct *tty) { tty->driver->put_char(tty, c); } -/* Must be called only when L_ECHO(tty) is true. */ +/** + * echo_char - echo characters + * @c: unicode byte to echo + * @tty: terminal device + * + * Echo user input back onto the screen. This must be called only when + * L_ECHO(tty) is true. Called from the driver receive_buf path. + */ static void echo_char(unsigned char c, struct tty_struct *tty) { @@ -331,6 +407,16 @@ } } +/** + * eraser - handle erase function + * @c: character input + * @tty: terminal device + * + * Perform erase and neccessary output when an erase character is + * present in the stream from the driver layer. Handles the complexities + * of UTF-8 multibyte symbols. + */ + static void eraser(unsigned char c, struct tty_struct *tty) { enum { ERASE, WERASE, KILL } kill_type; @@ -463,6 +549,18 @@ finish_erasing(tty); } +/** + * isig - handle the ISIG optio + * @sig: signal + * @tty: terminal + * @flush: force flush + * + * Called when a signal is being sent due to terminal input. This + * may caus terminal flushing to take place according to the termios + * settings and character used. Called from the driver receive_buf + * path so serialized. + */ + static inline void isig(int sig, struct tty_struct *tty, int flush) { if (tty->pgrp > 0) @@ -474,6 +572,16 @@ } } +/** + * n_tty_receive_break - handle break + * @tty: terminal + * + * An RS232 break event has been hit in the incoming bitstream. This + * can cause a variety of events depending upon the termios settings. + * + * Called from the receive_buf path so single threaded. + */ + static inline void n_tty_receive_break(struct tty_struct *tty) { if (I_IGNBRK(tty)) @@ -490,19 +598,40 @@ wake_up_interruptible(&tty->read_wait); } +/** + * n_tty_receive_overrun - handle overrun reporting + * @tty: terminal + * + * Data arrived faster than we could process it. While the tty + * driver has flagged this the bits that were missed are gone + * forever. + * + * Called from the receive_buf path so single threaded. Does not + * need locking as num_overrun and overrun_time are function + * private. + */ + static inline void n_tty_receive_overrun(struct tty_struct *tty) { char buf[64]; tty->num_overrun++; if (time_before(tty->overrun_time, jiffies - HZ)) { - printk("%s: %d input overrun(s)\n", tty_name(tty, buf), + printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), tty->num_overrun); tty->overrun_time = jiffies; tty->num_overrun = 0; } } +/** + * n_tty_receive_parity_error - error notifier + * @tty: terminal device + * @c: character + * + * Process a parity error and queue the right data to indicate + * the error case if neccessary. Locking as per n_tty_receive_buf. + */ static inline void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { @@ -520,6 +649,16 @@ wake_up_interruptible(&tty->read_wait); } +/** + * n_tty_receive_char - perform processing + * @tty: terminal device + * @c: character + * + * Process an individual character of input received from the driver. + * This is serialized with respect to itself by the rules for the + * driver above. + */ + static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { unsigned long flags; @@ -711,6 +850,16 @@ put_tty_queue(c, tty); } +/** + * n_tty_receive_room - receive space + * @tty: terminal + * + * Called by the driver to find out how much data it is + * permitted to feed to the line discipline without any being lost + * and thus to manage flow control. Not serialized. Answers for the + * "instant". + */ + static int n_tty_receive_room(struct tty_struct *tty) { int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; @@ -729,10 +878,13 @@ return 0; } -/* - * Required for the ptys, serial driver etc. since processes - * that attach themselves to the master and rely on ASYNC - * IO must be woken up +/** + * n_tty_write_wakeup - asynchronous I/O notifier + * @tty: tty device + * + * Required for the ptys, serial driver etc. since processes + * that attach themselves to the master and rely on ASYNC + * IO must be woken up */ static void n_tty_write_wakeup(struct tty_struct *tty) @@ -745,6 +897,19 @@ return; } +/** + * n_tty_receive_buf - data receive + * @tty: terminal device + * @cp: buffer + * @fp: flag buffer + * @count: characters + * + * Called by the terminal driver when a block of characters has + * been received. This function must be called from soft contexts + * not from interrupt context. The driver is responsible for making + * calls one at a time and in order (or using flush_to_ldisc) + */ + static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { @@ -828,6 +993,18 @@ current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); } +/** + * n_tty_set_termios - termios data changed + * @tty: terminal + * @old: previous data + * + * Called by the tty layer when the user changes termios flags so + * that the line discipline can plan ahead. This function cannot sleep + * and is protected from re-entry by the tty layer. The user is + * guaranteed that this function will not be re-entered or in progress + * when the ldisc is closed. + */ + static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) { if (!tty) @@ -843,7 +1020,6 @@ I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { - local_irq_disable(); // FIXME: is this safe? memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) @@ -879,7 +1055,6 @@ set_bit(SUSP_CHAR(tty), tty->process_char_map); } clear_bit(__DISABLED_CHAR, tty->process_char_map); - local_irq_enable(); // FIXME: is this safe? tty->raw = 0; tty->real_raw = 0; } else { @@ -893,6 +1068,16 @@ } } +/** + * n_tty_close - close the ldisc for this tty + * @tty: device + * + * Called from the terminal layer when this line discipline is + * being shut down, either because of a close or becsuse of a + * discipline change. The function will not be called while other + * ldisc methods are in progress. + */ + static void n_tty_close(struct tty_struct *tty) { n_tty_flush_buffer(tty); @@ -902,11 +1087,22 @@ } } +/** + * n_tty_open - open an ldisc + * @tty: terminal to open + * + * Called when this line discipline is being attached to the + * terminal device. Can sleep. Called serialized so that no + * other events will occur in parallel. No further open will occur + * until a close. + */ + static int n_tty_open(struct tty_struct *tty) { if (!tty) return -EINVAL; + /* This one is ugly. Currently a malloc failure here can panic */ if (!tty->read_buf) { tty->read_buf = alloc_buf(); if (!tty->read_buf) @@ -932,14 +1128,23 @@ return 0; } -/* - * Helper function to speed up read_chan. It is only called when - * ICANON is off; it copies characters straight from the tty queue to - * user space directly. It can be profitably called twice; once to - * drain the space from the tail pointer to the (physical) end of the - * buffer, and once to drain the space from the (physical) beginning of - * the buffer to head pointer. +/** + * copy_from_read_buf - copy read data directly + * @tty: terminal device + * @b: user data + * @nr: size of data + * + * Helper function to speed up read_chan. It is only called when + * ICANON is off; it copies characters straight from the tty queue to + * user space directly. It can be profitably called twice; once to + * drain the space from the tail pointer to the (physical) end of the + * buffer, and once to drain the space from the (physical) beginning of + * the buffer to head pointer. + * + * Called under the tty->atomic_read sem and with TTY_DONT_FLIP set + * */ + static inline int copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr) @@ -970,25 +1175,18 @@ extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *); -static ssize_t read_chan(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) +/** + * job_control - check job control + * @tty: tty + * @file: file handle + * + * Perform job control management checks on this file/tty descriptor + * and if appropriate send any needed signals and return a negative + * error code if action should be taken. + */ + +static int job_control(struct tty_struct *tty, struct file *file) { - unsigned char __user *b = buf; - DECLARE_WAITQUEUE(wait, current); - int c; - int minimum, time; - ssize_t retval = 0; - ssize_t size; - long timeout; - unsigned long flags; - -do_it_again: - - if (!tty->read_buf) { - printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); - return -EIO; - } - /* Job control check -- must be done at start and after every sleep (POSIX.1 7.1.1.4). */ /* NOTE: not yet done after every sleep pending a thorough @@ -1006,7 +1204,48 @@ return -ERESTARTSYS; } } + return 0; +} + + +/** + * read_chan - read function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Perform reads for the line discipline. We are guaranteed that the + * line discipline will not be closed under us but we may get multiple + * parallel readers and must handle this ourselves. We may also get + * a hangup. Always called in user context, may sleep. + * + * This code must be sure never to sleep through a hangup. + */ + +static ssize_t read_chan(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) +{ + unsigned char __user *b = buf; + DECLARE_WAITQUEUE(wait, current); + int c; + int minimum, time; + ssize_t retval = 0; + ssize_t size; + long timeout; + unsigned long flags; + +do_it_again: + + if (!tty->read_buf) { + printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); + return -EIO; + } + c = job_control(tty, file); + if(c < 0) + return c; + minimum = time = 0; timeout = MAX_SCHEDULE_TIMEOUT; if (!tty->icanon) { @@ -1028,6 +1267,9 @@ } } + /* + * Internal serialization of reads. + */ if (file->f_flags & O_NONBLOCK) { if (down_trylock(&tty->atomic_read)) return -EAGAIN; @@ -1177,6 +1419,21 @@ return retval; } +/** + * write_chan - write function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Write function of the terminal device. This is serialized with + * respect to other write callers but not to termios changes, reads + * and other such events. We must be careful with N_TTY as the receive + * code will echo characters, thus calling driver write methods. + * + * This code must be sure never to sleep through a hangup. + */ + static ssize_t write_chan(struct tty_struct * tty, struct file * file, const unsigned char __user * buf, size_t nr) { @@ -1246,7 +1503,25 @@ return (b - buf) ? b - buf : retval; } -/* Called without the kernel lock held - fine */ +/** + * normal_poll - poll method for N_TTY + * @tty: terminal device + * @file: file accessing it + * @wait: poll table + * + * Called when the line discipline is asked to poll() for data or + * for special events. This code is not serialized with respect to + * other events save open/close. + * + * This code must be sure never to sleep through a hangup. + * Called without the kernel lock held - fine + * + * FIXME: if someone changes the VMIN or discipline settings for the + * terminal while another process is in poll() the poll does not + * recompute the new limits. Possibly set_termios should issue + * a read wakeup to fix this bug. + */ + static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) { unsigned int mask = 0; @@ -1287,6 +1562,7 @@ n_tty_ioctl, /* ioctl */ n_tty_set_termios, /* set_termios */ normal_poll, /* poll */ + NULL, /* hangup */ n_tty_receive_buf, /* receive_buf */ n_tty_receive_room, /* receive_room */ n_tty_write_wakeup /* write_wakeup */ diff -Nru a/drivers/char/nwflash.c b/drivers/char/nwflash.c --- a/drivers/char/nwflash.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/nwflash.c 2004-10-18 14:57:05 -07:00 @@ -60,15 +60,6 @@ extern spinlock_t gpio_lock; -/* - * the delay routine - it is often required to let the flash "breeze"... - */ -void flash_wait(int timeout) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(timeout); -} - static int get_flash_id(void) { volatile unsigned int c1, c2; @@ -401,7 +392,7 @@ /* * wait 10 ms */ - flash_wait(HZ / 100); + msleep(10); /* * wait while erasing in process (up to 10 sec) @@ -409,7 +400,7 @@ timeout = jiffies + 10 * HZ; c1 = 0; while (!(c1 & 0x80) && time_before(jiffies, timeout)) { - flash_wait(HZ / 100); + msleep(10); /* * read any address */ @@ -440,7 +431,7 @@ /* * just to make sure - verify if erased OK... */ - flash_wait(HZ / 100); + msleep(10); pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + (nBlock << 16))); @@ -587,7 +578,7 @@ /* * wait couple ms */ - flash_wait(HZ / 100); + msleep(10); /* * red LED == write */ @@ -612,7 +603,7 @@ leds_event(led_amber_off); leds_event(led_green_on); - flash_wait(HZ / 100); + msleep(10); pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c --- a/drivers/char/pcmcia/synclink_cs.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/pcmcia/synclink_cs.c 2004-10-18 14:56:28 -07:00 @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.22 2004/06/01 20:27:46 paulkf Exp $ + * $Id: synclink_cs.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ #include #include #include +#include #include #include @@ -76,12 +78,8 @@ #include #include -#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE -#define CONFIG_SYNCLINK_SYNCPPP 1 -#endif - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#include +#ifdef CONFIG_HDLC_MODULE +#define CONFIG_HDLC 1 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -239,12 +237,11 @@ int netcount; int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_SYNCLINK_SYNCPPP - struct ppp_device pppdev; - char netname[10]; + +#ifdef CONFIG_HDLC struct net_device *netdev; - struct net_device_stats netstats; #endif + } MGSLPC_INFO; #define MGSLPC_MAGIC 0x5402 @@ -262,7 +259,7 @@ * FIXME: PPC has PVR defined in asm/reg.h. For now we just undef it. */ #undef PVR - + #define RXFIFO 0 #define TXFIFO 0 #define STAR 0x20 @@ -398,18 +395,12 @@ static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_SYNCLINK_SYNCPPP -/* SPPP/HDLC stuff */ -static void mgslpc_sppp_init(MGSLPC_INFO *info); -static void mgslpc_sppp_delete(MGSLPC_INFO *info); -static int mgslpc_sppp_open(struct net_device *d); -static int mgslpc_sppp_close(struct net_device *d); -static void mgslpc_sppp_tx_timeout(struct net_device *d); -static int mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *d); -static void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size); -static void mgslpc_sppp_tx_done(MGSLPC_INFO *info); -static int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -struct net_device_stats *mgslpc_net_stats(struct net_device *dev); +#ifdef CONFIG_HDLC +#define dev_to_port(D) (dev_to_hdlc(D)->priv) +static void hdlcdev_tx_done(MGSLPC_INFO *info); +static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); +static int hdlcdev_init(MGSLPC_INFO *info); +static void hdlcdev_exit(MGSLPC_INFO *info); #endif static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); @@ -453,8 +444,6 @@ static int set_rxenable(MGSLPC_INFO *info, int enable); static int wait_events(MGSLPC_INFO *info, int __user *mask); -#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) - static MGSLPC_INFO *mgslpc_device_list = NULL; static int mgslpc_device_count = 0; @@ -494,7 +483,7 @@ MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.22 $"; +static char *driver_version = "$Revision: 4.26 $"; static struct tty_driver *serial_driver; @@ -504,10 +493,6 @@ static void mgslpc_change_params(MGSLPC_INFO *info); static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* PCMCIA prototypes */ static void mgslpc_config(dev_link_t *link); @@ -531,6 +516,40 @@ return mgslpc_get_text_ptr; } +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_flush_buffer - flush line discipline receive buffers + * ldisc_receive_buf - pass receive data to line discipline + */ + +static void ldisc_flush_buffer(struct tty_struct *tty) +{ + struct tty_ldisc *ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } +} + +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + static dev_link_t *mgslpc_attach(void) { MGSLPC_INFO *info; @@ -984,13 +1003,7 @@ printk("bh_transmit() entry on %s\n", info->device_name); if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):calling ldisc.write_wakeup on %s\n", - __FILE__,__LINE__,info->device_name); - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } @@ -1163,9 +1176,9 @@ info->drop_rts_on_tx_done = 0; } -#ifdef CONFIG_SYNCLINK_SYNCPPP +#ifdef CONFIG_HDLC if (info->netcount) - mgslpc_sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif { @@ -1201,7 +1214,7 @@ return; while (info->tx_count && fifo_count) { - c = MIN(2, MIN(fifo_count, MIN(info->tx_count, TXBUFSIZE - info->tx_get))); + c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); if (c == 1) { write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); @@ -1271,13 +1284,13 @@ info->icount.dcd++; if (info->serial_signals & SerialSignal_DCD) { info->input_signal_events.dcd_up++; -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) - sppp_reopen(info->netdev); -#endif } else info->input_signal_events.dcd_down++; +#ifdef CONFIG_HDLC + if (info->netcount) + hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev); +#endif wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); @@ -1764,8 +1777,8 @@ } for (;;) { - c = MIN(count, - MIN(TXBUFSIZE - info->tx_count - 1, + c = min(count, + min(TXBUFSIZE - info->tx_count - 1, TXBUFSIZE - info->tx_put)); if (c <= 0) break; @@ -1875,11 +1888,9 @@ info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); spin_unlock_irqrestore(&info->lock,flags); - + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* Send a high-priority XON/XOFF character @@ -2588,9 +2599,8 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + ldisc_flush_buffer(tty); shutdown(info); @@ -2651,7 +2661,7 @@ char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); if (info->params.mode == MGSL_MODE_HDLC) { while (info->tx_active) { @@ -2876,7 +2886,7 @@ cleanup: if (retval) { if (tty->count == 1) - info->tty = NULL;/* tty layer will release tty struct */ + info->tty = NULL; /* tty layer will release tty struct */ if(info->count) info->count--; } @@ -2931,7 +2941,7 @@ if (info->icount.rxover) ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) - ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc); + ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); } else { ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); @@ -3070,12 +3080,8 @@ printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n", info->device_name, info->io_base, info->irq_level); - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#ifdef MODULE - if (info->dosyncppp) -#endif - mgslpc_sppp_init(info); +#ifdef CONFIG_HDLC + hdlcdev_init(info); #endif } @@ -3090,9 +3096,8 @@ last->next_device = info->next_device; else mgslpc_device_list = info->next_device; -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->dosyncppp) - mgslpc_sppp_delete(info); +#ifdef CONFIG_HDLC + hdlcdev_exit(info); #endif release_resources(info); kfree(info); @@ -3669,7 +3674,7 @@ } else { info->tx_active = 1; tx_ready(info); - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } } @@ -4021,9 +4026,12 @@ return_frame = 1; } framesize = 0; -#ifdef CONFIG_SYNCLINK_SYNCPPP - info->netstats.rx_errors++; - info->netstats.rx_frame_errors++; +#ifdef CONFIG_HDLC + { + struct net_device_stats *stats = hdlc_stats(info->netdev); + stats->rx_errors++; + stats->rx_frame_errors++; + } #endif } else return_frame = 1; @@ -4052,18 +4060,12 @@ ++framesize; } -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) { - /* pass frame to syncppp device */ - mgslpc_sppp_rx_done(info, buf->data, framesize); - } +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_rx(info, buf->data, framesize); else #endif - { - /* Call the line discipline receive callback directly. */ - if (tty && tty->ldisc.receive_buf) - tty->ldisc.receive_buf(tty, buf->data, info->flag_buf, framesize); - } + ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize); } } @@ -4128,7 +4130,7 @@ end_time=100; while(end_time-- && !info->irq_occurred) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); } info->testing_irq = FALSE; @@ -4215,88 +4217,134 @@ spin_unlock_irqrestore(&info->lock,flags); -#ifdef CONFIG_SYNCLINK_SYNCPPP +#ifdef CONFIG_HDLC if (info->netcount) - mgslpc_sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif bh_transmit(info); } -#ifdef CONFIG_SYNCLINK_SYNCPPP -/* syncppp net device routines +#ifdef CONFIG_HDLC + +/** + * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * set encoding and frame check sequence (FCS) options + * + * dev pointer to network device structure + * encoding serial encoding setting + * parity FCS setting + * + * returns 0 if success, otherwise error code */ - -static void mgslpc_setup(struct net_device *dev) +static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) { - dev->open = mgslpc_sppp_open; - dev->stop = mgslpc_sppp_close; - dev->hard_start_xmit = mgslpc_sppp_tx; - dev->do_ioctl = mgslpc_sppp_ioctl; - dev->get_stats = mgslpc_net_stats; - dev->tx_timeout = mgslpc_sppp_tx_timeout; - dev->watchdog_timeo = 10*HZ; -} + MGSLPC_INFO *info = dev_to_port(dev); + unsigned char new_encoding; + unsigned short new_crctype; -void mgslpc_sppp_init(MGSLPC_INFO *info) -{ - struct net_device *d; + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - sprintf(info->netname,"mgslp%d",info->line); - - d = alloc_netdev(0, info->netname, mgslpc_setup); - if (!d) { - printk(KERN_WARNING "%s: alloc_netdev failed.\n", - info->netname); - return; + switch (encoding) + { + case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; + case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; + case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; + case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; + case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; + default: return -EINVAL; } - info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = d; - - d->base_addr = info->io_base; - d->irq = info->irq_level; - d->priv = info; - - sppp_attach(&info->pppdev); - mgslpc_setup(d); - - if (register_netdev(d)) { - printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(info->netdev); - info->netdev = NULL; - info->pppdev.dev = NULL; - free_netdev(d); - return; + switch (parity) + { + case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; + case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; + case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; + default: return -EINVAL; } - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_init()\n"); + info->params.encoding = new_encoding; + info->params.crc_type = new_crctype;; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + mgslpc_program_hw(info); + + return 0; } -void mgslpc_sppp_delete(MGSLPC_INFO *info) +/** + * called by generic HDLC layer to send frame + * + * skb socket buffer containing HDLC frame + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { + MGSLPC_INFO *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_delete(%s)\n",info->netname); - unregister_netdev(info->netdev); - sppp_detach(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; - info->pppdev.dev = NULL; + printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); + + /* stop sending until this frame completes */ + netif_stop_queue(dev); + + /* copy data to device buffers */ + memcpy(info->tx_buf, skb->data, skb->len); + info->tx_get = 0; + info->tx_put = info->tx_count = skb->len; + + /* update network statistics */ + stats->tx_packets++; + stats->tx_bytes += skb->len; + + /* done with socket buffer, so free it */ + dev_kfree_skb(skb); + + /* save start time for transmit timeout detection */ + dev->trans_start = jiffies; + + /* start hardware transmitter if necessary */ + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + + return 0; } -int mgslpc_sppp_open(struct net_device *d) +/** + * called by network layer when interface enabled + * claim resources and initialize hardware + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_open(struct net_device *dev) { - MGSLPC_INFO *info = d->priv; - int err; + MGSLPC_INFO *info = dev_to_port(dev); + int rc; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_open(%s)\n",info->netname); + printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); + /* generic HDLC layer open processing */ + if ((rc = hdlc_open(dev))) + return rc; + + /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); if (info->count != 0 || info->netcount != 0) { - printk(KERN_WARNING "%s: sppp_open returning busy\n", info->netname); + printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; } @@ -4304,142 +4352,297 @@ spin_unlock_irqrestore(&info->netlock, flags); /* claim resources and init adapter */ - if ((err = startup(info)) != 0) - goto open_fail; - - /* allow syncppp module to do open processing */ - if ((err = sppp_open(d)) != 0) { - shutdown(info); - goto open_fail; + if ((rc = startup(info)) != 0) { + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + return rc; } + /* assert DTR and RTS, apply hardware settings */ info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; mgslpc_program_hw(info); - d->trans_start = jiffies; - netif_start_queue(d); - return 0; + /* enable network layer transmit */ + dev->trans_start = jiffies; + netif_start_queue(dev); -open_fail: - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return err; + /* inform generic HDLC layer of current DCD status */ + spin_lock_irqsave(&info->lock, flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock, flags); + hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); + + return 0; } -void mgslpc_sppp_tx_timeout(struct net_device *dev) +/** + * called by network layer when interface is disabled + * shutdown hardware and release resources + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_close(struct net_device *dev) { - MGSLPC_INFO *info = dev->priv; + MGSLPC_INFO *info = dev_to_port(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_tx_timeout(%s)\n",info->netname); + printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); - info->netstats.tx_errors++; - info->netstats.tx_aborted_errors++; + netif_stop_queue(dev); - spin_lock_irqsave(&info->lock,flags); - tx_stop(info); - spin_unlock_irqrestore(&info->lock,flags); + /* shutdown adapter and release resources */ + shutdown(info); - netif_wake_queue(dev); + hdlc_close(dev); + + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + + return 0; } -int mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *dev) +/** + * called by network layer to process IOCTL call to network device + * + * dev pointer to network device structure + * ifr pointer to network interface request structure + * cmd IOCTL command code + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - MGSLPC_INFO *info = dev->priv; - unsigned long flags; + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + MGSLPC_INFO *info = dev_to_port(dev); + unsigned int flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_tx(%s)\n",info->netname); + printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); - netif_stop_queue(dev); + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - info->tx_count = skb->len; + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); - memcpy(info->tx_buf, skb->data, skb->len); - info->tx_get = 0; - info->tx_put = info->tx_count = skb->len; + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: /* return current sync_serial_settings */ - info->netstats.tx_packets++; - info->netstats.tx_bytes += skb->len; - dev_kfree_skb(skb); + ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } - dev->trans_start = jiffies; + flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + + switch (flags){ + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; + case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; + default: new_line.clock_type = CLOCK_DEFAULT; + } - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); + new_line.clock_rate = info->params.clock_speed; + new_line.loopback = info->params.loopback ? 1:0; - return 0; + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + switch (new_line.clock_type) + { + case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; + case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; + case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; + case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; + case CLOCK_DEFAULT: flags = info->params.flags & + (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; + default: return -EINVAL; + } + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + info->params.flags |= flags; + + info->params.loopback = new_line.loopback; + + if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) + info->params.clock_speed = new_line.clock_rate; + else + info->params.clock_speed = 0; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + mgslpc_program_hw(info); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } } -int mgslpc_sppp_close(struct net_device *d) +/** + * called by network layer when transmit timeout is detected + * + * dev pointer to network device structure + */ +static void hdlcdev_tx_timeout(struct net_device *dev) { - MGSLPC_INFO *info = d->priv; + MGSLPC_INFO *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_close(%s)\n",info->netname); + printk("hdlcdev_tx_timeout(%s)\n",dev->name); - /* shutdown adapter and release resources */ - shutdown(info); + stats->tx_errors++; + stats->tx_aborted_errors++; - /* allow syncppp to do close processing */ - sppp_close(d); - netif_stop_queue(d); + spin_lock_irqsave(&info->lock,flags); + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return 0; + netif_wake_queue(dev); } -void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size) +/** + * called by device driver when transmit completes + * reenable network layer transmit if stopped + * + * info pointer to device instance information + */ +static void hdlcdev_tx_done(MGSLPC_INFO *info) +{ + if (netif_queue_stopped(info->netdev)) + netif_wake_queue(info->netdev); +} + +/** + * called by device driver when frame received + * pass frame to network layer + * + * info pointer to device instance information + * buf pointer to buffer contianing frame data + * size count of data bytes in buf + */ +static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); + struct net_device *dev = info->netdev; + struct net_device_stats *stats = hdlc_stats(dev); + if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_rx_done(%s)\n",info->netname); + printk("hdlcdev_rx(%s)\n",dev->name); + if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", - info->netname); - info->netstats.rx_dropped++; + printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); + stats->rx_dropped++; return; } memcpy(skb_put(skb, size),buf,size); - skb->protocol = htons(ETH_P_WAN_PPP); - skb->dev = info->netdev; - skb->mac.raw = skb->data; - info->netstats.rx_packets++; - info->netstats.rx_bytes += size; + skb->dev = info->netdev; + skb->mac.raw = skb->data; + skb->protocol = hdlc_type_trans(skb, skb->dev); + + stats->rx_packets++; + stats->rx_bytes += size; + netif_rx(skb); - info->netdev->trans_start = jiffies; -} -void mgslpc_sppp_tx_done(MGSLPC_INFO *info) -{ - if (netif_queue_stopped(info->netdev)) - netif_wake_queue(info->netdev); + info->netdev->last_rx = jiffies; } -struct net_device_stats *mgslpc_net_stats(struct net_device *dev) +/** + * called by device driver when adding device instance + * do generic HDLC initialization + * + * info pointer to device instance information + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_init(MGSLPC_INFO *info) { - MGSLPC_INFO *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_net_stats(%s)\n",info->netname); - return &info->netstats; + int rc; + struct net_device *dev; + hdlc_device *hdlc; + + /* allocate and initialize network and HDLC layer objects */ + + if (!(dev = alloc_hdlcdev(info))) { + printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); + return -ENOMEM; + } + + /* for network layer reporting purposes only */ + dev->base_addr = info->io_base; + dev->irq = info->irq_level; + + /* network layer callbacks and settings */ + dev->do_ioctl = hdlcdev_ioctl; + dev->open = hdlcdev_open; + dev->stop = hdlcdev_close; + dev->tx_timeout = hdlcdev_tx_timeout; + dev->watchdog_timeo = 10*HZ; + dev->tx_queue_len = 50; + + /* generic HDLC layer callbacks and settings */ + hdlc = dev_to_hdlc(dev); + hdlc->attach = hdlcdev_attach; + hdlc->xmit = hdlcdev_xmit; + + /* register objects with HDLC layer */ + if ((rc = register_hdlc_device(dev))) { + printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); + free_netdev(dev); + return rc; + } + + info->netdev = dev; + return 0; } -int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +/** + * called by device driver when removing device instance + * do generic HDLC cleanup + * + * info pointer to device instance information + */ +static void hdlcdev_exit(MGSLPC_INFO *info) { - MGSLPC_INFO *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, - info->netname, cmd ); - return sppp_do_ioctl(dev, ifr, cmd); + unregister_hdlc_device(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; } -#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */ +#endif /* CONFIG_HDLC */ + diff -Nru a/drivers/char/pcxx.c b/drivers/char/pcxx.c --- a/drivers/char/pcxx.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/pcxx.c 2004-10-18 14:56:33 -07:00 @@ -130,7 +130,6 @@ int pcxx_ncook=sizeof(pcxx_cook); int pcxx_nbios=sizeof(pcxx_bios); -#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define pcxxassert(x, msg) if(!(x)) pcxx_error(__LINE__, msg) #define FEPTIMEOUT 200000 @@ -206,7 +205,7 @@ { unsigned long flags; - int e1, e2; + int e1; printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION); @@ -223,12 +222,6 @@ restore_flags(flags); } -/* - * pcxe_init() is our init_module(): - */ -module_init(pcxe_init); -module_cleanup(pcxe_cleanup); - static inline struct channel *chan(register struct tty_struct *tty) { if (tty) { @@ -538,28 +531,11 @@ if(tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if(tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); shutdown(info); tty->closing = 0; info->event = 0; info->tty = NULL; -#ifndef MODULE -/* ldiscs[] is not available in a MODULE -** worth noting that while I'm not sure what this hunk of code is supposed -** to do, it is not present in the serial.c driver. Hmmm. If you know, -** please send me a note. brian@ilinx.com -** Don't know either what this is supposed to do christoph@lameter.com. -*/ - if(tty->ldisc.num != ldiscs[N_TTY].num) { - if(tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if(tty->ldisc.open) - (tty->ldisc.open)(tty); - } -#endif if(info->blocked_open) { if(info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -626,7 +602,7 @@ tail &= (size - 1); stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1); - count = MIN(stlen, count); + count = min(stlen, count); memoff(ch); restore_flags(flags); @@ -658,11 +634,11 @@ remain = tail - head - 1; stlen = remain; } - count = MIN(remain, count); + count = min(remain, count); txwinon(ch); while (count > 0) { - stlen = MIN(count, stlen); + stlen = min(count, stlen); memcpy(ch->txptr + head, buf, stlen); buf += stlen; count -= stlen; @@ -800,9 +776,7 @@ memoff(ch); restore_flags(flags); - wake_up_interruptible(&tty->write_wait); - if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } static void pcxe_flush_chars(struct tty_struct *tty) @@ -1013,9 +987,6 @@ } #endif -module_init(pcxe_init) -module_exit(pcxe_exit) - static struct tty_operations pcxe_ops = { .open = pcxe_open, .close = pcxe_close, @@ -1561,6 +1532,8 @@ return ret; } +module_init(pcxe_init) +module_exit(pcxe_cleanup) static void pcxxpoll(unsigned long dummy) { @@ -1675,10 +1648,7 @@ if (event & LOWTX_IND) { if (ch->statusflags & LOWWAIT) { ch->statusflags &= ~LOWWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -1686,10 +1656,7 @@ ch->statusflags &= ~TXBUSY; if (ch->statusflags & EMPTYWAIT) { ch->statusflags &= ~EMPTYWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } } @@ -1995,6 +1962,7 @@ volatile struct board_chan *bc; unsigned long flags; int mflag = 0; + int mstat; if(ch) bc = ch->brdchan; @@ -2069,6 +2037,7 @@ pcxxparam(tty,ch); memoff(ch); restore_flags(flags); + return 0; } @@ -2165,8 +2134,7 @@ tty_wait_until_sent(tty, 0); } else { - if(tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); } /* Fall Thru */ diff -Nru a/drivers/char/pty.c b/drivers/char/pty.c --- a/drivers/char/pty.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/pty.c 2004-10-18 14:56:28 -07:00 @@ -32,12 +32,6 @@ #include #include -#if defined(CONFIG_LEGACY_PTYS) || defined(CONFIG_UNIX98_PTYS) - -#ifdef CONFIG_LEGACY_PTYS -static struct tty_driver *pty_driver, *pty_slave_driver; -#endif - /* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS struct tty_driver *ptm_driver; @@ -91,10 +85,7 @@ if (!o_tty) return; - if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - o_tty->ldisc.write_wakeup) - (o_tty->ldisc.write_wakeup)(o_tty); - wake_up_interruptible(&o_tty->write_wait); + tty_wakeup(o_tty); set_bit(TTY_THROTTLED, &tty->flags); } @@ -107,6 +98,10 @@ * (2) avoid redundant copying for cases where count >> receive_room * N.B. Calls from user space may now return an error code instead of * a count. + * + * FIXME: Our pty_write method is called with our ldisc lock held but + * not our partners. We can't just take the other one blindly without + * risking deadlocks. There is also the small matter of TTY_DONT_FLIP */ static int pty_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) @@ -205,19 +200,6 @@ return ((count < N_TTY_BUF_SIZE/2) ? 0 : count); } -/* - * Return the device number of a Unix98 PTY (only!). This lets us open a - * master pty with the multi-headed ptmx device, then find out which - * one we got after it is open, with an ioctl. - */ -#ifdef CONFIG_UNIX98_PTYS -static int pty_get_device_number(struct tty_struct *tty, unsigned __user *value) -{ - unsigned int result = tty->index; - return put_user(result, value); -} -#endif - /* Set the lock flag on a pty */ static int pty_set_lock(struct tty_struct *tty, int __user * arg) { @@ -231,41 +213,6 @@ return 0; } -#ifdef CONFIG_LEGACY_PTYS -static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - if (!tty) { - printk("pty_ioctl called with NULL tty!\n"); - return -EIO; - } - switch(cmd) { - case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ - return pty_set_lock(tty, (int __user *) arg); - } - return -ENOIOCTLCMD; -} -#endif - -#ifdef CONFIG_UNIX98_PTYS -static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - if (!tty) { - printk("pty_unix98_ioctl called with NULL tty!\n"); - return -EIO; - } - switch(cmd) { - case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ - return pty_set_lock(tty, (int __user *)arg); - case TIOCGPTN: /* Get PT Number */ - return pty_get_device_number(tty, (unsigned int __user *)arg); - } - - return -ENOIOCTLCMD; -} -#endif - static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; @@ -322,42 +269,22 @@ .set_termios = pty_set_termios, }; -/* sysctl support for setting limits on the number of Unix98 ptys allocated. - Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */ -#ifdef CONFIG_UNIX98_PTYS -int pty_limit = NR_UNIX98_PTY_DEFAULT; -static int pty_limit_min = 0; -static int pty_limit_max = NR_UNIX98_PTY_MAX; +/* Traditional BSD devices */ +#ifdef CONFIG_LEGACY_PTYS +static struct tty_driver *pty_driver, *pty_slave_driver; -ctl_table pty_table[] = { - { - .ctl_name = PTY_MAX, - .procname = "max", - .maxlen = sizeof(int), - .mode = 0644, - .data = &pty_limit, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &pty_limit_min, - .extra2 = &pty_limit_max, - }, { - .ctl_name = PTY_NR, - .procname = "nr", - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = &proc_dointvec, - }, { - .ctl_name = 0 +static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ + return pty_set_lock(tty, (int __user *) arg); } -}; -#endif - -/* Initialization */ + return -ENOIOCTLCMD; +} -static int __init pty_init(void) +static void __init legacy_pty_init(void) { -#ifdef CONFIG_LEGACY_PTYS - /* Traditional BSD devices */ pty_driver = alloc_tty_driver(NR_PTYS); if (!pty_driver) @@ -404,11 +331,58 @@ panic("Couldn't register pty driver"); if (tty_register_driver(pty_slave_driver)) panic("Couldn't register pty slave driver"); +} +#else +static inline void legacy_pty_init(void) { } +#endif -#endif /* CONFIG_LEGACY_PTYS */ - +/* Unix98 devices */ #ifdef CONFIG_UNIX98_PTYS - /* Unix98 devices */ +/* + * sysctl support for setting limits on the number of Unix98 ptys allocated. + * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. + */ +int pty_limit = NR_UNIX98_PTY_DEFAULT; +static int pty_limit_min = 0; +static int pty_limit_max = NR_UNIX98_PTY_MAX; + +ctl_table pty_table[] = { + { + .ctl_name = PTY_MAX, + .procname = "max", + .maxlen = sizeof(int), + .mode = 0644, + .data = &pty_limit, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &pty_limit_min, + .extra2 = &pty_limit_max, + }, { + .ctl_name = PTY_NR, + .procname = "nr", + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, { + .ctl_name = 0 + } +}; + +static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ + return pty_set_lock(tty, (int __user *)arg); + case TIOCGPTN: /* Get PT Number */ + return put_user(tty->index, (unsigned int __user *)arg); + } + + return -ENOIOCTLCMD; +} + +static void __init unix98_pty_init(void) +{ devfs_mk_dir("pts"); ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); if (!ptm_driver) @@ -455,10 +429,15 @@ panic("Couldn't register Unix98 pts driver"); pty_table[1].data = &ptm_driver->refcount; -#endif /* CONFIG_UNIX98_PTYS */ +} +#else +static inline void unix98_pty_init(void) { } +#endif +static int __init pty_init(void) +{ + legacy_pty_init(); + unix98_pty_init(); return 0; } module_init(pty_init); - -#endif /* CONFIG_LEGACY_PTYS || CONFIG_UNIX98_PTYS */ diff -Nru a/drivers/char/random.c b/drivers/char/random.c --- a/drivers/char/random.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/random.c 2004-10-18 14:55:54 -07:00 @@ -401,6 +401,7 @@ */ static struct entropy_store *random_state; /* The default global store */ static struct entropy_store *sec_random_state; /* secondary store */ +static struct entropy_store *urandom_state; /* For urandom */ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); @@ -493,6 +494,7 @@ /* mostly-read data: */ struct poolinfo poolinfo; __u32 *pool; + const char *name; /* read-write data: */ spinlock_t lock ____cacheline_aligned_in_smp; @@ -507,7 +509,8 @@ * * Returns an negative error if there is a problem. */ -static int create_entropy_store(int size, struct entropy_store **ret_bucket) +static int create_entropy_store(int size, const char *name, + struct entropy_store **ret_bucket) { struct entropy_store *r; struct poolinfo *p; @@ -538,6 +541,7 @@ } memset(r->pool, 0, POOLBYTES); r->lock = SPIN_LOCK_UNLOCKED; + r->name = name; *ret_bucket = r; return 0; } @@ -643,12 +647,8 @@ } else { r->entropy_count += nbits; if (nbits) - DEBUG_ENT("%04d %04d : added %d bits to %s\n", - random_state->entropy_count, - sec_random_state->entropy_count, - nbits, - r == sec_random_state ? "secondary" : - r == random_state ? "primary" : "unknown"); + DEBUG_ENT("Added %d entropy credits to %s, now %d\n", + nbits, r->name, r->entropy_count); } spin_unlock_irqrestore(&r->lock, flags); @@ -781,9 +781,9 @@ /* There is one of these per entropy source */ struct timer_rand_state { - __u32 last_time; - __s32 last_delta,last_delta2; - int dont_count_entropy:1; + cycles_t last_time; + long last_delta,last_delta2; + unsigned dont_count_entropy:1; }; static struct timer_rand_state keyboard_timer_state; @@ -799,37 +799,31 @@ * The number "num" is also added to the pool - it should somehow describe * the type of event which just happened. This is currently 0-255 for * keyboard scan codes, and 256 upwards for interrupts. - * On the i386, this is assumed to be at most 16 bits, and the high bits - * are used for a high-resolution timer. * */ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) { - __u32 time; - __s32 delta, delta2, delta3; + cycles_t time; + long delta, delta2, delta3; int entropy = 0; + preempt_disable(); /* if over the trickle threshold, use only 1 in 4096 samples */ if ( random_state->entropy_count > trickle_thresh && (__get_cpu_var(trickle_count)++ & 0xfff)) - return; + goto out; -#if defined (__i386__) || defined (__x86_64__) - if (cpu_has_tsc) { - __u32 high; - rdtsc(time, high); - num ^= high; + /* + * Use get_cycles() if implemented, otherwise fall back to + * jiffies. + */ + time = get_cycles(); + if (time != 0) { + if (sizeof(time) > 4) + num ^= (u32)(time >> 32); } else { time = jiffies; } -#elif defined (__sparc_v9__) - unsigned long tick = tick_ops->get_tick(); - - time = (unsigned int) tick; - num ^= (tick >> 32UL); -#else - time = jiffies; -#endif /* * Calculate number of bits of randomness we probably added. @@ -868,6 +862,8 @@ entropy = int_ln_12bits(delta); } batch_entropy_store(num, time, entropy); +out: + preempt_enable(); } void add_keyboard_randomness(unsigned char scancode) @@ -1328,8 +1324,7 @@ "(%d of %d requested)\n", random_state->entropy_count, sec_random_state->entropy_count, - r == sec_random_state ? "secondary" : "unknown", - bytes * 8, nbytes * 8, r->entropy_count); + r->name, bytes * 8, nbytes * 8, r->entropy_count); bytes=extract_entropy(random_state, tmp, bytes, EXTRACT_ENTROPY_LIMIT); @@ -1373,9 +1368,7 @@ DEBUG_ENT("%04d %04d : trying to extract %d bits from %s\n", random_state->entropy_count, sec_random_state->entropy_count, - nbytes * 8, - r == sec_random_state ? "secondary" : - r == random_state ? "primary" : "unknown"); + nbytes * 8, r->name); if (flags & EXTRACT_ENTROPY_LIMIT && nbytes >= r->entropy_count / 8) nbytes = r->entropy_count / 8; @@ -1388,12 +1381,8 @@ if (r->entropy_count < random_write_wakeup_thresh) wake_up_interruptible(&random_write_wait); - DEBUG_ENT("%04d %04d : debiting %d bits from %s%s\n", - random_state->entropy_count, - sec_random_state->entropy_count, - nbytes * 8, - r == sec_random_state ? "secondary" : - r == random_state ? "primary" : "unknown", + DEBUG_ENT("Debiting %d entropy credits from %s%s\n", + nbytes * 8, r->name, flags & EXTRACT_ENTROPY_LIMIT ? "" : " (unlimited)"); spin_unlock_irqrestore(&r->lock, cpuflags); @@ -1482,14 +1471,21 @@ */ void get_random_bytes(void *buf, int nbytes) { - if (sec_random_state) - extract_entropy(sec_random_state, (char *) buf, nbytes, - EXTRACT_ENTROPY_SECONDARY); - else if (random_state) - extract_entropy(random_state, (char *) buf, nbytes, 0); - else + struct entropy_store *r = urandom_state; + int flags = EXTRACT_ENTROPY_SECONDARY; + + if (!r) + r = sec_random_state; + if (!r) { + r = random_state; + flags = 0; + } + if (!r) { printk(KERN_NOTICE "get_random_bytes called before " "random driver initialization\n"); + return; + } + extract_entropy(r, (char *) buf, nbytes, flags); } EXPORT_SYMBOL(get_random_bytes); @@ -1533,15 +1529,22 @@ { int i; - if (create_entropy_store(DEFAULT_POOL_SIZE, &random_state)) + if (create_entropy_store(DEFAULT_POOL_SIZE, "primary", &random_state)) goto err; if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state)) goto err; - if (create_entropy_store(SECONDARY_POOL_SIZE, &sec_random_state)) + if (create_entropy_store(SECONDARY_POOL_SIZE, "secondary", + &sec_random_state)) + goto err; + if (create_entropy_store(SECONDARY_POOL_SIZE, "urandom", + &urandom_state)) goto err; clear_entropy_store(random_state); clear_entropy_store(sec_random_state); + clear_entropy_store(urandom_state); init_std_data(random_state); + init_std_data(sec_random_state); + init_std_data(urandom_state); #ifdef CONFIG_SYSCTL sysctl_init_random(random_state); #endif @@ -1674,9 +1677,15 @@ urandom_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) { - return extract_entropy(sec_random_state, buf, nbytes, - EXTRACT_ENTROPY_USER | - EXTRACT_ENTROPY_SECONDARY); + int flags = EXTRACT_ENTROPY_USER; + unsigned long cpuflags; + + spin_lock_irqsave(&random_state->lock, cpuflags); + if (random_state->entropy_count > random_state->poolinfo.POOLBITS) + flags |= EXTRACT_ENTROPY_SECONDARY; + spin_unlock_irqrestore(&random_state->lock, cpuflags); + + return extract_entropy(urandom_state, buf, nbytes, flags); } static unsigned int @@ -1730,10 +1739,9 @@ random_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { - int *tmp, size, ent_count; + int size, ent_count; int __user *p = (int __user *)arg; int retval; - unsigned long flags; switch (cmd) { case RNDGETENTCNT: @@ -1754,40 +1762,6 @@ if (random_state->entropy_count >= random_read_wakeup_thresh) wake_up_interruptible(&random_read_wait); return 0; - case RNDGETPOOL: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(size, p) || - put_user(random_state->poolinfo.poolwords, p++)) - return -EFAULT; - if (size < 0) - return -EFAULT; - if (size > random_state->poolinfo.poolwords) - size = random_state->poolinfo.poolwords; - - /* prepare to atomically snapshot pool */ - - tmp = kmalloc(size * sizeof(__u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - - spin_lock_irqsave(&random_state->lock, flags); - ent_count = random_state->entropy_count; - memcpy(tmp, random_state->pool, size * sizeof(__u32)); - spin_unlock_irqrestore(&random_state->lock, flags); - - if (!copy_to_user(p, tmp, size * sizeof(__u32))) { - kfree(tmp); - return -EFAULT; - } - - kfree(tmp); - - if(put_user(ent_count, p++)) - return -EFAULT; - - return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1884,7 +1858,8 @@ struct entropy_store *new_store, *old_store; int ret; - if ((ret = create_entropy_store(poolsize, &new_store))) + if ((ret = create_entropy_store(poolsize, random_state->name, + &new_store))) return ret; add_entropy_words(new_store, random_state->pool, @@ -2212,7 +2187,7 @@ #undef K3 /* This should not be decreased so low that ISNs wrap too fast. */ -#define REKEY_INTERVAL 300 +#define REKEY_INTERVAL (300*HZ) /* * Bit layout of the tcp sequence numbers (before adding current time): * bit 24-31: increased after every key exchange @@ -2238,43 +2213,55 @@ #define HASH_MASK ( (1<rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { - keyptr = &ip_keydata[1^(ip_cnt&1)]; - keyptr->rekey_time = time; - get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); - keyptr->count = (ip_cnt&COUNT_MASK)<secret, sizeof(keyptr->secret)); + keyptr->count = (ip_cnt&COUNT_MASK)<rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { - keyptr = __check_and_rekey(time); - } + smp_rmb(); return keyptr; } +static __init int seqgen_init(void) +{ + rekey_seq_generator(NULL); + return 0; +} +late_initcall(seqgen_init); + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, __u16 sport, __u16 dport) @@ -2282,14 +2269,12 @@ struct timeval tv; __u32 seq; __u32 hash[12]; - struct keydata *keyptr; + struct keydata *keyptr = get_keyptr(); /* The procedure is the same as for IPv4, but addresses are longer. * Thus we must use twothirdsMD4Transform. */ - do_gettimeofday(&tv); /* We need the usecs below... */ - keyptr = check_and_rekey(tv.tv_sec); memcpy(hash, saddr, 16); hash[4]=(sport << 16) + dport; @@ -2297,38 +2282,22 @@ seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; seq += keyptr->count; + + do_gettimeofday(&tv); seq += tv.tv_usec + tv.tv_sec*1000000; return seq; } EXPORT_SYMBOL(secure_tcpv6_sequence_number); - -__u32 secure_ipv6_id(__u32 *daddr) -{ - struct keydata *keyptr; - - keyptr = check_and_rekey(get_seconds()); - - return halfMD4Transform(daddr, keyptr->secret); -} - -EXPORT_SYMBOL(secure_ipv6_id); #endif - __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { struct timeval tv; __u32 seq; __u32 hash[4]; - struct keydata *keyptr; - - /* - * Pick a random secret every REKEY_INTERVAL seconds. - */ - do_gettimeofday(&tv); /* We need the usecs below... */ - keyptr = check_and_rekey(tv.tv_sec); + struct keydata *keyptr = get_keyptr(); /* * Pick a unique starting offset for each TCP connection endpoints @@ -2351,6 +2320,7 @@ * That's funny, Linux has one built in! Use it! * (Networks are faster now - should this be increased?) */ + do_gettimeofday(&tv); seq += tv.tv_usec + tv.tv_sec*1000000; #if 0 printk("init_seq(%lx, %lx, %d, %d) = %d\n", @@ -2369,7 +2339,7 @@ struct keydata *keyptr; __u32 hash[4]; - keyptr = check_and_rekey(get_seconds()); + keyptr = get_keyptr(); /* * Pick a unique starting offset for each IP destination. diff -Nru a/drivers/char/rio/linux_compat.h b/drivers/char/rio/linux_compat.h --- a/drivers/char/rio/linux_compat.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/rio/linux_compat.h 2004-10-18 14:56:28 -07:00 @@ -16,7 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include #define disable(oldspl) save_flags (oldspl) diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c --- a/drivers/char/rio/rio_linux.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/rio/rio_linux.c 2004-10-18 14:56:33 -07:00 @@ -1138,8 +1138,8 @@ hp->Ivec = pdev->irq; if (((1 << hp->Ivec) & rio_irqmask) == 0) hp->Ivec = 0; - hp->CardP = (struct DpRam *) hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN); + hp->CardP = (struct DpRam *) hp->Caddr; hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; @@ -1196,8 +1196,8 @@ if (((1 << hp->Ivec) & rio_irqmask) == 0) hp->Ivec = 0; hp->Ivec |= 0x8000; /* Mark as non-sharable */ - hp->CardP = (struct DpRam *) hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN); + hp->CardP = (struct DpRam *) hp->Caddr; hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; @@ -1242,8 +1242,8 @@ hp->PaddrP = rio_probe_addrs[i]; /* There was something about the IRQs of these cards. 'Forget what.--REW */ hp->Ivec = 0; - hp->CardP = (struct DpRam *) hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN); + hp->CardP = (struct DpRam *) hp->Caddr; hp->Type = RIO_AT; hp->Copy = rio_pcicopy; /* AT card PCI???? - PVDL * -- YES! this is now a normal copy. Only the diff -Nru a/drivers/char/riscom8.c b/drivers/char/riscom8.c --- a/drivers/char/riscom8.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/riscom8.c 2004-10-18 14:56:29 -07:00 @@ -75,10 +75,6 @@ ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \ ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #define RS_EVENT_WRITE_WAKEUP 0 static struct riscom_board * IRQ_to_board[16]; @@ -107,7 +103,7 @@ }; static struct riscom_port rc_port[RC_NBOARD * RC_NPORT]; - + /* RISCom/8 I/O ports addresses (without address translation) */ static unsigned short rc_ioport[] = { #if 1 @@ -483,7 +479,7 @@ rc_out(bp, CD180_TDR, CD180_C_SBRK); port->COR2 &= ~COR2_ETC; } - count = MIN(port->break_length, 0xff); + count = min_t(int, port->break_length, 0xff); rc_out(bp, CD180_TDR, CD180_C_ESC); rc_out(bp, CD180_TDR, CD180_C_DELAY); rc_out(bp, CD180_TDR, count); @@ -1127,8 +1123,8 @@ rc_shutdown_port(bp, port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; port->event = 0; port->tty = NULL; @@ -1165,8 +1161,8 @@ down(&tmp_buf_sem); while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) break; @@ -1178,8 +1174,8 @@ } cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + c = min_t(int, c, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); port->xmit_cnt += c; @@ -1193,8 +1189,8 @@ } else { while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) { restore_flags(flags); break; @@ -1301,9 +1297,7 @@ restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } static int rc_tiocmget(struct tty_struct *tty, struct file *file) @@ -1644,9 +1638,7 @@ return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c --- a/drivers/char/rocket.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/rocket.c 2004-10-18 14:56:48 -07:00 @@ -250,12 +250,16 @@ CHANNEL_t * cp, unsigned int ChanStatus) { unsigned int CharNStat; - int ToRecv, wRecv, space, count; + int ToRecv, wRecv, space = 0, count; unsigned char *cbuf; char *fbuf; + struct tty_ldisc *ld; + + ld = tty_ldisc_ref(tty); ToRecv = sGetRxCnt(cp); - space = tty->ldisc.receive_room(tty); + if (ld) + space = ld->receive_room(tty); if (space > 2 * TTY_FLIPBUF_SIZE) space = 2 * TTY_FLIPBUF_SIZE; cbuf = tty->flip.char_buf; @@ -354,7 +358,8 @@ count += ToRecv; } /* Push the data up to the tty layer */ - tty->ldisc.receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); + ld->receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); + tty_ldisc_deref(ld); } /* @@ -389,7 +394,7 @@ while (1) { if (tty->stopped || tty->hw_stopped) break; - c = MIN(info->xmit_fifo_room, MIN(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail)); + c = min(info->xmit_fifo_room, min(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail)); if (c <= 0 || info->xmit_fifo_room <= 0) break; sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); @@ -408,8 +413,7 @@ clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); @@ -1022,7 +1026,7 @@ unsigned long flags; int timeout; CHANNEL_t *cp; - + if (rocket_paranoia_check(info, "rp_close")) return; @@ -1101,8 +1105,8 @@ if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty)) TTY_DRIVER_FLUSH_BUFFER(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); @@ -1283,11 +1287,7 @@ if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) return -EFAULT; -#ifdef CAP_SYS_ADMIN if (!capable(CAP_SYS_ADMIN)) -#else - if (!suser()) -#endif { if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) return -EPERM; @@ -1662,7 +1662,7 @@ * into FIFO. Use the write queue for temp storage. */ if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { - c = MIN(count, info->xmit_fifo_room); + c = min(count, info->xmit_fifo_room); b = buf; if (from_user) { if (copy_from_user(info->xmit_buf, buf, c)) { @@ -1672,7 +1672,7 @@ if (info->tty == 0) goto end; b = info->xmit_buf; - c = MIN(c, info->xmit_fifo_room); + c = min(c, info->xmit_fifo_room); } /* Push data into FIFO, 2 bytes at a time */ @@ -1700,7 +1700,7 @@ if (info->tty == 0) /* Seemingly obligatory check... */ goto end; - c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); + c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); if (c <= 0) break; @@ -1731,8 +1731,7 @@ end: if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); @@ -1806,8 +1805,7 @@ #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); #endif - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); cp = &info->channel; sFlushTxFIFO(cp); diff -Nru a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h --- a/drivers/char/rocket_int.h 2004-10-18 14:56:15 -07:00 +++ b/drivers/char/rocket_int.h 2004-10-18 14:56:15 -07:00 @@ -1241,10 +1241,6 @@ #define TTY_ROCKET_MAJOR 46 #define CUA_ROCKET_MAJOR 47 -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #ifdef PCI_VENDOR_ID_RP #undef PCI_VENDOR_ID_RP #undef PCI_DEVICE_ID_RP8OCTA diff -Nru a/drivers/char/selection.c b/drivers/char/selection.c --- a/drivers/char/selection.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/selection.c 2004-10-18 14:57:04 -07:00 @@ -26,10 +26,6 @@ #include #include -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* Don't take this from : 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') @@ -281,12 +277,15 @@ { struct vt_struct *vt = (struct vt_struct *) tty->driver_data; int pasted = 0, count; + struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); acquire_console_sem(); poke_blanked_console(); release_console_sem(); + ld = tty_ldisc_ref_wait(tty); + add_wait_queue(&vt->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); @@ -295,12 +294,14 @@ continue; } count = sel_buffer_lth - pasted; - count = MIN(count, tty->ldisc.receive_room(tty)); + count = min(count, tty->ldisc.receive_room(tty)); tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } remove_wait_queue(&vt->paste_wait, &wait); current->state = TASK_RUNNING; + + tty_ldisc_deref(ld); return 0; } diff -Nru a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c --- a/drivers/char/ser_a2232.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/char/ser_a2232.c 2004-10-18 14:56:27 -07:00 @@ -599,10 +599,7 @@ /* WakeUp if output buffer runs low */ if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup){ - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - } - wake_up_interruptible(&port->gs.tty->write_wait); + tty_wakeup(port->gs.tty); } } // if the port is used } // for every port on the board diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c --- a/drivers/char/serial167.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/serial167.c 2004-10-18 14:56:29 -07:00 @@ -83,10 +83,6 @@ #undef CYCLOM_16Y_HACK #define CYCLOM_ENABLE_MONITORING -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #define WAKEUP_CHARS 256 #define STD_COM_FLAGS (0) @@ -760,11 +756,7 @@ wake_up_interruptible(&info->open_wait); } if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } /* do_softint */ @@ -1238,8 +1230,8 @@ if (from_user) { down(&tmp_buf_sem); while (1) { - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; @@ -1251,8 +1243,8 @@ } local_irq_save(flags); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_cnt += c; @@ -1266,8 +1258,8 @@ } else { while (1) { local_irq_save(flags); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { local_irq_restore(flags); break; @@ -1343,10 +1335,7 @@ local_irq_save(flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; local_irq_restore(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* cy_flush_buffer */ @@ -1846,18 +1835,9 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); info->event = 0; info->tty = 0; - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -2379,7 +2359,7 @@ | CyPARITY| CyFRAME| CyOVERRUN; /* info->timeout */ - printk("ttyS%1d ", info->line); + printk("ttyS%d ", info->line); port_num++;info++; if(!(port_num & 7)){ printk("\n "); diff -Nru a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c --- a/drivers/char/serial_tx3912.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/char/serial_tx3912.c 2004-10-18 14:56:32 -07:00 @@ -191,12 +191,9 @@ } if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - port->gs.tty->ldisc.write_wakeup) - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + tty_wakeup(port->gs.tty); rs_dprintk (TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); - wake_up_interruptible(&port->gs.tty->write_wait); } } diff -Nru a/drivers/char/snsc.c b/drivers/char/snsc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/snsc.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,456 @@ +/* + * SN Platform system controller communication support + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * System controller communication driver + * + * This driver allows a user process to communicate with the system + * controller (a.k.a. "IRouter") network in an SGI SN system. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "snsc.h" + +#define SYSCTL_BASENAME "snsc" + +#define SCDRV_BUFSZ 2048 +#define SCDRV_TIMEOUT 1000 + +static irqreturn_t +scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs) +{ + struct subch_data_s *sd = subch_data; + unsigned long flags; + int status; + + spin_lock_irqsave(&sd->sd_rlock, flags); + spin_lock(&sd->sd_wlock); + status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); + + if (status > 0) { + if (status & SAL_IROUTER_INTR_RECV) { + wake_up(&sd->sd_rq); + } + if (status & SAL_IROUTER_INTR_XMIT) { + ia64_sn_irtr_intr_disable + (sd->sd_nasid, sd->sd_subch, + SAL_IROUTER_INTR_XMIT); + wake_up(&sd->sd_wq); + } + } + spin_unlock(&sd->sd_wlock); + spin_unlock_irqrestore(&sd->sd_rlock, flags); + return IRQ_HANDLED; +} + +/* + * scdrv_open + * + * Reserve a subchannel for system controller communication. + */ + +static int +scdrv_open(struct inode *inode, struct file *file) +{ + struct sysctl_data_s *scd; + struct subch_data_s *sd; + int rv; + + /* look up device info for this device file */ + scd = container_of(inode->i_cdev, struct sysctl_data_s, scd_cdev); + + /* allocate memory for subchannel data */ + sd = kmalloc(sizeof (struct subch_data_s), GFP_KERNEL); + if (sd == NULL) { + printk("%s: couldn't allocate subchannel data\n", + __FUNCTION__); + return -ENOMEM; + } + + /* initialize subch_data_s fields */ + memset(sd, 0, sizeof (struct subch_data_s)); + sd->sd_nasid = scd->scd_nasid; + sd->sd_subch = ia64_sn_irtr_open(scd->scd_nasid); + + if (sd->sd_subch < 0) { + kfree(sd); + printk("%s: couldn't allocate subchannel\n", __FUNCTION__); + return -EBUSY; + } + + spin_lock_init(&sd->sd_rlock); + spin_lock_init(&sd->sd_wlock); + init_waitqueue_head(&sd->sd_rq); + init_waitqueue_head(&sd->sd_wq); + sema_init(&sd->sd_rbs, 1); + sema_init(&sd->sd_wbs, 1); + + file->private_data = sd; + + /* hook this subchannel up to the system controller interrupt */ + rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, + SA_SHIRQ | SA_INTERRUPT, + SYSCTL_BASENAME, sd); + if (rv) { + ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); + kfree(sd); + printk("%s: irq request failed (%d)\n", __FUNCTION__, rv); + return -EBUSY; + } + + return 0; +} + +/* + * scdrv_release + * + * Release a previously-reserved subchannel. + */ + +static int +scdrv_release(struct inode *inode, struct file *file) +{ + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + int rv; + + /* free the interrupt */ + free_irq(SGI_UART_VECTOR, sd); + + /* ask SAL to close the subchannel */ + rv = ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); + + kfree(sd); + return rv; +} + +/* + * scdrv_read + * + * Called to read bytes from the open IRouter pipe. + * + */ + +static inline int +read_status_check(struct subch_data_s *sd, int *len) +{ + return ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, sd->sd_rb, len); +} + +static ssize_t +scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) +{ + int status; + int len; + unsigned long flags; + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + + /* try to get control of the read buffer */ + if (down_trylock(&sd->sd_rbs)) { + /* somebody else has it now; + * if we're non-blocking, then exit... + */ + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + /* ...or if we want to block, then do so here */ + if (down_interruptible(&sd->sd_rbs)) { + /* something went wrong with wait */ + return -ERESTARTSYS; + } + } + + /* anything to read? */ + len = CHUNKSIZE; + spin_lock_irqsave(&sd->sd_rlock, flags); + status = read_status_check(sd, &len); + + /* if not, and we're blocking I/O, loop */ + while (status < 0) { + DECLARE_WAITQUEUE(wait, current); + + if (file->f_flags & O_NONBLOCK) { + spin_unlock_irqrestore(&sd->sd_rlock, flags); + up(&sd->sd_rbs); + return -EAGAIN; + } + + len = CHUNKSIZE; + add_wait_queue(&sd->sd_rq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&sd->sd_rlock, flags); + + schedule_timeout(SCDRV_TIMEOUT); + + remove_wait_queue(&sd->sd_rq, &wait); + if (signal_pending(current)) { + /* wait was interrupted */ + up(&sd->sd_rbs); + return -ERESTARTSYS; + } + + spin_lock_irqsave(&sd->sd_rlock, flags); + status = read_status_check(sd, &len); + } + spin_unlock_irqrestore(&sd->sd_rlock, flags); + + if (len > 0) { + /* we read something in the last read_status_check(); copy + * it out to user space + */ + if (count < len) { + pr_debug("%s: only accepting %d of %d bytes\n", + __FUNCTION__, (int) count, len); + } + len = min((int) count, len); + if (copy_to_user(buf, sd->sd_rb, len)) + len = -EFAULT; + } + + /* release the read buffer and wake anyone who might be + * waiting for it + */ + up(&sd->sd_rbs); + + /* return the number of characters read in */ + return len; +} + +/* + * scdrv_write + * + * Writes a chunk of an IRouter packet (or other system controller data) + * to the system controller. + * + */ +static inline int +write_status_check(struct subch_data_s *sd, int count) +{ + return ia64_sn_irtr_send(sd->sd_nasid, sd->sd_subch, sd->sd_wb, count); +} + +static ssize_t +scdrv_write(struct file *file, const char __user *buf, + size_t count, loff_t *f_pos) +{ + unsigned long flags; + int status; + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + + /* try to get control of the write buffer */ + if (down_trylock(&sd->sd_wbs)) { + /* somebody else has it now; + * if we're non-blocking, then exit... + */ + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + /* ...or if we want to block, then do so here */ + if (down_interruptible(&sd->sd_wbs)) { + /* something went wrong with wait */ + return -ERESTARTSYS; + } + } + + count = min((int) count, CHUNKSIZE); + if (copy_from_user(sd->sd_wb, buf, count)) { + up(&sd->sd_wbs); + return -EFAULT; + } + + /* try to send the buffer */ + spin_lock_irqsave(&sd->sd_wlock, flags); + status = write_status_check(sd, count); + + /* if we failed, and we want to block, then loop */ + while (status <= 0) { + DECLARE_WAITQUEUE(wait, current); + + if (file->f_flags & O_NONBLOCK) { + spin_unlock(&sd->sd_wlock); + up(&sd->sd_wbs); + return -EAGAIN; + } + + add_wait_queue(&sd->sd_wq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&sd->sd_wlock, flags); + + schedule_timeout(SCDRV_TIMEOUT); + + remove_wait_queue(&sd->sd_wq, &wait); + if (signal_pending(current)) { + /* wait was interrupted */ + up(&sd->sd_wbs); + return -ERESTARTSYS; + } + + spin_lock_irqsave(&sd->sd_wlock, flags); + status = write_status_check(sd, count); + } + spin_unlock_irqrestore(&sd->sd_wlock, flags); + + /* release the write buffer and wake anyone who's waiting for it */ + up(&sd->sd_wbs); + + /* return the number of characters accepted (should be the complete + * "chunk" as requested) + */ + if ((status >= 0) && (status < count)) { + pr_debug("Didn't accept the full chunk; %d of %d\n", + status, (int) count); + } + return status; +} + +static unsigned int +scdrv_poll(struct file *file, struct poll_table_struct *wait) +{ + unsigned int mask = 0; + int status = 0; + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + unsigned long flags; + + poll_wait(file, &sd->sd_rq, wait); + poll_wait(file, &sd->sd_wq, wait); + + spin_lock_irqsave(&sd->sd_rlock, flags); + spin_lock(&sd->sd_wlock); + status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); + spin_unlock(&sd->sd_wlock); + spin_unlock_irqrestore(&sd->sd_rlock, flags); + + if (status > 0) { + if (status & SAL_IROUTER_INTR_RECV) { + mask |= POLLIN | POLLRDNORM; + } + if (status & SAL_IROUTER_INTR_XMIT) { + mask |= POLLOUT | POLLWRNORM; + } + } + + return mask; +} + +static struct file_operations scdrv_fops = { + .owner = THIS_MODULE, + .read = scdrv_read, + .write = scdrv_write, + .poll = scdrv_poll, + .open = scdrv_open, + .release = scdrv_release, +}; + +/* + * scdrv_init + * + * Called at boot time to initialize the system controller communication + * facility. + */ +int __init +scdrv_init(void) +{ + geoid_t geoid; + cmoduleid_t cmod; + int i; + char devname[32]; + char *devnamep; + module_t *m; + struct sysctl_data_s *scd; + void *salbuf; + struct class_simple *snsc_class; + dev_t first_dev, dev; + + if (alloc_chrdev_region(&first_dev, 0, (MAX_SLABS*nummodules), + SYSCTL_BASENAME) < 0) { + printk("%s: failed to register SN system controller device\n", + __FUNCTION__); + return -ENODEV; + } + snsc_class = class_simple_create(THIS_MODULE, SYSCTL_BASENAME); + + for (cmod = 0; cmod < nummodules; cmod++) { + m = sn_modules[cmod]; + for (i = 0; i <= MAX_SLABS; i++) { + + if (m->nodes[i] == -1) { + /* node is not alive in module */ + continue; + } + + geoid = m->geoid[i]; + devnamep = devname; + format_module_id(devnamep, geo_module(geoid), + MODULE_FORMAT_BRIEF); + devnamep = devname + strlen(devname); + sprintf(devnamep, "#%d", geo_slab(geoid)); + + /* allocate sysctl device data */ + scd = kmalloc(sizeof (struct sysctl_data_s), + GFP_KERNEL); + if (!scd) { + printk("%s: failed to allocate device info" + "for %s/%s\n", __FUNCTION__, + SYSCTL_BASENAME, devname); + continue; + } + memset(scd, 0, sizeof (struct sysctl_data_s)); + + /* initialize sysctl device data fields */ + scd->scd_nasid = cnodeid_to_nasid(m->nodes[i]); + if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) { + printk("%s: failed to allocate driver buffer" + "(%s%s)\n", __FUNCTION__, + SYSCTL_BASENAME, devname); + kfree(scd); + continue; + } + + if (ia64_sn_irtr_init(scd->scd_nasid, salbuf, + SCDRV_BUFSZ) < 0) { + printk + ("%s: failed to initialize SAL for" + " system controller communication" + " (%s/%s): outdated PROM?\n", + __FUNCTION__, SYSCTL_BASENAME, devname); + kfree(scd); + kfree(salbuf); + continue; + } + + dev = first_dev + m->nodes[i]; + cdev_init(&scd->scd_cdev, &scdrv_fops); + if (cdev_add(&scd->scd_cdev, dev, 1)) { + printk("%s: failed to register system" + " controller device (%s%s)\n", + __FUNCTION__, SYSCTL_BASENAME, devname); + kfree(scd); + kfree(salbuf); + continue; + } + + class_simple_device_add(snsc_class, dev, NULL, + "%s", devname); + + ia64_sn_irtr_intr_enable(scd->scd_nasid, + 0 /*ignored */ , + SAL_IROUTER_INTR_RECV); + } + } + return 0; +} + +module_init(scdrv_init); diff -Nru a/drivers/char/snsc.h b/drivers/char/snsc.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/snsc.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,50 @@ +/* + * SN Platform system controller communication support + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * This file contains macros and data types for communication with the + * system controllers in SGI SN systems. + */ + +#ifndef _SN_SYSCTL_H_ +#define _SN_SYSCTL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHUNKSIZE 127 + +/* This structure is used to track an open subchannel. */ +struct subch_data_s { + nasid_t sd_nasid; /* node on which the subchannel was opened */ + int sd_subch; /* subchannel number */ + spinlock_t sd_rlock; /* monitor lock for rsv */ + spinlock_t sd_wlock; /* monitor lock for wsv */ + wait_queue_head_t sd_rq; /* wait queue for readers */ + wait_queue_head_t sd_wq; /* wait queue for writers */ + struct semaphore sd_rbs; /* semaphore for read buffer */ + struct semaphore sd_wbs; /* semaphore for write buffer */ + + char sd_rb[CHUNKSIZE]; /* read buffer */ + char sd_wb[CHUNKSIZE]; /* write buffer */ +}; + +struct sysctl_data_s { + struct cdev scd_cdev; /* Character device info */ + nasid_t scd_nasid; /* Node on which subchannels are opened. */ +}; + +#endif /* _SN_SYSCTL_H_ */ diff -Nru a/drivers/char/sonypi.c b/drivers/char/sonypi.c --- a/drivers/char/sonypi.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/sonypi.c 2004-10-18 14:56:48 -07:00 @@ -50,12 +50,13 @@ #include #include +static int verbose; /* = 0 */ + #include "sonypi.h" #include static struct sonypi_device sonypi_device; static int minor = -1; -static int verbose; /* = 0 */ static int fnkeyinit; /* = 0 */ static int camera; /* = 0 */ static int compat; /* = 0 */ @@ -66,7 +67,7 @@ static inline void sonypi_initq(void) { sonypi_device.queue.head = sonypi_device.queue.tail = 0; sonypi_device.queue.len = 0; - sonypi_device.queue.s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED; + sonypi_device.queue.s_lock = SPIN_LOCK_UNLOCKED; init_waitqueue_head(&sonypi_device.queue.proc_list); } diff -Nru a/drivers/char/sonypi.h b/drivers/char/sonypi.h --- a/drivers/char/sonypi.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/sonypi.h 2004-10-18 14:56:33 -07:00 @@ -401,8 +401,6 @@ #define SONYPI_ACPI_ACTIVE 0 #endif /* CONFIG_ACPI */ -extern int verbose; - static inline int sonypi_ec_write(u8 addr, u8 value) { #ifdef CONFIG_ACPI_EC if (SONYPI_ACPI_ACTIVE) diff -Nru a/drivers/char/specialix.c b/drivers/char/specialix.c --- a/drivers/char/specialix.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/specialix.c 2004-10-18 14:57:03 -07:00 @@ -135,10 +135,6 @@ ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \ ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #undef RS_EVENT_WRITE_WAKEUP #define RS_EVENT_WRITE_WAKEUP 0 @@ -159,7 +155,7 @@ }; static struct specialix_port sx_port[SX_NBOARD * SX_NPORT]; - + #ifdef SPECIALIX_TIMER static struct timer_list missed_irq_timer; @@ -715,7 +711,7 @@ sx_out(bp, CD186x_TDR, CD186x_C_SBRK); port->COR2 &= ~COR2_ETC; } - count = MIN(port->break_length, 0xff); + count = min_t(int, port->break_length, 0xff); sx_out(bp, CD186x_TDR, CD186x_C_ESC); sx_out(bp, CD186x_TDR, CD186x_C_DELAY); sx_out(bp, CD186x_TDR, count); @@ -1468,8 +1464,7 @@ sx_shutdown_port(bp, port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; port->event = 0; port->tty = NULL; @@ -1506,7 +1501,7 @@ if (from_user) { down(&tmp_buf_sem); while (1) { - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) break; @@ -1519,7 +1514,7 @@ } cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + c = min_t(int, c, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); @@ -1534,7 +1529,7 @@ } else { while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) { restore_flags(flags); @@ -1646,10 +1641,8 @@ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; restore_flags(flags); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); } @@ -2052,12 +2045,8 @@ if(!(tty = port->tty)) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) + tty_wakeup(tty); } static struct tty_operations sx_ops = { diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c --- a/drivers/char/stallion.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/char/stallion.c 2004-10-18 14:56:49 -07:00 @@ -1197,8 +1197,7 @@ portp->tx.tail = (char *) NULL; } set_bit(TTY_IO_ERROR, &tty->flags); - if (tty->ldisc.flush_buffer) - (tty->ldisc.flush_buffer)(tty); + tty_ldisc_flush(tty); tty->closing = 0; portp->tty = (struct tty_struct *) NULL; @@ -1809,10 +1808,7 @@ return; stl_flush(portp); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /*****************************************************************************/ @@ -2193,10 +2189,7 @@ lock_kernel(); if (test_bit(ASYI_TXLOW, &portp->istate)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { clear_bit(ASYI_DCDCHANGE, &portp->istate); diff -Nru a/drivers/char/sx.c b/drivers/char/sx.c --- a/drivers/char/sx.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/sx.c 2004-10-18 14:56:29 -07:00 @@ -1046,12 +1046,9 @@ } if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - port->gs.tty->ldisc.write_wakeup) - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + tty_wakeup(port->gs.tty); sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); - wake_up_interruptible(&port->gs.tty->write_wait); } clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks); diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/char/synclink.c 2004-10-18 14:56:28 -07:00 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.24 2004/06/03 14:50:09 paulkf Exp $ + * $Id: synclink.c,v 4.28 2004/08/11 19:30:01 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -100,13 +100,10 @@ #include #include #include +#include -#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE -#define CONFIG_SYNCLINK_SYNCPPP 1 -#endif - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#include +#ifdef CONFIG_HDLC_MODULE +#define CONFIG_HDLC 1 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -187,7 +184,6 @@ */ struct mgsl_struct { - void *if_ptr; /* General purpose pointer (used by SPPP) */ int magic; int flags; int count; /* count of opens */ @@ -318,15 +314,13 @@ struct _input_signal_events input_signal_events; - /* SPPP/Cisco HDLC device parts */ + /* generic HDLC device parts */ int netcount; int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_SYNCLINK_SYNCPPP - struct ppp_device pppdev; - char netname[10]; + +#ifdef CONFIG_HDLC struct net_device *netdev; - struct net_device_stats netstats; #endif }; @@ -734,18 +728,12 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_SYNCLINK_SYNCPPP -/* SPPP/HDLC stuff */ -static void mgsl_sppp_init(struct mgsl_struct *info); -static void mgsl_sppp_delete(struct mgsl_struct *info); -int mgsl_sppp_open(struct net_device *d); -int mgsl_sppp_close(struct net_device *d); -void mgsl_sppp_tx_timeout(struct net_device *d); -int mgsl_sppp_tx(struct sk_buff *skb, struct net_device *d); -void mgsl_sppp_rx_done(struct mgsl_struct *info, char *buf, int size); -void mgsl_sppp_tx_done(struct mgsl_struct *info); -int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -struct net_device_stats *mgsl_net_stats(struct net_device *dev); +#ifdef CONFIG_HDLC +#define dev_to_port(D) (dev_to_hdlc(D)->priv) +static void hdlcdev_tx_done(struct mgsl_struct *info); +static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size); +static int hdlcdev_init(struct mgsl_struct *info); +static void hdlcdev_exit(struct mgsl_struct *info); #endif /* @@ -863,8 +851,6 @@ static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask); static int mgsl_loopmode_send_done( struct mgsl_struct * info ); -#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) - /* set non-zero on successful registration with PCI subsystem */ static int pci_registered; @@ -911,7 +897,7 @@ MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.24 $"; +static char *driver_version = "$Revision: 4.28 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -942,10 +928,6 @@ static void mgsl_change_params(struct mgsl_struct *info); static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * 1st function defined in .text section. Calling this function in * init_module() followed by a breakpoint allows a remote debugger @@ -993,6 +975,29 @@ return 0; } +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_receive_buf - pass receive data to line discipline + */ + +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + /* mgsl_stop() throttle (stop) transmitter * * Arguments: tty pointer to tty info structure @@ -1153,13 +1158,7 @@ __FILE__,__LINE__,info->device_name); if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):calling ldisc.write_wakeup on %s\n", - __FILE__,__LINE__,info->device_name); - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -1289,9 +1288,9 @@ info->drop_rts_on_tx_done = 0; } -#ifdef CONFIG_SYNCLINK_SYNCPPP +#ifdef CONFIG_HDLC if (info->netcount) - mgsl_sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif { @@ -1352,12 +1351,12 @@ icount->dcd++; if (status & MISCSTATUS_DCD) { info->input_signal_events.dcd_up++; -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) - sppp_reopen(info->netdev); -#endif } else info->input_signal_events.dcd_down++; +#ifdef CONFIG_HDLC + if (info->netcount) + hdlc_set_carrier(status & MISCSTATUS_DCD, info->netdev); +#endif } if (status & MISCSTATUS_CTS_LATCHED) { @@ -2258,8 +2257,8 @@ if (from_user) { down(&tmp_buf_sem); while (1) { - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, + min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; @@ -2272,7 +2271,7 @@ break; } spin_lock_irqsave(&info->irq_spinlock,flags); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); info->xmit_head = ((info->xmit_head + c) & @@ -2287,8 +2286,8 @@ } else { while (1) { spin_lock_irqsave(&info->irq_spinlock,flags); - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, + min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -2415,11 +2414,8 @@ spin_unlock_irqrestore(&info->irq_spinlock,flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - -} /* end of mgsl_flush_buffer() */ + tty_wakeup(tty); +} /* mgsl_send_xchar() * @@ -3253,9 +3249,8 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); shutdown(info); @@ -3326,7 +3321,7 @@ char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); if ( info->params.mode == MGSL_MODE_HDLC || info->params.mode == MGSL_MODE_RAW ) { @@ -3592,7 +3587,7 @@ cleanup: if (retval) { if (tty->count == 1) - info->tty = NULL;/* tty layer will release tty struct */ + info->tty = NULL; /* tty layer will release tty struct */ if(info->count) info->count--; } @@ -4187,7 +4182,7 @@ info->get_tx_holding_index=0; /* restart transmit timer */ - mod_timer(&info->tx_timer, jiffies + jiffies_from_ms(5000)); + mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); ret = 1; } @@ -4415,12 +4410,10 @@ info->max_frame_size ); } -#ifdef CONFIG_SYNCLINK_SYNCPPP -#ifdef MODULE - if (info->dosyncppp) -#endif - mgsl_sppp_init(info); +#ifdef CONFIG_HDLC + hdlcdev_init(info); #endif + } /* end of mgsl_add_device() */ /* mgsl_allocate_device() @@ -4575,9 +4568,8 @@ info = mgsl_device_list; while(info) { -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->dosyncppp) - mgsl_sppp_delete(info); +#ifdef CONFIG_HDLC + hdlcdev_exit(info); #endif mgsl_release_resources(info); tmp = info; @@ -5819,7 +5811,7 @@ usc_TCmd( info, TCmd_SendFrame ); - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } info->tx_active = 1; @@ -6750,9 +6742,12 @@ return_frame = 1; } framesize = 0; -#ifdef CONFIG_SYNCLINK_SYNCPPP - info->netstats.rx_errors++; - info->netstats.rx_frame_errors++; +#ifdef CONFIG_HDLC + { + struct net_device_stats *stats = hdlc_stats(info->netdev); + stats->rx_errors++; + stats->rx_frame_errors++; + } #endif } else return_frame = 1; @@ -6779,7 +6774,7 @@ if ( debug_level >= DEBUG_LEVEL_DATA ) mgsl_trace_block(info,info->rx_buffer_list[StartIndex].virt_addr, - MIN(framesize,DMABUFFERSIZE),0); + min_t(int, framesize, DMABUFFERSIZE),0); if (framesize) { if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) && @@ -6823,18 +6818,12 @@ *ptmp); } -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) { - /* pass frame to syncppp device */ - mgsl_sppp_rx_done(info,info->intermediate_rxbuffer,framesize); - } +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_rx(info,info->intermediate_rxbuffer,framesize); else #endif - { - /* Call the line discipline receive callback directly. */ - if ( tty && tty->ldisc.receive_buf ) - tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); - } + ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); } } /* Free the buffers used by this frame. */ @@ -6996,7 +6985,7 @@ if ( debug_level >= DEBUG_LEVEL_DATA ) mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr, - MIN(framesize,DMABUFFERSIZE),0); + min_t(int, framesize, DMABUFFERSIZE),0); if (framesize) { /* copy dma buffer(s) to contiguous intermediate buffer */ @@ -7006,9 +6995,7 @@ memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); info->icount.rxok++; - /* Call the line discipline receive callback directly. */ - if ( tty && tty->ldisc.receive_buf ) - tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); + ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); } /* Free the buffers used by this frame. */ @@ -7056,7 +7043,7 @@ DMABUFFERENTRY *pBufEntry; if ( debug_level >= DEBUG_LEVEL_DATA ) - mgsl_trace_block(info,Buffer, MIN(BufferSize,DMABUFFERSIZE), 1); + mgsl_trace_block(info,Buffer, min_t(int, BufferSize, DMABUFFERSIZE), 1); if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { /* set CMR:13 to start transmit when @@ -7214,7 +7201,7 @@ EndTime=100; while( EndTime-- && !info->irq_occurred ) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); } spin_lock_irqsave(&info->irq_spinlock,flags); @@ -7353,7 +7340,7 @@ /*************************************************************/ /* Wait 100ms for interrupt. */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); for(;;) { if (time_after(jiffies, EndTime)) { @@ -7409,7 +7396,7 @@ /**********************************/ /* Wait 100ms */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); for(;;) { if (time_after(jiffies, EndTime)) { @@ -7451,7 +7438,7 @@ /******************************/ /* Wait 100ms */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); /* While timer not expired wait for transmit complete */ @@ -7482,7 +7469,7 @@ /* WAIT FOR RECEIVE COMPLETE */ /* Wait 100ms */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); /* Wait for 16C32 to write receive status to buffer entry. */ status=info->rx_buffer_list[0].status; @@ -7736,9 +7723,9 @@ spin_unlock_irqrestore(&info->irq_spinlock,flags); -#ifdef CONFIG_SYNCLINK_SYNCPPP +#ifdef CONFIG_HDLC if (info->netcount) - mgsl_sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif mgsl_bh_transmit(info); @@ -7819,79 +7806,125 @@ return usc_InReg( info, CCSR ) & BIT6 ? 1 : 0 ; } -#ifdef CONFIG_SYNCLINK_SYNCPPP -/* syncppp net device routines +#ifdef CONFIG_HDLC + +/** + * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * set encoding and frame check sequence (FCS) options + * + * dev pointer to network device structure + * encoding serial encoding setting + * parity FCS setting + * + * returns 0 if success, otherwise error code */ -static void mgsl_setup(struct net_device *dev) +static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) { - dev->open = mgsl_sppp_open; - dev->stop = mgsl_sppp_close; - dev->hard_start_xmit = mgsl_sppp_tx; - dev->do_ioctl = mgsl_sppp_ioctl; - dev->get_stats = mgsl_net_stats; - dev->tx_timeout = mgsl_sppp_tx_timeout; - dev->watchdog_timeo = 10*HZ; -} + struct mgsl_struct *info = dev_to_port(dev); + unsigned char new_encoding; + unsigned short new_crctype; -static void mgsl_sppp_init(struct mgsl_struct *info) -{ - struct net_device *d; + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - sprintf(info->netname,"mgsl%d",info->line); + switch (encoding) + { + case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; + case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; + case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; + case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; + case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; + default: return -EINVAL; + } - d = alloc_netdev(0, info->netname, mgsl_setup); - if (!d) { - printk(KERN_WARNING "%s: alloc_netdev failed.\n", - info->netname); - return; + switch (parity) + { + case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; + case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; + case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; + default: return -EINVAL; } - info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = d; + info->params.encoding = new_encoding; + info->params.crc_type = new_crctype;; - d->base_addr = info->io_base; - d->irq = info->irq_level; - d->dma = info->dma_level; - d->priv = info; - - sppp_attach(&info->pppdev); - mgsl_setup(d); - - if (register_netdev(d)) { - printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(info->netdev); - info->netdev = NULL; - free_netdev(d); - return; - } + /* if network interface up, reprogram hardware */ + if (info->netcount) + mgsl_program_hw(info); - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_sppp_init()\n"); + return 0; } -void mgsl_sppp_delete(struct mgsl_struct *info) +/** + * called by generic HDLC layer to send frame + * + * skb socket buffer containing HDLC frame + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { + struct mgsl_struct *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_sppp_delete(%s)\n",info->netname); - unregister_netdev(info->netdev); - sppp_detach(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; - info->pppdev.dev = NULL; + printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); + + /* stop sending until this frame completes */ + netif_stop_queue(dev); + + /* copy data to device buffers */ + info->xmit_cnt = skb->len; + mgsl_load_tx_dma_buffer(info, skb->data, skb->len); + + /* update network statistics */ + stats->tx_packets++; + stats->tx_bytes += skb->len; + + /* done with socket buffer, so free it */ + dev_kfree_skb(skb); + + /* save start time for transmit timeout detection */ + dev->trans_start = jiffies; + + /* start hardware transmitter if necessary */ + spin_lock_irqsave(&info->irq_spinlock,flags); + if (!info->tx_active) + usc_start_transmitter(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + return 0; } -int mgsl_sppp_open(struct net_device *d) +/** + * called by network layer when interface enabled + * claim resources and initialize hardware + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_open(struct net_device *dev) { - struct mgsl_struct *info = d->priv; - int err; + struct mgsl_struct *info = dev_to_port(dev); + int rc; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_sppp_open(%s)\n",info->netname); + printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); + /* generic HDLC layer open processing */ + if ((rc = hdlc_open(dev))) + return rc; + + /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); if (info->count != 0 || info->netcount != 0) { - printk(KERN_WARNING "%s: sppp_open returning busy\n", info->netname); + printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; } @@ -7899,141 +7932,301 @@ spin_unlock_irqrestore(&info->netlock, flags); /* claim resources and init adapter */ - if ((err = startup(info)) != 0) - goto open_fail; - - /* allow syncppp module to do open processing */ - if ((err = sppp_open(d)) != 0) { - shutdown(info); - goto open_fail; + if ((rc = startup(info)) != 0) { + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + return rc; } + /* assert DTR and RTS, apply hardware settings */ info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; mgsl_program_hw(info); - d->trans_start = jiffies; - netif_start_queue(d); - return 0; + /* enable network layer transmit */ + dev->trans_start = jiffies; + netif_start_queue(dev); -open_fail: - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return err; + /* inform generic HDLC layer of current DCD status */ + spin_lock_irqsave(&info->irq_spinlock, flags); + usc_get_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock, flags); + hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); + + return 0; } -void mgsl_sppp_tx_timeout(struct net_device *dev) +/** + * called by network layer when interface is disabled + * shutdown hardware and release resources + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_close(struct net_device *dev) { - struct mgsl_struct *info = dev->priv; + struct mgsl_struct *info = dev_to_port(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_sppp_tx_timeout(%s)\n",info->netname); + printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); - info->netstats.tx_errors++; - info->netstats.tx_aborted_errors++; + netif_stop_queue(dev); - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_stop_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); + /* shutdown adapter and release resources */ + shutdown(info); - netif_wake_queue(dev); + hdlc_close(dev); + + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + + return 0; } -int mgsl_sppp_tx(struct sk_buff *skb, struct net_device *dev) +/** + * called by network layer to process IOCTL call to network device + * + * dev pointer to network device structure + * ifr pointer to network interface request structure + * cmd IOCTL command code + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct mgsl_struct *info = dev->priv; - unsigned long flags; + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + struct mgsl_struct *info = dev_to_port(dev); + unsigned int flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_sppp_tx(%s)\n",info->netname); + printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); - netif_stop_queue(dev); + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - info->xmit_cnt = skb->len; - mgsl_load_tx_dma_buffer(info, skb->data, skb->len); - info->netstats.tx_packets++; - info->netstats.tx_bytes += skb->len; - dev_kfree_skb(skb); + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); - dev->trans_start = jiffies; + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: /* return current sync_serial_settings */ - spin_lock_irqsave(&info->irq_spinlock,flags); - if (!info->tx_active) - usc_start_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); + ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } - return 0; + flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + + switch (flags){ + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; + case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; + default: new_line.clock_type = CLOCK_DEFAULT; + } + + new_line.clock_rate = info->params.clock_speed; + new_line.loopback = info->params.loopback ? 1:0; + + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + switch (new_line.clock_type) + { + case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; + case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; + case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; + case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; + case CLOCK_DEFAULT: flags = info->params.flags & + (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; + default: return -EINVAL; + } + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + info->params.flags |= flags; + + info->params.loopback = new_line.loopback; + + if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) + info->params.clock_speed = new_line.clock_rate; + else + info->params.clock_speed = 0; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + mgsl_program_hw(info); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } } -int mgsl_sppp_close(struct net_device *d) +/** + * called by network layer when transmit timeout is detected + * + * dev pointer to network device structure + */ +static void hdlcdev_tx_timeout(struct net_device *dev) { - struct mgsl_struct *info = d->priv; + struct mgsl_struct *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_sppp_close(%s)\n",info->netname); + printk("hdlcdev_tx_timeout(%s)\n",dev->name); - /* shutdown adapter and release resources */ - shutdown(info); + stats->tx_errors++; + stats->tx_aborted_errors++; - /* allow syncppp to do close processing */ - sppp_close(d); - netif_stop_queue(d); + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_stop_transmitter(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return 0; + netif_wake_queue(dev); } -void mgsl_sppp_rx_done(struct mgsl_struct *info, char *buf, int size) +/** + * called by device driver when transmit completes + * reenable network layer transmit if stopped + * + * info pointer to device instance information + */ +static void hdlcdev_tx_done(struct mgsl_struct *info) +{ + if (netif_queue_stopped(info->netdev)) + netif_wake_queue(info->netdev); +} + +/** + * called by device driver when frame received + * pass frame to network layer + * + * info pointer to device instance information + * buf pointer to buffer contianing frame data + * size count of data bytes in buf + */ +static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); + struct net_device *dev = info->netdev; + struct net_device_stats *stats = hdlc_stats(dev); + if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_sppp_rx_done(%s)\n",info->netname); + printk("hdlcdev_rx(%s)\n",dev->name); + if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", - info->netname); - info->netstats.rx_dropped++; + printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); + stats->rx_dropped++; return; } memcpy(skb_put(skb, size),buf,size); - skb->protocol = htons(ETH_P_WAN_PPP); - skb->dev = info->netdev; - skb->mac.raw = skb->data; - info->netstats.rx_packets++; - info->netstats.rx_bytes += size; + skb->dev = info->netdev; + skb->mac.raw = skb->data; + skb->protocol = hdlc_type_trans(skb, skb->dev); + + stats->rx_packets++; + stats->rx_bytes += size; + netif_rx(skb); - info->netdev->trans_start = jiffies; -} -void mgsl_sppp_tx_done(struct mgsl_struct *info) -{ - if (netif_queue_stopped(info->netdev)) - netif_wake_queue(info->netdev); + info->netdev->last_rx = jiffies; } -struct net_device_stats *mgsl_net_stats(struct net_device *dev) +/** + * called by device driver when adding device instance + * do generic HDLC initialization + * + * info pointer to device instance information + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_init(struct mgsl_struct *info) { - struct mgsl_struct *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgsl_net_stats(%s)\n",info->netname); - return &info->netstats; + int rc; + struct net_device *dev; + hdlc_device *hdlc; + + /* allocate and initialize network and HDLC layer objects */ + + if (!(dev = alloc_hdlcdev(info))) { + printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); + return -ENOMEM; + } + + /* for network layer reporting purposes only */ + dev->base_addr = info->io_base; + dev->irq = info->irq_level; + dev->dma = info->dma_level; + + /* network layer callbacks and settings */ + dev->do_ioctl = hdlcdev_ioctl; + dev->open = hdlcdev_open; + dev->stop = hdlcdev_close; + dev->tx_timeout = hdlcdev_tx_timeout; + dev->watchdog_timeo = 10*HZ; + dev->tx_queue_len = 50; + + /* generic HDLC layer callbacks and settings */ + hdlc = dev_to_hdlc(dev); + hdlc->attach = hdlcdev_attach; + hdlc->xmit = hdlcdev_xmit; + + /* register objects with HDLC layer */ + if ((rc = register_hdlc_device(dev))) { + printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); + free_netdev(dev); + return rc; + } + + info->netdev = dev; + return 0; } -int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +/** + * called by device driver when removing device instance + * do generic HDLC cleanup + * + * info pointer to device instance information + */ +static void hdlcdev_exit(struct mgsl_struct *info) { - struct mgsl_struct *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__, - info->netname, cmd ); - return sppp_do_ioctl(dev, ifr, cmd); + unregister_hdlc_device(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; } -#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */ +#endif /* CONFIG_HDLC */ + static int __devinit synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent) diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c --- a/drivers/char/synclinkmp.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/synclinkmp.c 2004-10-18 14:56:17 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 4.22 2004/06/03 14:50:10 paulkf Exp $ + * $Id: synclinkmp.c,v 4.29 2004/08/27 20:06:41 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -67,13 +67,10 @@ #include #include #include +#include -#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE -#define CONFIG_SYNCLINK_SYNCPPP 1 -#endif - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#include +#ifdef CONFIG_HDLC_MODULE +#define CONFIG_HDLC 1 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -284,12 +281,11 @@ int netcount; int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_SYNCLINK_SYNCPPP - struct ppp_device pppdev; - char netname[10]; + +#ifdef CONFIG_HDLC struct net_device *netdev; - struct net_device_stats netstats; #endif + } SLMP_INFO; #define MGSL_MAGIC 0x5401 @@ -361,12 +357,7 @@ #define TMCS 0x64 #define TEPR 0x65 -/* - * FIXME: DAR here clashed with asm-ppc/reg.h and asm-sh/.../dma.h - */ -#undef DAR /* DMA Controller Register macros */ -#define DAR 0x80 #define DARL 0x80 #define DARH 0x81 #define DARB 0x82 @@ -462,8 +453,6 @@ #define CRCE BIT2 -#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) - /* * Global linked list of SyncLink devices */ @@ -498,7 +487,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.22 $"; +static char *driver_version = "$Revision: 4.29 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -524,10 +513,6 @@ /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* tty callbacks */ @@ -553,20 +538,12 @@ static void unthrottle(struct tty_struct * tty); static void set_break(struct tty_struct *tty, int break_state); -/* sppp support and callbacks */ - -#ifdef CONFIG_SYNCLINK_SYNCPPP -static void sppp_init(SLMP_INFO *info); -static void sppp_delete(SLMP_INFO *info); -static void sppp_rx_done(SLMP_INFO *info, char *buf, int size); -static void sppp_tx_done(SLMP_INFO *info); - -static int sppp_cb_open(struct net_device *d); -static int sppp_cb_close(struct net_device *d); -static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev); -static void sppp_cb_tx_timeout(struct net_device *dev); -static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev); +#ifdef CONFIG_HDLC +#define dev_to_port(D) (dev_to_hdlc(D)->priv) +static void hdlcdev_tx_done(SLMP_INFO *info); +static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size); +static int hdlcdev_init(SLMP_INFO *info); +static void hdlcdev_exit(SLMP_INFO *info); #endif /* ioctl handlers */ @@ -668,7 +645,7 @@ static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes static u32 misc_ctrl_value = 0x007e4040; -static u32 lcr1_brdr_value = 0x0080002d; +static u32 lcr1_brdr_value = 0x00800029; static u32 read_ahead_count = 8; @@ -722,6 +699,29 @@ return 0; } +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_receive_buf - pass receive data to line discipline + */ + +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + /* tty callbacks */ /* Called when a port is opened. Init and enable port. @@ -800,7 +800,7 @@ cleanup: if (retval) { if (tty->count == 1) - info->tty = NULL;/* tty layer will release tty struct */ + info->tty = NULL; /* tty layer will release tty struct */ if(info->count) info->count--; } @@ -869,8 +869,7 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); shutdown(info); @@ -1017,8 +1016,8 @@ } for (;;) { - c = MIN(count, - MIN(info->max_frame_size - info->tx_count - 1, + c = min_t(int, count, + min(info->max_frame_size - info->tx_count - 1, info->max_frame_size - info->tx_put)); if (c <= 0) break; @@ -1161,7 +1160,7 @@ char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); if ( info->params.mode == MGSL_MODE_HDLC ) { while (info->tx_active) { @@ -1275,9 +1274,7 @@ spin_unlock_irqrestore(&info->lock,flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* throttle (stop) transmitter @@ -1627,79 +1624,125 @@ spin_unlock_irqrestore(&info->lock,flags); } -#ifdef CONFIG_SYNCLINK_SYNCPPP - -/* syncppp support and callbacks */ - -static void cb_setup(struct net_device *dev) -{ - dev->open = sppp_cb_open; - dev->stop = sppp_cb_close; - dev->hard_start_xmit = sppp_cb_tx; - dev->do_ioctl = sppp_cb_ioctl; - dev->get_stats = sppp_cb_net_stats; - dev->tx_timeout = sppp_cb_tx_timeout; - dev->watchdog_timeo = 10*HZ; -} +#ifdef CONFIG_HDLC -static void sppp_init(SLMP_INFO *info) +/** + * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * set encoding and frame check sequence (FCS) options + * + * dev pointer to network device structure + * encoding serial encoding setting + * parity FCS setting + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) { - struct net_device *d; + SLMP_INFO *info = dev_to_port(dev); + unsigned char new_encoding; + unsigned short new_crctype; - sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num); + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - d = alloc_netdev(0, info->netname, cb_setup); - if (!d) { - printk(KERN_WARNING "%s: alloc_netdev failed.\n", - info->netname); - return; + switch (encoding) + { + case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; + case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; + case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; + case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; + case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; + default: return -EINVAL; } - info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = d; - - d->irq = info->irq_level; - d->priv = info; + switch (parity) + { + case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; + case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; + case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; + default: return -EINVAL; + } - sppp_attach(&info->pppdev); - cb_setup(d); + info->params.encoding = new_encoding; + info->params.crc_type = new_crctype;; - if (register_netdev(d)) { - printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(info->netdev); - info->netdev = NULL; - info->pppdev.dev = NULL; - free_netdev(d); - return; - } + /* if network interface up, reprogram hardware */ + if (info->netcount) + program_hw(info); - if (debug_level >= DEBUG_LEVEL_INFO) - printk("sppp_init(%s)\n",info->netname); + return 0; } -static void sppp_delete(SLMP_INFO *info) +/** + * called by generic HDLC layer to send frame + * + * skb socket buffer containing HDLC frame + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { + SLMP_INFO *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + if (debug_level >= DEBUG_LEVEL_INFO) - printk("sppp_delete(%s)\n",info->netname); - unregister_netdev(info->netdev); - sppp_detach(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; - info->pppdev.dev = NULL; + printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); + + /* stop sending until this frame completes */ + netif_stop_queue(dev); + + /* copy data to device buffers */ + info->tx_count = skb->len; + tx_load_dma_buffer(info, skb->data, skb->len); + + /* update network statistics */ + stats->tx_packets++; + stats->tx_bytes += skb->len; + + /* done with socket buffer, so free it */ + dev_kfree_skb(skb); + + /* save start time for transmit timeout detection */ + dev->trans_start = jiffies; + + /* start hardware transmitter if necessary */ + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + + return 0; } -static int sppp_cb_open(struct net_device *d) +/** + * called by network layer when interface enabled + * claim resources and initialize hardware + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_open(struct net_device *dev) { - SLMP_INFO *info = d->priv; - int err; + SLMP_INFO *info = dev_to_port(dev); + int rc; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("sppp_cb_open(%s)\n",info->netname); + printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); + /* generic HDLC layer open processing */ + if ((rc = hdlc_open(dev))) + return rc; + + /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); if (info->count != 0 || info->netcount != 0) { - printk(KERN_WARNING "%s: sppp_cb_open returning busy\n", info->netname); + printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; } @@ -1707,141 +1750,300 @@ spin_unlock_irqrestore(&info->netlock, flags); /* claim resources and init adapter */ - if ((err = startup(info)) != 0) - goto open_fail; - - /* allow syncppp module to do open processing */ - if ((err = sppp_open(d)) != 0) { - shutdown(info); - goto open_fail; + if ((rc = startup(info)) != 0) { + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + return rc; } + /* assert DTR and RTS, apply hardware settings */ info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; program_hw(info); - d->trans_start = jiffies; - netif_start_queue(d); - return 0; + /* enable network layer transmit */ + dev->trans_start = jiffies; + netif_start_queue(dev); -open_fail: - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return err; + /* inform generic HDLC layer of current DCD status */ + spin_lock_irqsave(&info->lock, flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock, flags); + hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); + + return 0; } -static void sppp_cb_tx_timeout(struct net_device *dev) +/** + * called by network layer when interface is disabled + * shutdown hardware and release resources + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_close(struct net_device *dev) { - SLMP_INFO *info = dev->priv; + SLMP_INFO *info = dev_to_port(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("sppp_tx_timeout(%s)\n",info->netname); + printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); - info->netstats.tx_errors++; - info->netstats.tx_aborted_errors++; + netif_stop_queue(dev); - spin_lock_irqsave(&info->lock,flags); - tx_stop(info); - spin_unlock_irqrestore(&info->lock,flags); + /* shutdown adapter and release resources */ + shutdown(info); - netif_wake_queue(dev); + hdlc_close(dev); + + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + + return 0; } -static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev) +/** + * called by network layer to process IOCTL call to network device + * + * dev pointer to network device structure + * ifr pointer to network interface request structure + * cmd IOCTL command code + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - SLMP_INFO *info = dev->priv; - unsigned long flags; + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + SLMP_INFO *info = dev_to_port(dev); + unsigned int flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("sppp_tx(%s)\n",info->netname); + printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); - netif_stop_queue(dev); + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - info->tx_count = skb->len; - tx_load_dma_buffer(info, skb->data, skb->len); - info->netstats.tx_packets++; - info->netstats.tx_bytes += skb->len; - dev_kfree_skb(skb); + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); - dev->trans_start = jiffies; + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: /* return current sync_serial_settings */ - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); + ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } - return 0; + flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + + switch (flags){ + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; + case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; + default: new_line.clock_type = CLOCK_DEFAULT; + } + + new_line.clock_rate = info->params.clock_speed; + new_line.loopback = info->params.loopback ? 1:0; + + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + switch (new_line.clock_type) + { + case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; + case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; + case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; + case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; + case CLOCK_DEFAULT: flags = info->params.flags & + (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; + default: return -EINVAL; + } + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + info->params.flags |= flags; + + info->params.loopback = new_line.loopback; + + if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) + info->params.clock_speed = new_line.clock_rate; + else + info->params.clock_speed = 0; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + program_hw(info); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } } -static int sppp_cb_close(struct net_device *d) +/** + * called by network layer when transmit timeout is detected + * + * dev pointer to network device structure + */ +static void hdlcdev_tx_timeout(struct net_device *dev) { - SLMP_INFO *info = d->priv; + SLMP_INFO *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("sppp_cb_close(%s)\n",info->netname); + printk("hdlcdev_tx_timeout(%s)\n",dev->name); - /* shutdown adapter and release resources */ - shutdown(info); + stats->tx_errors++; + stats->tx_aborted_errors++; - /* allow syncppp to do close processing */ - sppp_close(d); - netif_stop_queue(d); + spin_lock_irqsave(&info->lock,flags); + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return 0; + netif_wake_queue(dev); } -static void sppp_rx_done(SLMP_INFO *info, char *buf, int size) +/** + * called by device driver when transmit completes + * reenable network layer transmit if stopped + * + * info pointer to device instance information + */ +static void hdlcdev_tx_done(SLMP_INFO *info) +{ + if (netif_queue_stopped(info->netdev)) + netif_wake_queue(info->netdev); +} + +/** + * called by device driver when frame received + * pass frame to network layer + * + * info pointer to device instance information + * buf pointer to buffer contianing frame data + * size count of data bytes in buf + */ +static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); + struct net_device *dev = info->netdev; + struct net_device_stats *stats = hdlc_stats(dev); + if (debug_level >= DEBUG_LEVEL_INFO) - printk("sppp_rx_done(%s)\n",info->netname); + printk("hdlcdev_rx(%s)\n",dev->name); + if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", - info->netname); - info->netstats.rx_dropped++; + printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); + stats->rx_dropped++; return; } memcpy(skb_put(skb, size),buf,size); - skb->protocol = htons(ETH_P_WAN_PPP); - skb->dev = info->netdev; - skb->mac.raw = skb->data; - info->netstats.rx_packets++; - info->netstats.rx_bytes += size; + skb->dev = info->netdev; + skb->mac.raw = skb->data; + skb->protocol = hdlc_type_trans(skb, skb->dev); + + stats->rx_packets++; + stats->rx_bytes += size; + netif_rx(skb); - info->netdev->trans_start = jiffies; -} -static void sppp_tx_done(SLMP_INFO *info) -{ - if (netif_queue_stopped(info->netdev)) - netif_wake_queue(info->netdev); + info->netdev->last_rx = jiffies; } -static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev) +/** + * called by device driver when adding device instance + * do generic HDLC initialization + * + * info pointer to device instance information + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_init(SLMP_INFO *info) { - SLMP_INFO *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("net_stats(%s)\n",info->netname); - return &info->netstats; + int rc; + struct net_device *dev; + hdlc_device *hdlc; + + /* allocate and initialize network and HDLC layer objects */ + + if (!(dev = alloc_hdlcdev(info))) { + printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); + return -ENOMEM; + } + + /* for network layer reporting purposes only */ + dev->mem_start = info->phys_sca_base; + dev->mem_end = info->phys_sca_base + SCA_BASE_SIZE - 1; + dev->irq = info->irq_level; + + /* network layer callbacks and settings */ + dev->do_ioctl = hdlcdev_ioctl; + dev->open = hdlcdev_open; + dev->stop = hdlcdev_close; + dev->tx_timeout = hdlcdev_tx_timeout; + dev->watchdog_timeo = 10*HZ; + dev->tx_queue_len = 50; + + /* generic HDLC layer callbacks and settings */ + hdlc = dev_to_hdlc(dev); + hdlc->attach = hdlcdev_attach; + hdlc->xmit = hdlcdev_xmit; + + /* register objects with HDLC layer */ + if ((rc = register_hdlc_device(dev))) { + printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); + free_netdev(dev); + return rc; + } + + info->netdev = dev; + return 0; } -static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +/** + * called by device driver when removing device instance + * do generic HDLC cleanup + * + * info pointer to device instance information + */ +static void hdlcdev_exit(SLMP_INFO *info) { - SLMP_INFO *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):ioctl %s cmd=%08X\n", __FILE__,__LINE__, - info->netname, cmd ); - return sppp_do_ioctl(dev, ifr, cmd); + unregister_hdlc_device(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; } -#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */ +#endif /* CONFIG_HDLC */ /* Return next bottom half action to perform. @@ -1941,13 +2143,7 @@ __FILE__,__LINE__,info->device_name); if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s calling ldisc.write_wakeup\n", - __FILE__,__LINE__,info->device_name); - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } @@ -1994,16 +2190,15 @@ { struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; - unsigned char status = read_reg(info, SR1); - unsigned char status2 = read_reg(info, SR2); + unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD); + unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN; /* clear status bits */ - if ( status & (FLGD + IDLD + CDCD + BRKD) ) - write_reg(info, SR1, - (unsigned char)(status & (FLGD + IDLD + CDCD + BRKD))); + if (status) + write_reg(info, SR1, status); - if ( status2 & OVRN ) - write_reg(info, SR2, (unsigned char)(status2 & OVRN)); + if (status2) + write_reg(info, SR2, status2); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_rxint status=%02X %02x\n", @@ -2140,15 +2335,22 @@ printk("%s(%d):%s isr_txeom status=%02x\n", __FILE__,__LINE__,info->device_name,status); - /* disable and clear MSCI interrupts */ - info->ie1_value &= ~(IDLE + UDRN); - write_reg(info, IE1, info->ie1_value); - write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); - write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + if (status & UDRN) { + write_reg(info, CMD, TXRESET); + write_reg(info, CMD, TXENABLE); + } else + write_reg(info, CMD, TXBUFCLR); + + /* disable and clear tx interrupts */ + info->ie0_value &= ~TXRDYE; + info->ie1_value &= ~(IDLE + UDRN); + write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); + write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); + if ( info->tx_active ) { if (info->params.mode != MGSL_MODE_ASYNC) { if (status & UDRN) @@ -2168,9 +2370,9 @@ set_signals(info); } -#ifdef CONFIG_SYNCLINK_SYNCPPP +#ifdef CONFIG_HDLC if (info->netcount) - sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif { @@ -2189,10 +2391,10 @@ */ void isr_txint(SLMP_INFO * info) { - unsigned char status = read_reg(info, SR1); + unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); /* clear status bits */ - write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS))); + write_reg(info, SR1, status); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txint status=%02x\n", @@ -2221,6 +2423,14 @@ printk("%s(%d):%s isr_txrdy() tx_count=%d\n", __FILE__,__LINE__,info->device_name,info->tx_count); + if (info->params.mode != MGSL_MODE_ASYNC) { + /* disable TXRDY IRQ, enable IDLE IRQ */ + info->ie0_value &= ~TXRDYE; + info->ie1_value |= IDLE; + write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); + return; + } + if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { tx_stop(info); return; @@ -2275,13 +2485,6 @@ void isr_txdmaok(SLMP_INFO * info) { - /* BIT7 = EOT (end of transfer, used for async mode) - * BIT6 = EOM (end of message/frame, used for sync mode) - * - * We don't look at DMA status because only EOT is enabled - * and we always clear and disable all tx DMA IRQs. - */ -// unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0; unsigned char status_reg1 = read_reg(info, SR1); write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ @@ -2292,19 +2495,10 @@ printk("%s(%d):%s isr_txdmaok(), status=%02x\n", __FILE__,__LINE__,info->device_name,status_reg1); - /* If transmitter already idle, do end of frame processing, - * otherwise enable interrupt for tx IDLE. - */ - if (status_reg1 & IDLE) - isr_txeom(info, IDLE); - else { - /* disable and clear underrun IRQ, enable IDLE interrupt */ - info->ie1_value |= IDLE; - info->ie1_value &= ~UDRN; - write_reg(info, IE1, info->ie1_value); - - write_reg(info, SR1, UDRN); - } + /* program TXRDY as FIFO empty flag, enable TXRDY IRQ */ + write_reg16(info, TRC0, 0); + info->ie0_value |= TXRDYE; + write_reg(info, IE0, info->ie0_value); } void isr_txdmaerror(SLMP_INFO * info) @@ -2358,12 +2552,12 @@ icount->dcd++; if (status & SerialSignal_DCD) { info->input_signal_events.dcd_up++; -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) - sppp_reopen(info->netdev); -#endif } else info->input_signal_events.dcd_down++; +#ifdef CONFIG_HDLC + if (info->netcount) + hdlc_set_carrier(status & SerialSignal_DCD, info->netdev); +#endif } if (status & MISCSTATUS_CTS_LATCHED) { @@ -2577,7 +2771,7 @@ change_params(info); - info->status_timer.expires = jiffies + jiffies_from_ms(10); + info->status_timer.expires = jiffies + msecs_to_jiffies(10); add_timer(&info->status_timer); if (info->tty) @@ -2988,7 +3182,7 @@ unsigned char oldval = info->ie1_value; unsigned char newval = oldval + (mask & MgslEvent_ExitHuntMode ? FLGD:0) + - (mask & MgslEvent_IdleReceived ? IDLE:0); + (mask & MgslEvent_IdleReceived ? IDLD:0); if ( oldval != newval ) { info->ie1_value = newval; write_reg(info, IE1, info->ie1_value); @@ -3055,7 +3249,7 @@ spin_lock_irqsave(&info->lock,flags); if (!waitqueue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ - info->ie1_value &= ~(FLGD|IDLE); + info->ie1_value &= ~(FLGD|IDLD); write_reg(info, IE1, info->ie1_value); } spin_unlock_irqrestore(&info->lock,flags); @@ -3449,9 +3643,10 @@ int claim_resources(SLMP_INFO *info) { - if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else @@ -3460,22 +3655,25 @@ if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else info->lcr_mem_requested = 1; - if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else info->sca_base_requested = 1; - if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else @@ -3485,33 +3683,41 @@ if (!info->memory_base) { printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } - if ( !memory_test(info) ) { - printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base ); - goto errout; - } - - info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset; + info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE); if (!info->lcr_base) { printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } + info->lcr_base += info->lcr_offset; - info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset; + info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE); if (!info->sca_base) { printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } + info->sca_base += info->sca_offset; - info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset; + info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE); if (!info->statctrl_base) { printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); + info->init_error = DiagStatus_CantAssignPciResources; + goto errout; + } + info->statctrl_base += info->statctrl_offset; + + if ( !memory_test(info) ) { + printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + info->init_error = DiagStatus_MemoryError; goto errout; } @@ -3534,7 +3740,7 @@ } if ( info->shared_mem_requested ) { - release_mem_region(info->phys_memory_base,0x40000); + release_mem_region(info->phys_memory_base,SCA_MEM_SIZE); info->shared_mem_requested = 0; } if ( info->lcr_mem_requested ) { @@ -3542,11 +3748,11 @@ info->lcr_mem_requested = 0; } if ( info->sca_base_requested ) { - release_mem_region(info->phys_sca_base + info->sca_offset,512); + release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE); info->sca_base_requested = 0; } if ( info->sca_statctrl_requested ) { - release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16); + release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE); info->sca_statctrl_requested = 0; } @@ -3616,9 +3822,8 @@ info->irq_level, info->max_frame_size ); -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->dosyncppp) - sppp_init(info); +#ifdef CONFIG_HDLC + hdlcdev_init(info); #endif } @@ -3788,7 +3993,6 @@ static void synclinkmp_cleanup(void) { - unsigned long flags; int rc; SLMP_INFO *info; SLMP_INFO *tmp; @@ -3802,34 +4006,24 @@ put_tty_driver(serial_driver); } + /* reset devices */ info = synclinkmp_device_list; while(info) { -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->dosyncppp) - sppp_delete(info); -#endif reset_port(info); - if ( info->port_num == 0 ) { - if ( info->irq_requested ) { - free_irq(info->irq_level, info); - info->irq_requested = 0; - } - } info = info->next_device; } - /* port 0 of each adapter originally claimed - * all resources, release those now - */ + /* release devices */ info = synclinkmp_device_list; while(info) { +#ifdef CONFIG_HDLC + hdlcdev_exit(info); +#endif free_dma_bufs(info); free_tmp_rx_buf(info); if ( info->port_num == 0 ) { - spin_lock_irqsave(&info->lock,flags); - reset_adapter(info); - write_reg(info, LPR, 1); /* set low power mode */ - spin_unlock_irqrestore(&info->lock,flags); + if (info->sca_base) + write_reg(info, LPR, 1); /* set low power mode */ release_resources(info); } tmp = info; @@ -4112,6 +4306,9 @@ } } + write_reg16(info, TRC0, + (unsigned short)(((tx_negate_fifo_level-1)<<8) + tx_active_fifo_level)); + write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ @@ -4123,17 +4320,16 @@ write_reg16(info, TXDMA + EDA, info->tx_buf_list_ex[info->last_tx_buf].phys_entry); - /* clear IDLE and UDRN status bit */ - info->ie1_value &= ~(IDLE + UDRN); - if (info->params.mode != MGSL_MODE_ASYNC) - info->ie1_value |= UDRN; /* HDLC, IRQ on underrun */ - write_reg(info, IE1, info->ie1_value); /* enable MSCI interrupts */ + /* enable underrun IRQ */ + info->ie1_value &= ~IDLE; + info->ie1_value |= UDRN; + write_reg(info, IE1, info->ie1_value); write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ write_reg(info, TXDMA + DSR, 0xf2); /* clear Tx DMA IRQs, enable Tx DMA */ - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } else { @@ -4823,10 +5019,12 @@ info->icount.rxcrc++; framesize = 0; - -#ifdef CONFIG_SYNCLINK_SYNCPPP - info->netstats.rx_errors++; - info->netstats.rx_frame_errors++; +#ifdef CONFIG_HDLC + { + struct net_device_stats *stats = hdlc_stats(info->netdev); + stats->rx_errors++; + stats->rx_frame_errors++; + } #endif } @@ -4836,7 +5034,7 @@ if ( debug_level >= DEBUG_LEVEL_DATA ) trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr, - MIN(framesize,SCABUFSIZE),0); + min_t(int, framesize,SCABUFSIZE),0); if (framesize) { if (framesize > info->max_frame_size) @@ -4851,7 +5049,7 @@ info->icount.rxok++; while(copy_count) { - int partial_count = MIN(copy_count,SCABUFSIZE); + int partial_count = min(copy_count,SCABUFSIZE); memcpy( ptmp, info->rx_buf_list_ex[index].virt_addr, partial_count ); @@ -4862,22 +5060,13 @@ index = 0; } -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) { - /* pass frame to syncppp device */ - sppp_rx_done(info,info->tmp_rx_buf,framesize); - } +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_rx(info,info->tmp_rx_buf,framesize); else #endif - { - if ( tty && tty->ldisc.receive_buf ) { - /* Call the line discipline receive callback directly. */ - tty->ldisc.receive_buf(tty, - info->tmp_rx_buf, - info->flag_buf, - framesize); - } - } + ldisc_receive_buf(tty,info->tmp_rx_buf, + info->flag_buf, framesize); } } /* Free the buffers used by this frame. */ @@ -4910,14 +5099,14 @@ SCADESC_EX *desc_ex; if ( debug_level >= DEBUG_LEVEL_DATA ) - trace_block(info,buf, MIN(count,SCABUFSIZE), 1); + trace_block(info,buf, min_t(int, count,SCABUFSIZE), 1); /* Copy source buffer to one or more DMA buffers, starting with * the first transmit dma buffer. */ for(i=0;;) { - copy_count = MIN(count,SCABUFSIZE); + copy_count = min_t(unsigned short,count,SCABUFSIZE); desc = &info->tx_buf_list[i]; desc_ex = &info->tx_buf_list_ex[i]; @@ -5021,7 +5210,7 @@ timeout=100; while( timeout-- && !info->irq_occurred ) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); } spin_lock_irqsave(&info->lock,flags); @@ -5172,7 +5361,7 @@ /* Set a timeout for waiting for interrupt. */ for ( timeout = 100; timeout; --timeout ) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); if (rx_get_frame(info)) { rc = TRUE; @@ -5384,9 +5573,9 @@ spin_unlock_irqrestore(&info->lock,flags); -#ifdef CONFIG_SYNCLINK_SYNCPPP +#ifdef CONFIG_HDLC if (info->netcount) - sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif bh_transmit(info); @@ -5428,7 +5617,7 @@ info->status_timer.data = (unsigned long)info; info->status_timer.function = status_timeout; - info->status_timer.expires = jiffies + jiffies_from_ms(10); + info->status_timer.expires = jiffies + msecs_to_jiffies(10); add_timer(&info->status_timer); } diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/tty_io.c 2004-10-18 14:56:33 -07:00 @@ -92,6 +92,7 @@ #include #include #include +#include #include #include @@ -120,10 +121,14 @@ EXPORT_SYMBOL(tty_std_termios); +/* This list gets poked at by procfs and various bits of boot up code. This + could do with some rationalisation such as pulling the tty proc function + into this file */ + LIST_HEAD(tty_drivers); /* linked list of tty drivers */ -struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ -/* Semaphore to protect creating and releasing a tty */ +/* Semaphore to protect creating and releasing a tty. This is shared with + vt.c for deeply disgusting hack reasons */ DECLARE_MUTEX(tty_sem); #ifdef CONFIG_UNIX98_PTYS @@ -142,6 +147,7 @@ ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *); static unsigned int tty_poll(struct file *, poll_table *); static int tty_open(struct inode *, struct file *); +static int ptmx_open(struct inode *, struct file *); static int tty_release(struct inode *, struct file *); int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); @@ -223,65 +229,323 @@ return 0; } +/* + * This is probably overkill for real world processors but + * they are not on hot paths so a little discipline won't do + * any harm. + */ + +static void tty_set_termios_ldisc(struct tty_struct *tty, int num) +{ + down(&tty->termios_sem); + tty->termios->c_line = num; + up(&tty->termios_sem); +} + +/* + * This guards the refcounted line discipline lists. The lock + * must be taken with irqs off because there are hangup path + * callers who will do ldisc lookups and cannot sleep. + */ + +static spinlock_t tty_ldisc_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); +static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ + int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { + unsigned long flags; + int ret = 0; + if (disc < N_TTY || disc >= NR_LDISCS) return -EINVAL; + spin_lock_irqsave(&tty_ldisc_lock, flags); if (new_ldisc) { - ldiscs[disc] = *new_ldisc; - ldiscs[disc].flags |= LDISC_FLAG_DEFINED; - ldiscs[disc].num = disc; - } else - memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); + tty_ldiscs[disc] = *new_ldisc; + tty_ldiscs[disc].num = disc; + tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; + tty_ldiscs[disc].refcount = 0; + } else { + if(tty_ldiscs[disc].refcount) + ret = -EBUSY; + else + tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); - return 0; + return ret; } EXPORT_SYMBOL(tty_register_ldisc); -/* Set the discipline of a tty line. */ +struct tty_ldisc *tty_ldisc_get(int disc) +{ + unsigned long flags; + struct tty_ldisc *ld; + + if (disc < N_TTY || disc >= NR_LDISCS) + return NULL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + + ld = &tty_ldiscs[disc]; + /* Check the entry is defined */ + if(ld->flags & LDISC_FLAG_DEFINED) + { + /* If the module is being unloaded we can't use it */ + if (!try_module_get(ld->owner)) + ld = NULL; + else /* lock it */ + ld->refcount++; + } + else + ld = NULL; + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return ld; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_get); + +void tty_ldisc_put(int disc) +{ + struct tty_ldisc *ld; + unsigned long flags; + + if (disc < N_TTY || disc >= NR_LDISCS) + BUG(); + + spin_lock_irqsave(&tty_ldisc_lock, flags); + ld = &tty_ldiscs[disc]; + if(ld->refcount == 0) + BUG(); + ld->refcount --; + module_put(ld->owner); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); +} + +EXPORT_SYMBOL_GPL(tty_ldisc_put); + +void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) +{ + tty->ldisc = *ld; + tty->ldisc.refcount = 0; +} + +/** + * tty_ldisc_try - internal helper + * @tty: the tty + * + * Make a single attempt to grab and bump the refcount on + * the tty ldisc. Return 0 on failure or 1 on success. This is + * used to implement both the waiting and non waiting versions + * of tty_ldisc_ref + */ + +static int tty_ldisc_try(struct tty_struct *tty) +{ + unsigned long flags; + struct tty_ldisc *ld; + int ret = 0; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + ld = &tty->ldisc; + if(test_bit(TTY_LDISC, &tty->flags)) + { + ld->refcount++; + ret = 1; + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return ret; +} + +/** + * tty_ldisc_ref_wait - wait for the tty ldisc + * @tty: tty device + * + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then + * wait patiently until it changes. + * + * Note: Must not be called from an IRQ/timer context. The caller + * must also be careful not to hold other locks that will deadlock + * against a discipline change, such as an existing ldisc reference + * (which we check for) + */ + +struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) +{ + /* wait_event is a macro */ + wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); + if(tty->ldisc.refcount == 0) + printk(KERN_ERR "tty_ldisc_ref_wait\n"); + return &tty->ldisc; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); + +/** + * tty_ldisc_ref - get the tty ldisc + * @tty: tty device + * + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then + * return NULL. Can be called from IRQ and timer functions. + */ + +struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) +{ + if(tty_ldisc_try(tty)) + return &tty->ldisc; + return NULL; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_ref); + +/** + * tty_ldisc_deref - free a tty ldisc reference + * @ld: reference to free up + * + * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May + * be called in IRQ context. + */ + +void tty_ldisc_deref(struct tty_ldisc *ld) +{ + unsigned long flags; + + if(ld == NULL) + BUG(); + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if(ld->refcount == 0) + printk(KERN_ERR "tty_ldisc_deref: no references.\n"); + else + ld->refcount--; + if(ld->refcount == 0) + wake_up(&tty_ldisc_wait); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); +} + +EXPORT_SYMBOL_GPL(tty_ldisc_deref); + +/** + * tty_ldisc_enable - allow ldisc use + * @tty: terminal to activate ldisc on + * + * Set the TTY_LDISC flag when the line discipline can be called + * again. Do neccessary wakeups for existing sleepers. + * + * Note: nobody should set this bit except via this function. Clearing + * directly is allowed. + */ + +static void tty_ldisc_enable(struct tty_struct *tty) +{ + set_bit(TTY_LDISC, &tty->flags); + wake_up(&tty_ldisc_wait); +} + +/** + * tty_set_ldisc - set line discipline + * @tty: the terminal to set + * @ldisc: the line discipline + * + * Set the discipline of a tty line. Must be called from a process + * context. + */ + static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval = 0; struct tty_ldisc o_ldisc; char buf[64]; + int work; + unsigned long flags; + struct tty_ldisc *ld; if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) return -EINVAL; + +restart: + + if (tty->ldisc.num == ldisc) + return 0; /* We are already in the desired discipline */ + + ld = tty_ldisc_get(ldisc); /* Eduardo Blanco */ /* Cyrus Durgin */ - if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { + if (ld == NULL) { request_module("tty-ldisc-%d", ldisc); + ld = tty_ldisc_get(ldisc); } - if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) + if (ld == NULL) return -EINVAL; - if (tty->ldisc.num == ldisc) - return 0; /* We are already in the desired discipline */ - - if (!try_module_get(ldiscs[ldisc].owner)) - return -EINVAL; - o_ldisc = tty->ldisc; tty_wait_until_sent(tty, 0); + + /* + * Make sure we don't change while someone holds a + * reference to the line discipline. The TTY_LDISC bit + * prevents anyone taking a reference once it is clear. + * We need the lock to avoid racing reference takers. + */ + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if(tty->ldisc.refcount) + { + /* Free the new ldisc we grabbed. Must drop the lock + first. */ + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + /* + * There are several reasons we may be busy, including + * random momentary I/O traffic. We must therefore + * retry. We could distinguish between blocking ops + * and retries if we made tty_ldisc_wait() smarter. That + * is up for discussion. + */ + if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + clear_bit(TTY_LDISC, &tty->flags); + clear_bit(TTY_DONT_FLIP, &tty->flags); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + /* + * From this point on we know nobody has an ldisc + * usage reference, nor can they obtain one until + * we say so later on. + */ + + work = cancel_delayed_work(&tty->flip.work); + /* + * Wait for ->hangup_work and ->flip.work handlers to terminate + */ + + flush_scheduled_work(); /* Shutdown the current discipline. */ if (tty->ldisc.close) (tty->ldisc.close)(tty); /* Now set up the new line discipline. */ - tty->ldisc = ldiscs[ldisc]; - tty->termios->c_line = ldisc; + tty_ldisc_assign(tty, ld); + tty_set_termios_ldisc(tty, ldisc); if (tty->ldisc.open) retval = (tty->ldisc.open)(tty); if (retval < 0) { - tty->ldisc = o_ldisc; - tty->termios->c_line = tty->ldisc.num; + tty_ldisc_put(ldisc); + /* There is an outstanding reference here so this is safe */ + tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num)); + tty_set_termios_ldisc(tty, tty->ldisc.num); if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; + tty_ldisc_put(o_ldisc.num); + /* This driver is always present */ + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(tty, N_TTY); if (tty->ldisc.open) { int r = tty->ldisc.open(tty); @@ -291,12 +555,27 @@ tty_name(tty, buf), r); } } - } else { - module_put(o_ldisc.owner); } + /* At this point we hold a reference to the new ldisc and a + a reference to the old ldisc. If we ended up flipping back + to the existing ldisc we have two references to it */ if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc) tty->driver->set_ldisc(tty); + + tty_ldisc_put(o_ldisc.num); + + /* + * Allow ldisc referencing to occur as soon as the driver + * ldisc callback completes. + */ + + tty_ldisc_enable(tty); + + /* Restart it in case no characters kick it off. Safe if + already running */ + if(work) + schedule_delayed_work(&tty->flip.work, 1); return retval; } @@ -377,6 +656,19 @@ .fasync = tty_fasync, }; +#ifdef CONFIG_UNIX98_PTYS +static struct file_operations ptmx_fops = { + .llseek = no_llseek, + .read = tty_read, + .write = tty_write, + .poll = tty_poll, + .ioctl = tty_ioctl, + .open = ptmx_open, + .release = tty_release, + .fasync = tty_fasync, +}; +#endif + static struct file_operations console_fops = { .llseek = no_llseek, .read = tty_read, @@ -399,6 +691,53 @@ static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED; static struct file *redirect; + +/** + * tty_wakeup - request more data + * @tty: terminal + * + * Internal and external helper for wakeups of tty. This function + * informs the line discipline if present that the driver is ready + * to receive more output data. + */ + +void tty_wakeup(struct tty_struct *tty) +{ + struct tty_ldisc *ld; + + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { + ld = tty_ldisc_ref(tty); + if(ld) { + if(ld->write_wakeup) + ld->write_wakeup(tty); + tty_ldisc_deref(ld); + } + } + wake_up_interruptible(&tty->write_wait); +} + +EXPORT_SYMBOL_GPL(tty_wakeup); + +/** + * tty_ldisc_flush - flush line discipline queue + * @tty: tty + * + * Flush the line discipline queue (if any) for this tty. If there + * is no line discipline active this is a no-op. + */ + +void tty_ldisc_flush(struct tty_struct *tty) +{ + struct tty_ldisc *ld = tty_ldisc_ref(tty); + if(ld) { + if(ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } +} + +EXPORT_SYMBOL_GPL(tty_ldisc_flush); + /* * This can be called by the "eventd" kernel thread. That is process synchronous, * but doesn't hold any locks, so we need to make sure we have the appropriate @@ -410,7 +749,7 @@ struct file * cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; - struct pid *pid; + struct tty_ldisc *ld; int closecount = 0, n; if (!tty) @@ -428,6 +767,7 @@ check_tty_count(tty, "do_tty_hangup"); file_list_lock(); + /* This breaks for file handles being sent over AF_UNIX sockets ? */ list_for_each_entry(filp, &tty->tty_files, f_list) { if (filp->f_op->write == redirected_tty_write) cons_filp = filp; @@ -440,21 +780,25 @@ file_list_unlock(); /* FIXME! What are the locking issues here? This may me overdoing things.. - * this question is especially important now that we've removed the irqlock. */ - { - unsigned long flags; + * this question is especially important now that we've removed the irqlock. */ - local_irq_save(flags); // FIXME: is this safe? - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + ld = tty_ldisc_ref(tty); + if(ld != NULL) /* We may have no line discipline at this point */ + { + if (ld->flush_buffer) + ld->flush_buffer(tty); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - local_irq_restore(flags); // FIXME: is this safe? + ld->write_wakeup) + ld->write_wakeup(tty); + if (ld->hangup) + ld->hangup(tty); } + /* FIXME: Once we trust the LDISC code better we can wait here for + ldisc completion and fix the driver call race */ + wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); @@ -463,26 +807,21 @@ * N_TTY. */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + { + down(&tty->termios_sem); *tty->termios = tty->driver->init_termios; - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - module_put(tty->ldisc.owner); - - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) { - int i = (tty->ldisc.open)(tty); - if (i < 0) - printk(KERN_ERR "do_tty_hangup: N_TTY open: " - "error %d\n", -i); - } + up(&tty->termios_sem); } + /* Defer ldisc switch */ + /* tty_deferred_ldisc_switch(N_TTY); + + This should get done automatically when the port closes and + tty_release is called */ + read_lock(&tasklist_lock); if (tty->session > 0) { - struct list_head *l; - for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) { + do_each_task_pid(tty->session, PIDTYPE_SID, p) { if (p->signal->tty == tty) p->signal->tty = NULL; if (!p->signal->leader) @@ -491,7 +830,7 @@ send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p); if (tty->pgrp > 0) p->signal->tty_old_pgrp = tty->pgrp; - } + } while_each_task_pid(tty->session, PIDTYPE_SID, p); } read_unlock(&tasklist_lock); @@ -511,6 +850,17 @@ tty->driver->close(tty, cons_filp); } else if (tty->driver->hangup) (tty->driver->hangup)(tty); + + /* We don't want to have driver/ldisc interactions beyond + the ones we did here. The driver layer expects no + calls after ->hangup() from the ldisc side. However we + can't yet guarantee all that */ + + set_bit(TTY_HUPPED, &tty->flags); + if (ld) { + tty_ldisc_enable(tty); + tty_ldisc_deref(ld); + } unlock_kernel(); if (f) fput(f); @@ -563,8 +913,6 @@ { struct tty_struct *tty; struct task_struct *p; - struct list_head *l; - struct pid *pid; int tty_pgrp = -1; lock_kernel(); @@ -593,8 +941,9 @@ tty->pgrp = -1; read_lock(&tasklist_lock); - for_each_task_pid(current->signal->session, PIDTYPE_SID, p, l, pid) + do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); unlock_kernel(); } @@ -627,9 +976,9 @@ } if (tty->driver->start) (tty->driver->start)(tty); - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + + /* If we have a running line discipline it may need kicking */ + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -641,6 +990,7 @@ int i; struct tty_struct * tty; struct inode *inode; + struct tty_ldisc *ld; tty = (struct tty_struct *)file->private_data; inode = file->f_dentry->d_inode; @@ -649,11 +999,15 @@ if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) return -EIO; + /* We want to wait for the line discipline to sort out in this + situation */ + ld = tty_ldisc_ref_wait(tty); lock_kernel(); - if (tty->ldisc.read) - i = (tty->ldisc.read)(tty,file,buf,count); + if (ld->read) + i = (ld->read)(tty,file,buf,count); else i = -EIO; + tty_ldisc_deref(ld); unlock_kernel(); if (i > 0) inode->i_atime = CURRENT_TIME; @@ -715,16 +1069,23 @@ { struct tty_struct * tty; struct inode *inode = file->f_dentry->d_inode; - + ssize_t ret; + struct tty_ldisc *ld; + tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_write")) return -EIO; if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags))) return -EIO; - if (!tty->ldisc.write) - return -EIO; - return do_tty_write(tty->ldisc.write, tty, file, + + ld = tty_ldisc_ref_wait(tty); + if (!ld->write) + ret = -EIO; + else + ret = do_tty_write(ld->write, tty, file, (const unsigned char __user *)buf, count); + tty_ldisc_deref(ld); + return ret; } ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t count, @@ -749,6 +1110,17 @@ return tty_write(file, buf, count, ppos); } +static char ptychar[] = "pqrstuvwxyzabcde"; + +static inline void pty_line_name(struct tty_driver *driver, int index, char *p) +{ + int i = index + driver->name_base; + /* ->name is initialized to "ttyp", but "tty" is expected */ + sprintf(p, "%s%c%x", + driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name, + ptychar[i >> 4 & 0xf], i & 0xf); +} + static inline void tty_line_name(struct tty_driver *driver, int index, char *p) { sprintf(p, "%s%d", driver->name, index + driver->name_base); @@ -910,6 +1282,7 @@ * If we fail here just call release_mem to clean up. No need * to decrement the use counts, as release_mem doesn't care. */ + if (tty->ldisc.open) { retval = (tty->ldisc.open)(tty); if (retval) @@ -922,7 +1295,9 @@ (tty->ldisc.close)(tty); goto release_mem_out; } + tty_ldisc_enable(o_tty); } + tty_ldisc_enable(tty); goto success; /* @@ -951,6 +1326,9 @@ tty->count++; tty->driver = driver; /* N.B. why do this every time?? */ + /* FIXME */ + if(!test_bit(TTY_LDISC, &tty->flags)) + printk(KERN_ERR "init_dev but no ldisc\n"); success: *ret_tty = tty; @@ -1054,6 +1432,7 @@ int devpts_master, devpts; int idx; char buf[64]; + unsigned long flags; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev")) @@ -1130,7 +1509,6 @@ } } #endif - if (tty->driver->close) tty->driver->close(tty, filp); @@ -1235,15 +1613,15 @@ */ if (tty_closing || o_tty_closing) { struct task_struct *p; - struct list_head *l; - struct pid *pid; read_lock(&tasklist_lock); - for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) + do_each_task_pid(tty->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(tty->session, PIDTYPE_SID, p); if (o_tty) - for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid) + do_each_task_pid(o_tty->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); } @@ -1254,36 +1632,58 @@ #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "freeing tty structure..."); #endif - /* * Prevent flush_to_ldisc() from rescheduling the work for later. Then - * kill any delayed work. + * kill any delayed work. As this is the final close it does not + * race with the set_ldisc code path. */ + clear_bit(TTY_LDISC, &tty->flags); clear_bit(TTY_DONT_FLIP, &tty->flags); cancel_delayed_work(&tty->flip.work); /* * Wait for ->hangup_work and ->flip.work handlers to terminate */ + flush_scheduled_work(); - + + /* + * Wait for any short term users (we know they are just driver + * side waiters as the file is closing so user count on the file + * side is zero. + */ + spin_lock_irqsave(&tty_ldisc_lock, flags); + while(tty->ldisc.refcount) + { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); + spin_lock_irqsave(&tty_ldisc_lock, flags); + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); /* * Shutdown the current line discipline, and reset it to N_TTY. * N.B. why reset ldisc when we're releasing the memory?? + * + * FIXME: this MUST get fixed for the new reflocking */ if (tty->ldisc.close) (tty->ldisc.close)(tty); - module_put(tty->ldisc.owner); + tty_ldisc_put(tty->ldisc.num); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; + /* + * Switch the line discipline back + */ + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(tty,N_TTY); if (o_tty) { + /* FIXME: could o_tty be in setldisc here ? */ + clear_bit(TTY_LDISC, &o_tty->flags); if (o_tty->ldisc.close) (o_tty->ldisc.close)(o_tty); - module_put(o_tty->ldisc.owner); - o_tty->ldisc = ldiscs[N_TTY]; + tty_ldisc_put(o_tty->ldisc.num); + tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(o_tty,N_TTY); } - /* * The release_mem function takes care of the details of clearing * the slots and preserving the termios structure. @@ -1323,6 +1723,7 @@ unsigned short saved_flags = filp->f_flags; nonseekable_open(inode, filp); + retry_open: noctty = filp->f_flags & O_NOCTTY; index = -1; @@ -1358,53 +1759,13 @@ return -ENODEV; } -#ifdef CONFIG_UNIX98_PTYS - if (device == MKDEV(TTYAUX_MAJOR,2)) { - int idr_ret; - - /* find a device that is not in use. */ - down(&allocated_ptys_lock); - if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { - up(&allocated_ptys_lock); - return -ENOMEM; - } - idr_ret = idr_get_new(&allocated_ptys, NULL, &index); - if (idr_ret < 0) { - up(&allocated_ptys_lock); - if (idr_ret == -EAGAIN) - return -ENOMEM; - return -EIO; - } - if (index >= pty_limit) { - idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); - return -EIO; - } - up(&allocated_ptys_lock); - - driver = ptm_driver; - retval = init_dev(driver, index, &tty); - if (retval) { - down(&allocated_ptys_lock); - idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); - return retval; - } - - set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - if (devpts_pty_new(tty->link)) - retval = -ENOMEM; - } else -#endif - { - driver = get_tty_driver(device, &index); - if (!driver) - return -ENODEV; + driver = get_tty_driver(device, &index); + if (!driver) + return -ENODEV; got_driver: - retval = init_dev(driver, index, &tty); - if (retval) - return retval; - } + retval = init_dev(driver, index, &tty); + if (retval) + return retval; filp->private_data = tty; file_move(filp, &tty->tty_files); @@ -1431,15 +1792,6 @@ printk(KERN_DEBUG "error %d in opening %s...", retval, tty->name); #endif - -#ifdef CONFIG_UNIX98_PTYS - if (index != -1) { - down(&allocated_ptys_lock); - idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); - } -#endif - release_dev(filp); if (retval != -ERESTARTSYS) return retval; @@ -1467,6 +1819,62 @@ return 0; } +#ifdef CONFIG_UNIX98_PTYS +static int ptmx_open(struct inode * inode, struct file * filp) +{ + struct tty_struct *tty; + int retval; + int index; + int idr_ret; + + nonseekable_open(inode, filp); + + /* find a device that is not in use. */ + down(&allocated_ptys_lock); + if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { + up(&allocated_ptys_lock); + return -ENOMEM; + } + idr_ret = idr_get_new(&allocated_ptys, NULL, &index); + if (idr_ret < 0) { + up(&allocated_ptys_lock); + if (idr_ret == -EAGAIN) + return -ENOMEM; + return -EIO; + } + if (index >= pty_limit) { + idr_remove(&allocated_ptys, index); + up(&allocated_ptys_lock); + return -EIO; + } + up(&allocated_ptys_lock); + + retval = init_dev(ptm_driver, index, &tty); + if (retval) + goto out; + + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + filp->private_data = tty; + file_move(filp, &tty->tty_files); + + retval = -ENOMEM; + if (devpts_pty_new(tty->link)) + goto out1; + + check_tty_count(tty, "tty_open"); + retval = ptm_driver->open(tty, filp); + if (!retval) + return 0; +out1: + release_dev(filp); +out: + down(&allocated_ptys_lock); + idr_remove(&allocated_ptys, index); + up(&allocated_ptys_lock); + return retval; +} +#endif + static int tty_release(struct inode * inode, struct file * filp) { lock_kernel(); @@ -1479,14 +1887,18 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait) { struct tty_struct * tty; + struct tty_ldisc *ld; + int ret = 0; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll")) return 0; - - if (tty->ldisc.poll) - return (tty->ldisc.poll)(tty, filp, wait); - return 0; + + ld = tty_ldisc_ref_wait(tty); + if (ld->poll) + ret = (ld->poll)(tty, filp, wait); + tty_ldisc_deref(ld); + return ret; } static int tty_fasync(int fd, struct file * filp, int on) @@ -1518,12 +1930,15 @@ static int tiocsti(struct tty_struct *tty, char __user *p) { char ch, mbz = 0; - + struct tty_ldisc *ld; + if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ch, p)) return -EFAULT; - tty->ldisc.receive_buf(tty, &ch, &mbz, 1); + ld = tty_ldisc_ref_wait(tty); + ld->receive_buf(tty, &ch, &mbz, 1); + tty_ldisc_deref(ld); return 0; } @@ -1606,8 +2021,6 @@ static int tiocsctty(struct tty_struct *tty, int arg) { - struct list_head *l; - struct pid *pid; task_t *p; if (current->signal->leader && @@ -1630,8 +2043,9 @@ */ read_lock(&tasklist_lock); - for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) + do_each_task_pid(tty->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(tty->session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); } else return -EPERM; @@ -1772,6 +2186,7 @@ struct tty_struct *tty, *real_tty; void __user *p = (void __user *)arg; int retval; + struct tty_ldisc *ld; tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_ioctl")) @@ -1861,6 +2276,7 @@ case TIOCGSID: return tiocgsid(tty, real_tty, p); case TIOCGETD: + /* FIXME: check this is ok */ return put_user(tty->ldisc.num, (int __user *)p); case TIOCSETD: return tiocsetd(tty, p); @@ -1899,16 +2315,19 @@ return tty_tiocmset(tty, file, cmd, p); } if (tty->driver->ioctl) { - int retval = (tty->driver->ioctl)(tty, file, cmd, arg); + retval = (tty->driver->ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } - if (tty->ldisc.ioctl) { - int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg); - if (retval != -ENOIOCTLCMD) - return retval; + ld = tty_ldisc_ref_wait(tty); + retval = -EINVAL; + if (ld->ioctl) { + retval = ld->ioctl(tty, file, cmd, arg); + if (retval == -ENOIOCTLCMD) + retval = -EINVAL; } - return -EINVAL; + tty_ldisc_deref(ld); + return retval; } @@ -1938,21 +2357,26 @@ #else struct tty_struct *tty = arg; struct task_struct *p; - struct list_head *l; - struct pid *pid; int session; int i; struct file *filp; + struct tty_ldisc *disc; if (!tty) return; session = tty->session; - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + /* We don't want an ldisc switch during this */ + disc = tty_ldisc_ref(tty); + if (disc && disc->flush_buffer) + disc->flush_buffer(tty); + tty_ldisc_deref(disc); + if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); + read_lock(&tasklist_lock); - for_each_task_pid(session, PIDTYPE_SID, p, l, pid) { + do_each_task_pid(session, PIDTYPE_SID, p) { if (p->signal->tty == tty || session > 0) { printk(KERN_NOTICE "SAK: killed process %d" " (%s): p->signal->session==tty->session\n", @@ -1979,7 +2403,7 @@ spin_unlock(&p->files->file_lock); } task_unlock(p); - } + } while_each_task_pid(session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); #endif } @@ -2002,24 +2426,29 @@ /* * This routine is called out of the software interrupt to flush data - * from the flip buffer to the line discipline. + * from the flip buffer to the line discipline. */ + static void flush_to_ldisc(void *private_) { struct tty_struct *tty = (struct tty_struct *) private_; unsigned char *cp; char *fp; int count; - unsigned long flags; + unsigned long flags; + struct tty_ldisc *disc; + + disc = tty_ldisc_ref(tty); + if (disc == NULL) /* !TTY_LDISC */ + return; if (test_bit(TTY_DONT_FLIP, &tty->flags)) { /* * Do it after the next timer tick: */ schedule_delayed_work(&tty->flip.work, 1); - return; + goto out; } - spin_lock_irqsave(&tty->read_lock, flags); if (tty->flip.buf_num) { cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; @@ -2038,7 +2467,31 @@ tty->flip.count = 0; spin_unlock_irqrestore(&tty->read_lock, flags); - tty->ldisc.receive_buf(tty, cp, fp, count); + disc->receive_buf(tty, cp, fp, count); +out: + tty_ldisc_deref(disc); +} + +/* + * Call the ldisc flush directly from a driver. This function may + * return an error and need retrying by the user. + */ + +int tty_push_data(struct tty_struct *tty, unsigned char *cp, unsigned char *fp, int count) +{ + int ret = 0; + struct tty_ldisc *disc; + + disc = tty_ldisc_ref(tty); + if(test_bit(TTY_DONT_FLIP, &tty->flags)) + ret = -EAGAIN; + else if(disc == NULL) + ret = -EIO; + else + disc->receive_buf(tty, cp, fp, count); + tty_ldisc_deref(disc); + return ret; + } /* @@ -2060,9 +2513,20 @@ static int n_baud_table = ARRAY_SIZE(baud_table); +/** + * tty_termios_baud_rate + * @termios: termios structure + * + * Convert termios baud rate data into a speed. This should be called + * with the termios lock held if this termios is a terminal termios + * structure. May change the termios data. + */ + int tty_termios_baud_rate(struct termios *termios) { - unsigned int cbaud = termios->c_cflag & CBAUD; + unsigned int cbaud; + + cbaud = termios->c_cflag & CBAUD; if (cbaud & CBAUDEX) { cbaud &= ~CBAUDEX; @@ -2072,12 +2536,20 @@ else cbaud += 15; } - return baud_table[cbaud]; } EXPORT_SYMBOL(tty_termios_baud_rate); +/** + * tty_get_baud_rate - get tty bit rates + * @tty: tty to query + * + * Returns the baud rate as an integer for this terminal. The + * termios lock must be held by the caller and the terminal bit + * flags may be updated. + */ + int tty_get_baud_rate(struct tty_struct *tty) { int baud = tty_termios_baud_rate(tty->termios); @@ -2096,6 +2568,17 @@ EXPORT_SYMBOL(tty_get_baud_rate); +/** + * tty_flip_buffer_push - terminal + * @tty: tty to push + * + * Queue a push of the terminal flip buffers to the line discipline. This + * function must not be called from IRQ context if tty->low_latency is set. + * + * In the event of the queue being busy for flipping the work will be + * held off and retried later. + */ + void tty_flip_buffer_push(struct tty_struct *tty) { if (tty->low_latency) @@ -2113,12 +2596,13 @@ { memset(tty, 0, sizeof(struct tty_struct)); tty->magic = TTY_MAGIC; - tty->ldisc = ldiscs[N_TTY]; + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); tty->pgrp = -1; tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; INIT_WORK(&tty->flip.work, flush_to_ldisc, tty); init_MUTEX(&tty->flip.pty_sem); + init_MUTEX(&tty->termios_sem); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); @@ -2154,6 +2638,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { + char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; if (index >= driver->num) { @@ -2165,13 +2650,11 @@ devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, "%s%d", driver->devfs_name, index + driver->name_base); - /* we don't care about the ptys */ - /* how nice to hide this behind some crappy interface.. */ - if (driver->type != TTY_DRIVER_TYPE_PTY) { - char name[64]; + if (driver->type == TTY_DRIVER_TYPE_PTY) + pty_line_name(driver, index, name); + else tty_line_name(driver, index, name); - class_simple_device_add(tty_class, dev, device, name); - } + class_simple_device_add(tty_class, dev, device, name); } /** @@ -2441,7 +2924,7 @@ class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); #ifdef CONFIG_UNIX98_PTYS - cdev_init(&ptmx_cdev, &tty_fops); + cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); diff -Nru a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c --- a/drivers/char/tty_ioctl.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/char/tty_ioctl.c 2004-10-18 14:57:05 -07:00 @@ -98,8 +98,17 @@ { int canon_change; struct termios old_termios = *tty->termios; + struct tty_ldisc *ld; + + /* + * Perform the actual termios internal changes under lock. + */ + + + /* FIXME: we need to decide on some locking/ordering semantics + for the set_termios notification eventually */ + down(&tty->termios_sem); - local_irq_disable(); // FIXME: is this safe? *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -109,12 +118,13 @@ tty->canon_data = 0; tty->erasing = 0; } - local_irq_enable(); // FIXME: is this safe? + + if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ wake_up_interruptible(&tty->read_wait); - /* see if packet mode change of state */ + /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { int old_flow = ((old_termios.c_iflag & IXON) && @@ -132,17 +142,23 @@ wake_up_interruptible(&tty->link->read_wait); } } - + if (tty->driver->set_termios) (*tty->driver->set_termios)(tty, &old_termios); - if (tty->ldisc.set_termios) - (*tty->ldisc.set_termios)(tty, &old_termios); + ld = tty_ldisc_ref(tty); + if (ld != NULL) { + if (ld->set_termios) + (ld->set_termios)(tty, &old_termios); + tty_ldisc_deref(ld); + } + up(&tty->termios_sem); } static int set_termios(struct tty_struct * tty, void __user *arg, int opt) { struct termios tmp_termios; + struct tty_ldisc *ld; int retval = tty_check_change(tty); if (retval) @@ -159,9 +175,14 @@ return -EFAULT; } - if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + ld = tty_ldisc_ref(tty); + + if (ld != NULL) { + if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } + if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) @@ -226,11 +247,14 @@ { struct sgttyb tmp; + down(&tty->termios_sem); tmp.sg_ispeed = 0; tmp.sg_ospeed = 0; tmp.sg_erase = tty->termios->c_cc[VERASE]; tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); + up(&tty->termios_sem); + return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -269,12 +293,16 @@ retval = tty_check_change(tty); if (retval) return retval; - termios = *tty->termios; + if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) return -EFAULT; + + down(&tty->termios_sem); + termios = *tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); + up(&tty->termios_sem); change_termios(tty, &termios); return 0; } @@ -365,6 +393,7 @@ struct tty_struct * real_tty; void __user *p = (void __user *)arg; int retval; + struct tty_ldisc *ld; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -443,22 +472,26 @@ retval = tty_check_change(tty); if (retval) return retval; + + ld = tty_ldisc_ref(tty); switch (arg) { case TCIFLUSH: - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + if (ld->flush_buffer) + ld->flush_buffer(tty); break; case TCIOFLUSH: - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + if (ld->flush_buffer) + ld->flush_buffer(tty); /* fall through */ case TCOFLUSH: if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); break; default: + tty_ldisc_deref(ld); return -EINVAL; } + tty_ldisc_deref(ld); return 0; case TIOCOUTQ: return put_user(tty->driver->chars_in_buffer ? @@ -504,9 +537,11 @@ case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; + down(&tty->termios_sem); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); + up(&tty->termios_sem); return 0; default: return -ENOIOCTLCMD; diff -Nru a/drivers/char/viocons.c b/drivers/char/viocons.c --- a/drivers/char/viocons.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/char/viocons.c 2004-10-18 14:55:46 -07:00 @@ -422,10 +422,7 @@ pi->overflowMessage = 0; if (pi->tty) { - if ((pi->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - (pi->tty->ldisc.write_wakeup)) - (pi->tty->ldisc.write_wakeup)(pi->tty); - wake_up_interruptible(&pi->tty->write_wait); + tty_wakeup(pi->tty); } } diff -Nru a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c --- a/drivers/char/vme_scc.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/vme_scc.c 2004-10-18 14:55:54 -07:00 @@ -544,12 +544,8 @@ SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ port->gs.flags &= ~GS_TX_INTEN; } - if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - port->gs.tty->ldisc.write_wakeup) - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - wake_up_interruptible(&port->gs.tty->write_wait); - } + if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) + tty_wakeup(port->gs.tty); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return IRQ_HANDLED; diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c --- a/drivers/char/vt.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/vt.c 2004-10-18 14:56:50 -07:00 @@ -136,9 +136,6 @@ #ifdef CONFIG_MDA_CONSOLE extern int mda_console_init(void); #endif -#ifdef CONFIG_FRAMEBUFFER_CONSOLE -extern int fb_console_init(void); -#endif struct vc vc_cons [MAX_NR_CONSOLES]; @@ -600,6 +597,17 @@ * Redrawing of screen */ +static void clear_buffer_attributes(int currcons) +{ + unsigned short *p = (unsigned short *) origin; + int count = screenbuf_size/2; + int mask = hi_font_mask | 0xff; + + for (; count > 0; count--, p++) { + scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); + } +} + void redraw_screen(int new_console, int is_switch) { int redraw = 1; @@ -637,9 +645,21 @@ if (redraw) { int update; + int old_was_color = vc_cons[currcons].d->vc_can_do_color; + set_origin(currcons); update = sw->con_switch(vc_cons[currcons].d); set_palette(currcons); + /* + * If console changed from mono<->color, the best we can do + * is to clear the buffer attributes. As it currently stands, + * rebuilding new attributes from the old buffer is not doable + * without overly complex code. + */ + if (old_was_color != vc_cons[currcons].d->vc_can_do_color) { + update_attr(currcons); + clear_buffer_attributes(currcons); + } if (update && vcmode != KD_GRAPHICS) do_update_region(currcons, origin, screenbuf_size/2); } @@ -1865,7 +1885,7 @@ * since console_init (and thus con_init) are called before any * kernel memory allocation is available. */ -char con_buf[PAGE_SIZE]; +char con_buf[CON_BUF_SIZE]; DECLARE_MUTEX(con_buf_sem); /* acquires console_sem */ @@ -1958,12 +1978,16 @@ hide_cursor(currcons); while (!tty->stopped && count) { - c = *buf; + int orig = *buf; + c = orig; buf++; n++; count--; - if (utf) { + /* Do no translation at all in control states */ + if (vc_state != ESnormal) { + tc = c; + } else if (utf) { /* Combine UTF-8 into Unicode */ /* Incomplete characters silently ignored */ if(c > 0x7f) { @@ -2063,7 +2087,7 @@ continue; } FLUSH - do_con_trol(tty, currcons, c); + do_con_trol(tty, currcons, orig); } FLUSH console_conditional_schedule(); @@ -2645,24 +2669,10 @@ #ifdef CONFIG_MDA_CONSOLE mda_console_init(); #endif -#ifdef CONFIG_FRAMEBUFFER_CONSOLE - fb_console_init(); -#endif return 0; } #ifndef VT_SINGLE_DRIVER - -static void clear_buffer_attributes(int currcons) -{ - unsigned short *p = (unsigned short *) origin; - int count = screenbuf_size/2; - int mask = hi_font_mask | 0xff; - - for (; count > 0; count--, p++) { - scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); - } -} /* * If we support more console drivers, this function is used diff -Nru a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c --- a/drivers/char/vt_ioctl.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/vt_ioctl.c 2004-10-18 14:56:48 -07:00 @@ -536,8 +536,7 @@ default: return -EINVAL; } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); return 0; case KDGKBMODE: diff -Nru a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig --- a/drivers/char/watchdog/Kconfig 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/watchdog/Kconfig 2004-10-18 14:56:33 -07:00 @@ -319,6 +319,12 @@ To compile this driver as a module, choose M here: the module will be called machzwd. +# PowerPC Architecture + +config 8xx_WDT + tristate "MPC8xx Watchdog Timer" + depends on WATCHDOG && 8xx + # MIPS Architecture config INDYDOG diff -Nru a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile --- a/drivers/char/watchdog/Makefile 2004-10-18 14:56:48 -07:00 +++ b/drivers/char/watchdog/Makefile 2004-10-18 14:56:48 -07:00 @@ -37,3 +37,4 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o +obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o diff -Nru a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c --- a/drivers/char/watchdog/cpu5wdt.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/char/watchdog/cpu5wdt.c 2004-10-18 14:56:27 -07:00 @@ -134,7 +134,7 @@ if ( test_and_set_bit(0, &cpu5wdt_device.inuse) ) return -EBUSY; - return 0; + return nonseekable_open(inode, file); } static int cpu5wdt_release(struct inode *inode, struct file *file) @@ -198,6 +198,7 @@ static struct file_operations cpu5wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .ioctl = cpu5wdt_ioctl, .open = cpu5wdt_open, .write = cpu5wdt_write, diff -Nru a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c --- a/drivers/char/watchdog/ib700wdt.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/char/watchdog/ib700wdt.c 2004-10-18 14:57:03 -07:00 @@ -263,6 +263,7 @@ static struct file_operations ibwdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = ibwdt_write, .ioctl = ibwdt_ioctl, .open = ibwdt_open, diff -Nru a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c --- a/drivers/char/watchdog/indydog.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/char/watchdog/indydog.c 2004-10-18 14:57:04 -07:00 @@ -162,6 +162,7 @@ static struct file_operations indydog_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = indydog_write, .ioctl = indydog_ioctl, .open = indydog_open, diff -Nru a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c --- a/drivers/char/watchdog/ixp4xx_wdt.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/char/watchdog/ixp4xx_wdt.c 2004-10-18 14:56:50 -07:00 @@ -170,6 +170,7 @@ static struct file_operations ixp4xx_wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = ixp4xx_wdt_write, .ioctl = ixp4xx_wdt_ioctl, .open = ixp4xx_wdt_open, diff -Nru a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c --- a/drivers/char/watchdog/machzwd.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/watchdog/machzwd.c 2004-10-18 14:56:17 -07:00 @@ -425,6 +425,7 @@ static struct file_operations zf_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = zf_write, .ioctl = zf_ioctl, .open = zf_open, diff -Nru a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c --- a/drivers/char/watchdog/mixcomwd.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/char/watchdog/mixcomwd.c 2004-10-18 14:56:27 -07:00 @@ -197,6 +197,7 @@ static struct file_operations mixcomwd_fops= { .owner = THIS_MODULE, + .llseek = no_llseek, .write = mixcomwd_write, .ioctl = mixcomwd_ioctl, .open = mixcomwd_open, diff -Nru a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/watchdog/mpc8xx_wdt.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,164 @@ +/* + * mpc8xx_wdt.c - MPC8xx watchdog userspace interface + * + * Author: Florian Schirmer + * + * 2002 (c) Florian Schirmer This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long wdt_opened; +static int wdt_status; + +static void mpc8xx_wdt_handler_disable(void) +{ + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + + imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE); + + printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n"); +} + +static void mpc8xx_wdt_handler_enable(void) +{ + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + + imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE; + + printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n"); +} + +static int mpc8xx_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &wdt_opened)) + return -EBUSY; + + m8xx_wdt_reset(); + mpc8xx_wdt_handler_disable(); + + return 0; +} + +static int mpc8xx_wdt_release(struct inode *inode, struct file *file) +{ + m8xx_wdt_reset(); + +#if !defined(CONFIG_WATCHDOG_NOWAYOUT) + mpc8xx_wdt_handler_enable(); +#endif + + clear_bit(0, &wdt_opened); + + return 0; +} + +static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len, + loff_t * ppos) +{ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (len) + m8xx_wdt_reset(); + + return len; +} + +static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int timeout; + static struct watchdog_info info = { + .options = WDIOF_KEEPALIVEPING, + .firmware_version = 0, + .identity = "MPC8xx watchdog", + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(wdt_status, (int *)arg)) + return -EFAULT; + wdt_status &= ~WDIOF_KEEPALIVEPING; + break; + + case WDIOC_GETTEMP: + return -EOPNOTSUPP; + + case WDIOC_SETOPTIONS: + return -EOPNOTSUPP; + + case WDIOC_KEEPALIVE: + m8xx_wdt_reset(); + wdt_status |= WDIOF_KEEPALIVEPING; + break; + + case WDIOC_SETTIMEOUT: + return -EOPNOTSUPP; + + case WDIOC_GETTIMEOUT: + timeout = m8xx_wdt_get_timeout(); + if (put_user(timeout, (int *)arg)) + return -EFAULT; + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static struct file_operations mpc8xx_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = mpc8xx_wdt_write, + .ioctl = mpc8xx_wdt_ioctl, + .open = mpc8xx_wdt_open, + .release = mpc8xx_wdt_release, +}; + +static struct miscdevice mpc8xx_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &mpc8xx_wdt_fops, +}; + +static int __init mpc8xx_wdt_init(void) +{ + return misc_register(&mpc8xx_wdt_miscdev); +} + +static void __exit mpc8xx_wdt_exit(void) +{ + misc_deregister(&mpc8xx_wdt_miscdev); + + m8xx_wdt_reset(); + mpc8xx_wdt_handler_enable(); +} + +module_init(mpc8xx_wdt_init); +module_exit(mpc8xx_wdt_exit); + +MODULE_AUTHOR("Florian Schirmer "); +MODULE_DESCRIPTION("MPC8xx watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff -Nru a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c --- a/drivers/char/watchdog/pcwd.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/char/watchdog/pcwd.c 2004-10-18 14:55:54 -07:00 @@ -859,8 +859,7 @@ /* Not an 'ff' from a floating bus, so must be a card! */ for (i = 0; i < 4; ++i) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); + msleep(500); last_port0 = port0; last_port1 = port1; diff -Nru a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c --- a/drivers/char/watchdog/sa1100_wdt.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/char/watchdog/sa1100_wdt.c 2004-10-18 14:56:29 -07:00 @@ -27,6 +27,10 @@ #include #include +#ifdef CONFIG_ARCH_PXA +#include +#endif + #include #include #include @@ -162,6 +166,7 @@ static struct file_operations sa1100dog_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = sa1100dog_write, .ioctl = sa1100dog_ioctl, .open = sa1100dog_open, diff -Nru a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c --- a/drivers/char/watchdog/sc1200wdt.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/char/watchdog/sc1200wdt.c 2004-10-18 14:56:17 -07:00 @@ -301,6 +301,7 @@ static struct file_operations sc1200wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = sc1200wdt_write, .ioctl = sc1200wdt_ioctl, .open = sc1200wdt_open, diff -Nru a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c --- a/drivers/char/watchdog/scx200_wdt.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/watchdog/scx200_wdt.c 2004-10-18 14:56:33 -07:00 @@ -201,6 +201,7 @@ static struct file_operations scx200_wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = scx200_wdt_write, .ioctl = scx200_wdt_ioctl, .open = scx200_wdt_open, diff -Nru a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c --- a/drivers/char/watchdog/wdt285.c 2004-10-18 14:56:18 -07:00 +++ b/drivers/char/watchdog/wdt285.c 2004-10-18 14:56:18 -07:00 @@ -180,6 +180,7 @@ static struct file_operations watchdog_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = watchdog_write, .ioctl = watchdog_ioctl, .open = watchdog_open, diff -Nru a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c --- a/drivers/char/watchdog/wdt977.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/char/watchdog/wdt977.c 2004-10-18 14:56:49 -07:00 @@ -392,6 +392,7 @@ static struct file_operations wdt977_fops= { .owner = THIS_MODULE, + .llseek = no_llseek, .write = wdt977_write, .ioctl = wdt977_ioctl, .open = wdt977_open, diff -Nru a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c --- a/drivers/char/watchdog/wdt_pci.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/char/watchdog/wdt_pci.c 2004-10-18 14:56:33 -07:00 @@ -674,8 +674,8 @@ out_misc: #ifdef CONFIG_WDT_501_PCI misc_deregister(&temp_miscdev); -#endif /* CONFIG_WDT_501_PCI */ out_rbt: +#endif /* CONFIG_WDT_501_PCI */ unregister_reboot_notifier(&wdtpci_notifier); out_irq: free_irq(irq, &wdtpci_miscdev); diff -Nru a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig --- a/drivers/cpufreq/Kconfig 2004-10-18 14:57:03 -07:00 +++ b/drivers/cpufreq/Kconfig 2004-10-18 14:57:03 -07:00 @@ -69,6 +69,21 @@ If in doubt, say Y. +config CPU_FREQ_GOV_ONDEMAND + tristate "'ondemand' cpufreq policy governor" + depends on CPU_FREQ + help + 'ondemand' - This driver adds a dynamic cpufreq policy governor. + The governor does a periodic polling and + changes frequency based on the CPU utilization. + The support for this governor depends on CPU capability to + do fast frequency switching (i.e, very low latency frequency + transitions). + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + config CPU_FREQ_24_API bool "/proc/sys/cpu/ interface (2.4. / OLD)" depends on CPU_FREQ && SYSCTL && CPU_FREQ_GOV_USERSPACE diff -Nru a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile --- a/drivers/cpufreq/Makefile 2004-10-18 14:57:05 -07:00 +++ b/drivers/cpufreq/Makefile 2004-10-18 14:57:05 -07:00 @@ -5,6 +5,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o +obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o diff -Nru a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c --- a/drivers/cpufreq/cpufreq.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/cpufreq/cpufreq.c 2004-10-18 14:56:17 -07:00 @@ -100,6 +100,85 @@ } /********************************************************************* + * EXTERNALLY AFFECTING FREQUENCY CHANGES * + *********************************************************************/ + +/** + * adjust_jiffies - adjust the system "loops_per_jiffy" + * + * This function alters the system "loops_per_jiffy" for the clock + * speed change. Note that loops_per_jiffy cannot be updated on SMP + * systems as each CPU might be scaled differently. So, use the arch + * per-CPU loops_per_jiffy value wherever possible. + */ +#ifndef CONFIG_SMP +static unsigned long l_p_j_ref; +static unsigned int l_p_j_ref_freq; + +static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) +{ + if (ci->flags & CPUFREQ_CONST_LOOPS) + return; + + if (!l_p_j_ref_freq) { + l_p_j_ref = loops_per_jiffy; + l_p_j_ref_freq = ci->old; + } + if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || + (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || + (val == CPUFREQ_RESUMECHANGE)) + loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); +} +#else +static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } +#endif + + +/** + * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition + * + * This function calls the transition notifiers and the "adjust_jiffies" function. It is called + * twice on all CPU frequency changes that have external effects. + */ +void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) +{ + BUG_ON(irqs_disabled()); + + freqs->flags = cpufreq_driver->flags; + + down_read(&cpufreq_notifier_rwsem); + switch (state) { + case CPUFREQ_PRECHANGE: + /* detect if the driver reported a value as "old frequency" which + * is not equal to what the cpufreq core thinks is "old frequency". + */ + if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { + if ((likely(cpufreq_cpu_data[freqs->cpu])) && + (likely(cpufreq_cpu_data[freqs->cpu]->cur)) && + (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) + { + printk(KERN_WARNING "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur); + freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; + } + } + notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); + adjust_jiffies(CPUFREQ_PRECHANGE, freqs); + break; + case CPUFREQ_POSTCHANGE: + adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); + notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); + if (likely(cpufreq_cpu_data[freqs->cpu])) + cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; + break; + } + up_read(&cpufreq_notifier_rwsem); +} +EXPORT_SYMBOL_GPL(cpufreq_notify_transition); + + + +/********************************************************************* * SYSFS INTERFACE * *********************************************************************/ @@ -521,9 +600,6 @@ { struct cpufreq_freqs freqs; - if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC) - panic("CPU Frequency is out of sync."); - printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " "core thinks of %u, is %u kHz.\n", old_freq, new_freq); @@ -614,11 +690,8 @@ if (unlikely(cur_freq != cpu_policy->cur)) { struct cpufreq_freqs freqs; - if (cpufreq_driver->flags & CPUFREQ_PANIC_RESUME_OUTOFSYNC) - panic("CPU Frequency is out of sync."); - - printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing" - "core thinks of %u, is %u kHz.\n", cpu_policy->cur, cur_freq); + printk(KERN_WARNING "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); freqs.cpu = cpu; freqs.old = cpu_policy->cur; @@ -626,6 +699,8 @@ notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); + + cpu_policy->cur = cur_freq; } } @@ -1003,87 +1078,6 @@ return ret; } EXPORT_SYMBOL(cpufreq_update_policy); - - -/********************************************************************* - * EXTERNALLY AFFECTING FREQUENCY CHANGES * - *********************************************************************/ - -/** - * adjust_jiffies - adjust the system "loops_per_jiffy" - * - * This function alters the system "loops_per_jiffy" for the clock - * speed change. Note that loops_per_jiffy cannot be updated on SMP - * systems as each CPU might be scaled differently. So, use the arch - * per-CPU loops_per_jiffy value wherever possible. - */ -#ifndef CONFIG_SMP -static unsigned long l_p_j_ref; -static unsigned int l_p_j_ref_freq; - -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) -{ - if (ci->flags & CPUFREQ_CONST_LOOPS) - return; - - if (!l_p_j_ref_freq) { - l_p_j_ref = loops_per_jiffy; - l_p_j_ref_freq = ci->old; - } - if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || - (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || - (val == CPUFREQ_RESUMECHANGE)) - loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); -} -#else -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } -#endif - - -/** - * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition - * - * This function calls the transition notifiers and the "adjust_jiffies" function. It is called - * twice on all CPU frequency changes that have external effects. - */ -void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) -{ - BUG_ON(irqs_disabled()); - - freqs->flags = cpufreq_driver->flags; - - down_read(&cpufreq_notifier_rwsem); - switch (state) { - case CPUFREQ_PRECHANGE: - /* detect if the driver reported a value as "old frequency" which - * is not equal to what the cpufreq core thinks is "old frequency". - */ - if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { - if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) && - (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) - { - if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC) - panic("CPU Frequency is out of sync."); - - printk(KERN_WARNING "Warning: CPU frequency out of sync: " - "cpufreq and timing core thinks of %u, is %u kHz.\n", - cpufreq_cpu_data[freqs->cpu]->cur, freqs->old); - freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; - } - } - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); - adjust_jiffies(CPUFREQ_PRECHANGE, freqs); - break; - case CPUFREQ_POSTCHANGE: - adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); - cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; - break; - } - up_read(&cpufreq_notifier_rwsem); -} -EXPORT_SYMBOL_GPL(cpufreq_notify_transition); - /********************************************************************* diff -Nru a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/cpufreq/cpufreq_ondemand.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,437 @@ +/* + * drivers/cpufreq/cpufreq_ondemand.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * dbs is used in this file as a shortform for demandbased switching + * It helps to keep variable names smaller, simpler + */ + +#define DEF_FREQUENCY_UP_THRESHOLD (80) +#define MIN_FREQUENCY_UP_THRESHOLD (0) +#define MAX_FREQUENCY_UP_THRESHOLD (100) + +#define DEF_FREQUENCY_DOWN_THRESHOLD (20) +#define MIN_FREQUENCY_DOWN_THRESHOLD (0) +#define MAX_FREQUENCY_DOWN_THRESHOLD (100) + +/* + * The polling frequency of this governor depends on the capability of + * the processor. Default polling frequency is 1000 times the transition + * latency of the processor. The governor will work on any processor with + * transition latency <= 10mS, using appropriate sampling + * rate. + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. + * All times here are in uS. + */ +static unsigned int def_sampling_rate; +#define MIN_SAMPLING_RATE (def_sampling_rate / 2) +#define MAX_SAMPLING_RATE (500 * def_sampling_rate) +#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) +#define DEF_SAMPLING_DOWN_FACTOR (10) +#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define sampling_rate_in_HZ(x) (((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000))) + +static void do_dbs_timer(void *data); + +struct cpu_dbs_info_s { + struct cpufreq_policy *cur_policy; + unsigned int prev_cpu_idle_up; + unsigned int prev_cpu_idle_down; + unsigned int enable; +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); + +static unsigned int dbs_enable; /* number of CPUs using this policy */ + +static DECLARE_MUTEX (dbs_sem); +static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); + +struct dbs_tuners { + unsigned int sampling_rate; + unsigned int sampling_down_factor; + unsigned int up_threshold; + unsigned int down_threshold; +}; + +struct dbs_tuners dbs_tuners_ins = { + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, + .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, +}; + +/************************** sysfs interface ************************/ +static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) +{ + return sprintf (buf, "%u\n", MAX_SAMPLING_RATE); +} + +static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf) +{ + return sprintf (buf, "%u\n", MIN_SAMPLING_RATE); +} + +#define define_one_ro(_name) \ +static struct freq_attr _name = { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = show_##_name, \ +} + +define_one_ro(sampling_rate_max); +define_one_ro(sampling_rate_min); + +/* cpufreq_ondemand Governor Tunables */ +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct cpufreq_policy *unused, char *buf) \ +{ \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +} +show_one(sampling_rate, sampling_rate); +show_one(sampling_down_factor, sampling_down_factor); +show_one(up_threshold, up_threshold); +show_one(down_threshold, down_threshold); + +static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + down(&dbs_sem); + if (ret != 1 ) + goto out; + + dbs_tuners_ins.sampling_down_factor = input; +out: + up(&dbs_sem); + return count; +} + +static ssize_t store_sampling_rate(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + down(&dbs_sem); + if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) + goto out; + + dbs_tuners_ins.sampling_rate = input; +out: + up(&dbs_sem); + return count; +} + +static ssize_t store_up_threshold(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + down(&dbs_sem); + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD || + input <= dbs_tuners_ins.down_threshold) + goto out; + + dbs_tuners_ins.up_threshold = input; +out: + up(&dbs_sem); + return count; +} + +static ssize_t store_down_threshold(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + down(&dbs_sem); + if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || + input < MIN_FREQUENCY_DOWN_THRESHOLD || + input >= dbs_tuners_ins.up_threshold) + goto out; + + dbs_tuners_ins.down_threshold = input; +out: + up(&dbs_sem); + return count; +} + +#define define_one_rw(_name) \ +static struct freq_attr _name = { \ + .attr = { .name = __stringify(_name), .mode = 0644 }, \ + .show = show_##_name, \ + .store = store_##_name, \ +} + +define_one_rw(sampling_rate); +define_one_rw(sampling_down_factor); +define_one_rw(up_threshold); +define_one_rw(down_threshold); + +static struct attribute * dbs_attributes[] = { + &sampling_rate_max.attr, + &sampling_rate_min.attr, + &sampling_rate.attr, + &sampling_down_factor.attr, + &up_threshold.attr, + &down_threshold.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "ondemand", +}; + +/************************** sysfs end ************************/ + +static void dbs_check_cpu(int cpu) +{ + unsigned int idle_ticks, up_idle_ticks, down_idle_ticks; + unsigned int total_idle_ticks; + unsigned int freq_down_step; + unsigned int freq_down_sampling_rate; + static int down_skip[NR_CPUS]; + struct cpu_dbs_info_s *this_dbs_info; + + this_dbs_info = &per_cpu(cpu_dbs_info, cpu); + if (!this_dbs_info->enable) + return; + + /* + * The default safe range is 20% to 80% + * Every sampling_rate, we check + * - If current idle time is less than 20%, then we try to + * increase frequency + * Every sampling_rate*sampling_down_factor, we check + * - If current idle time is more than 80%, then we try to + * decrease frequency + * + * Any frequency increase takes it to the maximum frequency. + * Frequency reduction happens at minimum steps of + * 5% of max_frequency + */ + /* Check for frequency increase */ + total_idle_ticks = kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait; + idle_ticks = total_idle_ticks - + this_dbs_info->prev_cpu_idle_up; + this_dbs_info->prev_cpu_idle_up = total_idle_ticks; + + /* Scale idle ticks by 100 and compare with up and down ticks */ + idle_ticks *= 100; + up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) * + sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate); + + if (idle_ticks < up_idle_ticks) { + __cpufreq_driver_target(this_dbs_info->cur_policy, + this_dbs_info->cur_policy->max, + CPUFREQ_RELATION_H); + down_skip[cpu] = 0; + this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + return; + } + + /* Check for frequency decrease */ + down_skip[cpu]++; + if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) + return; + + idle_ticks = total_idle_ticks - + this_dbs_info->prev_cpu_idle_down; + /* Scale idle ticks by 100 and compare with up and down ticks */ + idle_ticks *= 100; + down_skip[cpu] = 0; + this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + + freq_down_sampling_rate = dbs_tuners_ins.sampling_rate * + dbs_tuners_ins.sampling_down_factor; + down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * + sampling_rate_in_HZ(freq_down_sampling_rate); + + if (idle_ticks > down_idle_ticks ) { + freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100; + + /* max freq cannot be less than 100. But who knows.... */ + if (unlikely(freq_down_step == 0)) + freq_down_step = 5; + + __cpufreq_driver_target(this_dbs_info->cur_policy, + this_dbs_info->cur_policy->cur - freq_down_step, + CPUFREQ_RELATION_H); + return; + } +} + +static void do_dbs_timer(void *data) +{ + int i; + down(&dbs_sem); + for (i = 0; i < NR_CPUS; i++) + if (cpu_online(i)) + dbs_check_cpu(i); + schedule_delayed_work(&dbs_work, + sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate)); + up(&dbs_sem); +} + +static inline void dbs_timer_init(void) +{ + INIT_WORK(&dbs_work, do_dbs_timer, NULL); + schedule_work(&dbs_work); + return; +} + +static inline void dbs_timer_exit(void) +{ + cancel_delayed_work(&dbs_work); + return; +} + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + + this_dbs_info = &per_cpu(cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || + (!policy->cur)) + return -EINVAL; + + if (policy->cpuinfo.transition_latency > + (TRANSITION_LATENCY_LIMIT * 1000)) + return -EINVAL; + if (this_dbs_info->enable) /* Already enabled */ + break; + + down(&dbs_sem); + this_dbs_info->cur_policy = policy; + + this_dbs_info->prev_cpu_idle_up = + kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait; + this_dbs_info->prev_cpu_idle_down = + kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait; + this_dbs_info->enable = 1; + sysfs_create_group(&policy->kobj, &dbs_attr_group); + dbs_enable++; + /* + * Start the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 1) { + unsigned int latency; + /* policy latency is in nS. Convert it to uS first */ + + latency = policy->cpuinfo.transition_latency; + if (latency < 1000) + latency = 1000; + + def_sampling_rate = (latency / 1000) * + DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; + dbs_tuners_ins.sampling_rate = def_sampling_rate; + + dbs_timer_init(); + } + + up(&dbs_sem); + break; + + case CPUFREQ_GOV_STOP: + down(&dbs_sem); + this_dbs_info->enable = 0; + sysfs_remove_group(&policy->kobj, &dbs_attr_group); + dbs_enable--; + /* + * Stop the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 0) + dbs_timer_exit(); + + up(&dbs_sem); + + break; + + case CPUFREQ_GOV_LIMITS: + down(&dbs_sem); + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target( + this_dbs_info->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target( + this_dbs_info->cur_policy, + policy->min, CPUFREQ_RELATION_L); + up(&dbs_sem); + break; + } + return 0; +} + +struct cpufreq_governor cpufreq_gov_dbs = { + .name = "ondemand", + .governor = cpufreq_governor_dbs, + .owner = THIS_MODULE, +}; +EXPORT_SYMBOL(cpufreq_gov_dbs); + +static int __init cpufreq_gov_dbs_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_dbs); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + /* Make sure that the scheduled work is indeed not running */ + flush_scheduled_work(); + + cpufreq_unregister_governor(&cpufreq_gov_dbs); +} + + +MODULE_AUTHOR ("Venkatesh Pallipadi "); +MODULE_DESCRIPTION ("'cpufreq_ondemand' - A dynamic cpufreq governor for " + "Low Latency Frequency Transition capable processors"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_gov_dbs_init); +module_exit(cpufreq_gov_dbs_exit); diff -Nru a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c --- a/drivers/cpufreq/cpufreq_userspace.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/cpufreq/cpufreq_userspace.c 2004-10-18 14:55:55 -07:00 @@ -82,6 +82,13 @@ { struct cpufreq_freqs *freq = data; + /* Don't update cur_freq if CPU is managed and we're + * waking up: else we won't remember what frequency + * we need to set the CPU to. + */ + if (cpu_is_managed[freq->cpu] && (val == CPUFREQ_RESUMECHANGE)) + return 0; + cpu_cur_freq[freq->cpu] = freq->new; return 0; @@ -147,6 +154,9 @@ #ifdef CONFIG_CPU_FREQ_24_API +#warning The /proc/sys/cpu/ and sysctl interface to cpufreq will be removed from the 2.6. kernel series soon after 2005-01-01 + +static unsigned int warning_print = 0; /*********************** cpufreq_sysctl interface ********************/ static int @@ -162,6 +172,13 @@ return 0; } + if (!warning_print) { + warning_print++; + printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and " + "will be removed from (new) 2.6. kernels soon " + "after 2005-01-01\n"); + } + if (write) { unsigned int freq; @@ -197,6 +214,13 @@ if (!cpu_online(cpu)) return -EINVAL; + if (!warning_print) { + warning_print++; + printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and " + "will be removed from (new) 2.6. kernels soon " + "after 2005-01-01\n"); + } + if (oldval && oldlenp) { size_t oldlen; @@ -521,6 +545,9 @@ CPUFREQ_RELATION_H); else if (policy->min > cpu_cur_freq[cpu]) __cpufreq_driver_target(¤t_policy[cpu], policy->min, + CPUFREQ_RELATION_L); + else + __cpufreq_driver_target(¤t_policy[cpu], cpu_cur_freq[cpu], CPUFREQ_RELATION_L); memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); up(&userspace_sem); diff -Nru a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c --- a/drivers/cpufreq/proc_intf.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/cpufreq/proc_intf.c 2004-10-18 14:56:13 -07:00 @@ -12,9 +12,12 @@ #include #include +#warning This module will be removed from the 2.6. kernel series soon after 2005-01-01 #define CPUFREQ_ALL_CPUS ((NR_CPUS)) +static unsigned int warning_print = 0; + /** * cpufreq_parse_policy - parse a policy string * @input_string: the string to parse. @@ -110,6 +113,13 @@ if (off != 0) goto end; + if (!warning_print) { + warning_print++; + printk(KERN_INFO "Access to /proc/cpufreq is deprecated and " + "will be removed from (new) 2.6. kernels soon " + "after 2005-01-01\n"); + } + p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n"); for (i=0;i>= 2; len > 0; len--, x += sizeof(u32)) { u32 val, *p32 = p; @@ -123,7 +123,7 @@ } } -static inline void xram_copy_to (xram_p x, void *p, int len) +static inline void xram_copy_to(xram_p x, void *p, int len) { for (len >>= 2; len > 0; len--, x += sizeof(u32)) { u32 tmp, *p32 = p; @@ -135,7 +135,7 @@ } } -static inline void xram_bzero (xram_p x, int len) +static inline void xram_bzero(xram_p x, int len) { for (len >>= 1; len > 0; len--, x += sizeof(u16)) sbus_writew(0, x); @@ -274,7 +274,7 @@ soc_cq req[2]; /* Request CQs */ soc_cq rsp[2]; /* Response CQs */ int soc_no; - unsigned long regs; + void __iomem *regs; xram_p xram; fc_wwn wwn; u32 imask; /* Our copy of regs->imask */ diff -Nru a/drivers/fc4/socal.c b/drivers/fc4/socal.c --- a/drivers/fc4/socal.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/fc4/socal.c 2004-10-18 14:56:29 -07:00 @@ -60,7 +60,7 @@ #define for_each_socal(s) for (s = socals; s; s = s->next) struct socal *socals = NULL; -static void socal_copy_from_xram(void *d, unsigned long xram, long size) +static void socal_copy_from_xram(void *d, void __iomem *xram, long size) { u32 *dp = (u32 *) d; while (size) { @@ -70,7 +70,7 @@ } } -static void socal_copy_to_xram(unsigned long xram, void *s, long size) +static void socal_copy_to_xram(void __iomem *xram, void *s, long size) { u32 *sp = (u32 *) s; while (size) { diff -Nru a/drivers/fc4/socal.h b/drivers/fc4/socal.h --- a/drivers/fc4/socal.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/fc4/socal.h 2004-10-18 14:56:29 -07:00 @@ -295,9 +295,9 @@ socal_cq req[4]; /* Request CQs */ socal_cq rsp[4]; /* Response CQs */ int socal_no; - unsigned long regs; - unsigned long xram; - unsigned long eeprom; + void __iomem *regs; + void __iomem *xram; + void __iomem *eeprom; fc_wwn wwn; u32 imask; /* Our copy of regs->imask */ u32 cfg; /* Our copy of regs->cfg */ diff -Nru a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig --- a/drivers/firmware/Kconfig 2004-10-18 14:55:46 -07:00 +++ b/drivers/firmware/Kconfig 2004-10-18 14:55:46 -07:00 @@ -14,8 +14,9 @@ Services real mode BIOS calls to determine which disk BIOS tries boot from. This information is then exported via sysfs. - This option is experimental, but believed to be safe, - and most disk controller BIOS vendors do not yet implement this feature. + This option is experimental and is known to fail to boot on some + obscure configurations. Most disk controller BIOS vendors do + not yet implement this feature. config EFI_VARS tristate "EFI Variable Support via sysfs" diff -Nru a/drivers/i2c/Makefile b/drivers/i2c/Makefile --- a/drivers/i2c/Makefile 2004-10-18 14:55:54 -07:00 +++ b/drivers/i2c/Makefile 2004-10-18 14:55:54 -07:00 @@ -7,6 +7,9 @@ obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o obj-y += busses/ chips/ algos/ +i2c-sensor-objs := i2c-sensor-detect.o i2c-sensor-vid.o + + ifeq ($(CONFIG_I2C_DEBUG_CORE),y) EXTRA_CFLAGS += -DDEBUG endif diff -Nru a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig --- a/drivers/i2c/algos/Kconfig 2004-10-18 14:56:50 -07:00 +++ b/drivers/i2c/algos/Kconfig 2004-10-18 14:56:50 -07:00 @@ -27,6 +27,17 @@ This support is also available as a module. If so, the module will be called i2c-algo-pcf. +config I2C_ALGOPCA + tristate "I2C PCA 9564 interfaces" + depends on I2C + help + This allows you to use a range of I2C adapters called PCA adapters. + Say Y if you own an I2C adapter belonging to this class and then say + Y to the specific driver for you adapter below. + + This support is also available as a module. If so, the module + will be called i2c-algo-pca. + config I2C_ALGOITE tristate "ITE I2C Algorithm" depends on MIPS_ITE8172 && I2C diff -Nru a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile --- a/drivers/i2c/algos/Makefile 2004-10-18 14:56:48 -07:00 +++ b/drivers/i2c/algos/Makefile 2004-10-18 14:56:48 -07:00 @@ -4,6 +4,7 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o +obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) diff -Nru a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c --- a/drivers/i2c/algos/i2c-algo-bit.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/i2c/algos/i2c-algo-bit.c 2004-10-18 14:56:32 -07:00 @@ -565,8 +565,8 @@ MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); MODULE_LICENSE("GPL"); -MODULE_PARM(bit_test, "i"); -MODULE_PARM(i2c_debug,"i"); +module_param(bit_test, bool, 0); +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); MODULE_PARM_DESC(i2c_debug, diff -Nru a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c --- a/drivers/i2c/algos/i2c-algo-ite.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/i2c/algos/i2c-algo-ite.c 2004-10-18 14:57:03 -07:00 @@ -52,21 +52,15 @@ #define PM_IBSR IT8172_PCI_IO_BASE + IT_PM_DSR + 0x04 #define GPIO_CCR IT8172_PCI_IO_BASE + IT_GPCCR -/* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x #define DEB2(x) if (i2c_debug>=2) x #define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ -#define DEBPROTO(x) if (i2c_debug>=9) x; - /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 16 -/* ----- global variables --------------------------------------------- */ - /* module parameters: */ -static int i2c_debug=1; -static int iic_test=0; /* see if the line-setting functions work */ +static int i2c_debug; +static int iic_test; /* see if the line-setting functions work */ /* --- setting states on the bus with the right timing: --------------- */ @@ -804,8 +798,8 @@ MODULE_DESCRIPTION("ITE iic algorithm"); MODULE_LICENSE("GPL"); -MODULE_PARM(iic_test, "i"); -MODULE_PARM(i2c_debug,"i"); +module_param(iic_test, bool, 0); +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available"); MODULE_PARM_DESC(i2c_debug, diff -Nru a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/algos/i2c-algo-pca.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,395 @@ +/* + * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters + * Copyright (C) 2004 Arcom Control Systems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-algo-pca.h" + +#define DRIVER "i2c-algo-pca" + +#define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0) +#define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) +#define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0) + +static int i2c_debug=0; + +#define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val) +#define pca_inw(adap, reg) adap->read_byte(adap, reg) + +#define pca_status(adap) pca_inw(adap, I2C_PCA_STA) +#define pca_clock(adap) adap->get_clock(adap) +#define pca_own(adap) adap->get_own(adap) +#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) +#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) +#define pca_wait(adap) adap->wait_for_interrupt(adap) + +/* + * Generate a start condition on the i2c bus. + * + * returns after the start condition has occured + */ +static void pca_start(struct i2c_algo_pca_data *adap) +{ + int sta = pca_get_con(adap); + DEB2("=== START\n"); + sta |= I2C_PCA_CON_STA; + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + pca_wait(adap); +} + +/* + * Generate a repeated start condition on the i2c bus + * + * return after the repeated start condition has occured + */ +static void pca_repeated_start(struct i2c_algo_pca_data *adap) +{ + int sta = pca_get_con(adap); + DEB2("=== REPEATED START\n"); + sta |= I2C_PCA_CON_STA; + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + pca_wait(adap); +} + +/* + * Generate a stop condition on the i2c bus + * + * returns after the stop condition has been generated + * + * STOPs do not generate an interrupt or set the SI flag, since the + * part returns the the idle state (0xf8). Hence we don't need to + * pca_wait here. + */ +static void pca_stop(struct i2c_algo_pca_data *adap) +{ + int sta = pca_get_con(adap); + DEB2("=== STOP\n"); + sta |= I2C_PCA_CON_STO; + sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI); + pca_set_con(adap, sta); +} + +/* + * Send the slave address and R/W bit + * + * returns after the address has been sent + */ +static void pca_address(struct i2c_algo_pca_data *adap, + struct i2c_msg *msg) +{ + int sta = pca_get_con(adap); + int addr; + + addr = ( (0x7f & msg->addr) << 1 ); + if (msg->flags & I2C_M_RD ) + addr |= 1; + DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n", + msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr); + + pca_outw(adap, I2C_PCA_DAT, addr); + + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + + pca_wait(adap); +} + +/* + * Transmit a byte. + * + * Returns after the byte has been transmitted + */ +static void pca_tx_byte(struct i2c_algo_pca_data *adap, + __u8 b) +{ + int sta = pca_get_con(adap); + DEB2("=== WRITE %#04x\n", b); + pca_outw(adap, I2C_PCA_DAT, b); + + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + + pca_wait(adap); +} + +/* + * Receive a byte + * + * returns immediately. + */ +static void pca_rx_byte(struct i2c_algo_pca_data *adap, + __u8 *b, int ack) +{ + *b = pca_inw(adap, I2C_PCA_DAT); + DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK"); +} + +/* + * Setup ACK or NACK for next received byte and wait for it to arrive. + * + * Returns after next byte has arrived. + */ +static void pca_rx_ack(struct i2c_algo_pca_data *adap, + int ack) +{ + int sta = pca_get_con(adap); + + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA); + + if ( ack ) + sta |= I2C_PCA_CON_AA; + + pca_set_con(adap, sta); + pca_wait(adap); +} + +/* + * Reset the i2c bus / SIO + */ +static void pca_reset(struct i2c_algo_pca_data *adap) +{ + /* apparently only an external reset will do it. not a lot can be done */ + printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n"); +} + +static int pca_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], + int num) +{ + struct i2c_algo_pca_data *adap = i2c_adap->algo_data; + struct i2c_msg *msg = NULL; + int curmsg; + int numbytes = 0; + int state; + + state = pca_status(adap); + if ( state != 0xF8 ) { + printk(KERN_ERR DRIVER ": bus is not idle. status is %#04x\n", state ); + /* FIXME: what to do. Force stop ? */ + return -EREMOTEIO; + } + + DEB1("{{{ XFER %d messages\n", num); + + if (i2c_debug>=2) { + for (curmsg = 0; curmsg < num; curmsg++) { + int addr, i; + msg = &msgs[curmsg]; + + addr = (0x7f & msg->addr) ; + + if (msg->flags & I2C_M_RD ) + printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n", + curmsg, msg->len, addr, (addr<<1) | 1); + else { + printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s", + curmsg, msg->len, addr, addr<<1, + msg->len == 0 ? "" : ", "); + for(i=0; i < msg->len; i++) + printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", "); + printk("]\n"); + } + } + } + + curmsg = 0; + while (curmsg < num) { + state = pca_status(adap); + + DEB3("STATE is 0x%02x\n", state); + msg = &msgs[curmsg]; + + switch (state) { + case 0xf8: /* On reset or stop the bus is idle */ + pca_start(adap); + break; + + case 0x08: /* A START condition has been transmitted */ + case 0x10: /* A repeated start condition has been transmitted */ + pca_address(adap, msg); + break; + + case 0x18: /* SLA+W has been transmitted; ACK has been received */ + case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */ + if (numbytes < msg->len) { + pca_tx_byte(adap, msg->buf[numbytes]); + numbytes++; + break; + } + curmsg++; numbytes = 0; + if (curmsg == num) + pca_stop(adap); + else + pca_repeated_start(adap); + break; + + case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */ + DEB2("NOT ACK recieved after SLA+W\n"); + pca_stop(adap); + return -EREMOTEIO; + + case 0x40: /* SLA+R has been transmitted; ACK has been received */ + pca_rx_ack(adap, msg->len > 1); + break; + + case 0x50: /* Data bytes has been received; ACK has been returned */ + if (numbytes < msg->len) { + pca_rx_byte(adap, &msg->buf[numbytes], 1); + numbytes++; + pca_rx_ack(adap, numbytes < msg->len - 1); + break; + } + curmsg++; numbytes = 0; + if (curmsg == num) + pca_stop(adap); + else + pca_repeated_start(adap); + break; + + case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */ + DEB2("NOT ACK received after SLA+R\n"); + pca_stop(adap); + return -EREMOTEIO; + + case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */ + DEB2("NOT ACK recieved after data byte\n"); + return -EREMOTEIO; + + case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */ + DEB2("Arbitration lost\n"); + return -EREMOTEIO; + + case 0x58: /* Data byte has been received; NOT ACK has been returned */ + if ( numbytes == msg->len - 1 ) { + pca_rx_byte(adap, &msg->buf[numbytes], 0); + curmsg++; numbytes = 0; + if (curmsg == num) + pca_stop(adap); + else + pca_repeated_start(adap); + } else { + DEB2("NOT ACK sent after data byte received. " + "Not final byte. numbytes %d. len %d\n", + numbytes, msg->len); + pca_stop(adap); + return -EREMOTEIO; + } + break; + case 0x70: /* Bus error - SDA stuck low */ + DEB2("BUS ERROR - SDA Stuck low\n"); + pca_reset(adap); + return -EREMOTEIO; + case 0x90: /* Bus error - SCL stuck low */ + DEB2("BUS ERROR - SCL Stuck low\n"); + pca_reset(adap); + return -EREMOTEIO; + case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */ + DEB2("BUS ERROR - Illegal START or STOP\n"); + pca_reset(adap); + return -EREMOTEIO; + default: + printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state); + break; + } + + } + + DEB1(KERN_CRIT "}}} transfered %d messages. " + "status is %#04x. control is %#04x\n", + num, pca_status(adap), + pca_get_con(adap)); + return curmsg; +} + +static u32 pca_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static int pca_init(struct i2c_algo_pca_data *adap) +{ + static int freqs[] = {330,288,217,146,88,59,44,36}; + int own, clock; + + own = pca_own(adap); + clock = pca_clock(adap); + DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own); + DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]); + + pca_outw(adap, I2C_PCA_ADR, own << 1); + + pca_set_con(adap, I2C_PCA_CON_ENSIO | clock); + udelay(500); /* 500 µs for oscilator to stabilise */ + + return 0; +} + +static struct i2c_algorithm pca_algo = { + .name = "PCA9564 algorithm", + .id = I2C_ALGO_PCA, + .master_xfer = pca_xfer, + .functionality = pca_func, +}; + +/* + * registering functions to load algorithms at runtime + */ +int i2c_pca_add_bus(struct i2c_adapter *adap) +{ + struct i2c_algo_pca_data *pca_adap = adap->algo_data; + int rval; + + /* register new adapter to i2c module... */ + + adap->id |= pca_algo.id; + adap->algo = &pca_algo; + + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + + rval = pca_init(pca_adap); + + if (!rval) + i2c_add_adapter(adap); + + return rval; +} + +int i2c_pca_del_bus(struct i2c_adapter *adap) +{ + return i2c_del_adapter(adap); +} + +EXPORT_SYMBOL(i2c_pca_add_bus); +EXPORT_SYMBOL(i2c_pca_del_bus); + +MODULE_AUTHOR("Ian Campbell "); +MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); +MODULE_LICENSE("GPL"); + +module_param(i2c_debug, int, 0); diff -Nru a/drivers/i2c/algos/i2c-algo-pca.h b/drivers/i2c/algos/i2c-algo-pca.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/algos/i2c-algo-pca.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,26 @@ +#ifndef I2C_PCA9564_H +#define I2C_PCA9564_H 1 + +#define I2C_PCA_STA 0x00 /* STATUS Read Only */ +#define I2C_PCA_TO 0x00 /* TIMEOUT Write Only */ +#define I2C_PCA_DAT 0x01 /* DATA Read/Write */ +#define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */ +#define I2C_PCA_CON 0x03 /* CONTROL Read/Write */ + +#define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */ +#define I2C_PCA_CON_ENSIO 0x40 /* Enable */ +#define I2C_PCA_CON_STA 0x20 /* Start */ +#define I2C_PCA_CON_STO 0x10 /* Stop */ +#define I2C_PCA_CON_SI 0x08 /* Serial Interrupt */ +#define I2C_PCA_CON_CR 0x07 /* Clock Rate (MASK) */ + +#define I2C_PCA_CON_330kHz 0x00 +#define I2C_PCA_CON_288kHz 0x01 +#define I2C_PCA_CON_217kHz 0x02 +#define I2C_PCA_CON_146kHz 0x03 +#define I2C_PCA_CON_88kHz 0x04 +#define I2C_PCA_CON_59kHz 0x05 +#define I2C_PCA_CON_44kHz 0x06 +#define I2C_PCA_CON_36kHz 0x07 + +#endif /* I2C_PCA9564_H */ diff -Nru a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c --- a/drivers/i2c/algos/i2c-algo-pcf.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/i2c/algos/i2c-algo-pcf.c 2004-10-18 14:56:49 -07:00 @@ -38,8 +38,6 @@ #include "i2c-algo-pcf.h" -/* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x #define DEB2(x) if (i2c_debug>=2) x #define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ #define DEBPROTO(x) if (i2c_debug>=9) x; @@ -48,7 +46,7 @@ /* module parameters: */ -static int i2c_debug=0; +static int i2c_debug; /* --- setting states on the bus with the right timing: --------------- */ @@ -101,12 +99,6 @@ } -static inline void pcf_sleep(unsigned long timeout) -{ - schedule_timeout( timeout * HZ); -} - - static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { int timeout = DEF_TIMEOUT; @@ -472,6 +464,6 @@ MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); MODULE_LICENSE("GPL"); -MODULE_PARM(i2c_debug,"i"); +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig --- a/drivers/i2c/busses/Kconfig 2004-10-18 14:56:50 -07:00 +++ b/drivers/i2c/busses/Kconfig 2004-10-18 14:56:50 -07:00 @@ -164,6 +164,17 @@ This support is also available as a module. If so, the module will be called i2c-ixp4xx. +config I2C_IXP2000 + tristate "IXP2000 GPIO-Based I2C Interface" + depends on I2C && ARCH_IXP2000 + select I2C_ALGOBIT + help + Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based + system and are using GPIO lines for an I2C bus. + + This support is also available as a module. If so, the module + will be called i2c-ixp2000. + config I2C_KEYWEST tristate "Powermac Keywest I2C interface" depends on I2C && PPC_PMAC @@ -174,6 +185,18 @@ This support is also available as a module. If so, the module will be called i2c-keywest. +config I2C_MPC + tristate "MPC107/824x/85xx/52xx" + depends on I2C && FSL_OCP + help + If you say yes to this option, support will be included for the + built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and + MPC85xx family processors. The driver may also work on 52xx + family processors, though interrupts are known not to work. + + This driver can also be built as a module. If so, the module + will be called i2c-mpc. + config I2C_NFORCE2 tristate "Nvidia Nforce2" depends on I2C && PCI && EXPERIMENTAL @@ -395,5 +418,16 @@ This driver can also be built as a module. If so, the module will be called i2c-voodoo3. + +config I2C_PCA_ISA + tristate "PCA9564 on an ISA bus" + depends on I2C + select I2C_ALGOPCA + help + This driver supports ISA boards using the Philips PCA 9564 + Parallel bus to I2C bus controller + + This driver can also be built as a module. If so, the module + will be called i2c-pca-isa. endmenu diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile --- a/drivers/i2c/busses/Makefile 2004-10-18 14:55:54 -07:00 +++ b/drivers/i2c/busses/Makefile 2004-10-18 14:55:54 -07:00 @@ -15,11 +15,14 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_ISA) += i2c-isa.o obj-$(CONFIG_I2C_ITE) += i2c-ite.o +obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o +obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o +obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o diff -Nru a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c --- a/drivers/i2c/busses/i2c-ali1563.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/i2c/busses/i2c-ali1563.c 2004-10-18 14:56:33 -07:00 @@ -395,7 +395,7 @@ }; static struct pci_driver ali1563_pci_driver = { - .name = "i2c-ali1563", + .name = "ali1563_i2c", .id_table = ali1563_id_table, .probe = ali1563_probe, .remove = ali1563_remove, diff -Nru a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c --- a/drivers/i2c/busses/i2c-ali15x3.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/i2c/busses/i2c-ali15x3.c 2004-10-18 14:56:32 -07:00 @@ -126,8 +126,8 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static u16 force_addr = 0; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); @@ -509,7 +509,7 @@ } static struct pci_driver ali15x3_driver = { - .name = "ali15x3 smbus", + .name = "ali15x3_smbus", .id_table = ali15x3_ids, .probe = ali15x3_probe, .remove = __devexit_p(ali15x3_remove), diff -Nru a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c --- a/drivers/i2c/busses/i2c-amd756.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/i2c/busses/i2c-amd756.c 2004-10-18 14:56:50 -07:00 @@ -394,7 +394,7 @@ } static struct pci_driver amd756_driver = { - .name = "amd756 smbus", + .name = "amd756_smbus", .id_table = amd756_ids, .probe = amd756_probe, .remove = __devexit_p(amd756_remove), diff -Nru a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c --- a/drivers/i2c/busses/i2c-amd8111.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/i2c/busses/i2c-amd8111.c 2004-10-18 14:56:49 -07:00 @@ -392,7 +392,7 @@ } static struct pci_driver amd8111_driver = { - .name = "amd8111 smbus 2", + .name = "amd8111_smbus2", .id_table = amd8111_ids, .probe = amd8111_probe, .remove = __devexit_p(amd8111_remove), diff -Nru a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c --- a/drivers/i2c/busses/i2c-elektor.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/i2c/busses/i2c-elektor.c 2004-10-18 14:55:54 -07:00 @@ -269,11 +269,11 @@ MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); MODULE_LICENSE("GPL"); -MODULE_PARM(base, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(clock, "i"); -MODULE_PARM(own, "i"); -MODULE_PARM(mmapped, "i"); +module_param(base, int, 0); +module_param(irq, int, 0); +module_param(clock, int, 0); +module_param(own, int, 0); +module_param(mmapped, int, 0); module_init(i2c_pcfisa_init); module_exit(i2c_pcfisa_exit); diff -Nru a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c --- a/drivers/i2c/busses/i2c-hydra.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/i2c/busses/i2c-hydra.c 2004-10-18 14:56:28 -07:00 @@ -158,7 +158,7 @@ static struct pci_driver hydra_driver = { - .name = "hydra smbus", + .name = "hydra_smbus", .id_table = hydra_ids, .probe = hydra_probe, .remove = __devexit_p(hydra_remove), diff -Nru a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c --- a/drivers/i2c/busses/i2c-i801.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/i2c/busses/i2c-i801.c 2004-10-18 14:56:31 -07:00 @@ -98,8 +98,8 @@ /* If force_addr is set to anything different from 0, we forcibly enable the I801 at the given address. VERY DANGEROUS! */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static u16 force_addr; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Forcibly enable the I801 at the given address. " "EXTREMELY DANGEROUS!"); @@ -623,7 +623,7 @@ } static struct pci_driver i801_driver = { - .name = "i801 smbus", + .name = "i801_smbus", .id_table = i801_ids, .probe = i801_probe, .remove = __devexit_p(i801_remove), diff -Nru a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c --- a/drivers/i2c/busses/i2c-i810.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/i2c/busses/i2c-i810.c 2004-10-18 14:56:13 -07:00 @@ -231,7 +231,7 @@ } static struct pci_driver i810_driver = { - .name = "i810 smbus", + .name = "i810_smbus", .id_table = i810_ids, .probe = i810_probe, .remove = __devexit_p(i810_remove), diff -Nru a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c --- a/drivers/i2c/busses/i2c-ibm_iic.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/i2c/busses/i2c-ibm_iic.c 2004-10-18 14:56:48 -07:00 @@ -50,12 +50,12 @@ MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); MODULE_LICENSE("GPL"); -static int iic_force_poll = 0; -MODULE_PARM(iic_force_poll, "i"); +static int iic_force_poll; +module_param(iic_force_poll, bool, 0); MODULE_PARM_DESC(iic_force_poll, "Force polling mode"); -static int iic_force_fast = 0; -MODULE_PARM(iic_force_fast, "i"); +static int iic_force_fast; +module_param(iic_force_fast, bool, 0); MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)"); #define DBG_LEVEL 0 diff -Nru a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c --- a/drivers/i2c/busses/i2c-ite.c 2004-10-18 14:56:19 -07:00 +++ b/drivers/i2c/busses/i2c-ite.c 2004-10-18 14:56:19 -07:00 @@ -54,10 +54,10 @@ #define DEFAULT_CLOCK 0x1b0e /* default 16MHz/(27+14) = 400KHz */ #define DEFAULT_OWN 0x55 -static int base = 0; -static int irq = 0; -static int clock = 0; -static int own = 0; +static int base; +static int irq; +static int clock; +static int own; static struct iic_ite gpi; static wait_queue_head_t iic_wait; @@ -102,14 +102,6 @@ } -#if 0 -static void iic_ite_sleep(unsigned long timeout) -{ - schedule_timeout( timeout * HZ); -} -#endif - - /* Put this process to sleep. We will wake up when the * IIC controller interrupts. */ @@ -254,10 +246,10 @@ MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter"); MODULE_LICENSE("GPL"); -MODULE_PARM(base, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(clock, "i"); -MODULE_PARM(own, "i"); +module_param(base, int, 0); +module_param(irq, int, 0); +module_param(clock, int, 0); +module_param(own, int, 0); /* Called when module is loaded or when kernel is initialized. diff -Nru a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/busses/i2c-ixp2000.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,171 @@ +/* + * drivers/i2c/busses/i2c-ixp2000.c + * + * I2C adapter for IXP2000 systems using GPIOs for I2C bus + * + * Author: Deepak Saxena + * Based on IXDP2400 code by: Naeem M. Afzal + * Made generic by: Jeff Daly + * + * Copyright (c) 2003-2004 MontaVista Software Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * From Jeff Daly: + * + * I2C adapter driver for Intel IXDP2xxx platforms. This should work for any + * IXP2000 platform if it uses the HW GPIO in the same manner. Basically, + * SDA and SCL GPIOs have external pullups. Setting the respective GPIO to + * an input will make the signal a '1' via the pullup. Setting them to + * outputs will pull them down. + * + * The GPIOs are open drain signals and are used as configuration strap inputs + * during power-up so there's generally a buffer on the board that needs to be + * 'enabled' to drive the GPIOs. + */ + +#include +#ifdef CONFIG_I2C_DEBUG_BUS +#define DEBUG 1 +#endif + +#include +#include +#include +#include +#include +#include + +#include /* Pick up IXP42000-specific bits */ + +static inline int ixp2000_scl_pin(void *data) +{ + return ((struct ixp2000_i2c_pins*)data)->scl_pin; +} + +static inline int ixp2000_sda_pin(void *data) +{ + return ((struct ixp2000_i2c_pins*)data)->sda_pin; +} + + +static void ixp2000_bit_setscl(void *data, int val) +{ + int i = 5000; + + if (val) { + gpio_line_config(ixp2000_scl_pin(data), GPIO_IN); + while(!gpio_line_get(ixp2000_scl_pin(data)) && i--); + } else { + gpio_line_config(ixp2000_scl_pin(data), GPIO_OUT); + } +} + +static void ixp2000_bit_setsda(void *data, int val) +{ + if (val) { + gpio_line_config(ixp2000_sda_pin(data), GPIO_IN); + } else { + gpio_line_config(ixp2000_sda_pin(data), GPIO_OUT); + } +} + +static int ixp2000_bit_getscl(void *data) +{ + return gpio_line_get(ixp2000_scl_pin(data)); +} + +static int ixp2000_bit_getsda(void *data) +{ + return gpio_line_get(ixp2000_sda_pin(data)); +} + +struct ixp2000_i2c_data { + struct ixp2000_i2c_pins *gpio_pins; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo_data; +}; + +static int ixp2000_i2c_remove(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct ixp2000_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev); + + dev_set_drvdata(&plat_dev->dev, NULL); + + i2c_bit_del_bus(&drv_data->adapter); + + kfree(drv_data); + + return 0; +} + +static int ixp2000_i2c_probe(struct device *dev) +{ + int err; + struct platform_device *plat_dev = to_platform_device(dev); + struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data; + struct ixp2000_i2c_data *drv_data = + kmalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL); + + if (!drv_data) + return -ENOMEM; + memzero(drv_data, sizeof(*drv_data)); + drv_data->gpio_pins = gpio; + + drv_data->algo_data.data = gpio; + drv_data->algo_data.setsda = ixp2000_bit_setsda; + drv_data->algo_data.setscl = ixp2000_bit_setscl; + drv_data->algo_data.getsda = ixp2000_bit_getsda; + drv_data->algo_data.getscl = ixp2000_bit_getscl; + drv_data->algo_data.udelay = 6; + drv_data->algo_data.mdelay = 6; + drv_data->algo_data.timeout = 100; + + drv_data->adapter.id = I2C_HW_B_IXP2000, + drv_data->adapter.algo_data = &drv_data->algo_data, + + drv_data->adapter.dev.parent = &plat_dev->dev; + + gpio_line_config(gpio->sda_pin, GPIO_IN); + gpio_line_config(gpio->scl_pin, GPIO_IN); + gpio_line_set(gpio->scl_pin, 0); + gpio_line_set(gpio->sda_pin, 0); + + if ((err = i2c_bit_add_bus(&drv_data->adapter)) != 0) { + dev_err(dev, "Could not install, error %d\n", err); + kfree(drv_data); + return err; + } + + dev_set_drvdata(&plat_dev->dev, drv_data); + + return 0; +} + +static struct device_driver ixp2000_i2c_driver = { + .name = "IXP2000-I2C", + .bus = &platform_bus_type, + .probe = ixp2000_i2c_probe, + .remove = ixp2000_i2c_remove, +}; + +static int __init ixp2000_i2c_init(void) +{ + return driver_register(&ixp2000_i2c_driver); +} + +static void __exit ixp2000_i2c_exit(void) +{ + driver_unregister(&ixp2000_i2c_driver); +} + +module_init(ixp2000_i2c_init); +module_exit(ixp2000_i2c_exit); + +MODULE_AUTHOR ("Deepak Saxena "); +MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver"); +MODULE_LICENSE("GPL"); + diff -Nru a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c --- a/drivers/i2c/busses/i2c-keywest.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/i2c/busses/i2c-keywest.c 2004-10-18 14:56:48 -07:00 @@ -88,12 +88,12 @@ }; #endif /* DEBUG */ +static int probe; + MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); MODULE_LICENSE("GPL"); -MODULE_PARM(probe, "i"); - -static int probe = 0; +module_param(probe, bool, 0); #ifdef POLLED_MODE /* Don't schedule, the g5 fan controller is too @@ -662,8 +662,7 @@ spin_lock_irq(&iface->lock); while (iface->state != state_idle) { spin_unlock_irq(&iface->lock); - set_task_state(current,TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); spin_lock_irq(&iface->lock); } #endif /* POLLED_MODE */ diff -Nru a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/busses/i2c-mpc.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,392 @@ +/* + * (C) Copyright 2003-2004 + * Humboldt Solutions Ltd, adrian@humboldt.co.uk. + + * This is a combined i2c adapter and algorithm driver for the + * MPC107/Tsi107 PowerPC northbridge and processors that include + * the same I2C unit (8240, 8245, 85xx). + * + * Release 0.6 + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPC_I2C_ADDR 0x00 +#define MPC_I2C_FDR 0x04 +#define MPC_I2C_CR 0x08 +#define MPC_I2C_SR 0x0c +#define MPC_I2C_DR 0x10 +#define MPC_I2C_DFSRR 0x14 +#define MPC_I2C_REGION 0x20 + +#define CCR_MEN 0x80 +#define CCR_MIEN 0x40 +#define CCR_MSTA 0x20 +#define CCR_MTX 0x10 +#define CCR_TXAK 0x08 +#define CCR_RSTA 0x04 + +#define CSR_MCF 0x80 +#define CSR_MAAS 0x40 +#define CSR_MBB 0x20 +#define CSR_MAL 0x10 +#define CSR_SRW 0x04 +#define CSR_MIF 0x02 +#define CSR_RXAK 0x01 + +struct mpc_i2c { + char *base; + struct ocp_def *ocpdef; + u32 interrupt; + wait_queue_head_t queue; + struct i2c_adapter adap; +}; + +static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x) +{ + writeb(x, i2c->base + MPC_I2C_CR); +} + +static irqreturn_t mpc_i2c_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mpc_i2c *i2c = dev_id; + if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) { + /* Read again to allow register to stabilise */ + i2c->interrupt = readb(i2c->base + MPC_I2C_SR); + writeb(0, i2c->base + MPC_I2C_SR); + wake_up_interruptible(&i2c->queue); + } + return IRQ_HANDLED; +} + +static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long orig_jiffies = jiffies; + u32 x; + int result = 0; + + if (i2c->ocpdef->irq == OCP_IRQ_NA) { + while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) { + schedule(); + if (time_after(jiffies, orig_jiffies + timeout)) { + pr_debug("I2C: timeout\n"); + result = -EIO; + break; + } + } + x = readb(i2c->base + MPC_I2C_SR); + writeb(0, i2c->base + MPC_I2C_SR); + } else { + add_wait_queue(&i2c->queue, &wait); + while (!(i2c->interrupt & CSR_MIF)) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + pr_debug("I2C: Interrupted\n"); + result = -EINTR; + break; + } + if (time_after(jiffies, orig_jiffies + timeout)) { + pr_debug("I2C: timeout\n"); + result = -EIO; + break; + } + schedule_timeout(timeout); + } + current->state = TASK_RUNNING; + remove_wait_queue(&i2c->queue, &wait); + x = i2c->interrupt; + i2c->interrupt = 0; + } + + if (result < -0) + return result; + + if (!(x & CSR_MCF)) { + pr_debug("I2C: unfinished\n"); + return -EIO; + } + + if (x & CSR_MAL) { + pr_debug("I2C: MAL\n"); + return -EIO; + } + + if (writing && (x & CSR_RXAK)) { + pr_debug("I2C: No RXAK\n"); + /* generate stop */ + writeccr(i2c, CCR_MEN); + return -EIO; + } + return 0; +} + +static void mpc_i2c_setclock(struct mpc_i2c *i2c) +{ + struct ocp_fs_i2c_data *i2c_data = i2c->ocpdef->additions; + /* Set clock and filters */ + if (i2c_data && (i2c_data->flags & FS_I2C_SEPARATE_DFSRR)) { + writeb(0x31, i2c->base + MPC_I2C_FDR); + writeb(0x10, i2c->base + MPC_I2C_DFSRR); + } else if (i2c_data && (i2c_data->flags & FS_I2C_CLOCK_5200)) + writeb(0x3f, i2c->base + MPC_I2C_FDR); + else + writel(0x1031, i2c->base + MPC_I2C_FDR); +} + +static void mpc_i2c_start(struct mpc_i2c *i2c) +{ + /* Clear arbitration */ + writeb(0, i2c->base + MPC_I2C_SR); + /* Start with MEN */ + writeccr(i2c, CCR_MEN); +} + +static void mpc_i2c_stop(struct mpc_i2c *i2c) +{ + writeccr(i2c, CCR_MEN); +} + +static int mpc_write(struct mpc_i2c *i2c, int target, + const u8 * data, int length, int restart) +{ + int i; + unsigned timeout = HZ; + u32 flags = restart ? CCR_RSTA : 0; + + /* Start with MEN */ + if (!restart) + writeccr(i2c, CCR_MEN); + /* Start as master */ + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); + /* Write target byte */ + writeb((target << 1), i2c->base + MPC_I2C_DR); + + if (i2c_wait(i2c, timeout, 1) < 0) + return -1; + + for (i = 0; i < length; i++) { + /* Write data byte */ + writeb(data[i], i2c->base + MPC_I2C_DR); + + if (i2c_wait(i2c, timeout, 1) < 0) + return -1; + } + + return 0; +} + +static int mpc_read(struct mpc_i2c *i2c, int target, + u8 * data, int length, int restart) +{ + unsigned timeout = HZ; + int i; + u32 flags = restart ? CCR_RSTA : 0; + + /* Start with MEN */ + if (!restart) + writeccr(i2c, CCR_MEN); + /* Switch to read - restart */ + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); + /* Write target address byte - this time with the read flag set */ + writeb((target << 1) | 1, i2c->base + MPC_I2C_DR); + + if (i2c_wait(i2c, timeout, 1) < 0) + return -1; + + if (length) { + if (length == 1) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); + else + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA); + /* Dummy read */ + readb(i2c->base + MPC_I2C_DR); + } + + for (i = 0; i < length; i++) { + if (i2c_wait(i2c, timeout, 0) < 0) + return -1; + + /* Generate txack on next to last byte */ + if (i == length - 2) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); + /* Generate stop on last byte */ + if (i == length - 1) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK); + data[i] = readb(i2c->base + MPC_I2C_DR); + } + + return length; +} + +static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + int i; + int ret = 0; + unsigned long orig_jiffies = jiffies; + struct mpc_i2c *i2c = i2c_get_adapdata(adap); + + mpc_i2c_start(i2c); + + /* Allow bus up to 1s to become not busy */ + while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { + if (signal_pending(current)) { + pr_debug("I2C: Interrupted\n"); + return -EINTR; + } + if (time_after(jiffies, orig_jiffies + HZ)) { + pr_debug("I2C: timeout\n"); + return -EIO; + } + schedule(); + } + + for (i = 0; ret >= 0 && i < num; i++) { + pmsg = &msgs[i]; + pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, pmsg->addr, i + 1, num); + if (pmsg->flags & I2C_M_RD) + ret = + mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); + else + ret = + mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); + } + mpc_i2c_stop(i2c); + return (ret < 0) ? ret : num; +} + +static u32 mpc_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm mpc_algo = { + .name = "MPC algorithm", + .id = I2C_ALGO_MPC107, + .master_xfer = mpc_xfer, + .functionality = mpc_functionality, +}; + +static struct i2c_adapter mpc_ops = { + .owner = THIS_MODULE, + .name = "MPC adapter", + .id = I2C_ALGO_MPC107 | I2C_HW_MPC107, + .algo = &mpc_algo, + .class = I2C_CLASS_HWMON, + .timeout = 1, + .retries = 1 +}; + +static int __devinit mpc_i2c_probe(struct ocp_device *ocp) +{ + int result = 0; + struct mpc_i2c *i2c; + + if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) { + return -ENOMEM; + } + i2c->ocpdef = ocp->def; + init_waitqueue_head(&i2c->queue); + + if (!request_mem_region(ocp->def->paddr, MPC_I2C_REGION, "i2c-mpc")) { + printk(KERN_ERR "i2c-mpc - resource unavailable\n"); + return -ENODEV; + } + + i2c->base = ioremap(ocp->def->paddr, MPC_I2C_REGION); + + if (!i2c->base) { + printk(KERN_ERR "i2c-mpc - failed to map controller\n"); + result = -ENOMEM; + goto fail_map; + } + + if (ocp->def->irq != OCP_IRQ_NA) + if ((result = request_irq(ocp->def->irq, mpc_i2c_isr, + 0, "i2c-mpc", i2c)) < 0) { + printk(KERN_ERR + "i2c-mpc - failed to attach interrupt\n"); + goto fail_irq; + } + + i2c->adap = mpc_ops; + i2c_set_adapdata(&i2c->adap, i2c); + if ((result = i2c_add_adapter(&i2c->adap)) < 0) { + printk(KERN_ERR "i2c-mpc - failed to add adapter\n"); + goto fail_add; + } + + mpc_i2c_setclock(i2c); + ocp_set_drvdata(ocp, i2c); + return result; + + fail_add: + if (ocp->def->irq != OCP_IRQ_NA) + free_irq(ocp->def->irq, 0); + fail_irq: + iounmap(i2c->base); + fail_map: + release_mem_region(ocp->def->paddr, MPC_I2C_REGION); + kfree(i2c); + return result; +} +static void __devexit mpc_i2c_remove(struct ocp_device *ocp) +{ + struct mpc_i2c *i2c = ocp_get_drvdata(ocp); + ocp_set_drvdata(ocp, NULL); + i2c_del_adapter(&i2c->adap); + + if (ocp->def->irq != OCP_IRQ_NA) + free_irq(i2c->ocpdef->irq, i2c); + iounmap(i2c->base); + release_mem_region(i2c->ocpdef->paddr, MPC_I2C_REGION); + kfree(i2c); +} + +static struct ocp_device_id mpc_iic_ids[] __devinitdata = { + {.vendor = OCP_VENDOR_FREESCALE,.function = OCP_FUNC_IIC}, + {.vendor = OCP_VENDOR_INVALID} +}; + +MODULE_DEVICE_TABLE(ocp, mpc_iic_ids); + +static struct ocp_driver mpc_iic_driver = { + .name = "iic", + .id_table = mpc_iic_ids, + .probe = mpc_i2c_probe, + .remove = __devexit_p(mpc_i2c_remove) +}; + +static int __init iic_init(void) +{ + return ocp_register_driver(&mpc_iic_driver); +} + +static void __exit iic_exit(void) +{ + ocp_unregister_driver(&mpc_iic_driver); +} + +module_init(iic_init); +module_exit(iic_exit); + +MODULE_AUTHOR("Adrian Cox "); +MODULE_DESCRIPTION + ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c --- a/drivers/i2c/busses/i2c-nforce2.c 2004-10-18 14:56:15 -07:00 +++ b/drivers/i2c/busses/i2c-nforce2.c 2004-10-18 14:56:15 -07:00 @@ -244,8 +244,7 @@ temp = inb_p(NVIDIA_SMB_STS); } if (~temp & NVIDIA_SMB_STS_DONE) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/100); + msleep(10); temp = inb_p(NVIDIA_SMB_STS); } @@ -384,7 +383,7 @@ } static struct pci_driver nforce2_driver = { - .name = "nForce2 SMBus", + .name = "nForce2_smbus", .id_table = nforce2_ids, .probe = nforce2_probe, .remove = __devexit_p(nforce2_remove), diff -Nru a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c --- a/drivers/i2c/busses/i2c-parport-light.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/i2c/busses/i2c-parport-light.c 2004-10-18 14:56:49 -07:00 @@ -36,8 +36,8 @@ #define DEFAULT_BASE 0x378 -static int base; -MODULE_PARM(base, "i"); +static u16 base; +module_param(base, ushort, 0); MODULE_PARM_DESC(base, "Base I/O address"); /* ----- Low-level parallel port access ----------------------------------- */ diff -Nru a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h --- a/drivers/i2c/busses/i2c-parport.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/i2c/busses/i2c-parport.h 2004-10-18 14:57:04 -07:00 @@ -83,7 +83,7 @@ }; static int type; -MODULE_PARM(type, "i"); +module_param(type, int, 0); MODULE_PARM_DESC(type, "Type of adapter:\n" " 0 = Philips adapter\n" diff -Nru a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/busses/i2c-pca-isa.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,184 @@ +/* + * i2c-pca-isa.c driver for PCA9564 on ISA boards + * Copyright (C) 2004 Arcom Control Systems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "../algos/i2c-algo-pca.h" + +#define IO_SIZE 4 + +#undef DEBUG_IO +//#define DEBUG_IO + +static unsigned long base = 0x330; +static int irq = 10; + +/* Data sheet recommends 59kHz for 100kHz operation due to variation + * in the actual clock rate */ +static int clock = I2C_PCA_CON_59kHz; + +static int own = 0x55; + +static wait_queue_head_t pca_wait; + +static int pca_isa_getown(struct i2c_algo_pca_data *adap) +{ + return (own); +} + +static int pca_isa_getclock(struct i2c_algo_pca_data *adap) +{ + return (clock); +} + +static void +pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val) +{ +#ifdef DEBUG_IO + static char *names[] = { "T/O", "DAT", "ADR", "CON" }; + printk("*** write %s at %#lx <= %#04x\n", names[reg], base+reg, val); +#endif + outb(val, base+reg); +} + +static int +pca_isa_readbyte(struct i2c_algo_pca_data *adap, int reg) +{ + int res = inb(base+reg); +#ifdef DEBUG_IO + { + static char *names[] = { "STA", "DAT", "ADR", "CON" }; + printk("*** read %s => %#04x\n", names[reg], res); + } +#endif + return res; +} + +static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap) +{ + int ret = 0; + + if (irq > -1) { + ret = wait_event_interruptible(pca_wait, + pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI); + } else { + while ((pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) + udelay(100); + } + return ret; +} + +static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) { + wake_up_interruptible(&pca_wait); + return IRQ_HANDLED; +} + +static struct i2c_algo_pca_data pca_isa_data = { + .get_own = pca_isa_getown, + .get_clock = pca_isa_getclock, + .write_byte = pca_isa_writebyte, + .read_byte = pca_isa_readbyte, + .wait_for_interrupt = pca_isa_waitforinterrupt, +}; + +static struct i2c_adapter pca_isa_ops = { + .owner = THIS_MODULE, + .id = I2C_HW_A_ISA, + .algo_data = &pca_isa_data, + .name = "PCA9564 ISA Adapter", +}; + +static int __init pca_isa_init(void) +{ + + init_waitqueue_head(&pca_wait); + + printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq); + + if (!request_region(base, IO_SIZE, "i2c-pca-isa")) { + printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base); + goto out; + } + + if (irq > -1) { + if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) { + printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq); + goto out_region; + } + } + + if (i2c_pca_add_bus(&pca_isa_ops) < 0) { + printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n"); + goto out_irq; + } + + return 0; + + out_irq: + if (irq > -1) + free_irq(irq, &pca_isa_ops); + out_region: + release_region(base, IO_SIZE); + out: + return -ENODEV; +} + +static void pca_isa_exit(void) +{ + i2c_pca_del_bus(&pca_isa_ops); + + if (irq > 0) { + disable_irq(irq); + free_irq(irq, &pca_isa_ops); + } + release_region(base, IO_SIZE); +} + +MODULE_AUTHOR("Ian Campbell "); +MODULE_DESCRIPTION("ISA base PCA9564 driver"); +MODULE_LICENSE("GPL"); + +module_param(base, ulong, 0); +MODULE_PARM_DESC(base, "I/O base address"); + +module_param(irq, int, 0); +MODULE_PARM_DESC(irq, "IRQ"); +module_param(clock, int, 0); +MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet"); + +module_param(own, int, 0); /* the driver can't do slave mode, so there's no real point in this */ + +module_init(pca_isa_init); +module_exit(pca_isa_exit); diff -Nru a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c --- a/drivers/i2c/busses/i2c-piix4.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/i2c/busses/i2c-piix4.c 2004-10-18 14:56:27 -07:00 @@ -493,7 +493,7 @@ } static struct pci_driver piix4_driver = { - .name = "piix4-smbus", + .name = "piix4_smbus", .id_table = piix4_ids, .probe = piix4_probe, .remove = __devexit_p(piix4_remove), diff -Nru a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c --- a/drivers/i2c/busses/i2c-prosavage.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/i2c/busses/i2c-prosavage.c 2004-10-18 14:56:28 -07:00 @@ -314,7 +314,7 @@ }; static struct pci_driver prosavage_driver = { - .name = "prosavage-smbus", + .name = "prosavage_smbus", .id_table = prosavage_pci_tbl, .probe = prosavage_probe, .remove = prosavage_remove, diff -Nru a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c --- a/drivers/i2c/busses/i2c-savage4.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/i2c/busses/i2c-savage4.c 2004-10-18 14:56:29 -07:00 @@ -178,7 +178,7 @@ } static struct pci_driver savage4_driver = { - .name = "savage4 smbus", + .name = "savage4_smbus", .id_table = savage4_ids, .probe = savage4_probe, .remove = __devexit_p(savage4_remove), diff -Nru a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c --- a/drivers/i2c/busses/i2c-sis5595.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/i2c/busses/i2c-sis5595.c 2004-10-18 14:56:28 -07:00 @@ -124,8 +124,8 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static u16 force_addr = 0; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); static unsigned short sis5595_base = 0; @@ -393,7 +393,7 @@ } static struct pci_driver sis5595_driver = { - .name = "sis5595 smbus", + .name = "sis5595_smbus", .id_table = sis5595_ids, .probe = sis5595_probe, .remove = __devexit_p(sis5595_remove), diff -Nru a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c --- a/drivers/i2c/busses/i2c-sis630.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/i2c/busses/i2c-sis630.c 2004-10-18 14:56:27 -07:00 @@ -94,11 +94,11 @@ #define SIS630_BLOCK_DATA 0x05 /* insmod parameters */ -static int high_clock = 0; -static int force = 0; -MODULE_PARM(high_clock, "i"); +static int high_clock; +static int force; +module_param(high_clock, bool, 0); MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); -MODULE_PARM(force, "i"); +module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); /* acpi base address */ @@ -145,7 +145,7 @@ dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock); /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */ - if (high_clock > 0) + if (high_clock) sis630_write(SMB_CNT, 0x20); else sis630_write(SMB_CNT, (*oldclock & ~0x40)); @@ -210,7 +210,7 @@ * restore old Host Master Clock if high_clock is set * and oldclock was not 56KHz */ - if (high_clock > 0 && !(oldclock & 0x20)) + if (high_clock && !(oldclock & 0x20)) sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20)); dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); @@ -401,7 +401,7 @@ if (dummy) { pci_dev_put(dummy); } - else if (force > 0) { + else if (force) { dev_err(&sis630_dev->dev, "WARNING: Can't detect SIS630 compatible device, but " "loading because of force option enabled\n"); } @@ -464,6 +464,7 @@ static struct pci_device_id sis630_ids[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, + { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { 0, } }; @@ -494,7 +495,7 @@ static struct pci_driver sis630_driver = { - .name = "sis630 smbus", + .name = "sis630_smbus", .id_table = sis630_ids, .probe = sis630_probe, .remove = __devexit_p(sis630_remove), diff -Nru a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c --- a/drivers/i2c/busses/i2c-sis96x.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/i2c/busses/i2c-sis96x.c 2004-10-18 14:56:28 -07:00 @@ -339,7 +339,7 @@ } static struct pci_driver sis96x_driver = { - .name = "sis96x smbus", + .name = "sis96x_smbus", .id_table = sis96x_ids, .probe = sis96x_probe, .remove = __devexit_p(sis96x_remove), diff -Nru a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c --- a/drivers/i2c/busses/i2c-via.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/i2c/busses/i2c-via.c 2004-10-18 14:56:32 -07:00 @@ -158,7 +158,7 @@ static struct pci_driver vt586b_driver = { - .name = "vt586b smbus", + .name = "vt586b_smbus", .id_table = vt586b_ids, .probe = vt586b_probe, .remove = __devexit_p(vt586b_remove), diff -Nru a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c --- a/drivers/i2c/busses/i2c-viapro.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/i2c/busses/i2c-viapro.c 2004-10-18 14:56:49 -07:00 @@ -92,13 +92,13 @@ /* If force is set to anything different from 0, we forcibly enable the VT596. DANGEROUS! */ static int force; -MODULE_PARM(force, "i"); +module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!"); /* If force_addr is set to anything different from 0, we forcibly enable the VT596 at the given address. VERY DANGEROUS! */ -static int force_addr; -MODULE_PARM(force_addr, "i"); +static u16 force_addr; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Forcibly enable the SMBus at the given address. " "EXTREMELY DANGEROUS!"); @@ -455,7 +455,7 @@ }; static struct pci_driver vt596_driver = { - .name = "vt596 smbus", + .name = "vt596_smbus", .id_table = vt596_ids, .probe = vt596_probe, .remove = __devexit_p(vt596_remove), diff -Nru a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c --- a/drivers/i2c/busses/i2c-voodoo3.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/i2c/busses/i2c-voodoo3.c 2004-10-18 14:56:29 -07:00 @@ -224,7 +224,7 @@ } static struct pci_driver voodoo3_driver = { - .name = "voodoo3 smbus", + .name = "voodoo3_smbus", .id_table = voodoo3_ids, .probe = voodoo3_probe, .remove = __devexit_p(voodoo3_remove), diff -Nru a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c --- a/drivers/i2c/busses/scx200_acb.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/i2c/busses/scx200_acb.c 2004-10-18 14:56:31 -07:00 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,8 @@ #define MAX_DEVICES 4 static int base[MAX_DEVICES] = { 0x820, 0x840 }; -MODULE_PARM(base, "1-4i"); +static int num_base; +module_param_array(base, int, num_base, 0); MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers"); #ifdef DEBUG @@ -254,7 +256,7 @@ scx200_acb_machine(iface, status); return; } - schedule_timeout(HZ/100+1); + msleep(10); } scx200_acb_timeout(iface); diff -Nru a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c --- a/drivers/i2c/busses/scx200_i2c.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/i2c/busses/scx200_i2c.c 2004-10-18 14:56:29 -07:00 @@ -38,13 +38,13 @@ MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(scl, "i"); -MODULE_PARM_DESC(scl, "GPIO line for SCL"); -MODULE_PARM(sda, "i"); -MODULE_PARM_DESC(sda, "GPIO line for SDA"); - static int scl = CONFIG_SCx200_I2C_SCL; static int sda = CONFIG_SCx200_I2C_SDA; + +module_param(scl, int, 0); +MODULE_PARM_DESC(scl, "GPIO line for SCL"); +module_param(sda, int, 0); +MODULE_PARM_DESC(sda, "GPIO line for SDA"); static void scx200_i2c_setscl(void *data, int state) { diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig 2004-10-18 14:56:32 -07:00 +++ b/drivers/i2c/chips/Kconfig 2004-10-18 14:56:32 -07:00 @@ -149,7 +149,7 @@ config SENSORS_LM83 tristate "National Semiconductor LM83" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for National Semiconductor @@ -191,6 +191,19 @@ This driver can also be built as a module. If so, the module will be called max1619. +config SENSORS_SMSC47M1 + tristate "SMSC LPC47M10x and compatibles" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated fan + monitoring and control capabilities of the SMSC LPC47B27x, + LPC47M10x, LPC47M13x and LPC47M14x chips. + + This driver can also be built as a module. If so, the module + will be called smsc47m1. + config SENSORS_VIA686A tristate "VIA686A" depends on I2C && PCI && EXPERIMENTAL @@ -285,5 +298,17 @@ This driver can also be built as a module. If so, the module will be called i2c-rtc8564. + +config ISP1301_OMAP + tristate "Philips ISP1301 with OMAP OTG" + depends on I2C && ARCH_OMAP_OTG + help + If you say yes here you get support for the Philips ISP1301 + USB-On-The-Go transceiver working with the OMAP OTG controller. + The ISP1301 is used in products including H2 and H3 development + boards for Texas Instruments OMAP processors. + + This driver can also be built as a module. If so, the module + will be called isp1301_omap. endmenu diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile --- a/drivers/i2c/chips/Makefile 2004-10-18 14:57:19 -07:00 +++ b/drivers/i2c/chips/Makefile 2004-10-18 14:57:19 -07:00 @@ -26,9 +26,12 @@ obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o +obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG endif + diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c --- a/drivers/i2c/chips/adm1021.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/i2c/chips/adm1021.c 2004-10-18 14:55:54 -07:00 @@ -418,7 +418,7 @@ MODULE_DESCRIPTION("adm1021 driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(read_only, "i"); +module_param(read_only, bool, 0); MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); module_init(sensors_adm1021_init) diff -Nru a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c --- a/drivers/i2c/chips/adm1025.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/i2c/chips/adm1025.c 2004-10-18 14:55:46 -07:00 @@ -455,7 +455,7 @@ struct adm1025_data *data = i2c_get_clientdata(client); int i; - data->vrm = 82; + data->vrm = i2c_which_vrm(); /* * Set high limits diff -Nru a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c --- a/drivers/i2c/chips/asb100.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/i2c/chips/asb100.c 2004-10-18 14:56:32 -07:00 @@ -63,9 +63,6 @@ static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; -/* default VRM to 9.0 instead of 8.2 */ -#define ASB100_DEFAULT_VRM 90 - /* Insmod parameters */ SENSORS_INSMOD_1(asb100); I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " @@ -523,9 +520,9 @@ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); #define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_in0_ref) +device_create_file(&client->dev, &dev_attr_cpu0_vid) /* VRM */ static ssize_t show_vrm(struct device *dev, char *buf) @@ -959,7 +956,7 @@ vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; - data->vrm = ASB100_DEFAULT_VRM; + data->vrm = i2c_which_vrm(); vid = vid_from_reg(vid, data->vrm); /* Start monitoring */ diff -Nru a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c --- a/drivers/i2c/chips/ds1621.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/i2c/chips/ds1621.c 2004-10-18 14:57:04 -07:00 @@ -37,7 +37,7 @@ /* Insmod parameters */ SENSORS_INSMOD_1(ds1621); static int polarity = -1; -MODULE_PARM(polarity, "i"); +module_param(polarity, int, 0); MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low"); /* Many DS1621 constants specified below */ diff -Nru a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c --- a/drivers/i2c/chips/eeprom.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/i2c/chips/eeprom.c 2004-10-18 14:56:28 -07:00 @@ -45,7 +45,7 @@ SENSORS_INSMOD_1(eeprom); static int checksum = 0; -MODULE_PARM(checksum, "i"); +module_param(checksum, bool, 0); MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct"); diff -Nru a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/isp1301_omap.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,1660 @@ +/* + * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller + * + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#undef DEBUG +#undef VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#ifndef DEBUG +#undef VERBOSE +#endif + + +#define DRIVER_VERSION "24 August 2004" +#define DRIVER_NAME (isp1301_driver.name) + +MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver"); +MODULE_LICENSE("GPL"); + +struct isp1301 { + struct otg_transceiver otg; + struct i2c_client client; + void (*i2c_release)(struct device *dev); + + int irq; + + u32 last_otg_ctrl; + unsigned working:1; + + struct timer_list timer; + + /* use keventd context to change the state for us */ + struct work_struct work; + + unsigned long todo; +# define WORK_UPDATE_ISP 0 /* update ISP from OTG */ +# define WORK_UPDATE_OTG 1 /* update OTG from ISP */ +# define WORK_HOST_RESUME 4 /* resume host */ +# define WORK_TIMER 6 /* timer fired */ +# define WORK_STOP 7 /* don't resubmit */ +}; + + +/* bits in OTG_CTRL_REG */ + +#define OTG_XCEIV_OUTPUTS \ + (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID) +#define OTG_XCEIV_INPUTS \ + (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID) +#define OTG_CTRL_BITS \ + (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP) + /* and OTG_PULLUP is sometimes written */ + +#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \ + OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \ + OTG_CTRL_BITS) + + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_MACH_OMAP_H2 + +/* board-specific PM hooks */ + +#include +#include +#include + + +#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE) + +#include + +#else + +static inline int tps65010_set_vbus_draw(unsigned mA) +{ + pr_debug("tps65010: draw %d mA (STUB)\n", mA); + return 0; +} + +#endif + +static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) +{ + int status = tps65010_set_vbus_draw(mA); + if (status < 0) + pr_debug(" VBUS %d mA error %d\n", mA, status); +} + +static void enable_vbus_source(struct isp1301 *isp) +{ + /* this board won't supply more than 8mA vbus power. + * some boards can switch a 100ma "unit load" (or more). + */ +} + + +/* products will deliver OTG messages with LEDs, GUI, etc */ +static inline void notresponding(struct isp1301 *isp) +{ + printk(KERN_NOTICE "OTG device not responding.\n"); +} + + +#endif + +/*-------------------------------------------------------------------------*/ + +/* only two addresses possible */ +#define ISP_BASE 0x2c +static unsigned short normal_i2c[] = { + ISP_BASE, ISP_BASE + 1, + I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static struct i2c_driver isp1301_driver; + +/* smbus apis are used for portability */ + +static inline u8 +isp1301_get_u8(struct isp1301 *isp, u8 reg) +{ + return i2c_smbus_read_byte_data(&isp->client, reg + 0); +} + +static inline int +isp1301_get_u16(struct isp1301 *isp, u8 reg) +{ + return i2c_smbus_read_word_data(&isp->client, reg); +} + +static inline int +isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits) +{ + return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits); +} + +static inline int +isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) +{ + return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits); +} + +/*-------------------------------------------------------------------------*/ + +/* identification */ +#define ISP1301_VENDOR_ID 0x00 /* u16 read */ +#define ISP1301_PRODUCT_ID 0x02 /* u16 read */ +#define ISP1301_BCD_DEVICE 0x14 /* u16 read */ + +#define I2C_VENDOR_ID_PHILIPS 0x04cc +#define I2C_PRODUCT_ID_PHILIPS_1301 0x1301 + +/* operational registers */ +#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ +# define MC1_SPEED_REG (1 << 0) +# define MC1_SUSPEND_REG (1 << 1) +# define MC1_DAT_SE0 (1 << 2) +# define MC1_TRANSPARENT (1 << 3) +# define MC1_BDIS_ACON_EN (1 << 4) +# define MC1_OE_INT_EN (1 << 5) +# define MC1_UART_EN (1 << 6) +# define MC1_MASK 0x7f +#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ +# define MC2_GLOBAL_PWR_DN (1 << 0) +# define MC2_SPD_SUSP_CTRL (1 << 1) +# define MC2_BI_DI (1 << 2) +# define MC2_TRANSP_BDIR0 (1 << 3) +# define MC2_TRANSP_BDIR1 (1 << 4) +# define MC2_AUDIO_EN (1 << 5) +# define MC2_PSW_EN (1 << 6) +# define MC2_EN2V7 (1 << 7) +#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ +# define OTG1_DP_PULLUP (1 << 0) +# define OTG1_DM_PULLUP (1 << 1) +# define OTG1_DP_PULLDOWN (1 << 2) +# define OTG1_DM_PULLDOWN (1 << 3) +# define OTG1_ID_PULLDOWN (1 << 4) +# define OTG1_VBUS_DRV (1 << 5) +# define OTG1_VBUS_DISCHRG (1 << 6) +# define OTG1_VBUS_CHRG (1 << 7) +#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ +# define OTG_B_SESS_END (1 << 6) +# define OTG_B_SESS_VLD (1 << 7) + +#define ISP1301_INTERRUPT_SOURCE 0x08 /* u8 read */ +#define ISP1301_INTERRUPT_LATCH 0x0A /* u8 read, set, +1 clear */ + +#define ISP1301_INTERRUPT_FALLING 0x0C /* u8 read, set, +1 clear */ +#define ISP1301_INTERRUPT_RISING 0x0E /* u8 read, set, +1 clear */ + +/* same bitfields in all interrupt registers */ +# define INTR_VBUS_VLD (1 << 0) +# define INTR_SESS_VLD (1 << 1) +# define INTR_DP_HI (1 << 2) +# define INTR_ID_GND (1 << 3) +# define INTR_DM_HI (1 << 4) +# define INTR_ID_FLOAT (1 << 5) +# define INTR_BDIS_ACON (1 << 6) +# define INTR_CR_INT (1 << 7) + +/*-------------------------------------------------------------------------*/ + +static const char *state_string(enum usb_otg_state state) +{ + switch (state) { + case OTG_STATE_A_IDLE: return "a_idle"; + case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; + case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; + case OTG_STATE_A_HOST: return "a_host"; + case OTG_STATE_A_SUSPEND: return "a_suspend"; + case OTG_STATE_A_PERIPHERAL: return "a_peripheral"; + case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall"; + case OTG_STATE_A_VBUS_ERR: return "a_vbus_err"; + case OTG_STATE_B_IDLE: return "b_idle"; + case OTG_STATE_B_SRP_INIT: return "b_srp_init"; + case OTG_STATE_B_PERIPHERAL: return "b_peripheral"; + case OTG_STATE_B_WAIT_ACON: return "b_wait_acon"; + case OTG_STATE_B_HOST: return "b_host"; + default: return "UNDEFINED"; + } +} + +static inline const char *state_name(struct isp1301 *isp) +{ + return state_string(isp->otg.state); +} + +#ifdef VERBOSE +#define dev_vdbg dev_dbg +#else +#define dev_vdbg(dev, fmt, arg...) do{}while(0) +#endif + +/*-------------------------------------------------------------------------*/ + +/* NOTE: some of this ISP1301 setup is specific to H2 boards; + * not everything is guarded by board-specific checks, or even using + * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI. + * + * ALSO: this currently doesn't use ISP1301 low-power modes + * while OTG is running. + */ + +static void power_down(struct isp1301 *isp) +{ + isp->otg.state = OTG_STATE_UNDEFINED; + + // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG); + + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); +} + +static void power_up(struct isp1301 *isp) +{ + // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG); + + /* do this only when cpu is driving transceiver, + * so host won't see a low speed device... + */ + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); +} + +#define NO_HOST_SUSPEND + +static int host_suspend(struct isp1301 *isp) +{ +#ifdef NO_HOST_SUSPEND + return 0; +#else + struct device *dev; + + if (!isp->otg.host) + return -ENODEV; + + /* Currently ASSUMES only the OTG port matters; + * other ports could be active... + */ + dev = isp->otg.host->controller; + return dev->driver->suspend(dev, 3, 0); +#endif +} + +static int host_resume(struct isp1301 *isp) +{ +#ifdef NO_HOST_SUSPEND + return 0; +#else + struct device *dev; + + if (!isp->otg.host) + return -ENODEV; + + dev = isp->otg.host->controller; + return dev->driver->resume(dev, 0); +#endif +} + +static int gadget_suspend(struct isp1301 *isp) +{ + isp->otg.gadget->b_hnp_enable = 0; + isp->otg.gadget->a_hnp_support = 0; + isp->otg.gadget->a_alt_hnp_support = 0; + return usb_gadget_vbus_disconnect(isp->otg.gadget); +} + +/*-------------------------------------------------------------------------*/ + +#define TIMER_MINUTES 10 +#define TIMER_JIFFIES (TIMER_MINUTES * 60 * HZ) + +/* Almost all our I2C messaging comes from a work queue's task context. + * NOTE: guaranteeing certain response times might mean we shouldn't + * share keventd's work queue; a realtime task might be safest. + */ +void +isp1301_defer_work(struct isp1301 *isp, int work) +{ + int status; + + if (isp && !test_and_set_bit(work, &isp->todo)) { + (void) get_device(&isp->client.dev); + status = schedule_work(&isp->work); + if (!status && !isp->working) + dev_vdbg(&isp->client.dev, + "work item %d may be lost\n", work); + } +} + +/* called from irq handlers */ +static void a_idle(struct isp1301 *isp, const char *tag) +{ + if (isp->otg.state == OTG_STATE_A_IDLE) + return; + + isp->otg.default_a = 1; + if (isp->otg.host) { + isp->otg.host->is_b_host = 0; + host_suspend(isp); + } + if (isp->otg.gadget) { + isp->otg.gadget->is_a_peripheral = 1; + gadget_suspend(isp); + } + isp->otg.state = OTG_STATE_A_IDLE; + isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + pr_debug(" --> %s/%s\n", state_name(isp), tag); +} + +/* called from irq handlers */ +static void b_idle(struct isp1301 *isp, const char *tag) +{ + if (isp->otg.state == OTG_STATE_B_IDLE) + return; + + isp->otg.default_a = 0; + if (isp->otg.host) { + isp->otg.host->is_b_host = 1; + host_suspend(isp); + } + if (isp->otg.gadget) { + isp->otg.gadget->is_a_peripheral = 0; + gadget_suspend(isp); + } + isp->otg.state = OTG_STATE_B_IDLE; + isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + pr_debug(" --> %s/%s\n", state_name(isp), tag); +} + +static void +dump_regs(struct isp1301 *isp, const char *label) +{ +#ifdef DEBUG + u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1); + u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS); + u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); + + pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n", + OTG_CTRL_REG, label, state_name(isp), + ctrl, status, src); + /* mode control and irq enables don't change much */ +#endif +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_OTG + +/* + * The OMAP OTG controller handles most of the OTG state transitions. + * + * We translate isp1301 outputs (mostly voltage comparator status) into + * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state + * flags into isp1301 inputs ... and infer state transitions. + */ + +#ifdef VERBOSE + +static void check_state(struct isp1301 *isp, const char *tag) +{ + enum usb_otg_state state = OTG_STATE_UNDEFINED; + u8 fsm = OTG_TEST_REG & 0x0ff; + unsigned extra = 0; + + switch (fsm) { + + /* default-b */ + case 0x0: + state = OTG_STATE_B_IDLE; + break; + case 0x3: + case 0x7: + extra = 1; + case 0x1: + state = OTG_STATE_B_PERIPHERAL; + break; + case 0x11: + state = OTG_STATE_B_SRP_INIT; + break; + + /* extra dual-role default-b states */ + case 0x12: + case 0x13: + case 0x16: + extra = 1; + case 0x17: + state = OTG_STATE_B_WAIT_ACON; + break; + case 0x34: + state = OTG_STATE_B_HOST; + break; + + /* default-a */ + case 0x36: + state = OTG_STATE_A_IDLE; + break; + case 0x3c: + state = OTG_STATE_A_WAIT_VFALL; + break; + case 0x7d: + state = OTG_STATE_A_VBUS_ERR; + break; + case 0x9e: + case 0x9f: + extra = 1; + case 0x89: + state = OTG_STATE_A_PERIPHERAL; + break; + case 0xb7: + state = OTG_STATE_A_WAIT_VRISE; + break; + case 0xb8: + state = OTG_STATE_A_WAIT_BCON; + break; + case 0xb9: + state = OTG_STATE_A_HOST; + break; + case 0xba: + state = OTG_STATE_A_SUSPEND; + break; + default: + break; + } + if (isp->otg.state == state && !extra) + return; + pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, + state_string(state), fsm, state_name(isp), OTG_CTRL_REG); +} + +#else + +static inline void check_state(struct isp1301 *isp, const char *tag) { } + +#endif + +/* outputs from ISP1301_INTERRUPT_SOURCE */ +static void update_otg1(struct isp1301 *isp, u8 int_src) +{ + u32 otg_ctrl; + + otg_ctrl = OTG_CTRL_REG + & OTG_CTRL_MASK + & ~OTG_XCEIV_INPUTS + & ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD); + if (int_src & INTR_SESS_VLD) + otg_ctrl |= OTG_ASESSVLD; + else if (isp->otg.state == OTG_STATE_A_WAIT_VFALL) { + a_idle(isp, "vfall"); + otg_ctrl &= ~OTG_CTRL_BITS; + } + if (int_src & INTR_VBUS_VLD) + otg_ctrl |= OTG_VBUSVLD; + if (int_src & INTR_ID_GND) { /* default-A */ + if (isp->otg.state == OTG_STATE_B_IDLE + || isp->otg.state == OTG_STATE_UNDEFINED) { + a_idle(isp, "init"); + return; + } + } else { /* default-B */ + otg_ctrl |= OTG_ID; + if (isp->otg.state == OTG_STATE_A_IDLE + || isp->otg.state == OTG_STATE_UNDEFINED) { + b_idle(isp, "init"); + return; + } + } + OTG_CTRL_REG = otg_ctrl; +} + +/* outputs from ISP1301_OTG_STATUS */ +static void update_otg2(struct isp1301 *isp, u8 otg_status) +{ + u32 otg_ctrl; + + otg_ctrl = OTG_CTRL_REG + & OTG_CTRL_MASK + & ~OTG_XCEIV_INPUTS + & ~(OTG_BSESSVLD|OTG_BSESSEND); + if (otg_status & OTG_B_SESS_VLD) + otg_ctrl |= OTG_BSESSVLD; + else if (otg_status & OTG_B_SESS_END) + otg_ctrl |= OTG_BSESSEND; + OTG_CTRL_REG = otg_ctrl; +} + +/* inputs going to ISP1301 */ +static void otg_update_isp(struct isp1301 *isp) +{ + u32 otg_ctrl, otg_change; + u8 set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP; + + otg_ctrl = OTG_CTRL_REG; + otg_change = otg_ctrl ^ isp->last_otg_ctrl; + isp->last_otg_ctrl = otg_ctrl; + otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS; + + switch (isp->otg.state) { + case OTG_STATE_B_IDLE: + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_SRP_INIT: + if (!(otg_ctrl & OTG_PULLUP)) { + // if (otg_ctrl & OTG_B_HNPEN) { + if (isp->otg.gadget->b_hnp_enable) { + isp->otg.state = OTG_STATE_B_WAIT_ACON; + pr_debug(" --> b_wait_acon\n"); + } + goto pulldown; + } +pullup: + set |= OTG1_DP_PULLUP; + clr |= OTG1_DP_PULLDOWN; + break; + case OTG_STATE_A_SUSPEND: + case OTG_STATE_A_PERIPHERAL: + if (otg_ctrl & OTG_PULLUP) + goto pullup; + /* FALLTHROUGH */ + // case OTG_STATE_B_WAIT_ACON: + default: +pulldown: + set |= OTG1_DP_PULLDOWN; + clr |= OTG1_DP_PULLUP; + break; + } + +# define toggle(OTG,ISP) do { \ + if (otg_ctrl & OTG) set |= ISP; \ + else clr |= ISP; \ + } while (0) + + if (!(isp->otg.host)) + otg_ctrl &= ~OTG_DRV_VBUS; + + switch (isp->otg.state) { + case OTG_STATE_A_SUSPEND: + if (otg_ctrl & OTG_DRV_VBUS) { + set |= OTG1_VBUS_DRV; + break; + } + /* HNP failed for some reason (A_AIDL_BDIS timeout) */ + notresponding(isp); + + /* FALLTHROUGH */ + case OTG_STATE_A_VBUS_ERR: + isp->otg.state = OTG_STATE_A_WAIT_VFALL; + pr_debug(" --> a_wait_vfall\n"); + /* FALLTHROUGH */ + case OTG_STATE_A_WAIT_VFALL: + /* FIXME usbcore thinks port power is still on ... */ + clr |= OTG1_VBUS_DRV; + break; + case OTG_STATE_A_IDLE: + if (otg_ctrl & OTG_DRV_VBUS) { + isp->otg.state = OTG_STATE_A_WAIT_VRISE; + pr_debug(" --> a_wait_vrise\n"); + } + /* FALLTHROUGH */ + default: + toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV); + } + + toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG); + toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG); + +# undef toggle + + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr); + + /* HNP switch to host or peripheral; and SRP */ + if (otg_change & OTG_PULLUP) { + switch (isp->otg.state) { + case OTG_STATE_B_IDLE: + if (clr & OTG1_DP_PULLUP) + break; + isp->otg.state = OTG_STATE_B_PERIPHERAL; + pr_debug(" --> b_peripheral\n"); + break; + case OTG_STATE_A_SUSPEND: + if (clr & OTG1_DP_PULLUP) + break; + isp->otg.state = OTG_STATE_A_PERIPHERAL; + pr_debug(" --> a_peripheral\n"); + break; + default: + break; + } + OTG_CTRL_REG |= OTG_PULLUP; + } + + check_state(isp, __FUNCTION__); + dump_regs(isp, "otg->isp1301"); +} + +static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs) +{ + u16 otg_irq = OTG_IRQ_SRC_REG; + u32 otg_ctrl; + int ret = IRQ_NONE; + struct isp1301 *isp = _isp; + + /* update ISP1301 transciever from OTG controller */ + if (otg_irq & OPRT_CHG) { + OTG_IRQ_SRC_REG = OPRT_CHG; + isp1301_defer_work(isp, WORK_UPDATE_ISP); + ret = IRQ_HANDLED; + + /* SRP to become b_peripheral failed */ + } else if (otg_irq & B_SRP_TMROUT) { + pr_debug("otg: B_SRP_TIMEOUT, %06x\n", OTG_CTRL_REG); + notresponding(isp); + + /* gadget drivers that care should monitor all kinds of + * remote wakeup (SRP, normal) using their own timer + * to give "check cable and A-device" messages. + */ + if (isp->otg.state == OTG_STATE_B_SRP_INIT) + b_idle(isp, "srp_timeout"); + + OTG_IRQ_SRC_REG = B_SRP_TMROUT; + ret = IRQ_HANDLED; + + /* HNP to become b_host failed */ + } else if (otg_irq & B_HNP_FAIL) { + pr_debug("otg: %s B_HNP_FAIL, %06x\n", + state_name(isp), OTG_CTRL_REG); + notresponding(isp); + + otg_ctrl = OTG_CTRL_REG; + otg_ctrl |= OTG_BUSDROP; + otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl; + + /* subset of b_peripheral()... */ + isp->otg.state = OTG_STATE_B_PERIPHERAL; + pr_debug(" --> b_peripheral\n"); + + OTG_IRQ_SRC_REG = B_HNP_FAIL; + ret = IRQ_HANDLED; + + /* detect SRP from B-device ... */ + } else if (otg_irq & A_SRP_DETECT) { + pr_debug("otg: %s SRP_DETECT, %06x\n", + state_name(isp), OTG_CTRL_REG); + + isp1301_defer_work(isp, WORK_UPDATE_OTG); + switch (isp->otg.state) { + case OTG_STATE_A_IDLE: + if (!isp->otg.host) + break; + isp1301_defer_work(isp, WORK_HOST_RESUME); + otg_ctrl = OTG_CTRL_REG; + otg_ctrl |= OTG_A_BUSREQ; + otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) + & ~OTG_XCEIV_INPUTS + & OTG_CTRL_MASK; + OTG_CTRL_REG = otg_ctrl; + break; + default: + break; + } + + OTG_IRQ_SRC_REG = A_SRP_DETECT; + ret = IRQ_HANDLED; + + /* timer expired: T(a_wait_bcon) and maybe T(a_wait_vrise) + * we don't track them separately + */ + } else if (otg_irq & A_REQ_TMROUT) { + otg_ctrl = OTG_CTRL_REG; + pr_info("otg: BCON_TMOUT from %s, %06x\n", + state_name(isp), otg_ctrl); + notresponding(isp); + + otg_ctrl |= OTG_BUSDROP; + otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl; + isp->otg.state = OTG_STATE_A_WAIT_VFALL; + + OTG_IRQ_SRC_REG = A_REQ_TMROUT; + ret = IRQ_HANDLED; + + /* A-supplied voltage fell too low; overcurrent */ + } else if (otg_irq & A_VBUS_ERR) { + otg_ctrl = OTG_CTRL_REG; + printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n", + state_name(isp), otg_irq, otg_ctrl); + + otg_ctrl |= OTG_BUSDROP; + otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl; + isp->otg.state = OTG_STATE_A_VBUS_ERR; + + OTG_IRQ_SRC_REG = A_VBUS_ERR; + ret = IRQ_HANDLED; + + /* switch driver; the transciever code activates it, + * ungating the udc clock or resuming OHCI. + */ + } else if (otg_irq & DRIVER_SWITCH) { + int kick = 0; + + otg_ctrl = OTG_CTRL_REG; + printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n", + state_name(isp), + (otg_ctrl & OTG_DRIVER_SEL) + ? "gadget" : "host", + otg_ctrl); + isp1301_defer_work(isp, WORK_UPDATE_ISP); + + /* role is peripheral */ + if (otg_ctrl & OTG_DRIVER_SEL) { + switch (isp->otg.state) { + case OTG_STATE_A_IDLE: + b_idle(isp, __FUNCTION__); + break; + default: + break; + } + isp1301_defer_work(isp, WORK_UPDATE_ISP); + + /* role is host */ + } else { + if (!(otg_ctrl & OTG_ID)) { + otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ; + } + + if (isp->otg.host) { + switch (isp->otg.state) { + case OTG_STATE_B_WAIT_ACON: + isp->otg.state = OTG_STATE_B_HOST; + pr_debug(" --> b_host\n"); + kick = 1; + break; + case OTG_STATE_A_WAIT_BCON: + isp->otg.state = OTG_STATE_A_HOST; + pr_debug(" --> a_host\n"); + break; + case OTG_STATE_A_PERIPHERAL: + isp->otg.state = OTG_STATE_A_WAIT_BCON; + pr_debug(" --> a_wait_bcon\n"); + break; + default: + break; + } + isp1301_defer_work(isp, WORK_HOST_RESUME); + } + } + + OTG_IRQ_SRC_REG = DRIVER_SWITCH; + ret = IRQ_HANDLED; + + if (kick) + usb_bus_start_enum(isp->otg.host, + isp->otg.host->otg_port); + } + + check_state(isp, __FUNCTION__); + return ret; +} + +static struct platform_device *otg_dev; + +static int otg_init(struct isp1301 *isp) +{ + if (!otg_dev) + return -ENODEV; + + dump_regs(isp, __FUNCTION__); + /* some of these values are board-specific... */ + OTG_SYSCON_2_REG |= OTG_EN + /* for B-device: */ + | SRP_GPDATA /* 9msec Bdev D+ pulse */ + | SRP_GPDVBUS /* discharge after VBUS pulse */ + // | (3 << 24) /* 2msec VBUS pulse */ + /* for A-device: */ + | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */ + | SRP_DPW /* detect 167+ns SRP pulses */ + | SRP_DATA | SRP_VBUS /* accept both kinds of SRP pulse */ + ; + + update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); + update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); + + check_state(isp, __FUNCTION__); + pr_debug("otg: %s, %s %06x\n", + state_name(isp), __FUNCTION__, OTG_CTRL_REG); + + OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG + | B_SRP_TMROUT | B_HNP_FAIL + | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT; + OTG_SYSCON_2_REG |= OTG_EN; + + return 0; +} + +static int otg_probe(struct device *dev) +{ + // struct omap_usb_config *config = dev->platform_data; + + otg_dev = to_platform_device(dev); + return 0; +} + +static int otg_remove(struct device *dev) +{ + otg_dev = 0; + return 0; +} + +struct device_driver omap_otg_driver = { + .name = "omap_otg", + .bus = &platform_bus_type, + .probe = otg_probe, + .remove = otg_remove, +}; + +static int otg_bind(struct isp1301 *isp) +{ + int status; + + if (otg_dev) + return -EBUSY; + + status = driver_register(&omap_otg_driver); + if (status < 0) + return status; + + if (otg_dev) + status = request_irq(otg_dev->resource[1].start, omap_otg_irq, + SA_INTERRUPT, DRIVER_NAME, isp); + else + status = -ENODEV; + + if (status < 0) + driver_unregister(&omap_otg_driver); + return status; +} + +static void otg_unbind(struct isp1301 *isp) +{ + if (!otg_dev) + return; + free_irq(otg_dev->resource[1].start, isp); +} + +#else + +/* OTG controller isn't clocked */ + +#endif /* CONFIG_USB_OTG */ + +/*-------------------------------------------------------------------------*/ + +static void b_peripheral(struct isp1301 *isp) +{ + enable_vbus_draw(isp, 8); + OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + usb_gadget_vbus_connect(isp->otg.gadget); + +#ifdef CONFIG_USB_OTG + otg_update_isp(isp); +#else + /* UDC driver just set OTG_BSESSVLD */ + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); + isp->otg.state = OTG_STATE_B_PERIPHERAL; + pr_debug(" --> b_peripheral\n"); + dump_regs(isp, "2periph"); +#endif +} + +static int isp_update_otg(struct isp1301 *isp, u8 stat) +{ + u8 isp_stat, isp_bstat; + enum usb_otg_state state = isp->otg.state; + + if (stat & INTR_BDIS_ACON) + pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp)); + + /* start certain state transitions right away */ + isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); + if (isp_stat & INTR_ID_GND) { + if (isp->otg.default_a) { + switch (state) { + case OTG_STATE_B_IDLE: + a_idle(isp, "idle"); + /* FALLTHROUGH */ + case OTG_STATE_A_IDLE: + enable_vbus_source(isp); + /* FALLTHROUGH */ + case OTG_STATE_A_WAIT_VRISE: + /* we skip over OTG_STATE_A_WAIT_BCON, since + * the HC will transition to A_HOST (or + * A_SUSPEND!) without our noticing except + * when HNP is used. + */ + if (isp_stat & INTR_VBUS_VLD) + isp->otg.state = OTG_STATE_A_HOST; + break; + case OTG_STATE_A_WAIT_VFALL: + if (!(isp_stat & INTR_SESS_VLD)) + a_idle(isp, "vfell"); + break; + default: + if (!(isp_stat & INTR_VBUS_VLD)) + isp->otg.state = OTG_STATE_A_VBUS_ERR; + break; + } + isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); + } else { + switch (state) { + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_HOST: + case OTG_STATE_B_WAIT_ACON: + usb_gadget_vbus_disconnect(isp->otg.gadget); + break; + default: + break; + } + if (state != OTG_STATE_A_IDLE) + a_idle(isp, "id"); + if (isp->otg.host && state == OTG_STATE_A_IDLE) + isp1301_defer_work(isp, WORK_HOST_RESUME); + isp_bstat = 0; + } + } else { + /* if user unplugged mini-A end of cable, + * don't bypass A_WAIT_VFALL. + */ + if (isp->otg.default_a) { + switch (state) { + default: + isp->otg.state = OTG_STATE_A_WAIT_VFALL; + break; + case OTG_STATE_A_WAIT_VFALL: + state = OTG_STATE_A_IDLE; + /* khubd may take a while to notice and + * handle this disconnect, so don't go + * to B_IDLE quite yet. + */ + break; + case OTG_STATE_A_IDLE: + host_suspend(isp); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, + MC1_BDIS_ACON_EN); + isp->otg.state = OTG_STATE_B_IDLE; + OTG_CTRL_REG &= OTG_CTRL_REG & OTG_CTRL_MASK + & ~OTG_CTRL_BITS; + break; + case OTG_STATE_B_IDLE: + break; + } + } + isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); + + switch (isp->otg.state) { + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_WAIT_ACON: + case OTG_STATE_B_HOST: + if (likely(isp_bstat & OTG_B_SESS_VLD)) + break; + enable_vbus_draw(isp, 0); +#ifndef CONFIG_USB_OTG + /* UDC driver will clear OTG_BSESSVLD */ + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, + OTG1_DP_PULLDOWN); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, + OTG1_DP_PULLUP); + dump_regs(isp, __FUNCTION__); +#endif + /* FALLTHROUGH */ + case OTG_STATE_B_SRP_INIT: + b_idle(isp, __FUNCTION__); + OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + /* FALLTHROUGH */ + case OTG_STATE_B_IDLE: + if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) { +#ifdef CONFIG_USB_OTG + update_otg1(isp, isp_stat); + update_otg2(isp, isp_bstat); +#endif + b_peripheral(isp); + } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD))) + isp_bstat |= OTG_B_SESS_END; + break; + case OTG_STATE_A_WAIT_VFALL: + break; + default: + pr_debug("otg: unsupported b-device %s\n", + state_name(isp)); + break; + } + } + + if (state != isp->otg.state) + pr_debug(" isp, %s -> %s\n", + state_string(state), state_name(isp)); + +#ifdef CONFIG_USB_OTG + /* update the OTG controller state to match the isp1301; may + * trigger OPRT_CHG irqs for changes going to the isp1301. + */ + update_otg1(isp, isp_stat); + update_otg2(isp, isp_bstat); + check_state(isp, __FUNCTION__); +#endif + + dump_regs(isp, "isp1301->otg"); +} + +/*-------------------------------------------------------------------------*/ + +static u8 isp1301_clear_latch(struct isp1301 *isp) +{ + u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch); + return latch; +} + +static void +isp1301_work(void *data) +{ + struct isp1301 *isp = data; + int stop; + + /* implicit lock: we're the only task using this device */ + isp->working = 1; + do { + stop = test_bit(WORK_STOP, &isp->todo); + +#ifdef CONFIG_USB_OTG + /* transfer state from otg engine to isp1301 */ + if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) { + otg_update_isp(isp); + put_device(&isp->client.dev); + } +#endif + /* transfer state from isp1301 to otg engine */ + if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) { + u8 stat = isp1301_clear_latch(isp); + + isp_update_otg(isp, stat); + put_device(&isp->client.dev); + } + + if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) { + u32 otg_ctrl; + + /* + * skip A_WAIT_VRISE; hc transitions invisibly + * skip A_WAIT_BCON; same. + */ + switch (isp->otg.state) { + case OTG_STATE_A_WAIT_BCON: + case OTG_STATE_A_WAIT_VRISE: + isp->otg.state = OTG_STATE_A_HOST; + pr_debug(" --> a_host\n"); + otg_ctrl = OTG_CTRL_REG; + otg_ctrl |= OTG_A_BUSREQ; + otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) + & OTG_CTRL_MASK; + OTG_CTRL_REG = otg_ctrl; + break; + case OTG_STATE_B_WAIT_ACON: + isp->otg.state = OTG_STATE_B_HOST; + pr_debug(" --> b_host (acon)\n"); + break; + case OTG_STATE_B_HOST: + case OTG_STATE_B_IDLE: + case OTG_STATE_A_IDLE: + break; + default: + pr_debug(" host resume in %s\n", + state_name(isp)); + } + host_resume(isp); + // mdelay(10); + put_device(&isp->client.dev); + } + + if (test_and_clear_bit(WORK_TIMER, &isp->todo)) { +#ifdef VERBOSE + dump_regs(isp, "timer"); + if (!stop) + mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); +#endif + put_device(&isp->client.dev); + } + + if (isp->todo) + dev_vdbg(&isp->client.dev, + "work done, todo = 0x%lx\n", + isp->todo); + if (stop) { + dev_dbg(&isp->client.dev, "stop\n"); + break; + } + } while (isp->todo); + isp->working = 0; +} + +static irqreturn_t isp1301_irq(int irq, void *isp, struct pt_regs *regs) +{ + isp1301_defer_work(isp, WORK_UPDATE_OTG); + return IRQ_HANDLED; +} + +static void isp1301_timer(unsigned long _isp) +{ + isp1301_defer_work((void *)_isp, WORK_TIMER); +} + +/*-------------------------------------------------------------------------*/ + +static void isp1301_release(struct device *dev) +{ + struct isp1301 *isp; + + isp = container_of(dev, struct isp1301, client.dev); + + /* ugly -- i2c hijacks our memory hook to wait_for_completion() */ + if (isp->i2c_release) + isp->i2c_release(dev); + kfree (isp); +} + +static struct isp1301 *the_transceiver; + +static int isp1301_detach_client(struct i2c_client *i2c) +{ + struct isp1301 *isp; + + isp = container_of(i2c, struct isp1301, client); + + isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); + free_irq(isp->irq, isp); +#ifdef CONFIG_USB_OTG + otg_unbind(isp); +#endif + if (machine_is_omap_h2()) + omap_free_gpio(2); + + isp->timer.data = 0; + set_bit(WORK_STOP, &isp->todo); + del_timer_sync(&isp->timer); + flush_scheduled_work(); + + put_device(&i2c->dev); + the_transceiver = 0; + + return i2c_detach_client(i2c); +} + +/*-------------------------------------------------------------------------*/ + +/* NOTE: three modes are possible here, only one of which + * will be standards-conformant on any given system: + * + * - OTG mode (dual-role), required if there's a Mini-AB connector + * - HOST mode, for when there's one or more A (host) connectors + * - DEVICE mode, for when there's a B/Mini-B (device) connector + * + * As a rule, you won't have an isp1301 chip unless it's there to + * support the OTG mode. Other modes help testing USB controllers + * in isolation from (full) OTG support, or maybe so later board + * revisions can help to support those feature. + */ + +#ifdef CONFIG_USB_OTG + +static int isp1301_otg_enable(struct isp1301 *isp) +{ + power_up(isp); + otg_init(isp); + + /* NOTE: since we don't change this, this provides + * a few more interrupts than are strictly needed. + */ + isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, + INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); + isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, + INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); + + dev_info(&isp->client.dev, "ready for dual-role USB ...\n"); + + return 0; +} + +#endif + +/* add or disable the host device+driver */ +static int +isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host) +{ + struct isp1301 *isp = container_of(otg, struct isp1301, otg); + + if (!otg || isp != the_transceiver) + return -ENODEV; + + if (!host) { + OTG_IRQ_EN_REG = 0; + power_down(isp); + isp->otg.host = 0; + return 0; + } + +#ifdef CONFIG_USB_OTG + isp->otg.host = host; + dev_dbg(&isp->client.dev, "registered host\n"); + host_suspend(isp); + if (isp->otg.gadget) + return isp1301_otg_enable(isp); + return 0; + +#elif !defined(CONFIG_USB_GADGET_OMAP) + // FIXME update its refcount + isp->otg.host = host; + + power_up(isp); + + if (machine_is_omap_h2()) + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); + + dev_info(&isp->client.dev, "A-Host sessions ok\n"); + isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, + INTR_ID_GND); + isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, + INTR_ID_GND); + + /* If this has a Mini-AB connector, this mode is highly + * nonstandard ... but can be handy for testing, especially with + * the Mini-A end of an OTG cable. (Or something nonstandard + * like MiniB-to-StandardB, maybe built with a gender mender.) + */ + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); + + dump_regs(isp, __FUNCTION__); + + return 0; + +#else + dev_dbg(&isp->client.dev, "host sessions not allowed\n"); + return -EINVAL; +#endif + +} + +static int +isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget) +{ + struct isp1301 *isp = container_of(otg, struct isp1301, otg); + + if (!otg || isp != the_transceiver) + return -ENODEV; + + if (!gadget) { + OTG_IRQ_EN_REG = 0; + if (!isp->otg.default_a) + enable_vbus_draw(isp, 0); + usb_gadget_vbus_disconnect(isp->otg.gadget); + isp->otg.gadget = 0; + power_down(isp); + return 0; + } + +#ifdef CONFIG_USB_OTG + isp->otg.gadget = gadget; + dev_dbg(&isp->client.dev, "registered gadget\n"); + /* gadget driver may be suspended until vbus_connect () */ + if (isp->otg.host) + return isp1301_otg_enable(isp); + return 0; + +#elif !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE) + isp->otg.gadget = gadget; + // FIXME update its refcount + + OTG_CTRL_REG = (OTG_CTRL_REG & OTG_CTRL_MASK + & ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS)) + | OTG_ID; + power_up(isp); + isp->otg.state = OTG_STATE_B_IDLE; + + if (machine_is_omap_h2()) + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); + + isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, + INTR_SESS_VLD); + isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, + INTR_VBUS_VLD); + dev_info(&isp->client.dev, "B-Peripheral sessions ok\n"); + dump_regs(isp, __FUNCTION__); + + /* If this has a Mini-AB connector, this mode is highly + * nonstandard ... but can be handy for testing, so long + * as you don't plug a Mini-A cable into the jack. + */ + if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD) + b_peripheral(isp); + + return 0; + +#else + dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n"); + return -EINVAL; +#endif +} + + +/*-------------------------------------------------------------------------*/ + +static int +isp1301_set_power(struct otg_transceiver *dev, unsigned mA) +{ + if (!the_transceiver) + return -ENODEV; + if (dev->state == OTG_STATE_B_PERIPHERAL) + enable_vbus_draw(the_transceiver, mA); + return 0; +} + +static int +isp1301_start_srp(struct otg_transceiver *dev) +{ + struct isp1301 *isp = container_of(dev, struct isp1301, otg); + u32 otg_ctrl; + + if (!dev || isp != the_transceiver + || isp->otg.state != OTG_STATE_B_IDLE) + return -ENODEV; + + otg_ctrl = OTG_CTRL_REG; + if (!(otg_ctrl & OTG_BSESSEND)) + return -EINVAL; + + otg_ctrl |= OTG_B_BUSREQ; + otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; + OTG_CTRL_REG = otg_ctrl; + isp->otg.state = OTG_STATE_B_SRP_INIT; + + pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), OTG_CTRL_REG); +#ifdef CONFIG_USB_OTG + check_state(isp, __FUNCTION__); +#endif + return 0; +} + +static int +isp1301_start_hnp(struct otg_transceiver *dev) +{ +#ifdef CONFIG_USB_OTG + struct isp1301 *isp = container_of(dev, struct isp1301, otg); + + if (!dev || isp != the_transceiver) + return -ENODEV; + if (isp->otg.default_a && (isp->otg.host == NULL + || !isp->otg.host->b_hnp_enable)) + return -ENOTCONN; + if (!isp->otg.default_a && (isp->otg.gadget == NULL + || !isp->otg.gadget->b_hnp_enable)) + return -ENOTCONN; + + /* We want hardware to manage most HNP protocol timings. + * So do this part as early as possible... + */ + switch (isp->otg.state) { + case OTG_STATE_B_HOST: + isp->otg.state = OTG_STATE_B_PERIPHERAL; + /* caller will suspend next */ + break; + case OTG_STATE_A_HOST: +#if 0 + /* autoconnect mode avoids irq latency bugs */ + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, + MC1_BDIS_ACON_EN); +#endif + /* caller must suspend then clear A_BUSREQ */ + usb_gadget_vbus_connect(isp->otg.gadget); + OTG_CTRL_REG |= OTG_A_SETB_HNPEN; + + break; + case OTG_STATE_A_PERIPHERAL: + /* initiated by B-Host suspend */ + break; + default: + return -EILSEQ; + } + pr_debug("otg: HNP %s, %06x ...\n", + state_name(isp), OTG_CTRL_REG); + check_state(isp, __FUNCTION__); + return 0; +#else + /* srp-only */ + return -EINVAL; +#endif +} + +/*-------------------------------------------------------------------------*/ + +/* no error returns, they'd just make bus scanning stop */ +static int isp1301_probe(struct i2c_adapter *bus, int address, int kind) +{ + int status; + struct isp1301 *isp; + struct i2c_client *i2c; + + if (the_transceiver) + return 0; + + isp = kmalloc(sizeof *isp, GFP_KERNEL); + if (!isp) + return 0; + + memset(isp, 0, sizeof *isp); + + INIT_WORK(&isp->work, isp1301_work, isp); + init_timer(&isp->timer); + isp->timer.function = isp1301_timer; + isp->timer.data = (unsigned long) isp; + + isp->irq = -1; + isp->client.addr = address; + i2c_set_clientdata(&isp->client, isp); + isp->client.adapter = bus; + isp->client.id = 1301; + isp->client.driver = &isp1301_driver; + strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE); + i2c = &isp->client; + + /* if this is a true probe, verify the chip ... */ + if (kind < 0) { + status = isp1301_get_u16(isp, ISP1301_VENDOR_ID); + if (status != I2C_VENDOR_ID_PHILIPS) { + dev_dbg(&bus->dev, "addr %d not philips id: %d\n", + address, status); + goto fail1; + } + status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID); + if (status != I2C_PRODUCT_ID_PHILIPS_1301) { + dev_dbg(&bus->dev, "%d not isp1301, %d\n", + address, status); + goto fail1; + } + } + + status = i2c_attach_client(i2c); + if (status < 0) { + dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", + DRIVER_NAME, address, status); +fail1: + kfree(isp); + return 0; + } + isp->i2c_release = i2c->dev.release; + i2c->dev.release = isp1301_release; + + /* initial development used chiprev 2.00 */ + status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE); + dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n", + status >> 8, status & 0xff); + + /* make like power-on reset */ + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK); + + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI); + + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, + OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, + ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); + + isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); + +#ifdef CONFIG_USB_OTG + status = otg_bind(isp); + if (status < 0) { + dev_dbg(&i2c->dev, "can't bind OTG\n"); + goto fail2; + } +#endif + + if (machine_is_omap_h2()) { + /* full speed signaling by default */ + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, + MC1_SPEED_REG); + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, + MC2_SPD_SUSP_CTRL); + + /* IRQ wired at M14 */ + omap_cfg_reg(M14_1510_GPIO2); + isp->irq = OMAP_GPIO_IRQ(2); + omap_request_gpio(2); + omap_set_gpio_direction(2, 1); + omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE); + } + + status = request_irq(isp->irq, isp1301_irq, + SA_SAMPLE_RANDOM, DRIVER_NAME, isp); + if (status < 0) { + dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n", + isp->irq, status); +#ifdef CONFIG_USB_OTG +fail2: +#endif + i2c_detach_client(i2c); + goto fail1; + } + + isp->otg.dev = &isp->client.dev; + isp->otg.label = DRIVER_NAME; + + isp->otg.set_host = isp1301_set_host, + isp->otg.set_peripheral = isp1301_set_peripheral, + isp->otg.set_power = isp1301_set_power, + isp->otg.start_srp = isp1301_start_srp, + isp->otg.start_hnp = isp1301_start_hnp, + + enable_vbus_draw(isp, 0); + power_down(isp); + the_transceiver = isp; + +#ifdef CONFIG_USB_OTG + update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); + update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); +#endif + + dump_regs(isp, __FUNCTION__); + +#ifdef VERBOSE + mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); + dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); +#endif + + status = otg_set_transceiver(&isp->otg); + if (status < 0) + dev_err(&i2c->dev, "can't register transceiver, %d\n", + status); + + return 0; +} + +static int isp1301_scan_bus(struct i2c_adapter *bus) +{ + if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -EINVAL; + return i2c_probe(bus, &addr_data, isp1301_probe); +} + +static struct i2c_driver isp1301_driver = { + .owner = THIS_MODULE, + .name = "isp1301_omap", + .id = 1301, /* FIXME "official", i2c-ids.h */ + .class = I2C_CLASS_HWMON, + .flags = I2C_DF_NOTIFY, + .attach_adapter = isp1301_scan_bus, + .detach_client = isp1301_detach_client, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init isp_init(void) +{ + return i2c_add_driver(&isp1301_driver); +} +module_init(isp_init); + +static void __exit isp_exit(void) +{ + if (the_transceiver) + otg_set_transceiver(0); + i2c_del_driver(&isp1301_driver); +} +module_exit(isp_exit); + diff -Nru a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c --- a/drivers/i2c/chips/it87.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/i2c/chips/it87.c 2004-10-18 14:56:49 -07:00 @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -47,7 +48,7 @@ static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_1(it87); +SENSORS_INSMOD_2(it87, it8712); #define REG 0x2e /* The register to read/write */ #define DEV 0x07 /* Register: Logical device select */ @@ -163,8 +164,6 @@ ((val)+500)/1000),-128,127)) #define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) #define ALARMS_FROM_REG(val) (val) static int DIV_TO_REG(int val) @@ -201,6 +200,7 @@ u8 sensor; /* Register value */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ + int vrm; u32 alarms; /* Register encoding, combined */ }; @@ -543,6 +543,38 @@ } static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL); +static ssize_t +show_vrm_reg(struct device *dev, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} +static ssize_t +store_vrm_reg(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm) + +static ssize_t +show_vid_reg(struct device *dev, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid) + /* This function is called when: * it87_driver is inserted (when this module is loaded), for each available adapter @@ -659,7 +691,11 @@ if (kind <= 0) { i = it87_read_value(new_client, IT87_REG_CHIPID); if (i == 0x90) { + u16 val; kind = it87; + val = (superio_inb(DEVID) << 8) | + superio_inb(DEVID + 1); + if (val == IT8712F_DEVID) kind = it8712; } else { if (kind == 0) @@ -674,6 +710,8 @@ if (kind == it87) { name = "it87"; + } else if (kind == it8712) { + name = "it8712"; } /* Fill in the remaining client fields and put it into the global list */ @@ -741,6 +779,12 @@ device_create_file(&new_client->dev, &dev_attr_fan3_div); device_create_file(&new_client->dev, &dev_attr_alarms); + if (data->type == it8712) { + device_create_file_vrm(new_client); + device_create_file_vid(new_client); + data->vrm = i2c_which_vrm(); + } + return 0; ERROR2: @@ -910,7 +954,11 @@ (it87_read_value(client, IT87_REG_ALARM3) << 16); data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); - + /* The 8705 does not have VID capability */ + if (data->type == it8712) { + data->vid = it87_read_value(client, IT87_REG_VID); + data->vid &= 0x1f; + } data->last_updated = jiffies; data->valid = 1; } @@ -938,9 +986,9 @@ MODULE_AUTHOR("Chris Gauthron "); MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); -MODULE_PARM(update_vbat, "i"); +module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); -MODULE_PARM(reset, "i"); +module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Reset the chip's registers, default no"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c --- a/drivers/i2c/chips/lm78.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/i2c/chips/lm78.c 2004-10-18 14:56:49 -07:00 @@ -423,7 +423,7 @@ struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); } -static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* Alarms */ static ssize_t show_alarms(struct device *dev, char *buf) @@ -615,7 +615,7 @@ device_create_file(&new_client->dev, &dev_attr_fan3_min); device_create_file(&new_client->dev, &dev_attr_fan3_div); device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_in0_ref); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); return 0; diff -Nru a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c --- a/drivers/i2c/chips/lm83.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/i2c/chips/lm83.c 2004-10-18 14:56:29 -07:00 @@ -83,8 +83,10 @@ * The LM83 uses signed 8-bit values. */ -#define TEMP_FROM_REG(val) ((val > 127 ? val-256 : val) * 1000) -#define TEMP_TO_REG(val) ((val < 0 ? val+256 : val) / 1000) +#define TEMP_FROM_REG(val) (((val) > 127 ? (val) - 0x100 : (val)) * 1000) +#define TEMP_TO_REG(val) ((val) <= -50000 ? -50 + 0x100 : (val) >= 127000 ? 127 : \ + (val) > -500 ? ((val)+500) / 1000 : \ + ((val)-500) / 1000 + 0x100) static const u8 LM83_REG_R_TEMP[] = { LM83_REG_R_LOCAL_TEMP, @@ -178,7 +180,7 @@ { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm83_data *data = i2c_get_clientdata(client); \ - data->value = TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \ + data->value = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \ i2c_smbus_write_byte_data(client, reg, data->value); \ return count; \ } @@ -206,8 +208,11 @@ set_temp_high3); static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4, set_temp_high4); -static DEVICE_ATTR(temp_crit, S_IWUSR | S_IRUGO, show_temp_crit, +static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL); +static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL); +static DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp_crit, set_temp_crit); +static DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -259,6 +264,11 @@ * means that the driver was loaded with the force parameter and a * given kind of chip is requested, so both the detection and the * identification steps are skipped. */ + + /* Default to an LM83 if forced */ + if (kind == 0) + kind = lm83; + if (kind < 0) { /* detection */ if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) & 0xA8) != 0x00) || @@ -322,7 +332,10 @@ device_create_file(&new_client->dev, &dev_attr_temp2_max); device_create_file(&new_client->dev, &dev_attr_temp3_max); device_create_file(&new_client->dev, &dev_attr_temp4_max); - device_create_file(&new_client->dev, &dev_attr_temp_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + device_create_file(&new_client->dev, &dev_attr_temp4_crit); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; diff -Nru a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c --- a/drivers/i2c/chips/lm85.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/i2c/chips/lm85.c 2004-10-18 14:56:28 -07:00 @@ -308,9 +308,6 @@ * version of the driver. */ -/* Typically used with Pentium 4 systems v9.1 VRM spec */ -#define LM85_INIT_VRM 91 - /* Chip sampling rates * * Some sensors are not updated more frequently than once per second @@ -468,7 +465,7 @@ return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, char *buf) { @@ -832,7 +829,7 @@ goto ERROR1; /* Set the VRM version */ - data->vrm = LM85_INIT_VRM ; + data->vrm = i2c_which_vrm(); /* Initialize the LM85 chip */ lm85_init_client(new_client); @@ -877,7 +874,7 @@ device_create_file(&new_client->dev, &dev_attr_temp2_max); device_create_file(&new_client->dev, &dev_attr_temp3_max); device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_in0_ref); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; diff -Nru a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c --- a/drivers/i2c/chips/pcf8591.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/i2c/chips/pcf8591.c 2004-10-18 14:57:19 -07:00 @@ -36,7 +36,7 @@ SENSORS_INSMOD_1(pcf8591); static int input_mode; -MODULE_PARM(input_mode, "i"); +module_param(input_mode, int, 0); MODULE_PARM_DESC(input_mode, "Analog input mode:\n" " 0 = four single ended inputs\n" diff -Nru a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c --- a/drivers/i2c/chips/rtc8564.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/i2c/chips/rtc8564.c 2004-10-18 14:55:54 -07:00 @@ -56,8 +56,8 @@ #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) #define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) -static int debug = 0; -MODULE_PARM(debug, "i"); +static int debug;; +module_param(debug, int, S_IRUGO | S_IWUSR); static struct i2c_driver rtc8564_driver; diff -Nru a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/smsc47m1.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,579 @@ +/* + smsc47m1.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x + Super-I/O chips. + + Copyright (C) 2002 Mark D. Studebaker + Copyright (C) 2004 Jean Delvare + Ported to Linux 2.6 by Gabriele Gorla + and Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +/* Address is autodetected, there is no default value */ +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{NULL}}; + +enum chips { any_chip, smsc47m1 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_i2c_range = normal_i2c_range, + .normal_isa = normal_isa, + .normal_isa_range = normal_isa_range, + .probe = normal_i2c, /* cheat */ + .probe_range = normal_i2c_range, /* cheat */ + .ignore = normal_i2c, /* cheat */ + .ignore_range = normal_i2c_range, /* cheat */ + .forces = forces, +}; + +/* Super-I/0 registers and commands */ + +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +/* logical device for fans is 0x0A */ +#define superio_select() superio_outb(0x07, 0x0A) + +static inline void +superio_enter(void) +{ + outb(0x55, REG); +} + +static inline void +superio_exit(void) +{ + outb(0xAA, REG); +} + +#define SUPERIO_REG_ACT 0x30 +#define SUPERIO_REG_BASE 0x60 +#define SUPERIO_REG_DEVID 0x20 + +/* Logical device registers */ + +#define SMSC_EXTENT 0x80 + +/* nr is 0 or 1 in the macros below */ +#define SMSC47M1_REG_ALARM 0x04 +#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) +#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) +#define SMSC47M1_REG_PWM(nr) (0x56 + (nr)) +#define SMSC47M1_REG_FANDIV 0x58 +#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) +#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) + +#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ + 983040/((192-(reg))*(div))) +#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ + 983040/(((reg)-(preload))*(div))) +#define DIV_FROM_REG(reg) (1 << (reg)) +#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) +#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) +#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) + +struct smsc47m1_data { + struct i2c_client client; + struct semaphore lock; + int sysctl_id; + + struct semaphore update_lock; + unsigned long last_updated; /* In jiffies */ + + u8 fan[2]; /* Register value */ + u8 fan_preload[2]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u8 alarms; /* Register encoding */ + u8 pwm[2]; /* Register value (bit 7 is enable) */ +}; + + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); +static int smsc47m1_find(int *address); +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind); +static int smsc47m1_detach_client(struct i2c_client *client); + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg); +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value); + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init); + + +static int smsc47m1_id; + +static struct i2c_driver smsc47m1_driver = { + .owner = THIS_MODULE, + .name = "smsc47m1", + .id = I2C_DRIVERID_SMSC47M1, + .flags = I2C_DF_NOTIFY, + .attach_adapter = smsc47m1_attach_adapter, + .detach_client = smsc47m1_detach_client, +}; + +/* nr is 0 or 1 in the callback functions below */ + +static ssize_t get_fan(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + /* This chip (stupidly) stops monitoring fan speed if PWM is + enabled and duty cycle is 0%. This is fine if the monitoring + and control concern the same fan, but troublesome if they are + not (which could as well happen). */ + int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : + FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]), + data->fan_preload[nr]); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_min(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + int rpm = MIN_FROM_REG(data->fan_preload[nr], + DIV_FROM_REG(data->fan_div[nr])); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_div(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + +static ssize_t get_fan_pwm(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_fan_pwm_en(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_alarms(struct device *dev, char *buf) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", data->alarms); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long rpmdiv = simple_strtol(buf, NULL, 10) + * DIV_FROM_REG(data->fan_div[nr]); + + if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) + return -EINVAL; + + data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + + return count; +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan clock divider. This follows the principle + of least suprise; the user doesn't expect the fan minimum to change just + because the divider changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long new_div = simple_strtol(buf, NULL, 10), tmp; + u8 old_div = DIV_FROM_REG(data->fan_div[nr]); + + if (new_div == old_div) /* No change */ + return count; + switch (new_div) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: return -EINVAL; + } + + tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; + tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); + smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); + + /* Preserve fan min */ + tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + + new_div / 2) / new_div; + data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + + return count; +} + +static ssize_t set_fan_pwm(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val < 0 || val > 255) + return -EINVAL; + + data->pwm[nr] &= 0x81; /* Preserve additional bits */ + data->pwm[nr] |= PWM_TO_REG(val); + + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + return count; +} + +static ssize_t set_fan_pwm_en(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val != 0 && val != 1) + return -EINVAL; + + data->pwm[nr] &= 0xFE; /* preserve the other bits */ + data->pwm[nr] |= !val; + + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + + return count; +} + +#define fan_present(offset) \ +static ssize_t get_fan##offset (struct device *dev, char *buf) \ +{ \ + return get_fan(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_min (struct device *dev, char *buf) \ +{ \ + return get_fan_min(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_div (struct device *dev, char *buf) \ +{ \ + return get_fan_div(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_div (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_pwm (struct device *dev, char *buf) \ +{ \ + return get_fan_pwm(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_pwm (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_pwm(dev, buf, count, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_pwm_en (struct device *dev, char *buf) \ +{ \ + return get_fan_pwm_en(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_pwm_en (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_pwm_en(dev, buf, count, 0x##offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + get_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + get_fan##offset##_div, set_fan##offset##_div); \ +static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \ + get_fan##offset##_pwm, set_fan##offset##_pwm); \ +static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, \ + get_fan##offset##_pwm_en, set_fan##offset##_pwm_en); + +fan_present(1); +fan_present(2); + +static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, smsc47m1_detect); +} + +static int smsc47m1_find(int *address) +{ + u8 val; + + superio_enter(); + val = superio_inb(SUPERIO_REG_DEVID); + + /* + * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id + * 0x5F) and LPC47B27x (device id 0x51) have fan control. + * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" + * can do much more besides (device id 0x60, unsupported). + */ + if (val == 0x51) + printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n"); + else if (val == 0x59) + printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n"); + else if (val == 0x5F) + printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n"); + else { + superio_exit(); + return -ENODEV; + } + + superio_select(); + *address = (superio_inb(SUPERIO_REG_BASE) << 8) + | superio_inb(SUPERIO_REG_BASE + 1); + val = superio_inb(SUPERIO_REG_ACT); + if (*address == 0 || (val & 0x01) == 0) { + printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n"); + superio_exit(); + return -ENODEV; + } + + superio_exit(); + return 0; +} + +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct smsc47m1_data *data; + int err = 0; + + if (!i2c_is_isa_adapter(adapter)) { + return 0; + } + + if (!request_region(address, SMSC_EXTENT, "smsc47m1")) { + dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); + return -EBUSY; + } + + if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error_release; + } + memset(data, 0x00, sizeof(struct smsc47m1_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &smsc47m1_driver; + new_client->flags = 0; + + strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); + + new_client->id = smsc47m1_id++; + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto error_free; + + /* Some values (fan min, clock dividers, pwm registers) may be + needed before any update is triggered, so we better read them + at least once here. We don't usually do it that way, but in + this particular case, manually reading 5 registers out of 8 + doesn't make much sense and we're better using the existing + function. */ + smsc47m1_update_device(&new_client->dev, 1); + + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05) + == 0x05) { + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + } else + dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " + "skipping\n"); + + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05) + == 0x05) { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + } else + dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " + "skipping\n"); + + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) + == 0x04) { + device_create_file(&new_client->dev, &dev_attr_fan1_pwm); + device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable); + } else + dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " + "skipping\n"); + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) + == 0x04) { + device_create_file(&new_client->dev, &dev_attr_fan2_pwm); + device_create_file(&new_client->dev, &dev_attr_fan2_pwm_enable); + } else + dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " + "skipping\n"); + + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error_free: + kfree(new_client); +error_release: + release_region(address, SMSC_EXTENT); + return err; +} + +static int smsc47m1_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + release_region(client->addr, SMSC_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + res = inb_p(client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + return res; +} + +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + outb_p(value, client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); +} + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || init) { + int i; + + for (i = 0; i < 2; i++) { + data->fan[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN(i)); + data->fan_preload[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN_PRELOAD(i)); + data->pwm[i] = smsc47m1_read_value(client, + SMSC47M1_REG_PWM(i)); + } + + i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + + data->alarms = smsc47m1_read_value(client, + SMSC47M1_REG_ALARM) >> 6; + /* Clear alarms if needed */ + if (data->alarms) + smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); + + data->last_updated = jiffies; + } + + up(&data->update_lock); + return data; +} + +static int __init sm_smsc47m1_init(void) +{ + if (smsc47m1_find(normal_isa)) { + return -ENODEV; + } + + return i2c_add_driver(&smsc47m1_driver); +} + +static void __exit sm_smsc47m1_exit(void) +{ + i2c_del_driver(&smsc47m1_driver); +} + +MODULE_AUTHOR("Mark D. Studebaker "); +MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_smsc47m1_init); +module_exit(sm_smsc47m1_exit); diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c --- a/drivers/i2c/chips/via686a.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/i2c/chips/via686a.c 2004-10-18 14:55:55 -07:00 @@ -43,8 +43,8 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static unsigned short force_addr = 0; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors"); diff -Nru a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c --- a/drivers/i2c/chips/w83627hf.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/i2c/chips/w83627hf.c 2004-10-18 14:56:49 -07:00 @@ -46,12 +46,12 @@ #include #include "lm75.h" -static int force_addr; -MODULE_PARM(force_addr, "i"); +static u16 force_addr; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors"); -static int force_i2c = 0x1f; -MODULE_PARM(force_i2c, "i"); +static u8 force_i2c = 0x1f; +module_param(force_i2c, byte, 0); MODULE_PARM_DESC(force_i2c, "Initialize the i2c address of the sensors"); @@ -65,7 +65,7 @@ SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf); static int init = 1; -MODULE_PARM(init, "i"); +module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); /* modified from kernel/include/traps.c */ @@ -635,9 +635,9 @@ struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); #define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_in0_ref) +device_create_file(&client->dev, &dev_attr_cpu0_vid) static ssize_t show_vrm_reg(struct device *dev, char *buf) @@ -1281,7 +1281,7 @@ data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; } else { /* Convert VID to voltage based on default VRM */ - data->vrm = DEFAULT_VRM; + data->vrm = i2c_which_vrm(); } tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- a/drivers/i2c/chips/w83781d.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/i2c/chips/w83781d.c 2004-10-18 14:55:46 -07:00 @@ -60,7 +60,7 @@ "{bus, clientaddr, subclientaddr1, subclientaddr2}"); static int init = 1; -MODULE_PARM(init, "i"); +module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); /* Constants specified below */ @@ -503,9 +503,9 @@ } static -DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL); +DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); #define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_in0_ref); +device_create_file(&client->dev, &dev_attr_cpu0_vid); static ssize_t show_vrm_reg(struct device *dev, char *buf) { @@ -815,8 +815,7 @@ data->sens[nr - 1] = val; break; default: - dev_err(&client->dev, - "Invalid sensor type %ld; must be 1, 2, or %d\n", + dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", (long) val, W83781D_DEFAULT_BETA); break; } @@ -1513,7 +1512,7 @@ w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); } - data->vrm = 82; + data->vrm = i2c_which_vrm(); if ((type != w83781d) && (type != as99127f)) { tmp = w83781d_read_value(client, W83781D_REG_SCFG1); @@ -1593,7 +1592,7 @@ if (time_after (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2)) || time_before(jiffies, data->last_updated) || !data->valid) { - pr_debug("Starting device update\n"); + dev_dbg(dev, "Starting device update\n"); for (i = 0; i <= 8; i++) { if ((data->type == w83783s || data->type == w83697hf) diff -Nru a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/i2c-sensor-detect.c 2004-10-18 14:56:32 -07:00 @@ -0,0 +1,169 @@ +/* + i2c-sensor-detect.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2001 Frodo Looijaard and + Mark D. Studebaker + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */ +int i2c_detect(struct i2c_adapter *adapter, + struct i2c_address_data *address_data, + int (*found_proc) (struct i2c_adapter *, int, int)) +{ + int addr, i, found, j, err; + struct i2c_force_data *this_force; + int is_isa = i2c_is_isa_adapter(adapter); + int adapter_id = + is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter); + + /* Forget it if we can't probe using SMBUS_QUICK */ + if ((!is_isa) && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) + return -1; + + for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { + if (!is_isa && i2c_check_addr(adapter, addr)) + continue; + + /* If it is in one of the force entries, we don't do any + detection at all */ + found = 0; + for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) { + for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) { + if ( ((adapter_id == this_force->force[j]) || + ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) && + (addr == this_force->force[j + 1]) ) { + dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr); + if ((err = found_proc(adapter, addr, this_force->kind))) + return err; + found = 1; + } + } + } + if (found) + continue; + + /* If this address is in one of the ignores, we can forget about it + right now */ + for (i = 0; !found && (address_data->ignore[i] != I2C_CLIENT_END); i += 2) { + if ( ((adapter_id == address_data->ignore[i]) || + ((address_data->ignore[i] == ANY_I2C_BUS) && + !is_isa)) && + (addr == address_data->ignore[i + 1])) { + dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->ignore_range[i] != I2C_CLIENT_END); i += 3) { + if ( ((adapter_id == address_data->ignore_range[i]) || + ((address_data-> ignore_range[i] == ANY_I2C_BUS) & + !is_isa)) && + (addr >= address_data->ignore_range[i + 1]) && + (addr <= address_data->ignore_range[i + 2])) { + dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + if (found) + continue; + + /* Now, we will do a detection, but only if it is in the normal or + probe entries */ + if (is_isa) { + for (i = 0; !found && (address_data->normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) { + if (addr == address_data->normal_isa[i]) { + dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->normal_isa_range[i] != I2C_CLIENT_ISA_END); i += 3) { + if ((addr >= address_data->normal_isa_range[i]) && + (addr <= address_data->normal_isa_range[i + 1]) && + ((addr - address_data->normal_isa_range[i]) % address_data->normal_isa_range[i + 2] == 0)) { + dev_dbg(&adapter->dev, "found normal isa_range entry for adapter %d, addr %04x", adapter_id, addr); + found = 1; + } + } + } else { + for (i = 0; !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); i += 1) { + if (addr == address_data->normal_i2c[i]) { + found = 1; + dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x", adapter_id, addr); + } + } + for (i = 0; !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); i += 2) { + if ((addr >= address_data->normal_i2c_range[i]) && + (addr <= address_data->normal_i2c_range[i + 1])) { + dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + } + + for (i = 0; + !found && (address_data->probe[i] != I2C_CLIENT_END); + i += 2) { + if (((adapter_id == address_data->probe[i]) || + ((address_data-> + probe[i] == ANY_I2C_BUS) && !is_isa)) + && (addr == address_data->probe[i + 1])) { + dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) { + if ( ((adapter_id == address_data->probe_range[i]) || + ((address_data->probe_range[i] == ANY_I2C_BUS) && !is_isa)) && + (addr >= address_data->probe_range[i + 1]) && + (addr <= address_data->probe_range[i + 2])) { + found = 1; + dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, addr %04x\n", adapter_id, addr); + } + } + if (!found) + continue; + + /* OK, so we really should examine this address. First check + whether there is some client here at all! */ + if (is_isa || + (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0)) + if ((err = found_proc(adapter, addr, -1))) + return err; + } + return 0; +} + +EXPORT_SYMBOL(i2c_detect); + +MODULE_AUTHOR("Frodo Looijaard , " + "Rudolf Marek "); + +MODULE_DESCRIPTION("i2c-sensor driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/i2c/i2c-sensor-vid.c b/drivers/i2c/i2c-sensor-vid.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/i2c-sensor-vid.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,99 @@ +/* + i2c-sensor-vid.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (c) 2004 Rudolf Marek + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +struct vrm_model { + u8 vendor; + u8 eff_family; + u8 eff_model; + int vrm_type; +}; + +#define ANY 0xFF + +#ifdef CONFIG_X86 + +static struct vrm_model vrm_models[] = { + {X86_VENDOR_AMD, 0x6, ANY, 90}, /* Athlon Duron etc */ + {X86_VENDOR_AMD, 0xF, 0x4, 90}, /* Athlon 64 */ + {X86_VENDOR_AMD, 0xF, 0x5, 24}, /* Opteron */ + {X86_VENDOR_INTEL, 0x6, 0x9, 85}, /* 0.13um too */ + {X86_VENDOR_INTEL, 0x6, 0xB, 85}, /* 0xB Tualatin */ + {X86_VENDOR_INTEL, 0x6, ANY, 82}, /* any P6 */ + {X86_VENDOR_INTEL, 0x7, ANY, 0}, /* Itanium */ + {X86_VENDOR_INTEL, 0xF, 0x3, 100}, /* P4 Prescott */ + {X86_VENDOR_INTEL, 0xF, ANY, 90}, /* P4 before Prescott */ + {X86_VENDOR_INTEL, 0x10,ANY, 0}, /* Itanium 2 */ + {X86_VENDOR_UNKNOWN, ANY, ANY, 0} /* stop here */ + }; + +static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor) +{ + int i = 0; + + while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) { + if (vrm_models[i].vendor==vendor) + if ((vrm_models[i].eff_family==eff_family)&& \ + ((vrm_models[i].eff_model==eff_model)|| \ + (vrm_models[i].eff_model==ANY))) + return vrm_models[i].vrm_type; + i++; + } + + return 0; +} + +int i2c_which_vrm(void) +{ + struct cpuinfo_x86 *c = cpu_data; + u32 eax; + u8 eff_family, eff_model; + int vrm_ret; + + if (c->x86 < 6) return 0; /* any CPU with familly lower than 6 + dont have VID and/or CPUID */ + eax = cpuid_eax(1); + eff_family = ((eax & 0x00000F00)>>8); + eff_model = ((eax & 0x000000F0)>>4); + if (eff_family == 0xF) { /* use extended model & family */ + eff_family += ((eax & 0x00F00000)>>20); + eff_model += ((eax & 0x000F0000)>>16)<<4; + } + vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor); + if (vrm_ret == 0) + printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your" + " x86 CPU\n"); + return vrm_ret; +} + +/* and now something completely different for Non-x86 world*/ +#else +int i2c_which_vrm(void) +{ + printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your CPU\n"); + return 0; +} +#endif + +EXPORT_SYMBOL(i2c_which_vrm); diff -Nru a/drivers/i2c/i2c-sensor.c b/drivers/i2c/i2c-sensor.c --- a/drivers/i2c/i2c-sensor.c 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,167 +0,0 @@ -/* - i2c-sensor.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2001 Frodo Looijaard and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */ -int i2c_detect(struct i2c_adapter *adapter, - struct i2c_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int addr, i, found, j, err; - struct i2c_force_data *this_force; - int is_isa = i2c_is_isa_adapter(adapter); - int adapter_id = - is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter); - - /* Forget it if we can't probe using SMBUS_QUICK */ - if ((!is_isa) && - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) - return -1; - - for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { - if (!is_isa && i2c_check_addr(adapter, addr)) - continue; - - /* If it is in one of the force entries, we don't do any - detection at all */ - found = 0; - for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) { - for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) { - if ( ((adapter_id == this_force->force[j]) || - ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) && - (addr == this_force->force[j + 1]) ) { - dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr); - if ((err = found_proc(adapter, addr, this_force->kind))) - return err; - found = 1; - } - } - } - if (found) - continue; - - /* If this address is in one of the ignores, we can forget about it - right now */ - for (i = 0; !found && (address_data->ignore[i] != I2C_CLIENT_END); i += 2) { - if ( ((adapter_id == address_data->ignore[i]) || - ((address_data->ignore[i] == ANY_I2C_BUS) && - !is_isa)) && - (addr == address_data->ignore[i + 1])) { - dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - for (i = 0; !found && (address_data->ignore_range[i] != I2C_CLIENT_END); i += 3) { - if ( ((adapter_id == address_data->ignore_range[i]) || - ((address_data-> ignore_range[i] == ANY_I2C_BUS) & - !is_isa)) && - (addr >= address_data->ignore_range[i + 1]) && - (addr <= address_data->ignore_range[i + 2])) { - dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - if (found) - continue; - - /* Now, we will do a detection, but only if it is in the normal or - probe entries */ - if (is_isa) { - for (i = 0; !found && (address_data->normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) { - if (addr == address_data->normal_isa[i]) { - dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - for (i = 0; !found && (address_data->normal_isa_range[i] != I2C_CLIENT_ISA_END); i += 3) { - if ((addr >= address_data->normal_isa_range[i]) && - (addr <= address_data->normal_isa_range[i + 1]) && - ((addr - address_data->normal_isa_range[i]) % address_data->normal_isa_range[i + 2] == 0)) { - dev_dbg(&adapter->dev, "found normal isa_range entry for adapter %d, addr %04x", adapter_id, addr); - found = 1; - } - } - } else { - for (i = 0; !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); i += 1) { - if (addr == address_data->normal_i2c[i]) { - found = 1; - dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x", adapter_id, addr); - } - } - for (i = 0; !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); i += 2) { - if ((addr >= address_data->normal_i2c_range[i]) && - (addr <= address_data->normal_i2c_range[i + 1])) { - dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - } - - for (i = 0; - !found && (address_data->probe[i] != I2C_CLIENT_END); - i += 2) { - if (((adapter_id == address_data->probe[i]) || - ((address_data-> - probe[i] == ANY_I2C_BUS) && !is_isa)) - && (addr == address_data->probe[i + 1])) { - dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) { - if ( ((adapter_id == address_data->probe_range[i]) || - ((address_data->probe_range[i] == ANY_I2C_BUS) && !is_isa)) && - (addr >= address_data->probe_range[i + 1]) && - (addr <= address_data->probe_range[i + 2])) { - found = 1; - dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, addr %04x\n", adapter_id, addr); - } - } - if (!found) - continue; - - /* OK, so we really should examine this address. First check - whether there is some client here at all! */ - if (is_isa || - (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0)) - if ((err = found_proc(adapter, addr, -1))) - return err; - } - return 0; -} - -EXPORT_SYMBOL(i2c_detect); - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("i2c-sensor driver"); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/ide/Kconfig b/drivers/ide/Kconfig --- a/drivers/ide/Kconfig 2004-10-18 14:56:29 -07:00 +++ b/drivers/ide/Kconfig 2004-10-18 14:56:29 -07:00 @@ -457,11 +457,6 @@ Generally say N here. -config BLK_DEV_ADMA - bool - depends on PCI && BLK_DEV_IDEPCI - default BLK_DEV_IDEDMA_PCI - config BLK_DEV_AEC62XX tristate "AEC62XX chipset support" help @@ -834,6 +829,13 @@ help Say Y here if you want to support the Yellowstone RapIDE controller manufactured for use with Acorn computers. + +config BLK_DEV_IDE_BAST + tristate "Simtec BAST / Thorcom VR1000 IDE support" + depends on ARM && (ARCH_BAST || MACH_VR100) + help + Say Y here if you want to support the onboard IDE channels on the + Simtec BAST or the Thorcom VR1000 config BLK_DEV_GAYLE bool "Amiga Gayle IDE interface support" diff -Nru a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile --- a/drivers/ide/arm/Makefile 2004-10-18 14:55:53 -07:00 +++ b/drivers/ide/arm/Makefile 2004-10-18 14:55:53 -07:00 @@ -1,5 +1,6 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o +obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o EXTRA_CFLAGS := -Idrivers/ide diff -Nru a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/ide/arm/bast-ide.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,71 @@ +/* linux/drivers/ide/arm/bast-ide.c + * + * Copyright (c) 2003-2004 Simtec Electronics + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* list of registered interfaces */ +static ide_hwif_t *ifs[2]; + +static int __init +bastide_register(unsigned int base, unsigned int aux, int irq, + ide_hwif_t **hwif) +{ + hw_regs_t hw; + int i; + + memset(&hw, 0, sizeof(hw)); + + base += BAST_IDE_CS; + aux += BAST_IDE_CS; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw.io_ports[i] = (unsigned long)base; + base += 0x20; + } + + hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20); + hw.irq = irq; + + ide_register_hw(&hw, hwif); + + return 0; +} + +static int __init bastide_init(void) +{ + /* we can treat the VR1000 and the BAST the same */ + + if (!(machine_is_bast() || machine_is_vr1000())) + return 0; + + printk("BAST: IDE driver, (c) 2003-2004 Simtec Electronics\n"); + + bastide_register(BAST_VA_IDEPRI, BAST_VA_IDEPRIAUX, IRQ_IDE0, &ifs[0]); + bastide_register(BAST_VA_IDESEC, BAST_VA_IDESECAUX, IRQ_IDE1, &ifs[1]); + return 0; +} + +module_init(bastide_init); + +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simtec BAST / Thorcom VR1000 IDE driver"); diff -Nru a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c --- a/drivers/ide/arm/icside.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/ide/arm/icside.c 2004-10-18 14:56:32 -07:00 @@ -215,8 +215,6 @@ struct scatterlist *sg = hwif->sg_table; int nents; - BUG_ON(hwif->sg_dma_active); - if (rq->flags & REQ_DRIVE_TASKFILE) { ide_task_t *args = rq->special; @@ -401,8 +399,6 @@ dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction); - hwif->sg_dma_active = 0; - return get_dma_residue(hwif->hw.dma) != 0; } @@ -454,7 +450,6 @@ /* * We can not enable DMA on both channels. */ - BUG_ON(hwif->sg_dma_active); BUG_ON(dma_channel_active(hwif->hw.dma)); icside_build_sglist(drive, rq); diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/ide/ide-cd.c 2004-10-18 14:56:29 -07:00 @@ -2719,8 +2719,10 @@ if (!cdrom_get_media_event(cdi, &med)) { if (med.media_present) return CDS_DISC_OK; - if (med.door_open) + else if (med.door_open) return CDS_TRAY_OPEN; + else + return CDS_NO_DISC; } if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04) @@ -2732,10 +2734,12 @@ * any other way to detect this... */ if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a && sense.ascq == 1) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; + if (sense.asc == 0x3a) { + if (sense.ascq == 0 || sense.ascq == 1) + return CDS_NO_DISC; + else if (sense.ascq == 2) + return CDS_TRAY_OPEN; + } } return CDS_DRIVE_NOT_READY; diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/ide/ide-disk.c 2004-10-18 14:56:29 -07:00 @@ -340,12 +340,18 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block) { ide_hwif_t *hwif = HWIF(drive); + unsigned int dma = drive->using_dma; u8 lba48 = (drive->addressing == 1) ? 1 : 0; task_ioreg_t command = WIN_NOP; ata_nsector_t nsectors; nsectors.all = (u16) rq->nr_sectors; + if (hwif->no_lba48_dma && lba48 && dma) { + if (rq->sector + rq->nr_sectors > 1ULL << 28) + dma = 0; + } + if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); @@ -414,7 +420,7 @@ } if (rq_data_dir(rq) == READ) { - if (drive->using_dma && !hwif->ide_dma_read(drive)) + if (dma && !hwif->ide_dma_read(drive)) return ide_started; command = ((drive->mult_count) ? @@ -425,7 +431,7 @@ } else { ide_startstop_t startstop; - if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive))) + if (dma && !hwif->ide_dma_write(drive)) return ide_started; command = ((drive->mult_count) ? @@ -488,31 +494,38 @@ } EXPORT_SYMBOL_GPL(__ide_do_rw_disk); -static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task) +static u8 get_command(ide_drive_t *drive, struct request *rq, ide_task_t *task) { unsigned int lba48 = (drive->addressing == 1) ? 1 : 0; + unsigned int dma = drive->using_dma; + + if (drive->hwif->no_lba48_dma && lba48 && dma) { + if (rq->sector + rq->nr_sectors > 1ULL << 28) + dma = 0; + } - if (cmd == READ) { + if (rq_data_dir(rq) == READ) { task->command_type = IDE_DRIVE_TASK_IN; - if (drive->using_dma) + if (dma) return lba48 ? WIN_READDMA_EXT : WIN_READDMA; + task->handler = &task_in_intr; if (drive->mult_count) { - task->handler = &task_mulin_intr; + task->data_phase = TASKFILE_MULTI_IN; return lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD; } - task->handler = &task_in_intr; + task->data_phase = TASKFILE_IN; return lba48 ? WIN_READ_EXT : WIN_READ; } else { task->command_type = IDE_DRIVE_TASK_RAW_WRITE; - if (drive->using_dma) + if (dma) return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; + task->prehandler = &pre_task_out_intr; + task->handler = &task_out_intr; if (drive->mult_count) { - task->prehandler = &pre_task_mulout_intr; - task->handler = &task_mulout_intr; + task->data_phase = TASKFILE_MULTI_OUT; return lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; } - task->prehandler = &pre_task_out_intr; - task->handler = &task_out_intr; + task->data_phase = TASKFILE_OUT; return lba48 ? WIN_WRITE_EXT : WIN_WRITE; } } @@ -541,9 +554,10 @@ args.tfRegister[IDE_HCYL_OFFSET] = (cyl>>8); args.tfRegister[IDE_SELECT_OFFSET] = head; args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; + drive->hwif->data_phase = args.data_phase; return do_rw_taskfile(drive, &args); } @@ -565,9 +579,10 @@ args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); args.tfRegister[IDE_SELECT_OFFSET] = ((block>>8)&0x0f); args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; + drive->hwif->data_phase = args.data_phase; return do_rw_taskfile(drive, &args); } @@ -595,7 +610,7 @@ args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ args.tfRegister[IDE_SELECT_OFFSET] = drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.hobRegister[IDE_SECTOR_OFFSET] = (block>>=8); /* low lba */ args.hobRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.hobRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ @@ -603,6 +618,7 @@ args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; + drive->hwif->data_phase = args.data_phase; return do_rw_taskfile(drive, &args); } @@ -638,7 +654,6 @@ local_irq_set(flags); printk("%s: %s: status=0x%02x", drive->name, msg, stat); -#if FANCY_STATUS_DUMPS printk(" { "); if (stat & BUSY_STAT) printk("Busy "); @@ -652,12 +667,10 @@ if (stat & ERR_STAT) printk("Error "); } printk("}"); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { err = hwif->INB(IDE_ERROR_REG); printk("%s: %s: error=0x%02x", drive->name, msg, err); -#if FANCY_STATUS_DUMPS printk(" { "); if (err & ABRT_ERR) printk("DriveStatusError "); if (err & ICRC_ERR) @@ -700,8 +713,38 @@ (unsigned long long)HWGROUP(drive)->rq->sector); } } -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); + { + struct request *rq; + unsigned char opcode = 0; + int found = 0; + + spin_lock(&ide_lock); + rq = HWGROUP(drive)->rq; + spin_unlock(&ide_lock); + if (!rq) + goto out; + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + char *args = rq->buffer; + if (args) { + opcode = args[0]; + found = 1; + } + } else if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = rq->special; + if (args) { + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; + found = 1; + } + } + printk("ide: failed opcode was: "); + if (!found) + printk("unknown\n"); + else + printk("0x%02x\n", opcode); + } +out: local_irq_restore(flags); return err; } @@ -1117,6 +1160,7 @@ args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; args.command_type = IDE_DRIVE_TASK_IN; + args.data_phase = TASKFILE_IN; args.handler = &task_in_intr; (void) smart_enable(drive); return ide_raw_taskfile(drive, &args, buf); @@ -1203,6 +1247,42 @@ #endif /* CONFIG_PROC_FS */ +static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + ide_drive_t *drive = q->queuedata; + struct request *rq; + int ret; + + if (!drive->wcache) + return 0; + + rq = blk_get_request(q, WRITE, __GFP_WAIT); + + memset(rq->cmd, 0, sizeof(rq->cmd)); + + if (ide_id_has_flush_cache_ext(drive->id) && + (drive->capacity64 >= (1UL << 28))) + rq->cmd[0] = WIN_FLUSH_CACHE_EXT; + else + rq->cmd[0] = WIN_FLUSH_CACHE; + + + rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER; + rq->buffer = rq->cmd; + + ret = blk_execute_rq(q, disk, rq); + + /* + * if we failed and caller wants error offset, get it + */ + if (ret && error_sector) + *error_sector = ide_get_error_location(drive, rq->cmd); + + blk_put_request(rq); + return ret; +} + /* * This is tightly woven into the driver->do_special can not touch. * DON'T do it again until a total personality rewrite is committed. @@ -1231,16 +1311,10 @@ return 0; } -/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */ -#define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000) - -/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */ -#define ide_id_has_flush_cache_ext(id) \ - (((id)->cfs_enable_2 & 0x2400) == 0x2400) - -static int write_cache (ide_drive_t *drive, int arg) +static int write_cache(ide_drive_t *drive, int arg) { ide_task_t args; + int err; if (!ide_id_has_flush_cache(drive->id)) return 1; @@ -1251,7 +1325,10 @@ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; args.command_type = IDE_DRIVE_TASK_NO_DATA; args.handler = &task_no_data_intr; - (void) ide_raw_taskfile(drive, &args, NULL); + + err = ide_raw_taskfile(drive, &args, NULL); + if (err) + return err; drive->wcache = arg; return 0; @@ -1412,6 +1489,7 @@ { struct hd_driveid *id = drive->id; unsigned long long capacity; + int barrier; idedisk_add_settings(drive); @@ -1443,7 +1521,7 @@ blk_queue_max_sectors(drive->queue, max_s); } - printk("%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2); + printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2); /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { @@ -1472,13 +1550,22 @@ /* limit drive capacity to 137GB if LBA48 cannot be used */ if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) { - printk("%s: cannot use LBA48 - full capacity " + printk(KERN_WARNING "%s: cannot use LBA48 - full capacity " "%llu sectors (%llu MB)\n", drive->name, (unsigned long long)drive->capacity64, sectors_to_MB(drive->capacity64)); drive->capacity64 = 1ULL << 28; } + if (drive->hwif->no_lba48_dma && drive->addressing) { + if (drive->capacity64 > 1ULL << 28) { + printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode will" + " be used for accessing sectors > %u\n", + drive->name, 1 << 28); + } else + drive->addressing = 0; + } + /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: @@ -1543,6 +1630,29 @@ drive->wcache = 1; write_cache(drive, 1); + + /* + * We must avoid issuing commands a drive does not understand + * or we may crash it. We check flush cache is supported. We also + * check we have the LBA48 flush cache if the drive capacity is + * too large. By this time we have trimmed the drive capacity if + * LBA48 is not available so we don't need to recheck that. + */ + barrier = 0; + if (ide_id_has_flush_cache(id)) + barrier = 1; + if (drive->addressing == 1) { + /* Can't issue the correct flush ? */ + if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id)) + barrier = 0; + } + + printk(KERN_DEBUG "%s: cache flushes %ssupported\n", + drive->name, barrier ? "" : "not "); + if (barrier) { + blk_queue_ordered(drive->queue, 1); + blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush); + } } static void ide_cacheflush_p(ide_drive_t *drive) @@ -1723,11 +1833,9 @@ if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); - ide_cacheflush_p(drive); - ide_unregister_subdriver(drive); - DRIVER(drive)->busy--; - goto failed; - } + drive->attach = 0; + } else + drive->attach = 1; DRIVER(drive)->busy--; g->minors = 1 << PARTN_BITS; strcpy(g->devfs_name, drive->devfs_name); @@ -1735,7 +1843,6 @@ g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; set_capacity(g, current_capacity(drive)); g->fops = &idedisk_ops; - drive->attach = 1; add_disk(g); return 0; failed: diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c --- a/drivers/ide/ide-dma.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/ide/ide-dma.c 2004-10-18 14:56:32 -07:00 @@ -208,9 +208,6 @@ struct scatterlist *sg = hwif->sg_table; int nents; - if (hwif->sg_dma_active) - BUG(); - nents = blk_rq_map_sg(drive->queue, rq, hwif->sg_table); if (rq_data_dir(rq) == READ) @@ -366,7 +363,6 @@ hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction); - hwif->sg_dma_active = 0; return 0; /* revert to PIO for this request */ } @@ -390,7 +386,6 @@ int nents = HWIF(drive)->sg_nents; pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction); - HWIF(drive)->sg_dma_active = 0; } EXPORT_SYMBOL_GPL(ide_destroy_dmatable); @@ -412,10 +407,6 @@ ide_hwif_t *hwif = HWIF(drive); if ((id->capability & 1) && hwif->autodma) { - /* Consult the list of known "bad" drives */ - if (__ide_dma_bad_drive(drive)) - return __ide_dma_off(drive); - /* * Enable DMA on any drive that has * UltraDMA (mode 0/1/2/3/4/5/6) enabled @@ -569,6 +560,10 @@ int __ide_dma_on (ide_drive_t *drive) { + /* consult the list of known "bad" drives */ + if (__ide_dma_bad_drive(drive)) + return 1; + drive->using_dma = 1; ide_toggle_bounce(drive, 1); diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c --- a/drivers/ide/ide-io.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/ide/ide-io.c 2004-10-18 14:56:49 -07:00 @@ -54,38 +54,77 @@ #include #include -/** - * ide_end_request - complete an IDE I/O - * @drive: IDE device for the I/O - * @uptodate: - * @nr_sectors: number of sectors completed - * - * This is our end_request wrapper function. We complete the I/O - * update random number input and dequeue the request, which if - * it was tagged may be out of order. +static void ide_fill_flush_cmd(ide_drive_t *drive, struct request *rq) +{ + char *buf = rq->cmd; + + /* + * reuse cdb space for ata command + */ + memset(buf, 0, sizeof(rq->cmd)); + + rq->flags |= REQ_DRIVE_TASK | REQ_STARTED; + rq->buffer = buf; + rq->buffer[0] = WIN_FLUSH_CACHE; + + if (ide_id_has_flush_cache_ext(drive->id) && + (drive->capacity64 >= (1UL << 28))) + rq->buffer[0] = WIN_FLUSH_CACHE_EXT; +} + +/* + * preempt pending requests, and store this cache flush for immediate + * execution */ - -int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +static struct request *ide_queue_flush_cmd(ide_drive_t *drive, + struct request *rq, int post) { - struct request *rq; - unsigned long flags; - int ret = 1; + struct request *flush_rq = &HWGROUP(drive)->wrq; - spin_lock_irqsave(&ide_lock, flags); - rq = HWGROUP(drive)->rq; + /* + * write cache disabled, clear the barrier bit and treat it like + * an ordinary write + */ + if (!drive->wcache) { + rq->flags |= REQ_BAR_PREFLUSH; + return rq; + } - BUG_ON(!(rq->flags & REQ_STARTED)); + ide_init_drive_cmd(flush_rq); + ide_fill_flush_cmd(drive, flush_rq); - if (!nr_sectors) - nr_sectors = rq->hard_cur_sectors; + flush_rq->special = rq; + flush_rq->nr_sectors = rq->nr_sectors; + + if (!post) { + drive->doing_barrier = 1; + flush_rq->flags |= REQ_BAR_PREFLUSH; + blkdev_dequeue_request(rq); + } else + flush_rq->flags |= REQ_BAR_POSTFLUSH; + + __elv_add_request(drive->queue, flush_rq, ELEVATOR_INSERT_FRONT, 0); + HWGROUP(drive)->rq = NULL; + return flush_rq; +} + +static int __ide_end_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + int ret = 1; + + BUG_ON(!(rq->flags & REQ_STARTED)); /* * if failfast is set on a request, override number of sectors and * complete the whole request right now */ - if (blk_noretry_request(rq) && !uptodate) + if (blk_noretry_request(rq) && end_io_error(uptodate)) nr_sectors = rq->hard_nr_sectors; + if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + rq->errors = -EIO; + /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO @@ -97,15 +136,56 @@ if (!end_that_request_first(rq, uptodate, nr_sectors)) { add_disk_randomness(rq->rq_disk); + + if (blk_rq_tagged(rq)) + blk_queue_end_tag(drive->queue, rq); + blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; } - spin_unlock_irqrestore(&ide_lock, flags); return ret; } +/** + * ide_end_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * This is our end_request wrapper function. We complete the I/O + * update random number input and dequeue the request, which if + * it was tagged may be out of order. + */ + +int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + rq = HWGROUP(drive)->rq; + + if (!nr_sectors) + nr_sectors = rq->hard_cur_sectors; + + if (!blk_barrier_rq(rq) || !drive->wcache) + ret = __ide_end_request(drive, rq, uptodate, nr_sectors); + else { + struct request *flush_rq = &HWGROUP(drive)->wrq; + + flush_rq->nr_sectors -= nr_sectors; + if (!flush_rq->nr_sectors) { + ide_queue_flush_cmd(drive, rq, 1); + ret = 0; + } + } + + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} EXPORT_SYMBOL(ide_end_request); /** @@ -137,6 +217,113 @@ spin_unlock_irqrestore(&ide_lock, flags); } +/* + * FIXME: probably move this somewhere else, name is bad too :) + */ +u64 ide_get_error_location(ide_drive_t *drive, char *args) +{ + u32 high, low; + u8 hcyl, lcyl, sect; + u64 sector; + + high = 0; + hcyl = args[5]; + lcyl = args[4]; + sect = args[3]; + + if (ide_id_has_flush_cache_ext(drive->id)) { + low = (hcyl << 16) | (lcyl << 8) | sect; + HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + high = ide_read_24(drive); + } else { + u8 cur = HWIF(drive)->INB(IDE_SELECT_REG); + if (cur & 0x40) + low = (hcyl << 16) | (lcyl << 8) | sect; + else { + low = hcyl * drive->head * drive->sect; + low += lcyl * drive->sect; + low += sect - 1; + } + } + + sector = ((u64) high << 24) | low; + return sector; +} +EXPORT_SYMBOL(ide_get_error_location); + +static void ide_complete_barrier(ide_drive_t *drive, struct request *rq, + int error) +{ + struct request *real_rq = rq->special; + int good_sectors, bad_sectors; + sector_t sector; + + if (!error) { + if (blk_barrier_postflush(rq)) { + /* + * this completes the barrier write + */ + __ide_end_request(drive, real_rq, 1, real_rq->hard_nr_sectors); + drive->doing_barrier = 0; + } else { + /* + * just indicate that we did the pre flush + */ + real_rq->flags |= REQ_BAR_PREFLUSH; + elv_requeue_request(drive->queue, real_rq); + } + /* + * all is fine, return + */ + return; + } + + /* + * we need to end real_rq, but it's not on the queue currently. + * put it back on the queue, so we don't have to special case + * anything else for completing it + */ + if (!blk_barrier_postflush(rq)) + elv_requeue_request(drive->queue, real_rq); + + /* + * drive aborted flush command, assume FLUSH_CACHE_* doesn't + * work and disable barrier support + */ + if (error & ABRT_ERR) { + printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name); + __ide_end_request(drive, real_rq, -EOPNOTSUPP, real_rq->hard_nr_sectors); + blk_queue_ordered(drive->queue, 0); + blk_queue_issue_flush_fn(drive->queue, NULL); + } else { + /* + * find out what part of the request failed + */ + good_sectors = 0; + if (blk_barrier_postflush(rq)) { + sector = ide_get_error_location(drive, rq->buffer); + + if ((sector >= real_rq->hard_sector) && + (sector < real_rq->hard_sector + real_rq->hard_nr_sectors)) + good_sectors = sector - real_rq->hard_sector; + } else + sector = real_rq->hard_sector; + + bad_sectors = real_rq->hard_nr_sectors - good_sectors; + if (good_sectors) + __ide_end_request(drive, real_rq, 1, good_sectors); + if (bad_sectors) + __ide_end_request(drive, real_rq, 0, bad_sectors); + + printk(KERN_ERR "%s: failed barrier write: " + "sector=%Lx(good=%d/bad=%d)\n", + drive->name, (unsigned long long)sector, + good_sectors, bad_sectors); + } + + drive->doing_barrier = 0; +} + /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -197,6 +384,8 @@ args->hobRegister[IDE_DATA_OFFSET] = (data >> 8) & 0xFF; } args->tfRegister[IDE_ERROR_OFFSET] = err; + /* be sure we're looking at the low order bits */ + hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); @@ -226,6 +415,10 @@ spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); + + if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq)) + ide_complete_barrier(drive, rq, err); + HWGROUP(drive)->rq = NULL; end_that_request_last(rq); spin_unlock_irqrestore(&ide_lock, flags); @@ -501,7 +694,9 @@ if (!args) goto done; - + + hwif->data_phase = args->data_phase; + if (args->tf_out_flags.all != 0) return flagged_taskfile(drive, args); return do_rw_taskfile(drive, args); @@ -712,6 +907,22 @@ repeat: best = NULL; drive = hwgroup->drive; + + /* + * drive is doing pre-flush, ordered write, post-flush sequence. even + * though that is 3 requests, it must be seen as a single transaction. + * we must not preempt this drive until that is complete + */ + if (drive->doing_barrier) { + /* + * small race where queue could get replugged during + * the 3-request flush cycle, just yank the plug since + * we want it to finish asap + */ + blk_remove_plug(drive->queue); + return drive; + } + do { if ((!drive->sleep || time_after_eq(jiffies, drive->sleep)) && !elv_queue_empty(drive->queue)) { @@ -868,6 +1079,13 @@ } /* + * if rq is a barrier write, issue pre cache flush if not + * already done + */ + if (blk_barrier_rq(rq) && !blk_barrier_preflush(rq)) + rq = ide_queue_flush_cmd(drive, rq, 0); + + /* * Sanity: don't accept a request that isn't a PM request * if we are currently power managed. This is very important as * blk_stop_queue() doesn't prevent the elv_next_request() @@ -917,7 +1135,9 @@ */ void do_ide_request(request_queue_t *q) { - ide_do_request(q->queuedata, IDE_NO_IRQ); + ide_drive_t *drive = q->queuedata; + + ide_do_request(HWGROUP(drive), IDE_NO_IRQ); } /* @@ -1286,6 +1506,7 @@ { memset(rq, 0, sizeof(*rq)); rq->flags = REQ_DRIVE_CMD; + rq->ref_count = 1; } EXPORT_SYMBOL(ide_init_drive_cmd); diff -Nru a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c --- a/drivers/ide/ide-iops.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/ide-iops.c 2004-10-18 14:56:28 -07:00 @@ -112,57 +112,57 @@ static u8 ide_mm_inb (unsigned long port) { - return (u8) readb(port); + return (u8) readb((void __iomem *) port); } static u16 ide_mm_inw (unsigned long port) { - return (u16) readw(port); + return (u16) readw((void __iomem *) port); } static void ide_mm_insw (unsigned long port, void *addr, u32 count) { - __ide_mm_insw(port, addr, count); + __ide_mm_insw((void __iomem *) port, addr, count); } static u32 ide_mm_inl (unsigned long port) { - return (u32) readl(port); + return (u32) readl((void __iomem *) port); } static void ide_mm_insl (unsigned long port, void *addr, u32 count) { - __ide_mm_insl(port, addr, count); + __ide_mm_insl((void __iomem *) port, addr, count); } static void ide_mm_outb (u8 value, unsigned long port) { - writeb(value, port); + writeb(value, (void __iomem *) port); } static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port) { - writeb(value, port); + writeb(value, (void __iomem *) port); } static void ide_mm_outw (u16 value, unsigned long port) { - writew(value, port); + writew(value, (void __iomem *) port); } static void ide_mm_outsw (unsigned long port, void *addr, u32 count) { - __ide_mm_outsw(port, addr, count); + __ide_mm_outsw((void __iomem *) port, addr, count); } static void ide_mm_outl (u32 value, unsigned long port) { - writel(value, port); + writel(value, (void __iomem *) port); } static void ide_mm_outsl (unsigned long port, void *addr, u32 count) { - __ide_mm_outsl(port, addr, count); + __ide_mm_outsl((void __iomem *) port, addr, count); } void default_hwif_mmiops (ide_hwif_t *hwif) @@ -1096,7 +1096,6 @@ drive->failures = 0; } else { drive->failures++; -#if FANCY_STATUS_DUMPS printk("master: "); switch (tmp & 0x7f) { case 1: printk("passed"); @@ -1114,9 +1113,6 @@ if (tmp & 0x80) printk("; slave: failed"); printk("\n"); -#else - printk("failed\n"); -#endif /* FANCY_STATUS_DUMPS */ } } hwgroup->poll_timeout = 0; /* done polling */ diff -Nru a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c --- a/drivers/ide/ide-lib.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/ide/ide-lib.c 2004-10-18 14:57:04 -07:00 @@ -465,7 +465,6 @@ status.all = stat; local_irq_set(flags); printk("%s: %s: status=0x%02x", drive->name, msg, stat); -#if FANCY_STATUS_DUMPS printk(" { "); if (status.b.bsy) printk("Busy "); @@ -479,19 +478,16 @@ if (status.b.check) printk("Error "); } printk("}"); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) { error.all = HWIF(drive)->INB(IDE_ERROR_REG); printk("%s: %s: error=0x%02x", drive->name, msg, error.all); -#if FANCY_STATUS_DUMPS if (error.b.ili) printk("IllegalLengthIndication "); if (error.b.eom) printk("EndOfMedia "); if (error.b.abrt) printk("Aborted Command "); if (error.b.mcr) printk("MediaChangeRequested "); if (error.b.sense_key) printk("LastFailedSense 0x%02x ", error.b.sense_key); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); } local_irq_restore(flags); diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c --- a/drivers/ide/ide-probe.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/ide/ide-probe.c 2004-10-18 14:56:33 -07:00 @@ -389,15 +389,6 @@ */ printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie); -#ifdef CONFIG_BLK_DEV_CMD640 -#ifdef CMD640_DUMP_REGS - if (hwif->chipset == ide_cmd640) { - printk("%s: Hmmm.. probably a driver " - "problem.\n", drive->name); - CMD640_DUMP_REGS; - } -#endif /* CMD640_DUMP_REGS */ -#endif /* CONFIG_BLK_DEV_CMD640 */ } } } @@ -635,12 +626,11 @@ device_register(&hwif->gendev); } -#ifdef CONFIG_PPC static int wait_hwif_ready(ide_hwif_t *hwif) { int rc; - printk(KERN_INFO "Probing IDE interface %s...\n", hwif->name); + printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name); /* Let HW settle down a bit from whatever init state we * come from */ @@ -671,7 +661,6 @@ return rc; } -#endif /* * This routine only knows how to look for drive units 0 and 1 @@ -717,7 +706,6 @@ local_irq_set(flags); -#ifdef CONFIG_PPC /* This is needed on some PPCs and a bunch of BIOS-less embedded * platforms. Typical cases are: * @@ -738,8 +726,7 @@ * BenH. */ if (wait_hwif_ready(hwif)) - printk(KERN_WARNING "%s: Wait for ready failed before probe !\n", hwif->name); -#endif /* CONFIG_PPC */ + printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* * Second drive should only exist if first drive was found, @@ -749,6 +736,18 @@ ide_drive_t *drive = &hwif->drives[unit]; drive->dn = (hwif->channel ? 2 : 0) + unit; (void) probe_for_drive(drive); + if (drive->present && hwif->present && unit == 1) { + if (strcmp(hwif->drives[0].id->model, drive->id->model) == 0 && + /* Don't do this for noprobe or non ATA */ + strcmp(drive->id->model, "UNKNOWN") && + /* And beware of confused Maxtor drives that go "M0000000000" + "The SN# is garbage in the ID block..." [Eric] */ + strncmp(drive->id->serial_no, "M0000000000000000000", 20) && + strncmp(hwif->drives[0].id->serial_no, drive->id->serial_no, 20) == 0) { + printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n"); + drive->present = 0; + } + } if (drive->present && !hwif->present) { hwif->present = 1; if (hwif->chipset != ide_4drives || @@ -893,11 +892,15 @@ if (!q) return 1; - q->queuedata = HWGROUP(drive); + q->queuedata = drive; blk_queue_segment_boundary(q, 0xffff); - if (!hwif->rqsize) - hwif->rqsize = hwif->no_lba48 ? 256 : 65536; + if (!hwif->rqsize) { + if (hwif->no_lba48 || hwif->no_lba48_dma) + hwif->rqsize = 256; + else + hwif->rqsize = 65536; + } if (hwif->rqsize < max_sectors) max_sectors = hwif->rqsize; blk_queue_max_sectors(q, max_sectors); @@ -906,11 +909,11 @@ /* When we have an IOMMU, we may have a problem where pci_map_sg() * creates segments that don't completely match our boundary * requirements and thus need to be broken up again. Because it - * doesn't align properly neither, we may actually have to break up + * doesn't align properly either, we may actually have to break up * to more segments than what was we got in the first place, a max * worst case is twice as many. * This will be fixed once we teach pci_map_sg() about our boundary - * requirements, hopefully soon + * requirements, hopefully soon. *FIXME* */ if (!PCI_DMA_BUS_IS_PHYS) max_sg_entries >>= 1; diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c --- a/drivers/ide/ide-proc.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/ide/ide-proc.c 2004-10-18 14:56:32 -07:00 @@ -360,27 +360,14 @@ int err = 0; len = sprintf(page, "\n"); - - if (drive) - { + + if (drive) { unsigned short *val = (unsigned short *) page; - - /* - * The current code can't handle a driverless - * identify query taskfile. Now the right fix is - * to add a 'default' driver but that is a bit - * more work. - * - * FIXME: this has to be fixed for hotswap devices - */ - - if(DRIVER(drive)) - err = taskfile_lib_get_identify(drive, page); - else /* This relies on the ID changes */ - val = (unsigned short *)drive->id; - if(!err) - { + BUG_ON(!drive->driver); + + err = taskfile_lib_get_identify(drive, page); + if (!err) { char *out = ((char *)page) + (SECTOR_WORDS * 4); page = out; do { diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/ide-tape.c 2004-10-18 14:56:28 -07:00 @@ -530,7 +530,6 @@ */ #define IDETAPE_DEBUG_INFO 0 #define IDETAPE_DEBUG_LOG 0 -#define IDETAPE_DEBUG_LOG_VERBOSE 0 #define IDETAPE_DEBUG_BUGS 1 /* @@ -1260,70 +1259,6 @@ */ static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES]; -#if IDETAPE_DEBUG_LOG_VERBOSE - -/* - * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI - */ - -char *idetape_sense_key_verbose(u8 idetape_sense_key) -{ - switch (idetape_sense_key) { - default: { - char buf[22]; - sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key); - return(buf); - } - - } -} - -char *idetape_command_key_verbose(u8 idetape_command_key) -{ - switch (idetape_command_key) { - case IDETAPE_TEST_UNIT_READY_CMD: - return("TEST_UNIT_READY_CMD"); - case IDETAPE_REWIND_CMD: - return("REWIND_CMD"); - case IDETAPE_REQUEST_SENSE_CMD: - return("REQUEST_SENSE_CMD"); - case IDETAPE_READ_CMD: - return("READ_CMD"); - case IDETAPE_WRITE_CMD: - return("WRITE_CMD"); - case IDETAPE_WRITE_FILEMARK_CMD: - return("WRITE_FILEMARK_CMD"); - case IDETAPE_SPACE_CMD: - return("SPACE_CMD"); - case IDETAPE_INQUIRY_CMD: - return("INQUIRY_CMD"); - case IDETAPE_ERASE_CMD: - return("ERASE_CMD"); - case IDETAPE_MODE_SENSE_CMD: - return("MODE_SENSE_CMD"); - case IDETAPE_MODE_SELECT_CMD: - return("MODE_SELECT_CMD"); - case IDETAPE_LOAD_UNLOAD_CMD: - return("LOAD_UNLOAD_CMD"); - case IDETAPE_PREVENT_CMD: - return("PREVENT_CMD"); - case IDETAPE_LOCATE_CMD: - return("LOCATE_CMD"); - case IDETAPE_READ_POSITION_CMD: - return("READ_POSITION_CMD"); - case IDETAPE_READ_BUFFER_CMD: - return("READ_BUFFER_CMD"); - case IDETAPE_SET_SPEED_CMD: - return("SET_SPEED_CMD"); - default: { - char buf[20]; - sprintf(buf, "CMD (0x%02x)", idetape_command_key); - return(buf); - } - } -} -#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ - /* * Function declarations * @@ -1507,15 +1442,6 @@ "asc = %x, ascq = %x\n", pc->c[0], result->sense_key, result->asc, result->ascq); -#if IDETAPE_DEBUG_LOG_VERBOSE - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: pc = %s, sense key = %x, " - "asc = %x, ascq = %x\n", - idetape_command_key_verbose((byte) pc->c[0]), - result->sense_key, - result->asc, - result->ascq); -#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ #endif /* IDETAPE_DEBUG_LOG */ /* diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c --- a/drivers/ide/ide-taskfile.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/ide/ide-taskfile.c 2004-10-18 14:55:54 -07:00 @@ -96,36 +96,13 @@ else args.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY; args.command_type = IDE_DRIVE_TASK_IN; + args.data_phase = TASKFILE_IN; args.handler = &task_in_intr; return ide_raw_taskfile(drive, &args, buf); } EXPORT_SYMBOL(taskfile_lib_get_identify); -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG -void debug_taskfile (ide_drive_t *drive, ide_task_t *args) -{ - printk(KERN_INFO "%s: ", drive->name); -// printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]); - printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]); - printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]); - printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]); - printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]); - printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]); - printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]); - printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]); - printk(KERN_INFO "%s: ", drive->name); -// printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET]); - printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET]); - printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET]); - printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET]); - printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET]); - printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET]); - printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET]); - printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]); -} -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ - ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) { ide_hwif_t *hwif = HWIF(drive); @@ -133,10 +110,6 @@ hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; u8 HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF; -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG - void debug_taskfile(drive, task); -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ - /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ if (IDE_CONTROL_REG) { /* clear nIEN */ @@ -367,12 +340,44 @@ return stat; } +static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq, + unsigned int write) +{ + switch (drive->hwif->data_phase) { + case TASKFILE_MULTI_IN: + case TASKFILE_MULTI_OUT: + task_multi_sectors(drive, rq, write); + break; + default: + task_sectors(drive, rq, 1, write); + break; + } +} + #ifdef CONFIG_IDE_TASKFILE_IO static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, - const char *s, u8 stat, unsigned cur_bad) + const char *s, u8 stat) { if (rq->bio) { - int sectors = rq->hard_nr_sectors - rq->nr_sectors - cur_bad; + int sectors = rq->hard_nr_sectors - rq->nr_sectors; + + switch (drive->hwif->data_phase) { + case TASKFILE_IN: + if (rq->nr_sectors) + break; + /* fall through */ + case TASKFILE_OUT: + sectors--; + break; + case TASKFILE_MULTI_IN: + if (rq->nr_sectors) + break; + /* fall through */ + case TASKFILE_MULTI_OUT: + sectors -= drive->mult_count; + default: + break; + } if (sectors > 0) drive->driver->end_request(drive, 1, sectors); @@ -380,7 +385,7 @@ return drive->driver->error(drive, s, stat); } #else -# define task_error(d, rq, s, stat, cur_bad) drive->driver->error(d, s, stat) +# define task_error(d, rq, s, stat) drive->driver->error(d, s, stat) #endif static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) @@ -398,7 +403,7 @@ } /* - * Handler for command with PIO data-in phase (Read). + * Handler for command with PIO data-in phase (Read/Read Multiple). */ ide_startstop_t task_in_intr (ide_drive_t *drive) { @@ -407,19 +412,19 @@ if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { if (stat & (ERR_STAT | DRQ_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, 0); + return task_error(drive, rq, __FUNCTION__, stat); /* No data yet, so wait for another IRQ. */ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); return ide_started; } - task_sectors(drive, rq, 1, IDE_PIO_IN); + ide_pio_datablock(drive, rq, 0); /* If it was the last datablock check status and finish transfer. */ if (!rq->nr_sectors) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_R_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, 1); + return task_error(drive, rq, __FUNCTION__, stat); task_end_request(drive, rq, stat); return ide_stopped; } @@ -432,41 +437,7 @@ EXPORT_SYMBOL(task_in_intr); /* - * Handler for command with PIO data-in phase (Read Multiple). - */ -ide_startstop_t task_mulin_intr (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - u8 stat = HWIF(drive)->INB(IDE_STATUS_REG); - - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { - if (stat & (ERR_STAT | DRQ_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, 0); - /* No data yet, so wait for another IRQ. */ - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - - task_multi_sectors(drive, rq, IDE_PIO_IN); - - /* If it was the last datablock check status and finish transfer. */ - if (!rq->nr_sectors) { - stat = wait_drive_not_busy(drive); - if (!OK_STAT(stat, 0, BAD_R_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); - task_end_request(drive, rq, stat); - return ide_stopped; - } - - /* Still data left to transfer. */ - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); - - return ide_started; -} -EXPORT_SYMBOL(task_mulin_intr); - -/* - * Handler for command with PIO data-out phase (Write). + * Handler for command with PIO data-out phase (Write/Write Multiple). */ ide_startstop_t task_out_intr (ide_drive_t *drive) { @@ -475,11 +446,11 @@ stat = HWIF(drive)->INB(IDE_STATUS_REG); if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) - return task_error(drive, rq, __FUNCTION__, stat, 1); + return task_error(drive, rq, __FUNCTION__, stat); /* Deal with unexpected ATA data phase. */ if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors) - return task_error(drive, rq, __FUNCTION__, stat, 1); + return task_error(drive, rq, __FUNCTION__, stat); if (!rq->nr_sectors) { task_end_request(drive, rq, stat); @@ -487,7 +458,7 @@ } /* Still data left to transfer. */ - task_sectors(drive, rq, 1, IDE_PIO_OUT); + ide_pio_datablock(drive, rq, 1); ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); return ide_started; @@ -501,8 +472,10 @@ if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n", - drive->name, drive->addressing ? "_EXT" : ""); + printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n", + drive->name, + drive->hwif->data_phase ? "MULT" : "", + drive->addressing ? "_EXT" : ""); return startstop; } @@ -510,62 +483,12 @@ local_irq_disable(); ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); - task_sectors(drive, rq, 1, IDE_PIO_OUT); + ide_pio_datablock(drive, rq, 1); return ide_started; } EXPORT_SYMBOL(pre_task_out_intr); -/* - * Handler for command with PIO data-out phase (Write Multiple). - */ -ide_startstop_t task_mulout_intr (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - u8 stat; - - stat = HWIF(drive)->INB(IDE_STATUS_REG); - if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) - return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); - - /* Deal with unexpected ATA data phase. */ - if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors) - return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); - - if (!rq->nr_sectors) { - task_end_request(drive, rq, stat); - return ide_stopped; - } - - /* Still data left to transfer. */ - task_multi_sectors(drive, rq, IDE_PIO_OUT); - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - - return ide_started; -} -EXPORT_SYMBOL(task_mulout_intr); - -ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop, drive, DATA_READY, - drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing MULTWRITE%s\n", - drive->name, drive->addressing ? "_EXT" : ""); - return startstop; - } - - if (!drive->unmask) - local_irq_disable(); - - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - task_multi_sectors(drive, rq, IDE_PIO_OUT); - - return ide_started; -} -EXPORT_SYMBOL(pre_task_mulout_intr); - int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) { struct request rq; @@ -688,19 +611,6 @@ case TASKFILE_IN_DMA: err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; - case TASKFILE_IN_OUT: -#if 0 - args.prehandler = &pre_task_out_intr; - args.handler = &task_out_intr; - err = ide_diag_taskfile(drive, &args, taskout, outbuf); - args.prehandler = NULL; - args.handler = &task_in_intr; - err = ide_diag_taskfile(drive, &args, taskin, inbuf); - break; -#else - err = -EFAULT; - goto abort; -#endif case TASKFILE_MULTI_OUT: if (!drive->mult_count) { /* (hs): give up if multcount is not set */ @@ -710,10 +620,7 @@ err = -EPERM; goto abort; } - args.prehandler = &pre_task_mulout_intr; - args.handler = &task_mulout_intr; - err = ide_diag_taskfile(drive, &args, taskout, outbuf); - break; + /* fall through */ case TASKFILE_OUT: args.prehandler = &pre_task_out_intr; args.handler = &task_out_intr; @@ -728,9 +635,7 @@ err = -EPERM; goto abort; } - args.handler = &task_mulin_intr; - err = ide_diag_taskfile(drive, &args, taskin, inbuf); - break; + /* fall through */ case TASKFILE_IN: args.handler = &task_in_intr; err = ide_diag_taskfile(drive, &args, taskin, inbuf); @@ -906,11 +811,6 @@ #if DEBUG_TASKFILE u8 status; #endif - - -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG - void debug_taskfile(drive, task); -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ if (task->data_phase == TASKFILE_MULTI_IN || task->data_phase == TASKFILE_MULTI_OUT) { diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/ide/ide.c 2004-10-18 14:56:27 -07:00 @@ -320,13 +320,19 @@ #endif } -/* - * ide_system_bus_speed() returns what we think is the system VESA/PCI - * bus speed (in MHz). This is used for calculating interface PIO timings. - * The default is 40 for known PCI systems, 50 otherwise. - * The "idebus=xx" parameter can be used to override this value. - * The actual value to be used is computed/displayed the first time through. +/** + * ide_system_bus_speed - guess bus speed + * + * ide_system_bus_speed() returns what we think is the system VESA/PCI + * bus speed (in MHz). This is used for calculating interface PIO timings. + * The default is 40 for known PCI systems, 50 otherwise. + * The "idebus=xx" parameter can be used to override this value. + * The actual value to be used is computed/displayed the first time + * through. Drivers should only use this as a last resort. + * + * Returns a guessed speed in MHz. */ + int ide_system_bus_speed (void) { if (!system_bus_speed) { @@ -347,10 +353,15 @@ return system_bus_speed; } -/* - * current_capacity() returns the capacity (in sectors) of a drive - * according to its current geometry/LBA settings. +/** + * current_capacity - drive capacity + * @drive: drive to query + * + * Return the current capacity (in sectors) of a drive according to + * its current geometry/LBA settings. Empty removables are reported + * as size zero. */ + sector_t current_capacity (ide_drive_t *drive) { if (!drive->present) @@ -360,9 +371,17 @@ EXPORT_SYMBOL(current_capacity); -/* - * Error reporting, in human readable form (luxurious, but a memory hog). +/** + * ide_dump_status - translate ATA error + * @drive: drive the error occured on + * @msg: information string + * @stat: status byte + * + * Error reporting, in human readable form (luxurious, but a memory hog). + * Combines the drive name, message and status byte to provide a + * user understandable explanation of the device error. */ + u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat) { ide_hwif_t *hwif = HWIF(drive); @@ -371,7 +390,6 @@ local_irq_set(flags); printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat); -#if FANCY_STATUS_DUMPS printk(" { "); if (stat & BUSY_STAT) { printk("Busy "); @@ -385,12 +403,10 @@ if (stat & ERR_STAT) printk("Error "); } printk("}"); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { err = hwif->INB(IDE_ERROR_REG); printk("%s: %s: error=0x%02x", drive->name, msg, err); -#if FANCY_STATUS_DUMPS if (drive->media == ide_disk) { printk(" { "); if (err & ABRT_ERR) printk("DriveStatusError "); @@ -434,9 +450,34 @@ printk(", sector=%llu", (unsigned long long)HWGROUP(drive)->rq->sector); } } -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); } + { + struct request *rq; + int opcode = 0x100; + + spin_lock(&ide_lock); + rq = NULL; + if (HWGROUP(drive)) + rq = HWGROUP(drive)->rq; + spin_unlock(&ide_lock); + if (!rq) + goto out; + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + char *args = rq->buffer; + if (args) + opcode = args[0]; + } else if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = rq->special; + if (args) { + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; + } + } + + printk("ide: failed opcode was %x\n", opcode); + } +out: local_irq_restore(flags); return err; } @@ -448,11 +489,17 @@ return -ENXIO; } +/* + * drives_lock protects the list of drives, drivers_lock the + * list of drivers. Currently nobody takes both at once. + */ + static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED; static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(drivers); -/* Iterator */ +/* Iterator for the driver list. */ + static void *m_start(struct seq_file *m, loff_t *pos) { struct list_head *p; @@ -463,22 +510,26 @@ return list_entry(p, ide_driver_t, drivers); return NULL; } + static void *m_next(struct seq_file *m, void *v, loff_t *pos) { struct list_head *p = ((ide_driver_t *)v)->drivers.next; (*pos)++; return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers); } + static void m_stop(struct seq_file *m, void *v) { spin_unlock(&drivers_lock); } + static int show_driver(struct seq_file *m, void *v) { ide_driver_t *driver = v; seq_printf(m, "%s version %s\n", driver->name, driver->version); return 0; } + struct seq_operations ide_drivers_op = { .start = m_start, .next = m_next, @@ -515,6 +566,7 @@ * MMIO leaves it to the controller driver, * PIO will migrate this way over time. */ + int ide_hwif_request_regions(ide_hwif_t *hwif) { unsigned long addr; @@ -564,6 +616,7 @@ * importantly our caller should be doing this so we need to * restructure this as a helper function for drivers. */ + void ide_hwif_release_regions(ide_hwif_t *hwif) { u32 i = 0; @@ -581,7 +634,15 @@ release_region(hwif->io_ports[i], 1); } -/* restore hwif to a sane state */ +/** + * ide_hwif_restore - restore hwif to template + * @hwif: hwif to update + * @tmp_hwif: template + * + * Restore hwif to a previous state by copying most settngs + * from the template. + */ + static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) { hwif->hwgroup = tmp_hwif->hwgroup; @@ -702,18 +763,13 @@ void ide_unregister(unsigned int index) { ide_drive_t *drive; - ide_hwif_t *hwif, *g, *tmp_hwif; + ide_hwif_t *hwif, *g; + static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */ ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; BUG_ON(index >= MAX_HWIFS); - tmp_hwif = kmalloc(sizeof(*tmp_hwif), GFP_KERNEL|__GFP_NOFAIL); - if (!tmp_hwif) { - printk(KERN_ERR "%s: unable to allocate memory\n", __FUNCTION__); - return; - } - BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); down(&ide_cfg_sem); @@ -860,19 +916,17 @@ } /* copy original settings */ - *tmp_hwif = *hwif; + tmp_hwif = *hwif; /* restore hwif data to pristine status */ init_hwif_data(hwif, index); init_hwif_default(hwif, index); - ide_hwif_restore(hwif, tmp_hwif); + ide_hwif_restore(hwif, &tmp_hwif); abort: spin_unlock_irq(&ide_lock); up(&ide_cfg_sem); - - kfree(tmp_hwif); } EXPORT_SYMBOL(ide_unregister); @@ -931,10 +985,17 @@ */ } -/* - * Register an IDE interface, specifying exactly the registers etc - * Set init=1 iff calling before probes have taken place. +/** + * ide_register_hw - register IDE interface + * @hw: hardware registers + * @hwifp: pointer to returned hwif + * + * Register an IDE interface, specifying exactly the registers etc. + * Set init=1 iff calling before probes have taken place. + * + * Returns -1 on error. */ + int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp) { int index, retry = 1; @@ -1188,6 +1249,15 @@ return val; } +/** + * ide_spin_wait_hwgroup - wait for group + * @drive: drive in the group + * + * Wait for an IDE device group to go non busy and then return + * holding the ide_lock which guards the hwgroup->busy status + * and right to use it. + */ + int ide_spin_wait_hwgroup (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -1229,6 +1299,7 @@ * to the driver to change settings, and then wait on a sema for completion. * The current scheme of polling is kludgy, though safe enough. */ + int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) { int i; @@ -1322,22 +1393,14 @@ return err; } -int ide_atapi_to_scsi (ide_drive_t *drive, int arg) -{ - if (drive->media == ide_disk) { - drive->scsi = 0; - return 0; - } - - if (DRIVER(drive)->cleanup(drive)) { - drive->scsi = 0; - return 0; - } - - drive->scsi = (u8) arg; - ata_attach(drive); - return 0; -} +/** + * ide_add_generic_settings - generic ide settings + * @drive: drive being configured + * + * Add the generic parts of the system settings to the /proc files and + * ioctls for this IDE device. The caller must not be holding the + * ide_setting_sem. + */ void ide_add_generic_settings (ide_drive_t *drive) { @@ -1353,10 +1416,15 @@ ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL); ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate); ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL); - if (drive->media != ide_disk) - ide_add_setting(drive, "ide-scsi", SETTING_RW, -1, HDIO_SET_IDE_SCSI, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, ide_atapi_to_scsi); } +/** + * system_bus_clock - clock guess + * + * External version of the bus clock guess used by very old IDE drivers + * for things like VLB timings. Should not be used. + */ + int system_bus_clock (void) { return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); @@ -1391,6 +1459,22 @@ return 1; } +/** + * ata_attach - attach an ATA/ATAPI device + * @drive: drive to attach + * + * Takes a drive that is as yet not assigned to any midlayer IDE + * driver (or is assigned to the default driver) and figures out + * which driver would like to own it. If nobody claims the drive + * then it is automatically attached to the default driver used for + * unclaimed objects. + * + * A return of zero indicates attachment to a driver, of one + * attachment to the default driver. + * + * Takes drivers_lock. + */ + int ata_attach(ide_drive_t *drive) { struct list_head *p; @@ -2199,6 +2283,20 @@ EXPORT_SYMBOL(ide_register_subdriver); +/** + * ide_unregister_subdriver - disconnect drive from driver + * @drive: drive to unplug + * + * Disconnect a drive from the driver it was attached to and then + * clean up the various proc files and other objects attached to it. + * + * Takes ide_setting_sem, ide_lock and drives_lock. + * Caller must hold none of the locks. + * + * No locking versus subdriver unload because we are moving to the + * default driver anyway. Wants double checking. + */ + int ide_unregister_subdriver (ide_drive_t *drive) { unsigned long flags; @@ -2234,6 +2332,17 @@ return 0; } +/** + * ide_register_driver - register IDE device driver + * @driver: the IDE device driver + * + * Register a new device driver and then scan the devices + * on the IDE bus in case any should be attached to the + * driver we have just registered. If so attach them. + * + * Takes drivers_lock and drives_lock. + */ + int ide_register_driver(ide_driver_t *driver) { struct list_head list; @@ -2264,6 +2373,17 @@ } EXPORT_SYMBOL(ide_register_driver); + +/** + * ide_unregister_driver - unregister IDE device driver + * @driver: the IDE device driver + * + * Called when a driver module is being unloaded. We reattach any + * devices to whatever driver claims them next (typically the default + * driver). + * + * Takes drivers_lock and called functions will take ide_setting_sem. + */ void ide_unregister_driver(ide_driver_t *driver) { diff -Nru a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile --- a/drivers/ide/legacy/Makefile 2004-10-18 14:56:13 -07:00 +++ b/drivers/ide/legacy/Makefile 2004-10-18 14:56:13 -07:00 @@ -10,6 +10,5 @@ # Last of all obj-$(CONFIG_BLK_DEV_HD) += hd.o -obj-$(CONFIG_BLK_DEV_HD98) += hd98.o EXTRA_CFLAGS := -Idrivers/ide diff -Nru a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c --- a/drivers/ide/legacy/ide-cs.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/ide/legacy/ide-cs.c 2004-10-18 14:56:48 -07:00 @@ -412,12 +412,6 @@ /* FIXME: if this fails we need to queue the cleanup somehow -- need to investigate the required PCMCIA magic */ ide_unregister(info->hd); - /* deal with brain dead IDE resource management */ - request_region(link->io.BasePort1, link->io.NumPorts1, - info->node.dev_name); - if (link->io.NumPorts2) - request_region(link->io.BasePort2, link->io.NumPorts2, - info->node.dev_name); } info->ndev = 0; link->dev = NULL; diff -Nru a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c --- a/drivers/ide/legacy/pdc4030.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/ide/legacy/pdc4030.c 2004-10-18 14:56:32 -07:00 @@ -354,15 +354,6 @@ (unsigned long)rq->nr_sectors - nsect); #endif /* DEBUG_READ */ -#ifdef CONFIG_IDE_TASKFILE_IO - task_bio_sectors(drive, rq, nsect, IDE_PIO_IN); - - /* FIXME: can we check status after transfer on pdc4030? */ - /* Complete previously submitted bios. */ - while (rq->bio != rq->cbio) - if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) - return ide_stopped; -#else /* CONFIG_IDE_TASKFILE_IO */ HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); rq->buffer += nsect<<9; rq->sector += nsect; @@ -370,7 +361,6 @@ rq->nr_sectors -= nsect; if (!rq->current_nr_sectors) DRIVER(drive)->end_request(drive, 1, 0); -#endif /* CONFIG_IDE_TASKFILE_IO */ /* * Now the data has been read in, do the following: @@ -421,12 +411,8 @@ static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); -#ifdef CONFIG_IDE_TASKFILE_IO - struct request *rq = hwgroup->rq; -#else struct request *rq = &hwgroup->wrq; struct bio *bio = rq->bio; -#endif if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { @@ -450,15 +436,10 @@ printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name); #endif /* DEBUG_WRITE */ -#ifdef CONFIG_IDE_TASKFILE_IO - /* Complete previously submitted bios. */ - while (rq->bio != rq->cbio) - (void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio)); -#else bio->bi_idx = bio->bi_vcnt - rq->nr_cbio_segments; rq = hwgroup->rq; DRIVER(drive)->end_request(drive, 1, rq->hard_nr_sectors); -#endif + return ide_stopped; } @@ -466,27 +447,6 @@ * promise_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. */ -#ifdef CONFIG_IDE_TASKFILE_IO -static void promise_multwrite (ide_drive_t *drive, unsigned int msect) -{ - struct request* rq = HWGROUP(drive)->rq; - unsigned int nsect; - - rq->errors = 0; - do { - nsect = rq->current_nr_sectors; - if (nsect > msect) - nsect = msect; - - task_bio_sectors(drive, rq, nsect, IDE_PIO_OUT); - - if (!rq->nr_sectors) - msect = 0; - else - msect -= nsect; - } while (msect); -} -#else /* CONFIG_IDE_TASKFILE_IO */ static void promise_multwrite (ide_drive_t *drive, unsigned int mcount) { ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -537,7 +497,6 @@ taskfile_output_data(drive, buffer, nsect<<7); } while (mcount); } -#endif /* * promise_write_pollfunc() is the handler for disk write completion polling. @@ -545,12 +504,8 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); -#ifdef CONFIG_IDE_TASKFILE_IO - struct request *rq = hwgroup->rq; -#else struct request *rq = &hwgroup->wrq; struct bio *bio = rq->bio; -#endif if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { @@ -564,19 +519,11 @@ } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: write timed-out!\n",drive->name); -#ifndef CONFIG_IDE_TASKFILE_IO bio->bi_idx = bio->bi_vcnt - rq->nr_cbio_segments; -#endif return DRIVER(drive)->error(drive, "write timeout", HWIF(drive)->INB(IDE_STATUS_REG)); } -#ifdef CONFIG_IDE_TASKFILE_IO - /* Complete previously submitted bios. */ - while (rq->bio != rq->cbio) - (void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio)); -#endif - /* * Now write out last 4 sectors and poll for not BUSY */ @@ -602,11 +549,7 @@ static ide_startstop_t promise_write (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); -#ifdef CONFIG_IDE_TASKFILE_IO - struct request *rq = hwgroup->rq; -#else struct request *rq = &hwgroup->wrq; -#endif #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: %s: sectors(%lu-%lu)\n", @@ -654,39 +597,14 @@ * already set up. It issues a READ or WRITE command to the Promise * controller, assuming LBA has been used to set up the block number. */ -#ifndef CONFIG_IDE_TASKFILE_IO ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; unsigned long timeout; u8 stat = 0; -#else -static ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task) -{ - struct request *rq = HWGROUP(drive)->rq; - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - ide_startstop_t startstop; - unsigned long timeout; - u8 stat = 0; - - if (IDE_CONTROL_REG) - HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(drive, 0); - HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG); - HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); - /* refers to number of sectors to transfer */ - HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG); - /* refers to sector offset or start sector */ - HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); - HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); - HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG); - HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG); -#endif if (rq_data_dir(rq) == READ) { -#ifndef CONFIG_IDE_TASKFILE_IO HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG); -#endif /* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be @@ -722,9 +640,7 @@ "waiting - Odd!\n", drive->name); return ide_stopped; } else { -#ifndef CONFIG_IDE_TASKFILE_IO HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG); -#endif if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing " @@ -733,9 +649,7 @@ } if (!drive->unmask) local_irq_disable(); -#ifndef CONFIG_IDE_TASKFILE_IO HWGROUP(drive)->wrq = *rq; /* scratchpad */ -#endif return promise_write(drive); } } @@ -749,14 +663,9 @@ */ ide_hwif_t *hwif = HWIF(drive); int drive_number = (hwif->channel << 1) + drive->select.b.unit; -#ifdef CONFIG_IDE_TASKFILE_IO - struct hd_drive_task_hdr taskfile; - ide_task_t args; -#endif BUG_ON(rq->nr_sectors > 127); -#ifndef CONFIG_IDE_TASKFILE_IO if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); hwif->OUTB(drive_number, IDE_FEATURE_REG); @@ -767,27 +676,4 @@ hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); return do_pdc4030_io(drive, rq); -#else /* !CONFIG_IDE_TASKFILE_IO */ - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - - taskfile.feature = drive_number; - taskfile.sector_count = rq->nr_sectors; - taskfile.sector_number = block; - taskfile.low_cylinder = (block>>=8); - taskfile.high_cylinder = (block>>=8); - taskfile.device_head = ((block>>8)&0x0f)|drive->select.all; - taskfile.command = (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE; - - memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); - memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr)); - /* - * Setup the bits of args that we do need. - * Note that we don't use the generic interrupt handlers. - */ - args.handler = NULL; - args.rq = (struct request *) rq; - rq->special = (ide_task_t *)&args; - - return do_pdc4030_io(drive, &args); -#endif /* !CONFIG_IDE_TASKFILE_IO */ } diff -Nru a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h --- a/drivers/ide/legacy/qd65xx.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/ide/legacy/qd65xx.h 2004-10-18 14:57:04 -07:00 @@ -47,10 +47,10 @@ /* Drive specific timing taken from DOS driver v3.7 */ struct qd65xx_timing_s { - char offset; /* ofset from the beginning of Model Number" */ + s8 offset; /* ofset from the beginning of Model Number" */ char model[4]; /* 4 chars from Model number, no conversion */ - short active; /* active time */ - short recovery; /* recovery time */ + s16 active; /* active time */ + s16 recovery; /* recovery time */ } qd65xx_timing [] = { { 30, "2040", 110, 225 }, /* Conner CP30204 */ { 30, "2045", 135, 225 }, /* Conner CP30254 */ diff -Nru a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c --- a/drivers/ide/pci/aec62xx.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/ide/pci/aec62xx.c 2004-10-18 14:56:49 -07:00 @@ -29,8 +29,6 @@ static struct pci_dev *aec_devs[AEC_MAX_DEVS]; static int n_aec_devs; -#undef DEBUG_AEC_REGS - static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; @@ -44,9 +42,6 @@ struct pci_dev *dev = aec_devs[i]; unsigned long iobase = pci_resource_start(dev, 4); u8 c0 = 0, c1 = 0, art = 0; -#ifdef DEBUG_AEC_REGS - u8 uart = 0; -#endif /* DEBUG_AEC_REGS */ c0 = inb(iobase + 0x02); c1 = inb(iobase + 0x0a); @@ -83,24 +78,6 @@ p += sprintf(p, " %s(%s)\n", (c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO", (art&0x80)?"2":(art&0x40)?"1":"0"); -#ifdef DEBUG_AEC_REGS - (void) pci_read_config_byte(dev, 0x40, &art); - p += sprintf(p, "Active: 0x%02x", art); - (void) pci_read_config_byte(dev, 0x42, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x44, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x46, &art); - p += sprintf(p, " 0x%02x\n", art); - (void) pci_read_config_byte(dev, 0x41, &art); - p += sprintf(p, "Recovery: 0x%02x", art); - (void) pci_read_config_byte(dev, 0x43, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x45, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x47, &art); - p += sprintf(p, " 0x%02x\n", art); -#endif /* DEBUG_AEC_REGS */ } else { /* * case PCI_DEVICE_ID_ARTOP_ATP860: @@ -146,28 +123,6 @@ ((art&0x30)==0x30)?"2": ((art&0x20)==0x20)?"1": ((art&0x10)==0x10)?"0":"?"); -#ifdef DEBUG_AEC_REGS - (void) pci_read_config_byte(dev, 0x40, &art); - p += sprintf(p, "Active: 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x41, &art); - p += sprintf(p, " 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x42, &art); - p += sprintf(p, " 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x43, &art); - p += sprintf(p, " 0x%02x\n", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x40, &art); - p += sprintf(p, "Recovery: 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x41, &art); - p += sprintf(p, " 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x42, &art); - p += sprintf(p, " 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x43, &art); - p += sprintf(p, " 0x%02x\n", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x49, &uart); - p += sprintf(p, "reg49h = 0x%02x ", uart); - (void) pci_read_config_byte(dev, 0x4a, &uart); - p += sprintf(p, "reg4ah = 0x%02x\n", uart); -#endif /* DEBUG_AEC_REGS */ } } /* p - buffer must be less than 4k! */ @@ -240,6 +195,7 @@ unsigned long flags; local_irq_save(flags); + /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */ pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); tmp0 = pci_bus_clock_list(speed, BUSCLOCK(dev)); SPLIT_BYTE(tmp0,tmp1,tmp2); @@ -268,6 +224,7 @@ unsigned long flags; local_irq_save(flags); + /* high 4-bits: Active, low 4-bits: Recovery */ pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); drive_conf = pci_bus_clock_list(speed, BUSCLOCK(dev)); pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); @@ -540,7 +497,7 @@ MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl); static struct pci_driver driver = { - .name = "AEC62xx IDE", + .name = "AEC62xx_IDE", .id_table = aec62xx_pci_tbl, .probe = aec62xx_init_one, }; diff -Nru a/drivers/ide/pci/aec62xx.h b/drivers/ide/pci/aec62xx.h --- a/drivers/ide/pci/aec62xx.h 2004-10-18 14:56:31 -07:00 +++ b/drivers/ide/pci/aec62xx.h 2004-10-18 14:56:31 -07:00 @@ -53,13 +53,6 @@ { 0, 0x00, 0x00 } }; - -#ifndef HIGH_4 -#define HIGH_4(H) ((H)=(H>>4)) -#endif -#ifndef LOW_4 -#define LOW_4(L) ((L)=(L-((L>>4)<<4))) -#endif #ifndef SPLIT_BYTE #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif diff -Nru a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c --- a/drivers/ide/pci/alim15x3.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/pci/alim15x3.c 2004-10-18 14:56:28 -07:00 @@ -752,8 +752,8 @@ hwif->tuneproc = &ali15x3_tune_drive; hwif->speedproc = &ali15x3_tune_chipset; - /* Don't use LBA48 on ALi devices before rev 0xC5 */ - hwif->no_lba48 = (m5229_revision <= 0xC4) ? 1 : 0; + /* don't use LBA48 DMA on ALi devices before rev 0xC5 */ + hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0; if (!hwif->dma_base) { hwif->drives[0].autotune = 1; @@ -893,7 +893,7 @@ MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); static struct pci_driver driver = { - .name = "ALI15x3 IDE", + .name = "ALI15x3_IDE", .id_table = alim15x3_pci_tbl, .probe = alim15x3_init_one, }; diff -Nru a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c --- a/drivers/ide/pci/amd74xx.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/ide/pci/amd74xx.c 2004-10-18 14:57:05 -07:00 @@ -416,6 +416,9 @@ { int i; + if (!hwif->irq) + hwif->irq = hwif->channel ? 15 : 14; + hwif->autodma = 0; hwif->tuneproc = &amd74xx_tune_drive; @@ -520,7 +523,7 @@ MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); static struct pci_driver driver = { - .name = "AMD IDE", + .name = "AMD_IDE", .id_table = amd74xx_pci_tbl, .probe = amd74xx_probe, }; diff -Nru a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c --- a/drivers/ide/pci/atiixp.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/ide/pci/atiixp.c 2004-10-18 14:56:29 -07:00 @@ -490,7 +490,7 @@ MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); static struct pci_driver driver = { - .name = "ATIIXP IDE", + .name = "ATIIXP_IDE", .id_table = atiixp_pci_tbl, .probe = atiixp_init_one, }; diff -Nru a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c --- a/drivers/ide/pci/cmd640.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/ide/pci/cmd640.c 2004-10-18 14:57:03 -07:00 @@ -101,6 +101,8 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ #define CMD640_PREFETCH_MASKS 1 +//#define CMD640_DUMP_REGS + #include #include #include @@ -748,7 +750,7 @@ put_cmd640_reg(0x5b, 0); #ifdef CMD640_DUMP_REGS - CMD640_DUMP_REGS; + cmd640_dump_regs(); #endif /* @@ -870,7 +872,7 @@ } #ifdef CMD640_DUMP_REGS - CMD640_DUMP_REGS; + cmd640_dump_regs(); #endif return 1; } diff -Nru a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c --- a/drivers/ide/pci/cmd64x.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/ide/pci/cmd64x.c 2004-10-18 14:57:03 -07:00 @@ -38,8 +38,6 @@ static struct pci_dev *cmd_devs[CMD_MAX_DEVS]; static int n_cmd_devs; -#undef DEBUG_CMD_REGS - static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) { char *p = buf; @@ -49,9 +47,6 @@ u8 reg72 = 0, reg73 = 0; /* primary */ u8 reg7a = 0, reg7b = 0; /* secondary */ u8 reg50 = 0, reg71 = 0; /* extra */ -#ifdef DEBUG_CMD_REGS - u8 hi_byte = 0, lo_byte = 0; -#endif /* DEBUG_CMD_REGS */ p += sprintf(p, "\nController: %d\n", index); p += sprintf(p, "CMD%x Chipset.\n", dev->device); @@ -127,18 +122,6 @@ (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled", (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled"); -#ifdef DEBUG_CMD_REGS - SPLIT_BYTE(reg50, hi_byte, lo_byte); - p += sprintf(p, "CFR = 0x%02x, HI = 0x%02x, " - "LOW = 0x%02x\n", reg50, hi_byte, lo_byte); - SPLIT_BYTE(reg57, hi_byte, lo_byte); - p += sprintf(p, "ARTTIM23 = 0x%02x, HI = 0x%02x, " - "LOW = 0x%02x\n", reg57, hi_byte, lo_byte); - SPLIT_BYTE(reg71, hi_byte, lo_byte); - p += sprintf(p, "MRDMODE = 0x%02x, HI = 0x%02x, " - "LOW = 0x%02x\n", reg71, hi_byte, lo_byte); -#endif /* DEBUG_CMD_REGS */ - return (char *)p; } @@ -760,7 +743,7 @@ MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl); static struct pci_driver driver = { - .name = "CMD64x IDE", + .name = "CMD64x_IDE", .id_table = cmd64x_pci_tbl, .probe = cmd64x_init_one, }; diff -Nru a/drivers/ide/pci/cmd64x.h b/drivers/ide/pci/cmd64x.h --- a/drivers/ide/pci/cmd64x.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/ide/pci/cmd64x.h 2004-10-18 14:56:29 -07:00 @@ -15,10 +15,6 @@ #define cmdprintk(x...) #endif -#ifndef SPLIT_BYTE -#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) -#endif - /* * CMD64x specific registers definition. */ diff -Nru a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c --- a/drivers/ide/pci/cs5520.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/ide/pci/cs5520.c 2004-10-18 14:55:54 -07:00 @@ -290,7 +290,10 @@ return 1; } pci_set_master(dev); - pci_set_dma_mask(dev, 0xFFFFFFFF); + if (pci_set_dma_mask(dev, 0xFFFFFFFF)) { + printk(KERN_WARNING "cs5520: No suitable DMA available.\n"); + return -ENODEV; + } init_chipset_cs5520(dev, d->name); index.all = 0xf0f0; @@ -319,7 +322,7 @@ MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl); static struct pci_driver driver = { - .name = "CyrixIDE", + .name = "Cyrix_IDE", .id_table = cs5520_pci_tbl, .probe = cs5520_init_one, }; diff -Nru a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c --- a/drivers/ide/pci/cy82c693.c 2004-10-18 14:56:16 -07:00 +++ b/drivers/ide/pci/cy82c693.c 2004-10-18 14:56:16 -07:00 @@ -444,7 +444,7 @@ MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl); static struct pci_driver driver = { - .name = "Cypress IDE", + .name = "Cypress_IDE", .id_table = cy82c693_pci_tbl, .probe = cy82c693_init_one, }; diff -Nru a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c --- a/drivers/ide/pci/generic.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/ide/pci/generic.c 2004-10-18 14:56:32 -07:00 @@ -138,7 +138,7 @@ MODULE_DEVICE_TABLE(pci, generic_pci_tbl); static struct pci_driver driver = { - .name = "PCI IDE", + .name = "PCI_IDE", .id_table = generic_pci_tbl, .probe = generic_init_one, }; diff -Nru a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c --- a/drivers/ide/pci/hpt34x.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/pci/hpt34x.c 2004-10-18 14:56:28 -07:00 @@ -44,65 +44,6 @@ #include "hpt34x.h" -#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) -#include -#include - -static u8 hpt34x_proc = 0; - -#define HPT34X_MAX_DEVS 8 -static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS]; -static int n_hpt34x_devs; - -static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - int i, len; - - p += sprintf(p, "\n " - "HPT34X Chipset.\n"); - for (i = 0; i < n_hpt34x_devs; i++) { - struct pci_dev *dev = hpt34x_devs[i]; - unsigned long bibma = pci_resource_start(dev, 4); - u8 c0 = 0, c1 = 0; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((u16)bibma + 0x02); - c1 = inb_p((u16)bibma + 0x0a); - p += sprintf(p, "\nController: %d\n", i); - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - p += sprintf(p, " %sabled " - " %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 " - "-------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s" - " %s %s\n", - (c0&0x20) ? "yes" : "no ", - (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", - (c1&0x40) ? "yes" : "no " ); - - p += sprintf(p, "UDMA\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); - } - p += sprintf(p, "\n"); - - /* p - buffer must be less than 4k! */ - len = (p - buffer) - offset; - *addr = buffer + offset; - - return len > count ? count : len; -} -#endif /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */ - static u8 hpt34x_ratemask (ide_drive_t *drive) { return 1; @@ -277,15 +218,6 @@ local_irq_restore(flags); -#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) - hpt34x_devs[n_hpt34x_devs++] = dev; - - if (!hpt34x_proc) { - hpt34x_proc = 1; - ide_pci_create_host_proc("hpt34x", hpt34x_get_info); - } -#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */ - return dev->irq; } @@ -339,7 +271,7 @@ MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl); static struct pci_driver driver = { - .name = "HPT34x IDE", + .name = "HPT34x_IDE", .id_table = hpt34x_pci_tbl, .probe = hpt34x_init_one, }; diff -Nru a/drivers/ide/pci/hpt34x.h b/drivers/ide/pci/hpt34x.h --- a/drivers/ide/pci/hpt34x.h 2004-10-18 14:55:53 -07:00 +++ b/drivers/ide/pci/hpt34x.h 2004-10-18 14:55:53 -07:00 @@ -11,8 +11,6 @@ #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif -#undef DISPLAY_HPT34X_TIMINGS - static unsigned int init_chipset_hpt34x(struct pci_dev *, const char *); static void init_hwif_hpt34x(ide_hwif_t *); diff -Nru a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c --- a/drivers/ide/pci/hpt366.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/ide/pci/hpt366.c 2004-10-18 14:56:33 -07:00 @@ -777,9 +777,6 @@ u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40; u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53; - if (!hwif) - return -EINVAL; - // hwif->bus_state = state; pci_read_config_byte(dev, 0x59, ®59h); @@ -813,9 +810,6 @@ u8 tristate = 0, resetmask = 0, bus_reg = 0; u16 tri_reg; - if (!hwif) - return -EINVAL; - hwif->bus_state = state; if (hwif->channel) { @@ -958,7 +952,7 @@ /* Unsupported */ } else if (pll == F_LOW_PCI_50) { if (hpt_minimum_revision(dev,8)) - pci_set_drvdata(dev, NULL); + pci_set_drvdata(dev, (void *) fifty_base_hpt370a); else if (hpt_minimum_revision(dev,5)) pci_set_drvdata(dev, (void *) fifty_base_hpt372); else if (hpt_minimum_revision(dev,4)) @@ -991,11 +985,6 @@ if (pci_get_drvdata(dev)) goto init_hpt37X_done; - if (hpt_minimum_revision(dev,8)) - { - printk(KERN_ERR "HPT374: Only 33MHz PCI timings are supported.\n"); - return -EOPNOTSUPP; - } /* * adjust PLL based upon PCI clock, enable it, and wait for * stabilization. @@ -1403,7 +1392,7 @@ MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl); static struct pci_driver driver = { - .name = "HPT366 IDE", + .name = "HPT366_IDE", .id_table = hpt366_pci_tbl, .probe = hpt366_init_one, }; diff -Nru a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c --- a/drivers/ide/pci/it8172.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/ide/pci/it8172.c 2004-10-18 14:56:49 -07:00 @@ -302,7 +302,7 @@ MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); static struct pci_driver driver = { - .name = "IT8172IDE", + .name = "IT8172_IDE", .id_table = it8172_pci_tbl, .probe = it8172_init_one, }; diff -Nru a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c --- a/drivers/ide/pci/ns87415.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/ide/pci/ns87415.c 2004-10-18 14:56:29 -07:00 @@ -236,7 +236,7 @@ MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); static struct pci_driver driver = { - .name = "NS87415IDE", + .name = "NS87415_IDE", .id_table = ns87415_pci_tbl, .probe = ns87415_init_one, }; diff -Nru a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c --- a/drivers/ide/pci/opti621.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/pci/opti621.c 2004-10-18 14:56:28 -07:00 @@ -367,7 +367,7 @@ MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); static struct pci_driver driver = { - .name = "Opti621 IDE", + .name = "Opti621_IDE", .id_table = opti621_pci_tbl, .probe = opti621_init_one, }; diff -Nru a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c --- a/drivers/ide/pci/pdc202xx_new.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/ide/pci/pdc202xx_new.c 2004-10-18 14:56:49 -07:00 @@ -531,7 +531,7 @@ MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl); static struct pci_driver driver = { - .name = "Promise IDE", + .name = "Promise_IDE", .id_table = pdc202new_pci_tbl, .probe = pdc202new_init_one, }; diff -Nru a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c --- a/drivers/ide/pci/pdc202xx_old.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/ide/pci/pdc202xx_old.c 2004-10-18 14:57:04 -07:00 @@ -314,17 +314,6 @@ pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); } -#if PDC202XX_DECODE_REGISTER_INFO - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - pci_read_config_byte(dev, (drive_pci)|0x03, &DP); - - decode_registers(REG_A, AP); - decode_registers(REG_B, BP); - decode_registers(REG_C, CP); - decode_registers(REG_D, DP); -#endif /* PDC202XX_DECODE_REGISTER_INFO */ #if PDC202XX_DEBUG_DRIVE_INFO printk(KERN_DEBUG "%s: %s drive%d 0x%08x ", drive->name, ide_xfer_verbose(speed), @@ -905,7 +894,7 @@ MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl); static struct pci_driver driver = { - .name = "Promise Old IDE", + .name = "Promise_Old_IDE", .id_table = pdc202xx_pci_tbl, .probe = pdc202xx_init_one, }; diff -Nru a/drivers/ide/pci/pdc202xx_old.h b/drivers/ide/pci/pdc202xx_old.h --- a/drivers/ide/pci/pdc202xx_old.h 2004-10-18 14:55:53 -07:00 +++ b/drivers/ide/pci/pdc202xx_old.h 2004-10-18 14:55:53 -07:00 @@ -10,7 +10,6 @@ #endif #define PDC202XX_DEBUG_DRIVE_INFO 0 -#define PDC202XX_DECODE_REGISTER_INFO 0 static const char *pdc_quirk_drives[] = { "QUANTUM FIREBALLlct08 08", @@ -98,76 +97,6 @@ #define MC2 0x04 /* DMA"C" timing */ #define MC1 0x02 /* DMA"C" timing */ #define MC0 0x01 /* DMA"C" timing */ - -#if PDC202XX_DECODE_REGISTER_INFO - -#define REG_A 0x01 -#define REG_B 0x02 -#define REG_C 0x04 -#define REG_D 0x08 - -static void decode_registers (u8 registers, u8 value) -{ - u8 bit = 0, bit1 = 0, bit2 = 0; - - switch(registers) { - case REG_A: - bit2 = 0; - printk("A Register "); - if (value & 0x80) printk("SYNC_IN "); - if (value & 0x40) printk("ERRDY_EN "); - if (value & 0x20) printk("IORDY_EN "); - if (value & 0x10) printk("PREFETCH_EN "); - if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; } - if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; } - if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; } - if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; } - printk("PIO(A) = %d ", bit2); - break; - case REG_B: - bit1 = 0;bit2 = 0; - printk("B Register "); - if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; } - if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; } - if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; } - printk("DMA(B) = %d ", bit1 >> 5); - if (value & 0x10) printk("PIO_FORCED/PB4 "); - if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; } - if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; } - if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; } - if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; } - printk("PIO(B) = %d ", bit2); - break; - case REG_C: - bit2 = 0; - printk("C Register "); - if (value & 0x80) printk("DMARQp "); - if (value & 0x40) printk("IORDYp "); - if (value & 0x20) printk("DMAR_EN "); - if (value & 0x10) printk("DMAW_EN "); - - if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; } - if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; } - if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; } - if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; } - printk("DMA(C) = %d ", bit2); - break; - case REG_D: - printk("D Register "); - break; - default: - return; - } - printk("\n %s ", (registers & REG_D) ? "DP" : - (registers & REG_C) ? "CP" : - (registers & REG_B) ? "BP" : - (registers & REG_A) ? "AP" : "ERROR"); - for (bit=128;bit>0;bit/=2) - printk("%s", (value & bit) ? "1" : "0"); - printk("\n"); -} - -#endif /* PDC202XX_DECODE_REGISTER_INFO */ #define DISPLAY_PDC202XX_TIMINGS diff -Nru a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c --- a/drivers/ide/pci/piix.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/ide/pci/piix.c 2004-10-18 14:55:54 -07:00 @@ -561,36 +561,31 @@ drive->init_speed = 0; if ((id->capability & 1) && drive->autodma) { + /* Consult the list of known "bad" drives */ if (__ide_dma_bad_drive(drive)) goto fast_ata_pio; - if (id->field_valid & 4) { - if (id->dma_ultra & hwif->ultra_mask) { - /* Force if Capable UltraDMA */ - if ((id->field_valid & 2) && - (!piix_config_drive_for_dma(drive))) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if ((id->dma_mword & hwif->mwdma_mask) || - (id->dma_1word & hwif->swdma_mask)) { - /* Force if Capable regular DMA modes */ - if (!piix_config_drive_for_dma(drive)) - goto no_dma_set; - } - } else if (__ide_dma_good_drive(drive) && - (id->eide_dma_time < 150)) { - /* Consult the list of known "good" drives */ - if (!piix_config_drive_for_dma(drive)) - goto no_dma_set; - } else { - goto fast_ata_pio; + + /** + * Try to turn DMA on if: + * - UDMA or EIDE modes are supported or + * - drive is a known "good" drive + * + * Checks for best mode supported are down later by + * piix_config_drive_for_dma() -> ide_dma_speed() + */ + if ((id->field_valid & (4 | 2)) || + (__ide_dma_good_drive(drive) && id->eide_dma_time < 150)) { + if (piix_config_drive_for_dma(drive)) + return hwif->ide_dma_on(drive); } - return hwif->ide_dma_on(drive); + + /* For some reason DMA wasn't turned on, so try PIO. */ + goto fast_ata_pio; + } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: -no_dma_set: + /* Find best PIO mode. */ hwif->tuneproc(drive, 255); return hwif->ide_dma_off_quietly(drive); } @@ -803,7 +798,7 @@ MODULE_DEVICE_TABLE(pci, piix_pci_tbl); static struct pci_driver driver = { - .name = "PIIX IDE", + .name = "PIIX_IDE", .id_table = piix_pci_tbl, .probe = piix_init_one, }; diff -Nru a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c --- a/drivers/ide/pci/rz1000.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/pci/rz1000.c 2004-10-18 14:56:28 -07:00 @@ -74,7 +74,7 @@ MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl); static struct pci_driver driver = { - .name = "RZ1000 IDE", + .name = "RZ1000_IDE", .id_table = rz1000_pci_tbl, .probe = rz1000_init_one, }; diff -Nru a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c --- a/drivers/ide/pci/sc1200.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/ide/pci/sc1200.c 2004-10-18 14:56:33 -07:00 @@ -565,7 +565,7 @@ MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl); static struct pci_driver driver = { - .name = "SC1200 IDE", + .name = "SC1200_IDE", .id_table = sc1200_pci_tbl, .probe = sc1200_init_one, .suspend = sc1200_suspend, diff -Nru a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c --- a/drivers/ide/pci/serverworks.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/ide/pci/serverworks.c 2004-10-18 14:55:54 -07:00 @@ -812,7 +812,7 @@ MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); static struct pci_driver driver = { - .name = "Serverworks IDE", + .name = "Serverworks_IDE", .id_table = svwks_pci_tbl, .probe = svwks_init_one, #if 0 /* FIXME: implement */ diff -Nru a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c --- a/drivers/ide/pci/sgiioc4.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/ide/pci/sgiioc4.c 2004-10-18 14:56:32 -07:00 @@ -570,7 +570,6 @@ use_pio_instead: pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction); - hwif->sg_dma_active = 0; return 0; /* revert to PIO for this request */ } @@ -702,6 +701,10 @@ hwif->name, d->name); probe_hwif_init(hwif); + + /* Create /proc/ide entries */ + create_proc_ide_interfaces(); + return 0; } @@ -782,7 +785,7 @@ MODULE_DEVICE_TABLE(pci, sgiioc4_pci_tbl); static struct pci_driver driver = { - .name = "SGI-IOC4 IDE", + .name = "SGI-IOC4_IDE", .id_table = sgiioc4_pci_tbl, .probe = sgiioc4_init_one, }; diff -Nru a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c --- a/drivers/ide/pci/siimage.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/pci/siimage.c 2004-10-18 14:56:28 -07:00 @@ -727,8 +727,7 @@ unsigned long bar5 = pci_resource_start(dev, 5); unsigned long barsize = pci_resource_len(dev, 5); u8 tmpbyte = 0; - unsigned long addr; - void *ioaddr; + void __iomem *ioaddr; /* * Drop back to PIO if we can't map the mmio. Some @@ -751,22 +750,21 @@ } pci_set_master(dev); - pci_set_drvdata(dev, ioaddr); - addr = (unsigned long) ioaddr; + pci_set_drvdata(dev, (void *) ioaddr); if (pdev_is_sata(dev)) { - writel(0, addr + 0x148); - writel(0, addr + 0x1C8); + writel(0, ioaddr + 0x148); + writel(0, ioaddr + 0x1C8); } - writeb(0, addr + 0xB4); - writeb(0, addr + 0xF4); - tmpbyte = readb(addr + 0x4A); + writeb(0, ioaddr + 0xB4); + writeb(0, ioaddr + 0xF4); + tmpbyte = readb(ioaddr + 0x4A); switch(tmpbyte & 0x30) { case 0x00: /* In 100 MHz clocking, try and switch to 133 */ - writeb(tmpbyte|0x10, addr + 0x4A); + writeb(tmpbyte|0x10, ioaddr + 0x4A); break; case 0x10: /* On 133Mhz clocking */ @@ -777,29 +775,29 @@ case 0x30: /* Clocking is disabled */ /* 133 clock attempt to force it on */ - writeb(tmpbyte & ~0x20, addr + 0x4A); + writeb(tmpbyte & ~0x20, ioaddr + 0x4A); break; } - writeb( 0x72, addr + 0xA1); - writew( 0x328A, addr + 0xA2); - writel(0x62DD62DD, addr + 0xA4); - writel(0x43924392, addr + 0xA8); - writel(0x40094009, addr + 0xAC); - writeb( 0x72, addr + 0xE1); - writew( 0x328A, addr + 0xE2); - writel(0x62DD62DD, addr + 0xE4); - writel(0x43924392, addr + 0xE8); - writel(0x40094009, addr + 0xEC); + writeb( 0x72, ioaddr + 0xA1); + writew( 0x328A, ioaddr + 0xA2); + writel(0x62DD62DD, ioaddr + 0xA4); + writel(0x43924392, ioaddr + 0xA8); + writel(0x40094009, ioaddr + 0xAC); + writeb( 0x72, ioaddr + 0xE1); + writew( 0x328A, ioaddr + 0xE2); + writel(0x62DD62DD, ioaddr + 0xE4); + writel(0x43924392, ioaddr + 0xE8); + writel(0x40094009, ioaddr + 0xEC); if (pdev_is_sata(dev)) { - writel(0xFFFF0000, addr + 0x108); - writel(0xFFFF0000, addr + 0x188); - writel(0x00680000, addr + 0x148); - writel(0x00680000, addr + 0x1C8); + writel(0xFFFF0000, ioaddr + 0x108); + writel(0xFFFF0000, ioaddr + 0x188); + writel(0x00680000, ioaddr + 0x148); + writel(0x00680000, ioaddr + 0x1C8); } - tmpbyte = readb(addr + 0x4A); + tmpbyte = readb(ioaddr + 0x4A); proc_reports_siimage(dev, (tmpbyte>>4), name); return 1; @@ -1137,7 +1135,7 @@ MODULE_DEVICE_TABLE(pci, siimage_pci_tbl); static struct pci_driver driver = { - .name = "SiI IDE", + .name = "SiI_IDE", .id_table = siimage_pci_tbl, .probe = siimage_init_one, }; diff -Nru a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c --- a/drivers/ide/pci/sis5513.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/ide/pci/sis5513.c 2004-10-18 14:56:31 -07:00 @@ -788,6 +788,15 @@ if (trueid == 0x5518) { printk(KERN_INFO "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n"); chipset_family = ATA_133; + + /* Check for 5513 compability mapping + * We must use this, else the port enabled code will fail, + * as it expects the enablebits at 0x4a. + */ + if ((idemisc & 0x40000000) == 0) { + pci_write_config_dword(dev, 0x54, idemisc | 0x40000000); + printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n"); + } } } @@ -963,12 +972,13 @@ static struct pci_device_id sis5513_pci_tbl[] = { { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5518, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl); static struct pci_driver driver = { - .name = "SIS IDE", + .name = "SIS_IDE", .id_table = sis5513_pci_tbl, .probe = sis5513_init_one, }; diff -Nru a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c --- a/drivers/ide/pci/sl82c105.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/pci/sl82c105.c 2004-10-18 14:56:28 -07:00 @@ -503,7 +503,7 @@ MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl); static struct pci_driver driver = { - .name = "W82C105 IDE", + .name = "W82C105_IDE", .id_table = sl82c105_pci_tbl, .probe = sl82c105_init_one, }; diff -Nru a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c --- a/drivers/ide/pci/slc90e66.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/ide/pci/slc90e66.c 2004-10-18 14:56:49 -07:00 @@ -387,7 +387,7 @@ MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl); static struct pci_driver driver = { - .name = "SLC90e66 IDE", + .name = "SLC90e66_IDE", .id_table = slc90e66_pci_tbl, .probe = slc90e66_init_one, }; diff -Nru a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c --- a/drivers/ide/pci/triflex.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/ide/pci/triflex.c 2004-10-18 14:56:28 -07:00 @@ -41,57 +41,6 @@ #include #include -static struct pci_dev *triflex_dev; - -#ifdef CONFIG_PROC_FS -static int triflex_get_info(char *buf, char **addr, off_t offset, int count) -{ - char *p = buf; - int len; - - struct pci_dev *dev = triflex_dev; - unsigned long bibma = pci_resource_start(dev, 4); - u8 c0 = 0, c1 = 0; - u32 pri_timing, sec_timing; - - p += sprintf(p, "\n Compaq Triflex Chipset\n"); - - pci_read_config_dword(dev, 0x70, &pri_timing); - pci_read_config_dword(dev, 0x74, &sec_timing); - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb((unsigned short)bibma + 0x02); - c1 = inb((unsigned short)bibma + 0x0a); - - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - p += sprintf(p, " %sabled " - " %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 " - "-------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s " - " %s %s\n", - (c0&0x20) ? "yes" : "no ", - (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", - (c1&0x40) ? "yes" : "no " ); - - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); - - len = (p - buf) - offset; - *addr = buf + offset; - - return len > count ? count : len; -} -#endif - static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); @@ -206,18 +155,8 @@ hwif->drives[1].autodma = hwif->autodma; } -static unsigned int __init init_chipset_triflex(struct pci_dev *dev, - const char *name) -{ -#ifdef CONFIG_PROC_FS - ide_pci_create_host_proc("triflex", triflex_get_info); -#endif - return 0; -} - static ide_pci_device_t triflex_device __devinitdata = { .name = "TRIFLEX", - .init_chipset = init_chipset_triflex, .init_hwif = init_hwif_triflex, .channels = 2, .autodma = AUTODMA, @@ -229,7 +168,6 @@ const struct pci_device_id *id) { ide_setup_pci_device(dev, &triflex_device); - triflex_dev = dev; return 0; } @@ -242,7 +180,7 @@ MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); static struct pci_driver driver = { - .name = "TRIFLEX IDE", + .name = "TRIFLEX_IDE", .id_table = triflex_pci_tbl, .probe = triflex_init_one, }; diff -Nru a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c --- a/drivers/ide/pci/trm290.c 2004-10-18 14:56:19 -07:00 +++ b/drivers/ide/pci/trm290.c 2004-10-18 14:56:19 -07:00 @@ -408,7 +408,7 @@ MODULE_DEVICE_TABLE(pci, trm290_pci_tbl); static struct pci_driver driver = { - .name = "TRM290 IDE", + .name = "TRM290_IDE", .id_table = trm290_pci_tbl, .probe = trm290_init_one, }; diff -Nru a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c --- a/drivers/ide/pci/via82cxxx.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/ide/pci/via82cxxx.c 2004-10-18 14:55:53 -07:00 @@ -632,7 +632,7 @@ MODULE_DEVICE_TABLE(pci, via_pci_tbl); static struct pci_driver driver = { - .name = "VIA IDE", + .name = "VIA_IDE", .id_table = via_pci_tbl, .probe = via_init_one, }; diff -Nru a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c --- a/drivers/ide/ppc/pmac.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/ide/ppc/pmac.c 2004-10-18 14:55:54 -07:00 @@ -62,10 +62,10 @@ int irq; int kind; int aapl_bus_id; - int cable_80 : 1; - int mediabay : 1; - int broken_dma : 1; - int broken_dma_warn : 1; + unsigned cable_80 : 1; + unsigned mediabay : 1; + unsigned broken_dma : 1; + unsigned broken_dma_warn : 1; struct device_node* node; struct macio_dev *mdev; u32 timings[4]; @@ -75,7 +75,7 @@ * beeing done by the generic code about the kind of dma controller * and format of the dma table. This will have to be fixed though. */ - volatile struct dbdma_regs* dma_regs; + volatile struct dbdma_regs __iomem * dma_regs; struct dbdma_cmd* dma_table_cpu; dma_addr_t dma_table_dma; struct scatterlist* sg_table; @@ -497,6 +497,8 @@ *irq = pmac_ide[ix].irq; } +#define PMAC_IDE_REG(x) ((void __iomem *)(IDE_DATA_REG+(x))) + /* * Apply the timings of the proper unit (master/slave) to the shared * timing register when selecting that unit. This version is for @@ -511,12 +513,10 @@ return; if (drive->select.b.unit & 0x01) - writel(pmif->timings[1], - (unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); + writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG)); else - writel(pmif->timings[0], - (unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); - (void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); + writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG)); + (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } /* @@ -533,17 +533,13 @@ return; if (drive->select.b.unit & 0x01) { - writel(pmif->timings[1], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG)); - writel(pmif->timings[3], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG)); + writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); + writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); } else { - writel(pmif->timings[0], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG)); - writel(pmif->timings[2], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG)); + writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); + writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); } - (void)readl((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG)); + (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); } /* @@ -568,8 +564,8 @@ { u32 tmp; - writeb(value, port); - tmp = readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG)); + writeb(value, (void __iomem *) port); + tmp = readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } /* @@ -792,7 +788,7 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, u8 speed, int drive_cycle_time) { - int cycleTime, accessTime, recTime; + int cycleTime, accessTime = 0, recTime = 0; unsigned accessTicks, recTicks; struct mdma_timings_t* tm = NULL; int i; @@ -1281,7 +1277,8 @@ static int __devinit pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match) { - unsigned long base, regbase; + void __iomem *base; + unsigned long regbase; int irq; ide_hwif_t *hwif; pmac_ide_hwif_t *pmif; @@ -1324,8 +1321,8 @@ } else irq = macio_irq(mdev, 0); - base = (unsigned long)ioremap(macio_resource_start(mdev, 0), 0x400); - regbase = base; + base = ioremap(macio_resource_start(mdev, 0), 0x400); + regbase = (unsigned long) base; hwif->pci_dev = mdev->bus->pdev; hwif->gendev.parent = &mdev->ofdev.dev; @@ -1339,8 +1336,7 @@ if (macio_request_resource(mdev, 1, "ide-pmac (dma)")) printk(KERN_WARNING "ide%d: can't request DMA resource !\n", i); else - pmif->dma_regs = (volatile struct dbdma_regs*) - ioremap(macio_resource_start(mdev, 1), 0x1000); + pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000); } else pmif->dma_regs = NULL; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ @@ -1350,9 +1346,9 @@ if (rc != 0) { /* The inteface is released to the common IDE layer */ dev_set_drvdata(&mdev->ofdev.dev, NULL); - iounmap((void *)base); + iounmap(base); if (pmif->dma_regs) - iounmap((void *)pmif->dma_regs); + iounmap(pmif->dma_regs); memset(pmif, 0, sizeof(*pmif)); macio_release_resource(mdev, 0); if (pmif->dma_regs) @@ -1401,7 +1397,7 @@ ide_hwif_t *hwif; struct device_node *np; pmac_ide_hwif_t *pmif; - unsigned long base; + void __iomem *base; unsigned long rbase, rlen; int i, rc; @@ -1444,10 +1440,10 @@ rbase = pci_resource_start(pdev, 0); rlen = pci_resource_len(pdev, 0); - base = (unsigned long) ioremap(rbase, rlen); - pmif->regbase = base + 0x2000; + base = ioremap(rbase, rlen); + pmif->regbase = (unsigned long) base + 0x2000; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - pmif->dma_regs = (volatile struct dbdma_regs*)(base + 0x1000); + pmif->dma_regs = base + 0x1000; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ /* We use the OF node irq mapping */ @@ -1462,7 +1458,7 @@ if (rc != 0) { /* The inteface is released to the common IDE layer */ pci_set_drvdata(pdev, NULL); - iounmap((void *)base); + iounmap(base); memset(pmif, 0, sizeof(*pmif)); pci_release_regions(pdev); } @@ -1578,9 +1574,6 @@ struct scatterlist *sg = pmif->sg_table; int nents; - if (hwif->sg_dma_active) - BUG(); - nents = blk_rq_map_sg(drive->queue, rq, sg); if (rq_data_dir(rq) == READ) @@ -1639,7 +1632,7 @@ int i, count = 0; ide_hwif_t *hwif = HWIF(drive); pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - volatile struct dbdma_regs *dma = pmif->dma_regs; + volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; struct scatterlist *sg; int wr = (rq_data_dir(rq) == WRITE); @@ -1715,7 +1708,6 @@ pmif->sg_table, pmif->sg_nents, pmif->sg_dma_direction); - hwif->sg_dma_active = 0; return 0; /* revert to PIO for this request */ } @@ -1731,7 +1723,6 @@ if (nents) { pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction); pmif->sg_nents = 0; - HWIF(drive)->sg_dma_active = 0; } } @@ -1912,8 +1903,8 @@ /* Apple adds 60ns to wrDataSetup on reads */ if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { writel(pmif->timings[unit] + (reading ? 0x00800000UL : 0), - (unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); - (void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG)); + PMAC_IDE_REG(IDE_TIMING_CONFIG)); + (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } drive->waiting_for_dma = 1; @@ -1992,7 +1983,7 @@ pmac_ide_dma_begin (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; if (pmif == NULL) return 1; @@ -2011,7 +2002,7 @@ pmac_ide_dma_end (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; u32 dstat; if (pmif == NULL) @@ -2039,7 +2030,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; unsigned long status, timeout; if (pmif == NULL) @@ -2107,7 +2098,7 @@ pmac_ide_dma_lostirq (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; unsigned long status; if (pmif == NULL) diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c --- a/drivers/ieee1394/eth1394.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/ieee1394/eth1394.c 2004-10-18 14:56:33 -07:00 @@ -132,7 +132,7 @@ }; /* Our ieee1394 highlevel driver */ -#define ETH1394_DRIVER_NAME "ip1394" +#define ETH1394_DRIVER_NAME "eth1394" static const char driver_name[] = ETH1394_DRIVER_NAME; static kmem_cache_t *packet_task_cache; @@ -850,7 +850,7 @@ skb->mac.raw = skb->data; skb_pull (skb, ETH1394_HLEN); - eth = (struct eth1394hdr*)skb->mac.raw; + eth = eth1394_hdr(skb); if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) diff -Nru a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h --- a/drivers/ieee1394/eth1394.h 2004-10-18 14:57:03 -07:00 +++ b/drivers/ieee1394/eth1394.h 2004-10-18 14:57:03 -07:00 @@ -81,7 +81,14 @@ unsigned short h_proto; /* packet type ID field */ } __attribute__((packed)); +#ifdef __KERNEL__ +#include +static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb) +{ + return (struct eth1394hdr *)skb->mac.raw; +} +#endif typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; diff -Nru a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h --- a/drivers/ieee1394/ohci1394.h 2004-10-18 14:55:55 -07:00 +++ b/drivers/ieee1394/ohci1394.h 2004-10-18 14:55:55 -07:00 @@ -163,7 +163,7 @@ } init_state; /* remapped memory spaces */ - void *registers; + void __iomem *registers; /* dma buffer for self-id packets */ quadlet_t *selfid_buf_cpu; diff -Nru a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c --- a/drivers/input/gameport/cs461x.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/gameport/cs461x.c 2004-10-18 14:55:54 -07:00 @@ -312,7 +312,7 @@ } static struct pci_driver cs461x_pci_driver = { - .name = "CS461x Gameport", + .name = "CS461x_gameport", .id_table = cs461x_pci_tbl, .probe = cs461x_pci_probe, .remove = __devexit_p(cs461x_pci_remove), diff -Nru a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c --- a/drivers/input/gameport/emu10k1-gp.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/input/gameport/emu10k1-gp.c 2004-10-18 14:56:33 -07:00 @@ -50,8 +50,11 @@ }; static struct pci_device_id emu_tbl[] = { + { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ + { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ + { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */ { 0, } }; @@ -109,7 +112,7 @@ } static struct pci_driver emu_driver = { - .name = "Emu10k1 Gameport", + .name = "Emu10k1_gameport", .id_table = emu_tbl, .probe = emu_probe, .remove = __devexit_p(emu_remove), diff -Nru a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c --- a/drivers/input/gameport/fm801-gp.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/input/gameport/fm801-gp.c 2004-10-18 14:56:33 -07:00 @@ -137,7 +137,7 @@ }; static struct pci_driver fm801_gp_driver = { - .name = "FM801 GP", + .name = "FM801_gameport", .id_table = fm801_gp_id_table, .probe = fm801_gp_probe, .remove = __devexit_p(fm801_gp_remove), diff -Nru a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c --- a/drivers/input/gameport/vortex.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/input/gameport/vortex.c 2004-10-18 14:56:49 -07:00 @@ -55,8 +55,8 @@ struct vortex { struct gameport gameport; struct pci_dev *dev; - unsigned char *base; - unsigned char *io; + unsigned char __iomem *base; + unsigned char __iomem *io; char phys[32]; }; @@ -166,7 +166,7 @@ { 0 }}; static struct pci_driver vortex_driver = { - .name = "vortex", + .name = "vortex_gameport", .id_table = vortex_id_table, .probe = vortex_probe, .remove = __devexit_p(vortex_remove), diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c --- a/drivers/input/joydev.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/input/joydev.c 2004-10-18 14:56:31 -07:00 @@ -232,8 +232,10 @@ && list->head == list->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(list->joydev->wait, list->joydev->exist - && (list->startup < joydev->nabs + joydev->nkey || list->head != list->tail)); + retval = wait_event_interruptible(list->joydev->wait, + !list->joydev->exist || + list->startup < joydev->nabs + joydev->nkey || + list->head != list->tail); if (retval) return retval; diff -Nru a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig --- a/drivers/input/joystick/Kconfig 2004-10-18 14:55:53 -07:00 +++ b/drivers/input/joystick/Kconfig 2004-10-18 14:55:53 -07:00 @@ -247,9 +247,9 @@ To compile this driver as a module, choose M here: the module will be called amijoy. -config INPUT_JOYDUMP +config JOYSTICK_JOYDUMP tristate "Gameport data dumper" - depends on INPUT && INPUT_JOYSTICK + depends on INPUT && INPUT_JOYSTICK && GAMEPORT help Say Y here if you want to dump data from your joystick into the system log for debugging purposes. Say N if you are making a production diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c --- a/drivers/input/joystick/gamecon.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/input/joystick/gamecon.c 2004-10-18 14:57:05 -07:00 @@ -1,7 +1,8 @@ /* - * $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $ + * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux * - * Copyright (c) 1999-2001 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Peter Nelson * * Based on the work of: * Andree Borrmann John Dahlstrom @@ -9,10 +10,6 @@ */ /* - * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux - */ - -/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -72,8 +69,9 @@ #define GC_MULTI2 5 #define GC_N64 6 #define GC_PSX 7 +#define GC_DDR 8 -#define GC_MAX 7 +#define GC_MAX 8 #define GC_REFRESH_TIME HZ/100 @@ -91,7 +89,8 @@ static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", - "Multisystem 2-button joystick", "N64 controller", "PSX controller" }; + "Multisystem 2-button joystick", "N64 controller", "PSX controller" + "PSX DDR controller" }; /* * N64 support. */ @@ -237,7 +236,7 @@ #define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ #define GC_PSX_CLOCK 0x04 /* Pin 4 */ -#define GC_PSX_COMMAND 0x01 /* Pin 1 */ +#define GC_PSX_COMMAND 0x01 /* Pin 2 */ #define GC_PSX_POWER 0xf8 /* Pins 5-9 */ #define GC_PSX_SELECT 0x02 /* Pin 3 */ @@ -253,25 +252,29 @@ static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; +static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 }; /* * gc_psx_command() writes 8bit command and reads 8bit data from * the psx pad. */ -static int gc_psx_command(struct gc *gc, int b) +static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH]) { - int i, cmd, data = 0; + int i, j, cmd, read; + for (i = 0; i < 5; i++) + data[i] = 0; for (i = 0; i < 8; i++, b >>= 1) { cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); udelay(gc_psx_delay); - data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; + read = parport_read_status(gc->pd->port) ^ 0x80; + for (j = 0; j < 5; j++) + data[j] |= (read & gc_status_bit[j] & gc->pads[GC_PSX]) ? (1 << i) : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); udelay(gc_psx_delay); } - return data; } /* @@ -279,30 +282,39 @@ * device identifier code. */ -static int gc_psx_read_packet(struct gc *gc, unsigned char *data) +static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5]) { - int i, id; + int i, j, max_len = 0; unsigned long flags; + unsigned char data2[5]; parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); local_irq_save(flags); - gc_psx_command(gc, 0x01); /* Access pad */ - id = gc_psx_command(gc, 0x42); /* Get device id */ - if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */ - for (i = 0; i < GC_PSX_LEN(id) * 2; i++) - data[i] = gc_psx_command(gc, 0); - } else id = 0; + gc_psx_command(gc, 0x01, data2); /* Access pad */ + gc_psx_command(gc, 0x42, id); /* Get device ids */ + gc_psx_command(gc, 0, data2); /* Dump status */ + + for (i =0; i < 5; i++) /* Find the longest pad */ + if((gc_status_bit[i] & gc->pads[GC_PSX]) && (GC_PSX_LEN(id[i]) > max_len)) + max_len = GC_PSX_LEN(id[i]); + + for (i = 0; i < max_len * 2; i++) { /* Read in all the data */ + gc_psx_command(gc, 0, data2); + for (j = 0; j < 5; j++) + data[j][i] = data2[j]; + } local_irq_restore(flags); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); - return GC_PSX_ID(id); + for(i = 0; i < 5; i++) /* Set id's to the real value */ + id[i] = GC_PSX_ID(id[i]); } /* @@ -316,6 +328,7 @@ struct gc *gc = (void *) private; struct input_dev *dev = gc->dev; unsigned char data[GC_MAX_LENGTH]; + unsigned char data_psx[5][GC_PSX_LENGTH]; int i, j, s; /* @@ -412,53 +425,72 @@ * PSX controllers */ - if (gc->pads[GC_PSX]) { + if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) { - for (i = 0; i < 5; i++) - if (gc->pads[GC_PSX] & gc_status_bit[i]) - break; + gc_psx_read_packet(gc, data_psx, data); - switch (gc_psx_read_packet(gc, data)) { + for (i = 0; i < 5; i++) { + switch (data[i]) { - case GC_PSX_RUMBLE: + case GC_PSX_RUMBLE: - input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04); - input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02); - input_sync(dev + i); + input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04); + input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02); - case GC_PSX_NEGCON: - case GC_PSX_ANALOG: + case GC_PSX_NEGCON: + case GC_PSX_ANALOG: - for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]); - input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80)); - input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10)); + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; - case GC_PSX_NORMAL: + case GC_PSX_NORMAL: + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); - input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); + /* for some reason if the extra axes are left unset they drift */ + /* for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], 128); + * This needs to be debugged properly, + * maybe fuzz processing needs to be done in input_sync() + * --vojtech + */ + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; + + case 0: /* not a pad, ignore */ + break; + } } } @@ -490,8 +522,7 @@ { struct gc *gc; struct parport *pp; - int i, j, psx; - unsigned char data[32]; + int i, j; if (config[0] < 0) return NULL; @@ -588,43 +619,22 @@ break; case GC_PSX: + case GC_DDR: + if(config[i + 1] == GC_DDR) { + for (j = 0; j < 4; j++) + set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit); + } else { + for (j = 0; j < 6; j++) { + set_bit(gc_psx_abs[j], gc->dev[i].absbit); + gc->dev[i].absmin[gc_psx_abs[j]] = 4; + gc->dev[i].absmax[gc_psx_abs[j]] = 252; + gc->dev[i].absflat[gc_psx_abs[j]] = 2; + } + } - psx = gc_psx_read_packet(gc, data); + for (j = 0; j < 12; j++) + set_bit(gc_psx_btn[j], gc->dev[i].keybit); - switch(psx) { - case GC_PSX_NEGCON: - case GC_PSX_NORMAL: - case GC_PSX_ANALOG: - case GC_PSX_RUMBLE: - - for (j = 0; j < 6; j++) { - psx = gc_psx_abs[j]; - set_bit(psx, gc->dev[i].absbit); - if (j < 4) { - gc->dev[i].absmin[psx] = 4; - gc->dev[i].absmax[psx] = 252; - gc->dev[i].absflat[psx] = 2; - } else { - gc->dev[i].absmin[psx] = -1; - gc->dev[i].absmax[psx] = 1; - } - } - - for (j = 0; j < 12; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); - - break; - - case 0: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_ERR "gamecon.c: No PSX controller found.\n"); - break; - - default: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," - " please report to .\n", psx); - } break; } diff -Nru a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c --- a/drivers/input/joystick/grip_mp.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/input/joystick/grip_mp.c 2004-10-18 14:57:03 -07:00 @@ -107,6 +107,8 @@ static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; +static void register_slot(int i, struct grip_mp *grip); + /* * Returns whether an odd or even number of bits are on in pkt. */ @@ -355,7 +357,6 @@ u32 packet; int joytype = 0; int slot = 0; - static void register_slot(int i, struct grip_mp *grip); /* Get a packet and check for validity */ diff -Nru a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c --- a/drivers/input/joystick/iforce/iforce-main.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/input/joystick/iforce/iforce-main.c 2004-10-18 14:56:28 -07:00 @@ -524,7 +524,7 @@ usb_register(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_register_device(&iforce_serio_dev); + serio_register_driver(&iforce_serio_drv); #endif return 0; } @@ -535,7 +535,7 @@ usb_deregister(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_unregister_device(&iforce_serio_dev); + serio_unregister_driver(&iforce_serio_drv); #endif } diff -Nru a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c --- a/drivers/input/joystick/iforce/iforce-serio.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/joystick/iforce/iforce-serio.c 2004-10-18 14:55:54 -07:00 @@ -124,7 +124,7 @@ return IRQ_HANDLED; } -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { struct iforce *iforce; if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) @@ -137,7 +137,7 @@ iforce->serio = serio; serio->private = iforce; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(iforce); return; } @@ -158,9 +158,13 @@ kfree(iforce); } -struct serio_dev iforce_serio_dev = { - .write_wakeup = iforce_serio_write_wakeup, - .interrupt = iforce_serio_irq, - .connect = iforce_serio_connect, - .disconnect = iforce_serio_disconnect, +struct serio_driver iforce_serio_drv = { + .driver = { + .name = "iforce", + }, + .description = "RS232 I-Force joysticks and wheels driver", + .write_wakeup = iforce_serio_write_wakeup, + .interrupt = iforce_serio_irq, + .connect = iforce_serio_connect, + .disconnect = iforce_serio_disconnect, }; diff -Nru a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h --- a/drivers/input/joystick/iforce/iforce.h 2004-10-18 14:57:20 -07:00 +++ b/drivers/input/joystick/iforce/iforce.h 2004-10-18 14:57:20 -07:00 @@ -187,5 +187,5 @@ int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); /* Public variables */ -extern struct serio_dev iforce_serio_dev; +extern struct serio_driver iforce_serio_drv; extern struct usb_driver iforce_usb_driver; diff -Nru a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c --- a/drivers/input/joystick/magellan.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/joystick/magellan.c 2004-10-18 14:55:54 -07:00 @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -146,7 +148,7 @@ * it as an input device. */ -static void magellan_connect(struct serio *serio, struct serio_dev *dev) +static void magellan_connect(struct serio *serio, struct serio_driver *drv) { struct magellan *magellan; int i, t; @@ -184,7 +186,7 @@ serio->private = magellan; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(magellan); return; } @@ -199,10 +201,14 @@ * The serio device structure. */ -static struct serio_dev magellan_dev = { - .interrupt = magellan_interrupt, - .connect = magellan_connect, - .disconnect = magellan_disconnect, +static struct serio_driver magellan_drv = { + .driver = { + .name = "magellan", + }, + .description = DRIVER_DESC, + .interrupt = magellan_interrupt, + .connect = magellan_connect, + .disconnect = magellan_disconnect, }; /* @@ -211,13 +217,13 @@ int __init magellan_init(void) { - serio_register_device(&magellan_dev); + serio_register_driver(&magellan_drv); return 0; } void __exit magellan_exit(void) { - serio_unregister_device(&magellan_dev); + serio_unregister_driver(&magellan_drv); } module_init(magellan_init); diff -Nru a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c --- a/drivers/input/joystick/spaceball.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/joystick/spaceball.c 2004-10-18 14:55:54 -07:00 @@ -39,8 +39,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -201,7 +203,7 @@ * it as an input device. */ -static void spaceball_connect(struct serio *serio, struct serio_dev *dev) +static void spaceball_connect(struct serio *serio, struct serio_driver *drv) { struct spaceball *spaceball; int i, t, id; @@ -254,7 +256,7 @@ serio->private = spaceball; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceball); return; } @@ -269,10 +271,14 @@ * The serio device structure. */ -static struct serio_dev spaceball_dev = { - .interrupt = spaceball_interrupt, - .connect = spaceball_connect, - .disconnect = spaceball_disconnect, +static struct serio_driver spaceball_drv = { + .driver = { + .name = "spaceball", + }, + .description = DRIVER_DESC, + .interrupt = spaceball_interrupt, + .connect = spaceball_connect, + .disconnect = spaceball_disconnect, }; /* @@ -281,13 +287,13 @@ int __init spaceball_init(void) { - serio_register_device(&spaceball_dev); + serio_register_driver(&spaceball_drv); return 0; } void __exit spaceball_exit(void) { - serio_unregister_device(&spaceball_dev); + serio_unregister_driver(&spaceball_drv); } module_init(spaceball_init); diff -Nru a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c --- a/drivers/input/joystick/spaceorb.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/input/joystick/spaceorb.c 2004-10-18 14:56:29 -07:00 @@ -38,8 +38,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -162,7 +164,7 @@ * it as an input device. */ -static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) +static void spaceorb_connect(struct serio *serio, struct serio_driver *drv) { struct spaceorb *spaceorb; int i, t; @@ -201,7 +203,7 @@ serio->private = spaceorb; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceorb); return; } @@ -213,10 +215,14 @@ * The serio device structure. */ -static struct serio_dev spaceorb_dev = { - .interrupt = spaceorb_interrupt, - .connect = spaceorb_connect, - .disconnect = spaceorb_disconnect, +static struct serio_driver spaceorb_drv = { + .driver = { + .name = "spaceorb", + }, + .description = DRIVER_DESC, + .interrupt = spaceorb_interrupt, + .connect = spaceorb_connect, + .disconnect = spaceorb_disconnect, }; /* @@ -225,13 +231,13 @@ int __init spaceorb_init(void) { - serio_register_device(&spaceorb_dev); + serio_register_driver(&spaceorb_drv); return 0; } void __exit spaceorb_exit(void) { - serio_unregister_device(&spaceorb_dev); + serio_unregister_driver(&spaceorb_drv); } module_init(spaceorb_init); diff -Nru a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c --- a/drivers/input/joystick/stinger.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/input/joystick/stinger.c 2004-10-18 14:55:53 -07:00 @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gravis Stinger gamepad driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gravis Stinger gamepad driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -134,7 +136,7 @@ * it as an input device. */ -static void stinger_connect(struct serio *serio, struct serio_dev *dev) +static void stinger_connect(struct serio *serio, struct serio_driver *drv) { struct stinger *stinger; int i; @@ -172,7 +174,7 @@ stinger->dev.private = stinger; serio->private = stinger; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(stinger); return; } @@ -187,10 +189,14 @@ * The serio device structure. */ -static struct serio_dev stinger_dev = { - .interrupt = stinger_interrupt, - .connect = stinger_connect, - .disconnect = stinger_disconnect, +static struct serio_driver stinger_drv = { + .driver = { + .name = "stinger", + }, + .description = DRIVER_DESC, + .interrupt = stinger_interrupt, + .connect = stinger_connect, + .disconnect = stinger_disconnect, }; /* @@ -199,13 +205,13 @@ int __init stinger_init(void) { - serio_register_device(&stinger_dev); + serio_register_driver(&stinger_drv); return 0; } void __exit stinger_exit(void) { - serio_unregister_device(&stinger_dev); + serio_unregister_driver(&stinger_drv); } module_init(stinger_init); diff -Nru a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c --- a/drivers/input/joystick/tmdc.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/input/joystick/tmdc.c 2004-10-18 14:56:28 -07:00 @@ -322,7 +322,7 @@ tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { - if (tmdc->abs[i] < 0) continue; + if (tmdc->abs[j][i] < 0) continue; set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit); tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8; tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248; diff -Nru a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c --- a/drivers/input/joystick/twidjoy.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/joystick/twidjoy.c 2004-10-18 14:55:54 -07:00 @@ -187,7 +187,7 @@ * it as an input device. */ -static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) +static void twidjoy_connect(struct serio *serio, struct serio_driver *drv) { struct twidjoy_button_spec *bp; struct twidjoy *twidjoy; @@ -232,7 +232,7 @@ twidjoy->dev.private = twidjoy; serio->private = twidjoy; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(twidjoy); return; } @@ -246,10 +246,14 @@ * The serio device structure. */ -static struct serio_dev twidjoy_dev = { - .interrupt = twidjoy_interrupt, - .connect = twidjoy_connect, - .disconnect = twidjoy_disconnect, +static struct serio_driver twidjoy_drv = { + .driver = { + .name = "twidjoy", + }, + .description = DRIVER_DESC, + .interrupt = twidjoy_interrupt, + .connect = twidjoy_connect, + .disconnect = twidjoy_disconnect, }; /* @@ -258,13 +262,13 @@ int __init twidjoy_init(void) { - serio_register_device(&twidjoy_dev); + serio_register_driver(&twidjoy_drv); return 0; } void __exit twidjoy_exit(void) { - serio_unregister_device(&twidjoy_dev); + serio_unregister_driver(&twidjoy_drv); } module_init(twidjoy_init); diff -Nru a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c --- a/drivers/input/joystick/warrior.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/input/joystick/warrior.c 2004-10-18 14:56:48 -07:00 @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Logitech WingMan Warrior joystick driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Logitech WingMan Warrior joystick driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -139,7 +141,7 @@ * it as an input device. */ -static void warrior_connect(struct serio *serio, struct serio_dev *dev) +static void warrior_connect(struct serio *serio, struct serio_driver *drv) { struct warrior *warrior; int i; @@ -185,7 +187,7 @@ serio->private = warrior; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(warrior); return; } @@ -199,10 +201,14 @@ * The serio device structure. */ -static struct serio_dev warrior_dev = { - .interrupt = warrior_interrupt, - .connect = warrior_connect, - .disconnect = warrior_disconnect, +static struct serio_driver warrior_drv = { + .driver = { + .name = "warrior", + }, + .description = DRIVER_DESC, + .interrupt = warrior_interrupt, + .connect = warrior_connect, + .disconnect = warrior_disconnect, }; /* @@ -211,13 +217,13 @@ int __init warrior_init(void) { - serio_register_device(&warrior_dev); + serio_register_driver(&warrior_drv); return 0; } void __exit warrior_exit(void) { - serio_unregister_device(&warrior_dev); + serio_unregister_driver(&warrior_drv); } module_init(warrior_init); diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c --- a/drivers/input/keyboard/atkbd.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/input/keyboard/atkbd.c 2004-10-18 14:56:49 -07:00 @@ -27,8 +27,10 @@ #include #include +#define DRIVER_DESC "AT and PS/2 keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static int atkbd_set = 2; @@ -47,6 +49,10 @@ module_param_named(softrepeat, atkbd_softrepeat, bool, 0); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); +static int atkbd_softraw = 1; +module_param_named(softraw, atkbd_softraw, bool, 0); +MODULE_PARM_DESC(softraw, "Use software generated rawmode"); + static int atkbd_scroll; module_param_named(scroll, atkbd_scroll, bool, 0); MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); @@ -164,36 +170,64 @@ { ATKBD_SCR_CLICK, 0x60 }, }; +#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */ +#define ATKBD_FLAG_CMD1 2 /* First byte of command response */ +#define ATKBD_FLAG_ENABLED 3 /* Waining for init to finish */ + /* * The atkbd control structure */ struct atkbd { - unsigned char keycode[512]; - struct input_dev dev; - struct serio *serio; + /* Written only during init */ char name[64]; char phys[32]; - unsigned short id; + struct serio *serio; + struct input_dev dev; + unsigned char set; - unsigned int translated:1; - unsigned int extra:1; - unsigned int write:1; + unsigned short id; + unsigned char keycode[512]; + unsigned char translated; + unsigned char extra; + unsigned char write; + + /* Protected by FLAG_ACK */ + unsigned char nak; + /* Protected by FLAG_CMD */ unsigned char cmdbuf[4]; unsigned char cmdcnt; - volatile signed char ack; - unsigned char emul; - unsigned int resend:1; - unsigned int release:1; - unsigned int bat_xl:1; - unsigned int enabled:1; + /* Accessed only from interrupt */ + unsigned char emul; + unsigned char resend; + unsigned char release; + unsigned char bat_xl; unsigned int last; unsigned long time; + + /* Ensures that only one command is executing at a time */ + struct semaphore cmd_sem; + + /* Used to signal completion from interrupt handler */ + wait_queue_head_t wait; + + /* Flags */ + unsigned long flags; }; +/* Work structure to schedule execution of a command */ +struct atkbd_work { + struct work_struct work; + struct atkbd *atkbd; + int command; + unsigned char param[0]; +}; + + static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) { input_regs(dev, regs); @@ -224,7 +258,7 @@ #if !defined(__i386__) && !defined (__x86_64__) if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { - printk("atkbd.c: frame/parity error: %02x\n", flags); + printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags); serio_write(serio, ATKBD_CMD_RESEND); atkbd->resend = 1; goto out; @@ -234,24 +268,46 @@ atkbd->resend = 0; #endif - if (!atkbd->ack) + if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) { switch (code) { case ATKBD_RET_ACK: - atkbd->ack = 1; - goto out; + atkbd->nak = 0; + if (atkbd->cmdcnt) { + set_bit(ATKBD_FLAG_CMD, &atkbd->flags); + set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + } + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); + break; case ATKBD_RET_NAK: - atkbd->ack = -1; - goto out; + atkbd->nak = 1; + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); + break; } + goto out; + } + + if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) { + + if (atkbd->cmdcnt) + atkbd->cmdbuf[--atkbd->cmdcnt] = code; - if (atkbd->cmdcnt) { - atkbd->cmdbuf[--atkbd->cmdcnt] = code; + if (test_and_clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags) && atkbd->cmdcnt) + wake_up_interruptible(&atkbd->wait); + + if (!atkbd->cmdcnt) { + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); + } goto out; } - if (!atkbd->enabled) + if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) goto out; + input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); + if (atkbd->translated) { if (atkbd->emul || @@ -270,6 +326,7 @@ switch (code) { case ATKBD_RET_BAT: + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); serio_rescan(atkbd->serio); goto out; case ATKBD_RET_EMUL0: @@ -300,6 +357,9 @@ code |= (atkbd->set != 3) ? 0x80 : 0x100; } + if (atkbd->keycode[code] != ATKBD_KEY_NULL) + input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); + switch (atkbd->keycode[code]) { case ATKBD_KEY_NULL: break; @@ -372,83 +432,147 @@ * acknowledge. It doesn't handle resends according to the keyboard * protocol specs, because if these are needed, the keyboard needs * replacement anyway, and they only make a mess in the protocol. + * + * atkbd_sendbyte() can only be called from a process context */ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) { - int timeout = 20000; /* 200 msec */ - atkbd->ack = 0; - #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); #endif - if (serio_write(atkbd->serio, byte)) - return -1; + atkbd->nak = 1; + set_bit(ATKBD_FLAG_ACK, &atkbd->flags); - while (!atkbd->ack && timeout--) udelay(10); + if (serio_write(atkbd->serio, byte) == 0) + wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_ACK, &atkbd->flags), + msecs_to_jiffies(200)); - return -(atkbd->ack <= 0); + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + return -atkbd->nak; } /* * atkbd_command() sends a command, and its parameters to the keyboard, * then waits for the response and puts it in the param array. + * + * atkbd_command() can only be called from a process context */ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) { - int timeout = 500000; /* 500 msec */ + int timeout; int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; + int rc = -1; int i; - atkbd->cmdcnt = receive; + timeout = msecs_to_jiffies(command == ATKBD_CMD_RESET_BAT ? 4000 : 500); - if (command == ATKBD_CMD_RESET_BAT) - timeout = 2000000; /* 2 sec */ + down(&atkbd->cmd_sem); + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); if (receive && param) for (i = 0; i < receive; i++) atkbd->cmdbuf[(receive - 1) - i] = param[i]; + atkbd->cmdcnt = receive; + if (command & 0xff) if (atkbd_sendbyte(atkbd, command & 0xff)) - return (atkbd->cmdcnt = 0) - 1; + goto out; for (i = 0; i < send; i++) if (atkbd_sendbyte(atkbd, param[i])) - return (atkbd->cmdcnt = 0) - 1; - - while (atkbd->cmdcnt && timeout--) { + goto out; - if (atkbd->cmdcnt == 1 && - command == ATKBD_CMD_RESET_BAT && timeout > 100000) - timeout = 100000; + timeout = wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_CMD1, &atkbd->flags), timeout); - if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID && - atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) { + if (atkbd->cmdcnt && timeout > 0) { + if (command == ATKBD_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100) + timeout = msecs_to_jiffies(100); + + if (command == ATKBD_CMD_GETID && + atkbd->cmdbuf[receive - 1] != 0xab && atkbd->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); atkbd->cmdcnt = 0; - break; } - udelay(1); + wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_CMD, &atkbd->flags), timeout); } if (param) for (i = 0; i < receive; i++) param[i] = atkbd->cmdbuf[(receive - 1) - i]; - if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1) - atkbd->cmdcnt = 0; + if (atkbd->cmdcnt && (command != ATKBD_CMD_RESET_BAT || atkbd->cmdcnt != 1)) + goto out; + + rc = 0; + +out: + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + up(&atkbd->cmd_sem); + + return rc; +} + +/* + * atkbd_execute_scheduled_command() sends a command, previously scheduled by + * atkbd_schedule_command(), to the keyboard. + */ + +static void atkbd_execute_scheduled_command(void *data) +{ + struct atkbd_work *atkbd_work = data; + + atkbd_command(atkbd_work->atkbd, atkbd_work->param, atkbd_work->command); + + kfree(atkbd_work); +} + +/* + * atkbd_schedule_command() allows to schedule delayed execution of a keyboard + * command and can be used to issue a command from an interrupt or softirq + * context. + */ + +static int atkbd_schedule_command(struct atkbd *atkbd, unsigned char *param, int command) +{ + struct atkbd_work *atkbd_work; + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + + if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) + return -1; - if (atkbd->cmdcnt) { - atkbd->cmdcnt = 0; + if (!(atkbd_work = kmalloc(sizeof(struct atkbd_work) + max(send, receive), GFP_ATOMIC))) + return -1; + + memset(atkbd_work, 0, sizeof(struct atkbd_work)); + atkbd_work->atkbd = atkbd; + atkbd_work->command = command; + memcpy(atkbd_work->param, param, send); + INIT_WORK(&atkbd_work->work, atkbd_execute_scheduled_command, atkbd_work); + + if (!schedule_work(&atkbd_work->work)) { + kfree(atkbd_work); return -1; } return 0; } + /* * Event callback from the input module. Events that change the state of * the hardware are processed here. @@ -475,7 +599,7 @@ param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | (test_bit(LED_NUML, dev->led) ? 2 : 0) | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); - atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETLEDS); if (atkbd->extra) { param[0] = 0; @@ -484,7 +608,7 @@ | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); - atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); } return 0; @@ -500,7 +624,7 @@ dev->rep[REP_PERIOD] = period[i]; dev->rep[REP_DELAY] = delay[j]; param[0] = i | (j << 5); - atkbd_command(atkbd, param, ATKBD_CMD_SETREP); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETREP); return 0; } @@ -672,6 +796,11 @@ static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; + + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + synchronize_kernel(); + flush_scheduled_work(); + input_unregister_device(&atkbd->dev); serio_close(serio); kfree(atkbd); @@ -684,7 +813,7 @@ * to the input module. */ -static void atkbd_connect(struct serio *serio, struct serio_dev *dev) +static void atkbd_connect(struct serio *serio, struct serio_driver *drv) { struct atkbd *atkbd; int i; @@ -693,6 +822,9 @@ return; memset(atkbd, 0, sizeof(struct atkbd)); + init_MUTEX(&atkbd->cmd_sem); + init_waitqueue_head(&atkbd->wait); + switch (serio->type & SERIO_TYPE) { case SERIO_8042_XL: @@ -709,17 +841,22 @@ return; } + if (!atkbd->write) + atkbd_softrepeat = 1; + if (atkbd_softrepeat) + atkbd_softraw = 1; + if (atkbd->write) { - atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); + atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); if (!atkbd_softrepeat) { atkbd->dev.rep[REP_DELAY] = 250; atkbd->dev.rep[REP_PERIOD] = 33; - } + } else atkbd_softraw = 1; - atkbd->ack = 1; atkbd->serio = serio; init_input_dev(&atkbd->dev); @@ -732,7 +869,7 @@ serio->private = atkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(atkbd); return; } @@ -754,8 +891,6 @@ atkbd->id = 0xab00; } - atkbd->enabled = 1; - if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); sprintf(atkbd->name, "AT Set 2 Extra keyboard"); @@ -797,6 +932,8 @@ input_register_device(&atkbd->dev); + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); } @@ -808,10 +945,10 @@ static int atkbd_reconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; - struct serio_dev *dev = serio->dev; + struct serio_driver *drv = serio->drv; unsigned char param[1]; - if (!dev) { + if (!drv) { printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -832,26 +969,32 @@ return -1; } + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + return 0; } -static struct serio_dev atkbd_dev = { - .interrupt = atkbd_interrupt, - .connect = atkbd_connect, - .reconnect = atkbd_reconnect, - .disconnect = atkbd_disconnect, - .cleanup = atkbd_cleanup, +static struct serio_driver atkbd_drv = { + .driver = { + .name = "atkbd", + }, + .description = DRIVER_DESC, + .interrupt = atkbd_interrupt, + .connect = atkbd_connect, + .reconnect = atkbd_reconnect, + .disconnect = atkbd_disconnect, + .cleanup = atkbd_cleanup, }; int __init atkbd_init(void) { - serio_register_device(&atkbd_dev); + serio_register_driver(&atkbd_drv); return 0; } void __exit atkbd_exit(void) { - serio_unregister_device(&atkbd_dev); + serio_unregister_driver(&atkbd_drv); } module_init(atkbd_init); diff -Nru a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c --- a/drivers/input/keyboard/lkkbd.c 2004-10-18 14:56:16 -07:00 +++ b/drivers/input/keyboard/lkkbd.c 2004-10-18 14:56:16 -07:00 @@ -76,8 +76,10 @@ #include #include +#define DRIVER_DESC "LK keyboard driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("LK keyboard driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); /* @@ -622,7 +624,7 @@ * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. */ static void -lkkbd_connect (struct serio *serio, struct serio_dev *dev) +lkkbd_connect (struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; int i; @@ -665,7 +667,7 @@ serio->private = lk; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (lk); return; } @@ -703,10 +705,14 @@ kfree (lk); } -static struct serio_dev lkkbd_dev = { - .connect = lkkbd_connect, - .disconnect = lkkbd_disconnect, - .interrupt = lkkbd_interrupt, +static struct serio_driver lkkbd_drv = { + .driver = { + .name = "lkkbd", + }, + .description = DRIVER_DESC, + .connect = lkkbd_connect, + .disconnect = lkkbd_disconnect, + .interrupt = lkkbd_interrupt, }; /* @@ -715,14 +721,14 @@ int __init lkkbd_init (void) { - serio_register_device (&lkkbd_dev); + serio_register_driver(&lkkbd_drv); return 0; } void __exit lkkbd_exit (void) { - serio_unregister_device (&lkkbd_dev); + serio_unregister_driver(&lkkbd_drv); } module_init (lkkbd_init); diff -Nru a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c --- a/drivers/input/keyboard/newtonkbd.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/input/keyboard/newtonkbd.c 2004-10-18 14:55:53 -07:00 @@ -32,8 +32,10 @@ #include #include +#define DRIVER_DESC "Newton keyboard driver" + MODULE_AUTHOR("Justin Cormack "); -MODULE_DESCRIPTION("Newton keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define NKBD_KEY 0x7f @@ -82,7 +84,7 @@ } -void nkbd_connect(struct serio *serio, struct serio_dev *dev) +void nkbd_connect(struct serio *serio, struct serio_driver *drv) { struct nkbd *nkbd; int i; @@ -106,7 +108,7 @@ nkbd->dev.private = nkbd; serio->private = nkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(nkbd); return; } @@ -138,21 +140,25 @@ kfree(nkbd); } -struct serio_dev nkbd_dev = { - .interrupt = nkbd_interrupt, - .connect = nkbd_connect, - .disconnect = nkbd_disconnect +struct serio_driver nkbd_drv = { + .driver = { + .name = "newtonkbd", + }, + .description = DRIVER_DESC, + .interrupt = nkbd_interrupt, + .connect = nkbd_connect, + .disconnect = nkbd_disconnect, }; int __init nkbd_init(void) { - serio_register_device(&nkbd_dev); + serio_register_driver(&nkbd_drv); return 0; } void __exit nkbd_exit(void) { - serio_unregister_device(&nkbd_dev); + serio_unregister_driver(&nkbd_drv); } module_init(nkbd_init); diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c --- a/drivers/input/keyboard/sunkbd.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/input/keyboard/sunkbd.c 2004-10-18 14:55:53 -07:00 @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Sun keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Sun keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { @@ -221,7 +223,7 @@ * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. */ -static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) +static void sunkbd_connect(struct serio *serio, struct serio_driver *drv) { struct sunkbd *sunkbd; int i; @@ -257,7 +259,7 @@ serio->private = sunkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sunkbd); return; } @@ -301,10 +303,14 @@ kfree(sunkbd); } -static struct serio_dev sunkbd_dev = { - .interrupt = sunkbd_interrupt, - .connect = sunkbd_connect, - .disconnect = sunkbd_disconnect +static struct serio_driver sunkbd_drv = { + .driver = { + .name = "sunkbd", + }, + .description = DRIVER_DESC, + .interrupt = sunkbd_interrupt, + .connect = sunkbd_connect, + .disconnect = sunkbd_disconnect, }; /* @@ -313,13 +319,13 @@ int __init sunkbd_init(void) { - serio_register_device(&sunkbd_dev); + serio_register_driver(&sunkbd_drv); return 0; } void __exit sunkbd_exit(void) { - serio_unregister_device(&sunkbd_dev); + serio_unregister_driver(&sunkbd_drv); } module_init(sunkbd_init); diff -Nru a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c --- a/drivers/input/keyboard/xtkbd.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/input/keyboard/xtkbd.c 2004-10-18 14:56:32 -07:00 @@ -34,8 +34,10 @@ #include #include +#define DRIVER_DESC "XT keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("XT keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define XTKBD_EMUL0 0xe0 @@ -86,7 +88,7 @@ return IRQ_HANDLED; } -void xtkbd_connect(struct serio *serio, struct serio_dev *dev) +void xtkbd_connect(struct serio *serio, struct serio_driver *drv) { struct xtkbd *xtkbd; int i; @@ -111,7 +113,7 @@ serio->private = xtkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(xtkbd); return; } @@ -143,21 +145,25 @@ kfree(xtkbd); } -struct serio_dev xtkbd_dev = { - .interrupt = xtkbd_interrupt, - .connect = xtkbd_connect, - .disconnect = xtkbd_disconnect +struct serio_driver xtkbd_drv = { + .driver = { + .name = "xtkbd", + }, + .description = DRIVER_DESC, + .interrupt = xtkbd_interrupt, + .connect = xtkbd_connect, + .disconnect = xtkbd_disconnect, }; int __init xtkbd_init(void) { - serio_register_device(&xtkbd_dev); + serio_register_driver(&xtkbd_drv); return 0; } void __exit xtkbd_exit(void) { - serio_unregister_device(&xtkbd_dev); + serio_unregister_driver(&xtkbd_drv); } module_init(xtkbd_init); diff -Nru a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig --- a/drivers/input/misc/Kconfig 2004-10-18 14:56:29 -07:00 +++ b/drivers/input/misc/Kconfig 2004-10-18 14:56:29 -07:00 @@ -14,7 +14,7 @@ config INPUT_PCSPKR tristate "PC Speaker support" - depends on (ALPHA || X86 || X86_64 || MIPS) && INPUT && INPUT_MISC + depends on (ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES) && INPUT && INPUT_MISC help Say Y here if you want the standard PC Speaker to be used for bells and whistles. diff -Nru a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c --- a/drivers/input/misc/uinput.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/input/misc/uinput.c 2004-10-18 14:56:50 -07:00 @@ -279,6 +279,9 @@ { struct uinput_device *udev = file->private_data; + if (!test_bit(UIST_CREATED, &(udev->state))) + return 0; + poll_wait(file, &udev->waitq, wait); if (udev->head != udev->tail) diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig --- a/drivers/input/mouse/Kconfig 2004-10-18 14:56:49 -07:00 +++ b/drivers/input/mouse/Kconfig 2004-10-18 14:56:49 -07:00 @@ -30,8 +30,6 @@ and a new verion of GPM at: http://www.geocities.com/dt_or/gpm/gpm.html to take advantage of the advanced features of the touchpad. - If you do not want install specialized drivers but want tapping - working please use option psmouse.proto=imps. If unsure, say Y. diff -Nru a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c --- a/drivers/input/mouse/logips2pp.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/input/mouse/logips2pp.c 2004-10-18 14:56:33 -07:00 @@ -277,7 +277,7 @@ protocol = PSMOUSE_PS2TPP; } - } else if (get_model_info(model) != NULL) { + } else if (model_info != NULL) { param[0] = param[1] = param[2] = 0; ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ diff -Nru a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c --- a/drivers/input/mouse/pc110pad.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/input/mouse/pc110pad.c 2004-10-18 14:56:28 -07:00 @@ -109,9 +109,9 @@ static int __init pc110pad_init(void) { - if (request_region(pc110pad_io, 4, "pc110pad")) - { - printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", pc110pad_io, pc110pad_io + 4); + if (!request_region(pc110pad_io, 4, "pc110pad")) { + printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", + pc110pad_io, pc110pad_io + 4); return -EBUSY; } diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c --- a/drivers/input/mouse/psmouse-base.c 2004-10-18 14:56:19 -07:00 +++ b/drivers/input/mouse/psmouse-base.c 2004-10-18 14:56:19 -07:00 @@ -22,8 +22,10 @@ #include "synaptics.h" #include "logips2pp.h" +#define DRIVER_DESC "PS/2 mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("PS/2 mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *psmouse_proto; @@ -142,37 +144,67 @@ printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", flags & SERIO_TIMEOUT ? " timeout" : "", flags & SERIO_PARITY ? " bad parity" : ""); - if (psmouse->acking) { - psmouse->ack = -1; - psmouse->acking = 0; - } - psmouse->pktcnt = 0; + psmouse->nak = 1; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); goto out; } - if (psmouse->acking) { + if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) { switch (data) { case PSMOUSE_RET_ACK: - psmouse->ack = 1; + psmouse->nak = 0; break; + case PSMOUSE_RET_NAK: - psmouse->ack = -1; + psmouse->nak = 1; break; + + /* + * Workaround for mice which don't ACK the Get ID command. + * These are valid mouse IDs that we recognize. + */ + case 0x00: + case 0x03: + case 0x04: + if (test_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags)) { + psmouse->nak = 0; + break; + } + /* Fall through */ default: - psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ - if (psmouse->cmdcnt) - psmouse->cmdbuf[--psmouse->cmdcnt] = data; - break; + goto out; } - psmouse->acking = 0; - goto out; + + if (!psmouse->nak && psmouse->cmdcnt) { + set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + } + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); + + if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK) + goto out; } - if (psmouse->cmdcnt) { - psmouse->cmdbuf[--psmouse->cmdcnt] = data; + if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) { + if (psmouse->cmdcnt) + psmouse->cmdbuf[--psmouse->cmdcnt] = data; + + if (test_and_clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags) && psmouse->cmdcnt) + wake_up_interruptible(&psmouse->wait); + + if (!psmouse->cmdcnt) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); + } goto out; } + if (psmouse->state == PSMOUSE_INITIALIZING) + goto out; + if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", @@ -238,78 +270,96 @@ * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge. * It doesn't handle retransmission, though it could - because when there would * be need for retransmissions, the mouse has to be replaced anyway. + * + * psmouse_sendbyte() can only be called from a process context */ static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) { - int timeout = 10000; /* 100 msec */ - psmouse->ack = 0; - psmouse->acking = 1; - - if (serio_write(psmouse->serio, byte)) { - psmouse->acking = 0; - return -1; - } + psmouse->nak = 1; + set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - while (!psmouse->ack && timeout--) udelay(10); + if (serio_write(psmouse->serio, byte) == 0) + wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags), + msecs_to_jiffies(200)); - return -(psmouse->ack <= 0); + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + return -psmouse->nak; } /* * psmouse_command() sends a command and its parameters to the mouse, * then waits for the response and puts it in the param array. + * + * psmouse_command() can only be called from a process context */ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) { - int timeout = 500000; /* 500 msec */ + int timeout; int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; + int rc = -1; int i; - psmouse->cmdcnt = receive; + timeout = msecs_to_jiffies(command == PSMOUSE_CMD_RESET_BAT ? 4000 : 500); - if (command == PSMOUSE_CMD_RESET_BAT) - timeout = 4000000; /* 4 sec */ + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + if (command == PSMOUSE_CMD_GETID) + set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags); + + if (receive && param) + for (i = 0; i < receive; i++) + psmouse->cmdbuf[(receive - 1) - i] = param[i]; - /* initialize cmdbuf with preset values from param */ - if (receive) - for (i = 0; i < receive; i++) - psmouse->cmdbuf[(receive - 1) - i] = param[i]; + psmouse->cmdcnt = receive; if (command & 0xff) if (psmouse_sendbyte(psmouse, command & 0xff)) - return (psmouse->cmdcnt = 0) - 1; + goto out; for (i = 0; i < send; i++) if (psmouse_sendbyte(psmouse, param[i])) - return (psmouse->cmdcnt = 0) - 1; - - while (psmouse->cmdcnt && timeout--) { + goto out; - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT && - timeout > 100000) /* do not run in a endless loop */ - timeout = 100000; /* 1 sec */ + timeout = wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags), timeout); - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID && - psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) { + if (psmouse->cmdcnt && timeout > 0) { + if (command == PSMOUSE_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100) + timeout = msecs_to_jiffies(100); + + if (command == PSMOUSE_CMD_GETID && + psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); psmouse->cmdcnt = 0; - break; } - udelay(1); + wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags), timeout); } - for (i = 0; i < receive; i++) - param[i] = psmouse->cmdbuf[(receive - 1) - i]; + if (param) + for (i = 0; i < receive; i++) + param[i] = psmouse->cmdbuf[(receive - 1) - i]; - if (psmouse->cmdcnt) - return (psmouse->cmdcnt = 0) - 1; + if (psmouse->cmdcnt && (command != PSMOUSE_CMD_RESET_BAT || psmouse->cmdcnt != 1)) + goto out; - return 0; -} + rc = 0; +out: + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags); + return rc; +} /* * psmouse_sliced_command() sends an extended PS/2 command to the mouse @@ -394,6 +444,8 @@ { unsigned char param[2]; + intellimouse_detect(psmouse); + param[0] = 200; psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); param[0] = 200; @@ -598,6 +650,21 @@ } /* + * psmouse_set_state() sets new psmouse state and resets all flags and + * counters while holding serio lock so fighting with interrupt handler + * is not a concern. + */ + +static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) +{ + serio_pause_rx(psmouse->serio); + psmouse->state = new_state; + psmouse->pktcnt = psmouse->cmdcnt = psmouse->out_of_sync = 0; + psmouse->flags = 0; + serio_continue_rx(psmouse->serio); +} + +/* * psmouse_activate() enables the mouse so that we get motion reports from it. */ @@ -606,9 +673,24 @@ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys); - psmouse->state = PSMOUSE_ACTIVATED; + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); } + +/* + * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion + * reports from it unless we explicitely request it. + */ + +static void psmouse_deactivate(struct psmouse *psmouse) +{ + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE)) + printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", psmouse->serio->phys); + + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); +} + + /* * psmouse_cleanup() resets the mouse into power-on state. */ @@ -626,22 +708,21 @@ static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse = serio->private; + struct psmouse *psmouse, *parent; - psmouse->state = PSMOUSE_CMD_MODE; + psmouse = serio->private; + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - if (psmouse->ptport) { - if (psmouse->ptport->deactivate) - psmouse->ptport->deactivate(psmouse); - __serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */ - kfree(psmouse->ptport); - psmouse->ptport = NULL; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + if (parent->pt_deactivate) + parent->pt_deactivate(parent); } if (psmouse->disconnect) psmouse->disconnect(psmouse); - psmouse->state = PSMOUSE_IGNORE; + psmouse_set_state(psmouse, PSMOUSE_IGNORE); input_unregister_device(&psmouse->dev); serio_close(serio); @@ -652,39 +733,49 @@ * psmouse_connect() is a callback from the serio module when * an unhandled serio port is found. */ -static void psmouse_connect(struct serio *serio, struct serio_dev *dev) +static void psmouse_connect(struct serio *serio, struct serio_driver *drv) { - struct psmouse *psmouse; + struct psmouse *psmouse, *parent = NULL; if ((serio->type & SERIO_TYPE) != SERIO_8042 && (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) return; + /* + * If this is a pass-through port deactivate parent so the device + * connected to this port can be successfully identified + */ + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + psmouse_deactivate(parent); + } + if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) - return; + goto out; memset(psmouse, 0, sizeof(struct psmouse)); + init_waitqueue_head(&psmouse->wait); init_input_dev(&psmouse->dev); psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - psmouse->state = PSMOUSE_CMD_MODE; psmouse->serio = serio; psmouse->dev.private = psmouse; + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); serio->private = psmouse; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(psmouse); serio->private = NULL; - return; + goto out; } if (psmouse_probe(psmouse) < 0) { serio_close(serio); kfree(psmouse); serio->private = NULL; - return; + goto out; } psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); @@ -711,63 +802,88 @@ printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); - if (psmouse->ptport) { - printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys); - __serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */ - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); + if (parent && parent->pt_activate) + parent->pt_activate(parent); + + if (serio->child) { + /* + * Nothing to be done here, serio core will detect that + * the driver set serio->child and will register it for us. + */ + printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys); } psmouse_activate(psmouse); + +out: + /* If this is a pass-through port the parent awaits to be activated */ + if (parent) + psmouse_activate(parent); } static int psmouse_reconnect(struct serio *serio) { struct psmouse *psmouse = serio->private; - struct serio_dev *dev = serio->dev; + struct psmouse *parent = NULL; + struct serio_driver *drv = serio->drv; + int rc = -1; - if (!dev || !psmouse) { + if (!drv || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } - psmouse->state = PSMOUSE_CMD_MODE; - psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + psmouse_deactivate(parent); + } + + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); + if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) - return -1; + goto out; } else if (psmouse_probe(psmouse) < 0 || psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0)) - return -1; + goto out; /* ok, the device type (and capabilities) match the old one, * we can continue using it, complete intialization */ + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); - if (psmouse->ptport) { - if (psmouse_reconnect(&psmouse->ptport->serio)) { - __serio_unregister_port(&psmouse->ptport->serio); - __serio_register_port(&psmouse->ptport->serio); - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); - } - } + if (parent && parent->pt_activate) + parent->pt_activate(parent); psmouse_activate(psmouse); - return 0; + rc = 0; + +out: + /* If this is a pass-through port the parent waits to be activated */ + if (parent) + psmouse_activate(parent); + + return rc; } -static struct serio_dev psmouse_dev = { - .interrupt = psmouse_interrupt, - .connect = psmouse_connect, - .reconnect = psmouse_reconnect, - .disconnect = psmouse_disconnect, - .cleanup = psmouse_cleanup, +static struct serio_driver psmouse_drv = { + .driver = { + .name = "psmouse", + }, + .description = DRIVER_DESC, + .interrupt = psmouse_interrupt, + .connect = psmouse_connect, + .reconnect = psmouse_reconnect, + .disconnect = psmouse_disconnect, + .cleanup = psmouse_cleanup, }; static inline void psmouse_parse_proto(void) @@ -787,13 +903,13 @@ int __init psmouse_init(void) { psmouse_parse_proto(); - serio_register_device(&psmouse_dev); + serio_register_driver(&psmouse_drv); return 0; } void __exit psmouse_exit(void) { - serio_unregister_device(&psmouse_dev); + serio_unregister_driver(&psmouse_drv); } module_init(psmouse_init); diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h --- a/drivers/input/mouse/psmouse.h 2004-10-18 14:57:03 -07:00 +++ b/drivers/input/mouse/psmouse.h 2004-10-18 14:57:03 -07:00 @@ -9,6 +9,7 @@ #define PSMOUSE_CMD_GETID 0x02f2 #define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_DISABLE 0x00f5 #define PSMOUSE_CMD_RESET_DIS 0x00f6 #define PSMOUSE_CMD_RESET_BAT 0x02ff @@ -17,10 +18,17 @@ #define PSMOUSE_RET_ACK 0xfa #define PSMOUSE_RET_NAK 0xfe -/* psmouse states */ -#define PSMOUSE_CMD_MODE 0 -#define PSMOUSE_ACTIVATED 1 -#define PSMOUSE_IGNORE 2 +#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */ +#define PSMOUSE_FLAG_CMD1 2 /* Waiting for the first byte of command response */ +#define PSMOUSE_FLAG_WAITID 3 /* Command execiting is GET ID */ + +enum psmouse_state { + PSMOUSE_IGNORE, + PSMOUSE_INITIALIZING, + PSMOUSE_CMD_MODE, + PSMOUSE_ACTIVATED, +}; /* psmouse protocol handler return codes */ typedef enum { @@ -29,20 +37,10 @@ PSMOUSE_FULL_PACKET } psmouse_ret_t; -struct psmouse; - -struct psmouse_ptport { - struct serio serio; - - void (*activate)(struct psmouse *parent); - void (*deactivate)(struct psmouse *parent); -}; - struct psmouse { void *private; struct input_dev dev; struct serio *serio; - struct psmouse_ptport *ptport; char *vendor; char *name; unsigned char cmdbuf[8]; @@ -53,16 +51,22 @@ unsigned char model; unsigned long last; unsigned long out_of_sync; - unsigned char state; - char acking; - volatile char ack; + enum psmouse_state state; + unsigned char nak; char error; char devname[64]; char phys[32]; + unsigned long flags; + + /* Used to signal completion from interrupt handler */ + wait_queue_head_t wait; - psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); + + void (*pt_activate)(struct psmouse *psmouse); + void (*pt_deactivate)(struct psmouse *psmouse); }; #define PSMOUSE_PS2 1 diff -Nru a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c --- a/drivers/input/mouse/sermouse.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/input/mouse/sermouse.c 2004-10-18 14:56:48 -07:00 @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Serial mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Serial mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", @@ -237,7 +239,7 @@ * an unhandled serio port is found. */ -static void sermouse_connect(struct serio *serio, struct serio_dev *dev) +static void sermouse_connect(struct serio *serio, struct serio_driver *drv) { struct sermouse *sermouse; unsigned char c; @@ -279,7 +281,7 @@ sermouse->dev.id.product = c; sermouse->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sermouse); return; } @@ -289,21 +291,25 @@ printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); } -static struct serio_dev sermouse_dev = { - .interrupt = sermouse_interrupt, - .connect = sermouse_connect, - .disconnect = sermouse_disconnect +static struct serio_driver sermouse_drv = { + .driver = { + .name = "sermouse", + }, + .description = DRIVER_DESC, + .interrupt = sermouse_interrupt, + .connect = sermouse_connect, + .disconnect = sermouse_disconnect, }; int __init sermouse_init(void) { - serio_register_device(&sermouse_dev); + serio_register_driver(&sermouse_drv); return 0; } void __exit sermouse_exit(void) { - serio_unregister_device(&sermouse_dev); + serio_unregister_driver(&sermouse_drv); } module_init(sermouse_init); diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c --- a/drivers/input/mouse/synaptics.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/input/mouse/synaptics.c 2004-10-18 14:56:28 -07:00 @@ -212,9 +212,9 @@ /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_write(struct serio *port, unsigned char c) +static int synaptics_pt_write(struct serio *serio, unsigned char c) { - struct psmouse *parent = port->driver; + struct psmouse *parent = serio->parent->private; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ if (psmouse_sliced_command(parent, c)) @@ -233,22 +233,19 @@ { struct psmouse *child = ptport->private; - if (child) { - if (child->state == PSMOUSE_ACTIVATED) { - serio_interrupt(ptport, packet[1], 0, NULL); - serio_interrupt(ptport, packet[4], 0, NULL); - serio_interrupt(ptport, packet[5], 0, NULL); - if (child->type >= PSMOUSE_GENPS) - serio_interrupt(ptport, packet[2], 0, NULL); - } else if (child->state != PSMOUSE_IGNORE) { - serio_interrupt(ptport, packet[1], 0, NULL); - } - } + if (child && child->state == PSMOUSE_ACTIVATED) { + serio_interrupt(ptport, packet[1], 0, NULL); + serio_interrupt(ptport, packet[4], 0, NULL); + serio_interrupt(ptport, packet[5], 0, NULL); + if (child->type >= PSMOUSE_GENPS) + serio_interrupt(ptport, packet[2], 0, NULL); + } else + serio_interrupt(ptport, packet[1], 0, NULL); } static void synaptics_pt_activate(struct psmouse *psmouse) { - struct psmouse *child = psmouse->ptport->serio.private; + struct psmouse *child = psmouse->serio->child->private; /* adjust the touchpad to child's choice of protocol */ if (child && child->type >= PSMOUSE_GENPS) { @@ -259,23 +256,25 @@ static void synaptics_pt_create(struct psmouse *psmouse) { - struct psmouse_ptport *port; + struct serio *serio; - psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); - if (!port) { + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) { printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); return; } - memset(port, 0, sizeof(struct psmouse_ptport)); + memset(serio, 0, sizeof(struct serio)); + + serio->type = SERIO_PS_PSTHRU; + strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); + strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); + serio->write = synaptics_pt_write; + serio->parent = psmouse->serio; - port->serio.type = SERIO_PS_PSTHRU; - port->serio.name = "Synaptics pass-through"; - port->serio.phys = "synaptics-pt/serio0"; - port->serio.write = synaptics_pt_write; - port->serio.driver = psmouse; + psmouse->pt_activate = synaptics_pt_activate; - port->activate = synaptics_pt_activate; + psmouse->serio->child = serio; } /***************************************************************************** @@ -470,9 +469,10 @@ if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) - synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); - else + if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { + if (psmouse->serio->child) + synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); + } else synaptics_process_packet(psmouse); return PSMOUSE_FULL_PACKET; diff -Nru a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c --- a/drivers/input/mouse/vsxxxaa.c 2004-10-18 14:57:18 -07:00 +++ b/drivers/input/mouse/vsxxxaa.c 2004-10-18 14:57:18 -07:00 @@ -82,8 +82,10 @@ #include #include +#define DRIVER_DESC "Serial DEC VSXXX-AA/GA mouse / DEC tablet driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); #undef VSXXXAA_DEBUG @@ -482,7 +484,7 @@ } static void -vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) +vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; @@ -524,7 +526,7 @@ mouse->dev.id.bustype = BUS_RS232; mouse->serio = serio; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (mouse); return; } @@ -540,23 +542,27 @@ printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); } -static struct serio_dev vsxxxaa_dev = { - .connect = vsxxxaa_connect, - .interrupt = vsxxxaa_interrupt, - .disconnect = vsxxxaa_disconnect, +static struct serio_driver vsxxxaa_drv = { + .driver = { + .name = "vsxxxaa", + }, + .description = DRIVER_DESC, + .connect = vsxxxaa_connect, + .interrupt = vsxxxaa_interrupt, + .disconnect = vsxxxaa_disconnect, }; int __init vsxxxaa_init (void) { - serio_register_device (&vsxxxaa_dev); + serio_register_driver(&vsxxxaa_drv); return 0; } void __exit vsxxxaa_exit (void) { - serio_unregister_device (&vsxxxaa_dev); + serio_unregister_driver(&vsxxxaa_drv); } module_init (vsxxxaa_init); diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c --- a/drivers/input/mousedev.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/input/mousedev.c 2004-10-18 14:57:03 -07:00 @@ -48,8 +48,15 @@ module_param(yres, uint, 0); MODULE_PARM_DESC(yres, "Vertical screen resolution"); -struct mousedev_motion { +static unsigned tap_time = 200; +module_param(tap_time, uint, 0); +MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); + +struct mousedev_hw_data { int dx, dy, dz; + int x, y; + int abs_event; + unsigned long buttons; }; struct mousedev { @@ -61,22 +68,38 @@ struct list_head list; struct input_handle handle; - struct mousedev_motion packet; - unsigned long buttons; + struct mousedev_hw_data packet; unsigned int pkt_count; int old_x[4], old_y[4]; - unsigned int touch; + unsigned long touch; }; +enum mousedev_emul { + MOUSEDEV_EMUL_PS2, + MOUSEDEV_EMUL_IMPS, + MOUSEDEV_EMUL_EXPS +}; + +struct mousedev_motion { + int dx, dy, dz; + unsigned long buttons; +}; + +#define PACKET_QUEUE_LEN 16 struct mousedev_list { struct fasync_struct *fasync; struct mousedev *mousedev; struct list_head node; - int dx, dy, dz; - unsigned long buttons; + + struct mousedev_motion packets[PACKET_QUEUE_LEN]; + unsigned int head, tail; + spinlock_t packet_lock; + int pos_x, pos_y; + signed char ps2[6]; unsigned char ready, buffer, bufsiz; - unsigned char mode, imexseq, impsseq; + unsigned char imexseq, impsseq; + enum mousedev_emul mode; }; #define MOUSEDEV_SEQ_LEN 6 @@ -119,15 +142,19 @@ case ABS_X: size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; if (size == 0) size = xres; - mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size; - mousedev->old_x[0] = mousedev->packet.dx * size; + if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X]; + if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X]; + mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; + mousedev->packet.abs_event = 1; break; case ABS_Y: size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; if (size == 0) size = yres; - mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size; - mousedev->old_y[0] = mousedev->packet.dy * size; + if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y]; + if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y]; + mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; + mousedev->packet.abs_event = 1; break; } } @@ -165,30 +192,82 @@ } if (value) { - set_bit(index, &mousedev->buttons); - set_bit(index, &mousedev_mix.buttons); + set_bit(index, &mousedev->packet.buttons); + set_bit(index, &mousedev_mix.packet.buttons); } else { - clear_bit(index, &mousedev->buttons); - clear_bit(index, &mousedev_mix.buttons); + clear_bit(index, &mousedev->packet.buttons); + clear_bit(index, &mousedev_mix.packet.buttons); } } -static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) +static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) { struct mousedev_list *list; + struct mousedev_motion *p; + unsigned long flags; list_for_each_entry(list, &mousedev->list, node) { - list->dx += packet->dx; - list->dy += packet->dy; - list->dz += packet->dz; - list->buttons = mousedev->buttons; + spin_lock_irqsave(&list->packet_lock, flags); + + p = &list->packets[list->head]; + if (list->ready && p->buttons != packet->buttons) { + unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; + if (new_head != list->tail) { + p = &list->packets[list->head = new_head]; + memset(p, 0, sizeof(struct mousedev_motion)); + } + } + + if (packet->abs_event) { + p->dx += packet->x - list->pos_x; + p->dy += packet->y - list->pos_y; + list->pos_x = packet->x; + list->pos_y = packet->y; + } + + list->pos_x += packet->dx; + list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x); + list->pos_y += packet->dy; + list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y); + + p->dx += packet->dx; + p->dy += packet->dy; + p->dz += packet->dz; + p->buttons = mousedev->packet.buttons; + list->ready = 1; + + spin_unlock_irqrestore(&list->packet_lock, flags); kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&mousedev->wait); } +static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) +{ + if (!value) { + if (mousedev->touch && + time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { + /* + * Toggle left button to emulate tap. + * We rely on the fact that mousedev_mix always has 0 + * motion packet so we won't mess current position. + */ + set_bit(0, &mousedev->packet.buttons); + set_bit(0, &mousedev_mix.packet.buttons); + mousedev_notify_readers(mousedev, &mousedev_mix.packet); + mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet); + clear_bit(0, &mousedev->packet.buttons); + clear_bit(0, &mousedev_mix.packet.buttons); + } + mousedev->touch = mousedev->pkt_count = 0; + } + else + if (!mousedev->touch) + mousedev->touch = jiffies; +} + static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct mousedev *mousedev = handle->private; @@ -212,12 +291,8 @@ case EV_KEY: if (value != 2) { - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { - /* Handle touchpad data */ - mousedev->touch = value; - if (!mousedev->touch) - mousedev->pkt_count = 0; - } + if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) + mousedev_touchpad_touch(mousedev, value); else mousedev_key_event(mousedev, code, value); } @@ -237,7 +312,8 @@ mousedev_notify_readers(mousedev, &mousedev->packet); mousedev_notify_readers(&mousedev_mix, &mousedev->packet); - memset(&mousedev->packet, 0, sizeof(struct mousedev_motion)); + mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; + mousedev->packet.abs_event = 0; } break; } @@ -322,6 +398,9 @@ return -ENOMEM; memset(list, 0, sizeof(struct mousedev_list)); + spin_lock_init(&list->packet_lock); + list->pos_x = xres / 2; + list->pos_y = yres / 2; list->mousedev = mousedev_table[i]; list_add_tail(&list->node, &mousedev_table[i]->list); file->private_data = list; @@ -341,32 +420,56 @@ return 0; } -static void mousedev_packet(struct mousedev_list *list, unsigned char off) +static inline int mousedev_limit_delta(int delta, int limit) { - list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); - list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); - list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); - list->dx -= list->ps2[off + 1]; - list->dy -= list->ps2[off + 2]; - list->bufsiz = off + 3; - - if (list->mode == 2) { - list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); - list->bufsiz++; - } else { - list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1); + return delta > limit ? limit : (delta < -limit ? -limit : delta); +} + +static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) +{ + struct mousedev_motion *p; + unsigned long flags; + + spin_lock_irqsave(&list->packet_lock, flags); + p = &list->packets[list->tail]; + + ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); + ps2_data[1] = mousedev_limit_delta(p->dx, 127); + ps2_data[2] = mousedev_limit_delta(p->dy, 127); + p->dx -= ps2_data[1]; + p->dy -= ps2_data[2]; + + switch (list->mode) { + case MOUSEDEV_EMUL_EXPS: + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_IMPS: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_PS2: + default: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + p->dz = 0; + list->bufsiz = 3; + break; } - if (list->mode == 1) { - list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->bufsiz++; + if (!p->dx && !p->dy && !p->dz) { + if (list->tail != list->head) + list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; + if (list->tail == list->head) + list->ready = 0; } - if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; - list->buffer = list->bufsiz; + spin_unlock_irqrestore(&list->packet_lock, flags); } @@ -384,31 +487,31 @@ if (c == mousedev_imex_seq[list->imexseq]) { if (++list->imexseq == MOUSEDEV_SEQ_LEN) { list->imexseq = 0; - list->mode = 2; + list->mode = MOUSEDEV_EMUL_EXPS; } } else list->imexseq = 0; if (c == mousedev_imps_seq[list->impsseq]) { if (++list->impsseq == MOUSEDEV_SEQ_LEN) { list->impsseq = 0; - list->mode = 1; + list->mode = MOUSEDEV_EMUL_IMPS; } } else list->impsseq = 0; list->ps2[0] = 0xfa; - list->bufsiz = 1; switch (c) { case 0xeb: /* Poll */ - mousedev_packet(list, 1); + mousedev_packet(list, &list->ps2[1]); + list->bufsiz++; /* account for leading ACK */ break; case 0xf2: /* Get ID */ switch (list->mode) { - case 0: list->ps2[1] = 0; break; - case 1: list->ps2[1] = 3; break; - case 2: list->ps2[1] = 4; break; + case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break; + case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break; + case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break; } list->bufsiz = 2; break; @@ -419,13 +522,15 @@ break; case 0xff: /* Reset */ - list->impsseq = 0; - list->imexseq = 0; - list->mode = 0; - list->ps2[1] = 0xaa; - list->ps2[2] = 0x00; + list->impsseq = list->imexseq = 0; + list->mode = MOUSEDEV_EMUL_PS2; + list->ps2[1] = 0xaa; list->ps2[2] = 0x00; list->bufsiz = 3; break; + + default: + list->bufsiz = 1; + break; } list->buffer = list->bufsiz; @@ -446,13 +551,19 @@ if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(list->mousedev->wait, list->ready || list->buffer); + retval = wait_event_interruptible(list->mousedev->wait, + !list->mousedev->exist || list->ready || list->buffer); if (retval) return retval; - if (!list->buffer && list->ready) - mousedev_packet(list, 0); + if (!list->mousedev->exist) + return -ENODEV; + + if (!list->buffer && list->ready) { + mousedev_packet(list, list->ps2); + list->buffer = list->bufsiz; + } if (count > list->buffer) count = list->buffer; diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig --- a/drivers/input/serio/Kconfig 2004-10-18 14:56:32 -07:00 +++ b/drivers/input/serio/Kconfig 2004-10-18 14:56:32 -07:00 @@ -20,7 +20,7 @@ tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 default y select SERIO - depends on !PARISC + depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) ---help--- i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, @@ -130,3 +130,19 @@ To compile this driver as a module, choose M here: the module will be called maceps2. + +config SERIO_RAW + tristate "Raw access to serio ports" + depends on SERIO + help + Say Y here if you want to have raw access to serio ports, such as + AUX ports on i8042 keyboard controller. Each serio port that is + bound to this driver will be accessible via a char device with + major 10 and dynamically allocated minor. The driver will try + allocating minor 1 (that historically corresponds to /dev/psaux) + first. To bind this driver to a serio port use sysfs interface: + + echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver + + To compile this driver as a module, choose M here: the + module will be called serio_raw. diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile --- a/drivers/input/serio/Makefile 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/serio/Makefile 2004-10-18 14:55:54 -07:00 @@ -17,3 +17,4 @@ obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o +obj-$(CONFIG_SERIO_RAW) += serio_raw.o diff -Nru a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c --- a/drivers/input/serio/ambakmi.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/input/serio/ambakmi.c 2004-10-18 14:56:33 -07:00 @@ -29,7 +29,7 @@ #define KMI_BASE (kmi->base) struct amba_kmi_port { - struct serio io; + struct serio *io; struct clk *clk; unsigned char *base; unsigned int irq; @@ -44,7 +44,7 @@ int handled = IRQ_NONE; while (status & KMIIR_RXINTR) { - serio_interrupt(&kmi->io, readb(KMIDATA), 0, regs); + serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); status = readb(KMIIR); handled = IRQ_HANDLED; } @@ -54,7 +54,7 @@ static int amba_kmi_write(struct serio *io, unsigned char val) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int timeleft = 10000; /* timeout in 100ms */ while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) @@ -68,7 +68,7 @@ static int amba_kmi_open(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int divisor; int ret; @@ -105,7 +105,7 @@ static void amba_kmi_close(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; writeb(0, KMICR); @@ -117,6 +117,7 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) { struct amba_kmi_port *kmi; + struct serio *io; int ret; ret = amba_request_regions(dev, NULL); @@ -124,21 +125,25 @@ return ret; kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); - if (!kmi) { + io = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!kmi || !io) { ret = -ENOMEM; goto out; } memset(kmi, 0, sizeof(struct amba_kmi_port)); + memset(io, 0, sizeof(struct serio)); - kmi->io.type = SERIO_8042; - kmi->io.write = amba_kmi_write; - kmi->io.open = amba_kmi_open; - kmi->io.close = amba_kmi_close; - kmi->io.name = dev->dev.bus_id; - kmi->io.phys = dev->dev.bus_id; - kmi->io.driver = kmi; + io->type = SERIO_8042; + io->write = amba_kmi_write; + io->open = amba_kmi_open; + io->close = amba_kmi_close; + strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); + strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); + io->port_data = kmi; + io->dev.parent = &dev->dev; + kmi->io = io; kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { ret = -ENOMEM; @@ -154,13 +159,14 @@ kmi->irq = dev->irq[0]; amba_set_drvdata(dev, kmi); - serio_register_port(&kmi->io); + serio_register_port(kmi->io); return 0; unmap: iounmap(kmi->base); out: kfree(kmi); + kfree(io); amba_release_regions(dev); return ret; } @@ -171,7 +177,7 @@ amba_set_drvdata(dev, NULL); - serio_unregister_port(&kmi->io); + serio_unregister_port(kmi->io); clk_put(kmi->clk); iounmap(kmi->base); kfree(kmi); @@ -184,7 +190,7 @@ struct amba_kmi_port *kmi = amba_get_drvdata(dev); /* kick the serio layer to rescan this port */ - serio_rescan(&kmi->io); + serio_reconnect(kmi->io); return 0; } @@ -214,7 +220,7 @@ static void __exit amba_kmi_exit(void) { - return amba_driver_unregister(&ambakmi_driver); + amba_driver_unregister(&ambakmi_driver); } module_init(amba_kmi_init); diff -Nru a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c --- a/drivers/input/serio/ct82c710.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/serio/ct82c710.c 2004-10-18 14:55:54 -07:00 @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -43,9 +44,6 @@ MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); MODULE_LICENSE("GPL"); -static char ct82c710_name[] = "C&T 82c710 mouse port"; -static char ct82c710_phys[16]; - /* * ct82c710 interface */ @@ -61,10 +59,22 @@ #define CT82C710_IRQ 12 -static int ct82c710_data; -static int ct82c710_status; +#define CT82C710_DATA ct82c710_iores.start +#define CT82C710_STATUS (ct82c710_iores.start + 1) -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs); +static struct serio *ct82c710_port; +static struct platform_device *ct82c710_device; +static struct resource ct82c710_iores; + +/* + * Interrupt handler for the 82C710 mouse port. A character + * is waiting in the 82C710. + */ + +static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) +{ + return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs); +} /* * Wait for device to send output char and flush any input char. @@ -74,10 +84,10 @@ { int timeout = 60000; - while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) + while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { - if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data); + if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA); udelay(1); timeout--; @@ -91,7 +101,7 @@ if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); - outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status); + outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS); if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); @@ -106,21 +116,21 @@ if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) return -1; - status = inb_p(ct82c710_status); + status = inb_p(CT82C710_STATUS); status |= (CT82C710_ENABLE | CT82C710_RESET); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); status &= ~(CT82C710_RESET); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); status |= CT82C710_INTS_ON; - outb_p(status, ct82c710_status); /* Enable interrupts */ + outb_p(status, CT82C710_STATUS); /* Enable interrupts */ while (ct82c170_wait()) { printk(KERN_ERR "ct82c710: Device busy in open()\n"); status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); free_irq(CT82C710_IRQ, NULL); return -1; } @@ -135,30 +145,10 @@ static int ct82c710_write(struct serio *port, unsigned char c) { if (ct82c170_wait()) return -1; - outb_p(c, ct82c710_data); + outb_p(c, CT82C710_DATA); return 0; } -static struct serio ct82c710_port = -{ - .type = SERIO_8042, - .name = ct82c710_name, - .phys = ct82c710_phys, - .write = ct82c710_write, - .open = ct82c710_open, - .close = ct82c710_close, -}; - -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - return serio_interrupt(&ct82c710_port, inb(ct82c710_data), 0, regs); -} - /* * See if we can find a 82C710 device. Read mouse address. */ @@ -175,36 +165,60 @@ return -1; /* No: no 82C710 here */ outb_p(0x0d, 0x390); /* Write index */ - ct82c710_data = inb_p(0x391) << 2; /* Get mouse I/O address */ - ct82c710_status = ct82c710_data + 1; + ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */ + ct82c710_iores.end = ct82c710_iores.start + 1; + ct82c710_iores.flags = IORESOURCE_IO; outb_p(0x0f, 0x390); outb_p(0x0f, 0x391); /* Close config mode */ return 0; } +static struct serio * __init ct82c710_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->open = ct82c710_open; + serio->close = ct82c710_close; + serio->write = ct82c710_write; + serio->dev.parent = &ct82c710_device->dev; + strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA); + } + + return serio; +} + int __init ct82c710_init(void) { if (ct82c710_probe()) return -ENODEV; - if (request_region(ct82c710_data, 2, "ct82c710")) - return -EBUSY; - - sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); + ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1); + if (IS_ERR(ct82c710_device)) + return PTR_ERR(ct82c710_device); + + if (!(ct82c710_port = ct82c710_allocate_port())) { + platform_device_unregister(ct82c710_device); + return -ENOMEM; + } - serio_register_port(&ct82c710_port); + serio_register_port(ct82c710_port); - printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", - ct82c710_data, CT82C710_IRQ); + printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n", + CT82C710_DATA, CT82C710_IRQ); return 0; } void __exit ct82c710_exit(void) { - serio_unregister_port(&ct82c710_port); - release_region(ct82c710_data, 2); + serio_unregister_port(ct82c710_port); + platform_device_unregister(ct82c710_device); } module_init(ct82c710_init); diff -Nru a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c --- a/drivers/input/serio/gscps2.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/input/serio/gscps2.c 2004-10-18 14:57:04 -07:00 @@ -6,7 +6,7 @@ * Copyright (c) 2002 Thibaut Varene * * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c - * Copyright (c) 1999 Alex deVries + * Copyright (c) 1999 Alex deVries * Copyright (c) 1999-2000 Philipp Rumpf * Copyright (c) 2000 Xavier Debacker * Copyright (c) 2000-2001 Thomas Marteau @@ -91,7 +91,7 @@ struct gscps2port { struct list_head node; struct parisc_device *padev; - struct serio port; + struct serio *port; spinlock_t lock; char *addr; u8 act, append; /* position in buffer[] */ @@ -100,7 +100,6 @@ u8 str; } buffer[BUFFER_SIZE+1]; int id; - char name[32]; }; /* @@ -272,7 +271,7 @@ rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); - serio_interrupt(&ps2port->port, data, rxflags, regs); + serio_interrupt(ps2port->port, data, rxflags, regs); } /* while() */ @@ -288,7 +287,7 @@ static int gscps2_write(struct serio *port, unsigned char data) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; if (!gscps2_writeb_output(ps2port, data)) { printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); @@ -304,7 +303,7 @@ static int gscps2_open(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_reset(ps2port); @@ -319,7 +318,7 @@ static void gscps2_close(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_enable(ps2port, DISABLE); } @@ -343,7 +342,8 @@ static int __init gscps2_probe(struct parisc_device *dev) { - struct gscps2port *ps2port; + struct gscps2port *ps2port; + struct serio *serio; unsigned long hpa = dev->hpa; int ret; @@ -355,34 +355,45 @@ hpa += GSC_DINO_OFFSET; ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); - if (!ps2port) - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2port || !serio) { + ret = -ENOMEM; + goto fail_nomem; + } dev_set_drvdata(&dev->dev, ps2port); memset(ps2port, 0, sizeof(struct gscps2port)); + memset(serio, 0, sizeof(struct serio)); + ps2port->port = serio; ps2port->padev = dev; ps2port->addr = ioremap(hpa, GSC_STATUS + 4); spin_lock_init(&ps2port->lock); gscps2_reset(ps2port); - ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; - snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s", - gscps2_serio_port.name, - (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); - - memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); - ps2port->port.driver = ps2port; - ps2port->port.name = ps2port->name; - ps2port->port.phys = dev->dev.bus_id; + ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; + + snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", + (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->idbus = BUS_GSC; + serio->idvendor = PCI_VENDOR_ID_HP; + serio->idproduct = 0x0001; + serio->idversion = 0x0010; + serio->type = SERIO_8042; + serio->write = gscps2_write; + serio->open = gscps2_open; + serio->close = gscps2_close; + serio->port_data = ps2port; + serio->dev.parent = &dev->dev; list_add_tail(&ps2port->node, &ps2port_list); ret = -EBUSY; - if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port)) + if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) goto fail_miserably; - if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) { + if (ps2port->id != GSC_ID_KEYBOARD && ps2port->id != GSC_ID_MOUSE) { printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", hpa, ps2port->id); ret = -ENODEV; @@ -395,12 +406,12 @@ #endif printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", - ps2port->name, + ps2port->port->name, ps2port->addr, ps2port->padev->irq, - ps2port->port.phys); + ps2port->port->phys); - serio_register_port(&ps2port->port); + serio_register_port(ps2port->port); return 0; @@ -411,7 +422,10 @@ list_del(&ps2port->node); iounmap(ps2port->addr); release_mem_region(dev->hpa, GSC_STATUS + 4); + +fail_nomem: kfree(ps2port); + kfree(serio); return ret; } @@ -424,7 +438,7 @@ { struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); - serio_unregister_port(&ps2port->port); + serio_unregister_port(ps2port->port); free_irq(dev->irq, ps2port); gscps2_flush(ps2port); list_del(&ps2port->node); diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h --- a/drivers/input/serio/i8042-io.h 2004-10-18 14:55:53 -07:00 +++ b/drivers/input/serio/i8042-io.h 2004-10-18 14:55:53 -07:00 @@ -65,6 +65,31 @@ return; } +#if defined(__i386__) + +#include + +static struct dmi_system_id __initdata i8042_dmi_table[] = { + { + .ident = "Compaq Proliant 8500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), + }, + }, + { + .ident = "Compaq Proliant DL760", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), + }, + }, + { } +}; +#endif + static inline int i8042_platform_init(void) { /* @@ -79,6 +104,12 @@ #if !defined(__i386__) && !defined(__x86_64__) i8042_reset = 1; #endif + +#if defined(__i386__) + if (dmi_check_system(i8042_dmi_table)) + i8042_noloop = 1; +#endif + return 0; } diff -Nru a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h --- a/drivers/input/serio/i8042-sparcio.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/input/serio/i8042-sparcio.h 2004-10-18 14:57:04 -07:00 @@ -18,7 +18,7 @@ #define I8042_AUX_PHYS_DESC "sparcps2/serio1" #define I8042_MUX_PHYS_DESC "sparcps2/serio%d" -static unsigned long kbd_iobase; +static void __iomem *kbd_iobase; #define I8042_COMMAND_REG (kbd_iobase + 0x64UL) #define I8042_DATA_REG (kbd_iobase + 0x60UL) @@ -64,7 +64,7 @@ if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { /* Hardcoded values for MrCoffee. */ i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; - kbd_iobase = (unsigned long) ioremap(0x71300060, 8); + kbd_iobase = ioremap(0x71300060, 8); if (!kbd_iobase) return -1; } else { @@ -85,7 +85,7 @@ if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) || !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) { i8042_kbd_irq = child->irqs[0]; - kbd_iobase = (unsigned long) + kbd_iobase = ioremap(child->resource[0].start, 8); } if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) || @@ -109,7 +109,7 @@ static inline void i8042_platform_exit(void) { #ifdef CONFIG_PCI - iounmap((void *)kbd_iobase); + iounmap(kbd_iobase); #endif } diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/serio/i8042.c 2004-10-18 14:55:54 -07:00 @@ -1,7 +1,7 @@ /* * i8042 keyboard and mouse controller driver for Linux * - * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik */ /* @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -52,6 +53,10 @@ module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +static unsigned int i8042_noloop; +module_param_named(noloop, i8042_noloop, bool, 0); +MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port"); + __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); __obsolete_setup("i8042_unlock"); @@ -70,19 +75,35 @@ unsigned char irqen; unsigned char exists; signed char mux; - unsigned char *name; - unsigned char *phys; + char name[8]; +}; + +static struct i8042_values i8042_kbd_values = { + .disable = I8042_CTR_KBDDIS, + .irqen = I8042_CTR_KBDINT, + .mux = -1, + .name = "KBD", +}; + +static struct i8042_values i8042_aux_values = { + .disable = I8042_CTR_AUXDIS, + .irqen = I8042_CTR_AUXINT, + .mux = -1, + .name = "AUX", }; -static struct serio i8042_kbd_port; -static struct serio i8042_aux_port; +static struct i8042_values i8042_mux_values[I8042_NUM_MUX_PORTS]; + +static struct serio *i8042_kbd_port; +static struct serio *i8042_aux_port; +static struct serio *i8042_mux_port[I8042_NUM_MUX_PORTS]; static unsigned char i8042_initial_ctr; static unsigned char i8042_ctr; static unsigned char i8042_mux_open; static unsigned char i8042_mux_present; -static unsigned char i8042_sysdev_initialized; static struct pm_dev *i8042_pm_dev; -struct timer_list i8042_timer; +static struct timer_list i8042_timer; +static struct platform_device *i8042_platform_device; /* * Shared IRQ's require a device pointer, but this driver doesn't support @@ -95,6 +116,7 @@ /* * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to * be ready for reading values from it / writing values to it. + * Called always with i8042_lock held. */ static int i8042_wait_read(void) @@ -131,6 +153,7 @@ spin_lock_irqsave(&i8042_lock, flags); while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) { + udelay(50); data = i8042_read_data(); dbg("%02x <- i8042 (flush, %s)", data, i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd"); @@ -154,6 +177,9 @@ unsigned long flags; int retval = 0, i = 0; + if (i8042_noloop && command == I8042_CMD_AUX_LOOP) + return -1; + spin_lock_irqsave(&i8042_lock, flags); retval = i8042_wait_write(); @@ -214,7 +240,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; int retval; /* @@ -242,7 +268,7 @@ static int i8042_activate_port(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; i8042_flush(); @@ -270,7 +296,7 @@ static int i8042_open(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (i8042_mux_open++) @@ -309,7 +335,7 @@ static void i8042_close(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (--i8042_mux_open) @@ -328,52 +354,6 @@ } /* - * Structures for registering the devices in the serio.c module. - */ - -static struct i8042_values i8042_kbd_values = { - .irqen = I8042_CTR_KBDINT, - .disable = I8042_CTR_KBDDIS, - .name = "KBD", - .mux = -1, -}; - -static struct serio i8042_kbd_port = -{ - .type = SERIO_8042_XL, - .write = i8042_kbd_write, - .open = i8042_open, - .close = i8042_close, - .driver = &i8042_kbd_values, - .name = "i8042 Kbd Port", - .phys = I8042_KBD_PHYS_DESC, -}; - -static struct i8042_values i8042_aux_values = { - .irqen = I8042_CTR_AUXINT, - .disable = I8042_CTR_AUXDIS, - .name = "AUX", - .mux = -1, -}; - -static struct serio i8042_aux_port = -{ - .type = SERIO_8042, - .write = i8042_aux_write, - .open = i8042_open, - .close = i8042_close, - .driver = &i8042_aux_values, - .name = "i8042 Aux Port", - .phys = I8042_AUX_PHYS_DESC, -}; - -static struct i8042_values i8042_mux_values[4]; -static struct serio i8042_mux_port[4]; -static char i8042_mux_names[4][32]; -static char i8042_mux_short[4][16]; -static char i8042_mux_phys[4][32]; - -/* * i8042_interrupt() is the most important function in this driver - * it handles the interrupts from the i8042, and sends incoming bytes * to the upper layers. @@ -384,6 +364,7 @@ unsigned long flags; unsigned char str, data = 0; unsigned int dfl; + unsigned int aux_idx; int ret; mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); @@ -400,44 +381,67 @@ goto out; } - dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); - - if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) { + if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { + static unsigned long last_transmit; + static unsigned char last_str; + dfl = 0; if (str & I8042_STR_MUXERR) { + dbg("MUX error, status is %02x, data is %02x", str, data); switch (data) { + default: +/* + * When MUXERR condition is signalled the data register can only contain + * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately + * it is not always the case. Some KBC just get confused which port the + * data came from and signal error leaving the data intact. They _do not_ + * revert to legacy mode (actually I've never seen KBC reverting to legacy + * mode yet, when we see one we'll add proper handling). + * Anyway, we will assume that the data came from the same serio last byte + * was transmitted (if transmission happened not too long ago). + */ + if (time_before(jiffies, last_transmit + HZ/10)) { + str = last_str; + break; + } + /* fall through - report timeout */ case 0xfd: - case 0xfe: dfl = SERIO_TIMEOUT; break; - case 0xff: dfl = SERIO_PARITY; break; + case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; + case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; } - data = 0xfe; - } else dfl = 0; + } + + aux_idx = (str >> 6) & 3; dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", - data, (str >> 6), irq, + data, aux_idx, irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); + if (likely(i8042_mux_values[aux_idx].exists)) + serio_interrupt(i8042_mux_port[aux_idx], data, dfl, regs); + last_str = str; + last_transmit = jiffies; goto irq_ret; } + dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | + ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); + dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { - serio_interrupt(&i8042_aux_port, data, dfl, regs); - goto irq_ret; - } - - if (!i8042_kbd_values.exists) - goto irq_ret; - serio_interrupt(&i8042_kbd_port, data, dfl, regs); + if (str & I8042_STR_AUXDATA) { + if (likely(i8042_aux_values.exists)) + serio_interrupt(i8042_aux_port, data, dfl, regs); + } else { + if (likely(i8042_kbd_values.exists)) + serio_interrupt(i8042_kbd_port, data, dfl, regs); + } irq_ret: ret = 1; @@ -474,17 +478,8 @@ if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa9) return -1; param = 0xa4; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) { - -/* - * Do another loop test with the 0x5a value. Doing anything else upsets - * Profusion/ServerWorks OSB4 chipsets. - */ - - param = 0x5a; - i8042_command(¶m, I8042_CMD_AUX_LOOP); + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) return -1; - } if (mux_version) *mux_version = ~param; @@ -639,8 +634,10 @@ * registers it, and reports to the user. */ -static int __init i8042_port_register(struct i8042_values *values, struct serio *port) +static int __init i8042_port_register(struct serio *port) { + struct i8042_values *values = port->port_data; + values->exists = 1; i8042_ctr &= ~values->disable; @@ -677,6 +674,7 @@ static int i8042_controller_init(void) { + unsigned long flags; /* * Test the i8042. We need to know if it thinks it's working correctly @@ -723,12 +721,14 @@ * Handle keylock. */ + spin_lock_irqsave(&i8042_lock, flags); if (~i8042_read_status() & I8042_STR_KEYLOCK) { if (i8042_unlock) i8042_ctr |= I8042_CTR_IGNKEYLOCK; else printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); } + spin_unlock_irqrestore(&i8042_lock, flags); /* * If the chip is configured into nontranslated mode by the BIOS, don't @@ -745,10 +745,8 @@ * BIOSes. */ - if (i8042_direct) { + if (i8042_direct) i8042_ctr &= ~I8042_CTR_XLATE; - i8042_kbd_port.type = SERIO_8042; - } /* * Write CTR back. @@ -802,14 +800,14 @@ */ if (i8042_kbd_values.exists) - serio_cleanup(&i8042_kbd_port); + serio_cleanup(i8042_kbd_port); if (i8042_aux_values.exists) - serio_cleanup(&i8042_aux_port); + serio_cleanup(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_cleanup(i8042_mux_port + i); + serio_cleanup(i8042_mux_port[i]); i8042_controller_reset(); } @@ -851,15 +849,15 @@ * Reconnect anything that was connected to the ports. */ - if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0) - serio_reconnect(&i8042_kbd_port); + if (i8042_kbd_values.exists && i8042_activate_port(i8042_kbd_port) == 0) + serio_reconnect(i8042_kbd_port); - if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0) - serio_reconnect(&i8042_aux_port); + if (i8042_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0) + serio_reconnect(i8042_aux_port); - for (i = 0; i < 4; i++) - if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0) - serio_reconnect(i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) + if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port[i]) == 0) + serio_reconnect(i8042_mux_port[i]); /* * Restart timer (for polling "stuck" data) */ @@ -882,7 +880,7 @@ return NOTIFY_DONE; } -static struct notifier_block i8042_notifier= +static struct notifier_block i8042_notifier = { i8042_notify_sys, NULL, @@ -892,25 +890,27 @@ /* * Suspend/resume handlers for the new PM scheme (driver model) */ -static int i8042_suspend(struct sys_device *dev, u32 state) +static int i8042_suspend(struct device *dev, u32 state, u32 level) { - return i8042_controller_suspend(); + return level == SUSPEND_DISABLE ? i8042_controller_suspend() : 0; } -static int i8042_resume(struct sys_device *dev) +static int i8042_resume(struct device *dev, u32 level) { - return i8042_controller_resume(); + return level == RESUME_ENABLE ? i8042_controller_resume() : 0; } -static struct sysdev_class kbc_sysclass = { - set_kset_name("i8042"), - .suspend = i8042_suspend, - .resume = i8042_resume, -}; +static void i8042_shutdown(struct device *dev) +{ + i8042_controller_cleanup(); +} -static struct sys_device device_i8042 = { - .id = 0, - .cls = &kbc_sysclass, +static struct device_driver i8042_driver = { + .name = "i8042", + .bus = &platform_bus_type, + .suspend = i8042_suspend, + .resume = i8042_resume, + .shutdown = i8042_shutdown, }; /* @@ -929,23 +929,75 @@ return 0; } -static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index) +static struct serio * __init i8042_allocate_kbd_port(void) { - memcpy(port, &i8042_aux_port, sizeof(struct serio)); - memcpy(values, &i8042_aux_values, sizeof(struct i8042_values)); - sprintf(i8042_mux_names[index], "i8042 Aux-%d Port", index); - sprintf(i8042_mux_phys[index], I8042_MUX_PHYS_DESC, index + 1); - sprintf(i8042_mux_short[index], "AUX%d", index); - port->name = i8042_mux_names[index]; - port->phys = i8042_mux_phys[index]; - port->driver = values; - values->name = i8042_mux_short[index]; - values->mux = index; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = i8042_direct ? SERIO_8042 : SERIO_8042_XL, + serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write, + serio->open = i8042_open, + serio->close = i8042_close, + serio->port_data = &i8042_kbd_values, + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_aux_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = &i8042_aux_values, + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_mux_port(int index) +{ + struct serio *serio; + struct i8042_values *values = &i8042_mux_values[index]; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + *values = i8042_aux_values; + snprintf(values->name, sizeof(values->name), "AUX%d", index); + values->mux = index; + + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = values; + serio->dev.parent = &i8042_platform_device->dev; + snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); + snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); + } + + return serio; } int __init i8042_init(void) { int i; + int err; dbg_init(); @@ -961,30 +1013,36 @@ if (i8042_controller_init()) return -ENODEV; - if (i8042_dumbkbd) - i8042_kbd_port.write = NULL; + err = driver_register(&i8042_driver); + if (err) + return err; + + i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); + if (IS_ERR(i8042_platform_device)) { + driver_unregister(&i8042_driver); + return PTR_ERR(i8042_platform_device); + } if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) - for (i = 0; i < 4; i++) { - i8042_init_mux_values(i8042_mux_values + i, i8042_mux_port + i, i); - i8042_port_register(i8042_mux_values + i, i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { + i8042_mux_port[i] = i8042_allocate_mux_port(i); + if (i8042_mux_port[i]) + i8042_port_register(i8042_mux_port[i]); } - else - i8042_port_register(&i8042_aux_values, &i8042_aux_port); + else { + i8042_aux_port = i8042_allocate_aux_port(); + if (i8042_aux_port) + i8042_port_register(i8042_aux_port); + } } - i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); + i8042_kbd_port = i8042_allocate_kbd_port(); + if (i8042_kbd_port) + i8042_port_register(i8042_kbd_port); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - if (sysdev_class_register(&kbc_sysclass) == 0) { - if (sysdev_register(&device_i8042) == 0) - i8042_sysdev_initialized = 1; - else - sysdev_class_unregister(&kbc_sysclass); - } - i8042_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, i8042_pm_callback); register_reboot_notifier(&i8042_notifier); @@ -1001,23 +1059,22 @@ if (i8042_pm_dev) pm_unregister(i8042_pm_dev); - if (i8042_sysdev_initialized) { - sysdev_unregister(&device_i8042); - sysdev_class_unregister(&kbc_sysclass); - } - i8042_controller_cleanup(); if (i8042_kbd_values.exists) - serio_unregister_port(&i8042_kbd_port); + serio_unregister_port(i8042_kbd_port); if (i8042_aux_values.exists) - serio_unregister_port(&i8042_aux_port); + serio_unregister_port(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_unregister_port(i8042_mux_port + i); + serio_unregister_port(i8042_mux_port[i]); + del_timer_sync(&i8042_timer); + + platform_device_unregister(i8042_platform_device); + driver_unregister(&i8042_driver); i8042_platform_exit(); } diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h --- a/drivers/input/serio/i8042.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/input/serio/i8042.h 2004-10-18 14:56:49 -07:00 @@ -104,6 +104,13 @@ #define I8042_BUFFER_SIZE 32 /* + * Number of AUX ports on controllers supporting active multiplexing + * specification + */ + +#define I8042_NUM_MUX_PORTS 4 + +/* * Debug. */ diff -Nru a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c --- a/drivers/input/serio/maceps2.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/input/serio/maceps2.c 2004-10-18 14:56:28 -07:00 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -46,15 +47,18 @@ #define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ #define PS2_CONTROL_RESET BIT(5) /* reset */ - struct maceps2_data { struct mace_ps2port *port; int irq; }; +static struct maceps2_data port_data[2]; +static struct serio *maceps2_port[2]; +static struct platform_device *maceps2_device; + static int maceps2_write(struct serio *dev, unsigned char val) { - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int timeout = MACE_PS2_TIMEOUT; do { @@ -68,11 +72,10 @@ return -1; } -static irqreturn_t maceps2_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t maceps2_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct serio *dev = dev_id; - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int byte; if (mace_read(port->status) & PS2_STATUS_RX_FULL) { @@ -85,7 +88,7 @@ static int maceps2_open(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); @@ -106,7 +109,7 @@ static void maceps2_close(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, data->port->control); @@ -114,46 +117,59 @@ free_irq(data->irq, dev); } -static struct maceps2_data port0_data, port1_data; -static struct serio maceps2_port0 = +static struct serio * __init maceps2_allocate_port(int idx) { - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port0", - .phys = "mace/serio0", - .driver = &port0_data, -}; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = maceps2_write; + serio->open = maceps2_open; + serio->close = maceps2_close; + snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx); + snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx); + serio->port_data = &port_data[idx]; + serio->dev.parent = &maceps2_device->dev; + } + + return serio; +} -static struct serio maceps2_port1 = -{ - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port1", - .phys = "mace/serio1", - .driver = &port1_data, -}; static int __init maceps2_init(void) { - port0_data.port = &mace->perif.ps2.keyb; - port0_data.irq = MACEISA_KEYB_IRQ; - port1_data.port = &mace->perif.ps2.mouse; - port1_data.irq = MACEISA_MOUSE_IRQ; - serio_register_port(&maceps2_port0); - serio_register_port(&maceps2_port1); + maceps2_device = platform_device_register_simple("maceps2", -1, NULL, 0); + if (IS_ERR(maceps2_device)) + return PTR_ERR(maceps2_device); + + port_data[0].port = &mace->perif.ps2.keyb; + port_data[0].irq = MACEISA_KEYB_IRQ; + port_data[1].port = &mace->perif.ps2.mouse; + port_data[1].irq = MACEISA_MOUSE_IRQ; + + maceps2_port[0] = maceps2_allocate_port(0); + maceps2_port[1] = maceps2_allocate_port(1); + if (!maceps2_port[0] || !maceps2_port[1]) { + kfree(maceps2_port[0]); + kfree(maceps2_port[1]); + platform_device_unregister(maceps2_device); + return -ENOMEM; + } + + serio_register_port(maceps2_port[0]); + serio_register_port(maceps2_port[1]); return 0; } static void __exit maceps2_exit(void) { - serio_unregister_port(&maceps2_port0); - serio_unregister_port(&maceps2_port1); + serio_unregister_port(maceps2_port[0]); + serio_unregister_port(maceps2_port[1]); + platform_device_unregister(maceps2_device); } module_init(maceps2_init); diff -Nru a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c --- a/drivers/input/serio/parkbd.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/serio/parkbd.c 2004-10-18 14:55:54 -07:00 @@ -53,9 +53,7 @@ static unsigned long parkbd_start; static struct pardevice *parkbd_dev; - -static char parkbd_name[] = "PARKBD AT/XT keyboard adapter"; -static char parkbd_phys[32]; +static struct serio *parkbd_port; static int parkbd_readlines(void) { @@ -86,13 +84,6 @@ return 0; } -static struct serio parkbd_port = -{ - .write = parkbd_write, - .name = parkbd_name, - .phys = parkbd_phys, -}; - static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -125,7 +116,7 @@ parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; if (parkbd_counter == parkbd_mode + 10) - serio_interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); + serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); } parkbd_last = jiffies; @@ -163,16 +154,39 @@ return 0; } +static struct serio * __init parkbd_allocate_serio(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = parkbd_mode; + serio->write = parkbd_write, + strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name); + } + + return serio; +} int __init parkbd_init(void) { - if (parkbd_getport()) return -1; - parkbd_writelines(3); - parkbd_port.type = parkbd_mode; + int err; - sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name); + err = parkbd_getport(); + if (err) + return err; + + parkbd_port = parkbd_allocate_serio(); + if (!parkbd_port) { + parport_release(parkbd_dev); + return -ENOMEM; + } + + parkbd_writelines(3); - serio_register_port(&parkbd_port); + serio_register_port(parkbd_port); printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); @@ -183,7 +197,7 @@ void __exit parkbd_exit(void) { parport_release(parkbd_dev); - serio_unregister_port(&parkbd_port); + serio_unregister_port(parkbd_port); parport_unregister_device(parkbd_dev); } diff -Nru a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c --- a/drivers/input/serio/pcips2.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/input/serio/pcips2.c 2004-10-18 14:56:17 -07:00 @@ -38,14 +38,14 @@ #define PS2_STAT_TXEMPTY (1<<7) struct pcips2_data { - struct serio io; + struct serio *io; unsigned int base; struct pci_dev *dev; }; static int pcips2_write(struct serio *io, unsigned char val) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; unsigned int stat; do { @@ -80,7 +80,7 @@ if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); } while (1); return IRQ_RETVAL(handled); } @@ -101,7 +101,7 @@ static int pcips2_open(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; int ret, val = 0; outb(PS2_CTRL_ENABLE, ps2if->base); @@ -119,7 +119,7 @@ static void pcips2_close(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; outb(0, ps2if->base); @@ -129,46 +129,51 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct pcips2_data *ps2if; + struct serio *serio; int ret; ret = pci_enable_device(dev); if (ret) - return ret; + goto out; - if (!request_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0), "pcips2")) { - ret = -EBUSY; + ret = pci_request_regions(dev, "pcips2"); + if (ret) goto disable; - } ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); - if (!ps2if) { + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { ret = -ENOMEM; goto release; } memset(ps2if, 0, sizeof(struct pcips2_data)); + memset(serio, 0, sizeof(struct serio)); - ps2if->io.type = SERIO_8042; - ps2if->io.write = pcips2_write; - ps2if->io.open = pcips2_open; - ps2if->io.close = pcips2_close; - ps2if->io.name = pci_name(dev); - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + serio->type = SERIO_8042; + serio->write = pcips2_write; + serio->open = pcips2_open; + serio->close = pcips2_close; + strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &dev->dev; + ps2if->io = serio; ps2if->dev = dev; ps2if->base = pci_resource_start(dev, 0); pci_set_drvdata(dev, ps2if); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; release: - release_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + kfree(ps2if); + kfree(serio); + pci_release_regions(dev); disable: pci_disable_device(dev); + out: return ret; } @@ -176,11 +181,10 @@ { struct pcips2_data *ps2if = pci_get_drvdata(dev); - serio_unregister_port(&ps2if->io); - release_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + serio_unregister_port(ps2if->io); pci_set_drvdata(dev, NULL); kfree(ps2if); + pci_release_regions(dev); pci_disable_device(dev); } diff -Nru a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c --- a/drivers/input/serio/q40kbd.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/input/serio/q40kbd.c 2004-10-18 14:56:27 -07:00 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -47,43 +48,106 @@ MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); -static struct serio q40kbd_port = -{ - .type = SERIO_8042, - .name = "Q40 kbd port", - .phys = "Q40", - .write = NULL, -}; +spinlock_t q40kbd_lock = SPIN_LOCK_UNLOCKED; +static struct serio *q40kbd_port; +static struct platform_device *q40kbd_device; -static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; + + spin_lock_irqsave(&q40kbd_lock, flags); + if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) - serio_interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0, regs); + serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs); master_outb(-1, KEYBOARD_UNLOCK_REG); + + spin_unlock_irqrestore(&q40kbd_lock, flags); + return IRQ_HANDLED; } -static int __init q40kbd_init(void) +/* + * q40kbd_flush() flushes all data that may be in the keyboard buffers + */ + +static void q40kbd_flush(void) { - int maxread = 100; + int maxread = 100; + unsigned long flags; + + spin_lock_irqsave(&q40kbd_lock, flags); + + while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) + master_inb(KEYCODE_REG); + + spin_unlock_irqrestore(&q40kbd_lock, flags); +} + +/* + * q40kbd_open() is called when a port is open by the higher layer. + * It allocates the interrupt and enables in in the chip. + */ + +static int q40kbd_open(struct serio *port) +{ + q40kbd_flush(); + + if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { + printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); + return -1; + } + + /* off we go */ + master_outb(-1, KEYBOARD_UNLOCK_REG); + master_outb(1, KEY_IRQ_ENABLE_REG); + + return 0; +} +static void q40kbd_close(struct serio *port) +{ + master_outb(0, KEY_IRQ_ENABLE_REG); + master_outb(-1, KEYBOARD_UNLOCK_REG); + free_irq(Q40_IRQ_KEYBOARD, NULL); + + q40kbd_flush(); +} + +static struct serio * __init q40kbd_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->open = q40kbd_open; + serio->close = q40kbd_close; + serio->dev.parent = &q40kbd_device->dev; + strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, "Q40", sizeof(serio->phys)); + } + + return serio; +} + +static int __init q40kbd_init(void) +{ if (!MACH_IS_Q40) return -EIO; - /* allocate the IRQ */ - request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL); - - /* flush any pending input */ - while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) - master_inb(KEYCODE_REG); - - /* off we go */ - master_outb(-1,KEYBOARD_UNLOCK_REG); - master_outb(1,KEY_IRQ_ENABLE_REG); + q40kbd_device = platform_device_register_simple("q40kbd", -1, NULL, 0); + if (IS_ERR(q40kbd_device)) + return PTR_ERR(q40kbd_device); + + if (!(q40kbd_port = q40kbd_allocate_port())) { + platform_device_unregister(q40kbd_device); + return -ENOMEM; + } - serio_register_port(&q40kbd_port); + serio_register_port(q40kbd_port); printk(KERN_INFO "serio: Q40 kbd registered\n"); return 0; @@ -91,11 +155,8 @@ static void __exit q40kbd_exit(void) { - master_outb(0,KEY_IRQ_ENABLE_REG); - master_outb(-1,KEYBOARD_UNLOCK_REG); - - serio_unregister_port(&q40kbd_port); - free_irq(Q40_IRQ_KEYBOARD, NULL); + serio_unregister_port(q40kbd_port); + platform_device_unregister(q40kbd_device); } module_init(q40kbd_init); diff -Nru a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c --- a/drivers/input/serio/rpckbd.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/serio/rpckbd.c 2004-10-18 14:55:54 -07:00 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,9 @@ MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); +static struct serio *rpckbd_port; +static struct platform_device *rpckbd_device; + static int rpckbd_write(struct serio *port, unsigned char val) { while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) @@ -101,25 +105,49 @@ free_irq(IRQ_KEYBOARDTX, port); } -static struct serio rpckbd_port = -{ - .type = SERIO_8042, - .open = rpckbd_open, - .close = rpckbd_close, - .write = rpckbd_write, - .name = "RiscPC PS/2 kbd port", - .phys = "rpckbd/serio0", -}; +/* + * Allocate and initialize serio structure for subsequent registration + * with serio core. + */ + +static struct serio * __init rpckbd_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = rpckbd_write; + serio->open = rpckbd_open; + serio->close = rpckbd_close; + serio->dev.parent = &rpckbd_device->dev; + strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); + strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); + } + + return serio; +} static int __init rpckbd_init(void) { - serio_register_port(&rpckbd_port); + rpckbd_device = platform_device_register_simple("rpckbd", -1, NULL, 0); + if (IS_ERR(rpckbd_device)) + return PTR_ERR(rpckbd_device); + + if (!(rpckbd_port = rpckbd_allocate_port())) { + platform_device_unregister(rpckbd_device); + return -ENOMEM; + } + + serio_register_port(rpckbd_port); return 0; } static void __exit rpckbd_exit(void) { - serio_unregister_port(&rpckbd_port); + serio_unregister_port(rpckbd_port); + platform_device_unregister(rpckbd_device); } module_init(rpckbd_init); diff -Nru a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c --- a/drivers/input/serio/sa1111ps2.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/input/serio/sa1111ps2.c 2004-10-18 14:56:31 -07:00 @@ -26,7 +26,7 @@ #include struct ps2if { - struct serio io; + struct serio *io; struct sa1111_dev *dev; unsigned long base; unsigned int open; @@ -59,7 +59,7 @@ if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); status = sa1111_readl(ps2if->base + SA1111_PS2STAT); } @@ -95,7 +95,7 @@ */ static int ps2_write(struct serio *io, unsigned char val) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; unsigned long flags; unsigned int head; @@ -122,7 +122,7 @@ static int ps2_open(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; int ret; sa1111_enable_device(ps2if->dev); @@ -154,7 +154,7 @@ static void ps2_close(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; sa1111_writel(0, ps2if->base + SA1111_PS2CR); @@ -232,22 +232,28 @@ static int ps2_probe(struct sa1111_dev *dev) { struct ps2if *ps2if; + struct serio *serio; int ret; ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); - if (!ps2if) { - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { + ret = -ENOMEM; + goto free; } memset(ps2if, 0, sizeof(struct ps2if)); + memset(serio, 0, sizeof(struct serio)); - ps2if->io.type = SERIO_8042; - ps2if->io.write = ps2_write; - ps2if->io.open = ps2_open; - ps2if->io.close = ps2_close; - ps2if->io.name = dev->dev.bus_id; - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + serio->type = SERIO_8042; + serio->write = ps2_write; + serio->open = ps2_open; + serio->close = ps2_close; + strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &dev->dev; + ps2if->io = serio; ps2if->dev = dev; sa1111_set_drvdata(dev, ps2if); @@ -292,7 +298,7 @@ ps2_clear_input(ps2if); sa1111_disable_device(ps2if->dev); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; out: @@ -302,6 +308,7 @@ free: sa1111_set_drvdata(dev, NULL); kfree(ps2if); + kfree(serio); return ret; } @@ -312,7 +319,7 @@ { struct ps2if *ps2if = sa1111_get_drvdata(dev); - serio_unregister_port(&ps2if->io); + serio_unregister_port(ps2if->io); release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); sa1111_set_drvdata(dev, NULL); diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c --- a/drivers/input/serio/serio.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/input/serio/serio.c 2004-10-18 14:55:54 -07:00 @@ -1,11 +1,9 @@ /* - * $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $ - * - * Copyright (c) 1999-2001 Vojtech Pavlik - */ - -/* * The Serio abstraction module + * + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Dmitry Torokhov + * Copyright (c) 2003 Daniele Bellucci */ /* @@ -26,10 +24,6 @@ * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - * - * Changes: - * 20 Jul. 2003 Daniele Bellucci - * Minor cleanups. */ #include @@ -50,100 +44,178 @@ EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_register_port); EXPORT_SYMBOL(serio_register_port_delayed); -EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port_delayed); -EXPORT_SYMBOL(__serio_unregister_port); -EXPORT_SYMBOL(serio_register_device); -EXPORT_SYMBOL(serio_unregister_device); +EXPORT_SYMBOL(serio_register_driver); +EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_reconnect); +static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_diriver_list */ +static LIST_HEAD(serio_list); +static LIST_HEAD(serio_driver_list); +static unsigned int serio_no; + +struct bus_type serio_bus = { + .name = "serio", +}; + +static void serio_find_driver(struct serio *serio); +static void serio_create_port(struct serio *serio); +static void serio_destroy_port(struct serio *serio); +static void serio_connect_port(struct serio *serio, struct serio_driver *drv); +static void serio_reconnect_port(struct serio *serio); +static void serio_disconnect_port(struct serio *serio); + +static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) +{ + get_driver(&drv->driver); + + drv->connect(serio, drv); + if (serio->drv) { + down_write(&serio_bus.subsys.rwsem); + serio->dev.driver = &drv->driver; + device_bind_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + return 1; + } + + put_driver(&drv->driver); + return 0; +} + +/* serio_find_driver() must be called with serio_sem down. */ +static void serio_find_driver(struct serio *serio) +{ + struct serio_driver *drv; + + list_for_each_entry(drv, &serio_driver_list, node) + if (!drv->manual_bind) + if (serio_bind_driver(serio, drv)) + break; +} + +/* + * Serio event processing. + */ + struct serio_event { int type; struct serio *serio; struct list_head node; }; -static DECLARE_MUTEX(serio_sem); -static LIST_HEAD(serio_list); -static LIST_HEAD(serio_dev_list); +enum serio_event_type { + SERIO_RESCAN, + SERIO_RECONNECT, + SERIO_REGISTER_PORT, + SERIO_UNREGISTER_PORT, +}; + +static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */ static LIST_HEAD(serio_event_list); +static DECLARE_WAIT_QUEUE_HEAD(serio_wait); +static DECLARE_COMPLETION(serio_exited); static int serio_pid; -static void serio_find_dev(struct serio *serio) +static void serio_queue_event(struct serio *serio, int event_type) { - struct serio_dev *dev; + unsigned long flags; + struct serio_event *event; - list_for_each_entry(dev, &serio_dev_list, node) { - if (serio->dev) - break; - if (dev->connect) - dev->connect(serio, dev); - } -} + spin_lock_irqsave(&serio_event_lock, flags); -#define SERIO_RESCAN 1 -#define SERIO_RECONNECT 2 -#define SERIO_REGISTER_PORT 3 -#define SERIO_UNREGISTER_PORT 4 + if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { + event->type = event_type; + event->serio = serio; -static DECLARE_WAIT_QUEUE_HEAD(serio_wait); -static DECLARE_COMPLETION(serio_exited); + list_add_tail(&event->node, &serio_event_list); + wake_up(&serio_wait); + } + + spin_unlock_irqrestore(&serio_event_lock, flags); +} -static void serio_invalidate_pending_events(struct serio *serio) +static struct serio_event *serio_get_event(void) { struct serio_event *event; + struct list_head *node; + unsigned long flags; + + spin_lock_irqsave(&serio_event_lock, flags); + + if (list_empty(&serio_event_list)) { + spin_unlock_irqrestore(&serio_event_lock, flags); + return NULL; + } + + node = serio_event_list.next; + event = container_of(node, struct serio_event, node); + list_del_init(node); + + spin_unlock_irqrestore(&serio_event_lock, flags); - list_for_each_entry(event, &serio_event_list, node) - if (event->serio == serio) - event->serio = NULL; + return event; } -void serio_handle_events(void) +static void serio_handle_events(void) { - struct list_head *node, *next; struct serio_event *event; - list_for_each_safe(node, next, &serio_event_list) { - event = container_of(node, struct serio_event, node); + while ((event = serio_get_event())) { down(&serio_sem); - if (event->serio == NULL) - goto event_done; switch (event->type) { case SERIO_REGISTER_PORT : - __serio_register_port(event->serio); + serio_create_port(event->serio); + serio_connect_port(event->serio, NULL); break; case SERIO_UNREGISTER_PORT : - __serio_unregister_port(event->serio); + serio_disconnect_port(event->serio); + serio_destroy_port(event->serio); break; case SERIO_RECONNECT : - if (event->serio->dev && event->serio->dev->reconnect) - if (event->serio->dev->reconnect(event->serio) == 0) - break; - /* reconnect failed - fall through to rescan */ + serio_reconnect_port(event->serio); + break; case SERIO_RESCAN : - if (event->serio->dev && event->serio->dev->disconnect) - event->serio->dev->disconnect(event->serio); - serio_find_dev(event->serio); + serio_disconnect_port(event->serio); + serio_connect_port(event->serio, NULL); break; default: break; } -event_done: + up(&serio_sem); - list_del_init(node); kfree(event); } } +static void serio_remove_pending_events(struct serio *serio) +{ + struct list_head *node, *next; + struct serio_event *event; + unsigned long flags; + + spin_lock_irqsave(&serio_event_lock, flags); + + list_for_each_safe(node, next, &serio_event_list) { + event = container_of(node, struct serio_event, node); + if (event->serio == serio) { + list_del_init(node); + kfree(event); + } + } + + spin_unlock_irqrestore(&serio_event_lock, flags); +} + + static int serio_thread(void *nothing) { lock_kernel(); @@ -163,52 +235,239 @@ complete_and_exit(&serio_exited, 0); } -static void serio_queue_event(struct serio *serio, int event_type) + +/* + * Serio port operations + */ + +static ssize_t serio_show_description(struct device *dev, char *buf) { - struct serio_event *event; + struct serio *serio = to_serio_port(dev); + return sprintf(buf, "%s\n", serio->name); +} - if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { - event->type = event_type; - event->serio = serio; +static ssize_t serio_show_driver(struct device *dev, char *buf) +{ + return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)"); +} - list_add_tail(&event->node, &serio_event_list); - wake_up(&serio_wait); +static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) +{ + struct serio *serio = to_serio_port(dev); + struct device_driver *drv; + int retval; + + retval = down_interruptible(&serio_sem); + if (retval) + return retval; + + retval = count; + if (!strncmp(buf, "none", count)) { + serio_disconnect_port(serio); + } else if (!strncmp(buf, "reconnect", count)) { + serio_reconnect_port(serio); + } else if (!strncmp(buf, "rescan", count)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { + serio_disconnect_port(serio); + serio_connect_port(serio, to_serio_driver(drv)); + put_driver(drv); + } else { + retval = -EINVAL; } + + up(&serio_sem); + + return retval; } -void serio_rescan(struct serio *serio) +static ssize_t serio_show_bind_mode(struct device *dev, char *buf) { - serio_queue_event(serio, SERIO_RESCAN); + struct serio *serio = to_serio_port(dev); + return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); } -void serio_reconnect(struct serio *serio) +static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count) { - serio_queue_event(serio, SERIO_RECONNECT); + struct serio *serio = to_serio_port(dev); + int retval; + + retval = count; + if (!strncmp(buf, "manual", count)) { + serio->manual_bind = 1; + } else if (!strncmp(buf, "auto", count)) { + serio->manual_bind = 0; + } else { + retval = -EINVAL; + } + + return retval; } -irqreturn_t serio_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) +static struct device_attribute serio_device_attrs[] = { + __ATTR(description, S_IRUGO, serio_show_description, NULL), + __ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver), + __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), + __ATTR_NULL +}; + + +static void serio_release_port(struct device *dev) { - irqreturn_t ret = IRQ_NONE; + struct serio *serio = to_serio_port(dev); - if (serio->dev && serio->dev->interrupt) { - ret = serio->dev->interrupt(serio, data, flags, regs); - } else { - if (!flags) { - if ((serio->type == SERIO_8042 || - serio->type == SERIO_8042_XL) && (data != 0xaa)) - return ret; - serio_rescan(serio); - ret = IRQ_HANDLED; + kfree(serio); + module_put(THIS_MODULE); +} + +static void serio_create_port(struct serio *serio) +{ + try_module_get(THIS_MODULE); + + spin_lock_init(&serio->lock); + list_add_tail(&serio->node, &serio_list); + snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++); + serio->dev.bus = &serio_bus; + serio->dev.release = serio_release_port; + if (serio->parent) + serio->dev.parent = &serio->parent->dev; + device_register(&serio->dev); +} + +/* + * serio_destroy_port() completes deregistration process and removes + * port from the system + */ +static void serio_destroy_port(struct serio *serio) +{ + struct serio_driver *drv = serio->drv; + unsigned long flags; + + serio_remove_pending_events(serio); + list_del_init(&serio->node); + + if (drv) { + drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } + + if (serio->parent) { + spin_lock_irqsave(&serio->parent->lock, flags); + serio->parent->child = NULL; + spin_unlock_irqrestore(&serio->parent->lock, flags); + } + + device_unregister(&serio->dev); +} + +/* + * serio_connect_port() tries to bind the port and possible all its + * children to appropriate drivers. If driver passed in the function will not + * try otehr drivers when binding parent port. + */ +static void serio_connect_port(struct serio *serio, struct serio_driver *drv) +{ + WARN_ON(serio->drv); + WARN_ON(serio->child); + + if (drv) + serio_bind_driver(serio, drv); + else if (!serio->manual_bind) + serio_find_driver(serio); + + /* Ok, now bind children, if any */ + while (serio->child) { + serio = serio->child; + + WARN_ON(serio->drv); + WARN_ON(serio->child); + + serio_create_port(serio); + + if (!serio->manual_bind) { + /* + * With children we just _prefer_ passed in driver, + * but we will try other options in case preferred + * is not the one + */ + if (!drv || !serio_bind_driver(serio, drv)) + serio_find_driver(serio); } } - return ret; +} + +/* + * + */ +static void serio_reconnect_port(struct serio *serio) +{ + do { + if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* Ok, old children are now gone, we are done */ + break; + } + serio = serio->child; + } while (serio); +} + +/* + * serio_disconnect_port() unbinds a port from its driver. As a side effect + * all child ports are unbound and destroyed. + */ +static void serio_disconnect_port(struct serio *serio) +{ + struct serio_driver *drv = serio->drv; + struct serio *s; + + if (serio->child) { + /* + * Children ports should be disconnected and destroyed + * first, staring with the leaf one, since we don't want + * to do recursion + */ + do { + s = serio->child; + } while (s->child); + + while (s != serio) { + s = s->parent; + serio_destroy_port(s->child); + } + } + + /* + * Ok, no children left, now disconnect this port + */ + if (drv) { + drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } +} + +void serio_rescan(struct serio *serio) +{ + serio_queue_event(serio, SERIO_RESCAN); +} + +void serio_reconnect(struct serio *serio) +{ + serio_queue_event(serio, SERIO_RECONNECT); } void serio_register_port(struct serio *serio) { down(&serio_sem); - __serio_register_port(serio); + serio_create_port(serio); + serio_connect_port(serio, NULL); up(&serio_sem); } @@ -222,21 +481,11 @@ serio_queue_event(serio, SERIO_REGISTER_PORT); } -/* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * connect() function. - */ -void __serio_register_port(struct serio *serio) -{ - list_add_tail(&serio->node, &serio_list); - serio_find_dev(serio); -} - void serio_unregister_port(struct serio *serio) { down(&serio_sem); - __serio_unregister_port(serio); + serio_disconnect_port(serio); + serio_destroy_port(serio); up(&serio_sem); } @@ -250,82 +499,171 @@ serio_queue_event(serio, SERIO_UNREGISTER_PORT); } + /* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * disconnect() function. + * Serio driver operations */ -void __serio_unregister_port(struct serio *serio) + +static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) { - serio_invalidate_pending_events(serio); - list_del_init(&serio->node); - if (serio->dev && serio->dev->disconnect) - serio->dev->disconnect(serio); + struct serio_driver *driver = to_serio_driver(drv); + return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); +} + +static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf) +{ + struct serio_driver *serio_drv = to_serio_driver(drv); + return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); } -void serio_register_device(struct serio_dev *dev) +static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count) +{ + struct serio_driver *serio_drv = to_serio_driver(drv); + int retval; + + retval = count; + if (!strncmp(buf, "manual", count)) { + serio_drv->manual_bind = 1; + } else if (!strncmp(buf, "auto", count)) { + serio_drv->manual_bind = 0; + } else { + retval = -EINVAL; + } + + return retval; +} + + +static struct driver_attribute serio_driver_attrs[] = { + __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), + __ATTR(bind_mode, S_IWUSR | S_IRUGO, + serio_driver_show_bind_mode, serio_driver_set_bind_mode), + __ATTR_NULL +}; + +void serio_register_driver(struct serio_driver *drv) { struct serio *serio; + down(&serio_sem); - list_add_tail(&dev->node, &serio_dev_list); - list_for_each_entry(serio, &serio_list, node) - if (!serio->dev && dev->connect) - dev->connect(serio, dev); + + list_add_tail(&drv->node, &serio_driver_list); + + drv->driver.bus = &serio_bus; + driver_register(&drv->driver); + + if (drv->manual_bind) + goto out; + +start_over: + list_for_each_entry(serio, &serio_list, node) { + if (!serio->drv) { + serio_connect_port(serio, drv); + /* + * if new child appeared then the list is changed, + * we need to start over + */ + if (serio->child) + goto start_over; + } + } + +out: up(&serio_sem); } -void serio_unregister_device(struct serio_dev *dev) +void serio_unregister_driver(struct serio_driver *drv) { struct serio *serio; down(&serio_sem); - list_del_init(&dev->node); + list_del_init(&drv->node); + +start_over: list_for_each_entry(serio, &serio_list, node) { - if (serio->dev == dev && dev->disconnect) - dev->disconnect(serio); - serio_find_dev(serio); + if (serio->drv == drv) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* we could've deleted some ports, restart */ + goto start_over; + } } + + driver_unregister(&drv->driver); + up(&serio_sem); } -/* called from serio_dev->connect/disconnect methods under serio_sem */ -int serio_open(struct serio *serio, struct serio_dev *dev) +/* called from serio_driver->connect/disconnect methods under serio_sem */ +int serio_open(struct serio *serio, struct serio_driver *drv) { - serio->dev = dev; + serio_pause_rx(serio); + serio->drv = drv; + serio_continue_rx(serio); + if (serio->open && serio->open(serio)) { - serio->dev = NULL; + serio_pause_rx(serio); + serio->drv = NULL; + serio_continue_rx(serio); return -1; } return 0; } -/* called from serio_dev->connect/disconnect methods under serio_sem */ +/* called from serio_driver->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { if (serio->close) serio->close(serio); - serio->dev = NULL; + + serio_pause_rx(serio); + serio->drv = NULL; + serio_continue_rx(serio); } -static int __init serio_init(void) +irqreturn_t serio_interrupt(struct serio *serio, + unsigned char data, unsigned int dfl, struct pt_regs *regs) { - int pid; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + + spin_lock_irqsave(&serio->lock, flags); + + if (likely(serio->drv)) { + ret = serio->drv->interrupt(serio, data, dfl, regs); + } else { + if (!dfl) { + if ((serio->type != SERIO_8042 && + serio->type != SERIO_8042_XL) || (data == 0xaa)) { + serio_rescan(serio); + ret = IRQ_HANDLED; + } + } + } + + spin_unlock_irqrestore(&serio->lock, flags); - pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL); + return ret; +} - if (!pid) { +static int __init serio_init(void) +{ + if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { printk(KERN_WARNING "serio: Failed to start kseriod\n"); return -1; } - serio_pid = pid; + serio_bus.dev_attrs = serio_device_attrs; + serio_bus.drv_attrs = serio_driver_attrs; + bus_register(&serio_bus); return 0; } static void __exit serio_exit(void) { + bus_unregister(&serio_bus); kill_proc(serio_pid, SIGTERM, 1); wait_for_completion(&serio_exited); } diff -Nru a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/serio/serio_raw.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,390 @@ +/* + * Raw serio device providing access to a raw byte stream from underlying + * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device + * + * Copyright (c) 2004 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Raw serio driver" + +MODULE_AUTHOR("Dmitry Torokhov "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +#define SERIO_RAW_QUEUE_LEN 64 +struct serio_raw { + unsigned char queue[SERIO_RAW_QUEUE_LEN]; + unsigned int tail, head; + + char name[16]; + unsigned int refcnt; + struct serio *serio; + struct miscdevice dev; + wait_queue_head_t wait; + struct list_head list; + struct list_head node; +}; + +struct serio_raw_list { + struct fasync_struct *fasync; + struct serio_raw *serio_raw; + struct list_head node; +}; + +static DECLARE_MUTEX(serio_raw_sem); +static LIST_HEAD(serio_raw_list); +static unsigned int serio_raw_no; + +/********************************************************************* + * Interface with userspace (file operations) * + *********************************************************************/ + +static int serio_raw_fasync(int fd, struct file *file, int on) +{ + struct serio_raw_list *list = file->private_data; + int retval; + + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static struct serio_raw *serio_raw_locate(int minor) +{ + struct serio_raw *serio_raw; + + list_for_each_entry(serio_raw, &serio_raw_list, node) { + if (serio_raw->dev.minor == minor) + return serio_raw; + } + + return NULL; +} + +static int serio_raw_open(struct inode *inode, struct file *file) +{ + struct serio_raw *serio_raw; + struct serio_raw_list *list; + int retval = 0; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!(serio_raw = serio_raw_locate(iminor(inode)))) { + retval = -ENODEV; + goto out; + } + + if (!serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { + retval = -ENOMEM; + goto out; + } + + memset(list, 0, sizeof(struct serio_raw_list)); + list->serio_raw = serio_raw; + file->private_data = list; + + serio_raw->refcnt++; + list_add_tail(&list->node, &serio_raw->list); + +out: + up(&serio_raw_sem); + return retval; +} + +static int serio_raw_cleanup(struct serio_raw *serio_raw) +{ + if (--serio_raw->refcnt == 0) { + misc_deregister(&serio_raw->dev); + list_del_init(&serio_raw->node); + kfree(serio_raw); + + return 1; + } + + return 0; +} + +static int serio_raw_release(struct inode *inode, struct file *file) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + + down(&serio_raw_sem); + + serio_raw_fasync(-1, file, 0); + serio_raw_cleanup(serio_raw); + + up(&serio_raw_sem); + return 0; +} + +static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) +{ + unsigned long flags; + int empty; + + spin_lock_irqsave(&serio_raw->serio->lock, flags); + + empty = serio_raw->head == serio_raw->tail; + if (!empty) { + *c = serio_raw->queue[serio_raw->tail]; + serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; + } + + spin_unlock_irqrestore(&serio_raw->serio->lock, flags); + + return !empty; +} + +static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + char c; + ssize_t retval = 0; + + if (!serio_raw->serio) + return -ENODEV; + + if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) + return -EAGAIN; + + retval = wait_event_interruptible(list->serio_raw->wait, + serio_raw->head != serio_raw->tail || !serio_raw->serio); + if (retval) + return retval; + + if (!serio_raw->serio) + return -ENODEV; + + while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { + if (put_user(c, buffer++)) + return -EFAULT; + retval++; + } + + return retval; +} + +static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + ssize_t written = 0; + int retval; + unsigned char c; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!list->serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (count > 32) + count = 32; + + while (count--) { + if (get_user(c, buffer++)) { + retval = -EFAULT; + goto out; + } + if (serio_write(list->serio_raw->serio, c)) { + retval = -EIO; + goto out; + } + written++; + }; + +out: + up(&serio_raw_sem); + return written; +} + +static unsigned int serio_raw_poll(struct file *file, poll_table *wait) +{ + struct serio_raw_list *list = file->private_data; + + poll_wait(file, &list->serio_raw->wait, wait); + + if (list->serio_raw->head != list->serio_raw->tail) + return POLLIN | POLLRDNORM; + + return 0; +} + +struct file_operations serio_raw_fops = { + .owner = THIS_MODULE, + .open = serio_raw_open, + .release = serio_raw_release, + .read = serio_raw_read, + .write = serio_raw_write, + .poll = serio_raw_poll, + .fasync = serio_raw_fasync, +}; + + +/********************************************************************* + * Interface with serio port * + *********************************************************************/ + +static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, + unsigned int dfl, struct pt_regs *regs) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_raw_list *list; + unsigned int head = serio_raw->head; + + /* we are holding serio->lock here so we are prootected */ + serio_raw->queue[head] = data; + head = (head + 1) % SERIO_RAW_QUEUE_LEN; + if (likely(head != serio_raw->tail)) { + serio_raw->head = head; + list_for_each_entry(list, &serio_raw->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&serio_raw->wait); + } + + return IRQ_HANDLED; +} + +static void serio_raw_connect(struct serio *serio, struct serio_driver *drv) +{ + struct serio_raw *serio_raw; + int err; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) { + printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); + return; + } + + down(&serio_raw_sem); + + memset(serio_raw, 0, sizeof(struct serio_raw)); + snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); + serio_raw->refcnt = 1; + serio_raw->serio = serio; + INIT_LIST_HEAD(&serio_raw->list); + init_waitqueue_head(&serio_raw->wait); + + serio->private = serio_raw; + if (serio_open(serio, drv)) + goto out_free; + + list_add_tail(&serio_raw->node, &serio_raw_list); + + serio_raw->dev.minor = PSMOUSE_MINOR; + serio_raw->dev.name = serio_raw->name; + serio_raw->dev.fops = &serio_raw_fops; + + err = misc_register(&serio_raw->dev); + if (err) { + serio_raw->dev.minor = MISC_DYNAMIC_MINOR; + err = misc_register(&serio_raw->dev); + } + + if (err) { + printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n", + serio->phys); + goto out_close; + } + + printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n", + serio->phys, serio_raw->name, serio_raw->dev.minor); + goto out; + +out_close: + serio_close(serio); + list_del_init(&serio_raw->node); +out_free: + serio->private = NULL; + kfree(serio_raw); +out: + up(&serio_raw_sem); +} + +static int serio_raw_reconnect(struct serio *serio) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_driver *drv = serio->drv; + + if (!drv || !serio_raw) { + printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n"); + return -1; + } + + /* + * Nothing needs to be done here, we just need this method to + * keep the same device. + */ + return 0; +} + +static void serio_raw_disconnect(struct serio *serio) +{ + struct serio_raw *serio_raw; + + down(&serio_raw_sem); + + serio_raw = serio->private; + + serio_close(serio); + serio->private = NULL; + + serio_raw->serio = NULL; + if (!serio_raw_cleanup(serio_raw)) + wake_up_interruptible(&serio_raw->wait); + + up(&serio_raw_sem); +} + +static struct serio_driver serio_raw_drv = { + .driver = { + .name = "serio_raw", + }, + .description = DRIVER_DESC, + .interrupt = serio_raw_interrupt, + .connect = serio_raw_connect, + .reconnect = serio_raw_reconnect, + .disconnect = serio_raw_disconnect, + .manual_bind = 1, +}; + +int __init serio_raw_init(void) +{ + serio_register_driver(&serio_raw_drv); + return 0; +} + +void __exit serio_raw_exit(void) +{ + serio_unregister_driver(&serio_raw_drv); +} + +module_init(serio_raw_init); +module_exit(serio_raw_exit); diff -Nru a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c --- a/drivers/input/serio/serport.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/input/serio/serport.c 2004-10-18 14:57:03 -07:00 @@ -31,28 +31,25 @@ struct serport { struct tty_struct *tty; wait_queue_head_t wait; - struct serio serio; + struct serio *serio; unsigned long flags; - char phys[32]; }; -char serport_name[] = "Serial port"; - /* * Callback functions from the serio code. */ static int serport_serio_write(struct serio *serio, unsigned char data) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); } static void serport_serio_close(struct serio *serio) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; - serport->serio.type = 0; + serport->serio->type = 0; wake_up_interruptible(&serport->wait); } @@ -64,26 +61,30 @@ static int serport_ldisc_open(struct tty_struct *tty) { struct serport *serport; + struct serio *serio; char name[64]; serport = kmalloc(sizeof(struct serport), GFP_KERNEL); - if (unlikely(!serport)) + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (unlikely(!serport || !serio)) { + kfree(serport); + kfree(serio); return -ENOMEM; - memset(serport, 0, sizeof(struct serport)); + } + memset(serport, 0, sizeof(struct serport)); + serport->serio = serio; set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); serport->tty = tty; tty->disc_data = serport; - snprintf(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name)); - - serport->serio.name = serport_name; - serport->serio.phys = serport->phys; - - serport->serio.type = SERIO_RS232; - serport->serio.write = serport_serio_write; - serport->serio.close = serport_serio_close; - serport->serio.driver = serport; + memset(serio, 0, sizeof(struct serio)); + strlcpy(serio->name, "Serial port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); + serio->type = SERIO_RS232; + serio->write = serport_serio_write; + serio->close = serport_serio_close; + serio->port_data = serport; init_waitqueue_head(&serport->wait); @@ -114,7 +115,7 @@ struct serport *serport = (struct serport*) tty->disc_data; int i; for (i = 0; i < count; i++) - serio_interrupt(&serport->serio, cp[i], 0, NULL); + serio_interrupt(serport->serio, cp[i], 0, NULL); } /* @@ -142,10 +143,10 @@ if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) return -EBUSY; - serio_register_port(&serport->serio); + serio_register_port(serport->serio); printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); - wait_event_interruptible(serport->wait, !serport->serio.type); - serio_unregister_port(&serport->serio); + wait_event_interruptible(serport->wait, !serport->serio->type); + serio_unregister_port(serport->serio); clear_bit(SERPORT_BUSY, &serport->flags); @@ -161,7 +162,7 @@ struct serport *serport = (struct serport*) tty->disc_data; if (cmd == SPIOCSTYPE) - return get_user(serport->serio.type, (unsigned long __user *) arg); + return get_user(serport->serio->type, (unsigned long __user *) arg); return -EINVAL; } @@ -170,7 +171,7 @@ { struct serport *sp = (struct serport *) tty->disc_data; - serio_dev_write_wakeup(&sp->serio); + serio_drv_write_wakeup(sp->serio); } /* diff -Nru a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c --- a/drivers/input/touchscreen/gunze.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/input/touchscreen/gunze.c 2004-10-18 14:56:28 -07:00 @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gunze AHL-51S touchscreen driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -111,7 +113,7 @@ * and if yes, registers it as an input device. */ -static void gunze_connect(struct serio *serio, struct serio_dev *dev) +static void gunze_connect(struct serio *serio, struct serio_driver *drv) { struct gunze *gunze; @@ -142,7 +144,7 @@ gunze->dev.id.product = 0x0051; gunze->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(gunze); return; } @@ -156,10 +158,14 @@ * The serio device structure. */ -static struct serio_dev gunze_dev = { - .interrupt = gunze_interrupt, - .connect = gunze_connect, - .disconnect = gunze_disconnect, +static struct serio_driver gunze_drv = { + .driver = { + .name = "gunze", + }, + .description = DRIVER_DESC, + .interrupt = gunze_interrupt, + .connect = gunze_connect, + .disconnect = gunze_disconnect, }; /* @@ -168,13 +174,13 @@ int __init gunze_init(void) { - serio_register_device(&gunze_dev); + serio_register_driver(&gunze_drv); return 0; } void __exit gunze_exit(void) { - serio_unregister_device(&gunze_dev); + serio_unregister_driver(&gunze_drv); } module_init(gunze_init); diff -Nru a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c --- a/drivers/input/touchscreen/h3600_ts_input.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/input/touchscreen/h3600_ts_input.c 2004-10-18 14:56:50 -07:00 @@ -45,8 +45,10 @@ #include #include +#define DRIVER_DESC "H3600 touchscreen driver" + MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION("H3600 touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -373,7 +375,7 @@ * new serio device. It looks whether it was registered as a H3600 touchscreen * and if yes, registers it as an input device. */ -static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) +static void h3600ts_connect(struct serio *serio, struct serio_driver *drv) { struct h3600_dev *ts; @@ -441,7 +443,7 @@ ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ ts->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); kfree(ts); @@ -478,10 +480,14 @@ * The serio device structure. */ -static struct serio_dev h3600ts_dev = { - .interrupt = h3600ts_interrupt, - .connect = h3600ts_connect, - .disconnect = h3600ts_disconnect, +static struct serio_driver h3600ts_drv = { + .driver = { + .name = "h3600ts", + }, + .description = DRIVER_DESC, + .interrupt = h3600ts_interrupt, + .connect = h3600ts_connect, + .disconnect = h3600ts_disconnect, }; /* @@ -490,13 +496,13 @@ static int __init h3600ts_init(void) { - serio_register_device(&h3600ts_dev); + serio_register_driver(&h3600ts_drv); return 0; } static void __exit h3600ts_exit(void) { - serio_unregister_device(&h3600ts_dev); + serio_unregister_driver(&h3600ts_drv); } module_init(h3600ts_init); diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c --- a/drivers/input/tsdev.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/input/tsdev.c 2004-10-18 14:57:04 -07:00 @@ -3,32 +3,42 @@ * * Copyright (c) 2001 "Crazy" james Simmons * - * Input driver to Touchscreen device driver module. + * Compaq touchscreen protocol driver. The protocol emulated by this driver + * is obsolete; for new programs use the tslib library which can read directly + * from evdev and perform dejittering, variance filtering and calibration - + * all in user space, not at kernel level. The meaning of this driver is + * to allow usage of newer input drivers with old applications that use the + * old /dev/h3600_ts and /dev/h3600_tsraw devices. * - * Sponsored by Transvirtual Technology + * 09-Apr-2004: Andrew Zabolotny + * Fixed to actually work, not just output random numbers. + * Added support for both h3600_ts and h3600_tsraw protocol + * emulation. */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to . + * e-mail - mail your message to . */ #define TSDEV_MINOR_BASE 128 #define TSDEV_MINORS 32 +/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ +#define TSDEV_MINOR_MASK 15 #define TSDEV_BUFFER_SIZE 64 #include @@ -52,48 +62,84 @@ #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 #endif +/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw + * devices. The first one must output X/Y data in 'cooked' format, e.g. + * filtered, dejittered and calibrated. Second device just outputs raw + * data received from the hardware. + * + * This driver doesn't support filtering and dejittering; it supports only + * calibration. Filtering and dejittering must be done in the low-level + * driver, if needed, because it may gain additional benefits from knowing + * the low-level details, the nature of noise and so on. + * + * The driver precomputes a calibration matrix given the initial xres and + * yres values (quite innacurate for most touchscreens) that will result + * in a more or less expected range of output values. The driver supports + * the TS_SET_CAL ioctl, which will replace the calibration matrix with a + * new one, supposedly generated from the values taken from the raw device. + */ + MODULE_AUTHOR("James Simmons "); MODULE_DESCRIPTION("Input driver to touchscreen converter"); MODULE_LICENSE("GPL"); static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; module_param(xres, uint, 0); -MODULE_PARM_DESC(xres, "Horizontal screen resolution"); +MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; module_param(yres, uint, 0); -MODULE_PARM_DESC(yres, "Vertical screen resolution"); +MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); + +/* From Compaq's Touch Screen Specification version 0.2 (draft) */ +struct ts_event { + short pressure; + short x; + short y; + short millisecs; +}; + +struct ts_calibration { + int xscale; + int xtrans; + int yscale; + int ytrans; + int xyswap; +}; struct tsdev { int exist; int open; int minor; - char name[16]; + char name[8]; wait_queue_head_t wait; struct list_head list; struct input_handle handle; + int x, y, pressure; + struct ts_calibration cal; }; -/* From Compaq's Touch Screen Specification version 0.2 (draft) */ -typedef struct { - short pressure; - short x; - short y; - short millisecs; -} TS_EVENT; - struct tsdev_list { struct fasync_struct *fasync; struct list_head node; struct tsdev *tsdev; int head, tail; - int oldx, oldy, pendown; - TS_EVENT event[TSDEV_BUFFER_SIZE]; + struct ts_event event[TSDEV_BUFFER_SIZE]; + int raw; }; +/* The following ioctl codes are defined ONLY for backward compatibility. + * Don't use tsdev for new developement; use the tslib library instead. + * Touchscreen calibration is a fully userspace task. + */ +/* Use 'f' as magic number */ +#define IOC_H3600_TS_MAGIC 'f' +#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) +#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) + static struct input_handler tsdev_handler; -static struct tsdev *tsdev_table[TSDEV_MINORS]; +static struct tsdev *tsdev_table[TSDEV_MINORS/2]; static int tsdev_fasync(int fd, struct file *file, int on) { @@ -109,13 +155,16 @@ int i = iminor(inode) - TSDEV_MINOR_BASE; struct tsdev_list *list; - if (i >= TSDEV_MINORS || !tsdev_table[i]) + if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) return -ENODEV; if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) return -ENOMEM; memset(list, 0, sizeof(struct tsdev_list)); + list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; + + i &= TSDEV_MINOR_MASK; list->tsdev = tsdev_table[i]; list_add_tail(&list->node, &tsdev_table[i]->list); file->private_data = list; @@ -161,7 +210,7 @@ return -EAGAIN; retval = wait_event_interruptible(list->tsdev->wait, - (list->head != list->tail) && list->tsdev->exist); + list->head != list->tail || !list->tsdev->exist); if (retval) return retval; @@ -169,11 +218,13 @@ if (!list->tsdev->exist) return -ENODEV; - while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) { - if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT))) + while (list->head != list->tail && + retval + sizeof (struct ts_event) <= count) { + if (copy_to_user (buffer + retval, list->event + list->tail, + sizeof (struct ts_event))) return -EFAULT; list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); - retval += sizeof(TS_EVENT); + retval += sizeof (struct ts_event); } return retval; @@ -193,22 +244,27 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { -/* struct tsdev_list *list = file->private_data; - struct tsdev *evdev = list->tsdev; - struct input_dev *dev = tsdev->handle.dev; - int retval; - + struct tsdev *tsdev = list->tsdev; + int retval = 0; + switch (cmd) { - case HHEHE: - return 0; - case hjff: - return 0; - default: - return 0; + case TS_GET_CAL: + if (copy_to_user ((void __user *)arg, &tsdev->cal, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + case TS_SET_CAL: + if (copy_from_user (&tsdev->cal, (void __user *)arg, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + default: + retval = -EINVAL; + break; } -*/ - return -EINVAL; + + return retval; } struct file_operations tsdev_fops = { @@ -227,82 +283,85 @@ struct tsdev *tsdev = handle->private; struct tsdev_list *list; struct timeval time; - int size; - list_for_each_entry(list, &tsdev->list, node) { - switch (type) { - case EV_ABS: - switch (code) { - case ABS_X: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - if (size > 0) - list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size); - else - list->oldx = ((value - handle->dev->absmin[ABS_X])); - break; - case ABS_Y: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - if (size > 0) - list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size); - else - list->oldy = ((value - handle->dev->absmin[ABS_Y])); - break; - case ABS_PRESSURE: - list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ? - value - handle->dev->absmin[ABS_PRESSURE] : 0; - break; - } + switch (type) { + case EV_ABS: + switch (code) { + case ABS_X: + tsdev->x = value; + break; + case ABS_Y: + tsdev->y = value; break; + case ABS_PRESSURE: + if (value > handle->dev->absmax[ABS_PRESSURE]) + value = handle->dev->absmax[ABS_PRESSURE]; + value -= handle->dev->absmin[ABS_PRESSURE]; + if (value < 0) + value = 0; + tsdev->pressure = value; + break; + } + break; - case EV_REL: - switch (code) { - case REL_X: - if (!list->pendown) - return; - list->oldx += value; - if (list->oldx < 0) - list->oldx = 0; - else if (list->oldx > xres) - list->oldx = xres; + case EV_REL: + switch (code) { + case REL_X: + tsdev->x += value; + if (tsdev->x < 0) + tsdev->x = 0; + else if (tsdev->x > xres) + tsdev->x = xres; + break; + case REL_Y: + tsdev->y += value; + if (tsdev->y < 0) + tsdev->y = 0; + else if (tsdev->y > yres) + tsdev->y = yres; + break; + } + break; + + case EV_KEY: + if (code == BTN_TOUCH || code == BTN_MOUSE) { + switch (value) { + case 0: + tsdev->pressure = 0; break; - case REL_Y: - if (!list->pendown) - return; - list->oldy += value; - if (list->oldy < 0) - list->oldy = 0; - else if (list->oldy > xres) - list->oldy = xres; + case 1: + if (!tsdev->pressure) + tsdev->pressure = 1; break; } - break; - - case EV_KEY: - if (code == BTN_TOUCH || code == BTN_MOUSE) { - switch (value) { - case 0: - list->pendown = 0; - break; - case 1: - if (!list->pendown) - list->pendown = 1; - break; - case 2: - return; - } - } else - return; - break; } + break; + } + + if (type != EV_SYN || code != SYN_REPORT) + return; + + list_for_each_entry(list, &tsdev->list, node) { + int x, y, tmp; + do_gettimeofday(&time); list->event[list->head].millisecs = time.tv_usec / 100; - list->event[list->head].pressure = list->pendown; - list->event[list->head].x = list->oldx; - list->event[list->head].y = list->oldy; + list->event[list->head].pressure = tsdev->pressure; + + x = tsdev->x; + y = tsdev->y; + + /* Calibration */ + if (!list->raw) { + x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; + y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; + if (tsdev->cal.xyswap) { + tmp = x; x = y; y = tmp; + } + } + + list->event[list->head].x = x; + list->event[list->head].y = y; list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } @@ -314,11 +373,11 @@ struct input_device_id *id) { struct tsdev *tsdev; - int minor; + int minor, delta; - for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor]; + for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; minor++); - if (minor == TSDEV_MINORS) { + if (minor >= TSDEV_MINORS/2) { printk(KERN_ERR "tsdev: You have way too many touchscreens\n"); return NULL; @@ -340,10 +399,25 @@ tsdev->handle.handler = handler; tsdev->handle.private = tsdev; + /* Precompute the rough calibration matrix */ + delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.xscale = (xres << 8) / delta; + tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); + + delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.yscale = (yres << 8) / delta; + tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); + tsdev_table[minor] = tsdev; - + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), + S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), dev->dev, "ts%d", minor); @@ -362,6 +436,7 @@ wake_up_interruptible(&tsdev->wait); } else tsdev_free(tsdev); + devfs_remove("input/tsraw%d", tsdev->minor); } static struct input_device_id tsdev_ids[] = { @@ -378,6 +453,12 @@ .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, },/* A tablet like device, at least touch detection, two absolute axes */ + + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT(EV_ABS) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, + },/* A tablet like device with several gradations of pressure */ {},/* Terminating entry */ }; diff -Nru a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c --- a/drivers/isdn/act2000/act2000_isa.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/isdn/act2000/act2000_isa.c 2004-10-18 14:56:29 -07:00 @@ -434,7 +434,10 @@ l = (length > 1024) ? 1024 : length; c = 0; b = buf; - copy_from_user(buf, p, l); + if (copy_from_user(buf, p, l)) { + kfree(buf); + return -EFAULT; + } while (c < l) { if (act2000_isa_writeb(card, *b++)) { printk(KERN_WARNING diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c --- a/drivers/isdn/capi/capi.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/capi/capi.c 2004-10-18 14:57:04 -07:00 @@ -436,51 +436,62 @@ struct sk_buff *nskb; int datalen; u16 errcode, datahandle; - + struct tty_ldisc *ld; + datalen = skb->len - CAPIMSG_LEN(skb->data); - if (mp->tty) { - if (mp->tty->ldisc.receive_buf == 0) { - printk(KERN_ERR "capi: ldisc has no receive_buf function\n"); - return -1; - } - if (mp->ttyinstop) { + if (mp->tty == NULL) + { +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: currently no receiver\n"); +#endif + return -1; + } + + ld = tty_ldisc_ref(mp->tty); + if (ld == NULL) + return -1; + if (ld->receive_buf == NULL) { #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: recv tty throttled\n"); + printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); #endif - return -1; - } - if (mp->tty->ldisc.receive_room && - mp->tty->ldisc.receive_room(mp->tty) < datalen) { + goto bad; + } + if (mp->ttyinstop) { #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: no room in tty\n"); + printk(KERN_DEBUG "capi: recv tty throttled\n"); #endif - return -1; - } - if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { - printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); - return -1; - } - datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); - errcode = capi20_put_message(mp->ap, nskb); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", - errcode); - kfree_skb(nskb); - return -1; - } - (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", - datahandle, skb->len); + goto bad; + } + if (ld->receive_room && + ld->receive_room(mp->tty) < datalen) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: no room in tty\n"); #endif - mp->tty->ldisc.receive_buf(mp->tty, skb->data, NULL, skb->len); - kfree_skb(skb); - return 0; - + goto bad; } + if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); + goto bad; + } + datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); + errcode = capi20_put_message(mp->ap, nskb); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", + errcode); + kfree_skb(nskb); + goto bad; + } + (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); #ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: currently no receiver\n"); + printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", + datahandle, skb->len); #endif + ld->receive_buf(mp->tty, skb->data, NULL, skb->len); + kfree_skb(skb); + tty_ldisc_deref(ld); + return 0; +bad: + tty_ldisc_deref(ld); return -1; } @@ -614,6 +625,7 @@ if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); #ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", @@ -633,10 +645,8 @@ #endif kfree_skb(skb); (void)capiminor_del_ack(mp, datahandle); - if (mp->tty) { - if (mp->tty->ldisc.write_wakeup) - mp->tty->ldisc.write_wakeup(mp->tty); - } + if (mp->tty) + tty_wakeup(mp->tty); (void)handle_minor_send(mp); } else { diff -Nru a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c --- a/drivers/isdn/capi/capidrv.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/isdn/capi/capidrv.c 2004-10-18 14:56:29 -07:00 @@ -512,7 +512,8 @@ len = CAPIMSG_LEN(cmsg->buf); skb = alloc_skb(len, GFP_ATOMIC); memcpy(skb_put(skb, len), cmsg->buf, len); - capi20_put_message(&global.ap, skb); + if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) + kfree_skb(skb); } /* -------- state machine -------------------------------------------- */ diff -Nru a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c --- a/drivers/isdn/hardware/avm/b1.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/isdn/hardware/avm/b1.c 2004-10-18 14:57:03 -07:00 @@ -389,7 +389,7 @@ CAPIMSG_NCCI(skb->data), CAPIMSG_MSGID(skb->data)); if (retval != CAPI_NOERROR) - goto out; + return retval; dlen = CAPIMSG_DATALEN(skb->data); @@ -399,16 +399,14 @@ b1_put_slice(port, skb->data + len, dlen); spin_unlock_irqrestore(&card->lock, flags); } else { - retval = CAPI_NOERROR; - spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_MESSAGE); b1_put_slice(port, skb->data, len); spin_unlock_irqrestore(&card->lock, flags); } - out: + dev_kfree_skb_any(skb); - return retval; + return CAPI_NOERROR; } /* ------------------------------------------------------------- */ diff -Nru a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c --- a/drivers/isdn/hardware/avm/b1dma.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/isdn/hardware/avm/b1dma.c 2004-10-18 14:56:48 -07:00 @@ -839,8 +839,6 @@ } if (retval == CAPI_NOERROR) b1dma_queue_tx(card, skb); - else - dev_kfree_skb_any(skb); return retval; } diff -Nru a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c --- a/drivers/isdn/hardware/avm/c4.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/isdn/hardware/avm/c4.c 2004-10-18 14:56:32 -07:00 @@ -1029,8 +1029,6 @@ spin_lock_irqsave(&card->lock, flags); c4_dispatch_tx(card); spin_unlock_irqrestore(&card->lock, flags); - } else { - dev_kfree_skb_any(skb); } return retval; } diff -Nru a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c --- a/drivers/isdn/hardware/avm/t1isa.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/isdn/hardware/avm/t1isa.c 2004-10-18 14:56:33 -07:00 @@ -472,7 +472,7 @@ CAPIMSG_NCCI(skb->data), CAPIMSG_MSGID(skb->data)); if (retval != CAPI_NOERROR) - goto out; + return retval; dlen = CAPIMSG_DATALEN(skb->data); @@ -482,16 +482,15 @@ t1_put_slice(port, skb->data + len, dlen); spin_unlock_irqrestore(&card->lock, flags); } else { - retval = CAPI_NOERROR; spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_MESSAGE); t1_put_slice(port, skb->data, len); spin_unlock_irqrestore(&card->lock, flags); } - out: + dev_kfree_skb_any(skb); - return retval; + return CAPI_NOERROR; } /* ------------------------------------------------------------- */ diff -Nru a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c --- a/drivers/isdn/hardware/eicon/capifunc.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/isdn/hardware/eicon/capifunc.c 2004-10-18 14:56:50 -07:00 @@ -1,4 +1,4 @@ -/* $Id: capifunc.c,v 1.61.4.2 2004/05/05 16:09:25 armin Exp $ +/* $Id: capifunc.c,v 1.61.4.5 2004/08/27 20:10:12 armin Exp $ * * ISDN interface module for Eicon active cards DIVA. * CAPI Interface common functions @@ -998,7 +998,8 @@ write_end: diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); - diva_os_free_message_buffer(dmb); + if (retval == CAPI_NOERROR) + diva_os_free_message_buffer(dmb); return retval; } diff -Nru a/drivers/isdn/hardware/eicon/capifunc.h b/drivers/isdn/hardware/eicon/capifunc.h --- a/drivers/isdn/hardware/eicon/capifunc.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/isdn/hardware/eicon/capifunc.h 2004-10-18 14:56:49 -07:00 @@ -1,4 +1,4 @@ -/* $Id: capifunc.h,v 1.11 2004/03/20 17:19:58 armin Exp $ +/* $Id: capifunc.h,v 1.11.4.1 2004/08/28 20:03:53 armin Exp $ * * ISDN interface module for Eicon active cards DIVA. * CAPI Interface common functions @@ -12,8 +12,6 @@ #ifndef __CAPIFUNC_H__ #define __CAPIFUNC_H__ - -#define MAX_DESCRIPTORS 32 #define DRRELMAJOR 2 #define DRRELMINOR 0 diff -Nru a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c --- a/drivers/isdn/hardware/eicon/debug.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/isdn/hardware/eicon/debug.c 2004-10-18 14:56:32 -07:00 @@ -5,6 +5,7 @@ #include "divasync.h" #include "kst_ifc.h" #include "maintidi.h" +#include "man_defs.h" /* LOCALS @@ -13,17 +14,23 @@ static void DI_register (void *arg); static void DI_deregister (pDbgHandle hDbg); -static void DI_format (int do_lock, word id, int type, char *format, va_list ap); +static void DI_format (int do_lock, word id, int type, char *format, va_list argument_list); static void DI_format_locked (word id, int type, char *format, va_list argument_list); static void DI_format_old (word id, char *format, va_list ap) { } -static void DiProcessEventLog (word id, dword msgID, va_list ap) { } +static void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap) { } static void single_p (byte * P, word * PLength, byte Id); static void diva_maint_xdi_cb (ENTITY* e); static word SuperTraceCreateReadReq (byte* P, const char* path); +static int diva_mnt_cmp_nmbr (const char* nmbr); +static void diva_free_dma_descriptor (IDI_CALL request, int nr); +static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic); void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...); static dword MaxDumpSize = 256 ; static dword MaxXlogSize = 2 + 128 ; +static char TraceFilter[DIVA_MAX_SELECTIVE_FILTER_LENGTH+1]; +static int TraceFilterIdent = -1; +static int TraceFilterChannel = -1; typedef struct _diva_maint_client { dword sec; @@ -40,9 +47,10 @@ BUFFERS XData; char xbuffer[2048+512]; byte* pmem; - int request_pending; + int request_pending; + int dma_handle; } diva_maint_client_t; -static diva_maint_client_t clients[64]; +static diva_maint_client_t clients[MAX_DESCRIPTORS]; static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask); @@ -201,6 +209,10 @@ return (-1); } + TraceFilter[0] = 0; + TraceFilterIdent = -1; + TraceFilterChannel = -1; + dbg_base = base; diva_os_get_time (&start_sec, &start_usec); @@ -249,7 +261,6 @@ return (-1); } - return (0); } @@ -302,16 +313,16 @@ diva_os_spin_lock_magic_t* old_irql) { diva_dbg_entry_head_t* pmsg = NULL; - diva_os_enter_spin_lock_hard (&dbg_q_lock, old_irql, "read"); + diva_os_enter_spin_lock (&dbg_q_lock, old_irql, "read"); if (dbg_q_busy) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_busy"); + diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_busy"); return NULL; } dbg_q_busy = 1; if (!(pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, size))) { dbg_q_busy = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_empty"); + diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_empty"); } return (pmsg); @@ -330,7 +341,7 @@ queueFreeMsg (dbg_queue); } dbg_q_busy = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_ack"); + diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_ack"); } @@ -378,14 +389,14 @@ return ; } - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register"); for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) { if (clients[id].hDbg == hDbg) { /* driver already registered */ - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); return; } if (clients[id].hDbg) { /* slot is busy */ @@ -468,7 +479,7 @@ } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); } static void DI_deregister (pDbgHandle hDbg) { @@ -480,8 +491,8 @@ diva_os_get_time (&sec, &usec); - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "read"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read"); for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { if (clients[i].hDbg == hDbg) { @@ -543,8 +554,8 @@ } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "read_ack"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read_ack"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack"); if (pmem) { diva_os_free (0, pmem); @@ -572,13 +583,22 @@ char *data; unsigned short code; - if (!format) + if (diva_os_in_irq()) { + dbg_sequence++; return; + } + + if ((!format) || + ((TraceFilter[0] != 0) && ((TraceFilterIdent < 0) || (TraceFilterChannel < 0)))) { + return; + } + + diva_os_get_time (&sec, &usec); if (do_lock) { - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "format"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "format"); } switch (type) { @@ -703,7 +723,7 @@ } if (do_lock) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "format"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "format"); } } @@ -720,7 +740,7 @@ return (-1); } - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info"); if (clients[id].hDbg) { *p++ = 1; @@ -757,7 +777,7 @@ } *p++ = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info"); return (p - data); } @@ -769,7 +789,7 @@ if (!data || !id || (id >= (sizeof(clients)/sizeof(clients[0])))) { return (-1); } - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info"); if (clients[id].hDbg) { ret = 4; @@ -779,7 +799,7 @@ *data++= (byte)(clients[id].hDbg->dbgMask >> 24); } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info"); return (ret); } @@ -793,8 +813,8 @@ return (-1); } - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "dbg mask"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "dbg mask"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "dbg mask"); if (clients[id].hDbg) { dword old_mask = clients[id].hDbg->dbgMask; @@ -806,14 +826,14 @@ } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "dbg mask"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "dbg mask"); if (clients[id].request_pending) { clients[id].request_pending = 0; (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib)); } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "dbg mask"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); return (ret); } @@ -851,12 +871,12 @@ diva_os_get_time (&sec, &usec); diva_get_idi_adapter_info (d->request, &serial, &logical); if (serial & 0xff000000) { - sprintf (tmp, "ADAPTER:%d SN:%d-%d", + sprintf (tmp, "ADAPTER:%d SN:%u-%d", (int)logical, serial & 0x00ffffff, (byte)(((serial & 0xff000000) >> 24) + 1)); } else { - sprintf (tmp, "ADAPTER:%d SN:%d", (int)logical, serial); + sprintf (tmp, "ADAPTER:%d SN:%u", (int)logical, serial); } if (!(pmem = diva_os_malloc (0, DivaSTraceGetMemotyRequirement (d->channels)))) { @@ -864,13 +884,14 @@ } memset (pmem, 0x00, DivaSTraceGetMemotyRequirement (d->channels)); - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register"); for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) { if (clients[id].hDbg && (clients[id].request == d->request)) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_free(0, pmem); return; } if (clients[id].hDbg) { /* slot is busy */ @@ -891,8 +912,8 @@ } if (free_id < 0) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); diva_os_free (0, pmem); return; } @@ -908,6 +929,7 @@ clients[id].Dbg.drvTag[0] = 0; clients[id].logical = (int)logical; clients[id].channels = (int)d->channels; + clients[id].dma_handle = -1; clients[id].Dbg.dbgMask = 0; clients[id].dbgMask = clients[id].Dbg.dbgMask; @@ -949,8 +971,8 @@ clients[id].request = NULL; clients[id].request_pending = 0; clients[id].hDbg = NULL; - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); diva_os_free (0, pmem); return; } @@ -988,14 +1010,14 @@ org_mask = clients[id].Dbg.dbgMask; clients[id].Dbg.dbgMask = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); if (clients[id].request_pending) { clients[id].request_pending = 0; (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib)); } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); diva_set_driver_dbg_mask (id, org_mask); } @@ -1012,8 +1034,8 @@ diva_os_get_time (&sec, &usec); - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "read"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read"); for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { if (clients[i].hDbg && (clients[i].request == d->request)) { @@ -1030,8 +1052,15 @@ } clients[i].hDbg = NULL; - clients[i].request = NULL; clients[i].request_pending = 0; + if (clients[i].dma_handle >= 0) { + /* + Free DMA handle + */ + diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle); + clients[i].dma_handle = -1; + } + clients[i].request = NULL; /* Log driver register, MAINT driver ID is '0' @@ -1069,8 +1098,8 @@ } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "read_ack"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read_ack"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack"); if (pmem) { diva_os_free (0, pmem); @@ -1142,6 +1171,42 @@ if (pC && pC->pIdiLib && pC->request) { ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib); + IDI_SYNC_REQ* preq; + char buffer[((sizeof(preq->xdi_extended_features)+4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features)+4) : sizeof(ENTITY)]; + char features[4]; + word assign_data_length = 1; + + features[0] = 0; + pC->xbuffer[0] = 0; + preq = (IDI_SYNC_REQ*)&buffer[0]; + preq->xdi_extended_features.Req = 0; + preq->xdi_extended_features.Rc = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES; + preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features); + preq->xdi_extended_features.info.features = &features[0]; + + (*(pC->request))((ENTITY*)preq); + + if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) && + (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) { + dword rx_dma_magic; + if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) { + pC->xbuffer[0] = LLI; + pC->xbuffer[1] = 8; + pC->xbuffer[2] = 0x40; + pC->xbuffer[3] = (byte)pC->dma_handle; + pC->xbuffer[4] = (byte)rx_dma_magic; + pC->xbuffer[5] = (byte)(rx_dma_magic >> 8); + pC->xbuffer[6] = (byte)(rx_dma_magic >> 16); + pC->xbuffer[7] = (byte)(rx_dma_magic >> 24); + pC->xbuffer[8] = (byte)DIVA_MAX_MANAGEMENT_TRANSFER_SIZE; + pC->xbuffer[9] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE >> 8); + pC->xbuffer[10] = 0; + + assign_data_length = 11; + } + } else { + pC->dma_handle = -1; + } e->Id = MAN_ID; e->callback = diva_maint_xdi_cb; @@ -1149,9 +1214,8 @@ e->X = &pC->XData; e->Req = ASSIGN; e->ReqCh = 0; - e->X->PLength = 1; + e->X->PLength = assign_data_length; e->X->P = (byte*)&pC->xbuffer[0]; - pC->xbuffer[0] = 0; pC->request_pending = 1; @@ -1300,16 +1364,25 @@ diva_os_spin_lock_magic_t old_irql, old_irql1; - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "xdi_cb"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "xdi_cb"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb"); pC = (diva_maint_client_t*)pLib->hAdapter; - if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) { - diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error"); + if ((e->complete == 255) || (pC->dma_handle < 0)) { + if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) { + diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error"); + } + } else { + /* + Process combined management interface indication + */ + if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) { + diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error (DMA mode)"); + } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "xdi_cb"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb"); if (pC->request_pending) { @@ -1317,7 +1390,7 @@ (*(pC->request))(e); } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "xdi_cb"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb"); } @@ -1365,8 +1438,42 @@ } switch (notify_subject) { - case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: - if (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS) { + case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: { + int view = (TraceFilter[0] == 0); + /* + Process selective Trace + */ + if (channel->Line[0] == 'I' && channel->Line[1] == 'd' && + channel->Line[2] == 'l' && channel->Line[3] == 'e') { + if ((TraceFilterIdent == pC->hDbg->id) && (TraceFilterChannel == (int)channel->ChannelNumber)) { + (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 0); + (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 0); + diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace OFF for Ch=%d", + (int)channel->ChannelNumber); + TraceFilterIdent = -1; + TraceFilterChannel = -1; + view = 1; + } + } else if (TraceFilter[0] && (TraceFilterIdent < 0) && !(diva_mnt_cmp_nmbr (&channel->RemoteAddress[0]) && + diva_mnt_cmp_nmbr (&channel->LocalAddress[0]))) { + + if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0) { /* Activate B-channel trace */ + (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 1); + } + if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0) { /* Activate AudioTap Trace */ + (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 1); + } + + TraceFilterIdent = pC->hDbg->id; + TraceFilterChannel = (int)channel->ChannelNumber; + + if (TraceFilterIdent >= 0) { + diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace ON for Ch=%d", + (int)channel->ChannelNumber); + view = 1; + } + } + if (view && (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS)) { diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Ch = %d", (int)channel->ChannelNumber); diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Status = <%s>", &channel->Line[0]); @@ -1392,10 +1499,26 @@ channel->LastDisconnecCause); diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Owner = <%s>", &channel->UserID[0]); } - break; + + } break; case DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE: if (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_PROGRESS) { + { + int ch = TraceFilterChannel; + int id = TraceFilterIdent; + + if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { + if (ch != (int)modem->ChannelNumber) { + break; + } + } else if (TraceFilter[0] != 0) { + break; + } + } + + diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Ch = %lu", (int)modem->ChannelNumber); diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Event = %lu", modem->Event); @@ -1428,6 +1551,20 @@ case DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE: if (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_PROGRESS) { + { + int ch = TraceFilterChannel; + int id = TraceFilterIdent; + + if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { + if (ch != (int)fax->ChannelNumber) { + break; + } + } else if (TraceFilter[0] != 0) { + break; + } + } + diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Ch = %lu",(int)fax->ChannelNumber); diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Event = %lu", fax->Event); diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pages = %lu", fax->Page_Counter); @@ -1660,6 +1797,52 @@ diva_dbg_entry_head_t* pmsg; word size; dword sec, usec; + int ch = TraceFilterChannel; + int id = TraceFilterIdent; + + /* + Selective trace + */ + if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { + const char* p = NULL; + int ch_value = -1; + MI_XLOG_HDR *TrcData = (MI_XLOG_HDR *)xlog_buffer; + + if (Adapter != clients[id].logical) { + return; /* Ignore all trace messages from other adapters */ + } + + if (TrcData->code == 24) { + p = (char*)&TrcData->code; + p += 2; + } + + /* + All L1 messages start as [dsp,ch], so we can filter this information + and filter out all messages that use different channel + */ + if (p && p[0] == '[') { + if (p[2] == ',') { + p += 3; + ch_value = *p - '0'; + } else if (p[3] == ',') { + p += 4; + ch_value = *p - '0'; + } + if (ch_value >= 0) { + if (p[2] == ']') { + ch_value = ch_value * 10 + p[1] - '0'; + } + if (ch_value != ch) { + return; /* Ignore other channels */ + } + } + } + + } else if (TraceFilter[0] != 0) { + return; /* Ignore trace if trace filter is activated, but idle */ + } diva_os_get_time (&sec, &usec); @@ -1705,18 +1888,20 @@ (*(pC->pIdiLib->DivaSTraceSetDChannel))(pC->pIdiLib, (pC->hDbg->dbgMask & DIVA_MGT_DBG_DCHAN) != 0); } - if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) { - int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0); + if (!TraceFilter[0]) { + if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) { + int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0); - for (i = 0; i < pC->channels; i++) { - (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i+1, state); + for (i = 0; i < pC->channels; i++) { + (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i+1, state); + } } - } - if (changed & DIVA_MGT_DBG_IFC_AUDIO) { - int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0); + if (changed & DIVA_MGT_DBG_IFC_AUDIO) { + int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0); - for (i = 0; i < pC->channels; i++) { - (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i+1, state); + for (i = 0; i < pC->channels; i++) { + (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i+1, state); + } } } } @@ -1743,8 +1928,8 @@ for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { pmem = NULL; - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "unload"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "unload"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "unload"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "unload"); if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) { if ((*(clients[i].pIdiLib->DivaSTraceLibraryStop))(clients[i].pIdiLib) == 1) { @@ -1759,19 +1944,31 @@ clients[i].pmem = NULL; } clients[i].hDbg = NULL; - clients[i].request = NULL; clients[i].request_pending = 0; + + if (clients[i].dma_handle >= 0) { + /* + Free DMA handle + */ + diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle); + clients[i].dma_handle = -1; + } + clients[i].request = NULL; } else { fret = -1; } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "unload"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "unload"); if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) { clients[i].request_pending = 0; (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib)); + if (clients[i].dma_handle >= 0) { + diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle); + clients[i].dma_handle = -1; + } } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "unload"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "unload"); if (pmem) { diva_os_free (0, pmem); @@ -1779,5 +1976,158 @@ } return (fret); +} + +/* + Set/Read the trace filter used for selective tracing. + Affects B- and Audio Tap trace mask at run time + */ +int diva_set_trace_filter (int filter_length, const char* filter) { + diva_os_spin_lock_magic_t old_irql, old_irql1; + int i, ch, on, client_b_on, client_atap_on; + + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + + if (filter_length <= DIVA_MAX_SELECTIVE_FILTER_LENGTH) { + memcpy (&TraceFilter[0], filter, filter_length); + if (TraceFilter[filter_length]) { + TraceFilter[filter_length] = 0; + } + if (TraceFilter[0] == '*') { + TraceFilter[0] = 0; + } + } else { + filter_length = -1; + } + + TraceFilterIdent = -1; + TraceFilterChannel = -1; + + on = (TraceFilter[0] == 0); + + for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) { + client_b_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0); + client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0); + for (ch = 0; ch < clients[i].channels; ch++) { + (*(clients[i].pIdiLib->DivaSTraceSetBChannel))(clients[i].pIdiLib->hLib, ch+1, client_b_on); + (*(clients[i].pIdiLib->DivaSTraceSetAudioTap))(clients[i].pIdiLib->hLib, ch+1, client_atap_on); + } + } + } + + for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) { + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + clients[i].request_pending = 0; + (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib)); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + } + } + + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); + + return (filter_length); +} + +int diva_get_trace_filter (int max_length, char* filter) { + diva_os_spin_lock_magic_t old_irql; + int len; + + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read_filter"); + len = strlen (&TraceFilter[0]) + 1; + if (max_length >= len) { + memcpy (filter, &TraceFilter[0], len); + } + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_filter"); + + return (len); +} + +static int diva_dbg_cmp_key (const char* ref, const char* key) { + while (*key && (*ref++ == *key++)); + return (!*key && !*ref); +} + +/* + In case trace filter starts with "C" character then + all following characters are interpreted as command. + Followings commands are available: + - single, trace single call at time, independent from CPN/CiPN + */ +static int diva_mnt_cmp_nmbr (const char* nmbr) { + const char* ref = &TraceFilter[0]; + int ref_len = strlen(&TraceFilter[0]), nmbr_len = strlen(nmbr); + + if (ref[0] == 'C') { + if (diva_dbg_cmp_key (&ref[1], "single")) { + return (0); + } + return (-1); + } + + if (!ref_len || (ref_len > nmbr_len)) { + return (-1); + } + + nmbr = nmbr + nmbr_len - 1; + ref = ref + ref_len - 1; + + while (ref_len--) { + if (*nmbr-- != *ref--) { + return (-1); + } + } + + return (0); +} + +static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic) { + ENTITY e; + IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e; + + if (!request) { + return (-1); + } + + pReq->xdi_dma_descriptor_operation.Req = 0; + pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION; + + pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC; + pReq->xdi_dma_descriptor_operation.info.descriptor_number = -1; + pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; + pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; + + (*request)((ENTITY*)pReq); + + if (!pReq->xdi_dma_descriptor_operation.info.operation && + (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) && + pReq->xdi_dma_descriptor_operation.info.descriptor_magic) { + *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic; + return (pReq->xdi_dma_descriptor_operation.info.descriptor_number); + } else { + return (-1); + } +} + +static void diva_free_dma_descriptor (IDI_CALL request, int nr) { + ENTITY e; + IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e; + + if (!request || (nr < 0)) { + return; + } + + pReq->xdi_dma_descriptor_operation.Req = 0; + pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION; + + pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE; + pReq->xdi_dma_descriptor_operation.info.descriptor_number = nr; + pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; + pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; + + (*request)((ENTITY*)pReq); } diff -Nru a/drivers/isdn/hardware/eicon/debug_if.h b/drivers/isdn/hardware/eicon/debug_if.h --- a/drivers/isdn/hardware/eicon/debug_if.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/hardware/eicon/debug_if.h 2004-10-18 14:57:04 -07:00 @@ -57,12 +57,18 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d); int diva_mnt_shutdown_xdi_adapters (void); +#define DIVA_MAX_SELECTIVE_FILTER_LENGTH 127 +int diva_set_trace_filter (int filter_length, const char* filter); +int diva_get_trace_filter (int max_length, char* filter); + #define DITRACE_CMD_GET_DRIVER_INFO 1 #define DITRACE_READ_DRIVER_DBG_MASK 2 #define DITRACE_WRITE_DRIVER_DBG_MASK 3 #define DITRACE_READ_TRACE_ENTRY 4 #define DITRACE_READ_TRACE_ENTRYS 5 +#define DITRACE_WRITE_SELECTIVE_TRACE_FILTER 6 +#define DITRACE_READ_SELECTIVE_TRACE_FILTER 7 /* Trace lavels for debug via management interface diff -Nru a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h --- a/drivers/isdn/hardware/eicon/debuglib.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/hardware/eicon/debuglib.h 2004-10-18 14:57:04 -07:00 @@ -232,7 +232,7 @@ typedef void ( * DbgEnd) (pDbgHandle) ; typedef void ( * DbgLog) (unsigned short, int, char *, va_list) ; typedef void ( * DbgOld) (unsigned short, char *, va_list) ; -typedef void ( * DbgEv) (unsigned short, unsigned int, va_list) ; +typedef void ( * DbgEv) (unsigned short, unsigned long, va_list) ; typedef void ( * DbgIrq) (unsigned short, int, char *, va_list) ; typedef struct _DbgHandle_ { char Registered ; /* driver successfull registered */ @@ -259,7 +259,7 @@ void *pReserved3 ; } _DbgHandle_ ; extern _DbgHandle_ myDriverDebugHandle ; -typedef struct +typedef struct _OldDbgHandle_ { struct _OldDbgHandle_ *next ; void *pIrp ; long regTime[2] ; @@ -310,7 +310,7 @@ unsigned long B_ChannelMask; unsigned long LogBufferSize; } CardTrace; - } u1; + }Data; } _DbgExtendedInfo_; #ifndef DIVA_NO_DEBUGLIB /* ------------------------------------------------------------- diff -Nru a/drivers/isdn/hardware/eicon/diddfunc.c b/drivers/isdn/hardware/eicon/diddfunc.c --- a/drivers/isdn/hardware/eicon/diddfunc.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/hardware/eicon/diddfunc.c 2004-10-18 14:57:04 -07:00 @@ -1,4 +1,4 @@ -/* $Id: diddfunc.c,v 1.14 2003/08/25 10:06:37 schindler Exp $ +/* $Id: diddfunc.c,v 1.14.6.2 2004/08/28 20:03:53 armin Exp $ * * DIDD Interface module for Eicon active cards. * @@ -15,8 +15,6 @@ #include "di_defs.h" #include "dadapter.h" #include "divasync.h" - -#define MAX_DESCRIPTORS 32 #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) diff -Nru a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c --- a/drivers/isdn/hardware/eicon/diva_didd.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/isdn/hardware/eicon/diva_didd.c 2004-10-18 14:56:33 -07:00 @@ -1,4 +1,4 @@ -/* $Id: diva_didd.c,v 1.13 2003/08/27 10:11:21 schindler Exp $ +/* $Id: diva_didd.c,v 1.13.6.1 2004/08/28 20:03:53 armin Exp $ * * DIDD Interface module for Eicon active cards. * @@ -23,7 +23,7 @@ #include "divasync.h" #include "did_vers.h" -static char *main_revision = "$Revision: 1.13 $"; +static char *main_revision = "$Revision: 1.13.6.1 $"; static char *DRIVERNAME = "Eicon DIVA - DIDD table (http://www.melware.net)"; @@ -37,8 +37,6 @@ MODULE_SUPPORTED_DEVICE("Eicon diva drivers"); MODULE_LICENSE("GPL"); -#define MAX_DESCRIPTORS 32 - #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) @@ -50,8 +48,8 @@ static struct proc_dir_entry *proc_didd; struct proc_dir_entry *proc_net_eicon = NULL; -EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); -EXPORT_SYMBOL_NOVERS(proc_net_eicon); +EXPORT_SYMBOL(DIVA_DIDD_Read); +EXPORT_SYMBOL(proc_net_eicon); static char *getrev(const char *revision) { diff -Nru a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c --- a/drivers/isdn/hardware/eicon/divamnt.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/isdn/hardware/eicon/divamnt.c 2004-10-18 14:56:32 -07:00 @@ -1,4 +1,4 @@ -/* $Id: divamnt.c,v 1.32 2004/01/15 09:48:13 armin Exp $ +/* $Id: divamnt.c,v 1.32.6.5 2004/08/28 20:03:53 armin Exp $ * * Driver for Eicon DIVA Server ISDN cards. * Maint module @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include "platform.h" @@ -26,7 +24,7 @@ #include "divasync.h" #include "debug_if.h" -static char *main_revision = "$Revision: 1.32 $"; +static char *main_revision = "$Revision: 1.32.6.5 $"; static int major; @@ -47,8 +45,7 @@ char *DRIVERRELEASE_MNT = "2.0"; static wait_queue_head_t msgwaitq; -static DECLARE_MUTEX(opened_sem); -static int opened; +static unsigned long opened; static struct timeval start_time; extern int mntfunc_init(int *, void **, unsigned long); @@ -74,20 +71,6 @@ } /* - * buffer alloc - */ -void *diva_os_malloc_tbuffer(unsigned long flags, unsigned long size) -{ - return (kmalloc(size, GFP_KERNEL)); -} -void diva_os_free_tbuffer(unsigned long flags, void *ptr) -{ - if (ptr) { - kfree(ptr); - } -} - -/* * kernel/user space copy functions */ int diva_os_copy_to_user(void *os_handle, void __user *dst, const void *src, @@ -131,154 +114,8 @@ } /* - * /proc entries + * device node operations */ - -extern struct proc_dir_entry *proc_net_eicon; -static struct proc_dir_entry *maint_proc_entry = NULL; - -/* - Read function is provided for compatibility reason - this allows - to read unstructured traces, formated as ascii string only - */ -static ssize_t -maint_read(struct file *file, char __user *buf, size_t count, loff_t * off) -{ - diva_dbg_entry_head_t *pmsg = NULL; - diva_os_spin_lock_magic_t old_irql; - word size; - char *pstr, *dli_label = "UNK"; - int str_length; - int *str_msg; - - if (!file->private_data) { - for (;;) { - while ( - (pmsg = - diva_maint_get_message(&size, - &old_irql))) { - if (!(pmsg->facility == MSG_TYPE_STRING)) { - diva_maint_ack_message(1, - &old_irql); - } else { - break; - } - } - - if (!pmsg) { - if (file->f_flags & O_NONBLOCK) { - return (-EAGAIN); - } - interruptible_sleep_on(&msgwaitq); - if (signal_pending(current)) { - return (-ERESTARTSYS); - } - } else { - break; - } - } - /* - The length of message that shoule be read is: - pmsg->data_length + label(25) + DrvID(2) + byte CR + trailing zero - */ - if (! - (str_msg = - (int *) diva_os_malloc_tbuffer(0, - pmsg->data_length + - 29 + 2 * sizeof(int)))) { - diva_maint_ack_message(0, &old_irql); - return (-ENOMEM); - } - pstr = (char *) &str_msg[2]; - - switch (pmsg->dli) { - case DLI_LOG: - dli_label = "LOG"; - break; - case DLI_FTL: - dli_label = "FTL"; - break; - case DLI_ERR: - dli_label = "ERR"; - break; - case DLI_TRC: - dli_label = "TRC"; - break; - case DLI_REG: - dli_label = "REG"; - break; - case DLI_MEM: - dli_label = "MEM"; - break; - case DLI_SPL: - dli_label = "SPL"; - break; - case DLI_IRP: - dli_label = "IRP"; - break; - case DLI_TIM: - dli_label = "TIM"; - break; - case DLI_TAPI: - dli_label = "TAPI"; - break; - case DLI_NDIS: - dli_label = "NDIS"; - break; - case DLI_CONN: - dli_label = "CONN"; - break; - case DLI_STAT: - dli_label = "STAT"; - break; - case DLI_PRV0: - dli_label = "PRV0"; - break; - case DLI_PRV1: - dli_label = "PRV1"; - break; - case DLI_PRV2: - dli_label = "PRV2"; - break; - case DLI_PRV3: - dli_label = "PRV3"; - break; - } - str_length = sprintf(pstr, "%s %02x %s\n", - dli_label, (byte) pmsg->drv_id, - (char *) &pmsg[1]); - str_msg[0] = str_length; - str_msg[1] = 0; - file->private_data = str_msg; - diva_maint_ack_message(1, &old_irql); - } else { - str_msg = (int *) file->private_data; - pstr = (char *) &str_msg[2]; - pstr += str_msg[1]; /* head + offset */ - str_length = str_msg[0] - str_msg[1]; /* length - offset */ - } - str_length = MIN(str_length, count); - - if (diva_os_copy_to_user(NULL, buf, pstr, str_length)) { - diva_os_free_tbuffer(0, str_msg); - file->private_data = NULL; - return (-EFAULT); - } - str_msg[1] += str_length; - if ((str_msg[0] - str_msg[1]) <= 0) { - diva_os_free_tbuffer(0, str_msg); - file->private_data = NULL; - } - - return (str_length); -} - -static ssize_t -maint_write(struct file *file, const char __user *buf, size_t count, loff_t * off) -{ - return (-ENODEV); -} - static unsigned int maint_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; @@ -293,13 +130,10 @@ static int maint_open(struct inode *ino, struct file *filep) { - down(&opened_sem); - if (opened) { - up(&opened_sem); + /* only one open is allowed, so we test + it atomically */ + if (test_and_set_bit(0, &opened)) return (-EBUSY); - } - opened++; - up(&opened_sem); filep->private_data = NULL; @@ -309,54 +143,16 @@ static int maint_close(struct inode *ino, struct file *filep) { if (filep->private_data) { - diva_os_free_tbuffer(0, filep->private_data); + diva_os_free(0, filep->private_data); filep->private_data = NULL; } - down(&opened_sem); - opened--; - up(&opened_sem); + /* clear 'used' flag */ + clear_bit(0, &opened); + return (0); } -/* - * fops - */ -static struct file_operations maint_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = maint_read, - .write = maint_write, - .poll = maint_poll, - .open = maint_open, - .release = maint_close -}; - -static int DIVA_INIT_FUNCTION create_maint_proc(void) -{ - maint_proc_entry = - create_proc_entry("maint", S_IFREG | S_IRUGO | S_IWUSR, - proc_net_eicon); - if (!maint_proc_entry) - return (0); - - maint_proc_entry->proc_fops = &maint_fops; - maint_proc_entry->owner = THIS_MODULE; - - return (1); -} - -static void remove_maint_proc(void) -{ - if (maint_proc_entry) { - remove_proc_entry("maint", proc_net_eicon); - maint_proc_entry = NULL; - } -} - -/* - * device node operations - */ static ssize_t divas_maint_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { @@ -427,18 +223,10 @@ ret = -EIO; goto out; } - if (!create_maint_proc()) { - printk(KERN_ERR "%s: failed to create proc entry.\n", - DRIVERLNAME); - divas_maint_unregister_chrdev(); - ret = -EIO; - goto out; - } if (!(mntfunc_init(&buffer_length, &buffer, diva_dbg_mem))) { printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME); - remove_maint_proc(); divas_maint_unregister_chrdev(); ret = -EIO; goto out; @@ -457,7 +245,6 @@ */ static void DIVA_EXIT_FUNCTION maint_exit(void) { - remove_maint_proc(); divas_maint_unregister_chrdev(); mntfunc_finit(); @@ -466,3 +253,4 @@ module_init(maint_init); module_exit(maint_exit); + diff -Nru a/drivers/isdn/hardware/eicon/divasfunc.c b/drivers/isdn/hardware/eicon/divasfunc.c --- a/drivers/isdn/hardware/eicon/divasfunc.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/isdn/hardware/eicon/divasfunc.c 2004-10-18 14:56:32 -07:00 @@ -1,4 +1,4 @@ -/* $Id: divasfunc.c,v 1.23 2004/04/08 01:17:57 armin Exp $ +/* $Id: divasfunc.c,v 1.23.4.2 2004/08/28 20:03:53 armin Exp $ * * Low level driver for Eicon DIVA Server ISDN cards. * @@ -27,8 +27,6 @@ extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; -#define MAX_DESCRIPTORS 32 - extern char *DRIVERRELEASE_DIVAS; static dword notify_handle; @@ -76,10 +74,10 @@ d.features = IoAdapters[card - 1]->Properties.Features; DBG_TRC(("DIDD register A(%d) channels=%d", card, d.channels)) - /* workaround for different Name in structure */ - strlcpy(IoAdapters[card - 1]->Name, - IoAdapters[card - 1]->Properties.Name, - sizeof(IoAdapters[card - 1]->Name)); + /* workaround for different Name in structure */ + strlcpy(IoAdapters[card - 1]->Name, + IoAdapters[card - 1]->Properties.Name, + sizeof(IoAdapters[card - 1]->Name)); req.didd_remove_adapter.e.Req = 0; req.didd_add_adapter.e.Rc = IDI_SYNC_REQ_DIDD_ADD_ADAPTER; req.didd_add_adapter.info.descriptor = (void *) &d; diff -Nru a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h --- a/drivers/isdn/hardware/eicon/divasync.h 2004-10-18 14:56:20 -07:00 +++ b/drivers/isdn/hardware/eicon/divasync.h 2004-10-18 14:56:20 -07:00 @@ -31,33 +31,31 @@ #define IDI_SYNC_REQ_SET_POSTCALL 0x03 #define IDI_SYNC_REQ_GET_XLOG 0x04 #define IDI_SYNC_REQ_GET_FEATURES 0x05 -/* Added for DIVA USB support */ #define IDI_SYNC_REQ_USB_REGISTER 0x06 #define IDI_SYNC_REQ_USB_RELEASE 0x07 #define IDI_SYNC_REQ_USB_ADD_DEVICE 0x08 #define IDI_SYNC_REQ_USB_START_DEVICE 0x09 #define IDI_SYNC_REQ_USB_STOP_DEVICE 0x0A #define IDI_SYNC_REQ_USB_REMOVE_DEVICE 0x0B -/* Added for Diva Server Monitor */ #define IDI_SYNC_REQ_GET_CARDTYPE 0x0C #define IDI_SYNC_REQ_GET_DBG_XLOG 0x0D -#define IDI_SYNC_REQ_GET_LINE_IDX 0x0E #define DIVA_USB #define DIVA_USB_REQ 0xAC #define DIVA_USB_TEST 0xAB #define DIVA_USB_ADD_ADAPTER 0xAC #define DIVA_USB_REMOVE_ADAPTER 0xAD -/******************************************************************************/ #define IDI_SYNC_REQ_SERIAL_HOOK 0x80 #define IDI_SYNC_REQ_XCHANGE_STATUS 0x81 #define IDI_SYNC_REQ_USB_HOOK 0x82 #define IDI_SYNC_REQ_PORTDRV_HOOK 0x83 -#define IDI_SYNC_REQ_SLI (0x84) /* SLI request from 3signal modem drivers */ +#define IDI_SYNC_REQ_SLI 0x84 /* SLI request from 3signal modem drivers */ #define IDI_SYNC_REQ_RECONFIGURE 0x85 #define IDI_SYNC_REQ_RESET 0x86 +#define IDI_SYNC_REQ_GET_85X_DEVICE_DATA 0x87 #define IDI_SYNC_REQ_LOCK_85X 0x88 +#define IDI_SYNC_REQ_DIVA_85X_USB_DATA_EXCHANGE 0x99 +#define IDI_SYNC_REQ_DIPORT_EXCHANGE_REQ 0x98 #define IDI_SYNC_REQ_GET_85X_EXT_PORT_TYPE 0xA0 -#define IDI_SYNC_REQ_DIPORT_GET_85X_TX_CTRL_FN 0x98 /******************************************************************************/ #define IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES 0x92 /* @@ -87,6 +85,8 @@ #define DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS 0x08 #define DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC 0x10 #define DIVA_XDI_EXTENDED_FEATURE_RX_DMA 0x20 +#define DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA 0x40 +#define DIVA_XDI_EXTENDED_FEATURE_WIDE_ID 0x80 #define DIVA_XDI_EXTENDED_FEATURES_MAX_SZ 1 /******************************************************************************/ #define IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR 0x93 @@ -115,6 +115,7 @@ typedef struct _diva_xdi_get_logical_adapter_number { dword logical_adapter_number; dword controller; + dword total_controllers; } diva_xdi_get_logical_adapter_number_s_t; /******************************************************************************/ #define IDI_SYNC_REQ_UP1DM_OPERATION 0x96 @@ -134,6 +135,7 @@ #define IDI_SYNC_REQ_DIDD_ADD_ADAPTER 0x03 #define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER 0x04 #define IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY 0x05 +#define IDI_SYNC_REQ_DIDD_GET_CFG_LIB_IFC 0x10 typedef struct _diva_didd_adapter_notify { dword handle; /* Notification handle */ void * callback; @@ -149,6 +151,9 @@ void * buffer; dword length; } diva_didd_read_adapter_array_t; +typedef struct _diva_didd_get_cfg_lib_ifc { + void* ifc; +} diva_didd_get_cfg_lib_ifc_t; /******************************************************************************/ #define IDI_SYNC_REQ_XDI_GET_STREAM 0x91 #define DIVA_XDI_SYNCHRONOUS_SERVICE 0x01 @@ -466,6 +471,10 @@ ENTITY e; diva_didd_read_adapter_array_t info; } didd_read_adapter_array; + struct { + ENTITY e; + diva_didd_get_cfg_lib_ifc_t info; + } didd_get_cfg_lib_ifc; struct { unsigned char Req; unsigned char Rc; diff -Nru a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c --- a/drivers/isdn/hardware/eicon/idifunc.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/hardware/eicon/idifunc.c 2004-10-18 14:57:04 -07:00 @@ -1,4 +1,4 @@ -/* $Id: idifunc.c,v 1.14.4.2 2004/05/09 16:42:20 armin Exp $ +/* $Id: idifunc.c,v 1.14.4.4 2004/08/28 20:03:53 armin Exp $ * * Driver for Eicon DIVA Server ISDN cards. * User Mode IDI Interface @@ -24,8 +24,6 @@ extern void DIVA_DIDD_Read(void *, int); extern int diva_user_mode_idi_create_adapter(const DESCRIPTOR *, int); extern void diva_user_mode_idi_remove_adapter(int); - -#define MAX_DESCRIPTORS 32 static dword notify_handle; static DESCRIPTOR DAdapter; diff -Nru a/drivers/isdn/hardware/eicon/io.c b/drivers/isdn/hardware/eicon/io.c --- a/drivers/isdn/hardware/eicon/io.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/isdn/hardware/eicon/io.c 2004-10-18 14:56:27 -07:00 @@ -77,6 +77,7 @@ #if defined(DIVA_IDI_RX_DMA) DIVA_XDI_EXTENDED_FEATURE_CMA | DIVA_XDI_EXTENDED_FEATURE_RX_DMA | + DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA | #endif DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC), 0 @@ -226,8 +227,10 @@ if (pI->descriptor_number >= 0) { dword dma_magic; void* local_addr; +#if 0 DBG_TRC(("A(%d) dma_alloc(%d)", IoAdapter->ANum, pI->descriptor_number)) +#endif diva_get_dma_map_entry (\ (struct _diva_dma_map_entry*)IoAdapter->dma_map, pI->descriptor_number, @@ -240,7 +243,9 @@ } } else if ((pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE) && (pI->descriptor_number >= 0)) { +#if 0 DBG_TRC(("A(%d) dma_free(%d)", IoAdapter->ANum, pI->descriptor_number)) +#endif diva_free_dma_map_entry((struct _diva_dma_map_entry*)IoAdapter->dma_map, pI->descriptor_number); pI->descriptor_number = -1; @@ -257,6 +262,7 @@ &syncReq->xdi_logical_adapter_number.info; pI->logical_adapter_number = IoAdapter->ANum; pI->controller = IoAdapter->ControllerNumber; + pI->total_controllers = IoAdapter->Properties.Adapters; } return; case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: { diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info; @@ -318,6 +324,16 @@ } syncReq->GetSerial.serial = 0 ; break ; + case IDI_SYNC_REQ_GET_CARDTYPE: + if ( IoAdapter ) + { + syncReq->GetCardType.cardtype = IoAdapter->cardType ; + DBG_TRC(("xdi: Adapter %d / CardType %ld", + IoAdapter->ANum, IoAdapter->cardType)) + return ; + } + syncReq->GetCardType.cardtype = 0 ; + break ; case IDI_SYNC_REQ_GET_XLOG: if ( IoAdapter ) { @@ -326,6 +342,14 @@ } e->Ind = 0 ; break ; + case IDI_SYNC_REQ_GET_DBG_XLOG: + if ( IoAdapter ) + { + pcm_req (IoAdapter, e) ; + return ; + } + e->Ind = 0 ; + break ; case IDI_SYNC_REQ_GET_FEATURES: if ( IoAdapter ) { @@ -345,7 +369,9 @@ } if ( IoAdapter ) { +#if 0 DBG_FTL(("xdi: unknown Req 0 / Rc %d !", e->Rc)) +#endif return ; } } @@ -496,7 +522,7 @@ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &OldIrql, "data_pcm_1"); - IoAdapter->pcm_data = (unsigned long)pcm; + IoAdapter->pcm_data = (void *)pcm; IoAdapter->pcm_pending = 1; diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr); diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, @@ -510,7 +536,7 @@ &OldIrql, "data_pcm_3"); IoAdapter->pcm_pending = 0; - IoAdapter->pcm_data = 0; + IoAdapter->pcm_data = NULL ; diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &OldIrql, "data_pcm_3"); @@ -528,7 +554,7 @@ &OldIrql, "data_pcm_4"); IoAdapter->pcm_pending = 0; - IoAdapter->pcm_data = 0; + IoAdapter->pcm_data = NULL ; diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &OldIrql, "data_pcm_4"); @@ -668,7 +694,7 @@ void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len) { byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); - byte* P = (byte*)buffer; + byte* P = (byte*)buffer; if ((long)adr & 1) { outppw(Port+4, (word)(unsigned long)adr); *P = inpp(Port); @@ -678,7 +704,7 @@ if (!len) { DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); return; - } + } } outppw(Port+4, (word)(unsigned long)adr); inppw_buffer (Port, P, len+1); @@ -710,7 +736,7 @@ void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len) { byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); - byte* P = (byte*)buffer; + byte* P = (byte*)buffer; if ((long)adr & 1) { outppw(Port+4, (word)(unsigned long)adr); outpp(Port, *P); @@ -839,21 +865,21 @@ /* -------------------------------------------------------------------------- routines for aligned reading and writing on RISC -------------------------------------------------------------------------- */ -void outp_words_from_buffer (word* adr, byte* P, word len) +void outp_words_from_buffer (word* adr, byte* P, dword len) { - word i = 0; + dword i = 0; word w; - while (i < (len & 0xfffe)) { + while (i < (len & 0xfffffffe)) { w = P[i++]; w += (P[i++])<<8; outppw (adr, w); } } -void inp_words_to_buffer (word* adr, byte* P, word len) +void inp_words_to_buffer (word* adr, byte* P, dword len) { - word i = 0; + dword i = 0; word w; - while (i < (len & 0xfffe)) { + while (i < (len & 0xfffffffe)) { w = inppw (adr); P[i++] = (byte)(w); P[i++] = (byte)(w>>8); diff -Nru a/drivers/isdn/hardware/eicon/io.h b/drivers/isdn/hardware/eicon/io.h --- a/drivers/isdn/hardware/eicon/io.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/hardware/eicon/io.h 2004-10-18 14:57:04 -07:00 @@ -40,6 +40,14 @@ PISDN_ADAPTER QuadroAdapter[4] ; } ADAPTER_LIST_ENTRY, *PADAPTER_LIST_ENTRY ; /* -------------------------------------------------------------------------- + Special OS memory support structures + -------------------------------------------------------------------------- */ +#define MAX_MAPPED_ENTRIES 8 +typedef struct { + void * Address; + dword Length; +} ADAPTER_MEMORY ; +/* -------------------------------------------------------------------------- Configuration of XDI clients carried by XDI -------------------------------------------------------------------------- */ #define DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON 0x01 @@ -52,6 +60,7 @@ -------------------------------------------------------------------------- */ struct _ISDN_ADAPTER { void (* DIRequest)(PISDN_ADAPTER, ENTITY *) ; + int State ; /* from NT4 1.srv, a good idea, but a poor achievment */ int Initialized ; int RegisteredWithDidd ; int Unavailable ; /* callback function possible? */ @@ -63,6 +72,7 @@ /* remember mapped memory areas */ + ADAPTER_MEMORY MappedMemory[MAX_MAPPED_ENTRIES] ; CARD_PROPERTIES Properties ; dword cardType ; dword protocol_id ; /* configured protocol identifier */ @@ -87,15 +97,15 @@ dword downloadAddrTable[4] ; /* add. for MultiMaster */ dword MemoryBase ; dword MemorySize ; - byte *Address ; + byte *Address ; byte *Config ; byte *Control ; - byte *reset ; - byte *port ; - byte *ram ; - byte *cfg ; - byte *prom ; - byte *ctlReg ; + byte *reset ; + byte *port ; + byte *ram ; + byte *cfg ; + byte *prom ; + byte *ctlReg ; struct pc_maint *pcm ; diva_os_dependent_devica_name_t os_name; byte Name[32] ; @@ -105,6 +115,7 @@ char *ProtocolSuffix ; /* internal protocolfile table */ char Archive[32] ; char Protocol[32] ; + char AddDownload[32] ; /* Dsp- or other additional download files */ char Oad1[ISDN_MAX_NUM_LEN] ; char Osa1[ISDN_MAX_NUM_LEN] ; char Oad2[ISDN_MAX_NUM_LEN] ; @@ -153,8 +164,26 @@ byte ModemCarrierWaitTimeSec; byte ModemCarrierLossWaitTimeTenthSec; byte PiafsLinkTurnaroundInFrames; + byte DiscAfterProgress; + byte AniDniLimiter[3]; + byte TxAttenuation; /* PRI/E1 only: attenuate TX signal */ word QsigFeatures; dword GenerateRingtone ; + dword SupplementaryServicesFeatures; + dword R2Dialect; + dword R2CasOptions; + dword FaxV34Options; + dword DisabledDspMask; + dword AdapterTestMask; + dword DspImageLength; + word AlertToIn20mSecTicks; + word ModemEyeSetup; + byte R2CtryLength; + byte CCBSRelTimer; + byte *PcCfgBufferFile;/* flexible parameter via file */ + byte *PcCfgBuffer ; /* flexible parameter via multistring */ + diva_os_dump_file_t dump_file; /* dump memory to file at lowest irq level */ + diva_os_board_trace_t board_trace ; /* traces from the board */ diva_os_spin_lock_t isr_spin_lock; diva_os_spin_lock_t data_spin_lock; diva_os_soft_isr_t req_soft_isr; @@ -180,15 +209,21 @@ void (* stop)(PISDN_ADAPTER) ; void (* rstFnc)(PISDN_ADAPTER) ; void (* trapFnc)(PISDN_ADAPTER) ; + dword (* DetectDsps)(PISDN_ADAPTER) ; void (* os_trap_nfy_Fnc)(PISDN_ADAPTER, dword) ; diva_os_isr_callback_t diva_isr_handler; - dword sdram_bar; + dword sdram_bar; /* must be 32 bit */ dword fpga_features; volatile int pcm_pending; - volatile unsigned long pcm_data; + volatile void * pcm_data; diva_xdi_capi_cfg_t capi_cfg; dword tasks; - void* dma_map; + void *dma_map; + int (*DivaAdapterTestProc)(PISDN_ADAPTER); + void *AdapterTestMemoryStart; + dword AdapterTestMemoryLength; + const byte* cfg_lib_memory_init; + dword cfg_lib_memory_init_length; }; /* --------------------------------------------------------------------- Entity table @@ -219,8 +254,8 @@ /* --------------------------------------------------------------------- Functions for port io --------------------------------------------------------------------- */ -void outp_words_from_buffer (word* adr, byte* P, word len); -void inp_words_to_buffer (word* adr, byte* P, word len); +void outp_words_from_buffer (word* adr, byte* P, dword len); +void inp_words_to_buffer (word* adr, byte* P, dword len); /* --------------------------------------------------------------------- platform specific conversions --------------------------------------------------------------------- */ @@ -240,6 +275,10 @@ void io_outw(ADAPTER * a, void * adr, word data); void io_out_buffer(ADAPTER * a, void * adr, void * P, word length); void io_inc(ADAPTER * a, void * adr); +void bri_in_buffer (PISDN_ADAPTER IoAdapter, dword Pos, + void *Buf, dword Len); +int bri_out_buffer (PISDN_ADAPTER IoAdapter, dword Pos, + void *Buf, dword Len, int Verify); /* --------------------------------------------------------------------- ram access functions for memory mapped cards --------------------------------------------------------------------- */ diff -Nru a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c --- a/drivers/isdn/hardware/eicon/maintidi.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/isdn/hardware/eicon/maintidi.c 2004-10-18 14:55:53 -07:00 @@ -115,7 +115,7 @@ return NULL; } - pmem += sizeof(*pLib); + pmem += sizeof(*pLib); memset(pLib, 0x00, sizeof(*pLib)); pLib->Adapter = Adapter; @@ -337,13 +337,60 @@ pLib->e.RNum = 1; pLib->e.R->P = (byte*)&pLib->buffer[0]; pLib->e.R->PLength = (word)(sizeof(pLib->buffer) - 1); + } else { /* Indication reception complete, process it now */ byte* p = (byte*)&pLib->buffer[0]; pLib->buffer[pLib->e.R->PLength] = 0; /* terminate I.E. with zero */ + switch (Ind) { + case MAN_COMBI_IND: { + int total_length = pLib->e.R->PLength; + word this_ind_length; + + while (total_length > 3 && *p) { + Ind = *p++; + this_ind_length = (word)p[0] | ((word)p[1] << 8); + p += 2; + + switch (Ind) { + case MAN_INFO_IND: + if (process_idi_info (pLib, (diva_man_var_header_t*)p)) { + return (-1); + } + break; + case MAN_EVENT_IND: + if (process_idi_event (pLib, (diva_man_var_header_t*)p)) { + return (-1); + } + break; + case MAN_TRACE_IND: + if (pLib->trace_on == 1) { + /* + Ignore first trace event that is result of + EVENT_ON operation + */ + pLib->trace_on++; + } else { + /* + Delivery XLOG buffer to application + */ + if (pLib->user_proc_table.trace_proc) { + (*(pLib->user_proc_table.trace_proc))(pLib->user_proc_table.user_context, + &pLib->instance, pLib->Adapter, + p, this_ind_length); + } + } + break; + default: + diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind (DMA mode): %02x", Ind); + } + p += (this_ind_length+1); + total_length -= (4 + this_ind_length); + } + } break; case MAN_INFO_IND: if (process_idi_info (pLib, (diva_man_var_header_t*)p)) { return (-1); @@ -806,7 +853,7 @@ } static int process_idi_event (diva_strace_context_t* pLib, - diva_man_var_header_t* pVar) { + diva_man_var_header_t* pVar) { const char* path = (char*)&pVar->path_length+1; char name[64]; int i; diff -Nru a/drivers/isdn/hardware/eicon/maintidi.h b/drivers/isdn/hardware/eicon/maintidi.h --- a/drivers/isdn/hardware/eicon/maintidi.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/isdn/hardware/eicon/maintidi.h 2004-10-18 14:56:29 -07:00 @@ -49,6 +49,8 @@ void* variable; /* Variable that will receive value */ } diva_strace_path2action_t; +#define DIVA_MAX_MANAGEMENT_TRANSFER_SIZE 4096 + typedef struct _diva_strace_context { diva_strace_library_interface_t instance; @@ -62,7 +64,7 @@ IDI_CALL request; BUFFERS XData; BUFFERS RData; - byte buffer[2048+512+1]; + byte buffer[DIVA_MAX_MANAGEMENT_TRANSFER_SIZE + 1]; int removal_state; int general_b_ch_event; int general_fax_event; diff -Nru a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c --- a/drivers/isdn/hardware/eicon/mntfunc.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/isdn/hardware/eicon/mntfunc.c 2004-10-18 14:55:54 -07:00 @@ -1,4 +1,4 @@ -/* $Id: mntfunc.c,v 1.19 2004/01/09 21:22:03 armin Exp $ +/* $Id: mntfunc.c,v 1.19.6.2 2004/08/28 20:03:53 armin Exp $ * * Driver for Eicon DIVA Server ISDN cards. * Maint module @@ -23,17 +23,12 @@ extern void DIVA_DIDD_Read(void *, int); -#define MAX_DESCRIPTORS 32 - static dword notify_handle; static DESCRIPTOR DAdapter; static DESCRIPTOR MAdapter; static DESCRIPTOR MaintDescriptor = { IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp }; -extern void *diva_os_malloc_tbuffer(unsigned long flags, - unsigned long size); -extern void diva_os_free_tbuffer(unsigned long flags, void *ptr); extern int diva_os_copy_to_user(void *os_handle, void __user *dst, const void *src, int length); extern int diva_os_copy_from_user(void *os_handle, void *dst, @@ -47,16 +42,6 @@ #include "debuglib.c" /* - * stop debug - */ -static void stop_dbg(void) -{ - DbgDeregister(); - memset(&MAdapter, 0, sizeof(MAdapter)); - dprintf = no_printf; -} - -/* * DIDD callback function */ static void *didd_callback(void *context, DESCRIPTOR * adapter, @@ -66,7 +51,9 @@ DBG_ERR(("cb: Change in DAdapter ? Oops ?.")); } else if (adapter->type == IDI_DIMAINT) { if (removal) { - stop_dbg(); + DbgDeregister(); + memset(&MAdapter, 0, sizeof(MAdapter)); + dprintf = no_printf; } else { memcpy(&MAdapter, adapter, sizeof(MAdapter)); dprintf = (DIVA_DI_PRINTF) MAdapter.request; @@ -131,8 +118,6 @@ { IDI_SYNC_REQ req; - stop_dbg(); - req.didd_notify.e.Req = 0; req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; req.didd_notify.info.handle = notify_handle; @@ -193,34 +178,63 @@ } break; + /* + Filter commands will ignore the ID due to fact that filtering affects + the B- channel and Audio Tap trace levels only. Also MAINT driver will + select the right trace ID by itself + */ + case DITRACE_WRITE_SELECTIVE_TRACE_FILTER: + if (!mask) { + ret = diva_set_trace_filter (1, "*"); + } else if (mask < sizeof(data)) { + if (copy_from_user(data, (char __user *)buf+12, mask)) { + ret = -EFAULT; + } else { + ret = diva_set_trace_filter ((int)mask, data); + } + } else { + ret = -EINVAL; + } + break; + + case DITRACE_READ_SELECTIVE_TRACE_FILTER: + if ((ret = diva_get_trace_filter (sizeof(data), data)) > 0) { + if (copy_to_user (buf, data, ret)) + ret = -EFAULT; + } else { + ret = -ENODEV; + } + break; + case DITRACE_READ_TRACE_ENTRY:{ diva_os_spin_lock_magic_t old_irql; word size; diva_dbg_entry_head_t *pmsg; byte *pbuf; - if ((pmsg = diva_maint_get_message(&size, &old_irql))) { + if (!(pbuf = diva_os_malloc(0, mask))) { + return (-ENOMEM); + } + + for(;;) { + if (!(pmsg = + diva_maint_get_message(&size, &old_irql))) { + break; + } if (size > mask) { diva_maint_ack_message(0, &old_irql); ret = -EINVAL; - } else { - if (!(pbuf = diva_os_malloc_tbuffer(0, size))) - { - diva_maint_ack_message(0, &old_irql); - ret = -ENOMEM; - } else { - ret = size; - memcpy(pbuf, pmsg, size); - diva_maint_ack_message(1, &old_irql); - if ((count < size) || diva_os_copy_to_user (NULL, buf, - (void *) pbuf, size)) - ret = -EFAULT; - diva_os_free_tbuffer(0, pbuf); - } + break; } - } else { - ret = 0; + ret = size; + memcpy(pbuf, pmsg, size); + diva_maint_ack_message(1, &old_irql); + if ((count < size) || + diva_os_copy_to_user (NULL, buf, (void *) pbuf, size)) + ret = -EFAULT; + break; } + diva_os_free(0, pbuf); } break; @@ -235,7 +249,7 @@ ret = -EINVAL; break; } - if (!(pbuf = diva_os_malloc_tbuffer(0, mask))) { + if (!(pbuf = diva_os_malloc(0, mask))) { return (-ENOMEM); } @@ -273,7 +287,7 @@ } else { ret = written; } - diva_os_free_tbuffer(0, pbuf); + diva_os_free(0, pbuf); } break; @@ -302,7 +316,7 @@ } else { while ((*buffer_length >= (64 * 1024)) && - (!(*buffer = diva_os_malloc_tbuffer(0, *buffer_length)))) { + (!(*buffer = diva_os_malloc (0, *buffer_length)))) { *buffer_length -= 1024; } @@ -314,7 +328,7 @@ if (diva_maint_init(*buffer, *buffer_length, (diva_dbg_mem == 0))) { if (!diva_dbg_mem) { - diva_os_free_tbuffer(0, *buffer); + diva_os_free (0, *buffer); } DBG_ERR(("init: maint init failed")); return (0); @@ -324,7 +338,7 @@ DBG_ERR(("init: failed to connect to DIDD.")); diva_maint_finit(); if (!diva_dbg_mem) { - diva_os_free_tbuffer(0, *buffer); + diva_os_free (0, *buffer); } return (0); } @@ -339,6 +353,8 @@ void *buffer; int i = 100; + DbgDeregister(); + while (diva_mnt_shutdown_xdi_adapters() && i--) { diva_os_sleep(10); } @@ -346,6 +362,9 @@ disconnect_didd(); if ((buffer = diva_maint_finit())) { - diva_os_free_tbuffer(0, buffer); + diva_os_free (0, buffer); } + + memset(&MAdapter, 0, sizeof(MAdapter)); + dprintf = no_printf; } diff -Nru a/drivers/isdn/hardware/eicon/pc.h b/drivers/isdn/hardware/eicon/pc.h --- a/drivers/isdn/hardware/eicon/pc.h 2004-10-18 14:56:27 -07:00 +++ b/drivers/isdn/hardware/eicon/pc.h 2004-10-18 14:56:27 -07:00 @@ -143,6 +143,7 @@ #define N_DATA_ACK 12 /* data ack ind for D-bit procedure */ #define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */ #define N_XON 15 /* clear RNR state */ +#define N_COMBI_IND N_XON /* combined indication */ #define N_Q_BIT 0x10 /* Q-bit for req/ind */ #define N_M_BIT 0x20 /* M-bit for req/ind */ #define N_D_BIT 0x40 /* D-bit for req/ind */ @@ -228,6 +229,10 @@ #define VSWITCH_IND 66 /* capifunctions for D-CH-switching */ #define MWI_POLL 67 /* Message Waiting Status Request fkt */ #define CALL_PEND_NOTIFY 68 /* notify capi to set new listen */ +#define DO_NOTHING 69 /* dont do somethin if you get this */ +#define INT_CT_REJ 70 /* ECT rejected internal command */ +#define CALL_HOLD_COMPLETE 71 /* In NT Mode indicate hold complete */ +#define CALL_RETRIEVE_COMPLETE 72 /* In NT Mode indicate retrieve complete */ /*------------------------------------------------------------------*/ /* management service primitives */ /*------------------------------------------------------------------*/ @@ -241,6 +246,7 @@ #define MAN_INFO_IND 2 #define MAN_EVENT_IND 3 #define MAN_TRACE_IND 4 +#define MAN_COMBI_IND 9 #define MAN_ESC 0x80 /*------------------------------------------------------------------*/ /* return code coding */ @@ -265,6 +271,7 @@ /*------------------------------------------------------------------*/ #define SHIFT 0x90 /* codeset shift */ #define MORE 0xa0 /* more data */ +#define SDNCMPL 0xa1 /* sending complete */ #define CL 0xb0 /* congestion level */ /* codeset 0 */ #define SMSG 0x00 /* segmented message */ @@ -288,6 +295,8 @@ #define RDX 0x73 /* redirecting number extended */ #define RDN 0x74 /* redirecting number */ #define RIN 0x76 /* redirection number */ +#define IUP 0x76 /* VN6 rerouter->PCS (codeset 6) */ +#define IPU 0x77 /* VN6 PCS->rerouter (codeset 6) */ #define RI 0x79 /* restart indicator */ #define MIE 0x7a /* management info element */ #define LLC 0x7c /* low layer compatibility */ @@ -296,6 +305,8 @@ #define ESC 0x7f /* escape extension */ #define DLC 0x20 /* data link layer configuration */ #define NLC 0x21 /* network layer configuration */ +#define REDIRECT_IE 0x22 /* redirection request/indication data */ +#define REDIRECT_NET_IE 0x23 /* redirection network override data */ /* codeset 6 */ #define SIN 0x01 /* service indicator */ #define CIF 0x02 /* charging information */ @@ -306,6 +317,7 @@ /*------------------------------------------------------------------*/ #define MSGTYPEIE 0x7a /* Messagetype info element */ #define CRIE 0x7b /* INFO info element */ +#define CODESET6IE 0xec /* Tunnel for Codeset 6 IEs */ #define VSWITCHIE 0xed /* VSwitch info element */ #define SSEXTIE 0xee /* Supplem. Service info element */ #define PROFILEIE 0xef /* Profile info element */ @@ -344,6 +356,13 @@ #define CCBS_REQUEST 0x32 #define CCBS_DEACTIVATE 0x33 #define CCBS_INTERROGATE 0x34 +#define CCBS_STATUS 0x35 +#define CCBS_ERASE 0x36 +#define CCBS_B_FREE 0x37 +#define CCNR_INFO_RETAIN 0x38 +#define CCBS_REMOTE_USER_FREE 0x39 +#define CCNR_REQUEST 0x3a +#define CCNR_INTERROGATE 0x3b #define GET_SUPPORTED_SERVICES 0xff #define DIVERSION_PROCEDURE_CFU 0x70 #define DIVERSION_PROCEDURE_CFB 0x71 @@ -362,6 +381,7 @@ #define SMASK_3PTY 0x00000008 #define SMASK_CALL_FORWARDING 0x00000010 #define SMASK_CALL_DEFLECTION 0x00000020 +#define SMASK_MCID 0x00000040 #define SMASK_CCBS 0x00000080 #define SMASK_MWI 0x00000100 #define SMASK_CCNR 0x00000200 @@ -406,6 +426,8 @@ #define RTPL2_IN 13 /* RTP layer-2 protocol, incomming */ #define RTPL2 14 /* RTP layer-2 protocol */ #define V120_V42BIS 15 /* V.120 asynchronous mode supporting V.42bis compression */ +#define LISTENER 27 /* Layer 2 to listen line */ +#define MTP2 28 /* MTP2 Layer 2 */ #define PIAFS_CRC 29 /* PIAFS Layer 2 with CRC calculation at L2 */ /* ------------------------------------------------------ PIAFS DLC DEFINITIONS @@ -506,6 +528,22 @@ | | | data transfer. | +---------------------+------+-----------------------------------------+ */ +/* ------------------------------------------------------ + LISTENER DLC DEFINITIONS + ------------------------------------------------------ */ +#define LISTENER_FEATURE_MASK_CUMMULATIVE 0x0001 +/* ------------------------------------------------------ + LISTENER META-FRAME CODE/PRIMITIVE DEFINITIONS + ------------------------------------------------------ */ +#define META_CODE_LL_UDATA_RX 0x01 +#define META_CODE_LL_UDATA_TX 0x02 +#define META_CODE_LL_DATA_RX 0x03 +#define META_CODE_LL_DATA_TX 0x04 +#define META_CODE_LL_MDATA_RX 0x05 +#define META_CODE_LL_MDATA_TX 0x06 +#define META_CODE_EMPTY 0x10 +#define META_CODE_LOST_FRAMES 0x11 +#define META_FLAG_TRUNCATED 0x0001 /*------------------------------------------------------------------*/ /* CAPI-like profile to indicate features on LAW_REQ */ /*------------------------------------------------------------------*/ @@ -577,6 +615,14 @@ #define MANUFACTURER_FEATURE_DMACONNECT 0x04000000L #define MANUFACTURER_FEATURE_AUDIO_TAP 0x08000000L #define MANUFACTURER_FEATURE_FAX_NONSTANDARD 0x10000000L +#define MANUFACTURER_FEATURE_SS7 0x20000000L +#define MANUFACTURER_FEATURE_MADAPTER 0x40000000L +#define MANUFACTURER_FEATURE_MEASURE 0x80000000L +#define MANUFACTURER_FEATURE2_LISTENING 0x00000001L +#define MANUFACTURER_FEATURE2_SS_DIFFCONTPOSSIBLE 0x00000002L +#define MANUFACTURER_FEATURE2_GENERIC_TONE 0x00000004L +#define MANUFACTURER_FEATURE2_COLOR_FAX 0x00000008L +#define MANUFACTURER_FEATURE2_SS_ECT_DIFFCONTPOSSIBLE 0x00000010L #define RTP_PRIM_PAYLOAD_PCMU_8000 0 #define RTP_PRIM_PAYLOAD_1016_8000 1 #define RTP_PRIM_PAYLOAD_G726_32_8000 2 @@ -624,6 +670,15 @@ #define VSINVOKEID 4 #define VSCLMRKS 5 #define VSTBCTIDENT 6 +#define VSETSILINKID 7 +#define VSSAMECONTROLLER 8 +/* Errorcodes for VSETSILINKID begin */ +#define VSETSILINKIDRRWC 1 +#define VSETSILINKIDREJECT 2 +#define VSETSILINKIDTIMEOUT 3 +#define VSETSILINKIDFAILCOUNT 4 +#define VSETSILINKIDERROR 5 +/* Errorcodes for VSETSILINKID end */ /* -----------------------------------------------------------** ** The PROTOCOL_FEATURE_STRING in feature.h (included ** ** in prstart.sx and astart.sx) defines capabilities and ** @@ -647,5 +702,37 @@ #define PROTCAP_FREE13 0x2000 /* not used */ #define PROTCAP_FREE14 0x4000 /* not used */ #define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ +/* -----------------------------------------------------------* */ +/* Onhook data transmission ETS30065901 */ +/* Message Type */ +/*#define RESERVED4 0x4*/ +#define CALL_SETUP 0x80 +#define MESSAGE_WAITING_INDICATOR 0x82 +/*#define RESERVED84 0x84*/ +/*#define RESERVED85 0x85*/ +#define ADVICE_OF_CHARGE 0x86 +/*1111 0001 +to +1111 1111 +F1H - Reserved for network operator use +to +FFH*/ +/* Parameter Types */ +#define DATE_AND_TIME 1 +#define CLI_PARAMETER_TYPE 2 +#define CALLED_DIRECTORY_NUMBER_PARAMETER_TYPE 3 +#define REASON_FOR_ABSENCE_OF_CLI_PARAMETER_TYPE 4 +#define NAME_PARAMETER_TYPE 7 +#define REASON_FOR_ABSENCE_OF_CALLING_PARTY_NAME_PARAMETER_TYPE 8 +#define VISUAL_INDICATOR_PARAMETER_TYPE 0xb +#define COMPLEMENTARY_CLI_PARAMETER_TYPE 0x10 +#define CALL_TYPE_PARAMETER_TYPE 0x11 +#define FIRST_CALLED_LINE_DIRECTORY_NUMBER_PARAMETER_TYPE 0x12 +#define NETWORK_MESSAGE_SYSTEM_STATUS_PARAMETER_TYPE 0x13 +#define FORWARDED_CALL_TYPE_PARAMETER_TYPE 0x15 +#define TYPE_OF_CALLING_USER_PARAMETER_TYPE 0x16 +#define REDIRECTING_NUMBER_PARAMETER_TYPE 0x1a +#define EXTENSION_FOR_NETWORK_OPERATOR_USE_PARAMETER_TYPE 0xe0 +/* -----------------------------------------------------------* */ #else #endif /* PC_H_INCLUDED } */ diff -Nru a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h --- a/drivers/isdn/hardware/eicon/platform.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/isdn/hardware/eicon/platform.h 2004-10-18 14:56:49 -07:00 @@ -1,4 +1,4 @@ -/* $Id: platform.h,v 1.37.4.1 2004/07/28 14:47:21 armin Exp $ +/* $Id: platform.h,v 1.37.4.2 2004/08/28 20:03:53 armin Exp $ * * platform.h * @@ -269,20 +269,6 @@ diva_os_spin_lock_magic_t* old_irql, \ void* dbg) { spin_unlock_bh(a); } -static __inline__ void diva_os_enter_spin_lock_hard (diva_os_spin_lock_t* a, \ - diva_os_spin_lock_magic_t* old_irql, \ - void* dbg) { \ - unsigned long flags; \ - spin_lock_irqsave (a, flags); \ - *old_irql = (diva_os_spin_lock_magic_t)flags; \ -} -static __inline__ void diva_os_leave_spin_lock_hard (diva_os_spin_lock_t* a, \ - diva_os_spin_lock_magic_t* old_irql, \ - void* dbg) { \ - unsigned long flags = (unsigned long)*old_irql; \ - spin_unlock_irqrestore (a, flags); \ -} - #define diva_os_destroy_spin_lock(a,b) do { } while(0) /* @@ -347,12 +333,18 @@ #define DIVA_IDI_RX_DMA 1 +/* +** endian macros +*/ #define READ_WORD(addr) readw(addr) #define READ_DWORD(addr) readl(addr) #define WRITE_WORD(addr,v) writew(v,addr) #define WRITE_DWORD(addr,v) writel(v,addr) +/* +** 32/64 bit macors +*/ #ifdef BITS_PER_LONG #if BITS_PER_LONG > 32 #define PLATFORM_GT_32BIT @@ -360,8 +352,23 @@ #endif #endif +/* +** undef os definitions of macros we use +*/ #undef ID_MASK #undef N_DATA #undef ADDR + +/* +** dump file +*/ +#define diva_os_dump_file_t char +#define diva_os_board_trace_t char +#define diva_os_dump_file(__x__) do { } while(0) + +/* +** size of internal arrays +*/ +#define MAX_DESCRIPTORS 64 #endif /* __PLATFORM_H__ */ diff -Nru a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c --- a/drivers/isdn/hisax/avm_pci.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/isdn/hisax/avm_pci.c 2004-10-18 14:56:28 -07:00 @@ -752,70 +752,70 @@ cs->hw.avm.cfg_reg = card->para[1]; cs->irq = card->para[0]; cs->subtyp = AVM_FRITZ_PNP; - } else { + goto ready; + } #ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_avm_d = NULL; - if ((pnp_avm_c = pnp_find_card( + if (isapnp_present()) { + struct pnp_dev *pnp_avm_d = NULL; + if ((pnp_avm_c = pnp_find_card( + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { + if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; + ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { + int err; - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (!cs->irq) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return(0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PNP; - goto ready; + pnp_disable_dev(pnp_avm_d); + err = pnp_activate_dev(pnp_avm_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + cs->hw.avm.cfg_reg = + pnp_port_start(pnp_avm_d, 0); + cs->irq = pnp_irq(pnp_avm_d, 0); + if (!cs->irq) { + printk(KERN_ERR "FritzPnP:No IRQ\n"); + return(0); + } + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPnP:No IO address\n"); + return(0); } + cs->subtyp = AVM_FRITZ_PNP; + goto ready; } - } else { - printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); } + } else { + printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); + } #endif #ifdef CONFIG_PCI - if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return(0); - } - if (pci_enable_device(dev_avm)) - return(0); - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_A1, dev_avm))) { + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); + return(0); + } + if (pci_enable_device(dev_avm)) + return(0); + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); return(0); } - cs->irq_flags |= SA_SHIRQ; + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } + cs->irq_flags |= SA_SHIRQ; #else - printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); - return (0); + printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); + return (0); #endif /* CONFIG_PCI */ - } ready: cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; if (!request_region(cs->hw.avm.cfg_reg, 32, diff -Nru a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c --- a/drivers/isdn/hisax/bkm_a4t.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/isdn/hisax/bkm_a4t.c 2004-10-18 14:56:28 -07:00 @@ -265,7 +265,7 @@ char tmp[64]; u_int pci_memaddr = 0, found = 0; I20_REGISTER_FILE *pI20_Regs; -#if CONFIG_PCI +#ifdef CONFIG_PCI #endif strcpy(tmp, bkm_a4t_revision); @@ -275,7 +275,7 @@ } else return (0); -#if CONFIG_PCI +#ifdef CONFIG_PCI while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { u16 sub_sys; diff -Nru a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c --- a/drivers/isdn/hisax/bkm_a8.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/isdn/hisax/bkm_a8.c 2004-10-18 14:56:50 -07:00 @@ -21,7 +21,7 @@ #include #include "bkm_ax.h" -#if CONFIG_PCI +#ifdef CONFIG_PCI #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ @@ -285,7 +285,7 @@ int __init setup_sct_quadro(struct IsdnCard *card) { -#if CONFIG_PCI +#ifdef CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; u_char pci_rev_id; diff -Nru a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c --- a/drivers/isdn/hisax/diva.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/hisax/diva.c 2004-10-18 14:57:04 -07:00 @@ -1027,7 +1027,7 @@ } } #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI cs->subtyp = 0; if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { diff -Nru a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c --- a/drivers/isdn/hisax/elsa.c 2004-10-18 14:56:11 -07:00 +++ b/drivers/isdn/hisax/elsa.c 2004-10-18 14:56:11 -07:00 @@ -1022,7 +1022,7 @@ cs->hw.elsa.base, cs->irq); } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { -#if CONFIG_PCI +#ifdef CONFIG_PCI cs->subtyp = 0; if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { diff -Nru a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c --- a/drivers/isdn/hisax/enternow_pci.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/isdn/hisax/enternow_pci.c 2004-10-18 14:56:49 -07:00 @@ -299,7 +299,7 @@ struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI +#ifdef CONFIG_PCI #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif diff -Nru a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c --- a/drivers/isdn/hisax/gazel.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/isdn/hisax/gazel.c 2004-10-18 14:56:32 -07:00 @@ -634,7 +634,7 @@ return (0); } else { -#if CONFIG_PCI +#ifdef CONFIG_PCI if (setup_gazelpci(cs)) return (0); #else diff -Nru a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c --- a/drivers/isdn/hisax/hfc_pci.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/isdn/hisax/hfc_pci.c 2004-10-18 14:56:29 -07:00 @@ -65,7 +65,7 @@ }; -#if CONFIG_PCI +#ifdef CONFIG_PCI /******************************************/ /* free hardware resources used by driver */ @@ -1655,7 +1655,7 @@ #endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); -#if CONFIG_PCI +#ifdef CONFIG_PCI cs->hw.hfcpci.int_s1 = 0; cs->dc.hfcpci.ph_state = 0; cs->hw.hfcpci.fifo = 255; diff -Nru a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c --- a/drivers/isdn/hisax/niccy.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/isdn/hisax/niccy.c 2004-10-18 14:56:28 -07:00 @@ -309,7 +309,7 @@ return (0); } } else { -#if CONFIG_PCI +#ifdef CONFIG_PCI u_int pci_ioaddr; cs->subtyp = 0; if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, diff -Nru a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c --- a/drivers/isdn/hisax/nj_s.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/isdn/hisax/nj_s.c 2004-10-18 14:56:27 -07:00 @@ -167,7 +167,7 @@ return(0); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI +#ifdef CONFIG_PCI for ( ;; ) { diff -Nru a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c --- a/drivers/isdn/hisax/nj_u.c 2004-10-18 14:56:20 -07:00 +++ b/drivers/isdn/hisax/nj_u.c 2004-10-18 14:56:20 -07:00 @@ -137,7 +137,7 @@ int bytecnt; struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI +#ifdef CONFIG_PCI #endif #ifdef __BIG_ENDIAN #error "not running on big endian machines now" @@ -148,7 +148,7 @@ return(0); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI +#ifdef CONFIG_PCI for ( ;; ) { diff -Nru a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c --- a/drivers/isdn/hisax/sedlbauer.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/isdn/hisax/sedlbauer.c 2004-10-18 14:57:04 -07:00 @@ -618,7 +618,7 @@ } #endif /* Probe for Sedlbauer speed pci */ -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { if (pci_enable_device(dev_sedl)) diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c --- a/drivers/isdn/hisax/st5481_usb.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/isdn/hisax/st5481_usb.c 2004-10-18 14:56:33 -07:00 @@ -143,9 +143,6 @@ if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { /* Special case handling for pipe reset */ le16_to_cpus(&ctrl_msg->dr.wIndex); - usb_endpoint_running(adapter->usb_dev, - ctrl_msg->dr.wIndex & ~USB_DIR_IN, - (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0); /* toggle is reset on clear */ usb_settoggle(adapter->usb_dev, diff -Nru a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c --- a/drivers/isdn/hisax/telespci.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/isdn/hisax/telespci.c 2004-10-18 14:56:48 -07:00 @@ -300,7 +300,7 @@ printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) return (0); -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) return(0); diff -Nru a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c --- a/drivers/isdn/hisax/w6692.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/isdn/hisax/w6692.c 2004-10-18 14:57:03 -07:00 @@ -1012,7 +1012,7 @@ printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) return (0); -#if CONFIG_PCI +#ifdef CONFIG_PCI while (id_list[id_idx].vendor_id) { dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, diff -Nru a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c --- a/drivers/isdn/i4l/isdn_net.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/isdn/i4l/isdn_net.c 2004-10-18 14:57:05 -07:00 @@ -1369,7 +1369,7 @@ skb->mac.raw = skb->data; skb_pull(skb, ETH_HLEN); - eth = skb->mac.ethernet; + eth = eth_hdr(skb); if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) diff -Nru a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c --- a/drivers/isdn/i4l/isdn_tty.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/isdn/i4l/isdn_tty.c 2004-10-18 14:56:48 -07:00 @@ -296,10 +296,7 @@ info->send_outstanding++; info->msr &= ~UART_MSR_CTS; info->lsr &= ~UART_LSR_TEMT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); return; } if (slen < 0) { @@ -1174,10 +1171,7 @@ /* If DLE decoding results in zero-transmit, but * c originally was non-zero, do a wakeup. */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); info->msr |= UART_MSR_CTS; info->lsr |= UART_LSR_TEMT; } @@ -1290,9 +1284,7 @@ isdn_tty_cleanup_xmit(info); info->xmit_count = 0; wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); } static void @@ -1747,10 +1739,10 @@ } dev->modempoll--; isdn_tty_shutdown(info); + if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); info->tty = NULL; info->ncarrier = 0; tty->closing = 0; @@ -2681,8 +2673,7 @@ if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { return; } - if (info->tty->ldisc.flush_buffer) - info->tty->ldisc.flush_buffer(info->tty); + tty_ldisc_flush(info->tty); if ((info->flags & ISDN_ASYNC_CHECK_CD) && (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) { diff -Nru a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c --- a/drivers/isdn/tpam/tpam_main.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/isdn/tpam/tpam_main.c 2004-10-18 14:56:48 -07:00 @@ -23,7 +23,7 @@ /* Local functions prototypes */ static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *); -static void __devexit tpam_unregister_card(tpam_card *); +static void __devexit tpam_unregister_card(struct pci_dev *, tpam_card *); static void __devexit tpam_remove(struct pci_dev *); static int __init tpam_init(void); static void __exit tpam_exit(void); @@ -86,13 +86,20 @@ */ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { tpam_card *card, *c; - int i; + int i, err; + + if (pci_enable_device(dev)) { + printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n", + pci_name(dev)); + return -ENODEV; + } /* allocate memory for the board structure */ if (!(card = (tpam_card *)kmalloc(sizeof(tpam_card), GFP_KERNEL))) { printk(KERN_ERR "TurboPAM: tpam_register_card: " "kmalloc failed!\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_out_disable_dev; } memset((char *)card, 0, sizeof(tpam_card)); @@ -106,8 +113,8 @@ card->interface.id, card)) { printk(KERN_ERR "TurboPAM: tpam_register_card: " "could not request irq %d\n", card->irq); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_free_card; } /* remap board memory */ @@ -115,9 +122,8 @@ 0x800000))) { printk(KERN_ERR "TurboPAM: tpam_register_card: " "unable to remap bar0\n"); - free_irq(card->irq, card); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_free_irq; } /* reset the board */ @@ -150,10 +156,8 @@ if (!register_isdn(&card->interface)) { printk(KERN_ERR "TurboPAM: tpam_register_card: " "unable to register %s\n", card->interface.id); - free_irq(card->irq, card); - iounmap((void *)card->bar0); - kfree(card); - return -EIO; + err = -EIO; + goto err_out_iounmap; } card->id = card->interface.channels; @@ -195,6 +199,19 @@ pci_set_drvdata(dev, card); return 0; + +err_out_iounmap: + iounmap((void *)card->bar0); + +err_out_free_irq: + free_irq(card->irq, card); + +err_out_free_card: + kfree(card); + +err_out_disable_dev: + pci_disable_device(dev); + return err; } /* @@ -202,7 +219,7 @@ * * card: the board. */ -static void __devexit tpam_unregister_card(tpam_card *card) { +static void __devexit tpam_unregister_card(struct pci_dev *pcidev, tpam_card *card) { isdn_ctrl cmd; /* prevent the ISDN link layer that the driver will be unloaded */ @@ -215,6 +232,8 @@ /* release mapped memory */ iounmap((void *)card->bar0); + + pci_disable_device(pcidev); } /* @@ -235,7 +254,7 @@ } /* unregister each board */ - tpam_unregister_card(card); + tpam_unregister_card(pcidev, card); /* and free the board structure itself */ kfree(card); diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c --- a/drivers/macintosh/adbhid.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/macintosh/adbhid.c 2004-10-18 14:57:05 -07:00 @@ -74,15 +74,135 @@ #define ADB_KEY_POWER_OLD 0x7e #define ADB_KEY_POWER 0x7f -unsigned char adb_to_linux_keycodes[128] = { - 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19, - 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24, - 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52, - 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0, - 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, - 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,124, 89,121, - 63, 64, 65, 61, 66, 67,123, 87,122, 99, 0, 70, 0, 68,101, 88, - 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,126,116 +u8 adb_to_linux_keycodes[128] = { + /* 0x00 */ KEY_A, /* 30 */ + /* 0x01 */ KEY_S, /* 31 */ + /* 0x02 */ KEY_D, /* 32 */ + /* 0x03 */ KEY_F, /* 33 */ + /* 0x04 */ KEY_H, /* 35 */ + /* 0x05 */ KEY_G, /* 34 */ + /* 0x06 */ KEY_Z, /* 44 */ + /* 0x07 */ KEY_X, /* 45 */ + /* 0x08 */ KEY_C, /* 46 */ + /* 0x09 */ KEY_V, /* 47 */ + /* 0x0a */ KEY_102ND, /* 86 */ + /* 0x0b */ KEY_B, /* 48 */ + /* 0x0c */ KEY_Q, /* 16 */ + /* 0x0d */ KEY_W, /* 17 */ + /* 0x0e */ KEY_E, /* 18 */ + /* 0x0f */ KEY_R, /* 19 */ + /* 0x10 */ KEY_Y, /* 21 */ + /* 0x11 */ KEY_T, /* 20 */ + /* 0x12 */ KEY_1, /* 2 */ + /* 0x13 */ KEY_2, /* 3 */ + /* 0x14 */ KEY_3, /* 4 */ + /* 0x15 */ KEY_4, /* 5 */ + /* 0x16 */ KEY_6, /* 7 */ + /* 0x17 */ KEY_5, /* 6 */ + /* 0x18 */ KEY_EQUAL, /* 13 */ + /* 0x19 */ KEY_9, /* 10 */ + /* 0x1a */ KEY_7, /* 8 */ + /* 0x1b */ KEY_MINUS, /* 12 */ + /* 0x1c */ KEY_8, /* 9 */ + /* 0x1d */ KEY_0, /* 11 */ + /* 0x1e */ KEY_RIGHTBRACE, /* 27 */ + /* 0x1f */ KEY_O, /* 24 */ + /* 0x20 */ KEY_U, /* 22 */ + /* 0x21 */ KEY_LEFTBRACE, /* 26 */ + /* 0x22 */ KEY_I, /* 23 */ + /* 0x23 */ KEY_P, /* 25 */ + /* 0x24 */ KEY_ENTER, /* 28 */ + /* 0x25 */ KEY_L, /* 38 */ + /* 0x26 */ KEY_J, /* 36 */ + /* 0x27 */ KEY_APOSTROPHE, /* 40 */ + /* 0x28 */ KEY_K, /* 37 */ + /* 0x29 */ KEY_SEMICOLON, /* 39 */ + /* 0x2a */ KEY_BACKSLASH, /* 43 */ + /* 0x2b */ KEY_COMMA, /* 51 */ + /* 0x2c */ KEY_SLASH, /* 53 */ + /* 0x2d */ KEY_N, /* 49 */ + /* 0x2e */ KEY_M, /* 50 */ + /* 0x2f */ KEY_DOT, /* 52 */ + /* 0x30 */ KEY_TAB, /* 15 */ + /* 0x31 */ KEY_SPACE, /* 57 */ + /* 0x32 */ KEY_GRAVE, /* 41 */ + /* 0x33 */ KEY_BACKSPACE, /* 14 */ + /* 0x34 */ KEY_KPENTER, /* 96 */ + /* 0x35 */ KEY_ESC, /* 1 */ + /* 0x36 */ KEY_LEFTCTRL, /* 29 */ + /* 0x37 */ KEY_LEFTMETA, /* 125 */ + /* 0x38 */ KEY_LEFTSHIFT, /* 42 */ + /* 0x39 */ KEY_CAPSLOCK, /* 58 */ + /* 0x3a */ KEY_LEFTALT, /* 56 */ + /* 0x3b */ KEY_LEFT, /* 105 */ + /* 0x3c */ KEY_RIGHT, /* 106 */ + /* 0x3d */ KEY_DOWN, /* 108 */ + /* 0x3e */ KEY_UP, /* 103 */ + /* 0x3f */ 0, + /* 0x40 */ 0, + /* 0x41 */ KEY_KPDOT, /* 83 */ + /* 0x42 */ 0, + /* 0x43 */ KEY_KPASTERISK, /* 55 */ + /* 0x44 */ 0, + /* 0x45 */ KEY_KPPLUS, /* 78 */ + /* 0x46 */ 0, + /* 0x47 */ KEY_NUMLOCK, /* 69 */ + /* 0x48 */ 0, + /* 0x49 */ 0, + /* 0x4a */ 0, + /* 0x4b */ KEY_KPSLASH, /* 98 */ + /* 0x4c */ KEY_KPENTER, /* 96 */ + /* 0x4d */ 0, + /* 0x4e */ KEY_KPMINUS, /* 74 */ + /* 0x4f */ 0, + /* 0x50 */ 0, + /* 0x51 */ KEY_KPEQUAL, /* 117 */ + /* 0x52 */ KEY_KP0, /* 82 */ + /* 0x53 */ KEY_KP1, /* 79 */ + /* 0x54 */ KEY_KP2, /* 80 */ + /* 0x55 */ KEY_KP3, /* 81 */ + /* 0x56 */ KEY_KP4, /* 75 */ + /* 0x57 */ KEY_KP5, /* 76 */ + /* 0x58 */ KEY_KP6, /* 77 */ + /* 0x59 */ KEY_KP7, /* 71 */ + /* 0x5a */ 0, + /* 0x5b */ KEY_KP8, /* 72 */ + /* 0x5c */ KEY_KP9, /* 73 */ + /* 0x5d */ KEY_YEN, /* 124 */ + /* 0x5e */ KEY_RO, /* 89 */ + /* 0x5f */ KEY_KPCOMMA, /* 121 */ + /* 0x60 */ KEY_F5, /* 63 */ + /* 0x61 */ KEY_F6, /* 64 */ + /* 0x62 */ KEY_F7, /* 65 */ + /* 0x63 */ KEY_F3, /* 61 */ + /* 0x64 */ KEY_F8, /* 66 */ + /* 0x65 */ KEY_F9, /* 67 */ + /* 0x66 */ KEY_HANJA, /* 123 */ + /* 0x67 */ KEY_F11, /* 87 */ + /* 0x68 */ KEY_HANGUEL, /* 122 */ + /* 0x69 */ KEY_SYSRQ, /* 99 */ + /* 0x6a */ 0, + /* 0x6b */ KEY_SCROLLLOCK, /* 70 */ + /* 0x6c */ 0, + /* 0x6d */ KEY_F10, /* 68 */ + /* 0x6e */ KEY_COMPOSE, /* 127 */ + /* 0x6f */ KEY_F12, /* 88 */ + /* 0x70 */ 0, + /* 0x71 */ KEY_PAUSE, /* 119 */ + /* 0x72 */ KEY_INSERT, /* 110 */ + /* 0x73 */ KEY_HOME, /* 102 */ + /* 0x74 */ KEY_PAGEUP, /* 104 */ + /* 0x75 */ KEY_DELETE, /* 111 */ + /* 0x76 */ KEY_F4, /* 62 */ + /* 0x77 */ KEY_END, /* 107 */ + /* 0x78 */ KEY_F2, /* 60 */ + /* 0x79 */ KEY_PAGEDOWN, /* 109 */ + /* 0x7a */ KEY_F1, /* 59 */ + /* 0x7b */ KEY_RIGHTSHIFT, /* 54 */ + /* 0x7c */ KEY_RIGHTALT, /* 100 */ + /* 0x7d */ KEY_RIGHTCTRL, /* 97 */ + /* 0x7e */ KEY_RIGHTMETA, /* 126 */ + /* 0x7f */ KEY_POWER, /* 116 */ }; struct adbhid { @@ -326,7 +446,7 @@ input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); - if (nb >= 4) + if (nb >= 4 && adbhid[id]->mouse_kind != ADBMOUSE_TRACKPAD) input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); input_report_rel(&adbhid[id]->input, REL_X, @@ -453,7 +573,7 @@ static void leds_done(struct adb_request *req) { - int leds, device; + int leds = 0, device = 0, pending = 0; unsigned long flags; spin_lock_irqsave(&leds_lock, flags); @@ -464,11 +584,11 @@ leds_pending[device] = 0; pending_led_start++; pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + pending = leds_req_pending; } else leds_req_pending = 0; - spin_unlock_irqrestore(&leds_lock, flags); - if (leds_req_pending) + if (pending) adb_request(&led_request, leds_done, 0, 3, ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds); } diff -Nru a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c --- a/drivers/macintosh/ans-lcd.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/macintosh/ans-lcd.c 2004-10-18 14:57:04 -07:00 @@ -9,6 +9,8 @@ #include #include #include +#include + #include #include #include @@ -154,7 +156,7 @@ retval = misc_register(&anslcd_dev); if(retval < 0){ printk(KERN_INFO "LCD: misc_register failed\n"); - iounmap(anslcd_ptr); + iounmap((void *)anslcd_ptr); return retval; } @@ -177,7 +179,7 @@ anslcd_exit(void) { misc_deregister(&anslcd_dev); - iounmap(anslcd_ptr); + iounmap((void *)anslcd_ptr); } module_init(anslcd_init); diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c --- a/drivers/macintosh/macserial.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/macintosh/macserial.c 2004-10-18 14:57:04 -07:00 @@ -713,12 +713,8 @@ if (!tty) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) + tty_wakeup(tty); } static int startup(struct mac_serial * info) @@ -1564,10 +1560,7 @@ spin_lock_irqsave(&info->lock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; spin_unlock_irqrestore(&info->lock, flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1994,16 +1987,14 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(info->close_delay); + msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } @@ -2048,8 +2039,7 @@ if (timeout) char_time = min_t(unsigned long, char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(char_time); + msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) diff -Nru a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c --- a/drivers/macintosh/therm_adt746x.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/macintosh/therm_adt746x.c 2004-10-18 14:56:49 -07:00 @@ -28,6 +28,7 @@ #include #include #include +#include #undef DEBUG @@ -53,7 +54,7 @@ MODULE_LICENSE("GPL"); MODULE_PARM(limit_adjust,"i"); -MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50°C cpu, 70°C gpu) by N °C."); +MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 cpu, 70 gpu) by N degrees."); MODULE_PARM(fan_speed,"i"); MODULE_PARM_DESC(fan_speed,"Specify fan speed (0-255) when lim < temp < lim+8 (default 128)"); @@ -70,9 +71,7 @@ static int therm_bus, therm_address; static struct of_device * of_dev; static struct thermostat* thermostat; -static pid_t monitor_thread_id; -static int monitor_running; -static struct completion monitor_task_compl; +static struct task_struct *thread_therm = NULL; static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno); static void write_both_fan_speed(struct thermostat *th, int speed); @@ -136,13 +135,12 @@ th = thermostat; - if (monitor_running) { - monitor_running = 0; - wait_for_completion(&monitor_task_compl); + if (thread_therm != NULL) { + kthread_stop(thread_therm); } printk(KERN_INFO "adt746x: Putting max temperatures back from %d, %d, %d," - " to %d, %d, %d, (°C)\n", + " to %d, %d, %d\n", th->limits[0], th->limits[1], th->limits[2], th->initial_limits[0], th->initial_limits[1], th->initial_limits[2]); @@ -178,7 +176,8 @@ tmp[0] = read_reg(th, addr + 1); res = tmp[1] + (tmp[0] << 8); - return (90000*60)/res; + /* "a value of 0xffff means that the fan has stopped" */ + return (res == 0xffff ? 0 : (90000*60)/res); } static void write_both_fan_speed(struct thermostat *th, int speed) @@ -237,16 +236,9 @@ #ifdef DEBUG int mfan_speed; #endif - - lock_kernel(); - daemonize("kfand"); - unlock_kernel(); - strcpy(current->comm, "thermostat"); - monitor_running = 1; - - while(monitor_running) + while(!kthread_should_stop()) { - msleep(2000); + msleep_interruptible(2000); /* Check status */ /* local : chip */ @@ -270,14 +262,14 @@ int var = temps[i] - lims[i]; if (var > 8) { if (th->overriding[fan_number] == 0) - printk(KERN_INFO "adt746x: Limit exceeded by %d°C, overriding specified fan speed for %s.\n", + printk(KERN_INFO "adt746x: Limit exceeded by %d, overriding specified fan speed for %s.\n", var, fan_number?"GPU":"CPU"); th->overriding[fan_number] = 1; write_fan_speed(th, 255, fan_number); started = 1; } else if ((!th->overriding[fan_number] || var < 6) && var > 0) { if (th->overriding[fan_number] == 1) - printk(KERN_INFO "adt746x: Limit exceeded by %d°C, setting speed to specified for %s.\n", + printk(KERN_INFO "adt746x: Limit exceeded by %d, setting speed to specified for %s.\n", var, fan_number?"GPU":"CPU"); th->overriding[fan_number] = 0; write_fan_speed(th, fan_speed, fan_number); @@ -308,8 +300,8 @@ || temps[1] != th->cached_temp[1] || temps[2] != th->cached_temp[2]) { printk(KERN_INFO "adt746x: Temperature infos:" - " thermostats: %d,%d,%d °C;" - " limits: %d,%d,%d °C;" + " thermostats: %d,%d,%d;" + " limits: %d,%d,%d;" " fan speed: %d RPM\n", temps[0], temps[1], temps[2], lims[0], lims[1], lims[2], @@ -321,7 +313,6 @@ #endif } - complete_and_exit(&monitor_task_compl, 0); return 0; } @@ -380,14 +371,14 @@ } printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" - " to %d, %d, %d (°C)\n", + " to %d, %d, %d\n", th->initial_limits[0], th->initial_limits[1], th->initial_limits[2], th->limits[0], th->limits[1], th->limits[2]); thermostat = th; if (i2c_attach_client(&th->clt)) { - printk("adt746x: Thermostat failed to attach client !\n"); + printk(KERN_INFO "adt746x: Thermostat failed to attach client !\n"); thermostat = NULL; kfree(th); return -ENODEV; @@ -403,10 +394,13 @@ write_both_fan_speed(th, -1); } - init_completion(&monitor_task_compl); - - monitor_thread_id = kernel_thread(monitor_task, th, - SIGCHLD | CLONE_KERNEL); + thread_therm = kthread_run(monitor_task, th, "kfand"); + + if (thread_therm == ERR_PTR(-ENOMEM)) { + printk(KERN_INFO "adt746x: Kthread creation failed\n"); + thread_therm = NULL; + return -ENOMEM; + } return 0; } @@ -417,17 +411,21 @@ * choice but implement a bunch of them... * */ -#define BUILD_SHOW_FUNC_DEG(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ -{ \ - return sprintf(buf, "%d°C\n", data); \ -} #define BUILD_SHOW_FUNC_INT(name, data) \ static ssize_t show_##name(struct device *dev, char *buf) \ { \ return sprintf(buf, "%d\n", data); \ } +#define BUILD_SHOW_FUNC_FAN(name, data) \ +static ssize_t show_##name(struct device *dev, char *buf) \ +{ \ + return sprintf(buf, "%d (%d rpm)\n", \ + thermostat->last_speed[data], \ + read_fan_speed(thermostat, FAN_SPEED[data]) \ + ); \ +} + #define BUILD_STORE_FUNC_DEG(name, data) \ static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ { \ @@ -448,19 +446,19 @@ val = simple_strtoul(buf, NULL, 10); \ if (val < 0 || val > 255) \ return -EINVAL; \ - printk(KERN_INFO "Setting fan speed to %d\n", val); \ + printk(KERN_INFO "Setting specified fan speed to %d\n", val); \ data = val; \ return n; \ } -BUILD_SHOW_FUNC_DEG(cpu_temperature, (read_reg(thermostat, TEMP_REG[1]))) -BUILD_SHOW_FUNC_DEG(gpu_temperature, (read_reg(thermostat, TEMP_REG[2]))) -BUILD_SHOW_FUNC_DEG(cpu_limit, thermostat->limits[1]) -BUILD_SHOW_FUNC_DEG(gpu_limit, thermostat->limits[2]) +BUILD_SHOW_FUNC_INT(cpu_temperature, (read_reg(thermostat, TEMP_REG[1]))) +BUILD_SHOW_FUNC_INT(gpu_temperature, (read_reg(thermostat, TEMP_REG[2]))) +BUILD_SHOW_FUNC_INT(cpu_limit, thermostat->limits[1]) +BUILD_SHOW_FUNC_INT(gpu_limit, thermostat->limits[2]) BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed) -BUILD_SHOW_FUNC_INT(cpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[0]))) -BUILD_SHOW_FUNC_INT(gpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[1]))) +BUILD_SHOW_FUNC_FAN(cpu_fan_speed, 0) +BUILD_SHOW_FUNC_FAN(gpu_fan_speed, 1) BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust) diff -Nru a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c --- a/drivers/macintosh/therm_windtunnel.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/macintosh/therm_windtunnel.c 2004-10-18 14:56:49 -07:00 @@ -292,8 +292,7 @@ while( x.running ) { up( &x.lock ); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout( 8*HZ ); + msleep_interruptible(8000); down( &x.lock ); poll_temp(); diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c --- a/drivers/macintosh/via-pmu.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/macintosh/via-pmu.c 2004-10-18 14:57:03 -07:00 @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include @@ -138,7 +137,6 @@ static volatile int adb_int_pending; static volatile int disable_poll; static struct adb_request bright_req_1, bright_req_2; -static unsigned long async_req_locks; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; @@ -155,6 +153,7 @@ static int option_lid_wakeup = 1; static int sleep_in_progress; static int can_sleep; +static unsigned long async_req_locks; #endif /* CONFIG_PMAC_PBOOK */ static unsigned int pmu_irq_stats[11]; @@ -494,12 +493,9 @@ /* Create /proc/pmu */ proc_pmu_root = proc_mkdir("pmu", NULL); if (proc_pmu_root) { - int i; - proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root, - proc_get_info, NULL); - proc_pmu_irqstats = create_proc_read_entry("interrupts", 0, proc_pmu_root, - proc_get_irqstats, NULL); #ifdef CONFIG_PMAC_PBOOK + int i; + for (i=0; inlink = 1; @@ -746,6 +747,8 @@ pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + capa = max = amperage = voltage = 0; + if (req->reply[1] & 0x04) { bat_flags |= PMU_BATT_PRESENT; switch(req->reply[0]) { @@ -765,8 +768,7 @@ req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]); break; } - } else - capa = max = amperage = voltage = 0; + } if ((req->reply[1] & 0x01) && (amperage > 0)) bat_flags |= PMU_BATT_CHARGING; @@ -1445,7 +1447,7 @@ pmu_sr_intr(struct pt_regs *regs) { struct adb_request *req; - int bite; + int bite = 0; if (via[B] & TREQ) { printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); diff -Nru a/drivers/md/Kconfig b/drivers/md/Kconfig --- a/drivers/md/Kconfig 2004-10-18 14:55:55 -07:00 +++ b/drivers/md/Kconfig 2004-10-18 14:55:55 -07:00 @@ -85,6 +85,24 @@ If unsure, say Y. +config MD_RAID10 + tristate "RAID-10 (mirrored striping) mode (EXPERIMENTAL)" + depends on BLK_DEV_MD && EXPERIMENTAL + ---help--- + RAID-10 provides a combination of striping (RAID-0) and + mirroring (RAID-1) with easier configuration and more flexable + layout. + Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to + be the same size (or atleast, only as much as the smallest device + will be used). + RAID-10 provides a variety of layouts that provide different levels + of redundancy and performance. + + RAID-10 requires mdadm-1.7.0 or later, available at: + + ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/ + + config MD_RAID5 tristate "RAID-4/RAID-5 mode" depends on BLK_DEV_MD diff -Nru a/drivers/md/Makefile b/drivers/md/Makefile --- a/drivers/md/Makefile 2004-10-18 14:56:32 -07:00 +++ b/drivers/md/Makefile 2004-10-18 14:56:32 -07:00 @@ -10,7 +10,7 @@ raid6int1.o raid6int2.o raid6int4.o \ raid6int8.o raid6int16.o raid6int32.o \ raid6mmx.o raid6sse1.o raid6sse2.o -host-progs := mktables +hostprogs-y := mktables # Note: link order is important. All raid personalities # and xor.o must come before md.o, as they each initialise @@ -20,6 +20,7 @@ obj-$(CONFIG_MD_LINEAR) += linear.o obj-$(CONFIG_MD_RAID0) += raid0.o obj-$(CONFIG_MD_RAID1) += raid1.o +obj-$(CONFIG_MD_RAID10) += raid10.o obj-$(CONFIG_MD_RAID5) += raid5.o xor.o obj-$(CONFIG_MD_RAID6) += raid6.o xor.o obj-$(CONFIG_MD_MULTIPATH) += multipath.o diff -Nru a/drivers/md/dm-log.c b/drivers/md/dm-log.c --- a/drivers/md/dm-log.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/md/dm-log.c 2004-10-18 14:57:04 -07:00 @@ -140,6 +140,13 @@ int sync_search; + /* Resync flag */ + enum sync { + DEFAULTSYNC, /* Synchronize if necessary */ + NOSYNC, /* Devices known to be already in sync */ + FORCESYNC, /* Force a sync to happen */ + } sync; + /* * Disk log fields */ @@ -205,7 +212,8 @@ header_from_disk(&log->header, log->disk_header); - if (log->header.magic != MIRROR_MAGIC) { + /* New log required? */ + if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) { log->header.magic = MIRROR_MAGIC; log->header.version = MIRROR_DISK_VERSION; log->header.nr_regions = 0; @@ -273,22 +281,38 @@ } /*---------------------------------------------------------------- - * constructor/destructor + * core log constructor/destructor + * + * argv contains region_size followed optionally by [no]sync *--------------------------------------------------------------*/ #define BYTE_SHIFT 3 static int core_ctr(struct dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv) { + enum sync sync = DEFAULTSYNC; + struct log_c *lc; sector_t region_size; unsigned int region_count; size_t bitset_size; - if (argc != 1) { - DMWARN("wrong number of arguments to log_c"); + if (argc < 1 || argc > 2) { + DMWARN("wrong number of arguments to mirror log"); return -EINVAL; } + if (argc > 1) { + if (!strcmp(argv[1], "sync")) + sync = FORCESYNC; + else if (!strcmp(argv[1], "nosync")) + sync = NOSYNC; + else { + DMWARN("unrecognised sync argument to mirror log: %s", + argv[1]); + return -EINVAL; + } + } + if (sscanf(argv[0], SECTOR_FORMAT, ®ion_size) != 1) { DMWARN("invalid region size string"); return -EINVAL; @@ -306,6 +330,7 @@ lc->touched = 0; lc->region_size = region_size; lc->region_count = region_count; + lc->sync = sync; /* * Work out how many words we need to hold the bitset. @@ -330,8 +355,8 @@ kfree(lc); return -ENOMEM; } - memset(lc->sync_bits, 0, bitset_size); - lc->sync_count = 0; + memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size); + lc->sync_count = (sync == NOSYNC) ? region_count : 0; lc->recovering_bits = vmalloc(bitset_size); if (!lc->recovering_bits) { @@ -356,6 +381,11 @@ kfree(lc); } +/*---------------------------------------------------------------- + * disk log constructor/destructor + * + * argv contains log_device region_size followed optionally by [no]sync + *--------------------------------------------------------------*/ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv) { @@ -364,8 +394,8 @@ struct log_c *lc; struct dm_dev *dev; - if (argc != 2) { - DMWARN("wrong number of arguments to log_d"); + if (argc < 2 || argc > 3) { + DMWARN("wrong number of arguments to disk mirror log"); return -EINVAL; } @@ -452,10 +482,15 @@ if (r) return r; - /* zero any new bits if the mirror has grown */ - for (i = lc->header.nr_regions; i < lc->region_count; i++) - /* FIXME: amazingly inefficient */ - log_clear_bit(lc, lc->clean_bits, i); + /* set or clear any new bits */ + if (lc->sync == NOSYNC) + for (i = lc->header.nr_regions; i < lc->region_count; i++) + /* FIXME: amazingly inefficient */ + log_set_bit(lc, lc->clean_bits, i); + else + for (i = lc->header.nr_regions; i < lc->region_count; i++) + /* FIXME: amazingly inefficient */ + log_clear_bit(lc, lc->clean_bits, i); /* copy clean across to sync */ memcpy(lc->sync_bits, lc->clean_bits, size); @@ -566,6 +601,51 @@ return lc->sync_count; } +#define DMEMIT_SYNC \ + if (lc->sync != DEFAULTSYNC) \ + DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "") + +static int core_status(struct dirty_log *log, status_type_t status, + char *result, unsigned int maxlen) +{ + int sz = 0; + struct log_c *lc = log->context; + + switch(status) { + case STATUSTYPE_INFO: + break; + + case STATUSTYPE_TABLE: + DMEMIT("%s %u " SECTOR_FORMAT " ", log->type->name, + lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size); + DMEMIT_SYNC; + } + + return sz; +} + +static int disk_status(struct dirty_log *log, status_type_t status, + char *result, unsigned int maxlen) +{ + int sz = 0; + char buffer[16]; + struct log_c *lc = log->context; + + switch(status) { + case STATUSTYPE_INFO: + break; + + case STATUSTYPE_TABLE: + format_dev_t(buffer, lc->log_dev->bdev->bd_dev); + DMEMIT("%s %u %s " SECTOR_FORMAT " ", log->type->name, + lc->sync == DEFAULTSYNC ? 2 : 3, buffer, + lc->region_size); + DMEMIT_SYNC; + } + + return sz; +} + static struct dirty_log_type _core_type = { .name = "core", .module = THIS_MODULE, @@ -579,7 +659,8 @@ .clear_region = core_clear_region, .get_resync_work = core_get_resync_work, .complete_resync_work = core_complete_resync_work, - .get_sync_count = core_get_sync_count + .get_sync_count = core_get_sync_count, + .status = core_status, }; static struct dirty_log_type _disk_type = { @@ -597,7 +678,8 @@ .clear_region = core_clear_region, .get_resync_work = core_get_resync_work, .complete_resync_work = core_complete_resync_work, - .get_sync_count = core_get_sync_count + .get_sync_count = core_get_sync_count, + .status = disk_status, }; int __init dm_dirty_log_init(void) diff -Nru a/drivers/md/dm-log.h b/drivers/md/dm-log.h --- a/drivers/md/dm-log.h 2004-10-18 14:56:20 -07:00 +++ b/drivers/md/dm-log.h 2004-10-18 14:56:20 -07:00 @@ -101,6 +101,12 @@ * Returns the number of regions that are in sync. */ region_t (*get_sync_count)(struct dirty_log *log); + + /* + * Support function for mirror status requests. + */ + int (*status)(struct dirty_log *log, status_type_t status_type, + char *result, unsigned int maxlen); }; int dm_register_dirty_log_type(struct dirty_log_type *type); diff -Nru a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c --- a/drivers/md/dm-raid1.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/md/dm-raid1.c 2004-10-18 14:57:05 -07:00 @@ -1009,8 +1009,8 @@ * log_type #log_params * #mirrors [mirror_path offset]{2,} * - * For now, #log_params = 1, log_type = "core" - * + * log_type is "core" or "disk" + * #log_params is between 1 and 3 */ #define DM_IO_PAGES 64 static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) @@ -1182,35 +1182,30 @@ char *result, unsigned int maxlen) { char buffer[32]; - unsigned int m, sz = 0; + unsigned int m, sz; struct mirror_set *ms = (struct mirror_set *) ti->private; -#define EMIT(x...) sz += ((sz >= maxlen) ? \ - 0 : scnprintf(result + sz, maxlen - sz, x)) + sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen); switch (type) { case STATUSTYPE_INFO: - EMIT("%d ", ms->nr_mirrors); - + DMEMIT("%d ", ms->nr_mirrors); for (m = 0; m < ms->nr_mirrors; m++) { format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); - EMIT("%s ", buffer); + DMEMIT("%s ", buffer); } - EMIT(SECTOR_FORMAT "/" SECTOR_FORMAT, - ms->rh.log->type->get_sync_count(ms->rh.log), - ms->nr_regions); + DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT, + ms->rh.log->type->get_sync_count(ms->rh.log), + ms->nr_regions); break; case STATUSTYPE_TABLE: - EMIT("%s 1 " SECTOR_FORMAT " %d ", - ms->rh.log->type->name, ms->rh.region_size, - ms->nr_mirrors); - + DMEMIT("%d ", ms->nr_mirrors); for (m = 0; m < ms->nr_mirrors; m++) { format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); - EMIT("%s " SECTOR_FORMAT " ", - buffer, ms->mirror[m].offset); + DMEMIT("%s " SECTOR_FORMAT " ", + buffer, ms->mirror[m].offset); } } diff -Nru a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c --- a/drivers/md/dm-stripe.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/md/dm-stripe.c 2004-10-18 14:56:29 -07:00 @@ -191,20 +191,17 @@ unsigned int i; char buffer[32]; -#define EMIT(x...) sz += ((sz >= maxlen) ? \ - 0 : scnprintf(result + sz, maxlen - sz, x)) - switch (type) { case STATUSTYPE_INFO: result[0] = '\0'; break; case STATUSTYPE_TABLE: - EMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1); + DMEMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1); for (i = 0; i < sc->stripes; i++) { format_dev_t(buffer, sc->stripe[i].dev->bdev->bd_dev); - EMIT(" %s " SECTOR_FORMAT, buffer, - sc->stripe[i].physical_start); + DMEMIT(" %s " SECTOR_FORMAT, buffer, + sc->stripe[i].physical_start); } break; } diff -Nru a/drivers/md/dm-table.c b/drivers/md/dm-table.c --- a/drivers/md/dm-table.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/md/dm-table.c 2004-10-18 14:57:04 -07:00 @@ -825,7 +825,7 @@ * Make sure we obey the optimistic sub devices * restrictions. */ - q->max_sectors = t->limits.max_sectors; + blk_queue_max_sectors(q, t->limits.max_sectors); q->max_phys_segments = t->limits.max_phys_segments; q->max_hw_segments = t->limits.max_hw_segments; q->hardsect_size = t->limits.hardsect_size; @@ -900,6 +900,28 @@ } } +int dm_table_flush_all(struct dm_table *t) +{ + struct list_head *d, *devices = dm_table_get_devices(t); + int ret = 0; + + for (d = devices->next; d != devices; d = d->next) { + struct dm_dev *dd = list_entry(d, struct dm_dev, list); + request_queue_t *q = bdev_get_queue(dd->bdev); + int err; + + if (!q->issue_flush_fn) + err = -EOPNOTSUPP; + else + err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL); + + if (!ret) + ret = err; + } + + return ret; +} + EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); @@ -908,3 +930,4 @@ EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); EXPORT_SYMBOL(dm_table_unplug_all); +EXPORT_SYMBOL(dm_table_flush_all); diff -Nru a/drivers/md/dm.c b/drivers/md/dm.c --- a/drivers/md/dm.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/md/dm.c 2004-10-18 14:56:49 -07:00 @@ -15,15 +15,13 @@ #include #include #include +#include static const char *_name = DM_NAME; static unsigned int major = 0; static unsigned int _major = 0; -static int realloc_minor_bits(unsigned long requested_minor); -static void free_minor_bits(void); - /* * One of these is allocated per bio. */ @@ -113,19 +111,11 @@ return -ENOMEM; } - r = realloc_minor_bits(1024); - if (r < 0) { - kmem_cache_destroy(_tio_cache); - kmem_cache_destroy(_io_cache); - return r; - } - _major = major; r = register_blkdev(_major, _name); if (r < 0) { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); return r; } @@ -139,7 +129,6 @@ { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); if (unregister_blkdev(_major, _name) < 0) DMERR("devfs_unregister_blkdev failed"); @@ -597,6 +586,21 @@ return 0; } +static int dm_flush_all(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct mapped_device *md = q->queuedata; + struct dm_table *map = dm_get_table(md); + int ret = -ENXIO; + + if (map) { + ret = dm_table_flush_all(md->map); + dm_table_put(map); + } + + return ret; +} + static void dm_unplug_all(request_queue_t *q) { struct mapped_device *md = q->queuedata; @@ -624,59 +628,15 @@ } /*----------------------------------------------------------------- - * A bitset is used to keep track of allocated minor numbers. + * An IDR is used to keep track of allocated minor numbers. *---------------------------------------------------------------*/ static DECLARE_MUTEX(_minor_lock); -static unsigned long *_minor_bits = NULL; -static unsigned long _max_minors = 0; - -#define MINORS_SIZE(minors) ((minors / BITS_PER_LONG) * sizeof(unsigned long)) - -static int realloc_minor_bits(unsigned long requested_minor) -{ - unsigned long max_minors; - unsigned long *minor_bits, *tmp; - - if (requested_minor < _max_minors) - return -EINVAL; - - /* Round up the requested minor to the next power-of-2. */ - max_minors = 1 << fls(requested_minor - 1); - if (max_minors > (1 << MINORBITS)) - return -EINVAL; - - minor_bits = kmalloc(MINORS_SIZE(max_minors), GFP_KERNEL); - if (!minor_bits) - return -ENOMEM; - memset(minor_bits, 0, MINORS_SIZE(max_minors)); - - /* Copy the existing bit-set to the new one. */ - if (_minor_bits) - memcpy(minor_bits, _minor_bits, MINORS_SIZE(_max_minors)); - - tmp = _minor_bits; - _minor_bits = minor_bits; - _max_minors = max_minors; - if (tmp) - kfree(tmp); - - return 0; -} - -static void free_minor_bits(void) -{ - down(&_minor_lock); - kfree(_minor_bits); - _minor_bits = NULL; - _max_minors = 0; - up(&_minor_lock); -} +static DEFINE_IDR(_minor_idr); static void free_minor(unsigned int minor) { down(&_minor_lock); - if (minor < _max_minors) - clear_bit(minor, _minor_bits); + idr_remove(&_minor_idr, minor); up(&_minor_lock); } @@ -685,24 +645,37 @@ */ static int specific_minor(unsigned int minor) { - int r = 0; + int r, m; - if (minor > (1 << MINORBITS)) + if (minor >= (1 << MINORBITS)) return -EINVAL; down(&_minor_lock); - if (minor >= _max_minors) { - r = realloc_minor_bits(minor); - if (r) { - up(&_minor_lock); - return r; - } + + if (idr_find(&_minor_idr, minor)) { + r = -EBUSY; + goto out; + } + + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new_above(&_minor_idr, specific_minor, minor, &m); + if (r) { + goto out; } - if (test_and_set_bit(minor, _minor_bits)) + if (m != minor) { + idr_remove(&_minor_idr, m); r = -EBUSY; - up(&_minor_lock); + goto out; + } +out: + up(&_minor_lock); return r; } @@ -712,21 +685,29 @@ unsigned int m; down(&_minor_lock); - m = find_first_zero_bit(_minor_bits, _max_minors); - if (m >= _max_minors) { - r = realloc_minor_bits(_max_minors * 2); - if (r) { - up(&_minor_lock); - return r; - } - m = find_first_zero_bit(_minor_bits, _max_minors); + + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new(&_minor_idr, next_free_minor, &m); + if (r) { + goto out; + } + + if (m >= (1 << MINORBITS)) { + idr_remove(&_minor_idr, m); + r = -ENOSPC; + goto out; } - set_bit(m, _minor_bits); *minor = m; - up(&_minor_lock); - return 0; +out: + up(&_minor_lock); + return r; } static struct block_device_operations dm_blk_dops; @@ -764,6 +745,7 @@ md->queue->backing_dev_info.congested_data = md; blk_queue_make_request(md->queue, dm_request); md->queue->unplug_fn = dm_unplug_all; + md->queue->issue_flush_fn = dm_flush_all; md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab, mempool_free_slab, _io_cache); diff -Nru a/drivers/md/dm.h b/drivers/md/dm.h --- a/drivers/md/dm.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/md/dm.h 2004-10-18 14:56:29 -07:00 @@ -19,6 +19,9 @@ #define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x) #define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x) +#define DMEMIT(x...) sz += ((sz >= maxlen) ? \ + 0 : scnprintf(result + sz, maxlen - sz, x)) + /* * FIXME: I think this should be with the definition of sector_t * in types.h. @@ -113,6 +116,7 @@ void dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); void dm_table_unplug_all(struct dm_table *t); +int dm_table_flush_all(struct dm_table *t); /*----------------------------------------------------------------- * A registry of target types. diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c --- a/drivers/md/linear.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/md/linear.c 2004-10-18 14:56:29 -07:00 @@ -47,7 +47,6 @@ return hash->dev0; } - /** * linear_mergeable_bvec -- tell bio layer if a two requests can be merged * @q: request queue @@ -93,6 +92,27 @@ } } +static int linear_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + linear_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; i < mddev->raid_disks; i++) { + struct block_device *bdev = conf->disks[i].rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + return ret; +} static int linear_run (mddev_t *mddev) { @@ -137,7 +157,7 @@ */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->size = rdev->size; mddev->array_size += rdev->size; @@ -200,6 +220,7 @@ blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->unplug_fn = linear_unplug; + mddev->queue->issue_flush_fn = linear_issue_flush; return 0; out: diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/md/md.c 2004-10-18 14:56:27 -07:00 @@ -154,6 +154,39 @@ tmp = tmp->next;}) \ ) +int md_flush_mddev(mddev_t *mddev, sector_t *error_sector) +{ + struct list_head *tmp; + mdk_rdev_t *rdev; + int ret = 0; + + /* + * this list iteration is done without any locking in md?! + */ + ITERATE_RDEV(mddev, rdev, tmp) { + request_queue_t *r_queue = bdev_get_queue(rdev->bdev); + int err; + + if (!r_queue->issue_flush_fn) + err = -EOPNOTSUPP; + else + err = r_queue->issue_flush_fn(r_queue, rdev->bdev->bd_disk, error_sector); + + if (!ret) + ret = err; + } + + return ret; +} + +static int md_flush_all(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + + return md_flush_mddev(mddev, error_sector); +} + static int md_fail_request (request_queue_t *q, struct bio *bio) { bio_io_error(bio, bio->bi_size); @@ -373,7 +406,7 @@ return 0; fail: - printk(KERN_ERR "md: disabled device %s, could not read superblock.\n", + printk(KERN_WARNING "md: disabled device %s, could not read superblock.\n", bdevname(rdev->bdev,b)); return -EINVAL; } @@ -439,6 +472,31 @@ return csum; } +/* csum_partial is not consistent between different architectures. + * Some (i386) do a 32bit csum. Some (alpha) do 16 bit. + * This makes it hard for user-space to know what to do. + * So we use calc_sb_csum to set the checksum to allow working + * with older kernels, but allow calc_sb_csum_common to + * be used when checking if a checksum is correct, to + * make life easier for user-space tools that might write + * a superblock. + */ +static unsigned int calc_sb_csum_common(mdp_super_t *super) +{ + unsigned int disk_csum = super->sb_csum; + unsigned long long newcsum = 0; + unsigned int csum; + int i; + unsigned int *superc = (int*) super; + super->sb_csum = 0; + + for (i=0; i>32); + super->sb_csum = disk_csum; + return csum; +} + /* * Handle superblock details. * We want to be able to handle multiple superblock formats @@ -521,7 +579,8 @@ if (sb->raid_disks <= 0) goto abort; - if (calc_sb_csum(sb) != sb->sb_csum) { + if (calc_sb_csum(sb) != sb->sb_csum && + calc_sb_csum_common(sb) != sb->sb_csum) { printk(KERN_WARNING "md: invalid superblock checksum on %s\n", b); goto abort; @@ -745,11 +804,21 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) { unsigned int disk_csum, csum; + unsigned long long newcsum; int size = 256 + sb->max_dev*2; + unsigned int *isuper = (unsigned int*)sb; + int i; disk_csum = sb->sb_csum; sb->sb_csum = 0; - csum = csum_partial((void *)sb, size, 0); + newcsum = 0; + for (i=0; size>=4; size -= 4 ) + newcsum += le32_to_cpu(*isuper++); + + if (size == 2) + newcsum += le16_to_cpu(*(unsigned short*) isuper); + + csum = (newcsum & 0xffffffff) + (newcsum >> 32); sb->sb_csum = disk_csum; return csum; } @@ -1042,20 +1111,24 @@ /* * prevent the device from being mounted, repartitioned or * otherwise reused by a RAID array (or any other kernel - * subsystem), by opening the device. [simply getting an - * inode is not enough, the SCSI module usage code needs - * an explicit open() on the device] + * subsystem), by bd_claiming the device. */ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) { int err = 0; struct block_device *bdev; + char b[BDEVNAME_SIZE]; bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); - if (IS_ERR(bdev)) + if (IS_ERR(bdev)) { + printk(KERN_ERR "md: could not open %s.\n", + __bdevname(dev, b)); return PTR_ERR(bdev); + } err = bd_claim(bdev, rdev); if (err) { + printk(KERN_ERR "md: could not bd_claim %s.\n", + bdevname(bdev, b)); blkdev_put(bdev); return err; } @@ -1117,10 +1190,7 @@ static void print_desc(mdp_disk_t *desc) { - char b[BDEVNAME_SIZE]; - - printk(" DISK\n", desc->number, - __bdevname(MKDEV(desc->major, desc->minor), b), + printk(" DISK\n", desc->number, desc->major,desc->minor,desc->raid_disk,desc->state); } @@ -1312,8 +1382,7 @@ rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { - printk(KERN_ERR "md: could not alloc mem for %s!\n", - __bdevname(newdev, b)); + printk(KERN_ERR "md: could not alloc mem for new device!\n"); return ERR_PTR(-ENOMEM); } memset(rdev, 0, sizeof(*rdev)); @@ -1322,11 +1391,9 @@ goto abort_free; err = lock_rdev(rdev, newdev); - if (err) { - printk(KERN_ERR "md: could not lock %s.\n", - __bdevname(newdev, b)); + if (err) goto abort_free; - } + rdev->desc_nr = -1; rdev->faulty = 0; rdev->in_sync = 0; @@ -1615,6 +1682,8 @@ mddev->pers = pers[pnum]; spin_unlock(&pers_lock); + mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ + err = mddev->pers->run(mddev); if (err) { printk(KERN_ERR "md: pers->run() failed ...\n"); @@ -1645,6 +1714,7 @@ */ mddev->queue->queuedata = mddev; mddev->queue->make_request_fn = mddev->pers->make_request; + mddev->queue->issue_flush_fn = md_flush_all; mddev->changed = 1; return 0; @@ -1881,11 +1951,9 @@ mdk_rdev_t *start_rdev = NULL, *rdev; start_rdev = md_import_device(startdev, 0, 0); - if (IS_ERR(start_rdev)) { - printk(KERN_WARNING "md: could not import %s!\n", - __bdevname(startdev, b)); + if (IS_ERR(start_rdev)) return err; - } + /* NOTE: this can only work for 0.90.0 superblocks */ sb = (mdp_super_t*)page_address(start_rdev->sb_page); @@ -1916,12 +1984,9 @@ if (MAJOR(dev) != desc->major || MINOR(dev) != desc->minor) continue; rdev = md_import_device(dev, 0, 0); - if (IS_ERR(rdev)) { - printk(KERN_WARNING "md: could not import %s," - " trying to run array nevertheless.\n", - __bdevname(dev, b)); + if (IS_ERR(rdev)) continue; - } + list_add(&rdev->same_set, &pending_raid_disks); } @@ -2153,42 +2218,6 @@ return 0; } -static int hot_generate_error(mddev_t * mddev, dev_t dev) -{ - char b[BDEVNAME_SIZE]; - struct request_queue *q; - mdk_rdev_t *rdev; - - if (!mddev->pers) - return -ENODEV; - - printk(KERN_INFO "md: trying to generate %s error in %s ... \n", - __bdevname(dev, b), mdname(mddev)); - - rdev = find_rdev(mddev, dev); - if (!rdev) { - /* MD_BUG(); */ /* like hell - it's not a driver bug */ - return -ENXIO; - } - - if (rdev->desc_nr == -1) { - MD_BUG(); - return -EINVAL; - } - if (!rdev->in_sync) - return -ENODEV; - - q = bdev_get_queue(rdev->bdev); - if (!q) { - MD_BUG(); - return -ENODEV; - } - printk(KERN_INFO "md: okay, generating error!\n"); -// q->oneshot_error = 1; // disabled for now - - return 0; -} - static int hot_remove_disk(mddev_t * mddev, dev_t dev) { char b[BDEVNAME_SIZE]; @@ -2197,9 +2226,6 @@ if (!mddev->pers) return -ENODEV; - printk(KERN_INFO "md: trying to remove %s from %s ... \n", - __bdevname(dev, b), mdname(mddev)); - rdev = find_rdev(mddev, dev); if (!rdev) return -ENXIO; @@ -2227,9 +2253,6 @@ if (!mddev->pers) return -ENODEV; - printk(KERN_INFO "md: trying to hot-add %s to %s ... \n", - __bdevname(dev, b), mdname(mddev)); - if (mddev->major_version != 0) { printk(KERN_WARNING "%s: HOT_ADD may only be used with" " version-0 superblocks.\n", @@ -2489,7 +2512,6 @@ static int md_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - char b[BDEVNAME_SIZE]; int err = 0; void __user *argp = (void __user *)arg; struct hd_geometry __user *loc = argp; @@ -2548,8 +2570,7 @@ } err = autostart_array(new_decode_dev(arg)); if (err) { - printk(KERN_WARNING "md: autostart %s failed!\n", - __bdevname(arg, b)); + printk(KERN_WARNING "md: autostart failed!\n"); goto abort; } goto done; @@ -2690,9 +2711,7 @@ err = add_new_disk(mddev, &info); goto done_unlock; } - case HOT_GENERATE_ERROR: - err = hot_generate_error(mddev, new_decode_dev(arg)); - goto done_unlock; + case HOT_REMOVE_DISK: err = hot_remove_disk(mddev, new_decode_dev(arg)); goto done_unlock; @@ -2876,7 +2895,7 @@ return thread; } -void md_interrupt_thread(mdk_thread_t *thread) +static void md_interrupt_thread(mdk_thread_t *thread) { if (!thread->tsk) { MD_BUG(); @@ -2919,6 +2938,7 @@ if (!mddev->pers->error_handler) return; mddev->pers->error_handler(mddev,rdev); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); } @@ -2951,7 +2971,11 @@ unsigned long max_blocks, resync, res, dt, db, rt; resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; - max_blocks = mddev->size; + + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) + max_blocks = mddev->resync_max_sectors >> 1; + else + max_blocks = mddev->size; /* * Should not happen. @@ -3187,11 +3211,6 @@ return 0; } -void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors) -{ - rdev->bdev->bd_contains->bd_disk->sync_io += nr_sectors; -} - static int is_mddev_idle(mddev_t *mddev) { mdk_rdev_t * rdev; @@ -3204,8 +3223,12 @@ struct gendisk *disk = rdev->bdev->bd_contains->bd_disk; curr_events = disk_stat_read(disk, read_sectors) + disk_stat_read(disk, write_sectors) - - disk->sync_io; - if ((curr_events - rdev->last_events) > 32) { + atomic_read(&disk->sync_io); + /* Allow some slack between valud of curr_events and last_events, + * as there are some uninteresting races. + * Note: the following is an unsigned comparison. + */ + if ((curr_events - rdev->last_events + 32) > 64) { rdev->last_events = curr_events; idle = 0; } @@ -3339,7 +3362,14 @@ } } while (mddev->curr_resync < 2); - max_sectors = mddev->size << 1; + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) + /* resync follows the size requested by the personality, + * which default to physical size, but can be virtual size + */ + max_sectors = mddev->resync_max_sectors; + else + /* recovery follows the physical size of devices */ + max_sectors = mddev->size << 1; printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" @@ -3697,7 +3727,6 @@ static void autostart_arrays(int part) { - char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; int i; @@ -3707,11 +3736,9 @@ dev_t dev = detected_devices[i]; rdev = md_import_device(dev,0, 0); - if (IS_ERR(rdev)) { - printk(KERN_ALERT "md: could not import %s!\n", - __bdevname(dev, b)); + if (IS_ERR(rdev)) continue; - } + if (rdev->faulty) { MD_BUG(); continue; @@ -3762,7 +3789,6 @@ EXPORT_SYMBOL(register_md_personality); EXPORT_SYMBOL(unregister_md_personality); EXPORT_SYMBOL(md_error); -EXPORT_SYMBOL(md_sync_acct); EXPORT_SYMBOL(md_done_sync); EXPORT_SYMBOL(md_write_start); EXPORT_SYMBOL(md_write_end); @@ -3771,6 +3797,5 @@ EXPORT_SYMBOL(md_unregister_thread); EXPORT_SYMBOL(md_wakeup_thread); EXPORT_SYMBOL(md_print_devices); -EXPORT_SYMBOL(md_interrupt_thread); EXPORT_SYMBOL(md_check_recovery); MODULE_LICENSE("GPL"); diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c --- a/drivers/md/multipath.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/md/multipath.c 2004-10-18 14:56:29 -07:00 @@ -99,12 +99,12 @@ * operation and are ready to return a success/failure code to the buffer * cache layer. */ -static void multipath_end_bh_io (struct multipath_bh *mp_bh, int uptodate) +static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) { struct bio *bio = mp_bh->master_bio; multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); - bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); + bio_endio(bio, bio->bi_size, err); mempool_free(mp_bh, conf->pool); } @@ -119,8 +119,8 @@ return 1; if (uptodate) - multipath_end_bh_io(mp_bh, uptodate); - else if ((bio->bi_rw & (1 << BIO_RW_AHEAD)) == 0) { + multipath_end_bh_io(mp_bh, 0); + else if (!bio_rw_ahead(bio)) { /* * oops, IO error: */ @@ -131,7 +131,7 @@ (unsigned long long)bio->bi_sector); multipath_reschedule_retry(mp_bh); } else - multipath_end_bh_io(mp_bh, 0); + multipath_end_bh_io(mp_bh, error); rdev_dec_pending(rdev, conf->mddev); return 0; } @@ -217,6 +217,31 @@ seq_printf (seq, "]"); } +static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + multipath_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->multipaths[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} /* * Careful, this can execute in IRQ contexts as well! @@ -300,7 +325,7 @@ */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); conf->working_disks++; rdev->raid_disk = path; @@ -377,7 +402,7 @@ " error for block %llu\n", bdevname(bio->bi_bdev,b), (unsigned long long)bio->bi_sector); - multipath_end_bh_io(mp_bh, 0); + multipath_end_bh_io(mp_bh, -EIO); } else { printk(KERN_ERR "multipath: %s: redirecting sector %llu" " to another IO path\n", @@ -435,6 +460,8 @@ mddev->queue->unplug_fn = multipath_unplug; + mddev->queue->issue_flush_fn = multipath_issue_flush; + conf->working_disks = 0; ITERATE_RDEV(mddev,rdev,tmp) { disk_idx = rdev->raid_disk; @@ -452,7 +479,7 @@ * a merge_bvec_fn to be involved in multipath */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!rdev->faulty) conf->working_disks++; diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c --- a/drivers/md/raid0.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/md/raid0.c 2004-10-18 14:56:32 -07:00 @@ -40,6 +40,31 @@ } } +static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid0_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t **devlist = conf->strip_zone[0].dev; + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + struct block_device *bdev = devlist[i]->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret =r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + return ret; +} + + static int create_strip_zones (mddev_t *mddev) { int i, c, j; @@ -137,7 +162,7 @@ if (rdev1->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!smallest || (rdev1->size size)) smallest = rdev1; @@ -218,6 +243,8 @@ } mddev->queue->unplug_fn = raid0_unplug; + + mddev->queue->issue_flush_fn = raid0_issue_flush; printk("raid0: done.\n"); return 0; diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c --- a/drivers/md/raid1.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/md/raid1.c 2004-10-18 14:56:32 -07:00 @@ -24,10 +24,6 @@ #include -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER -#define MD_PERSONALITY - /* * Number of guaranteed r1bios in case of extreme VM load: */ @@ -44,13 +40,12 @@ { struct pool_info *pi = data; r1bio_t *r1_bio; + int size = offsetof(r1bio_t, bios[pi->raid_disks]); /* allocate a r1bio with room for raid_disks entries in the bios array */ - r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*pi->raid_disks, - gfp_flags); + r1_bio = kmalloc(size, gfp_flags); if (r1_bio) - memset(r1_bio, 0, sizeof(*r1_bio) + - sizeof(struct bio*) * pi->raid_disks); + memset(r1_bio, 0, size); else unplug_slaves(pi->mddev); @@ -104,7 +99,7 @@ bio->bi_io_vec[i].bv_page = page; } - r1_bio->master_bio = bio; + r1_bio->master_bio = NULL; return r1_bio; @@ -189,32 +184,6 @@ spin_unlock_irqrestore(&conf->resync_lock, flags); } -static int map(mddev_t *mddev, mdk_rdev_t **rdevp) -{ - conf_t *conf = mddev_to_conf(mddev); - int i, disks = conf->raid_disks; - - /* - * Later we do read balancing on the read side - * now we use the first available disk. - */ - - spin_lock_irq(&conf->device_lock); - for (i = 0; i < disks; i++) { - mdk_rdev_t *rdev = conf->mirrors[i].rdev; - if (rdev && rdev->in_sync) { - *rdevp = rdev; - atomic_inc(&rdev->nr_pending); - spin_unlock_irq(&conf->device_lock); - return i; - } - } - spin_unlock_irq(&conf->device_lock); - - printk(KERN_ERR "raid1_map(): huh, no more operational devices?\n"); - return -1; -} - static void reschedule_retry(r1bio_t *r1_bio) { unsigned long flags; @@ -292,8 +261,9 @@ * oops, read error: */ char b[BDEVNAME_SIZE]; - printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n", - bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector); + if (printk_ratelimit()) + printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n", + bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector); reschedule_retry(r1_bio); } @@ -363,11 +333,11 @@ * * The rdev for the device selected will have nr_pending incremented. */ -static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio) +static int read_balance(conf_t *conf, r1bio_t *r1_bio) { const unsigned long this_sector = r1_bio->sector; int new_disk = conf->last_used, disk = new_disk; - const int sectors = bio->bi_size >> 9; + const int sectors = r1_bio->sectors; sector_t new_distance, current_distance; spin_lock_irq(&conf->device_lock); @@ -378,14 +348,14 @@ */ if (conf->mddev->recovery_cp < MaxSector && (this_sector + sectors >= conf->next_resync)) { - /* make sure that disk is operational */ + /* Choose the first operation device, for consistancy */ new_disk = 0; while (!conf->mirrors[new_disk].rdev || !conf->mirrors[new_disk].rdev->in_sync) { new_disk++; if (new_disk == conf->raid_disks) { - new_disk = 0; + new_disk = -1; break; } } @@ -400,7 +370,7 @@ new_disk = conf->raid_disks; new_disk--; if (new_disk == disk) { - new_disk = conf->last_used; + new_disk = -1; goto rb_out; } } @@ -440,13 +410,13 @@ } while (disk != conf->last_used); rb_out: - r1_bio->read_disk = new_disk; - conf->next_seq_sect = this_sector + sectors; - conf->last_used = new_disk; - if (conf->mirrors[new_disk].rdev) + if (new_disk >= 0) { + conf->next_seq_sect = this_sector + sectors; + conf->last_used = new_disk; atomic_inc(&conf->mirrors[new_disk].rdev->nr_pending); + } spin_unlock_irq(&conf->device_lock); return new_disk; @@ -481,6 +451,32 @@ unplug_slaves(q->queuedata); } +static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + conf_t *conf = mddev_to_conf(mddev); + unsigned long flags; + int i, ret = 0; + + spin_lock_irqsave(&conf->device_lock, flags); + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->mirrors[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (r_queue->issue_flush_fn) { + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + } + spin_unlock_irqrestore(&conf->device_lock, flags); + return ret; +} + /* * Throttle resync depth, so that we can both get proper overlapping of * requests, but are still able to handle normal requests quickly. @@ -545,15 +541,26 @@ r1_bio->mddev = mddev; r1_bio->sector = bio->bi_sector; + r1_bio->state = 0; + if (bio_data_dir(bio) == READ) { /* * read balancing logic: */ - mirror = conf->mirrors + read_balance(conf, bio, r1_bio); + int rdisk = read_balance(conf, r1_bio); + + if (rdisk < 0) { + /* couldn't find anywhere to read from */ + raid_end_bio_io(r1_bio); + return 0; + } + mirror = conf->mirrors + rdisk; + + r1_bio->read_disk = rdisk; read_bio = bio_clone(bio, GFP_NOIO); - r1_bio->bios[r1_bio->read_disk] = read_bio; + r1_bio->bios[rdisk] = read_bio; read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset; read_bio->bi_bdev = mirror->rdev->bdev; @@ -746,7 +753,7 @@ */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); p->head_position = 0; rdev->raid_disk = mirror; @@ -877,7 +884,7 @@ atomic_inc(&conf->mirrors[i].rdev->nr_pending); atomic_inc(&r1_bio->remaining); - md_sync_acct(conf->mirrors[i].rdev, wbio->bi_size >> 9); + md_sync_acct(conf->mirrors[i].rdev->bdev, wbio->bi_size >> 9); generic_make_request(wbio); } @@ -925,7 +932,7 @@ } else { int disk; bio = r1_bio->bios[r1_bio->read_disk]; - if ((disk=map(mddev, &rdev)) == -1) { + if ((disk=read_balance(conf, r1_bio)) == -1) { printk(KERN_ALERT "raid1: %s: unrecoverable I/O" " read error for block %llu\n", bdevname(bio->bi_bdev,b), @@ -935,10 +942,12 @@ r1_bio->bios[r1_bio->read_disk] = NULL; r1_bio->read_disk = disk; r1_bio->bios[r1_bio->read_disk] = bio; - printk(KERN_ERR "raid1: %s: redirecting sector %llu to" - " another mirror\n", - bdevname(rdev->bdev,b), - (unsigned long long)r1_bio->sector); + rdev = conf->mirrors[disk].rdev; + if (printk_ratelimit()) + printk(KERN_ERR "raid1: %s: redirecting sector %llu to" + " another mirror\n", + bdevname(rdev->bdev,b), + (unsigned long long)r1_bio->sector); bio->bi_bdev = rdev->bdev; bio->bi_sector = r1_bio->sector + rdev->data_offset; bio->bi_rw = READ; @@ -1117,7 +1126,7 @@ bio = r1_bio->bios[disk]; r1_bio->sectors = nr_sectors; - md_sync_acct(mirror->rdev, nr_sectors); + md_sync_acct(mirror->rdev->bdev, nr_sectors); generic_make_request(bio); @@ -1168,6 +1177,7 @@ mddev->queue->unplug_fn = raid1_unplug; + mddev->queue->issue_flush_fn = raid1_issue_flush; ITERATE_RDEV(mddev, rdev, tmp) { disk_idx = rdev->raid_disk; @@ -1186,7 +1196,7 @@ */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; if (!rdev->faulty && rdev->in_sync) diff -Nru a/drivers/md/raid10.c b/drivers/md/raid10.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/md/raid10.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,1780 @@ +/* + * raid10.c : Multiple Devices driver for Linux + * + * Copyright (C) 2000-2004 Neil Brown + * + * RAID-10 support for md. + * + * Base on code in raid1.c. See raid1.c for futher copyright information. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +/* + * RAID10 provides a combination of RAID0 and RAID1 functionality. + * The layout of data is defined by + * chunk_size + * raid_disks + * near_copies (stored in low byte of layout) + * far_copies (stored in second byte of layout) + * + * The data to be stored is divided into chunks using chunksize. + * Each device is divided into far_copies sections. + * In each section, chunks are laid out in a style similar to raid0, but + * near_copies copies of each chunk is stored (each on a different drive). + * The starting device for each section is offset near_copies from the starting + * device of the previous section. + * Thus there are (near_copies*far_copies) of each chunk, and each is on a different + * drive. + * near_copies and far_copies must be at least one, and there product is at most + * raid_disks. + */ + +/* + * Number of guaranteed r10bios in case of extreme VM load: + */ +#define NR_RAID10_BIOS 256 + +static void unplug_slaves(mddev_t *mddev); + +static void * r10bio_pool_alloc(int gfp_flags, void *data) +{ + conf_t *conf = data; + r10bio_t *r10_bio; + int size = offsetof(struct r10bio_s, devs[conf->copies]); + + /* allocate a r10bio with room for raid_disks entries in the bios array */ + r10_bio = kmalloc(size, gfp_flags); + if (r10_bio) + memset(r10_bio, 0, size); + else + unplug_slaves(conf->mddev); + + return r10_bio; +} + +static void r10bio_pool_free(void *r10_bio, void *data) +{ + kfree(r10_bio); +} + +#define RESYNC_BLOCK_SIZE (64*1024) +//#define RESYNC_BLOCK_SIZE PAGE_SIZE +#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9) +#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE) +#define RESYNC_WINDOW (2048*1024) + +/* + * When performing a resync, we need to read and compare, so + * we need as many pages are there are copies. + * When performing a recovery, we need 2 bios, one for read, + * one for write (we recover only one drive per r10buf) + * + */ +static void * r10buf_pool_alloc(int gfp_flags, void *data) +{ + conf_t *conf = data; + struct page *page; + r10bio_t *r10_bio; + struct bio *bio; + int i, j; + int nalloc; + + r10_bio = r10bio_pool_alloc(gfp_flags, conf); + if (!r10_bio) { + unplug_slaves(conf->mddev); + return NULL; + } + + if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery)) + nalloc = conf->copies; /* resync */ + else + nalloc = 2; /* recovery */ + + /* + * Allocate bios. + */ + for (j = nalloc ; j-- ; ) { + bio = bio_alloc(gfp_flags, RESYNC_PAGES); + if (!bio) + goto out_free_bio; + r10_bio->devs[j].bio = bio; + } + /* + * Allocate RESYNC_PAGES data pages and attach them + * where needed. + */ + for (j = 0 ; j < nalloc; j++) { + bio = r10_bio->devs[j].bio; + for (i = 0; i < RESYNC_PAGES; i++) { + page = alloc_page(gfp_flags); + if (unlikely(!page)) + goto out_free_pages; + + bio->bi_io_vec[i].bv_page = page; + } + } + + return r10_bio; + +out_free_pages: + for ( ; i > 0 ; i--) + __free_page(bio->bi_io_vec[i-1].bv_page); + while (j--) + for (i = 0; i < RESYNC_PAGES ; i++) + __free_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page); + j = -1; +out_free_bio: + while ( ++j < nalloc ) + bio_put(r10_bio->devs[j].bio); + r10bio_pool_free(r10_bio, conf); + return NULL; +} + +static void r10buf_pool_free(void *__r10_bio, void *data) +{ + int i; + conf_t *conf = data; + r10bio_t *r10bio = __r10_bio; + int j; + + for (j=0; j < conf->copies; j++) { + struct bio *bio = r10bio->devs[j].bio; + if (bio) { + for (i = 0; i < RESYNC_PAGES; i++) { + __free_page(bio->bi_io_vec[i].bv_page); + bio->bi_io_vec[i].bv_page = NULL; + } + bio_put(bio); + } + } + r10bio_pool_free(r10bio, conf); +} + +static void put_all_bios(conf_t *conf, r10bio_t *r10_bio) +{ + int i; + + for (i = 0; i < conf->copies; i++) { + struct bio **bio = & r10_bio->devs[i].bio; + if (*bio) + bio_put(*bio); + *bio = NULL; + } +} + +static inline void free_r10bio(r10bio_t *r10_bio) +{ + unsigned long flags; + + conf_t *conf = mddev_to_conf(r10_bio->mddev); + + /* + * Wake up any possible resync thread that waits for the device + * to go idle. + */ + spin_lock_irqsave(&conf->resync_lock, flags); + if (!--conf->nr_pending) { + wake_up(&conf->wait_idle); + wake_up(&conf->wait_resume); + } + spin_unlock_irqrestore(&conf->resync_lock, flags); + + put_all_bios(conf, r10_bio); + mempool_free(r10_bio, conf->r10bio_pool); +} + +static inline void put_buf(r10bio_t *r10_bio) +{ + conf_t *conf = mddev_to_conf(r10_bio->mddev); + unsigned long flags; + + mempool_free(r10_bio, conf->r10buf_pool); + + spin_lock_irqsave(&conf->resync_lock, flags); + if (!conf->barrier) + BUG(); + --conf->barrier; + wake_up(&conf->wait_resume); + wake_up(&conf->wait_idle); + + if (!--conf->nr_pending) { + wake_up(&conf->wait_idle); + wake_up(&conf->wait_resume); + } + spin_unlock_irqrestore(&conf->resync_lock, flags); +} + +static void reschedule_retry(r10bio_t *r10_bio) +{ + unsigned long flags; + mddev_t *mddev = r10_bio->mddev; + conf_t *conf = mddev_to_conf(mddev); + + spin_lock_irqsave(&conf->device_lock, flags); + list_add(&r10_bio->retry_list, &conf->retry_list); + spin_unlock_irqrestore(&conf->device_lock, flags); + + md_wakeup_thread(mddev->thread); +} + +/* + * raid_end_bio_io() is called when we have finished servicing a mirrored + * operation and are ready to return a success/failure code to the buffer + * cache layer. + */ +static void raid_end_bio_io(r10bio_t *r10_bio) +{ + struct bio *bio = r10_bio->master_bio; + + bio_endio(bio, bio->bi_size, + test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO); + free_r10bio(r10_bio); +} + +/* + * Update disk head position estimator based on IRQ completion info. + */ +static inline void update_head_pos(int slot, r10bio_t *r10_bio) +{ + conf_t *conf = mddev_to_conf(r10_bio->mddev); + + conf->mirrors[r10_bio->devs[slot].devnum].head_position = + r10_bio->devs[slot].addr + (r10_bio->sectors); +} + +static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error) +{ + int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); + int slot, dev; + conf_t *conf = mddev_to_conf(r10_bio->mddev); + + if (bio->bi_size) + return 1; + + slot = r10_bio->read_slot; + dev = r10_bio->devs[slot].devnum; + /* + * this branch is our 'one mirror IO has finished' event handler: + */ + if (!uptodate) + md_error(r10_bio->mddev, conf->mirrors[dev].rdev); + else + /* + * Set R10BIO_Uptodate in our master bio, so that + * we will return a good error code to the higher + * levels even if IO on some other mirrored buffer fails. + * + * The 'master' represents the composite IO operation to + * user-side. So if something waits for IO, then it will + * wait for the 'master' bio. + */ + set_bit(R10BIO_Uptodate, &r10_bio->state); + + update_head_pos(slot, r10_bio); + + /* + * we have only one bio on the read side + */ + if (uptodate) + raid_end_bio_io(r10_bio); + else { + /* + * oops, read error: + */ + char b[BDEVNAME_SIZE]; + if (printk_ratelimit()) + printk(KERN_ERR "raid10: %s: rescheduling sector %llu\n", + bdevname(conf->mirrors[dev].rdev->bdev,b), (unsigned long long)r10_bio->sector); + reschedule_retry(r10_bio); + } + + rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); + return 0; +} + +static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error) +{ + int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); + int slot, dev; + conf_t *conf = mddev_to_conf(r10_bio->mddev); + + if (bio->bi_size) + return 1; + + for (slot = 0; slot < conf->copies; slot++) + if (r10_bio->devs[slot].bio == bio) + break; + dev = r10_bio->devs[slot].devnum; + + /* + * this branch is our 'one mirror IO has finished' event handler: + */ + if (!uptodate) + md_error(r10_bio->mddev, conf->mirrors[dev].rdev); + else + /* + * Set R10BIO_Uptodate in our master bio, so that + * we will return a good error code for to the higher + * levels even if IO on some other mirrored buffer fails. + * + * The 'master' represents the composite IO operation to + * user-side. So if something waits for IO, then it will + * wait for the 'master' bio. + */ + set_bit(R10BIO_Uptodate, &r10_bio->state); + + update_head_pos(slot, r10_bio); + + /* + * + * Let's see if all mirrored write operations have finished + * already. + */ + if (atomic_dec_and_test(&r10_bio->remaining)) { + md_write_end(r10_bio->mddev); + raid_end_bio_io(r10_bio); + } + + rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); + return 0; +} + + +/* + * RAID10 layout manager + * Aswell as the chunksize and raid_disks count, there are two + * parameters: near_copies and far_copies. + * near_copies * far_copies must be <= raid_disks. + * Normally one of these will be 1. + * If both are 1, we get raid0. + * If near_copies == raid_disks, we get raid1. + * + * Chunks are layed out in raid0 style with near_copies copies of the + * first chunk, followed by near_copies copies of the next chunk and + * so on. + * If far_copies > 1, then after 1/far_copies of the array has been assigned + * as described above, we start again with a device offset of near_copies. + * So we effectively have another copy of the whole array further down all + * the drives, but with blocks on different drives. + * With this layout, and block is never stored twice on the one device. + * + * raid10_find_phys finds the sector offset of a given virtual sector + * on each device that it is on. If a block isn't on a device, + * that entry in the array is set to MaxSector. + * + * raid10_find_virt does the reverse mapping, from a device and a + * sector offset to a virtual address + */ + +static void raid10_find_phys(conf_t *conf, r10bio_t *r10bio) +{ + int n,f; + sector_t sector; + sector_t chunk; + sector_t stripe; + int dev; + + int slot = 0; + + /* now calculate first sector/dev */ + chunk = r10bio->sector >> conf->chunk_shift; + sector = r10bio->sector & conf->chunk_mask; + + chunk *= conf->near_copies; + stripe = chunk; + dev = sector_div(stripe, conf->raid_disks); + + sector += stripe << conf->chunk_shift; + + /* and calculate all the others */ + for (n=0; n < conf->near_copies; n++) { + int d = dev; + sector_t s = sector; + r10bio->devs[slot].addr = sector; + r10bio->devs[slot].devnum = d; + slot++; + + for (f = 1; f < conf->far_copies; f++) { + d += conf->near_copies; + if (d >= conf->raid_disks) + d -= conf->raid_disks; + s += conf->stride; + r10bio->devs[slot].devnum = d; + r10bio->devs[slot].addr = s; + slot++; + } + dev++; + if (dev >= conf->raid_disks) { + dev = 0; + sector += (conf->chunk_mask + 1); + } + } + BUG_ON(slot != conf->copies); +} + +static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev) +{ + sector_t offset, chunk, vchunk; + + while (sector > conf->stride) { + sector -= conf->stride; + if (dev < conf->near_copies) + dev += conf->raid_disks - conf->near_copies; + else + dev -= conf->near_copies; + } + + offset = sector & conf->chunk_mask; + chunk = sector >> conf->chunk_shift; + vchunk = chunk * conf->raid_disks + dev; + sector_div(vchunk, conf->near_copies); + return (vchunk << conf->chunk_shift) + offset; +} + +/** + * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged + * @q: request queue + * @bio: the buffer head that's been built up so far + * @biovec: the request that could be merged to it. + * + * Return amount of bytes we can accept at this offset + * If near_copies == raid_disk, there are no striping issues, + * but in that case, the function isn't called at all. + */ +static int raid10_mergeable_bvec(request_queue_t *q, struct bio *bio, + struct bio_vec *bio_vec) +{ + mddev_t *mddev = q->queuedata; + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); + int max; + unsigned int chunk_sectors = mddev->chunk_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; + + max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; + if (max < 0) max = 0; /* bio_add cannot handle a negative return */ + if (max <= bio_vec->bv_len && bio_sectors == 0) + return bio_vec->bv_len; + else + return max; +} + +/* + * This routine returns the disk from which the requested read should + * be done. There is a per-array 'next expected sequential IO' sector + * number - if this matches on the next IO then we use the last disk. + * There is also a per-disk 'last know head position' sector that is + * maintained from IRQ contexts, both the normal and the resync IO + * completion handlers update this position correctly. If there is no + * perfect sequential match then we pick the disk whose head is closest. + * + * If there are 2 mirrors in the same 2 devices, performance degrades + * because position is mirror, not device based. + * + * The rdev for the device selected will have nr_pending incremented. + */ + +/* + * FIXME: possibly should rethink readbalancing and do it differently + * depending on near_copies / far_copies geometry. + */ +static int read_balance(conf_t *conf, r10bio_t *r10_bio) +{ + const unsigned long this_sector = r10_bio->sector; + int disk, slot, nslot; + const int sectors = r10_bio->sectors; + sector_t new_distance, current_distance; + + raid10_find_phys(conf, r10_bio); + spin_lock_irq(&conf->device_lock); + /* + * Check if we can balance. We can balance on the whole + * device if no resync is going on, or below the resync window. + * We take the first readable disk when above the resync window. + */ + if (conf->mddev->recovery_cp < MaxSector + && (this_sector + sectors >= conf->next_resync)) { + /* make sure that disk is operational */ + slot = 0; + disk = r10_bio->devs[slot].devnum; + + while (!conf->mirrors[disk].rdev || + !conf->mirrors[disk].rdev->in_sync) { + slot++; + if (slot == conf->copies) { + slot = 0; + disk = -1; + break; + } + disk = r10_bio->devs[slot].devnum; + } + goto rb_out; + } + + + /* make sure the disk is operational */ + slot = 0; + disk = r10_bio->devs[slot].devnum; + while (!conf->mirrors[disk].rdev || + !conf->mirrors[disk].rdev->in_sync) { + slot ++; + if (slot == conf->copies) { + disk = -1; + goto rb_out; + } + disk = r10_bio->devs[slot].devnum; + } + + + current_distance = abs(this_sector - conf->mirrors[disk].head_position); + + /* Find the disk whose head is closest */ + + for (nslot = slot; nslot < conf->copies; nslot++) { + int ndisk = r10_bio->devs[nslot].devnum; + + + if (!conf->mirrors[ndisk].rdev || + !conf->mirrors[ndisk].rdev->in_sync) + continue; + + if (!atomic_read(&conf->mirrors[ndisk].rdev->nr_pending)) { + disk = ndisk; + slot = nslot; + break; + } + new_distance = abs(r10_bio->devs[nslot].addr - + conf->mirrors[ndisk].head_position); + if (new_distance < current_distance) { + current_distance = new_distance; + disk = ndisk; + slot = nslot; + } + } + +rb_out: + r10_bio->read_slot = slot; +/* conf->next_seq_sect = this_sector + sectors;*/ + + if (disk >= 0 && conf->mirrors[disk].rdev) + atomic_inc(&conf->mirrors[disk].rdev->nr_pending); + spin_unlock_irq(&conf->device_lock); + + return disk; +} + +static void unplug_slaves(mddev_t *mddev) +{ + conf_t *conf = mddev_to_conf(mddev); + int i; + unsigned long flags; + + spin_lock_irqsave(&conf->device_lock, flags); + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->mirrors[i].rdev; + if (rdev && atomic_read(&rdev->nr_pending)) { + request_queue_t *r_queue = bdev_get_queue(rdev->bdev); + + atomic_inc(&rdev->nr_pending); + spin_unlock_irqrestore(&conf->device_lock, flags); + + if (r_queue->unplug_fn) + r_queue->unplug_fn(r_queue); + + spin_lock_irqsave(&conf->device_lock, flags); + atomic_dec(&rdev->nr_pending); + } + } + spin_unlock_irqrestore(&conf->device_lock, flags); +} +static void raid10_unplug(request_queue_t *q) +{ + unplug_slaves(q->queuedata); +} + +static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + conf_t *conf = mddev_to_conf(mddev); + unsigned long flags; + int i, ret = 0; + + spin_lock_irqsave(&conf->device_lock, flags); + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->mirrors[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (r_queue->issue_flush_fn) { + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + } + spin_unlock_irqrestore(&conf->device_lock, flags); + return ret; +} + +/* + * Throttle resync depth, so that we can both get proper overlapping of + * requests, but are still able to handle normal requests quickly. + */ +#define RESYNC_DEPTH 32 + +static void device_barrier(conf_t *conf, sector_t sect) +{ + spin_lock_irq(&conf->resync_lock); + wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume), + conf->resync_lock, unplug_slaves(conf->mddev)); + + if (!conf->barrier++) { + wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, + conf->resync_lock, unplug_slaves(conf->mddev)); + if (conf->nr_pending) + BUG(); + } + wait_event_lock_irq(conf->wait_resume, conf->barrier < RESYNC_DEPTH, + conf->resync_lock, unplug_slaves(conf->mddev)); + conf->next_resync = sect; + spin_unlock_irq(&conf->resync_lock); +} + +static int make_request(request_queue_t *q, struct bio * bio) +{ + mddev_t *mddev = q->queuedata; + conf_t *conf = mddev_to_conf(mddev); + mirror_info_t *mirror; + r10bio_t *r10_bio; + struct bio *read_bio; + int i; + int chunk_sects = conf->chunk_mask + 1; + + /* If this request crosses a chunk boundary, we need to + * split it. This will only happen for 1 PAGE (or less) requests. + */ + if (unlikely( (bio->bi_sector & conf->chunk_mask) + (bio->bi_size >> 9) + > chunk_sects && + conf->near_copies < conf->raid_disks)) { + struct bio_pair *bp; + /* Sanity check -- queue functions should prevent this happening */ + if (bio->bi_vcnt != 1 || + bio->bi_idx != 0) + goto bad_map; + /* This is a one page bio that upper layers + * refuse to split for us, so we need to split it. + */ + bp = bio_split(bio, bio_split_pool, + chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); + if (make_request(q, &bp->bio1)) + generic_make_request(&bp->bio1); + if (make_request(q, &bp->bio2)) + generic_make_request(&bp->bio2); + + bio_pair_release(bp); + return 0; + bad_map: + printk("raid10_make_request bug: can't convert block across chunks" + " or bigger than %dk %llu %d\n", chunk_sects/2, + (unsigned long long)bio->bi_sector, bio->bi_size >> 10); + + bio_io_error(bio, bio->bi_size); + return 0; + } + + /* + * Register the new request and wait if the reconstruction + * thread has put up a bar for new requests. + * Continue immediately if no resync is active currently. + */ + spin_lock_irq(&conf->resync_lock); + wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock, ); + conf->nr_pending++; + spin_unlock_irq(&conf->resync_lock); + + if (bio_data_dir(bio)==WRITE) { + disk_stat_inc(mddev->gendisk, writes); + disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bio)); + } else { + disk_stat_inc(mddev->gendisk, reads); + disk_stat_add(mddev->gendisk, read_sectors, bio_sectors(bio)); + } + + r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO); + + r10_bio->master_bio = bio; + r10_bio->sectors = bio->bi_size >> 9; + + r10_bio->mddev = mddev; + r10_bio->sector = bio->bi_sector; + + if (bio_data_dir(bio) == READ) { + /* + * read balancing logic: + */ + int disk = read_balance(conf, r10_bio); + int slot = r10_bio->read_slot; + if (disk < 0) { + raid_end_bio_io(r10_bio); + return 0; + } + mirror = conf->mirrors + disk; + + read_bio = bio_clone(bio, GFP_NOIO); + + r10_bio->devs[slot].bio = read_bio; + + read_bio->bi_sector = r10_bio->devs[slot].addr + + mirror->rdev->data_offset; + read_bio->bi_bdev = mirror->rdev->bdev; + read_bio->bi_end_io = raid10_end_read_request; + read_bio->bi_rw = READ; + read_bio->bi_private = r10_bio; + + generic_make_request(read_bio); + return 0; + } + + /* + * WRITE: + */ + /* first select target devices under spinlock and + * inc refcount on their rdev. Record them by setting + * bios[x] to bio + */ + raid10_find_phys(conf, r10_bio); + spin_lock_irq(&conf->device_lock); + for (i = 0; i < conf->copies; i++) { + int d = r10_bio->devs[i].devnum; + if (conf->mirrors[d].rdev && + !conf->mirrors[d].rdev->faulty) { + atomic_inc(&conf->mirrors[d].rdev->nr_pending); + r10_bio->devs[i].bio = bio; + } else + r10_bio->devs[i].bio = NULL; + } + spin_unlock_irq(&conf->device_lock); + + atomic_set(&r10_bio->remaining, 1); + md_write_start(mddev); + for (i = 0; i < conf->copies; i++) { + struct bio *mbio; + int d = r10_bio->devs[i].devnum; + if (!r10_bio->devs[i].bio) + continue; + + mbio = bio_clone(bio, GFP_NOIO); + r10_bio->devs[i].bio = mbio; + + mbio->bi_sector = r10_bio->devs[i].addr+ + conf->mirrors[d].rdev->data_offset; + mbio->bi_bdev = conf->mirrors[d].rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE; + mbio->bi_private = r10_bio; + + atomic_inc(&r10_bio->remaining); + generic_make_request(mbio); + } + + if (atomic_dec_and_test(&r10_bio->remaining)) { + md_write_end(mddev); + raid_end_bio_io(r10_bio); + } + + return 0; +} + +static void status(struct seq_file *seq, mddev_t *mddev) +{ + conf_t *conf = mddev_to_conf(mddev); + int i; + + if (conf->near_copies < conf->raid_disks) + seq_printf(seq, " %dK chunks", mddev->chunk_size/1024); + if (conf->near_copies > 1) + seq_printf(seq, " %d near-copies", conf->near_copies); + if (conf->far_copies > 1) + seq_printf(seq, " %d far-copies", conf->far_copies); + + seq_printf(seq, " [%d/%d] [", conf->raid_disks, + conf->working_disks); + for (i = 0; i < conf->raid_disks; i++) + seq_printf(seq, "%s", + conf->mirrors[i].rdev && + conf->mirrors[i].rdev->in_sync ? "U" : "_"); + seq_printf(seq, "]"); +} + +static void error(mddev_t *mddev, mdk_rdev_t *rdev) +{ + char b[BDEVNAME_SIZE]; + conf_t *conf = mddev_to_conf(mddev); + + /* + * If it is not operational, then we have already marked it as dead + * else if it is the last working disks, ignore the error, let the + * next level up know. + * else mark the drive as failed + */ + if (rdev->in_sync + && conf->working_disks == 1) + /* + * Don't fail the drive, just return an IO error. + * The test should really be more sophisticated than + * "working_disks == 1", but it isn't critical, and + * can wait until we do more sophisticated "is the drive + * really dead" tests... + */ + return; + if (rdev->in_sync) { + mddev->degraded++; + conf->working_disks--; + /* + * if recovery is running, make sure it aborts. + */ + set_bit(MD_RECOVERY_ERR, &mddev->recovery); + } + rdev->in_sync = 0; + rdev->faulty = 1; + mddev->sb_dirty = 1; + printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n" + " Operation continuing on %d devices\n", + bdevname(rdev->bdev,b), conf->working_disks); +} + +static void print_conf(conf_t *conf) +{ + int i; + mirror_info_t *tmp; + + printk("RAID10 conf printout:\n"); + if (!conf) { + printk("(!conf)\n"); + return; + } + printk(" --- wd:%d rd:%d\n", conf->working_disks, + conf->raid_disks); + + for (i = 0; i < conf->raid_disks; i++) { + char b[BDEVNAME_SIZE]; + tmp = conf->mirrors + i; + if (tmp->rdev) + printk(" disk %d, wo:%d, o:%d, dev:%s\n", + i, !tmp->rdev->in_sync, !tmp->rdev->faulty, + bdevname(tmp->rdev->bdev,b)); + } +} + +static void close_sync(conf_t *conf) +{ + spin_lock_irq(&conf->resync_lock); + wait_event_lock_irq(conf->wait_resume, !conf->barrier, + conf->resync_lock, unplug_slaves(conf->mddev)); + spin_unlock_irq(&conf->resync_lock); + + if (conf->barrier) BUG(); + if (waitqueue_active(&conf->wait_idle)) BUG(); + + mempool_destroy(conf->r10buf_pool); + conf->r10buf_pool = NULL; +} + +static int raid10_spare_active(mddev_t *mddev) +{ + int i; + conf_t *conf = mddev->private; + mirror_info_t *tmp; + + spin_lock_irq(&conf->device_lock); + /* + * Find all non-in_sync disks within the RAID10 configuration + * and mark them in_sync + */ + for (i = 0; i < conf->raid_disks; i++) { + tmp = conf->mirrors + i; + if (tmp->rdev + && !tmp->rdev->faulty + && !tmp->rdev->in_sync) { + conf->working_disks++; + mddev->degraded--; + tmp->rdev->in_sync = 1; + } + } + spin_unlock_irq(&conf->device_lock); + + print_conf(conf); + return 0; +} + + +static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) +{ + conf_t *conf = mddev->private; + int found = 0; + int mirror; + mirror_info_t *p; + + if (mddev->recovery_cp < MaxSector) + /* only hot-add to in-sync arrays, as recovery is + * very different from resync + */ + return 0; + spin_lock_irq(&conf->device_lock); + for (mirror=0; mirror < mddev->raid_disks; mirror++) + if ( !(p=conf->mirrors+mirror)->rdev) { + p->rdev = rdev; + + blk_queue_stack_limits(mddev->queue, + rdev->bdev->bd_disk->queue); + /* as we don't honour merge_bvec_fn, we must never risk + * violating it, so limit ->max_sector to one PAGE, as + * a one page request is never in violation. + */ + if (rdev->bdev->bd_disk->queue->merge_bvec_fn && + mddev->queue->max_sectors > (PAGE_SIZE>>9)) + mddev->queue->max_sectors = (PAGE_SIZE>>9); + + p->head_position = 0; + rdev->raid_disk = mirror; + found = 1; + break; + } + spin_unlock_irq(&conf->device_lock); + + print_conf(conf); + return found; +} + +static int raid10_remove_disk(mddev_t *mddev, int number) +{ + conf_t *conf = mddev->private; + int err = 1; + mirror_info_t *p = conf->mirrors+ number; + + print_conf(conf); + spin_lock_irq(&conf->device_lock); + if (p->rdev) { + if (p->rdev->in_sync || + atomic_read(&p->rdev->nr_pending)) { + err = -EBUSY; + goto abort; + } + p->rdev = NULL; + err = 0; + } + if (err) + MD_BUG(); +abort: + spin_unlock_irq(&conf->device_lock); + + print_conf(conf); + return err; +} + + +static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) +{ + int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); + conf_t *conf = mddev_to_conf(r10_bio->mddev); + int i,d; + + if (bio->bi_size) + return 1; + + for (i=0; icopies; i++) + if (r10_bio->devs[i].bio == bio) + break; + if (i == conf->copies) + BUG(); + update_head_pos(i, r10_bio); + d = r10_bio->devs[i].devnum; + if (!uptodate) + md_error(r10_bio->mddev, + conf->mirrors[d].rdev); + + /* for reconstruct, we always reschedule after a read. + * for resync, only after all reads + */ + if (test_bit(R10BIO_IsRecover, &r10_bio->state) || + atomic_dec_and_test(&r10_bio->remaining)) { + /* we have read all the blocks, + * do the comparison in process context in raid10d + */ + reschedule_retry(r10_bio); + } + rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev); + return 0; +} + +static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) +{ + int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); + mddev_t *mddev = r10_bio->mddev; + conf_t *conf = mddev_to_conf(mddev); + int i,d; + + if (bio->bi_size) + return 1; + + for (i = 0; i < conf->copies; i++) + if (r10_bio->devs[i].bio == bio) + break; + d = r10_bio->devs[i].devnum; + + if (!uptodate) + md_error(mddev, conf->mirrors[d].rdev); + update_head_pos(i, r10_bio); + + while (atomic_dec_and_test(&r10_bio->remaining)) { + if (r10_bio->master_bio == NULL) { + /* the primary of several recovery bios */ + md_done_sync(mddev, r10_bio->sectors, 1); + put_buf(r10_bio); + break; + } else { + r10bio_t *r10_bio2 = (r10bio_t *)r10_bio->master_bio; + put_buf(r10_bio); + r10_bio = r10_bio2; + } + } + rdev_dec_pending(conf->mirrors[d].rdev, mddev); + return 0; +} + +/* + * Note: sync and recover and handled very differently for raid10 + * This code is for resync. + * For resync, we read through virtual addresses and read all blocks. + * If there is any error, we schedule a write. The lowest numbered + * drive is authoritative. + * However requests come for physical address, so we need to map. + * For every physical address there are raid_disks/copies virtual addresses, + * which is always are least one, but is not necessarly an integer. + * This means that a physical address can span multiple chunks, so we may + * have to submit multiple io requests for a single sync request. + */ +/* + * We check if all blocks are in-sync and only write to blocks that + * aren't in sync + */ +static void sync_request_write(mddev_t *mddev, r10bio_t *r10_bio) +{ + conf_t *conf = mddev_to_conf(mddev); + int i, first; + struct bio *tbio, *fbio; + + atomic_set(&r10_bio->remaining, 1); + + /* find the first device with a block */ + for (i=0; icopies; i++) + if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) + break; + + if (i == conf->copies) + goto done; + + first = i; + fbio = r10_bio->devs[i].bio; + + /* now find blocks with errors */ + for (i=first+1 ; i < conf->copies ; i++) { + int vcnt, j, d; + + if (!test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) + continue; + /* We know that the bi_io_vec layout is the same for + * both 'first' and 'i', so we just compare them. + * All vec entries are PAGE_SIZE; + */ + tbio = r10_bio->devs[i].bio; + vcnt = r10_bio->sectors >> (PAGE_SHIFT-9); + for (j = 0; j < vcnt; j++) + if (memcmp(page_address(fbio->bi_io_vec[j].bv_page), + page_address(tbio->bi_io_vec[j].bv_page), + PAGE_SIZE)) + break; + if (j == vcnt) + continue; + /* Ok, we need to write this bio + * First we need to fixup bv_offset, bv_len and + * bi_vecs, as the read request might have corrupted these + */ + tbio->bi_vcnt = vcnt; + tbio->bi_size = r10_bio->sectors << 9; + tbio->bi_idx = 0; + tbio->bi_phys_segments = 0; + tbio->bi_hw_segments = 0; + tbio->bi_hw_front_size = 0; + tbio->bi_hw_back_size = 0; + tbio->bi_flags &= ~(BIO_POOL_MASK - 1); + tbio->bi_flags |= 1 << BIO_UPTODATE; + tbio->bi_next = NULL; + tbio->bi_rw = WRITE; + tbio->bi_private = r10_bio; + tbio->bi_sector = r10_bio->devs[i].addr; + + for (j=0; j < vcnt ; j++) { + tbio->bi_io_vec[j].bv_offset = 0; + tbio->bi_io_vec[j].bv_len = PAGE_SIZE; + + memcpy(page_address(tbio->bi_io_vec[j].bv_page), + page_address(fbio->bi_io_vec[j].bv_page), + PAGE_SIZE); + } + tbio->bi_end_io = end_sync_write; + + d = r10_bio->devs[i].devnum; + atomic_inc(&conf->mirrors[d].rdev->nr_pending); + atomic_inc(&r10_bio->remaining); + md_sync_acct(conf->mirrors[d].rdev->bdev, tbio->bi_size >> 9); + + generic_make_request(tbio); + } + +done: + if (atomic_dec_and_test(&r10_bio->remaining)) { + md_done_sync(mddev, r10_bio->sectors, 1); + put_buf(r10_bio); + } +} + +/* + * Now for the recovery code. + * Recovery happens across physical sectors. + * We recover all non-is_sync drives by finding the virtual address of + * each, and then choose a working drive that also has that virt address. + * There is a separate r10_bio for each non-in_sync drive. + * Only the first two slots are in use. The first for reading, + * The second for writing. + * + */ + +static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio) +{ + conf_t *conf = mddev_to_conf(mddev); + int i, d; + struct bio *bio, *wbio; + + + /* move the pages across to the second bio + * and submit the write request + */ + bio = r10_bio->devs[0].bio; + wbio = r10_bio->devs[1].bio; + for (i=0; i < wbio->bi_vcnt; i++) { + struct page *p = bio->bi_io_vec[i].bv_page; + bio->bi_io_vec[i].bv_page = wbio->bi_io_vec[i].bv_page; + wbio->bi_io_vec[i].bv_page = p; + } + d = r10_bio->devs[1].devnum; + + atomic_inc(&conf->mirrors[d].rdev->nr_pending); + md_sync_acct(conf->mirrors[d].rdev->bdev, wbio->bi_size >> 9); + generic_make_request(wbio); +} + + +/* + * This is a kernel thread which: + * + * 1. Retries failed read operations on working mirrors. + * 2. Updates the raid superblock when problems encounter. + * 3. Performs writes following reads for array syncronising. + */ + +static void raid10d(mddev_t *mddev) +{ + r10bio_t *r10_bio; + struct bio *bio; + unsigned long flags; + conf_t *conf = mddev_to_conf(mddev); + struct list_head *head = &conf->retry_list; + int unplug=0; + mdk_rdev_t *rdev; + + md_check_recovery(mddev); + md_handle_safemode(mddev); + + for (;;) { + char b[BDEVNAME_SIZE]; + spin_lock_irqsave(&conf->device_lock, flags); + if (list_empty(head)) + break; + r10_bio = list_entry(head->prev, r10bio_t, retry_list); + list_del(head->prev); + spin_unlock_irqrestore(&conf->device_lock, flags); + + mddev = r10_bio->mddev; + conf = mddev_to_conf(mddev); + if (test_bit(R10BIO_IsSync, &r10_bio->state)) { + sync_request_write(mddev, r10_bio); + unplug = 1; + } else if (test_bit(R10BIO_IsRecover, &r10_bio->state)) { + recovery_request_write(mddev, r10_bio); + unplug = 1; + } else { + int mirror; + bio = r10_bio->devs[r10_bio->read_slot].bio; + r10_bio->devs[r10_bio->read_slot].bio = NULL; + mirror = read_balance(conf, r10_bio); + r10_bio->devs[r10_bio->read_slot].bio = bio; + if (mirror == -1) { + printk(KERN_ALERT "raid10: %s: unrecoverable I/O" + " read error for block %llu\n", + bdevname(bio->bi_bdev,b), + (unsigned long long)r10_bio->sector); + raid_end_bio_io(r10_bio); + } else { + rdev = conf->mirrors[mirror].rdev; + if (printk_ratelimit()) + printk(KERN_ERR "raid10: %s: redirecting sector %llu to" + " another mirror\n", + bdevname(rdev->bdev,b), + (unsigned long long)r10_bio->sector); + bio->bi_bdev = rdev->bdev; + bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr + + rdev->data_offset; + bio->bi_next = NULL; + bio->bi_flags &= (1<bi_flags |= 1 << BIO_UPTODATE; + bio->bi_idx = 0; + bio->bi_size = r10_bio->sectors << 9; + bio->bi_rw = READ; + unplug = 1; + generic_make_request(bio); + } + } + } + spin_unlock_irqrestore(&conf->device_lock, flags); + if (unplug) + unplug_slaves(mddev); +} + + +static int init_resync(conf_t *conf) +{ + int buffs; + + buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; + if (conf->r10buf_pool) + BUG(); + conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf); + if (!conf->r10buf_pool) + return -ENOMEM; + conf->next_resync = 0; + return 0; +} + +/* + * perform a "sync" on one "block" + * + * We need to make sure that no normal I/O request - particularly write + * requests - conflict with active sync requests. + * + * This is achieved by tracking pending requests and a 'barrier' concept + * that can be installed to exclude normal IO requests. + * + * Resync and recovery are handled very differently. + * We differentiate by looking at MD_RECOVERY_SYNC in mddev->recovery. + * + * For resync, we iterate over virtual addresses, read all copies, + * and update if there are differences. If only one copy is live, + * skip it. + * For recovery, we iterate over physical addresses, read a good + * value for each non-in_sync drive, and over-write. + * + * So, for recovery we may have several outstanding complex requests for a + * given address, one for each out-of-sync device. We model this by allocating + * a number of r10_bio structures, one for each out-of-sync device. + * As we setup these structures, we collect all bio's together into a list + * which we then process collectively to add pages, and then process again + * to pass to generic_make_request. + * + * The r10_bio structures are linked using a borrowed master_bio pointer. + * This link is counted in ->remaining. When the r10_bio that points to NULL + * has its remaining count decremented to 0, the whole complex operation + * is complete. + * + */ + +static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) +{ + conf_t *conf = mddev_to_conf(mddev); + r10bio_t *r10_bio; + struct bio *biolist = NULL, *bio; + sector_t max_sector, nr_sectors; + int disk; + int i; + + sector_t sectors_skipped = 0; + int chunks_skipped = 0; + + if (!conf->r10buf_pool) + if (init_resync(conf)) + return -ENOMEM; + + skipped: + max_sector = mddev->size << 1; + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) + max_sector = mddev->resync_max_sectors; + if (sector_nr >= max_sector) { + close_sync(conf); + return sectors_skipped; + } + if (chunks_skipped >= conf->raid_disks) { + /* if there has been nothing to do on any drive, + * then there is nothing to do at all.. + */ + sector_t sec = max_sector - sector_nr; + md_done_sync(mddev, sec, 1); + return sec + sectors_skipped; + } + + /* make sure whole request will fit in a chunk - if chunks + * are meaningful + */ + if (conf->near_copies < conf->raid_disks && + max_sector > (sector_nr | conf->chunk_mask)) + max_sector = (sector_nr | conf->chunk_mask) + 1; + /* + * If there is non-resync activity waiting for us then + * put in a delay to throttle resync. + */ + if (!go_faster && waitqueue_active(&conf->wait_resume)) + schedule_timeout(HZ); + device_barrier(conf, sector_nr + RESYNC_SECTORS); + + /* Again, very different code for resync and recovery. + * Both must result in an r10bio with a list of bios that + * have bi_end_io, bi_sector, bi_bdev set, + * and bi_private set to the r10bio. + * For recovery, we may actually create several r10bios + * with 2 bios in each, that correspond to the bios in the main one. + * In this case, the subordinate r10bios link back through a + * borrowed master_bio pointer, and the counter in the master + * includes a ref from each subordinate. + */ + /* First, we decide what to do and set ->bi_end_io + * To end_sync_read if we want to read, and + * end_sync_write if we will want to write. + */ + + if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { + /* recovery... the complicated one */ + int i, j, k; + r10_bio = NULL; + + for (i=0 ; iraid_disks; i++) + if (conf->mirrors[i].rdev && + !conf->mirrors[i].rdev->in_sync) { + /* want to reconstruct this device */ + r10bio_t *rb2 = r10_bio; + + r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO); + spin_lock_irq(&conf->resync_lock); + conf->nr_pending++; + if (rb2) conf->barrier++; + spin_unlock_irq(&conf->resync_lock); + atomic_set(&r10_bio->remaining, 0); + + r10_bio->master_bio = (struct bio*)rb2; + if (rb2) + atomic_inc(&rb2->remaining); + r10_bio->mddev = mddev; + set_bit(R10BIO_IsRecover, &r10_bio->state); + r10_bio->sector = raid10_find_virt(conf, sector_nr, i); + raid10_find_phys(conf, r10_bio); + for (j=0; jcopies;j++) { + int d = r10_bio->devs[j].devnum; + if (conf->mirrors[d].rdev && + conf->mirrors[d].rdev->in_sync) { + /* This is where we read from */ + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; + bio->bi_private = r10_bio; + bio->bi_end_io = end_sync_read; + bio->bi_rw = 0; + bio->bi_sector = r10_bio->devs[j].addr + + conf->mirrors[d].rdev->data_offset; + bio->bi_bdev = conf->mirrors[d].rdev->bdev; + atomic_inc(&conf->mirrors[d].rdev->nr_pending); + atomic_inc(&r10_bio->remaining); + /* and we write to 'i' */ + + for (k=0; kcopies; k++) + if (r10_bio->devs[k].devnum == i) + break; + bio = r10_bio->devs[1].bio; + bio->bi_next = biolist; + biolist = bio; + bio->bi_private = r10_bio; + bio->bi_end_io = end_sync_write; + bio->bi_rw = 1; + bio->bi_sector = r10_bio->devs[k].addr + + conf->mirrors[i].rdev->data_offset; + bio->bi_bdev = conf->mirrors[i].rdev->bdev; + + r10_bio->devs[0].devnum = d; + r10_bio->devs[1].devnum = i; + + break; + } + } + if (j == conf->copies) { + BUG(); + } + } + if (biolist == NULL) { + while (r10_bio) { + r10bio_t *rb2 = r10_bio; + r10_bio = (r10bio_t*) rb2->master_bio; + rb2->master_bio = NULL; + put_buf(rb2); + } + goto giveup; + } + } else { + /* resync. Schedule a read for every block at this virt offset */ + int count = 0; + r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO); + + spin_lock_irq(&conf->resync_lock); + conf->nr_pending++; + spin_unlock_irq(&conf->resync_lock); + + r10_bio->mddev = mddev; + atomic_set(&r10_bio->remaining, 0); + + r10_bio->master_bio = NULL; + r10_bio->sector = sector_nr; + set_bit(R10BIO_IsSync, &r10_bio->state); + raid10_find_phys(conf, r10_bio); + r10_bio->sectors = (sector_nr | conf->chunk_mask) - sector_nr +1; + spin_lock_irq(&conf->device_lock); + for (i=0; icopies; i++) { + int d = r10_bio->devs[i].devnum; + bio = r10_bio->devs[i].bio; + bio->bi_end_io = NULL; + if (conf->mirrors[d].rdev == NULL || + conf->mirrors[d].rdev->faulty) + continue; + atomic_inc(&conf->mirrors[d].rdev->nr_pending); + atomic_inc(&r10_bio->remaining); + bio->bi_next = biolist; + biolist = bio; + bio->bi_private = r10_bio; + bio->bi_end_io = end_sync_read; + bio->bi_rw = 0; + bio->bi_sector = r10_bio->devs[i].addr + + conf->mirrors[d].rdev->data_offset; + bio->bi_bdev = conf->mirrors[d].rdev->bdev; + count++; + } + spin_unlock_irq(&conf->device_lock); + if (count < 2) { + for (i=0; icopies; i++) { + int d = r10_bio->devs[i].devnum; + if (r10_bio->devs[i].bio->bi_end_io) + atomic_dec(&conf->mirrors[d].rdev->nr_pending); + } + put_buf(r10_bio); + goto giveup; + } + } + + for (bio = biolist; bio ; bio=bio->bi_next) { + + bio->bi_flags &= ~(BIO_POOL_MASK - 1); + if (bio->bi_end_io) + bio->bi_flags |= 1 << BIO_UPTODATE; + bio->bi_vcnt = 0; + bio->bi_idx = 0; + bio->bi_phys_segments = 0; + bio->bi_hw_segments = 0; + bio->bi_size = 0; + } + + nr_sectors = 0; + do { + struct page *page; + int len = PAGE_SIZE; + disk = 0; + if (sector_nr + (len>>9) > max_sector) + len = (max_sector - sector_nr) << 9; + if (len == 0) + break; + for (bio= biolist ; bio ; bio=bio->bi_next) { + page = bio->bi_io_vec[bio->bi_vcnt].bv_page; + if (bio_add_page(bio, page, len, 0) == 0) { + /* stop here */ + struct bio *bio2; + bio->bi_io_vec[bio->bi_vcnt].bv_page = page; + for (bio2 = biolist; bio2 && bio2 != bio; bio2 = bio2->bi_next) { + /* remove last page from this bio */ + bio2->bi_vcnt--; + bio2->bi_size -= len; + bio2->bi_flags &= ~(1<< BIO_SEG_VALID); + } + goto bio_full; + } + disk = i; + } + nr_sectors += len>>9; + sector_nr += len>>9; + } while (biolist->bi_vcnt < RESYNC_PAGES); + bio_full: + r10_bio->sectors = nr_sectors; + + while (biolist) { + bio = biolist; + biolist = biolist->bi_next; + + bio->bi_next = NULL; + r10_bio = bio->bi_private; + r10_bio->sectors = nr_sectors; + + if (bio->bi_end_io == end_sync_read) { + md_sync_acct(bio->bi_bdev, nr_sectors); + generic_make_request(bio); + } + } + + return nr_sectors; + giveup: + /* There is nowhere to write, so all non-sync + * drives must be failed, so try the next chunk... + */ + { + int sec = max_sector - sector_nr; + sectors_skipped += sec; + chunks_skipped ++; + sector_nr = max_sector; + md_done_sync(mddev, sec, 1); + goto skipped; + } +} + +static int run(mddev_t *mddev) +{ + conf_t *conf; + int i, disk_idx; + mirror_info_t *disk; + mdk_rdev_t *rdev; + struct list_head *tmp; + int nc, fc; + sector_t stride, size; + + if (mddev->level != 10) { + printk(KERN_ERR "raid10: %s: raid level not set correctly... (%d)\n", + mdname(mddev), mddev->level); + goto out; + } + nc = mddev->layout & 255; + fc = (mddev->layout >> 8) & 255; + if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks || + (mddev->layout >> 16)) { + printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n", + mdname(mddev), mddev->layout); + goto out; + } + /* + * copy the already verified devices into our private RAID10 + * bookkeeping area. [whatever we allocate in run(), + * should be freed in stop()] + */ + conf = kmalloc(sizeof(conf_t), GFP_KERNEL); + mddev->private = conf; + if (!conf) { + printk(KERN_ERR "raid10: couldn't allocate memory for %s\n", + mdname(mddev)); + goto out; + } + memset(conf, 0, sizeof(*conf)); + conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks, + GFP_KERNEL); + if (!conf->mirrors) { + printk(KERN_ERR "raid10: couldn't allocate memory for %s\n", + mdname(mddev)); + goto out_free_conf; + } + memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks); + + conf->near_copies = nc; + conf->far_copies = fc; + conf->copies = nc*fc; + conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; + conf->chunk_shift = ffz(~mddev->chunk_size) - 9; + stride = mddev->size >> (conf->chunk_shift-1); + sector_div(stride, fc); + conf->stride = stride << conf->chunk_shift; + + conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, + r10bio_pool_free, conf); + if (!conf->r10bio_pool) { + printk(KERN_ERR "raid10: couldn't allocate memory for %s\n", + mdname(mddev)); + goto out_free_conf; + } + mddev->queue->unplug_fn = raid10_unplug; + + mddev->queue->issue_flush_fn = raid10_issue_flush; + + ITERATE_RDEV(mddev, rdev, tmp) { + disk_idx = rdev->raid_disk; + if (disk_idx >= mddev->raid_disks + || disk_idx < 0) + continue; + disk = conf->mirrors + disk_idx; + + disk->rdev = rdev; + + blk_queue_stack_limits(mddev->queue, + rdev->bdev->bd_disk->queue); + /* as we don't honour merge_bvec_fn, we must never risk + * violating it, so limit ->max_sector to one PAGE, as + * a one page request is never in violation. + */ + if (rdev->bdev->bd_disk->queue->merge_bvec_fn && + mddev->queue->max_sectors > (PAGE_SIZE>>9)) + mddev->queue->max_sectors = (PAGE_SIZE>>9); + + disk->head_position = 0; + if (!rdev->faulty && rdev->in_sync) + conf->working_disks++; + } + conf->raid_disks = mddev->raid_disks; + conf->mddev = mddev; + conf->device_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&conf->retry_list); + + conf->resync_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&conf->wait_idle); + init_waitqueue_head(&conf->wait_resume); + + if (!conf->working_disks) { + printk(KERN_ERR "raid10: no operational mirrors for %s\n", + mdname(mddev)); + goto out_free_conf; + } + + mddev->degraded = 0; + for (i = 0; i < conf->raid_disks; i++) { + + disk = conf->mirrors + i; + + if (!disk->rdev) { + disk->head_position = 0; + mddev->degraded++; + } + } + + + mddev->thread = md_register_thread(raid10d, mddev, "%s_raid10"); + if (!mddev->thread) { + printk(KERN_ERR + "raid10: couldn't allocate thread for %s\n", + mdname(mddev)); + goto out_free_conf; + } + + printk(KERN_INFO + "raid10: raid set %s active with %d out of %d devices\n", + mdname(mddev), mddev->raid_disks - mddev->degraded, + mddev->raid_disks); + /* + * Ok, everything is just fine now + */ + size = conf->stride * conf->raid_disks; + sector_div(size, conf->near_copies); + mddev->array_size = size/2; + mddev->resync_max_sectors = size; + + /* Calculate max read-ahead size. + * We need to readahead at least twice a whole stripe.... + * maybe... + */ + { + int stripe = conf->raid_disks * mddev->chunk_size / PAGE_CACHE_SIZE; + stripe /= conf->near_copies; + if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) + mddev->queue->backing_dev_info.ra_pages = 2* stripe; + } + + if (conf->near_copies < mddev->raid_disks) + blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec); + return 0; + +out_free_conf: + if (conf->r10bio_pool) + mempool_destroy(conf->r10bio_pool); + if (conf->mirrors) + kfree(conf->mirrors); + kfree(conf); + mddev->private = NULL; +out: + return -EIO; +} + +static int stop(mddev_t *mddev) +{ + conf_t *conf = mddev_to_conf(mddev); + + md_unregister_thread(mddev->thread); + mddev->thread = NULL; + if (conf->r10bio_pool) + mempool_destroy(conf->r10bio_pool); + if (conf->mirrors) + kfree(conf->mirrors); + kfree(conf); + mddev->private = NULL; + return 0; +} + + +static mdk_personality_t raid10_personality = +{ + .name = "raid10", + .owner = THIS_MODULE, + .make_request = make_request, + .run = run, + .stop = stop, + .status = status, + .error_handler = error, + .hot_add_disk = raid10_add_disk, + .hot_remove_disk= raid10_remove_disk, + .spare_active = raid10_spare_active, + .sync_request = sync_request, +}; + +static int __init raid_init(void) +{ + return register_md_personality(RAID10, &raid10_personality); +} + +static void raid_exit(void) +{ + unregister_md_personality(RAID10); +} + +module_init(raid_init); +module_exit(raid_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("md-personality-9"); /* RAID10 */ diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/md/raid5.c 2004-10-18 14:56:17 -07:00 @@ -477,8 +477,8 @@ if (!rdev->faulty) { mddev->sb_dirty = 1; - conf->working_disks--; if (rdev->in_sync) { + conf->working_disks--; mddev->degraded++; conf->failed_disks++; rdev->in_sync = 0; @@ -1071,7 +1071,8 @@ PRINTK("Reading block %d (sync=%d)\n", i, syncing); if (syncing) - md_sync_acct(conf->disks[i].rdev, STRIPE_SECTORS); + md_sync_acct(conf->disks[i].rdev->bdev, + STRIPE_SECTORS); } } } @@ -1256,7 +1257,7 @@ if (rdev) { if (test_bit(R5_Syncio, &sh->dev[i].flags)) - md_sync_acct(rdev, STRIPE_SECTORS); + md_sync_acct(rdev->bdev, STRIPE_SECTORS); bi->bi_bdev = rdev->bdev; PRINTK("for %llu schedule op %ld on disc %d\n", @@ -1339,6 +1340,39 @@ unplug_slaves(mddev); } +static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->disks[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue; + + if (!bdev) + continue; + + r_queue = bdev_get_queue(bdev); + if (!r_queue) + continue; + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} + static inline void raid5_plug_device(raid5_conf_t *conf) { spin_lock_irq(&conf->device_lock); @@ -1545,6 +1579,7 @@ atomic_set(&conf->preread_active_stripes, 0); mddev->queue->unplug_fn = raid5_unplug_device; + mddev->queue->issue_flush_fn = raid5_issue_flush; PRINTK("raid5: run(%s) called.\n", mdname(mddev)); diff -Nru a/drivers/md/raid6main.c b/drivers/md/raid6main.c --- a/drivers/md/raid6main.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/md/raid6main.c 2004-10-18 14:55:54 -07:00 @@ -498,8 +498,8 @@ if (!rdev->faulty) { mddev->sb_dirty = 1; - conf->working_disks--; if (rdev->in_sync) { + conf->working_disks--; mddev->degraded++; conf->failed_disks++; rdev->in_sync = 0; @@ -1208,7 +1208,8 @@ PRINTK("Reading block %d (sync=%d)\n", i, syncing); if (syncing) - md_sync_acct(conf->disks[i].rdev, STRIPE_SECTORS); + md_sync_acct(conf->disks[i].rdev->bdev, + STRIPE_SECTORS); } } } @@ -1418,7 +1419,7 @@ if (rdev) { if (test_bit(R5_Syncio, &sh->dev[i].flags)) - md_sync_acct(rdev, STRIPE_SECTORS); + md_sync_acct(rdev->bdev, STRIPE_SECTORS); bi->bi_bdev = rdev->bdev; PRINTK("for %llu schedule op %ld on disc %d\n", @@ -1501,6 +1502,39 @@ unplug_slaves(mddev); } +static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid6_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->disks[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue; + + if (!bdev) + continue; + + r_queue = bdev_get_queue(bdev); + if (!r_queue) + continue; + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} + static inline void raid6_plug_device(raid6_conf_t *conf) { spin_lock_irq(&conf->device_lock); @@ -1708,6 +1742,7 @@ atomic_set(&conf->preread_active_stripes, 0); mddev->queue->unplug_fn = raid6_unplug_device; + mddev->queue->issue_flush_fn = raid6_issue_flush; PRINTK("raid6: run(%s) called.\n", mdname(mddev)); diff -Nru a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c --- a/drivers/media/common/saa7146_i2c.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/media/common/saa7146_i2c.c 2004-10-18 14:57:04 -07:00 @@ -1,13 +1,6 @@ #include #include -/* helper function */ -static void my_wait(struct saa7146_dev *dev, long ms) -{ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout((((ms+10)/10)*HZ)/1000); -} - u32 saa7146_i2c_func(struct i2c_adapter *adapter) { //fm DEB_I2C(("'%s'.\n", adapter->name)); @@ -136,12 +129,12 @@ /* set "ABORT-OPERATION"-bit (bit 7)*/ saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); /* clear all error-bits pending; this is needed because p.123, note 1 */ saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); } /* check if any error is (still) present. (this can be necessary because p.123, note 1) */ @@ -155,18 +148,18 @@ after serious protocol errors caused by e.g. the SAA7740 */ saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); /* clear all error-bits pending */ saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); /* the data sheet says it might be necessary to clear the status twice after an abort */ saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); } /* if any error is still present, a fatal error has occured ... */ @@ -243,7 +236,7 @@ if ((++trial < 20) && short_delay) udelay(10); else - my_wait(dev,1); + msleep(1); } } @@ -345,7 +338,7 @@ } /* delay a bit before retrying */ - my_wait(dev, 10); + msleep(10); } while (err != num && retries--); diff -Nru a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c --- a/drivers/media/dvb/b2c2/skystar2.c 2004-10-18 14:57:20 -07:00 +++ b/drivers/media/dvb/b2c2/skystar2.c 2004-10-18 14:57:20 -07:00 @@ -2345,7 +2345,7 @@ MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl); static struct pci_driver skystar2_pci_driver = { - .name = "Technisat SkyStar2 driver", + .name = "SkyStar2", .id_table = skystar2_pci_tbl, .probe = skystar2_probe, .remove = skystar2_remove, diff -Nru a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c --- a/drivers/media/dvb/bt8xx/bt878.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/media/dvb/bt8xx/bt878.c 2004-10-18 14:56:32 -07:00 @@ -417,6 +417,8 @@ printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", bt878_num); + if (pci_enable_device(dev)) + return -EIO; bt = &bt878[bt878_num]; bt->dev = dev; @@ -426,11 +428,10 @@ bt->id = dev->device; bt->irq = dev->irq; bt->bt878_adr = pci_resource_start(dev, 0); - if (pci_enable_device(dev)) - return -EIO; if (!request_mem_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0), "bt878")) { - return -EBUSY; + result = -EBUSY; + goto fail0; } pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision); @@ -501,6 +502,8 @@ fail1: release_mem_region(pci_resource_start(bt->dev, 0), pci_resource_len(bt->dev, 0)); + fail0: + pci_disable_device(dev); return result; } @@ -517,7 +520,7 @@ /* first disable interrupts before unmapping the memory! */ btwrite(0, BT878_AINT_MASK); - btwrite(~0x0UL, BT878_AINT_STAT); + btwrite(~0U, BT878_AINT_STAT); /* disable PCI bus-mastering */ pci_read_config_byte(bt->dev, PCI_COMMAND, &command); @@ -540,6 +543,7 @@ bt878_mem_free(bt); pci_set_drvdata(pci_dev, NULL); + pci_disable_device(pci_dev); return; } diff -Nru a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2004-10-18 14:56:28 -07:00 @@ -1196,7 +1196,7 @@ int status; char fragbuf[HOST_LINK_BUF_SIZE]; int fragpos = 0; - int fraglen; + size_t fraglen; unsigned long timeout; int written; @@ -1257,7 +1257,7 @@ int slot; int slot_count = 0; int idx; - int fraglen; + size_t fraglen; int connection_id = -1; int found = 0; u8 hdr[2]; @@ -1484,21 +1484,20 @@ static struct file_operations dvb_ca_fops = { - owner: THIS_MODULE, - read: dvb_ca_en50221_io_read, - write: dvb_ca_en50221_io_write, - ioctl: dvb_ca_en50221_io_ioctl, - open: dvb_ca_en50221_io_open, - release: dvb_ca_en50221_io_release, - poll: dvb_ca_en50221_io_poll, + .owner = THIS_MODULE, + .read = dvb_ca_en50221_io_read, + .write = dvb_ca_en50221_io_write, + .ioctl = dvb_ca_en50221_io_ioctl, + .open = dvb_ca_en50221_io_open, + .release = dvb_ca_en50221_io_release, + .poll = dvb_ca_en50221_io_poll, }; static struct dvb_device dvbdev_ca = { - priv: NULL, - users: 1, - readers: 1, - writers: 1, - fops: &dvb_ca_fops, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &dvb_ca_fops, }; diff -Nru a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c --- a/drivers/media/dvb/dvb-core/dvb_net.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/media/dvb/dvb-core/dvb_net.c 2004-10-18 14:56:17 -07:00 @@ -142,7 +142,7 @@ skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); - eth= skb->mac.ethernet; + eth = eth_hdr(skb); if (*eth->h_dest & 1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) @@ -563,7 +563,7 @@ if (buffer2 != 0) printk(KERN_WARNING "buffer2 not 0: %p.\n", buffer2); if (buffer1_len > 32768) - printk(KERN_WARNING "length > 32k: %u.\n", buffer1_len); + printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len); /* printk("TS callback: %u bytes, %u TS cells @ %p.\n", buffer1_len, buffer1_len / TS_SZ, buffer1); */ dvb_net_ule(dev, buffer1, buffer1_len); diff -Nru a/drivers/media/dvb/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c --- a/drivers/media/dvb/frontends/alps_tdlb7.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/media/dvb/frontends/alps_tdlb7.c 2004-10-18 14:57:19 -07:00 @@ -54,9 +54,6 @@ /* starting point for firmware in file 'Sc_main.mc' */ #define SP8870_FIRMWARE_OFFSET 0x0A - -static int errno; - static struct dvb_frontend_info tdlb7_info = { .name = "Alps TDLB7", .type = FE_OFDM, diff -Nru a/drivers/media/dvb/frontends/dst.c b/drivers/media/dvb/frontends/dst.c --- a/drivers/media/dvb/frontends/dst.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/media/dvb/frontends/dst.c 2004-10-18 14:56:50 -07:00 @@ -1145,8 +1145,8 @@ } dst_init (dst); - dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, - (u32)dst, (u32)(dst->bt), (u32)(dst->i2c)); + dprintk("%s: register dst %p bt %p i2c %p\n", __FUNCTION__, + dst, dst->bt, dst->i2c); info = &dst_info_sat; if (dst->dst_type == DST_TYPE_IS_TERR) @@ -1162,7 +1162,7 @@ static void dst_detach (struct dvb_i2c_bus *i2c, void *data) { dvb_unregister_frontend (dst_ioctl, i2c); - dprintk("%s: unregister dst %8.8x\n", __FUNCTION__, (u32)(data)); + dprintk("%s: unregister dst %p\n", __FUNCTION__, data); if (data) kfree(data); } diff -Nru a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c --- a/drivers/media/dvb/frontends/sp887x.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/media/dvb/frontends/sp887x.c 2004-10-18 14:56:49 -07:00 @@ -67,8 +67,6 @@ FE_CAN_RECOVER }; -static int errno; - static int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len) { diff -Nru a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c --- a/drivers/media/dvb/frontends/stv0299.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/media/dvb/frontends/stv0299.c 2004-10-18 14:57:05 -07:00 @@ -319,7 +319,7 @@ static int pll_write (struct dvb_i2c_bus *i2c, u8 addr, u8 *data, int len) { int ret; - struct i2c_msg msg = { addr: addr, .flags = 0, .buf = data, .len = len }; + struct i2c_msg msg = { .addr = addr, .buf = data, .len = len }; stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ @@ -1257,12 +1257,12 @@ u8 stat [] = { 0 }; u8 tda6100_buf [] = { 0, 0 }; int ret; - struct i2c_msg msg1 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, + struct i2c_msg msg1 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; - struct i2c_msg msg2 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, + struct i2c_msg msg2 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, { .addr = 0x61, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; - struct i2c_msg msg3 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, - { .addr = 0x60, .flags = 0, .buf = tda6100_buf, .len = 2 }}; + struct i2c_msg msg3 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, + { .addr = 0x60, .buf = tda6100_buf, .len = 2 }}; stv0299_writereg (i2c, 0x01, 0x15); stv0299_writereg (i2c, 0x02, 0x30); @@ -1271,7 +1271,7 @@ printk ("%s: try to attach to %s\n", __FUNCTION__, adapter->name); - if ( strcmp(adapter->name, "Technisat SkyStar2 driver") == 0 ) + if ( strcmp(adapter->name, "SkyStar2") == 0 ) { printk ("%s: setup for tuner Samsung TBMU24112IMB\n", __FILE__); diff -Nru a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c --- a/drivers/media/dvb/frontends/tda1004x.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/media/dvb/frontends/tda1004x.c 2004-10-18 14:55:53 -07:00 @@ -188,8 +188,6 @@ static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} }; static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo); -static int errno; - static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data) { diff -Nru a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig --- a/drivers/media/dvb/ttpci/Kconfig 2004-10-18 14:55:55 -07:00 +++ b/drivers/media/dvb/ttpci/Kconfig 2004-10-18 14:55:55 -07:00 @@ -1,6 +1,6 @@ config DVB_AV7110 tristate "AV7110 cards" - depends on DVB_CORE + depends on DVB_CORE && PCI select FW_LOADER select VIDEO_DEV select VIDEO_SAA7146_VV @@ -45,7 +45,7 @@ config DVB_BUDGET tristate "Budget cards" - depends on DVB_CORE + depends on DVB_CORE && PCI select VIDEO_SAA7146 help Support for simple SAA7146 based DVB cards @@ -59,7 +59,7 @@ config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" - depends on DVB_CORE + depends on DVB_CORE && PCI select VIDEO_SAA7146 help Support for simple SAA7146 based DVB cards @@ -76,7 +76,7 @@ config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" - depends on DVB_CORE + depends on DVB_CORE && PCI select VIDEO_DEV select VIDEO_SAA7146_VV help diff -Nru a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile --- a/drivers/media/dvb/ttpci/Makefile 2004-10-18 14:55:55 -07:00 +++ b/drivers/media/dvb/ttpci/Makefile 2004-10-18 14:55:55 -07:00 @@ -13,7 +13,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -host-progs := fdump +hostprogs-y := fdump ifdef CONFIG_DVB_AV7110_FIRMWARE $(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h diff -Nru a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-10-18 14:57:03 -07:00 @@ -1181,7 +1181,7 @@ firmware_size = fw_entry->size; if (firmware_size < 60) { - printk("%s: firmware size too small for DSP code (%u < 60).\n", + printk("%s: firmware size too small for DSP code (%zu < 60).\n", __FUNCTION__, firmware_size); return -1; } diff -Nru a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c --- a/drivers/media/radio/miropcm20-rds.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/media/radio/miropcm20-rds.c 2004-10-18 14:55:55 -07:00 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "miropcm20-rds-core.h" @@ -60,8 +61,7 @@ char c; char bits[8]; - current->state=TASK_UNINTERRUPTIBLE; - schedule_timeout(2*HZ); + msleep(2000); aci_rds_cmd(RDS_STATUS, &c, 1); print_matrix(&c, bits); if (copy_to_user(buffer, bits, 8)) diff -Nru a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c --- a/drivers/media/radio/radio-aimslab.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/media/radio/radio-aimslab.c 2004-10-18 14:56:27 -07:00 @@ -63,12 +63,7 @@ if(!d) udelay(n); else - { - /* Yield CPU time */ - unsigned long x=jiffies; - while((jiffies-x)<=d) - schedule(); - } + msleep(jiffies_to_msecs(d)); } static void rt_decvol(void) diff -Nru a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c --- a/drivers/media/radio/radio-cadet.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/media/radio/radio-cadet.c 2004-10-18 14:56:29 -07:00 @@ -69,8 +69,7 @@ outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */ spin_unlock(&cadet_io_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); spin_lock(&cadet_io_lock); outb(3,io); /* Select Decoder Control/Status */ @@ -243,8 +242,7 @@ outb(curvol,io+1); spin_unlock(&cadet_io_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); cadet_gettune(); if((tunestat & 0x40) == 0) { /* Tuned */ diff -Nru a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c --- a/drivers/media/radio/radio-maestro.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/media/radio/radio-maestro.c 2004-10-18 14:56:33 -07:00 @@ -93,27 +93,6 @@ struct semaphore lock; } radio_unit = {0, 0, 0, 0, }; -static void sleep_125ms(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ >> 3); -} - -static void udelay2(void) -{ - udelay(2); -} - -static void udelay4(void) -{ - udelay(4); -} - -static void udelay16(void) -{ - udelay(16); -} - static __u32 radio_bits_get(struct radio_device *dev) { register __u16 io=dev->io, l, rdata; @@ -122,14 +101,15 @@ omask = inw(io + IO_MASK); outw(~(STR_CLK | STR_WREN), io + IO_MASK); outw(0, io); - udelay16(); + udelay(16); + for (l=24;l--;) { outw(STR_CLK, io); /* HI state */ - udelay2(); + udelay(2); if(!l) dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff; outw(0, io); /* LO state */ - udelay2(); + udelay(2); data <<= 1; /* shift data */ rdata = inw(io); if(!l) @@ -138,11 +118,11 @@ else if(rdata & STR_DATA) data++; - udelay2(); + udelay(2); } if(dev->muted) outw(STR_WREN, io); - udelay4(); + udelay(4); outw(omask, io + IO_MASK); return data & 0x3ffe; } @@ -155,23 +135,23 @@ odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); outw(odir | STR_DATA, io + IO_DIR); outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); - udelay16(); + udelay(16); for (l=25;l;l--) { bits = ((data >> 18) & STR_DATA) | STR_WREN ; data <<= 1; /* shift data */ outw(bits, io); /* start strobe */ - udelay2(); + udelay(2); outw(bits | STR_CLK, io); /* HI level */ - udelay2(); + udelay(2); outw(bits, io); /* LO level */ - udelay4(); + udelay(4); } if(!dev->muted) outw(0, io); - udelay4(); + udelay(4); outw(omask, io + IO_MASK); outw(odir, io + IO_DIR); - sleep_125ms(); + msleep(125); } inline static int radio_function(struct inode *inode, struct file *file, @@ -238,9 +218,9 @@ outw(~STR_WREN, io + IO_MASK); outw((card->muted = v->flags & VIDEO_AUDIO_MUTE) ? STR_WREN : 0, io); - udelay4(); + udelay(4); outw(omask, io + IO_MASK); - sleep_125ms(); + msleep(125); return 0; } } @@ -270,7 +250,7 @@ return ret; } -inline static __u16 radio_install(struct pci_dev *pcidev); +static __u16 radio_install(struct pci_dev *pcidev); MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl"); MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio."); @@ -315,7 +295,7 @@ outw(odir, io + IO_DIR); outw(~(STR_WREN | STR_CLK), io + IO_MASK); outw(dev->muted ? 0 : STR_WREN, io); - udelay16(); + udelay(16); outw(omask, io + IO_MASK); ofreq = radio_bits_get(dev); if((ofreqFREQ2BITS(FREQ_HI))) @@ -324,7 +304,7 @@ return (ofreq == radio_bits_get(dev)); } -inline static __u16 radio_install(struct pci_dev *pcidev) +static __u16 radio_install(struct pci_dev *pcidev) { if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) return 0; diff -Nru a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c --- a/drivers/media/radio/radio-maxiradio.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/media/radio/radio-maxiradio.c 2004-10-18 14:57:04 -07:00 @@ -104,13 +104,6 @@ } radio_unit = {0, 0, 0, 0, }; -static void sleep_125ms(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ >> 3); -} - - static void outbit(unsigned long bit, __u16 io) { if(bit != 0) @@ -228,7 +221,7 @@ return -EINVAL; card->freq = *freq; set_freq(card->io, FREQ2BITS(card->freq)); - sleep_125ms(); + msleep(125); return 0; } case VIDIOCGAUDIO: { diff -Nru a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c --- a/drivers/media/radio/radio-sf16fmi.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/media/radio/radio-sf16fmi.c 2004-10-18 14:57:03 -07:00 @@ -89,8 +89,7 @@ outbits(16, RSF16_ENCODE(freq), myport); outbits(8, 0xC0, myport); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/7); + msleep(143); /* was schedule_timeout(HZ/7) */ up(&lock); if (dev->curvol) fmi_unmute(myport); return 0; @@ -107,8 +106,7 @@ val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */ outb(val, myport); outb(val | 0x10, myport); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/7); + msleep(143); /* was schedule_timeout(HZ/7) */ res = (int)inb(myport+1); outb(val, myport); diff -Nru a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c --- a/drivers/media/radio/radio-sf16fmr2.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/media/radio/radio-sf16fmr2.c 2004-10-18 14:56:29 -07:00 @@ -55,19 +55,6 @@ #define RSF16_MINFREQ 87*16000 #define RSF16_MAXFREQ 108*16000 -/* from radio-aimslab */ -static void sleep_delay(unsigned long n) -{ - unsigned d=n/(1000000U/HZ); - if (!d) - udelay(n); - else - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(d); - } -} - static inline void wait(int n,int port) { for (;n;--n) inb(port); @@ -153,7 +140,7 @@ fmr2_unmute(port); /* wait 0.11 sec */ - sleep_delay(110000LU); + msleep(110); /* NOTE if mute this stop radio you must set freq on unmute */ diff -Nru a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig --- a/drivers/media/video/Kconfig 2004-10-18 14:57:03 -07:00 +++ b/drivers/media/video/Kconfig 2004-10-18 14:57:03 -07:00 @@ -155,7 +155,7 @@ config VIDEO_ZORAN tristate "Zoran ZR36057/36067 Video For Linux" - depends on VIDEO_DEV && PCI && I2C + depends on VIDEO_DEV && PCI && I2C_ALGOBIT help Say Y for support for MJPEG capture cards based on the Zoran 36057/36067 PCI controller chipset. This includes the Iomega diff -Nru a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c --- a/drivers/media/video/adv7175.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/media/video/adv7175.c 2004-10-18 14:57:03 -07:00 @@ -156,6 +156,22 @@ return ret; } +static void +set_subcarrier_freq (struct i2c_client *client, + int pass_through) +{ + /* for some reason pass_through NTSC needs + * a different sub-carrier freq to remain stable. */ + if(pass_through) + adv7175_write(client, 0x02, 0x00); + else + adv7175_write(client, 0x02, 0x55); + + adv7175_write(client, 0x03, 0x55); + adv7175_write(client, 0x04, 0x55); + adv7175_write(client, 0x05, 0x25); +} + #ifdef ENCODER_DUMP static void dump (struct i2c_client *client) @@ -322,6 +338,10 @@ case 0: adv7175_write(client, 0x01, 0x00); + + if (encoder->norm == VIDEO_MODE_NTSC) + set_subcarrier_freq(client, 1); + adv7175_write(client, 0x0c, TR1CAPT); /* TR1 */ if (encoder->norm == VIDEO_MODE_SECAM) adv7175_write(client, 0x0d, 0x49); // Disable genlock @@ -334,6 +354,10 @@ case 1: adv7175_write(client, 0x01, 0x00); + + if (encoder->norm == VIDEO_MODE_NTSC) + set_subcarrier_freq(client, 0); + adv7175_write(client, 0x0c, TR1PLAY); /* TR1 */ adv7175_write(client, 0x0d, 0x49); adv7175_write(client, 0x07, TR0MODE | TR0RST); @@ -343,6 +367,10 @@ case 2: adv7175_write(client, 0x01, 0x80); + + if (encoder->norm == VIDEO_MODE_NTSC) + set_subcarrier_freq(client, 0); + adv7175_write(client, 0x0d, 0x49); adv7175_write(client, 0x07, TR0MODE | TR0RST); adv7175_write(client, 0x07, TR0MODE); diff -Nru a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c --- a/drivers/media/video/bttv-cards.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/media/video/bttv-cards.c 2004-10-18 14:56:29 -07:00 @@ -31,7 +31,7 @@ #include #include #include -#ifdef CONFIG_FW_LOADER +#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) # include #endif @@ -74,6 +74,9 @@ static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input); static void picolo_tetra_init(struct bttv *btv); +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input); +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input); + static int terratec_active_radio_upgrade(struct bttv *btv); static int tea5757_read(struct bttv *btv); static int tea5757_write(struct bttv *btv, int value); @@ -170,6 +173,7 @@ { 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, { 0x6607107d, BTTV_WINFASTVC100, "Leadtek WinFast VC 100" }, + { 0x6609107d, BTTV_WINFAST2000, "Leadtek TV 2000 XP" }, { 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, { 0x264510b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, @@ -224,6 +228,7 @@ { 0x1431aa00, BTTV_PV143, "Provideo PV143B" }, { 0x1432aa00, BTTV_PV143, "Provideo PV143C" }, { 0x1433aa00, BTTV_PV143, "Provideo PV143D" }, + { 0x1433aa03, BTTV_PV143, "Security Eyes" }, { 0x1460aa00, BTTV_PV150, "Provideo PV150A-1" }, { 0x1461aa01, BTTV_PV150, "Provideo PV150A-2" }, @@ -265,6 +270,7 @@ { 0x01020304, BTTV_XGUARD, "Grandtec Grand X-Guard" }, { 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, + { 0xa0501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, { 0x18511851, BTTV_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" }, { 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, { 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" }, @@ -297,7 +303,7 @@ // DVB cards (using pci function .1 for mpeg data xfer) { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, - { 0x07611461, BTTV_NEBULA_DIGITV, "AverMedia AverTV DVB-T" }, + { 0x07611461, BTTV_AVDVBT_761, "AverMedia AverTV DVB-T" }, { 0x002611bd, BTTV_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB-T" }, { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, @@ -2078,6 +2084,69 @@ #if 0 /* untested */ .has_remote = 1, #endif +},{ + /* ---- card 0x7c ---------------------------------- */ + /* Matt Jesson */ + /* Based on the Nebula card data - added remote and new card number - BTTV_AVDVBT_761, see also ir-kbd-gpio.c */ + .name = "AverMedia AverTV DVB-T 761", + .video_inputs = 1, + .tuner = -1, + .svhs = -1, + .muxsel = { 2, 3, 1, 0}, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = -1, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, +},{ + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SQ", + .video_inputs = 16, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0x0, + .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 }, + .muxsel_hook = sigmaSQ_muxsel, + .audiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, +},{ + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SLC", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0x0, + .muxsel = { 2, 2, 2, 2 }, + .muxsel_hook = sigmaSLC_muxsel, + .audiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, +},{ + /* BTTV_APAC_VIEWCOMP */ + /* Attila Kondoros */ + /* bt878 TV + FM 0x00000000 subsystem ID */ + .name = "APAC Viewcomp 878(AMAX)", + .video_inputs = 2, + .audio_inputs = 1, + .tuner = 0, + .svhs = -1, + .gpiomask = 0xFF, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 2, 0, 0, 0, 10}, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ + .has_radio = 1, /* not every card has radio */ }}; const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -2405,6 +2474,19 @@ gpio_write(0x000000); } +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 8; + gpio_inout( 0xf, 0xf ); + gpio_bits( 0xf, inmux ); +} + +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 4; + gpio_inout( 3<<9, 3<<9 ); + gpio_bits( 3<<9, inmux<<9 ); +} /* ----------------------------------------------------------------------- */ @@ -2859,7 +2941,7 @@ return 0; } -#ifndef CONFIG_FW_LOADER +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) /* old 2.4.x way -- via soundcore's mod_firmware_load */ static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf"; @@ -4063,7 +4145,7 @@ return; } - rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); + rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),0); if (!(rc & PX_CFG_PXC200F)) { printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc); return; diff -Nru a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c --- a/drivers/media/video/bttv-driver.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/media/video/bttv-driver.c 2004-10-18 14:56:49 -07:00 @@ -1051,11 +1051,6 @@ btwrite(whitecrush_upper, BT848_WC_UP); btwrite(whitecrush_lower, BT848_WC_DOWN); - bt848_bright(btv, btv->bright); - bt848_hue(btv, btv->hue); - bt848_contrast(btv, btv->contrast); - bt848_sat(btv, btv->saturation); - if (btv->opt_lumafilter) { btwrite(0, BT848_E_CONTROL); btwrite(0, BT848_O_CONTROL); @@ -1064,6 +1059,11 @@ btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); } + bt848_bright(btv, btv->bright); + bt848_hue(btv, btv->hue); + bt848_contrast(btv, btv->contrast); + bt848_sat(btv, btv->saturation); + /* interrupt */ init_irqreg(btv); } @@ -1861,6 +1861,8 @@ if (NULL == fh->ovfmt) return -EINVAL; + if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup); if (0 != retval) return retval; @@ -2052,6 +2054,7 @@ f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = diff -Nru a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c --- a/drivers/media/video/bttv-gpio.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/media/video/bttv-gpio.c 2004-10-18 14:56:49 -07:00 @@ -106,6 +106,20 @@ } } +void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach) +{ + struct bttv_sub_driver *drv; + struct bttv_sub_device *dev; + struct list_head *item; + + list_for_each(item,&core->subs) { + dev = list_entry(item,struct bttv_sub_device,list); + drv = to_bttv_sub_drv(dev->dev.driver); + if (drv && drv->i2c_info) + drv->i2c_info(dev,client,attach); + } +} + /* ----------------------------------------------------------------------- */ /* external: sub-driver register/unregister */ diff -Nru a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c --- a/drivers/media/video/bttv-i2c.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/media/video/bttv-i2c.c 2004-10-18 14:55:54 -07:00 @@ -40,6 +40,7 @@ static void bttv_dec_use(struct i2c_adapter *adap); #endif static int attach_inform(struct i2c_client *client); +static int detach_inform(struct i2c_client *client); static int i2c_debug = 0; static int i2c_hw = 0; @@ -114,6 +115,7 @@ I2C_DEVNAME("bt848"), .id = I2C_HW_B_BT848, .client_register = attach_inform, + .client_unregister = detach_inform, }; /* ----------------------------------------------------------------------- */ @@ -298,6 +300,7 @@ .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, .algo = &bttv_algo, .client_register = attach_inform, + .client_unregister = detach_inform, }; /* ----------------------------------------------------------------------- */ @@ -324,11 +327,20 @@ if (btv->pinnacle_id != UNSET) bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); + bttv_i2c_info(&btv->c, client, 1); if (bttv_debug) printk("bttv%d: i2c attach [client=%s]\n", btv->c.nr, i2c_clientname(client)); return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + struct bttv *btv = i2c_get_adapdata(client->adapter); + + bttv_i2c_info(&btv->c, client, 0); + return 0; } void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) diff -Nru a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c --- a/drivers/media/video/bttv-risc.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/media/video/bttv-risc.c 2004-10-18 14:56:31 -07:00 @@ -55,6 +55,8 @@ instructions += 2; if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) return rc; + dprintk("bttv%d: risc packed: bpl %d lines %d instr %d size %d ptr %p\n", + btv->c.nr, bpl, lines, instructions, risc->size, risc->cpu); /* sync instruction */ rp = risc->cpu; @@ -99,8 +101,10 @@ offset += todo; } offset += padding; + dprintk("bttv%d: risc packed: line %d ptr %p\n", + btv->c.nr, line, rp); } - dprintk("bttv%d: risc planar: %d sglist elems\n", btv->c.nr, (int)(sg-sglist)); + dprintk("bttv%d: risc packed: %d sglist elems\n", btv->c.nr, (int)(sg-sglist)); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -121,6 +125,7 @@ struct scatterlist *ysg; struct scatterlist *usg; struct scatterlist *vsg; + int topfield = (0 == yoffset); int rc; /* estimate risc mem: worst case is one write per page border + @@ -145,11 +150,26 @@ (line >= (ylines - VCR_HACK_LINES))) continue; switch (vshift) { - case 0: chroma = 1; break; - case 1: chroma = !(line & 1); break; - case 2: chroma = !(line & 3); break; - default: chroma = 0; + case 0: + chroma = 1; + break; + case 1: + if (topfield) + chroma = (line & 1) == 0; + else + chroma = (line & 1) == 1; + break; + case 2: + if (topfield) + chroma = (line & 3) == 0; + else + chroma = (line & 3) == 2; + break; + default: + chroma = 0; + break; } + for (todo = ybpl; todo > 0; todo -= ylen) { /* go to next sg entry if needed */ while (yoffset && yoffset >= sg_dma_len(ysg)) { diff -Nru a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h --- a/drivers/media/video/bttv.h 2004-10-18 14:55:55 -07:00 +++ b/drivers/media/video/bttv.h 2004-10-18 14:55:55 -07:00 @@ -126,6 +126,10 @@ #define BTTV_LMLBT4 0x76 #define BTTV_PICOLO_TETRA_CHIP 0x79 #define BTTV_AVDVBT_771 0x7b +#define BTTV_AVDVBT_761 0x7c +#define BTTV_MATRIX_VISIONSQ 0x7d +#define BTTV_MATRIX_VISIONSLC 0x7e +#define BTTV_APAC_VIEWCOMP 0x7f /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -298,6 +302,8 @@ struct device_driver drv; char wanted[BUS_ID_SIZE]; void (*gpio_irq)(struct bttv_sub_device *sub); + void (*i2c_info)(struct bttv_sub_device *sub, + struct i2c_client *client, int attach); }; #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) diff -Nru a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h --- a/drivers/media/video/bttvp.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/media/video/bttvp.h 2004-10-18 14:56:28 -07:00 @@ -225,6 +225,7 @@ int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_del_devices(struct bttv_core *core); void bttv_gpio_irq(struct bttv_core *core); +void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach); /* ---------------------------------------------------------- */ diff -Nru a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c --- a/drivers/media/video/cpia.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/media/video/cpia.c 2004-10-18 14:56:48 -07:00 @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -62,6 +63,15 @@ MODULE_SUPPORTED_DEVICE("video"); #endif +static unsigned short colorspace_conv = 0; +module_param(colorspace_conv, ushort, 0444); +MODULE_PARM_DESC(colorspace_conv, + "\n Colorspace conversion:" + "\n0 = disable" + "\n1 = enable" + "\nDefault value is 0" + "\n"); + #define ABOUT "V4L-Driver for Vision CPiA based cameras" #ifndef VID_HARDWARE_CPIA @@ -1428,14 +1438,19 @@ /* supported frame palettes and depths */ static inline int valid_mode(u16 palette, u16 depth) { - return (palette == VIDEO_PALETTE_GREY && depth == 8) || - (palette == VIDEO_PALETTE_RGB555 && depth == 16) || - (palette == VIDEO_PALETTE_RGB565 && depth == 16) || - (palette == VIDEO_PALETTE_RGB24 && depth == 24) || - (palette == VIDEO_PALETTE_RGB32 && depth == 32) || - (palette == VIDEO_PALETTE_YUV422 && depth == 16) || - (palette == VIDEO_PALETTE_YUYV && depth == 16) || - (palette == VIDEO_PALETTE_UYVY && depth == 16); + if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) || + (palette == VIDEO_PALETTE_YUYV && depth == 16)) + return 1; + + if (colorspace_conv) + return (palette == VIDEO_PALETTE_GREY && depth == 8) || + (palette == VIDEO_PALETTE_RGB555 && depth == 16) || + (palette == VIDEO_PALETTE_RGB565 && depth == 16) || + (palette == VIDEO_PALETTE_RGB24 && depth == 24) || + (palette == VIDEO_PALETTE_RGB32 && depth == 32) || + (palette == VIDEO_PALETTE_UYVY && depth == 16); + + return 0; } static int match_videosize( int width, int height ) @@ -4040,6 +4055,13 @@ { printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); + + printk(KERN_WARNING "Since in-kernel colorspace conversion is not " + "allowed, it is disabled by default now. Users should fix the " + "applications in case they don't work without conversion " + "reenabled by setting the 'colorspace_conv' module " + "parameter to 1"); + #ifdef CONFIG_PROC_FS proc_cpia_create(); #endif diff -Nru a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c --- a/drivers/media/video/dpc7146.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/media/video/dpc7146.c 2004-10-18 14:56:29 -07:00 @@ -123,6 +123,7 @@ /* check if all devices are present */ if( 0 == dpc->saa7111a ) { DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n")); + i2c_del_adapter(&dpc->i2c_adapter); kfree(dpc); return -ENODEV; } diff -Nru a/drivers/media/video/meye.c b/drivers/media/video/meye.c --- a/drivers/media/video/meye.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/media/video/meye.c 2004-10-18 14:56:33 -07:00 @@ -58,7 +58,7 @@ static inline void meye_initq(struct meye_queue *queue) { queue->head = queue->tail = 0; queue->len = 0; - queue->s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED; + queue->s_lock = SPIN_LOCK_UNLOCKED; init_waitqueue_head(&queue->proc_list); } diff -Nru a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c --- a/drivers/media/video/msp3400.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/media/video/msp3400.c 2004-10-18 14:56:33 -07:00 @@ -1552,13 +1552,12 @@ /* ----------------------------------------------------------------------- */ -static int msp3400_init_module(void) +static int __init msp3400_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void msp3400_cleanup_module(void) +static void __exit msp3400_cleanup_module(void) { i2c_del_driver(&driver); } diff -Nru a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c --- a/drivers/media/video/saa7134/saa6752hs.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/media/video/saa7134/saa6752hs.c 2004-10-18 14:57:04 -07:00 @@ -387,13 +387,12 @@ .driver = &driver, }; -static int saa6752hs_init_module(void) +static int __init saa6752hs_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void saa6752hs_cleanup_module(void) +static void __exit saa6752hs_cleanup_module(void) { i2c_del_driver(&driver); } diff -Nru a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c --- a/drivers/media/video/saa7134/saa7134-cards.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/media/video/saa7134/saa7134-cards.c 2004-10-18 14:56:50 -07:00 @@ -154,6 +154,26 @@ .gpio = 0x8000, }, }, + [SAA7134_BOARD_FLYTVPLATINUM] = { + /* "Arnaud Quette" */ + .name = "LifeView FlyTV Platinum", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_SECAM, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, [SAA7134_BOARD_EMPRESS] = { /* "Gert Vervoort" */ .name = "EMPRESS", @@ -177,7 +197,6 @@ .name = name_radio, .amux = LINE2, }, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -243,7 +262,7 @@ .name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -278,7 +297,7 @@ .name = "KNC One TV-Station DVR", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x820000, .inputs = {{ .name = name_tv, @@ -302,7 +321,6 @@ .amux = LINE2, .gpio = 0x20000, }, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -333,7 +351,7 @@ .name = "Medion 5044", .audio_clock = 0x00187de7, // was: 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -414,7 +432,7 @@ //.audio_clock = 0x00200000, .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -440,7 +458,7 @@ .name = "Typhoon TV+Radio 90031", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -503,7 +521,7 @@ .name = "ASUS TV-FM 7134", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -607,7 +625,6 @@ .vmux = 8, .amux = LINE1, }}, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -666,7 +683,7 @@ .name = "AverMedia M156 / Medion 2819", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -709,7 +726,6 @@ .amux = LINE2, .tv = 1, }}, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -719,7 +735,7 @@ // probably wrong, the 7133 one is the NTSC version ... // .tuner_type = TUNER_PHILIPS_FM1236_MK3 .tuner_type = TUNER_LG_NTSC_NEW_TAPC, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -743,7 +759,7 @@ .name = "Pinnacle PCTV Stereo (saa7134)", .audio_clock = 0x00187de7, .tuner_type = TUNER_MT2032, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 3, @@ -957,7 +973,7 @@ .name = "AverMedia 305", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -989,7 +1005,7 @@ .name = "UPMOST PURPLE TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 7, @@ -1000,7 +1016,7 @@ .vmux = 7, .amux = LINE1, }}, - }, + }, [SAA7134_BOARD_ITEMS_MTV005] = { /* Norman Jonas */ .name = "Items MuchTV Plus / IT-005", @@ -1025,6 +1041,56 @@ .amux = LINE2, }, }, + [SAA7134_BOARD_CINERGY200] = { + .name = "Terratec Cinergy 200 TV", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .gpio = 0x0000, + .tv = 1, + }}, + .mute = { + .name = name_mute, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_VIDEOMATE_TV_PVR] = { + /* Alain St-Denis */ + .name = "Compro VideoMate TV PVR/FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .gpiomask = 0x808c0080, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x00080 + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x00080 + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + .gpio = 0x00080 + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x80000 + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x40000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -1088,6 +1154,12 @@ .driver_data = SAA7134_BOARD_FLYVIDEO2000, },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .subvendor = 0x5168, + .subdevice = 0x0212, + .driver_data = SAA7134_BOARD_FLYTVPLATINUM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x16be, .subdevice = 0x0003, @@ -1219,6 +1291,19 @@ .subvendor = 0x12ab, .subdevice = 0x0800, .driver_data = SAA7133_BOARD_UPMOST_PURPLE_TV, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x153B, + .subdevice = 0x1152, + .driver_data = SAA7134_BOARD_CINERGY200, + + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x185b, + .subdevice = 0xc100, + .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, },{ /* --- boards without eeprom + subsystem ID --- */ @@ -1297,6 +1382,7 @@ static void board_flyvideo(struct saa7134_dev *dev) { #if 0 + /* non-working attempt to detect the correct tuner type ... */ u32 value; int index; @@ -1307,6 +1393,10 @@ fly_list[index].tuner_type); dev->tuner_type = fly_list[index].tuner_type; #endif + printk("%s: there are different flyvideo cards with different tuners\n" + "%s: out there, you might have to use the tuner= insmod\n" + "%s: option to override the default value.\n", + dev->name, dev->name, dev->name); } /* ----------------------------------------------------------- */ @@ -1321,8 +1411,10 @@ switch (dev->board) { case SAA7134_BOARD_FLYVIDEO2000: case SAA7134_BOARD_FLYVIDEO3000: - board_flyvideo(dev); dev->has_remote = 1; + /* fall throuth */ + case SAA7134_BOARD_FLYTVPLATINUM: + board_flyvideo(dev); break; case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: @@ -1332,6 +1424,12 @@ break; case SAA7134_BOARD_AVACSSMARTTV: dev->has_remote = 1; + break; + case SAA7134_BOARD_MD5044: + printk("%s: seems there are two different versions of the MD5044\n" + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name,dev->name,dev->name); break; } return 0; diff -Nru a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c --- a/drivers/media/video/saa7134/saa7134-core.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/media/video/saa7134/saa7134-core.c 2004-10-18 14:56:28 -07:00 @@ -868,7 +868,8 @@ must_configure_manually(); dev->board = SAA7134_BOARD_UNKNOWN; } - dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[saa7134_devcount]) dev->tuner_type = tuner[saa7134_devcount]; printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", @@ -919,7 +920,7 @@ /* load i2c helpers */ if (TUNER_ABSENT != dev->tuner_type) request_module("tuner"); - if (saa7134_boards[dev->board].need_tda9887) + if (dev->tda9887_conf) request_module("tda9887"); if (card_has_ts(dev)) request_module("saa6752hs"); @@ -949,7 +950,7 @@ dev->name); goto fail4; } - printk(KERN_INFO "%s: registered device video%d [ts]\n", + printk(KERN_INFO "%s: registered device video%d [mpeg]\n", dev->name,dev->ts_dev->minor & 0x1f); } diff -Nru a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c --- a/drivers/media/video/saa7134/saa7134-i2c.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/media/video/saa7134/saa7134-i2c.c 2004-10-18 14:56:13 -07:00 @@ -327,8 +327,10 @@ { struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; + int conf = dev->tda9887_conf; saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner); + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&conf); return 0; } diff -Nru a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c --- a/drivers/media/video/saa7134/saa7134-oss.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/media/video/saa7134/saa7134-oss.c 2004-10-18 14:56:31 -07:00 @@ -776,8 +776,6 @@ dev->oss.rate = 32000; if (oss_rate) dev->oss.rate = oss_rate; - if (saa7134_boards[dev->board].i2s_rate) - dev->oss.rate = saa7134_boards[dev->board].i2s_rate; dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000; /* mixer */ diff -Nru a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c --- a/drivers/media/video/saa7134/saa7134-tvaudio.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c 2004-10-18 14:55:53 -07:00 @@ -504,7 +504,8 @@ dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); dev->tvaudio = NULL; tvaudio_init(dev); - dev->automute = 1; + if (dev->ctl_automute) + dev->automute = 1; mute_input_7134(dev); /* give the tuner some time */ @@ -924,8 +925,9 @@ int (*my_thread)(void *data) = NULL; /* enable I2S audio output */ - if (saa7134_boards[dev->board].i2s_rate) { - int i2sform = (32000 == saa7134_boards[dev->board].i2s_rate) ? 0x00 : 0x01; + if (saa7134_boards[dev->board].has_ts) { + int i2sform = (48000 == dev->oss.rate) + ? 0x01 : 0x00; /* enable I2S output */ saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); diff -Nru a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c --- a/drivers/media/video/saa7134/saa7134-video.c 2004-10-18 14:56:14 -07:00 +++ b/drivers/media/video/saa7134/saa7134-video.c 2004-10-18 14:56:14 -07:00 @@ -272,7 +272,8 @@ #define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) #define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) #define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 4) static const struct v4l2_queryctrl no_ctrl = { .name = "42", @@ -356,6 +357,13 @@ .maximum = 128, .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_AUTOMUTE, + .name = "automute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, } }; static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); @@ -433,10 +441,11 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - int luma_control,sync_control,mux; + int luma_control,sync_control,mux,nosignal; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; + nosignal = (0 == (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)); mux = card_in(dev,dev->ctl_input).vmux; luma_control = norm->luma_control; @@ -444,7 +453,7 @@ if (mux > 5) luma_control |= 0x80; /* svideo */ - if (noninterlaced) + if (noninterlaced || nosignal) sync_control |= 0x20; /* setup cropping */ @@ -1043,6 +1052,9 @@ case V4L2_CID_PRIVATE_Y_ODD: c->value = dev->ctl_y_odd; break; + case V4L2_CID_PRIVATE_AUTOMUTE: + c->value = dev->ctl_automute; + break; default: return -EINVAL; } @@ -1118,6 +1130,17 @@ dev->ctl_y_odd = c->value; restart_overlay = 1; break; + case V4L2_CID_PRIVATE_AUTOMUTE: + dev->ctl_automute = c->value; + if (dev->tda9887_conf) { + if (dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; + else + dev->tda9887_conf &= ~TDA9887_AUTOMUTE; + saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, + &dev->tda9887_conf); + } + break; default: return -EINVAL; } @@ -1820,7 +1843,7 @@ struct v4l2_frequency *f = arg; memset(f,0,sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; return 0; } @@ -1830,7 +1853,9 @@ if (0 != f->tuner) return -EINVAL; - if (V4L2_TUNER_ANALOG_TV != f->type) + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) return -EINVAL; down(&dev->lock); dev->ctl_freq = f->frequency; @@ -2244,9 +2269,12 @@ dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; + dev->ctl_mute = ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; + dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; + dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; - dev->ctl_invert = 0; - dev->ctl_mute = 1; + if (dev->tda9887_conf && dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; dev->automute = 0; INIT_LIST_HEAD(&dev->video_q.queue); @@ -2300,10 +2328,14 @@ if (0 != norm) { /* wake up tvaudio audio carrier scan thread */ saa7134_tvaudio_do_scan(dev); + if (!noninterlaced) + saa_clearb(SAA7134_SYNC_CTRL, 0x20); } else { /* no video signal -> mute audio */ - dev->automute = 1; + if (dev->ctl_automute) + dev->automute = 1; saa7134_tvaudio_setmute(dev); + saa_setb(SAA7134_SYNC_CTRL, 0x20); } } diff -Nru a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h --- a/drivers/media/video/saa7134/saa7134.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/media/video/saa7134/saa7134.h 2004-10-18 14:56:49 -07:00 @@ -156,6 +156,9 @@ #define SAA7134_BOARD_AVERMEDIA_305 35 #define SAA7133_BOARD_UPMOST_PURPLE_TV 36 #define SAA7134_BOARD_ITEMS_MTV005 37 +#define SAA7134_BOARD_CINERGY200 38 +#define SAA7134_BOARD_FLYTVPLATINUM 39 +#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40 #define SAA7134_INPUT_MAX 8 @@ -178,13 +181,12 @@ struct saa7134_input mute; /* peripheral I/O */ - unsigned int i2s_rate; unsigned int has_ts; enum saa7134_video_out video_out; /* i2c chip info */ unsigned int tuner_type; - unsigned int need_tda9887:1; + unsigned int tda9887_conf; }; #define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) @@ -362,6 +364,7 @@ /* config info */ unsigned int board; unsigned int tuner_type; + unsigned int tda9887_conf; unsigned int gpio_value; /* i2c i/o */ @@ -397,6 +400,7 @@ int ctl_mirror; int ctl_y_odd; int ctl_y_even; + int ctl_automute; /* crop */ struct v4l2_rect crop_bounds; diff -Nru a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c --- a/drivers/media/video/tda7432.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/media/video/tda7432.c 2004-10-18 14:56:48 -07:00 @@ -532,17 +532,17 @@ .driver = &driver, }; -static int tda7432_init(void) +static int __init tda7432_init(void) { if ( (loudness < 0) || (loudness > 15) ) { printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n"); return -EINVAL; } - i2c_add_driver(&driver); - return 0; + + return i2c_add_driver(&driver); } -static void tda7432_fini(void) +static void __exit tda7432_fini(void) { i2c_del_driver(&driver); } diff -Nru a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c --- a/drivers/media/video/tda9875.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/media/video/tda9875.c 2004-10-18 14:56:29 -07:00 @@ -403,13 +403,12 @@ .driver = &driver, }; -static int tda9875_init(void) +static int __init tda9875_init(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tda9875_fini(void) +static void __exit tda9875_fini(void) { i2c_del_driver(&driver); } diff -Nru a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c --- a/drivers/media/video/tda9887.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/media/video/tda9887.c 2004-10-18 14:55:53 -07:00 @@ -8,6 +8,7 @@ #include #include +#include #include /* Chips: @@ -47,6 +48,7 @@ struct i2c_client client; v4l2_std_id std; unsigned int radio; + unsigned int config; unsigned int pinnacle_id; unsigned int using_v4l2; }; @@ -397,6 +399,36 @@ return 0; } +static int tda9887_set_config(struct tda9887 *t, char *buf) +{ + if (t->config & TDA9887_PORT1) + buf[1] |= cOutputPort1Inactive; + if (t->config & TDA9887_PORT2) + buf[1] |= cOutputPort2Inactive; + if (t->config & TDA9887_QSS) + buf[1] |= cQSS; + if (t->config & TDA9887_INTERCARRIER) + buf[1] &= ~cQSS; + + if (t->config & TDA9887_AUTOMUTE) + buf[1] |= cAutoMuteFmActive; + if (t->config & TDA9887_DEEMPHASIS_MASK) { + buf[2] &= ~0x60; + switch (t->config & TDA9887_DEEMPHASIS_MASK) { + case TDA9887_DEEMPHASIS_NONE: + buf[2] |= cDeemphasisOFF; + break; + case TDA9887_DEEMPHASIS_50: + buf[2] |= cDeemphasisON | cDeemphasis50; + break; + case TDA9887_DEEMPHASIS_75: + buf[2] |= cDeemphasisON | cDeemphasis75; + break; + } + } + return 0; +} + /* ---------------------------------------------------------------------- */ static int tda9887_set_pinnacle(struct tda9887 *t, char *buf) @@ -499,6 +531,7 @@ if (UNSET != t->pinnacle_id) { tda9887_set_pinnacle(t,buf); } + tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", @@ -594,6 +627,14 @@ tda9887_configure(t); break; } + case TDA9887_SET_CONFIG: + { + int *i = arg; + + t->config = *i; + tda9887_configure(t); + break; + } /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -644,6 +685,25 @@ t->radio = 1; } tda9887_configure(t); + break; + } + case VIDIOC_G_TUNER: + { + static int AFC_BITS_2_kHz[] = { + -12500, -37500, -62500, -97500, + -112500, -137500, -162500, -187500, + 187500, 162500, 137500, 112500, + 97500 , 62500, 37500 , 12500 + }; + struct v4l2_tuner* tuner = arg; + + if (t->radio) { + __u8 reg = 0; + tuner->afc=0; + if (1 == i2c_master_recv(&t->client,®,1)) + tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; + } + break; } default: /* nothing */ @@ -670,13 +730,12 @@ .driver = &driver, }; -static int tda9887_init_module(void) +static int __init tda9887_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tda9887_cleanup_module(void) +static void __exit tda9887_cleanup_module(void) { i2c_del_driver(&driver); } diff -Nru a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c --- a/drivers/media/video/tuner.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/media/video/tuner.c 2004-10-18 14:56:50 -07:00 @@ -208,7 +208,7 @@ { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ - 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,732 }, // Corrected to NTSC=732 (was:940) + 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, @@ -229,7 +229,7 @@ 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, { "HITACHI V7-J180AT", HITACHI, NTSC, - 16*170.00, 16*450.00, 0x01,0x02,0x00,0x8e,940 }, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, { "Philips PAL_MK (FI1216 MK)", Philips, PAL, 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, @@ -241,6 +241,13 @@ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, { "Microtune 4049 FM5",Microtune,PAL, 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, + { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, + 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, + { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, + 16*170.00, 16*450.00, 0x01,0x02,0x04,0x8e,732 }, + + { "Tenna TNF 8831 BGFF)", Philips, PAL, + 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, }; #define TUNERS ARRAY_SIZE(tuners) @@ -934,6 +941,9 @@ case TUNER_PHILIPS_FM1236_MK3: buffer[3] = 0x19; break; + case TUNER_LG_PAL_FM: + buffer[3] = 0xa5; + break; default: buffer[3] = 0xa4; break; @@ -1300,13 +1310,12 @@ .driver = &driver, }; -static int tuner_init_module(void) +static int __init tuner_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tuner_cleanup_module(void) +static void __exit tuner_cleanup_module(void) { i2c_del_driver(&driver); } diff -Nru a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c --- a/drivers/media/video/tvaudio.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/media/video/tvaudio.c 2004-10-18 14:56:28 -07:00 @@ -1651,7 +1651,7 @@ .driver = &driver, }; -static int audiochip_init_module(void) +static int __init audiochip_init_module(void) { struct CHIPDESC *desc; printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); @@ -1659,11 +1659,11 @@ for (desc = chiplist; desc->name != NULL; desc++) printk("%s%s", (desc == chiplist) ? "" : ",",desc->name); printk("\n"); - i2c_add_driver(&driver); - return 0; + + return i2c_add_driver(&driver); } -static void audiochip_cleanup_module(void) +static void __exit audiochip_cleanup_module(void) { i2c_del_driver(&driver); } diff -Nru a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c --- a/drivers/media/video/tvmixer.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/media/video/tvmixer.c 2004-10-18 14:57:03 -07:00 @@ -330,17 +330,17 @@ /* ----------------------------------------------------------------------- */ -static int tvmixer_init_module(void) +static int __init tvmixer_init_module(void) { int i; for (i = 0; i < DEV_MAX; i++) devices[i].minor = -1; - i2c_add_driver(&driver); - return 0; + + return i2c_add_driver(&driver); } -static void tvmixer_cleanup_module(void) +static void __exit tvmixer_cleanup_module(void) { int i; diff -Nru a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c --- a/drivers/media/video/videodev.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/media/video/videodev.c 2004-10-18 14:55:55 -07:00 @@ -254,7 +254,7 @@ return 0; } -extern struct file_operations video_fops; +static struct file_operations video_fops; /** * video_register_device - register video4linux devices diff -Nru a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c --- a/drivers/media/video/zoran_device.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/media/video/zoran_device.c 2004-10-18 14:56:32 -07:00 @@ -1105,8 +1105,7 @@ ZR36057_ISR); btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ / 20); + msleep(50); set_videobus_dir(zr, 0); set_frame(zr, 1); // /FRAME diff -Nru a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c --- a/drivers/media/video/zoran_driver.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/media/video/zoran_driver.c 2004-10-18 14:56:49 -07:00 @@ -2265,8 +2265,8 @@ dprintk(3, KERN_DEBUG - "%s: VIDIOCSFBUF - base=0x%x, w=%d, h=%d, depth=%d, bpl=%d\n", - ZR_DEVNAME(zr), (u32) vbuf->base, vbuf->width, + "%s: VIDIOCSFBUF - base=%p, w=%d, h=%d, depth=%d, bpl=%d\n", + ZR_DEVNAME(zr), vbuf->base, vbuf->width, vbuf->height, vbuf->depth, vbuf->bytesperline); for (i = 0; i < zoran_num_formats; i++) diff -Nru a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig --- a/drivers/message/fusion/Kconfig 2004-10-18 14:57:18 -07:00 +++ b/drivers/message/fusion/Kconfig 2004-10-18 14:57:18 -07:00 @@ -27,39 +27,6 @@ necessary (or recommended) unless the user will be running large I/O's via the raw interface. -config FUSION_ISENSE - tristate "Enhanced SCSI error reporting" - depends on MODULES && FUSION && m - ---help--- - The isense module (roughly stands for Interpret SENSE data) is - completely optional. It simply provides extra English readable - strings in SCSI Error Report(s) that might be generated from the - Fusion MPT SCSI Host driver, for example when a target device - returns a SCSI check condition on a I/O. Without this module - loaded you might see: - - SCSI Error Report =-=-= (ioc0,scsi5:0) - SCSI_Status=02h (CHECK_CONDITION) - Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 - SenseKey=2h (NOT READY); FRU=02h - ASC/ASCQ=29h/00h - - Where otherwise, if this module had been loaded, you would see: - - SCSI Error Report =-=-= (ioc0,scsi5:0) - SCSI_Status=02h (CHECK_CONDITION) - Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)" - SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 - SenseKey=2h (NOT READY); FRU=02h - ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" - - Say M for "Enhanced SCSI error reporting" to compile this optional module, - creating a driver named: isense. - - NOTE: Support for building this feature into the kernel is not - available, due to kernel size considerations. - config FUSION_CTL tristate "Fusion MPT misc device (ioctl) driver" depends on MODULES && FUSION && m diff -Nru a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile --- a/drivers/message/fusion/Makefile 2004-10-18 14:56:33 -07:00 +++ b/drivers/message/fusion/Makefile 2004-10-18 14:56:33 -07:00 @@ -2,7 +2,7 @@ # Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers. # # Note! If you want to turn on various debug defines for an extended period of -# time but don't want them lingering around in the Makefile when you pass it on +# time but don't want them lingering around in the Makefile when you pass it on # to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC @@ -48,6 +48,5 @@ #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC obj-$(CONFIG_FUSION) += mptbase.o mptscsih.o -obj-$(CONFIG_FUSION_ISENSE) += isense.o obj-$(CONFIG_FUSION_CTL) += mptctl.o obj-$(CONFIG_FUSION_LAN) += mptlan.o diff -Nru a/drivers/message/fusion/ascq_tbl.c b/drivers/message/fusion/ascq_tbl.c --- a/drivers/message/fusion/ascq_tbl.c 2004-10-18 14:57:04 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,2416 +0,0 @@ -#ifndef SCSI_ASCQ_TBL_C_INCLUDED -#define SCSI_ASCQ_TBL_C_INCLUDED - -/* AuToMaGiCaLlY generated from: "t10.org/asc-num.txt" - ******************************************************************************* - * File: ASC-NUM.TXT - * - * SCSI ASC/ASCQ Assignments - * Numeric Sorted Listing - * as of 5/18/00 - * - * D - DIRECT ACCESS DEVICE (SBC-2) device column key - * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- - * . L - PRINTER DEVICE (SSC) blank = reserved - * . P - PROCESSOR DEVICE (SPC) not blank = allowed - * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) - * . . R - CD DEVICE (MMC) - * . . S - SCANNER DEVICE (SCSI-2) - * . . .O - OPTICAL MEMORY DEVICE (SBC-2) - * . . . M - MEDIA CHANGER DEVICE (SMC) - * . . . C - COMMUNICATION DEVICE (SCSI-2) - * . . . .A - STORAGE ARRAY DEVICE (SCC) - * . . . . E - ENCLOSURE SERVICES DEVICE (SES) - * . . . . B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) - * . . . . .K - OPTICAL CARD READER/WRITER DEVICE (OCRW) - * ASC/ASCQ DTLPWRSOMCAEBK Description - * ------- -------------- ---------------------------------------------------- - */ - -static char SenseDevTypes001[] = "DTLPWRSOMCAEBK"; -static char SenseDevTypes002[] = ".T............"; -static char SenseDevTypes003[] = ".T....S......."; -static char SenseDevTypes004[] = ".TL...S......."; -static char SenseDevTypes005[] = ".....R........"; -static char SenseDevTypes006[] = "DTL.WRSOM.AEBK"; -static char SenseDevTypes007[] = "D...W..O....BK"; -static char SenseDevTypes008[] = "D...WR.OM...BK"; -static char SenseDevTypes009[] = "DTL.W.SO....BK"; -static char SenseDevTypes010[] = "DTL..R.O....B."; -static char SenseDevTypes011[] = "DT..W..OMCA.BK"; -static char SenseDevTypes012[] = ".............."; -static char SenseDevTypes013[] = "DTL.WRSOMCAEBK"; -static char SenseDevTypes014[] = "DTL.WRSOM...BK"; -static char SenseDevTypes015[] = "DT...R.OM...BK"; -static char SenseDevTypes016[] = "DTLPWRSO.C...K"; -static char SenseDevTypes017[] = "DT..WR.O....B."; -static char SenseDevTypes018[] = "....WR.O.....K"; -static char SenseDevTypes019[] = "....WR.O......"; -static char SenseDevTypes020[] = ".T...RS......."; -static char SenseDevTypes021[] = ".............K"; -static char SenseDevTypes022[] = "DT..W..O....B."; -static char SenseDevTypes023[] = "DT..WRSO....BK"; -static char SenseDevTypes024[] = "DT..W.SO....BK"; -static char SenseDevTypes025[] = "....WR.O....B."; -static char SenseDevTypes026[] = "....W..O....B."; -static char SenseDevTypes027[] = "DT.....O....BK"; -static char SenseDevTypes028[] = "DTL.WRSO....BK"; -static char SenseDevTypes029[] = "DT..WR.O....BK"; -static char SenseDevTypes030[] = "DT..W..O....BK"; -static char SenseDevTypes031[] = "D...WR.O....BK"; -static char SenseDevTypes032[] = "D......O.....K"; -static char SenseDevTypes033[] = "D......O....BK"; -static char SenseDevTypes034[] = "DT..WR.OM...BK"; -static char SenseDevTypes035[] = "D............."; -static char SenseDevTypes036[] = "DTLPWRSOMCAE.K"; -static char SenseDevTypes037[] = "DTLPWRSOMCA.BK"; -static char SenseDevTypes038[] = ".T...R........"; -static char SenseDevTypes039[] = "DT..WR.OM...B."; -static char SenseDevTypes040[] = "DTL.WRSOMCAE.K"; -static char SenseDevTypes041[] = "DTLPWRSOMCAE.."; -static char SenseDevTypes042[] = "......S......."; -static char SenseDevTypes043[] = "............B."; -static char SenseDevTypes044[] = "DTLPWRSO.CA..K"; -static char SenseDevTypes045[] = "DT...R.......K"; -static char SenseDevTypes046[] = "D.L..R.O....B."; -static char SenseDevTypes047[] = "..L..........."; -static char SenseDevTypes048[] = ".TL..........."; -static char SenseDevTypes049[] = "DTLPWRSOMC..BK"; -static char SenseDevTypes050[] = "DT..WR.OMCAEBK"; -static char SenseDevTypes051[] = "DT..WR.OMCAEB."; -static char SenseDevTypes052[] = ".T...R.O......"; -static char SenseDevTypes053[] = "...P.........."; -static char SenseDevTypes054[] = "DTLPWRSOM.AE.K"; -static char SenseDevTypes055[] = "DTLPWRSOM.AE.."; -static char SenseDevTypes056[] = ".......O......"; -static char SenseDevTypes057[] = "DTLPWRSOM...BK"; -static char SenseDevTypes058[] = "DT..WR.O..A.BK"; -static char SenseDevTypes059[] = "DTLPWRSOM....K"; -static char SenseDevTypes060[] = "D......O......"; -static char SenseDevTypes061[] = ".....R......B."; -static char SenseDevTypes062[] = "D...........B."; -static char SenseDevTypes063[] = "............BK"; -static char SenseDevTypes064[] = "..........A..."; - -static ASCQ_Table_t ASCQ_Table[] = { - { - 0x00, 0x00, - SenseDevTypes001, - "NO ADDITIONAL SENSE INFORMATION" - }, - { - 0x00, 0x01, - SenseDevTypes002, - "FILEMARK DETECTED" - }, - { - 0x00, 0x02, - SenseDevTypes003, - "END-OF-PARTITION/MEDIUM DETECTED" - }, - { - 0x00, 0x03, - SenseDevTypes002, - "SETMARK DETECTED" - }, - { - 0x00, 0x04, - SenseDevTypes003, - "BEGINNING-OF-PARTITION/MEDIUM DETECTED" - }, - { - 0x00, 0x05, - SenseDevTypes004, - "END-OF-DATA DETECTED" - }, - { - 0x00, 0x06, - SenseDevTypes001, - "I/O PROCESS TERMINATED" - }, - { - 0x00, 0x11, - SenseDevTypes005, - "AUDIO PLAY OPERATION IN PROGRESS" - }, - { - 0x00, 0x12, - SenseDevTypes005, - "AUDIO PLAY OPERATION PAUSED" - }, - { - 0x00, 0x13, - SenseDevTypes005, - "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED" - }, - { - 0x00, 0x14, - SenseDevTypes005, - "AUDIO PLAY OPERATION STOPPED DUE TO ERROR" - }, - { - 0x00, 0x15, - SenseDevTypes005, - "NO CURRENT AUDIO STATUS TO RETURN" - }, - { - 0x00, 0x16, - SenseDevTypes001, - "OPERATION IN PROGRESS" - }, - { - 0x00, 0x17, - SenseDevTypes006, - "CLEANING REQUESTED" - }, - { - 0x01, 0x00, - SenseDevTypes007, - "NO INDEX/SECTOR SIGNAL" - }, - { - 0x02, 0x00, - SenseDevTypes008, - "NO SEEK COMPLETE" - }, - { - 0x03, 0x00, - SenseDevTypes009, - "PERIPHERAL DEVICE WRITE FAULT" - }, - { - 0x03, 0x01, - SenseDevTypes002, - "NO WRITE CURRENT" - }, - { - 0x03, 0x02, - SenseDevTypes002, - "EXCESSIVE WRITE ERRORS" - }, - { - 0x04, 0x00, - SenseDevTypes001, - "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE" - }, - { - 0x04, 0x01, - SenseDevTypes001, - "LOGICAL UNIT IS IN PROCESS OF BECOMING READY" - }, - { - 0x04, 0x02, - SenseDevTypes001, - "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" - }, - { - 0x04, 0x03, - SenseDevTypes001, - "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED" - }, - { - 0x04, 0x04, - SenseDevTypes010, - "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS" - }, - { - 0x04, 0x05, - SenseDevTypes011, - "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS" - }, - { - 0x04, 0x06, - SenseDevTypes011, - "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS" - }, - { - 0x04, 0x07, - SenseDevTypes001, - "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS" - }, - { - 0x04, 0x08, - SenseDevTypes005, - "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS" - }, - { - 0x04, 0x09, - SenseDevTypes001, - "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS" - }, - { - 0x04, 0x10, - SenseDevTypes012, - "auxiliary memory code 2 (99-148) [proposed]" - }, - { - 0x05, 0x00, - SenseDevTypes013, - "LOGICAL UNIT DOES NOT RESPOND TO SELECTION" - }, - { - 0x06, 0x00, - SenseDevTypes008, - "NO REFERENCE POSITION FOUND" - }, - { - 0x07, 0x00, - SenseDevTypes014, - "MULTIPLE PERIPHERAL DEVICES SELECTED" - }, - { - 0x08, 0x00, - SenseDevTypes013, - "LOGICAL UNIT COMMUNICATION FAILURE" - }, - { - 0x08, 0x01, - SenseDevTypes013, - "LOGICAL UNIT COMMUNICATION TIME-OUT" - }, - { - 0x08, 0x02, - SenseDevTypes013, - "LOGICAL UNIT COMMUNICATION PARITY ERROR" - }, - { - 0x08, 0x03, - SenseDevTypes015, - "LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32)" - }, - { - 0x08, 0x04, - SenseDevTypes016, - "UNREACHABLE COPY TARGET" - }, - { - 0x09, 0x00, - SenseDevTypes017, - "TRACK FOLLOWING ERROR" - }, - { - 0x09, 0x01, - SenseDevTypes018, - "TRACKING SERVO FAILURE" - }, - { - 0x09, 0x02, - SenseDevTypes018, - "FOCUS SERVO FAILURE" - }, - { - 0x09, 0x03, - SenseDevTypes019, - "SPINDLE SERVO FAILURE" - }, - { - 0x09, 0x04, - SenseDevTypes017, - "HEAD SELECT FAULT" - }, - { - 0x0A, 0x00, - SenseDevTypes001, - "ERROR LOG OVERFLOW" - }, - { - 0x0B, 0x00, - SenseDevTypes001, - "WARNING" - }, - { - 0x0B, 0x01, - SenseDevTypes001, - "WARNING - SPECIFIED TEMPERATURE EXCEEDED" - }, - { - 0x0B, 0x02, - SenseDevTypes001, - "WARNING - ENCLOSURE DEGRADED" - }, - { - 0x0C, 0x00, - SenseDevTypes020, - "WRITE ERROR" - }, - { - 0x0C, 0x01, - SenseDevTypes021, - "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION" - }, - { - 0x0C, 0x02, - SenseDevTypes007, - "WRITE ERROR - AUTO REALLOCATION FAILED" - }, - { - 0x0C, 0x03, - SenseDevTypes007, - "WRITE ERROR - RECOMMEND REASSIGNMENT" - }, - { - 0x0C, 0x04, - SenseDevTypes022, - "COMPRESSION CHECK MISCOMPARE ERROR" - }, - { - 0x0C, 0x05, - SenseDevTypes022, - "DATA EXPANSION OCCURRED DURING COMPRESSION" - }, - { - 0x0C, 0x06, - SenseDevTypes022, - "BLOCK NOT COMPRESSIBLE" - }, - { - 0x0C, 0x07, - SenseDevTypes005, - "WRITE ERROR - RECOVERY NEEDED" - }, - { - 0x0C, 0x08, - SenseDevTypes005, - "WRITE ERROR - RECOVERY FAILED" - }, - { - 0x0C, 0x09, - SenseDevTypes005, - "WRITE ERROR - LOSS OF STREAMING" - }, - { - 0x0C, 0x0A, - SenseDevTypes005, - "WRITE ERROR - PADDING BLOCKS ADDED" - }, - { - 0x0C, 0x0B, - SenseDevTypes012, - "auxiliary memory code 4 (99-148) [proposed]" - }, - { - 0x10, 0x00, - SenseDevTypes007, - "ID CRC OR ECC ERROR" - }, - { - 0x11, 0x00, - SenseDevTypes023, - "UNRECOVERED READ ERROR" - }, - { - 0x11, 0x01, - SenseDevTypes023, - "READ RETRIES EXHAUSTED" - }, - { - 0x11, 0x02, - SenseDevTypes023, - "ERROR TOO LONG TO CORRECT" - }, - { - 0x11, 0x03, - SenseDevTypes024, - "MULTIPLE READ ERRORS" - }, - { - 0x11, 0x04, - SenseDevTypes007, - "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED" - }, - { - 0x11, 0x05, - SenseDevTypes025, - "L-EC UNCORRECTABLE ERROR" - }, - { - 0x11, 0x06, - SenseDevTypes025, - "CIRC UNRECOVERED ERROR" - }, - { - 0x11, 0x07, - SenseDevTypes026, - "DATA RE-SYNCHRONIZATION ERROR" - }, - { - 0x11, 0x08, - SenseDevTypes002, - "INCOMPLETE BLOCK READ" - }, - { - 0x11, 0x09, - SenseDevTypes002, - "NO GAP FOUND" - }, - { - 0x11, 0x0A, - SenseDevTypes027, - "MISCORRECTED ERROR" - }, - { - 0x11, 0x0B, - SenseDevTypes007, - "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT" - }, - { - 0x11, 0x0C, - SenseDevTypes007, - "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA" - }, - { - 0x11, 0x0D, - SenseDevTypes017, - "DE-COMPRESSION CRC ERROR" - }, - { - 0x11, 0x0E, - SenseDevTypes017, - "CANNOT DECOMPRESS USING DECLARED ALGORITHM" - }, - { - 0x11, 0x0F, - SenseDevTypes005, - "ERROR READING UPC/EAN NUMBER" - }, - { - 0x11, 0x10, - SenseDevTypes005, - "ERROR READING ISRC NUMBER" - }, - { - 0x11, 0x11, - SenseDevTypes005, - "READ ERROR - LOSS OF STREAMING" - }, - { - 0x11, 0x12, - SenseDevTypes012, - "auxiliary memory code 3 (99-148) [proposed]" - }, - { - 0x12, 0x00, - SenseDevTypes007, - "ADDRESS MARK NOT FOUND FOR ID FIELD" - }, - { - 0x13, 0x00, - SenseDevTypes007, - "ADDRESS MARK NOT FOUND FOR DATA FIELD" - }, - { - 0x14, 0x00, - SenseDevTypes028, - "RECORDED ENTITY NOT FOUND" - }, - { - 0x14, 0x01, - SenseDevTypes029, - "RECORD NOT FOUND" - }, - { - 0x14, 0x02, - SenseDevTypes002, - "FILEMARK OR SETMARK NOT FOUND" - }, - { - 0x14, 0x03, - SenseDevTypes002, - "END-OF-DATA NOT FOUND" - }, - { - 0x14, 0x04, - SenseDevTypes002, - "BLOCK SEQUENCE ERROR" - }, - { - 0x14, 0x05, - SenseDevTypes030, - "RECORD NOT FOUND - RECOMMEND REASSIGNMENT" - }, - { - 0x14, 0x06, - SenseDevTypes030, - "RECORD NOT FOUND - DATA AUTO-REALLOCATED" - }, - { - 0x15, 0x00, - SenseDevTypes014, - "RANDOM POSITIONING ERROR" - }, - { - 0x15, 0x01, - SenseDevTypes014, - "MECHANICAL POSITIONING ERROR" - }, - { - 0x15, 0x02, - SenseDevTypes029, - "POSITIONING ERROR DETECTED BY READ OF MEDIUM" - }, - { - 0x16, 0x00, - SenseDevTypes007, - "DATA SYNCHRONIZATION MARK ERROR" - }, - { - 0x16, 0x01, - SenseDevTypes007, - "DATA SYNC ERROR - DATA REWRITTEN" - }, - { - 0x16, 0x02, - SenseDevTypes007, - "DATA SYNC ERROR - RECOMMEND REWRITE" - }, - { - 0x16, 0x03, - SenseDevTypes007, - "DATA SYNC ERROR - DATA AUTO-REALLOCATED" - }, - { - 0x16, 0x04, - SenseDevTypes007, - "DATA SYNC ERROR - RECOMMEND REASSIGNMENT" - }, - { - 0x17, 0x00, - SenseDevTypes023, - "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED" - }, - { - 0x17, 0x01, - SenseDevTypes023, - "RECOVERED DATA WITH RETRIES" - }, - { - 0x17, 0x02, - SenseDevTypes029, - "RECOVERED DATA WITH POSITIVE HEAD OFFSET" - }, - { - 0x17, 0x03, - SenseDevTypes029, - "RECOVERED DATA WITH NEGATIVE HEAD OFFSET" - }, - { - 0x17, 0x04, - SenseDevTypes025, - "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED" - }, - { - 0x17, 0x05, - SenseDevTypes031, - "RECOVERED DATA USING PREVIOUS SECTOR ID" - }, - { - 0x17, 0x06, - SenseDevTypes007, - "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED" - }, - { - 0x17, 0x07, - SenseDevTypes031, - "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT" - }, - { - 0x17, 0x08, - SenseDevTypes031, - "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE" - }, - { - 0x17, 0x09, - SenseDevTypes031, - "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN" - }, - { - 0x18, 0x00, - SenseDevTypes029, - "RECOVERED DATA WITH ERROR CORRECTION APPLIED" - }, - { - 0x18, 0x01, - SenseDevTypes031, - "RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED" - }, - { - 0x18, 0x02, - SenseDevTypes031, - "RECOVERED DATA - DATA AUTO-REALLOCATED" - }, - { - 0x18, 0x03, - SenseDevTypes005, - "RECOVERED DATA WITH CIRC" - }, - { - 0x18, 0x04, - SenseDevTypes005, - "RECOVERED DATA WITH L-EC" - }, - { - 0x18, 0x05, - SenseDevTypes031, - "RECOVERED DATA - RECOMMEND REASSIGNMENT" - }, - { - 0x18, 0x06, - SenseDevTypes031, - "RECOVERED DATA - RECOMMEND REWRITE" - }, - { - 0x18, 0x07, - SenseDevTypes007, - "RECOVERED DATA WITH ECC - DATA REWRITTEN" - }, - { - 0x19, 0x00, - SenseDevTypes032, - "DEFECT LIST ERROR" - }, - { - 0x19, 0x01, - SenseDevTypes032, - "DEFECT LIST NOT AVAILABLE" - }, - { - 0x19, 0x02, - SenseDevTypes032, - "DEFECT LIST ERROR IN PRIMARY LIST" - }, - { - 0x19, 0x03, - SenseDevTypes032, - "DEFECT LIST ERROR IN GROWN LIST" - }, - { - 0x1A, 0x00, - SenseDevTypes001, - "PARAMETER LIST LENGTH ERROR" - }, - { - 0x1B, 0x00, - SenseDevTypes001, - "SYNCHRONOUS DATA TRANSFER ERROR" - }, - { - 0x1C, 0x00, - SenseDevTypes033, - "DEFECT LIST NOT FOUND" - }, - { - 0x1C, 0x01, - SenseDevTypes033, - "PRIMARY DEFECT LIST NOT FOUND" - }, - { - 0x1C, 0x02, - SenseDevTypes033, - "GROWN DEFECT LIST NOT FOUND" - }, - { - 0x1D, 0x00, - SenseDevTypes029, - "MISCOMPARE DURING VERIFY OPERATION" - }, - { - 0x1E, 0x00, - SenseDevTypes007, - "RECOVERED ID WITH ECC CORRECTION" - }, - { - 0x1F, 0x00, - SenseDevTypes032, - "PARTIAL DEFECT LIST TRANSFER" - }, - { - 0x20, 0x00, - SenseDevTypes001, - "INVALID COMMAND OPERATION CODE" - }, - { - 0x20, 0x01, - SenseDevTypes012, - "access controls code 1 (99-314) [proposed]" - }, - { - 0x20, 0x02, - SenseDevTypes012, - "access controls code 2 (99-314) [proposed]" - }, - { - 0x20, 0x03, - SenseDevTypes012, - "access controls code 3 (99-314) [proposed]" - }, - { - 0x21, 0x00, - SenseDevTypes034, - "LOGICAL BLOCK ADDRESS OUT OF RANGE" - }, - { - 0x21, 0x01, - SenseDevTypes034, - "INVALID ELEMENT ADDRESS" - }, - { - 0x22, 0x00, - SenseDevTypes035, - "ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00)" - }, - { - 0x24, 0x00, - SenseDevTypes001, - "INVALID FIELD IN CDB" - }, - { - 0x24, 0x01, - SenseDevTypes001, - "CDB DECRYPTION ERROR" - }, - { - 0x25, 0x00, - SenseDevTypes001, - "LOGICAL UNIT NOT SUPPORTED" - }, - { - 0x26, 0x00, - SenseDevTypes001, - "INVALID FIELD IN PARAMETER LIST" - }, - { - 0x26, 0x01, - SenseDevTypes001, - "PARAMETER NOT SUPPORTED" - }, - { - 0x26, 0x02, - SenseDevTypes001, - "PARAMETER VALUE INVALID" - }, - { - 0x26, 0x03, - SenseDevTypes036, - "THRESHOLD PARAMETERS NOT SUPPORTED" - }, - { - 0x26, 0x04, - SenseDevTypes001, - "INVALID RELEASE OF PERSISTENT RESERVATION" - }, - { - 0x26, 0x05, - SenseDevTypes037, - "DATA DECRYPTION ERROR" - }, - { - 0x26, 0x06, - SenseDevTypes016, - "TOO MANY TARGET DESCRIPTORS" - }, - { - 0x26, 0x07, - SenseDevTypes016, - "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE" - }, - { - 0x26, 0x08, - SenseDevTypes016, - "TOO MANY SEGMENT DESCRIPTORS" - }, - { - 0x26, 0x09, - SenseDevTypes016, - "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE" - }, - { - 0x26, 0x0A, - SenseDevTypes016, - "UNEXPECTED INEXACT SEGMENT" - }, - { - 0x26, 0x0B, - SenseDevTypes016, - "INLINE DATA LENGTH EXCEEDED" - }, - { - 0x26, 0x0C, - SenseDevTypes016, - "INVALID OPERATION FOR COPY SOURCE OR DESTINATION" - }, - { - 0x26, 0x0D, - SenseDevTypes016, - "COPY SEGMENT GRANULARITY VIOLATION" - }, - { - 0x27, 0x00, - SenseDevTypes029, - "WRITE PROTECTED" - }, - { - 0x27, 0x01, - SenseDevTypes029, - "HARDWARE WRITE PROTECTED" - }, - { - 0x27, 0x02, - SenseDevTypes029, - "LOGICAL UNIT SOFTWARE WRITE PROTECTED" - }, - { - 0x27, 0x03, - SenseDevTypes038, - "ASSOCIATED WRITE PROTECT" - }, - { - 0x27, 0x04, - SenseDevTypes038, - "PERSISTENT WRITE PROTECT" - }, - { - 0x27, 0x05, - SenseDevTypes038, - "PERMANENT WRITE PROTECT" - }, - { - 0x28, 0x00, - SenseDevTypes001, - "NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED" - }, - { - 0x28, 0x01, - SenseDevTypes039, - "IMPORT OR EXPORT ELEMENT ACCESSED" - }, - { - 0x29, 0x00, - SenseDevTypes001, - "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" - }, - { - 0x29, 0x01, - SenseDevTypes001, - "POWER ON OCCURRED" - }, - { - 0x29, 0x02, - SenseDevTypes001, - "SCSI BUS RESET OCCURRED" - }, - { - 0x29, 0x03, - SenseDevTypes001, - "BUS DEVICE RESET FUNCTION OCCURRED" - }, - { - 0x29, 0x04, - SenseDevTypes001, - "DEVICE INTERNAL RESET" - }, - { - 0x29, 0x05, - SenseDevTypes001, - "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED" - }, - { - 0x29, 0x06, - SenseDevTypes001, - "TRANSCEIVER MODE CHANGED TO LVD" - }, - { - 0x2A, 0x00, - SenseDevTypes013, - "PARAMETERS CHANGED" - }, - { - 0x2A, 0x01, - SenseDevTypes013, - "MODE PARAMETERS CHANGED" - }, - { - 0x2A, 0x02, - SenseDevTypes040, - "LOG PARAMETERS CHANGED" - }, - { - 0x2A, 0x03, - SenseDevTypes036, - "RESERVATIONS PREEMPTED" - }, - { - 0x2A, 0x04, - SenseDevTypes041, - "RESERVATIONS RELEASED" - }, - { - 0x2A, 0x05, - SenseDevTypes041, - "REGISTRATIONS PREEMPTED" - }, - { - 0x2B, 0x00, - SenseDevTypes016, - "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT" - }, - { - 0x2C, 0x00, - SenseDevTypes001, - "COMMAND SEQUENCE ERROR" - }, - { - 0x2C, 0x01, - SenseDevTypes042, - "TOO MANY WINDOWS SPECIFIED" - }, - { - 0x2C, 0x02, - SenseDevTypes042, - "INVALID COMBINATION OF WINDOWS SPECIFIED" - }, - { - 0x2C, 0x03, - SenseDevTypes005, - "CURRENT PROGRAM AREA IS NOT EMPTY" - }, - { - 0x2C, 0x04, - SenseDevTypes005, - "CURRENT PROGRAM AREA IS EMPTY" - }, - { - 0x2C, 0x05, - SenseDevTypes043, - "ILLEGAL POWER CONDITION REQUEST" - }, - { - 0x2D, 0x00, - SenseDevTypes002, - "OVERWRITE ERROR ON UPDATE IN PLACE" - }, - { - 0x2E, 0x00, - SenseDevTypes044, - "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR" - }, - { - 0x2E, 0x01, - SenseDevTypes044, - "THIRD PARTY DEVICE FAILURE" - }, - { - 0x2E, 0x02, - SenseDevTypes044, - "COPY TARGET DEVICE NOT REACHABLE" - }, - { - 0x2E, 0x03, - SenseDevTypes044, - "INCORRECT COPY TARGET DEVICE TYPE" - }, - { - 0x2E, 0x04, - SenseDevTypes044, - "COPY TARGET DEVICE DATA UNDERRUN" - }, - { - 0x2E, 0x05, - SenseDevTypes044, - "COPY TARGET DEVICE DATA OVERRUN" - }, - { - 0x2F, 0x00, - SenseDevTypes001, - "COMMANDS CLEARED BY ANOTHER INITIATOR" - }, - { - 0x30, 0x00, - SenseDevTypes034, - "INCOMPATIBLE MEDIUM INSTALLED" - }, - { - 0x30, 0x01, - SenseDevTypes029, - "CANNOT READ MEDIUM - UNKNOWN FORMAT" - }, - { - 0x30, 0x02, - SenseDevTypes029, - "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT" - }, - { - 0x30, 0x03, - SenseDevTypes045, - "CLEANING CARTRIDGE INSTALLED" - }, - { - 0x30, 0x04, - SenseDevTypes029, - "CANNOT WRITE MEDIUM - UNKNOWN FORMAT" - }, - { - 0x30, 0x05, - SenseDevTypes029, - "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT" - }, - { - 0x30, 0x06, - SenseDevTypes017, - "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM" - }, - { - 0x30, 0x07, - SenseDevTypes006, - "CLEANING FAILURE" - }, - { - 0x30, 0x08, - SenseDevTypes005, - "CANNOT WRITE - APPLICATION CODE MISMATCH" - }, - { - 0x30, 0x09, - SenseDevTypes005, - "CURRENT SESSION NOT FIXATED FOR APPEND" - }, - { - 0x31, 0x00, - SenseDevTypes029, - "MEDIUM FORMAT CORRUPTED" - }, - { - 0x31, 0x01, - SenseDevTypes046, - "FORMAT COMMAND FAILED" - }, - { - 0x32, 0x00, - SenseDevTypes007, - "NO DEFECT SPARE LOCATION AVAILABLE" - }, - { - 0x32, 0x01, - SenseDevTypes007, - "DEFECT LIST UPDATE FAILURE" - }, - { - 0x33, 0x00, - SenseDevTypes002, - "TAPE LENGTH ERROR" - }, - { - 0x34, 0x00, - SenseDevTypes001, - "ENCLOSURE FAILURE" - }, - { - 0x35, 0x00, - SenseDevTypes001, - "ENCLOSURE SERVICES FAILURE" - }, - { - 0x35, 0x01, - SenseDevTypes001, - "UNSUPPORTED ENCLOSURE FUNCTION" - }, - { - 0x35, 0x02, - SenseDevTypes001, - "ENCLOSURE SERVICES UNAVAILABLE" - }, - { - 0x35, 0x03, - SenseDevTypes001, - "ENCLOSURE SERVICES TRANSFER FAILURE" - }, - { - 0x35, 0x04, - SenseDevTypes001, - "ENCLOSURE SERVICES TRANSFER REFUSED" - }, - { - 0x36, 0x00, - SenseDevTypes047, - "RIBBON, INK, OR TONER FAILURE" - }, - { - 0x37, 0x00, - SenseDevTypes013, - "ROUNDED PARAMETER" - }, - { - 0x38, 0x00, - SenseDevTypes043, - "EVENT STATUS NOTIFICATION" - }, - { - 0x38, 0x02, - SenseDevTypes043, - "ESN - POWER MANAGEMENT CLASS EVENT" - }, - { - 0x38, 0x04, - SenseDevTypes043, - "ESN - MEDIA CLASS EVENT" - }, - { - 0x38, 0x06, - SenseDevTypes043, - "ESN - DEVICE BUSY CLASS EVENT" - }, - { - 0x39, 0x00, - SenseDevTypes040, - "SAVING PARAMETERS NOT SUPPORTED" - }, - { - 0x3A, 0x00, - SenseDevTypes014, - "MEDIUM NOT PRESENT" - }, - { - 0x3A, 0x01, - SenseDevTypes034, - "MEDIUM NOT PRESENT - TRAY CLOSED" - }, - { - 0x3A, 0x02, - SenseDevTypes034, - "MEDIUM NOT PRESENT - TRAY OPEN" - }, - { - 0x3A, 0x03, - SenseDevTypes039, - "MEDIUM NOT PRESENT - LOADABLE" - }, - { - 0x3A, 0x04, - SenseDevTypes039, - "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE" - }, - { - 0x3B, 0x00, - SenseDevTypes048, - "SEQUENTIAL POSITIONING ERROR" - }, - { - 0x3B, 0x01, - SenseDevTypes002, - "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM" - }, - { - 0x3B, 0x02, - SenseDevTypes002, - "TAPE POSITION ERROR AT END-OF-MEDIUM" - }, - { - 0x3B, 0x03, - SenseDevTypes047, - "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY" - }, - { - 0x3B, 0x04, - SenseDevTypes047, - "SLEW FAILURE" - }, - { - 0x3B, 0x05, - SenseDevTypes047, - "PAPER JAM" - }, - { - 0x3B, 0x06, - SenseDevTypes047, - "FAILED TO SENSE TOP-OF-FORM" - }, - { - 0x3B, 0x07, - SenseDevTypes047, - "FAILED TO SENSE BOTTOM-OF-FORM" - }, - { - 0x3B, 0x08, - SenseDevTypes002, - "REPOSITION ERROR" - }, - { - 0x3B, 0x09, - SenseDevTypes042, - "READ PAST END OF MEDIUM" - }, - { - 0x3B, 0x0A, - SenseDevTypes042, - "READ PAST BEGINNING OF MEDIUM" - }, - { - 0x3B, 0x0B, - SenseDevTypes042, - "POSITION PAST END OF MEDIUM" - }, - { - 0x3B, 0x0C, - SenseDevTypes003, - "POSITION PAST BEGINNING OF MEDIUM" - }, - { - 0x3B, 0x0D, - SenseDevTypes034, - "MEDIUM DESTINATION ELEMENT FULL" - }, - { - 0x3B, 0x0E, - SenseDevTypes034, - "MEDIUM SOURCE ELEMENT EMPTY" - }, - { - 0x3B, 0x0F, - SenseDevTypes005, - "END OF MEDIUM REACHED" - }, - { - 0x3B, 0x11, - SenseDevTypes034, - "MEDIUM MAGAZINE NOT ACCESSIBLE" - }, - { - 0x3B, 0x12, - SenseDevTypes034, - "MEDIUM MAGAZINE REMOVED" - }, - { - 0x3B, 0x13, - SenseDevTypes034, - "MEDIUM MAGAZINE INSERTED" - }, - { - 0x3B, 0x14, - SenseDevTypes034, - "MEDIUM MAGAZINE LOCKED" - }, - { - 0x3B, 0x15, - SenseDevTypes034, - "MEDIUM MAGAZINE UNLOCKED" - }, - { - 0x3B, 0x16, - SenseDevTypes005, - "MECHANICAL POSITIONING OR CHANGER ERROR" - }, - { - 0x3D, 0x00, - SenseDevTypes036, - "INVALID BITS IN IDENTIFY MESSAGE" - }, - { - 0x3E, 0x00, - SenseDevTypes001, - "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET" - }, - { - 0x3E, 0x01, - SenseDevTypes001, - "LOGICAL UNIT FAILURE" - }, - { - 0x3E, 0x02, - SenseDevTypes001, - "TIMEOUT ON LOGICAL UNIT" - }, - { - 0x3E, 0x03, - SenseDevTypes001, - "LOGICAL UNIT FAILED SELF-TEST" - }, - { - 0x3E, 0x04, - SenseDevTypes001, - "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG" - }, - { - 0x3F, 0x00, - SenseDevTypes001, - "TARGET OPERATING CONDITIONS HAVE CHANGED" - }, - { - 0x3F, 0x01, - SenseDevTypes001, - "MICROCODE HAS BEEN CHANGED" - }, - { - 0x3F, 0x02, - SenseDevTypes049, - "CHANGED OPERATING DEFINITION" - }, - { - 0x3F, 0x03, - SenseDevTypes001, - "INQUIRY DATA HAS CHANGED" - }, - { - 0x3F, 0x04, - SenseDevTypes050, - "COMPONENT DEVICE ATTACHED" - }, - { - 0x3F, 0x05, - SenseDevTypes050, - "DEVICE IDENTIFIER CHANGED" - }, - { - 0x3F, 0x06, - SenseDevTypes051, - "REDUNDANCY GROUP CREATED OR MODIFIED" - }, - { - 0x3F, 0x07, - SenseDevTypes051, - "REDUNDANCY GROUP DELETED" - }, - { - 0x3F, 0x08, - SenseDevTypes051, - "SPARE CREATED OR MODIFIED" - }, - { - 0x3F, 0x09, - SenseDevTypes051, - "SPARE DELETED" - }, - { - 0x3F, 0x0A, - SenseDevTypes050, - "VOLUME SET CREATED OR MODIFIED" - }, - { - 0x3F, 0x0B, - SenseDevTypes050, - "VOLUME SET DELETED" - }, - { - 0x3F, 0x0C, - SenseDevTypes050, - "VOLUME SET DEASSIGNED" - }, - { - 0x3F, 0x0D, - SenseDevTypes050, - "VOLUME SET REASSIGNED" - }, - { - 0x3F, 0x0E, - SenseDevTypes041, - "REPORTED LUNS DATA HAS CHANGED" - }, - { - 0x3F, 0x0F, - SenseDevTypes001, - "ECHO BUFFER OVERWRITTEN" - }, - { - 0x3F, 0x10, - SenseDevTypes039, - "MEDIUM LOADABLE" - }, - { - 0x3F, 0x11, - SenseDevTypes039, - "MEDIUM AUXILIARY MEMORY ACCESSIBLE" - }, - { - 0x40, 0x00, - SenseDevTypes035, - "RAM FAILURE (SHOULD USE 40 NN)" - }, - { - 0x40, 0xFF, - SenseDevTypes001, - "DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH)" - }, - { - 0x41, 0x00, - SenseDevTypes035, - "DATA PATH FAILURE (SHOULD USE 40 NN)" - }, - { - 0x42, 0x00, - SenseDevTypes035, - "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)" - }, - { - 0x43, 0x00, - SenseDevTypes001, - "MESSAGE ERROR" - }, - { - 0x44, 0x00, - SenseDevTypes001, - "INTERNAL TARGET FAILURE" - }, - { - 0x45, 0x00, - SenseDevTypes001, - "SELECT OR RESELECT FAILURE" - }, - { - 0x46, 0x00, - SenseDevTypes049, - "UNSUCCESSFUL SOFT RESET" - }, - { - 0x47, 0x00, - SenseDevTypes001, - "SCSI PARITY ERROR" - }, - { - 0x47, 0x01, - SenseDevTypes001, - "DATA PHASE CRC ERROR DETECTED" - }, - { - 0x47, 0x02, - SenseDevTypes001, - "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE" - }, - { - 0x47, 0x03, - SenseDevTypes001, - "INFORMATION UNIT CRC ERROR DETECTED" - }, - { - 0x47, 0x04, - SenseDevTypes001, - "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED" - }, - { - 0x48, 0x00, - SenseDevTypes001, - "INITIATOR DETECTED ERROR MESSAGE RECEIVED" - }, - { - 0x49, 0x00, - SenseDevTypes001, - "INVALID MESSAGE ERROR" - }, - { - 0x4A, 0x00, - SenseDevTypes001, - "COMMAND PHASE ERROR" - }, - { - 0x4B, 0x00, - SenseDevTypes001, - "DATA PHASE ERROR" - }, - { - 0x4C, 0x00, - SenseDevTypes001, - "LOGICAL UNIT FAILED SELF-CONFIGURATION" - }, - { - 0x4D, 0xFF, - SenseDevTypes001, - "TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG)" - }, - { - 0x4E, 0x00, - SenseDevTypes001, - "OVERLAPPED COMMANDS ATTEMPTED" - }, - { - 0x50, 0x00, - SenseDevTypes002, - "WRITE APPEND ERROR" - }, - { - 0x50, 0x01, - SenseDevTypes002, - "WRITE APPEND POSITION ERROR" - }, - { - 0x50, 0x02, - SenseDevTypes002, - "POSITION ERROR RELATED TO TIMING" - }, - { - 0x51, 0x00, - SenseDevTypes052, - "ERASE FAILURE" - }, - { - 0x52, 0x00, - SenseDevTypes002, - "CARTRIDGE FAULT" - }, - { - 0x53, 0x00, - SenseDevTypes014, - "MEDIA LOAD OR EJECT FAILED" - }, - { - 0x53, 0x01, - SenseDevTypes002, - "UNLOAD TAPE FAILURE" - }, - { - 0x53, 0x02, - SenseDevTypes034, - "MEDIUM REMOVAL PREVENTED" - }, - { - 0x54, 0x00, - SenseDevTypes053, - "SCSI TO HOST SYSTEM INTERFACE FAILURE" - }, - { - 0x55, 0x00, - SenseDevTypes053, - "SYSTEM RESOURCE FAILURE" - }, - { - 0x55, 0x01, - SenseDevTypes033, - "SYSTEM BUFFER FULL" - }, - { - 0x55, 0x02, - SenseDevTypes054, - "INSUFFICIENT RESERVATION RESOURCES" - }, - { - 0x55, 0x03, - SenseDevTypes041, - "INSUFFICIENT RESOURCES" - }, - { - 0x55, 0x04, - SenseDevTypes055, - "INSUFFICIENT REGISTRATION RESOURCES" - }, - { - 0x55, 0x05, - SenseDevTypes012, - "access controls code 4 (99-314) [proposed]" - }, - { - 0x55, 0x06, - SenseDevTypes012, - "auxiliary memory code 1 (99-148) [proposed]" - }, - { - 0x57, 0x00, - SenseDevTypes005, - "UNABLE TO RECOVER TABLE-OF-CONTENTS" - }, - { - 0x58, 0x00, - SenseDevTypes056, - "GENERATION DOES NOT EXIST" - }, - { - 0x59, 0x00, - SenseDevTypes056, - "UPDATED BLOCK READ" - }, - { - 0x5A, 0x00, - SenseDevTypes057, - "OPERATOR REQUEST OR STATE CHANGE INPUT" - }, - { - 0x5A, 0x01, - SenseDevTypes034, - "OPERATOR MEDIUM REMOVAL REQUEST" - }, - { - 0x5A, 0x02, - SenseDevTypes058, - "OPERATOR SELECTED WRITE PROTECT" - }, - { - 0x5A, 0x03, - SenseDevTypes058, - "OPERATOR SELECTED WRITE PERMIT" - }, - { - 0x5B, 0x00, - SenseDevTypes059, - "LOG EXCEPTION" - }, - { - 0x5B, 0x01, - SenseDevTypes059, - "THRESHOLD CONDITION MET" - }, - { - 0x5B, 0x02, - SenseDevTypes059, - "LOG COUNTER AT MAXIMUM" - }, - { - 0x5B, 0x03, - SenseDevTypes059, - "LOG LIST CODES EXHAUSTED" - }, - { - 0x5C, 0x00, - SenseDevTypes060, - "RPL STATUS CHANGE" - }, - { - 0x5C, 0x01, - SenseDevTypes060, - "SPINDLES SYNCHRONIZED" - }, - { - 0x5C, 0x02, - SenseDevTypes060, - "SPINDLES NOT SYNCHRONIZED" - }, - { - 0x5D, 0x00, - SenseDevTypes001, - "FAILURE PREDICTION THRESHOLD EXCEEDED" - }, - { - 0x5D, 0x01, - SenseDevTypes061, - "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED" - }, - { - 0x5D, 0x02, - SenseDevTypes005, - "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED" - }, - { - 0x5D, 0x10, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" - }, - { - 0x5D, 0x11, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x12, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x13, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x14, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" - }, - { - 0x5D, 0x15, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH" - }, - { - 0x5D, 0x16, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH" - }, - { - 0x5D, 0x17, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS" - }, - { - 0x5D, 0x18, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED" - }, - { - 0x5D, 0x19, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE" - }, - { - 0x5D, 0x1A, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE" - }, - { - 0x5D, 0x1B, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT" - }, - { - 0x5D, 0x1C, - SenseDevTypes062, - "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" - }, - { - 0x5D, 0x20, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" - }, - { - 0x5D, 0x21, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x22, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x23, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x24, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" - }, - { - 0x5D, 0x25, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH" - }, - { - 0x5D, 0x26, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH" - }, - { - 0x5D, 0x27, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS" - }, - { - 0x5D, 0x28, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED" - }, - { - 0x5D, 0x29, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE" - }, - { - 0x5D, 0x2A, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE" - }, - { - 0x5D, 0x2B, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT" - }, - { - 0x5D, 0x2C, - SenseDevTypes062, - "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" - }, - { - 0x5D, 0x30, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" - }, - { - 0x5D, 0x31, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x32, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x33, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x34, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" - }, - { - 0x5D, 0x35, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH" - }, - { - 0x5D, 0x36, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH" - }, - { - 0x5D, 0x37, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS" - }, - { - 0x5D, 0x38, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED" - }, - { - 0x5D, 0x39, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE" - }, - { - 0x5D, 0x3A, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE" - }, - { - 0x5D, 0x3B, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT" - }, - { - 0x5D, 0x3C, - SenseDevTypes062, - "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" - }, - { - 0x5D, 0x40, - SenseDevTypes062, - "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" - }, - { - 0x5D, 0x41, - SenseDevTypes062, - "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x42, - SenseDevTypes062, - "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x43, - SenseDevTypes062, - "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x44, - SenseDevTypes062, - "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" - }, - { - 0x5D, 0x45, - SenseDevTypes062, - "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH" - }, - { - 0x5D, 0x46, - SenseDevTypes062, - "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH" - }, - { - 0x5D, 0x47, - SenseDevTypes062, - "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS" - }, - { - 0x5D, 0x48, - SenseDevTypes062, - "SERVO IMPENDING FAILURE CONTROLLER DETECTED" - }, - { - 0x5D, 0x49, - SenseDevTypes062, - "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE" - }, - { - 0x5D, 0x4A, - SenseDevTypes062, - "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE" - }, - { - 0x5D, 0x4B, - SenseDevTypes062, - "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT" - }, - { - 0x5D, 0x4C, - SenseDevTypes062, - "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" - }, - { - 0x5D, 0x50, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" - }, - { - 0x5D, 0x51, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x52, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x53, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x54, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" - }, - { - 0x5D, 0x55, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH" - }, - { - 0x5D, 0x56, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH" - }, - { - 0x5D, 0x57, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS" - }, - { - 0x5D, 0x58, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED" - }, - { - 0x5D, 0x59, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE" - }, - { - 0x5D, 0x5A, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE" - }, - { - 0x5D, 0x5B, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT" - }, - { - 0x5D, 0x5C, - SenseDevTypes062, - "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" - }, - { - 0x5D, 0x60, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" - }, - { - 0x5D, 0x61, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x62, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x63, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" - }, - { - 0x5D, 0x64, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" - }, - { - 0x5D, 0x65, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH" - }, - { - 0x5D, 0x66, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH" - }, - { - 0x5D, 0x67, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS" - }, - { - 0x5D, 0x68, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED" - }, - { - 0x5D, 0x69, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE" - }, - { - 0x5D, 0x6A, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE" - }, - { - 0x5D, 0x6B, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT" - }, - { - 0x5D, 0x6C, - SenseDevTypes062, - "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" - }, - { - 0x5D, 0xFF, - SenseDevTypes001, - "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)" - }, - { - 0x5E, 0x00, - SenseDevTypes044, - "LOW POWER CONDITION ON" - }, - { - 0x5E, 0x01, - SenseDevTypes044, - "IDLE CONDITION ACTIVATED BY TIMER" - }, - { - 0x5E, 0x02, - SenseDevTypes044, - "STANDBY CONDITION ACTIVATED BY TIMER" - }, - { - 0x5E, 0x03, - SenseDevTypes044, - "IDLE CONDITION ACTIVATED BY COMMAND" - }, - { - 0x5E, 0x04, - SenseDevTypes044, - "STANDBY CONDITION ACTIVATED BY COMMAND" - }, - { - 0x5E, 0x41, - SenseDevTypes043, - "POWER STATE CHANGE TO ACTIVE" - }, - { - 0x5E, 0x42, - SenseDevTypes043, - "POWER STATE CHANGE TO IDLE" - }, - { - 0x5E, 0x43, - SenseDevTypes043, - "POWER STATE CHANGE TO STANDBY" - }, - { - 0x5E, 0x45, - SenseDevTypes043, - "POWER STATE CHANGE TO SLEEP" - }, - { - 0x5E, 0x47, - SenseDevTypes063, - "POWER STATE CHANGE TO DEVICE CONTROL" - }, - { - 0x60, 0x00, - SenseDevTypes042, - "LAMP FAILURE" - }, - { - 0x61, 0x00, - SenseDevTypes042, - "VIDEO ACQUISITION ERROR" - }, - { - 0x61, 0x01, - SenseDevTypes042, - "UNABLE TO ACQUIRE VIDEO" - }, - { - 0x61, 0x02, - SenseDevTypes042, - "OUT OF FOCUS" - }, - { - 0x62, 0x00, - SenseDevTypes042, - "SCAN HEAD POSITIONING ERROR" - }, - { - 0x63, 0x00, - SenseDevTypes005, - "END OF USER AREA ENCOUNTERED ON THIS TRACK" - }, - { - 0x63, 0x01, - SenseDevTypes005, - "PACKET DOES NOT FIT IN AVAILABLE SPACE" - }, - { - 0x64, 0x00, - SenseDevTypes005, - "ILLEGAL MODE FOR THIS TRACK" - }, - { - 0x64, 0x01, - SenseDevTypes005, - "INVALID PACKET SIZE" - }, - { - 0x65, 0x00, - SenseDevTypes001, - "VOLTAGE FAULT" - }, - { - 0x66, 0x00, - SenseDevTypes042, - "AUTOMATIC DOCUMENT FEEDER COVER UP" - }, - { - 0x66, 0x01, - SenseDevTypes042, - "AUTOMATIC DOCUMENT FEEDER LIFT UP" - }, - { - 0x66, 0x02, - SenseDevTypes042, - "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER" - }, - { - 0x66, 0x03, - SenseDevTypes042, - "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER" - }, - { - 0x67, 0x00, - SenseDevTypes064, - "CONFIGURATION FAILURE" - }, - { - 0x67, 0x01, - SenseDevTypes064, - "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED" - }, - { - 0x67, 0x02, - SenseDevTypes064, - "ADD LOGICAL UNIT FAILED" - }, - { - 0x67, 0x03, - SenseDevTypes064, - "MODIFICATION OF LOGICAL UNIT FAILED" - }, - { - 0x67, 0x04, - SenseDevTypes064, - "EXCHANGE OF LOGICAL UNIT FAILED" - }, - { - 0x67, 0x05, - SenseDevTypes064, - "REMOVE OF LOGICAL UNIT FAILED" - }, - { - 0x67, 0x06, - SenseDevTypes064, - "ATTACHMENT OF LOGICAL UNIT FAILED" - }, - { - 0x67, 0x07, - SenseDevTypes064, - "CREATION OF LOGICAL UNIT FAILED" - }, - { - 0x67, 0x08, - SenseDevTypes064, - "ASSIGN FAILURE OCCURRED" - }, - { - 0x67, 0x09, - SenseDevTypes064, - "MULTIPLY ASSIGNED LOGICAL UNIT" - }, - { - 0x68, 0x00, - SenseDevTypes064, - "LOGICAL UNIT NOT CONFIGURED" - }, - { - 0x69, 0x00, - SenseDevTypes064, - "DATA LOSS ON LOGICAL UNIT" - }, - { - 0x69, 0x01, - SenseDevTypes064, - "MULTIPLE LOGICAL UNIT FAILURES" - }, - { - 0x69, 0x02, - SenseDevTypes064, - "PARITY/DATA MISMATCH" - }, - { - 0x6A, 0x00, - SenseDevTypes064, - "INFORMATIONAL, REFER TO LOG" - }, - { - 0x6B, 0x00, - SenseDevTypes064, - "STATE CHANGE HAS OCCURRED" - }, - { - 0x6B, 0x01, - SenseDevTypes064, - "REDUNDANCY LEVEL GOT BETTER" - }, - { - 0x6B, 0x02, - SenseDevTypes064, - "REDUNDANCY LEVEL GOT WORSE" - }, - { - 0x6C, 0x00, - SenseDevTypes064, - "REBUILD FAILURE OCCURRED" - }, - { - 0x6D, 0x00, - SenseDevTypes064, - "RECALCULATE FAILURE OCCURRED" - }, - { - 0x6E, 0x00, - SenseDevTypes064, - "COMMAND TO LOGICAL UNIT FAILED" - }, - { - 0x6F, 0x00, - SenseDevTypes005, - "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE" - }, - { - 0x6F, 0x01, - SenseDevTypes005, - "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT" - }, - { - 0x6F, 0x02, - SenseDevTypes005, - "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED" - }, - { - 0x6F, 0x03, - SenseDevTypes005, - "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION" - }, - { - 0x6F, 0x04, - SenseDevTypes005, - "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION" - }, - { - 0x6F, 0x05, - SenseDevTypes005, - "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR" - }, - { - 0x70, 0xFF, - SenseDevTypes002, - "DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN" - }, - { - 0x71, 0x00, - SenseDevTypes002, - "DECOMPRESSION EXCEPTION LONG ALGORITHM ID" - }, - { - 0x72, 0x00, - SenseDevTypes005, - "SESSION FIXATION ERROR" - }, - { - 0x72, 0x01, - SenseDevTypes005, - "SESSION FIXATION ERROR WRITING LEAD-IN" - }, - { - 0x72, 0x02, - SenseDevTypes005, - "SESSION FIXATION ERROR WRITING LEAD-OUT" - }, - { - 0x72, 0x03, - SenseDevTypes005, - "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION" - }, - { - 0x72, 0x04, - SenseDevTypes005, - "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK" - }, - { - 0x72, 0x05, - SenseDevTypes005, - "NO MORE TRACK RESERVATIONS ALLOWED" - }, - { - 0x73, 0x00, - SenseDevTypes005, - "CD CONTROL ERROR" - }, - { - 0x73, 0x01, - SenseDevTypes005, - "POWER CALIBRATION AREA ALMOST FULL" - }, - { - 0x73, 0x02, - SenseDevTypes005, - "POWER CALIBRATION AREA IS FULL" - }, - { - 0x73, 0x03, - SenseDevTypes005, - "POWER CALIBRATION AREA ERROR" - }, - { - 0x73, 0x04, - SenseDevTypes005, - "PROGRAM MEMORY AREA UPDATE FAILURE" - }, - { - 0x73, 0x05, - SenseDevTypes005, - "PROGRAM MEMORY AREA IS FULL" - }, - { - 0x73, 0x06, - SenseDevTypes005, - "RMA/PMA IS FULL" - }, -}; - -static int ASCQ_TableSize = 463; - - -#endif diff -Nru a/drivers/message/fusion/ascq_tbl.sh b/drivers/message/fusion/ascq_tbl.sh --- a/drivers/message/fusion/ascq_tbl.sh 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,109 +0,0 @@ -#!/bin/sh -# -# ascq_tbl.sh - Translate SCSI t10.org's "asc-num.txt" file of -# SCSI Additional Sense Code & Qualifiers (ASC/ASCQ's) -# into something useful in C, creating "ascq_tbl.c" file. -# -#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# - -PREF_INFILE="t10.org/asc-num.txt" # From SCSI t10.org -PREF_OUTFILE="ascq_tbl.c" - -#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# - -xlate_ascq() { - cat | awk ' - BEGIN { - DQ = "\042"; - OUTFILE = "'"${PREF_OUTFILE}"'"; - TRUE = 1; - FALSE = 0; - #debug = TRUE; - - # read and discard all lines up to and including the one that begins - # with the "magic token" of "------- -------------- ---"... - headers_gone = FALSE; - while (!headers_gone) { - if (getline <= 0) - exit 1; - header_line[++hdrs] = $0; - if (debug) - printf("header_line[%d] = :%s:\n", ++hdrs, $0); - if ($0 ~ /^------- -------------- ---/) { - headers_gone = TRUE; - } - } - outcount = 0; - } - - (NF > 1) { - ++outcount; - if (debug) - printf( "DBG: %s\n", $0 ); - ASC[outcount] = substr($0,1,2); - ASCQ[outcount] = substr($0,5,2); - devtypes = substr($0,10,14); - gsub(/ /, ".", devtypes); - DESCRIP[outcount] = substr($0,26); - - if (!(devtypes in DevTypesVoodoo)) { - DevTypesVoodoo[devtypes] = ++voodoo; - DevTypesIdx[voodoo] = devtypes; - } - DEVTYPES[outcount] = DevTypesVoodoo[devtypes]; - - # Handle 0xNN exception stuff... - if (ASCQ[outcount] == "NN" || ASCQ[outcount] == "nn") - ASCQ[outcount] = "FF"; - } - - END { - printf("#ifndef SCSI_ASCQ_TBL_C_INCLUDED\n") > OUTFILE; - printf("#define SCSI_ASCQ_TBL_C_INCLUDED\n") >> OUTFILE; - - printf("\n/* AuToMaGiCaLlY generated from: %s'"${FIN}"'%s\n", DQ, DQ) >> OUTFILE; - printf(" *******************************************************************************\n") >> OUTFILE; - for (i=1; i<=hdrs; i++) { - printf(" * %s\n", header_line[i]) >> OUTFILE; - } - printf(" */\n") >> OUTFILE; - - printf("\n") >> OUTFILE; - for (i=1; i<=voodoo; i++) { - printf("static char SenseDevTypes%03d[] = %s%s%s;\n", i, DQ, DevTypesIdx[i], DQ) >> OUTFILE; - } - - printf("\nstatic ASCQ_Table_t ASCQ_Table[] = {\n") >> OUTFILE; - for (i=1; i<=outcount; i++) { - printf(" {\n") >> OUTFILE; - printf(" 0x%s, 0x%s,\n", ASC[i], ASCQ[i]) >> OUTFILE; - printf(" SenseDevTypes%03d,\n", DEVTYPES[i]) >> OUTFILE; - printf(" %s%s%s\n", DQ, DESCRIP[i], DQ) >> OUTFILE; - printf(" },\n") >> OUTFILE; - } - printf( "};\n\n" ) >> OUTFILE; - - printf( "static int ASCQ_TableSize = %d;\n\n", outcount ) >> OUTFILE; - printf( "Total of %d ASC/ASCQ records generated\n", outcount ); - printf("\n#endif\n") >> OUTFILE; - close(OUTFILE); - }' - return -} - -#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# - -# main() -if [ $# -lt 1 ]; then - echo "INFO: No input filename supplied - using: $PREF_INFILE" >&2 - FIN=$PREF_INFILE -else - FIN="$1" - if [ "$FIN" != "$PREF_INFILE" ]; then - echo "INFO: Ok, I'll try chewing on '$FIN' for SCSI ASC/ASCQ combos..." >&2 - fi - shift -fi - -cat $FIN | xlate_ascq -exit 0 diff -Nru a/drivers/message/fusion/isense.c b/drivers/message/fusion/isense.c --- a/drivers/message/fusion/isense.c 2004-10-18 14:56:31 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,119 +0,0 @@ -/* - * linux/drivers/message/fusion/isense.c - * Little linux driver / shim that interfaces with the Fusion MPT - * Linux base driver to provide english readable strings in SCSI - * Error Report logging output. This module implements SCSI-3 - * Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings. - * - * Copyright (c) 1991-2004 Steven J. Ralston - * Written By: Steven J. Ralston - * (yes I wrote some of the orig. code back in 1991!) - * (mailto:sjralston1@netscape.net) - * (mailto:mpt_linux_developer@lsil.com) - * - * $Id: isense.c,v 1.33 2002/02/27 18:44:19 sralston Exp $ - */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - 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; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - NO WARRANTY - THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - DISCLAIMER OF LIABILITY - NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -#include -#include -#include -#include -#include -#include - -#define MODULEAUTHOR "Steven J. Ralston" -#define COPYRIGHT "Copyright (c) 2001-2004 " MODULEAUTHOR -#include "mptbase.h" - -#include "isense.h" - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Private data... - */ - -/* - * YIKES! I don't usually #include C source files, but.. - * The following #include's pulls in our needed ASCQ_Table[] array, - * ASCQ_TableSz integer, and ScsiOpcodeString[] array! - */ -#include "ascq_tbl.c" -#include "scsiops.c" - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#define my_NAME "SCSI-3 Opcodes & ASC/ASCQ Strings" -#define my_VERSION MPT_LINUX_VERSION_COMMON -#define MYNAM "isense" - -MODULE_AUTHOR(MODULEAUTHOR); -MODULE_DESCRIPTION(my_NAME); -MODULE_LICENSE("GPL"); - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -int __init isense_init(void) -{ - show_mptmod_ver(my_NAME, my_VERSION); - - /* - * Install our handler - */ - if (mpt_register_ascqops_strings(&ASCQ_Table[0], ASCQ_TableSize, ScsiOpcodeString) != 1) - { - printk(KERN_ERR MYNAM ": ERROR: Can't register with Fusion MPT base driver!\n"); - return -EBUSY; - } - printk(KERN_INFO MYNAM ": Registered SCSI-3 Opcodes & ASC/ASCQ Strings\n"); - return 0; -} - - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static void isense_exit(void) -{ -#ifdef MODULE - mpt_deregister_ascqops_strings(); -#endif - printk(KERN_INFO MYNAM ": Deregistered SCSI-3 Opcodes & ASC/ASCQ Strings\n"); -} - -module_init(isense_init); -module_exit(isense_exit); - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - diff -Nru a/drivers/message/fusion/isense.h b/drivers/message/fusion/isense.h --- a/drivers/message/fusion/isense.h 2004-10-18 14:56:33 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,95 +0,0 @@ -#ifndef ISENSE_H_INCLUDED -#define ISENSE_H_INCLUDED -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -#ifdef __KERNEL__ -#include /* needed for u8, etc. */ -#include /* needed for strcat */ -#include /* needed for sprintf */ -#else - #ifndef U_STUFF_DEFINED - #define U_STUFF_DEFINED - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned int u32; - #endif -#endif - -#include "scsi3.h" /* needed for all things SCSI */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Defines and typedefs... - */ - -#ifdef __KERNEL__ -#define PrintF(x) printk x -#else -#define PrintF(x) printf x -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#define RETRY_STATUS ((int) 1) -#define PUT_STATUS ((int) 0) - -/* - * A generic structure to hold info about IO request that caused - * a Request Sense to be performed, and the resulting Sense Data. - */ -typedef struct IO_Info -{ - char *DevIDStr; /* String of chars which identifies the device. */ - u8 *cdbPtr; /* Pointer (Virtual/Logical addr) to CDB bytes of - IO request that caused ContAllegianceCond. */ - u8 *sensePtr; /* Pointer (Virtual/Logical addr) to Sense Data - returned by Request Sense operation. */ - u8 *dataPtr; /* Pointer (Virtual/Logical addr) to Data buffer - of IO request caused ContAllegianceCondition. */ - u8 *inqPtr; /* Pointer (Virtual/Logical addr) to Inquiry Data for - IO *Device* that caused ContAllegianceCondition. */ - u8 SCSIStatus; /* SCSI status byte of IO request that caused - Contingent Allegiance Condition. */ - u8 DoDisplay; /* Shall we display any messages? */ - u16 rsvd_align1; - u32 ComplCode; /* Four-byte OS-dependent completion code. */ - u32 NotifyL; /* Four-byte OS-dependent notification field. */ -} IO_Info_t; - -/* - * SCSI Additional Sense Code and Additional Sense Code Qualifier table. - */ -typedef struct ASCQ_Table -{ - u8 ASC; - u8 ASCQ; - char *DevTypes; - char *Description; -} ASCQ_Table_t; - -#if 0 -/* - * SCSI Opcodes table. - */ -typedef struct SCSI_OPS_Table -{ - u8 OpCode; - char *DevTypes; - char *ScsiCmndStr; -} SCSI_OPS_Table_t; -#endif - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Public entry point prototypes - */ - -/* in scsiherr.c, needed by mptscsih.c */ -extern int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop); - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#endif - diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c --- a/drivers/message/fusion/mptbase.c 2004-10-18 14:56:19 -07:00 +++ b/drivers/message/fusion/mptbase.c 2004-10-18 14:56:19 -07:00 @@ -139,11 +139,6 @@ DmpServices_t *DmpService; -void *mpt_v_ASCQ_TablePtr; -const char **mpt_ScsiOpcodesPtr; -int mpt_ASCQ_TableSz; - - #define WHOINIT_UNKNOWN 0xAA /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -165,7 +160,6 @@ static int FusionInitCalled = 0; static int mpt_base_index = -1; static int last_drv_idx = -1; -static int isense_idx = -1; static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); @@ -177,8 +171,8 @@ static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag); -static void mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev); -static void mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup); +static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev); +static void mpt_adapter_disable(MPT_ADAPTER *ioc); static void mpt_adapter_dispose(MPT_ADAPTER *ioc); static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); @@ -291,7 +285,7 @@ int type; int freeme; - ioc = bus_id; + ioc = (MPT_ADAPTER *)bus_id; /* * Drain the reply FIFO! @@ -333,8 +327,8 @@ cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n", - ioc->name, mr)); + dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x\n", + ioc->name, mr, req_idx)); DBG_DUMP_REPLY_FRAME(mr) /* NEW! 20010301 -sralston @@ -358,7 +352,7 @@ /* * Process turbo (context) reply... */ - dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%08x)\n", ioc->name, pa)); + dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa)); type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT); if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) { cb_idx = mpt_stm_index; @@ -506,7 +500,7 @@ results = ProcessEventNotification(ioc, pEvReply, &evHandlers); if (results != evHandlers) { /* CHECKME! Any special handling needed here? */ - dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", + devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", ioc->name, evHandlers, results)); } @@ -659,8 +653,6 @@ MptEvHandlers[cb_idx] = NULL; last_drv_idx++; - if (isense_idx != -1 && isense_idx <= cb_idx) - isense_idx++; } } @@ -803,56 +795,60 @@ * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) * allocated per MPT adapter. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * * Returns pointer to a MPT request frame or %NULL if none are available * or IOC is not active. */ MPT_FRAME_HDR* -mpt_get_msg_frame(int handle, MPT_ADAPTER *iocp) +mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) { MPT_FRAME_HDR *mf; unsigned long flags; + u16 req_idx; /* Request index */ + + /* validate handle and ioc identifier */ #ifdef MFCNT - if (!iocp->active) + if (!ioc->active) printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n"); #endif /* If interrupts are not attached, do not return a request frame */ - if (!iocp->active) + if (!ioc->active) return NULL; - spin_lock_irqsave(&iocp->FreeQlock, flags); - if (! Q_IS_EMPTY(&iocp->FreeQ)) { + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (! Q_IS_EMPTY(&ioc->FreeQ)) { int req_offset; - mf = iocp->FreeQ.head; + mf = ioc->FreeQ.head; Q_DEL_ITEM(&mf->u.frame.linkage); mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ - req_offset = (u8 *)mf - (u8 *)iocp->req_frames; + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; /* u16! */ - mf->u.frame.hwhdr.msgctxu.fld.req_idx = - cpu_to_le16(req_offset / iocp->req_sz); + req_idx = cpu_to_le16(req_offset / ioc->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.req_idx = req_idx; mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */ #ifdef MFCNT - iocp->mfcnt++; + ioc->mfcnt++; #endif } else mf = NULL; - spin_unlock_irqrestore(&iocp->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); #ifdef MFCNT if (mf == NULL) - printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth); + printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth); mfcounter++; if (mfcounter == PRINT_MF_COUNT) - printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth); + printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth); #endif dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", - iocp->name, handle, iocid, mf)); + ioc->name, handle, ioc->id, mf)); return mf; } @@ -861,23 +857,25 @@ * mpt_put_msg_frame - Send a protocol specific MPT request frame * to a IOC. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * * This routine posts a MPT request frame to the request post FIFO of a * specific MPT adapter. */ void -mpt_put_msg_frame(int handle, MPT_ADAPTER *iocp, MPT_FRAME_HDR *mf) +mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { u32 mf_dma_addr; int req_offset; + u16 req_idx; /* Request index */ /* ensure values are reset properly! */ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ - req_offset = (u8 *)mf - (u8 *)iocp->req_frames; - /* u16! */ - mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz); + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; + /* u16! */ + req_idx = cpu_to_le16(req_offset / ioc->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.req_idx = req_idx; mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; #ifdef MPT_DEBUG_MSG_FRAME @@ -886,8 +884,8 @@ int ii, n; printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", - iocp->name, m); - n = iocp->req_sz/4 - 1; + ioc->name, m); + n = ioc->req_sz/4 - 1; while (m[n] == 0) n--; for (ii=0; ii<=n; ii++) { @@ -899,32 +897,33 @@ } #endif - mf_dma_addr = iocp->req_frames_low_dma + req_offset; - CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); + mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; + dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx])); + CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_free_msg_frame - Place MPT request frame back on FreeQ. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. */ void -mpt_free_msg_frame(int handle, MPT_ADAPTER *iocp, MPT_FRAME_HDR *mf) +mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { unsigned long flags; /* Put Request back on FreeQ! */ - spin_lock_irqsave(&iocp->FreeQlock, flags); - Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); #ifdef MFCNT - iocp->mfcnt--; + ioc->mfcnt--; #endif - spin_unlock_irqrestore(&iocp->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -996,7 +995,7 @@ * mpt_send_handshake_request - Send MPT request via doorbell * handshake method. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. @@ -1010,7 +1009,7 @@ * Returns 0 for success, non-zero for failure. */ int -mpt_send_handshake_request(int handle, MPT_ADAPTER *iocp, int reqBytes, u32 *req, int sleepFlag) +mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) { int r = 0; u8 *req_as_bytes; @@ -1026,37 +1025,38 @@ * setting cb_idx/req_idx. But ONLY if this request * is in proper (pre-alloc'd) request buffer range... */ - ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req); - if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) { + ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); + if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; } /* Make sure there are no doorbells */ - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); - CHIPREG_WRITE32(&iocp->chip->Doorbell, + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + CHIPREG_WRITE32(&ioc->chip->Doorbell, ((MPI_FUNCTION_HANDSHAKE<chip->Doorbell) & MPI_DOORBELL_ACTIVE)) + if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) return -5; dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", - iocp->name, ii)); + ioc->name, ii)); - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - r = WaitForDoorbellAck(iocp, 5, sleepFlag); - if (r < 0) + if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { return -2; - + } + /* Send request via doorbell handshake */ req_as_bytes = (u8 *) req; for (ii = 0; ii < reqBytes/4; ii++) { @@ -1066,21 +1066,21 @@ (req_as_bytes[(ii*4) + 1] << 8) | (req_as_bytes[(ii*4) + 2] << 16) | (req_as_bytes[(ii*4) + 3] << 24)); - CHIPREG_WRITE32(&iocp->chip->Doorbell, word); - r = WaitForDoorbellAck(iocp, 5, sleepFlag); - if (r < 0) { + CHIPREG_WRITE32(&ioc->chip->Doorbell, word); + if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { r = -3; break; } } - if (r >= 0 && WaitForDoorbellInt(iocp, 10, sleepFlag) >= 0) + if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0) r = 0; else r = -4; /* Make sure there are no doorbells */ - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + return r; } @@ -1141,11 +1141,15 @@ u8 revision; u8 pcixcmd; static int mpt_ids = 0; +#ifdef CONFIG_PROC_FS struct proc_dir_entry *dent, *ent; +#endif if (pci_enable_device(pdev)) return r; + dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n")); + if (!pci_set_dma_mask(pdev, mask)) { dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); @@ -1170,9 +1174,8 @@ ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; - + ioc->pcidev = pdev; - ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); @@ -1223,8 +1226,8 @@ return -EINVAL; } - dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); - dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); + dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); + dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); mem = NULL; /* Get logical ptr for PciMem0 space */ @@ -1236,15 +1239,15 @@ return -EINVAL; } ioc->memmap = mem; - dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); + dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); - dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", + dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", &ioc->facts, &ioc->pfacts[0])); ioc->mem_phys = mem_phys; ioc->chip = (SYSIF_REGS*)mem; - /* Save Port IO values incase we need to do downloadboot */ + /* Save Port IO values in case we need to do downloadboot */ { u8 *pmem = (u8*)port; ioc->pio_mem_phys = port; @@ -1314,7 +1317,6 @@ sprintf(ioc->name, "ioc%d", ioc->id); - Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); spin_lock_init(&ioc->FreeQlock); /* Disable all! */ @@ -1337,7 +1339,6 @@ printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", ioc->name, __irq_itoa(pdev->irq)); #endif - Q_DEL_ITEM(ioc); list_del(&ioc->list); iounmap(mem); kfree(ioc); @@ -1369,7 +1370,6 @@ ": WARNING - %s did not initialize properly! (%d)\n", ioc->name, r); - Q_DEL_ITEM(ioc); list_del(&ioc->list); free_irq(ioc->pci_irq, ioc); iounmap(mem); @@ -1386,6 +1386,7 @@ } } +#ifdef CONFIG_PROC_FS /* * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. */ @@ -1402,6 +1403,7 @@ ent->data = ioc; } } +#endif return 0; } @@ -1625,7 +1627,7 @@ int hard_reset_done = 0; int alt_ioc_ready = 0; int hard; - int r; + int rc=0; int ii; int handlers; int ret = 0; @@ -1675,39 +1677,37 @@ * and 1 if a hard reset was performed. */ if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { - if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) + if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else printk(KERN_WARNING MYNAM - ": alt-%s: (%d) Not ready WARNING!\n", - ioc->alt_ioc->name, r); + ": alt-%s: Not ready WARNING!\n", + ioc->alt_ioc->name); } for (ii=0; ii<5; ii++) { - /* Get IOC facts! Allow 1 retry */ - if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) { - dinitprintk((MYIOC_s_INFO_FMT - "ii=%d IocFacts failed r=%x\n", ioc->name, ii, r)); - } else + /* Get IOC facts! Allow 5 retries */ + if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) break; } + - if (r) { - dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed r=%x\n", ioc->name, r)); + if (ii == 5) { + dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc)); ret = -2; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); } - + if (alt_ioc_ready) { - if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { - dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed r=%x\n", ioc->name, r)); + if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { + dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); /* Retry - alt IOC was initialized once */ - r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); + rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); } - if (r) { - dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed r=%x\n", ioc->name, r)); + if (rc) { + dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { @@ -1720,29 +1720,29 @@ * init as upper addresses are needed for init. * If fails, continue with alt-ioc processing */ - if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0)) + if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) ret = -3; /* May need to check/upload firmware & data here! * If fails, continue with alt-ioc processing */ - if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0)) + if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) ret = -4; // NEW! - if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) { + if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", - ioc->alt_ioc->name, r); + ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } if (alt_ioc_ready) { - if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { + if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n", - ioc->alt_ioc->name, r); + ioc->alt_ioc->name, rc); } } @@ -1754,18 +1754,8 @@ /* Controller is not operational, cannot do upload */ if (ret == 0) { - r = mpt_do_upload(ioc, sleepFlag); - if (r != 0) - printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); - } - - /* Handle the alt IOC too */ - if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){ - ddlprintk((MYIOC_s_INFO_FMT - "Alt-ioc firmware upload required!\n", - ioc->name)); - r = mpt_do_upload(ioc->alt_ioc, sleepFlag); - if (r != 0) + rc = mpt_do_upload(ioc, sleepFlag); + if (rc != 0) printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); } } @@ -1859,19 +1849,19 @@ * MptResetHandlers[] registered yet. */ if (hard_reset_done) { - r = handlers = 0; + rc = handlers = 0; for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { if ((ret == 0) && MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n", ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); + rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); handlers++; } if (alt_ioc_ready && MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", ioc->name, ioc->alt_ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); + rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); handlers++; } } @@ -1932,84 +1922,90 @@ /* * mpt_adapter_disable - Disable misbehaving MPT adapter. * @this: Pointer to MPT adapter structure - * @free: Free up alloc'd reply, request, etc. */ static void -mpt_adapter_disable(MPT_ADAPTER *this, int freeup) +mpt_adapter_disable(MPT_ADAPTER *ioc) { - if (this != NULL) { - int sz=0; - int ret; - - if (this->cached_fw != NULL) { - ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n")); + int sz; + int ret; - if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) { - printk(KERN_WARNING MYNAM - ": firmware downloadboot failure (%d)!\n", ret); - } + if (ioc->cached_fw != NULL) { + ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n")); + if ((ret = mpt_downloadboot(ioc, NO_SLEEP)) < 0) { + printk(KERN_WARNING MYNAM + ": firmware downloadboot failure (%d)!\n", ret); } + } - /* Disable adapter interrupts! */ - CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); - this->active = 0; - /* Clear any lingering interrupt */ - CHIPREG_WRITE32(&this->chip->IntStatus, 0); - - if (freeup && this->fifo_pool != NULL) { - pci_free_consistent(this->pcidev, - this->fifo_pool_sz, - this->fifo_pool, this->fifo_pool_dma); - this->reply_frames = NULL; - this->reply_alloc = NULL; - this->req_frames = NULL; - this->req_alloc = NULL; - this->chain_alloc = NULL; - this->fifo_pool = NULL; - this->alloc_total -= this->fifo_pool_sz; - } - if (freeup && this->sense_buf_pool != NULL) { - sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC); - pci_free_consistent(this->pcidev, sz, - this->sense_buf_pool, this->sense_buf_pool_dma); - this->sense_buf_pool = NULL; - this->alloc_total -= sz; - } - - if (freeup && this->events != NULL){ - sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); - kfree(this->events); - this->events = NULL; - this->alloc_total -= sz; - } - - if (freeup && this->cached_fw != NULL) { - - sz = this->facts.FWImageSize; - pci_free_consistent(this->pcidev, sz, - this->cached_fw, this->cached_fw_dma); - this->cached_fw = NULL; - this->alloc_total -= sz; - } - - if (freeup && this->spi_data.nvram != NULL) { - kfree(this->spi_data.nvram); - this->spi_data.nvram = NULL; - } - - if (freeup && this->spi_data.pIocPg3 != NULL) { - kfree(this->spi_data.pIocPg3); - this->spi_data.pIocPg3 = NULL; - } - - if (freeup && this->spi_data.pIocPg4 != NULL) { - sz = this->spi_data.IocPg4Sz; - pci_free_consistent(this->pcidev, sz, - this->spi_data.pIocPg4, - this->spi_data.IocPg4_dma); - this->spi_data.pIocPg4 = NULL; - this->alloc_total -= sz; - } + /* Disable adapter interrupts! */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + ioc->active = 0; + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; + dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n", + ioc->name, ioc->alloc, ioc->alloc_sz)); + pci_free_consistent(ioc->pcidev, sz, + ioc->alloc, ioc->alloc_dma); + ioc->reply_frames = NULL; + ioc->req_frames = NULL; + ioc->alloc = NULL; + ioc->alloc_total -= sz; + } + + if (ioc->sense_buf_pool != NULL) { + sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); + pci_free_consistent(ioc->pcidev, sz, + ioc->sense_buf_pool, ioc->sense_buf_pool_dma); + ioc->sense_buf_pool = NULL; + ioc->alloc_total -= sz; + } + + if (ioc->events != NULL){ + sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); + kfree(ioc->events); + ioc->events = NULL; + ioc->alloc_total -= sz; + } + + if (ioc->cached_fw != NULL) { + sz = ioc->facts.FWImageSize; + pci_free_consistent(ioc->pcidev, sz, + ioc->cached_fw, ioc->cached_fw_dma); + ioc->cached_fw = NULL; + ioc->alloc_total -= sz; + } + + if (ioc->spi_data.nvram != NULL) { + kfree(ioc->spi_data.nvram); + ioc->spi_data.nvram = NULL; + } + + if (ioc->spi_data.pIocPg3 != NULL) { + kfree(ioc->spi_data.pIocPg3); + ioc->spi_data.pIocPg3 = NULL; + } + + if (ioc->spi_data.pIocPg4 != NULL) { + sz = ioc->spi_data.IocPg4Sz; + pci_free_consistent(ioc->pcidev, sz, + ioc->spi_data.pIocPg4, + ioc->spi_data.IocPg4_dma); + ioc->spi_data.pIocPg4 = NULL; + ioc->alloc_total -= sz; + } + + if (ioc->ReqToChain != NULL) { + kfree(ioc->ReqToChain); + kfree(ioc->RequestNB); + ioc->ReqToChain = NULL; + } + + if (ioc->ChainToChain != NULL) { + kfree(ioc->ChainToChain); + ioc->ChainToChain = NULL; } } @@ -2017,43 +2013,43 @@ /* * mpt_adapter_dispose - Free all resources associated with a MPT * adapter. - * @this: Pointer to MPT adapter structure + * @ioc: Pointer to MPT adapter structure * * This routine unregisters h/w resources and frees all alloc'd memory * associated with a MPT adapter structure. */ static void -mpt_adapter_dispose(MPT_ADAPTER *this) +mpt_adapter_dispose(MPT_ADAPTER *ioc) { - if (this != NULL) { + if (ioc != NULL) { int sz_first, sz_last; - sz_first = this->alloc_total; + sz_first = ioc->alloc_total; - mpt_adapter_disable(this, 1); + mpt_adapter_disable(ioc); - if (this->pci_irq != -1) { - free_irq(this->pci_irq, this); - this->pci_irq = -1; + if (ioc->pci_irq != -1) { + free_irq(ioc->pci_irq, ioc); + ioc->pci_irq = -1; } - if (this->memmap != NULL) - iounmap((u8 *) this->memmap); + if (ioc->memmap != NULL) + iounmap((u8 *) ioc->memmap); #if defined(CONFIG_MTRR) && 0 - if (this->mtrr_reg > 0) { - mtrr_del(this->mtrr_reg, 0, 0); - dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name)); + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name)); } #endif /* Zap the adapter lookup ptr! */ - list_del(&this->list); + list_del(&ioc->list); - sz_last = this->alloc_total; + sz_last = ioc->alloc_total; dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", - this->name, sz_first-sz_last+(int)sizeof(*this), sz_first)); - kfree(this); + ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); + kfree(ioc); } } @@ -2228,13 +2224,13 @@ ii++; cntdn--; if (!cntdn) { printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (ii+5)/HZ); + ioc->name, (int)((ii+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); } else { mdelay (1); /* 1 msec delay */ } @@ -2292,7 +2288,9 @@ int r; int req_sz; int reply_sz; - u32 status; + int sz; + u32 status, vv; + u8 shiftFactor=1; /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { @@ -2315,7 +2313,9 @@ get_facts.Function = MPI_FUNCTION_IOC_FACTS; /* Assert: All other get_facts fields are zero! */ - dinitprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name)); + dinitprintk((MYIOC_s_INFO_FMT + "Sending get IocFacts request req_sz=%d reply_sz=%d\n", + ioc->name, req_sz, reply_sz)); /* No non-zero fields in the get_facts request are greater than * 1 byte in size, so we can just fire it off as is. @@ -2388,6 +2388,13 @@ facts->FWImageSize = le32_to_cpu(facts->FWImageSize); } + sz = facts->FWImageSize; + if ( sz & 0x01 ) + sz += 1; + if ( sz & 0x02 ) + sz += 2; + facts->FWImageSize = sz; + if (!facts->RequestFrameSize) { /* Something is wrong! */ printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", @@ -2395,6 +2402,18 @@ return -55; } + r = sz = le32_to_cpu(facts->BlockSize); + vv = ((63 / (sz * 4)) + 1) & 0x03; + ioc->NB_for_64_byte_frame = vv; + while ( sz ) + { + shiftFactor++; + sz = sz >> 1; + } + ioc->NBShiftFactor = shiftFactor; + dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", + ioc->name, vv, shiftFactor, r)); + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { /* * Set values for this IOC's request & reply frame sizes, @@ -2405,9 +2424,9 @@ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); - dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", + dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", ioc->name, ioc->reply_sz, ioc->reply_depth)); - dprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", + dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", ioc->name, ioc->req_sz, ioc->req_depth)); /* Get port facts! */ @@ -2416,7 +2435,7 @@ } } else { printk(MYIOC_s_ERR_FMT - "Invalid IOC facts reply, msgLength=%d offsetof=%d!\n", + "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n", ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32))); return -66; @@ -2465,7 +2484,7 @@ get_pfacts.PortNumber = portnum; /* Assert: All other get_pfacts fields are zero! */ - dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", + dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", ioc->name, portnum)); /* No non-zero fields in the get_pfacts request are greater than @@ -2516,24 +2535,18 @@ memset(&init_reply, 0, sizeof(init_reply)); ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; -/* ioc_init.ChainOffset = 0; */ ioc_init.Function = MPI_FUNCTION_IOC_INIT; -/* ioc_init.Flags = 0; */ /* If we are in a recovery mode and we uploaded the FW image, * then this pointer is not NULL. Skip the upload a second time. * Set this flag if cached_fw set for either IOC. */ - ioc->upload_fw = 0; - ioc_init.Flags = 0; - if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) - ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE; - else - ioc->upload_fw = 1; - } - ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", - ioc->name, ioc_init.Flags, ioc->upload_fw)); + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) + ioc->upload_fw = 1; + else + ioc->upload_fw = 0; + ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n", + ioc->name, ioc->upload_fw, ioc->facts.Flags)); if ((int)ioc->chip_type <= (int)FC929) { ioc_init.MaxDevices = MPT_MAX_FC_DEVICES; @@ -2542,17 +2555,13 @@ } ioc_init.MaxBuses = MPT_MAX_BUS; -/* ioc_init.MsgFlags = 0; */ -/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ - - ioc->facts.RequestFrameSize = ioc_init.ReplyFrameSize; if (sizeof(dma_addr_t) == sizeof(u64)) { /* Save the upper 32-bits of the request * (reply) and sense buffers. */ - ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); + ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32)); ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); } else { /* Force 32-bit addressing */ @@ -2591,14 +2600,14 @@ while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); } else { mdelay(1); } if (!cntdn) { printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n", - ioc->name, (count+5)/HZ); + ioc->name, (int)((count+5)/HZ)); return -9; } @@ -2644,7 +2653,7 @@ /* port_enable.MsgFlags = 0; */ /* port_enable.MsgContext = 0; */ - dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", + dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", ioc->name, portnum, &port_enable)); /* RAID FW may take a long time to enable @@ -2668,20 +2677,22 @@ } /* - * Inputs: size - total FW bytes - * Outputs: frags - number of fragments needed - * Return NULL if failed. + * ioc: Pointer to MPT_ADAPTER structure + * size - total FW bytes */ void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) { - /* cached_fw - */ - - if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) - ioc->alloc_total += size; + if (ioc->cached_fw) + return; /* use already allocated memory */ + if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { + ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ + ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; + } else { + if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) + ioc->alloc_total += size; + } } - /* * If alt_img is NULL, delete from ioc structure. * Else, delete a secondary image in same format. @@ -2692,6 +2703,8 @@ int sz; sz = ioc->facts.FWImageSize; + dinitprintk((KERN_WARNING MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); ioc->cached_fw = NULL; @@ -2725,30 +2738,24 @@ int sgeoffset; u32 flagsLength; int ii, sz, reply_sz; - int cmdStatus, freeMem = 0; + int cmdStatus; - /* If the image size is 0 or if the pointer is - * not NULL (error), we are done. + /* If the image size is 0, we are done. */ - if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw) + if ((sz = ioc->facts.FWImageSize) == 0) return 0; - if ( sz & 0x01 ) - sz += 1; - if ( sz & 0x02 ) - sz += 2; - mpt_alloc_fw_memory(ioc, sz); + dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + if (ioc->cached_fw == NULL) { /* Major Failure. */ return -ENOMEM; } - dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", - ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); - prequest = (FWUpload_t *)&request; preply = (FWUploadReply_t *)&reply; @@ -2797,23 +2804,11 @@ dinitprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n", ioc->name, cmdStatus)); - /* Check to see if we have a copy of this image in - * host memory already. - */ - if (cmdStatus == 0) { - ioc->upload_fw = 0; - if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) - freeMem = 1; - } - - /* We already have a copy of this image or - * we had some type of an error - either the handshake - * failed (i != 0) or the command did not complete successfully. - */ - if (cmdStatus || freeMem) { + + if (cmdStatus) { - ddlprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n", - ioc->name, cmdStatus ? "incomplete" : "duplicate")); + ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n", + ioc->name)); mpt_free_fw_memory(ioc); } @@ -2841,28 +2836,26 @@ MpiExtImageHeader_t *pExtImage; u32 fwSize; u32 diag0val; -#ifdef MPT_DEBUG - u32 diag1val = 0; -#endif - int count = 0; + int count; u32 *ptrFw; u32 diagRwData; u32 nextImage; u32 load_addr; - u32 ioc_state; + u32 ioc_state=0; ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x, ioc FW Ptr %p\n", ioc->name, ioc->facts.FWImageSize, ioc->cached_fw)); - /* Get dma_addr and data transfer size. - */ if ( ioc->facts.FWImageSize == 0 ) return -1; - /* Get the DMA from ioc or ioc->alt_ioc */ if (ioc->cached_fw == NULL) return -2; + /* prevent a second downloadboot and memory free with alt_ioc */ + if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) + ioc->alt_ioc->cached_fw = NULL; + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); @@ -2870,18 +2863,17 @@ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - diag0val |= (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); - /* wait 100 msec */ + /* wait 1 msec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); + schedule_timeout(1 * HZ / 1000); } else { - mdelay (100); + mdelay (1); } + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); for (count = 0; count < 30; count ++) { @@ -2894,7 +2886,7 @@ /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -2914,8 +2906,7 @@ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); /* Set the DiagRwEn and Disable ARM bits */ - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, (diag0val | MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); pFwHeader = (MpiFwHeader_t *) ioc->cached_fw; fwSize = (pFwHeader->ImageSize + 3)/4; @@ -2961,15 +2952,6 @@ ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); - /* clear the PREVENT_IOC_BOOT bit */ - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT\n", - ioc->name, diag0val)); - diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", - ioc->name, diag0val)); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - /* Clear the internal flash bad bit - autoincrementing register, * so must do two writes. */ @@ -2980,28 +2962,13 @@ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off DISABLE_ARM, RW_ENABLE, RESET_HISTORY\n", + ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT, DISABLE_ARM\n", ioc->name, diag0val)); - diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_RESET_HISTORY); + diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", ioc->name, diag0val)); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - /* wait 100 msec */ - if (sleepFlag == CAN_SLEEP) { - ddlprintk((MYIOC_s_INFO_FMT "CAN_SLEEP 100 msec before reset the sequencer\n", ioc->name)); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); - } else { - ddlprintk((MYIOC_s_INFO_FMT "mdelay 100 msec before reset the sequencer\n", ioc->name)); - mdelay (100); - } - - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - if ( diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM) ) { - ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed, diag0val=%x FLASH_BAD_SIG | DISABLE_ARM on\n ", - ioc->name, diag0val)); - } /* Write 0xFF to reset the sequencer */ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); @@ -3009,26 +2976,18 @@ if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) { ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n", ioc->name, count, ioc_state)); -/* if ((r = GetIocFacts(ioc, sleepFlag, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) { - if ((r = GetIocFacts(ioc, sleepFlag, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) { - ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed\n", - ioc->name)); - return -EFAULT; - } - } */ - /* wait 2 sec */ -/* if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(5000 * HZ / 1000); - } else { - mdelay (5000); - } */ - + if ((SendIocInit(ioc, sleepFlag)) != 0) { + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n", + ioc->name)); + return -EFAULT; + } + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n", + ioc->name)); return 0; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(10 * HZ / 1000); } else { mdelay (10); } @@ -3068,8 +3027,8 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) { int hard_reset_done = 0; - u32 ioc_state; - int cntdn, cnt = 0; + u32 ioc_state=0; + int cnt,cntdn; dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); if ((int)ioc->chip_type > (int)FC929) { @@ -3080,7 +3039,7 @@ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -3090,26 +3049,27 @@ if (hard_reset_done < 0) return hard_reset_done; - dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", + dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", ioc->name)); - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 20; /* 20 seconds */ + cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ for (cnt=0; cntname, cnt)); + ioc_state = mpt_GetIocState(ioc, 1); + if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) { + dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n", + ioc->name, cnt)); return hard_reset_done; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(10 * HZ / 1000); } else { mdelay (10); } } - printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n", - ioc->name); + printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", + ioc->name, ioc_state); return -1; } @@ -3199,12 +3159,6 @@ dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); #endif - /* Write the PreventIocBoot bit */ - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { - diag0val |= MPI_DIAG_PREVENT_IOC_BOOT; - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - } - /* * Disable the ARM (Bug fix) * @@ -3246,20 +3200,13 @@ /* FIXME? Examine results here? */ } - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { + if (ioc->cached_fw) { /* If the DownloadBoot operation fails, the * IOC will be left unusable. This is a fatal error * case. _diag_reset will return < 0 */ for (count = 0; count < 30; count ++) { diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT - "DbG2b: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { break; } @@ -3267,7 +3214,7 @@ /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -3295,7 +3242,7 @@ /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -3419,13 +3366,13 @@ count *= 10; printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n", - ioc->name, (count+5)/HZ); + ioc->name, (int)((count+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); } else { mdelay (1); /* 1 msec delay */ } @@ -3443,35 +3390,45 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * PrimeIocFifos - Initialize IOC request and reply FIFOs. - * @ioc: Pointer to MPT_ADAPTER structure - * - * This routine allocates memory for the MPT reply and request frame - * pools (if necessary), and primes the IOC reply FIFO with - * reply frames. - * - * Returns 0 for success, non-zero for failure. + * initChainBuffers - Allocate memory for and initialize + * chain buffers, chain buffer control arrays and spinlock. + * @hd: Pointer to MPT_SCSI_HOST structure + * @init: If set, initialize the spin lock. */ static int -PrimeIocFifos(MPT_ADAPTER *ioc) +initChainBuffers(MPT_ADAPTER *ioc) { - MPT_FRAME_HDR *mf; - unsigned long b; - unsigned long flags; - dma_addr_t aligned_mem_dma; - u8 *aligned_mem; - int i, sz; - int chain_buffer_sz, reply_buffer_sz, request_buffer_sz; - int scale, num_sge, num_chain; - - /* request buffer size, rounding UP to nearest 4-kB boundary */ - request_buffer_sz = (ioc->req_sz * ioc->req_depth) + 128; - request_buffer_sz = ((request_buffer_sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + u8 *mem; + int sz, ii, num_chain; + int scale, num_sge, numSGE; + + /* ReqToChain size must equal the req_depth + * index = req_idx + */ + if (ioc->ReqToChain == NULL) { + sz = ioc->req_depth * sizeof(int); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; + + ioc->ReqToChain = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; - /* reply buffer size */ - reply_buffer_sz = (ioc->reply_sz * ioc->reply_depth) + 128; + ioc->RequestNB = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + } + for (ii = 0; ii < ioc->req_depth; ii++) { + ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN; + } - /* chain buffer size, copied from from mptscsih_initChainBuffers() + /* ChainToChain size must equal the total number + * of chain buffers to be allocated. + * index = chain_idx * * Calculate the number of chain buffers needed(plus 1) per I/O * then multiply the the maximum number of simultaneous cmds @@ -3479,79 +3436,134 @@ * num_sge = num sge in request frame + last chain buffer * scale = num sge per chain buffer if no chain element */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); if (sizeof(dma_addr_t) == sizeof(u64)) num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); else - num_sge = 1 + scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + + if (sizeof(dma_addr_t) == sizeof(u64)) { + numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + } else { + numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + } + dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n", + ioc->name, num_sge, numSGE)); + + if ( numSGE > MPT_SCSI_SG_DEPTH ) + numSGE = MPT_SCSI_SG_DEPTH; num_chain = 1; - while (MPT_SCSI_SG_DEPTH - num_sge > 0) { + while (numSGE - num_sge > 0) { num_chain++; num_sge += (scale - 1); } num_chain++; - if ((int)ioc->chip_type > (int) FC929) + dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n", + ioc->name, numSGE, num_sge, num_chain)); + + if ((int) ioc->chip_type > (int) FC929) num_chain *= MPT_SCSI_CAN_QUEUE; else num_chain *= MPT_FC_CAN_QUEUE; - chain_buffer_sz = num_chain * ioc->req_sz; + ioc->num_chain = num_chain; - if(ioc->fifo_pool == NULL) { + sz = num_chain * sizeof(int); + if (ioc->ChainToChain == NULL) { + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; - ioc->fifo_pool_sz = request_buffer_sz + - reply_buffer_sz + chain_buffer_sz; + ioc->ChainToChain = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + } else { + mem = (u8 *) ioc->ChainToChain; + } + memset(mem, 0xFF, sz); + return num_chain; +} - ioc->fifo_pool = pci_alloc_consistent(ioc->pcidev, - ioc->fifo_pool_sz, &ioc->fifo_pool_dma); +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * PrimeIocFifos - Initialize IOC request and reply FIFOs. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine allocates memory for the MPT reply and request frame + * pools (if necessary), and primes the IOC reply FIFO with + * reply frames. + * + * Returns 0 for success, non-zero for failure. + */ +static int +PrimeIocFifos(MPT_ADAPTER *ioc) +{ + MPT_FRAME_HDR *mf; + unsigned long flags; + dma_addr_t alloc_dma; + u8 *mem; + int i, reply_sz, sz, total_size, num_chain; - if( ioc->fifo_pool == NULL) + /* Prime reply FIFO... */ + + if (ioc->reply_frames == NULL) { + if ( (num_chain = initChainBuffers(ioc)) < 0) + return -1; + + total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", + ioc->name, ioc->reply_sz, ioc->reply_depth)); + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n", + ioc->name, reply_sz, reply_sz)); + + sz = (ioc->req_sz * ioc->req_depth); + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n", + ioc->name, ioc->req_sz, ioc->req_depth)); + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n", + ioc->name, sz, sz)); + total_size += sz; + + sz = num_chain * ioc->req_sz; /* chain buffer pool size */ + dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n", + ioc->name, ioc->req_sz, num_chain)); + dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n", + ioc->name, sz, sz, num_chain)); + + total_size += sz; + mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma); + if (mem == NULL) { + printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n", + ioc->name); goto out_fail; + } - ioc->alloc_total += ioc->fifo_pool_sz; - memset(ioc->fifo_pool, 0, ioc->fifo_pool_sz); + dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); - /* reply fifo pointers */ - ioc->reply_alloc = ioc->fifo_pool; - ioc->reply_alloc_dma = ioc->fifo_pool_dma; - /* request fifo pointers */ - ioc->req_alloc = ioc->reply_alloc+reply_buffer_sz; - ioc->req_alloc_dma = ioc->reply_alloc_dma+reply_buffer_sz; - /* chain buffer pointers */ - ioc->chain_alloc = ioc->req_alloc+request_buffer_sz; - ioc->chain_alloc_dma = ioc->req_alloc_dma+request_buffer_sz; - ioc->chain_alloc_sz = chain_buffer_sz; - - /* Prime reply FIFO... */ - dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%p], sz=%d bytes\n", - ioc->name, ioc->reply_alloc, - (void *)(ulong)ioc->reply_alloc_dma, reply_buffer_sz)); - - b = (unsigned long) ioc->reply_alloc; - b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ - aligned_mem = (u8 *) b; - ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem; - ioc->reply_frames_dma = - (ioc->reply_alloc_dma + (aligned_mem - ioc->reply_alloc)); + memset(mem, 0, total_size); + ioc->alloc_total += total_size; + ioc->alloc = mem; + ioc->alloc_dma = alloc_dma; + ioc->alloc_sz = total_size; + ioc->reply_frames = (MPT_FRAME_HDR *) mem; + ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); + + alloc_dma += reply_sz; + mem += reply_sz; - ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF); - /* Request FIFO - WE manage this! */ - dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%p], sz=%d bytes\n", - ioc->name, ioc->req_alloc, - (void *)(ulong)ioc->req_alloc_dma, request_buffer_sz)); - - b = (unsigned long) ioc->req_alloc; - b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ - aligned_mem = (u8 *) b; - ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem; - ioc->req_frames_dma = - (ioc->req_alloc_dma + (aligned_mem - ioc->req_alloc)); - ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF); + ioc->req_frames = (MPT_FRAME_HDR *) mem; + ioc->req_frames_dma = alloc_dma; + + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffers @ %p[%p]\n", + ioc->name, mem, (void *)(ulong)alloc_dma)); + + ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); #if defined(CONFIG_MTRR) && 0 /* @@ -3559,79 +3571,93 @@ * (at least as much as we can; "size and base must be * multiples of 4 kiB" */ - ioc->mtrr_reg = mtrr_add(ioc->fifo_pool, - ioc->fifo_pool_sz, + ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma, + sz, MTRR_TYPE_WRCOMB, 1); dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n", - ioc->name, ioc->fifo_pool, ioc->fifo_pool_sz)); + ioc->name, ioc->req_frames_dma, sz)); #endif - } /* ioc->fifo_pool == NULL */ - - /* Post Reply frames to FIFO - */ - aligned_mem_dma = ioc->reply_frames_dma; - dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n", - ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma)); + for (i = 0; i < ioc->req_depth; i++) { + alloc_dma += ioc->req_sz; + mem += ioc->req_sz; + } - for (i = 0; i < ioc->reply_depth; i++) { - /* Write each address to the IOC! */ - CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma); - aligned_mem_dma += ioc->reply_sz; - } + ioc->ChainBuffer = mem; + ioc->ChainBufferDMA = alloc_dma; + dinitprintk((KERN_INFO MYNAM " :%s.ChainBuffers @ %p(%p)\n", + ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); - /* Initialize Request frames linked list - */ - aligned_mem_dma = ioc->req_frames_dma; - aligned_mem = (u8 *) ioc->req_frames; - dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%p]\n", - ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma)); + /* Initialize the free chain Q. + */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); - for (i = 0; i < ioc->req_depth; i++) { - mf = (MPT_FRAME_HDR *) aligned_mem; - - /* Queue REQUESTs *internally*! */ - Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); - aligned_mem += ioc->req_sz; - } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); + Q_INIT(&ioc->FreeChainQ, MPT_FRAME_HDR); + /* Post the chain buffers to the FreeChainQ. + */ + mem = (u8 *)ioc->ChainBuffer; + for (i=0; i < num_chain; i++) { + mf = (MPT_FRAME_HDR *) mem; + Q_ADD_TAIL(&ioc->FreeChainQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); + mem += ioc->req_sz; + } + + /* Initialize Request frames linked list + */ + alloc_dma = ioc->req_frames_dma; + mem = (u8 *) ioc->req_frames; + + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); + for (i = 0; i < ioc->req_depth; i++) { + mf = (MPT_FRAME_HDR *) mem; + + /* Queue REQUESTs *internally*! */ + Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); + mem += ioc->req_sz; + } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); - if (ioc->sense_buf_pool == NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); ioc->sense_buf_pool = - pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); - if (ioc->sense_buf_pool == NULL) + pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); + if (ioc->sense_buf_pool == NULL) { + printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n", + ioc->name); goto out_fail; + } ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); ioc->alloc_total += sz; + dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n", + ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); + + } + + /* Post Reply frames to FIFO + */ + alloc_dma = ioc->alloc_dma; + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n", + ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); + + for (i = 0; i < ioc->reply_depth; i++) { + /* Write each address to the IOC! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma); + alloc_dma += ioc->reply_sz; } return 0; out_fail: - if (ioc->fifo_pool != NULL) { + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; pci_free_consistent(ioc->pcidev, - ioc->fifo_pool_sz, - ioc->fifo_pool, ioc->fifo_pool_dma); + sz, + ioc->alloc, ioc->alloc_dma); ioc->reply_frames = NULL; - ioc->reply_alloc = NULL; ioc->req_frames = NULL; - ioc->req_alloc = NULL; - ioc->chain_alloc = NULL; - ioc->fifo_pool = NULL; - ioc->alloc_total -= ioc->fifo_pool_sz; -#if defined(CONFIG_MTRR) && 0 - if (ioc->mtrr_reg > 0) { - mtrr_del(ioc->mtrr_reg, 0, 0); - dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n", - ioc->name)); - } -#endif + ioc->alloc_total -= sz; } if (ioc->sense_buf_pool != NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); @@ -3693,8 +3719,8 @@ if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; - dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n", - ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", + ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); /* Read doorbell and check for active bit */ if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) @@ -3728,7 +3754,7 @@ failcnt++; } - dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); + dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); DBG_DUMP_REQUEST_FRAME_HDR(req) dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n", @@ -3783,7 +3809,7 @@ if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) break; set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); count++; } } else { @@ -3833,7 +3859,7 @@ if (intstat & MPI_HIS_DOORBELL_INTERRUPT) break; set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); count++; } } else { @@ -3935,7 +3961,7 @@ } #endif - dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); + dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); DBG_DUMP_REPLY_FRAME(mptReply) dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", @@ -4282,9 +4308,11 @@ pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); - if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; - + dinitprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n", + ioc->name, pPP0->Capabilities)); + } ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; if (data) { @@ -4907,8 +4935,8 @@ mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) { ToolboxIstwiReadWriteRequest_t *pReq; - struct pci_dev *pdev; MPT_FRAME_HDR *mf; + struct pci_dev *pdev; unsigned long flags; int rc; u32 flagsLength; @@ -5226,12 +5254,6 @@ if (drvname) len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname); - /* - * Handle isense special case, because it - * doesn't do a formal mpt_register call. - */ - if (isense_idx == ii) - len += sprintf(buf+len, " Fusion MPT isense driver\n"); } } @@ -5286,7 +5308,7 @@ len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", - (void *)ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma); + (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); /* * Rounding UP to nearest 4-kB boundary here... */ @@ -5298,8 +5320,8 @@ 4*ioc->facts.RequestFrameSize, ioc->facts.GlobalCredits); - len += sprintf(buf+len, " ReplyFrames @ 0x%p (Dma @ 0x%p)\n", - (void *)ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma); + len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n", + (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); sz = (ioc->reply_sz * ioc->reply_depth) + 128; len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); @@ -5592,7 +5614,7 @@ } evStr = EventDescriptionStr(event, evData0); - dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n", + devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n", ioc->name, evStr, event)); @@ -5664,7 +5686,7 @@ */ for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { if (MptEvHandlers[ii]) { - dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", + devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", ioc->name, ii)); r += (*(MptEvHandlers[ii]))(ioc, pEventReply); handlers++; @@ -5677,8 +5699,8 @@ */ if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { if ((ii = SendEventAck(ioc, pEventReply)) != 0) { - printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n", - ioc->name, ii); + devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n", + ioc->name, ii)); } } @@ -5702,9 +5724,8 @@ "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" }; u8 subcl = (log_info >> 24) & 0x7; -// u32 SubCl = log_info & 0x27000000; - printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}", + printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n", ioc->name, log_info, subcl_str[subcl]); } @@ -5907,50 +5928,6 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI - * OpCode strings from the (optional) isense module. - * @ascqTable: Pointer to ASCQ_Table_t structure - * @ascqtbl_sz: Number of entries in ASCQ_Table - * @opsTable: Pointer to array of SCSI OpCode strings (char pointers) - * - * Specialized driver registration routine for the isense driver. - */ -int -mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable) -{ - int r = 0; - - if (ascqTable && ascqtbl_sz && opsTable) { - mpt_v_ASCQ_TablePtr = ascqTable; - mpt_ASCQ_TableSz = ascqtbl_sz; - mpt_ScsiOpcodesPtr = opsTable; - printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n"); - isense_idx = last_drv_idx; - r = 1; - } - return r; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI - * OpCode strings from the isense driver. - * - * Specialized driver deregistration routine for the isense driver. - */ -void -mpt_deregister_ascqops_strings(void) -{ - mpt_v_ASCQ_TablePtr = NULL; - mpt_ASCQ_TableSz = 0; - mpt_ScsiOpcodesPtr = NULL; - printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); - isense_idx = -1; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - EXPORT_SYMBOL(ioc_list); EXPORT_SYMBOL(mpt_proc_root_dir); EXPORT_SYMBOL(DmpService); @@ -5981,13 +5958,6 @@ EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); - -EXPORT_SYMBOL(mpt_register_ascqops_strings); -EXPORT_SYMBOL(mpt_deregister_ascqops_strings); -EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr); -EXPORT_SYMBOL(mpt_ASCQ_TableSz); -EXPORT_SYMBOL(mpt_ScsiOpcodesPtr); - static struct pci_driver mptbase_driver = { .name = "mptbase", diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h --- a/drivers/message/fusion/mptbase.h 2004-10-18 14:56:15 -07:00 +++ b/drivers/message/fusion/mptbase.h 2004-10-18 14:56:15 -07:00 @@ -60,8 +60,6 @@ #include #include -#include "scsi3.h" /* SCSI defines */ - #include "lsi/mpi_type.h" #include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */ #include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */ @@ -85,8 +83,8 @@ #define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.01.09" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.09" +#define MPT_LINUX_VERSION_COMMON "3.01.16" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.16" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -320,17 +318,6 @@ struct _Q_ITEM *tail; } Q_TRACKER; -typedef struct _MPT_DONE_Q { - struct _MPT_DONE_Q *forw; - struct _MPT_DONE_Q *back; - void *argp; -} MPT_DONE_Q; - -typedef struct _DONE_Q_TRACKER { - MPT_DONE_Q *head; - MPT_DONE_Q *tail; -} DONE_Q_TRACKER; - /* * Chip-specific stuff... FC929 delineates break between * FC and Parallel SCSI parts. Do NOT re-order. @@ -403,6 +390,11 @@ void *tail; } ScsiCmndTracker; +/* VirtDevice negoFlags field */ +#define MPT_TARGET_NO_NEGO_WIDE 0x01 +#define MPT_TARGET_NO_NEGO_SYNC 0x02 +#define MPT_TARGET_NO_NEGO_QAS 0x04 +#define MPT_TAPE_NEGO_IDP 0x08 /* * VirtDevice - FC LUN device or SCSI target device @@ -420,8 +412,8 @@ u8 bus_id; u8 minSyncFactor; /* 0xFF is async */ u8 maxOffset; /* 0 if async */ - u8 maxWidth; /* 0 if narrow, 1 if wide*/ - u8 negoFlags; /* bit field, 0 if WDTR/SDTR/QAS allowed */ + u8 maxWidth; /* 0 if narrow, 1 if wide */ + u8 negoFlags; /* bit field, see above */ u8 raidVolume; /* set, if RAID Volume */ u8 type; /* byte 0 of Inquiry data */ u8 cflags; /* controller flags */ @@ -460,10 +452,6 @@ #define MPT_TARGET_FLAGS_VALID_56 0x10 #define MPT_TARGET_FLAGS_SAF_TE_ISSUED 0x20 -#define MPT_TARGET_NO_NEGO_WIDE 0x01 -#define MPT_TARGET_NO_NEGO_SYNC 0x02 -#define MPT_TARGET_NO_NEGO_QAS 0x04 - typedef struct _VirtDevTracker { struct _VirtDevice *head; struct _VirtDevice *tail; @@ -523,6 +511,7 @@ u8 target; /* target for reset */ void *tmPtr; struct timer_list TMtimer; /* timer function for this adapter */ + struct semaphore sem_ioc; } MPT_IOCTL; /* @@ -592,33 +581,38 @@ int pci_irq; /* This irq */ char name[MPT_NAME_LENGTH]; /* "iocN" */ char *prod_name; /* "LSIFC9x9" */ - volatile SYSIF_REGS *chip; /* == c8817000 (mmap) */ - volatile SYSIF_REGS *pio_chip; /* Programmed IO (downloadboot) */ + SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */ + SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */ u32 mem_phys; /* == f4020000 (mmap) */ u32 pio_mem_phys; /* Programmed IO (downloadboot) */ int mem_size; /* mmap memory size */ int alloc_total; u32 last_state; int active; - u8 *fifo_pool; /* dma pool for fifo's */ - dma_addr_t fifo_pool_dma; - int fifo_pool_sz; /* allocated size */ - u8 *chain_alloc; /* chain buffer alloc ptr */ - dma_addr_t chain_alloc_dma; - int chain_alloc_sz; - u8 *reply_alloc; /* Reply frames alloc ptr */ - dma_addr_t reply_alloc_dma; + u8 *alloc; /* frames alloc ptr */ + dma_addr_t alloc_dma; + u32 alloc_sz; MPT_FRAME_HDR *reply_frames; /* Reply msg frames - rounded up! */ - dma_addr_t reply_frames_dma; u32 reply_frames_low_dma; int reply_depth; /* Num Allocated reply frames */ int reply_sz; /* Reply frame size */ + int num_chain; /* Number of chain buffers */ + /* Pool of buffers for chaining. ReqToChain + * and ChainToChain track index of chain buffers. + * ChainBuffer (DMA) virt/phys addresses. + * FreeChainQ (lock) locking mechanisms. + */ + int *ReqToChain; + int *RequestNB; + int *ChainToChain; + u8 *ChainBuffer; + dma_addr_t ChainBufferDMA; + MPT_Q_TRACKER FreeChainQ; + spinlock_t FreeChainQlock; CHIP_TYPE chip_type; /* We (host driver) get to manage our own RequestQueue! */ - u8 *req_alloc; /* Request frames alloc ptr */ - dma_addr_t req_alloc_dma; - MPT_FRAME_HDR *req_frames; /* Request msg frames - rounded up! */ dma_addr_t req_frames_dma; + MPT_FRAME_HDR *req_frames; /* Request msg frames - rounded up! */ u32 req_frames_low_dma; int req_depth; /* Number of request frames */ int req_sz; /* Request frame size (bytes) */ @@ -661,6 +655,7 @@ #else u32 mfcnt; #endif + u32 NB_for_64_byte_frame; u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)]; u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)]; IOCFactsReply_t facts; @@ -674,8 +669,10 @@ u8 FirstWhoInit; u8 upload_fw; /* If set, do a fw upload */ u8 reload_fw; /* Force a FW Reload on next reset */ - u8 pad1[5]; + u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ + u8 pad1[4]; struct list_head list; + struct net_device *netdev; } MPT_ADAPTER; @@ -757,10 +754,10 @@ #define dexitprintk(x) #endif -#ifdef MPT_DEBUG_RESET -#define drsprintk(x) printk x +#if defined MPT_DEBUG_FAIL || defined (MPT_DEBUG_SG) +#define dfailprintk(x) printk x #else -#define drsprintk(x) +#define dfailprintk(x) #endif #ifdef MPT_DEBUG_HANDSHAKE @@ -769,11 +766,34 @@ #define dhsprintk(x) #endif +#ifdef MPT_DEBUG_EVENTS +#define devtprintk(x) printk x +#else +#define devtprintk(x) +#endif + +#ifdef MPT_DEBUG_RESET +#define drsprintk(x) printk x +#else +#define drsprintk(x) +#endif + //#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) #if defined(MPT_DEBUG_MSG_FRAME) #define dmfprintk(x) printk x +#define DBG_DUMP_REQUEST_FRAME(mfp) \ + { int i, n = 24; \ + u32 *m = (u32 *)(mfp); \ + for (i=0; i> 16; \ + printk("TM_REPLY MessageLength=%d:\n", n); \ + for (i=0; iid])) + if (down_trylock(&ioc->ioctl->sem_ioc)) rc = -EAGAIN; } else { - if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) + if (down_interruptible(&ioc->ioctl->sem_ioc)) rc = -ERESTARTSYS; } dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc)); @@ -445,7 +447,7 @@ mptctl_free_tm_flags(ioctl->ioc); del_timer(&ioctl->TMtimer); - mpt_free_msg_frame(mptctl_id, ioctl->ioc, mf); + mpt_free_msg_frame(ioctl->ioc, mf); ioctl->tmPtr = NULL; } @@ -482,7 +484,7 @@ spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmState = TM_STATE_ERROR; + hd->tmState = TM_STATE_NONE; hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); @@ -520,7 +522,7 @@ if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TMTIMER_ACTIVE)){ ioctl->status &= ~MPT_IOCTL_STATUS_TMTIMER_ACTIVE; del_timer(&ioctl->TMtimer); - mpt_free_msg_frame(mptctl_id, ioc, ioctl->tmPtr); + mpt_free_msg_frame(ioc, ioctl->tmPtr); } } else { @@ -630,8 +632,7 @@ else ret = -EINVAL; - - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } @@ -1807,7 +1808,6 @@ struct buflist bufOut; /* data Out buffer */ dma_addr_t dma_addr_in; dma_addr_t dma_addr_out; - int dir; /* PCI data direction */ int sgSize = 0; /* Num SG elements */ int iocnum, flagsLength; int sz, rc = 0; @@ -2117,9 +2117,9 @@ /* Set up the dataOut memory allocation */ if (karg.dataOutSize > 0) { - dir = PCI_DMA_TODEVICE; if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size() ) << MPI_SGE_FLAGS_SHIFT; @@ -2158,7 +2158,6 @@ } if (karg.dataInSize > 0) { - dir = PCI_DMA_FROMDEVICE; flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; flagsLength |= karg.dataInSize; @@ -2196,6 +2195,7 @@ add_timer(&ioc->ioctl->timer); if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { + DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf); rc = mpt_send_handshake_request(mptctl_id, ioc, sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); if (rc == 0) { @@ -2206,7 +2206,7 @@ del_timer(&ioc->ioctl->timer); ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE; ioc->ioctl->status |= MPT_IOCTL_STATUS_TM_FAILED; - mpt_free_msg_frame(mptctl_id, ioc, mf); + mpt_free_msg_frame(ioc, mf); } } else { mpt_put_msg_frame(mptctl_id, ioc, mf); @@ -2324,7 +2324,7 @@ * otherwise, failure occured after mf acquired. */ if (mf) - mpt_free_msg_frame(mptctl_id, ioc, mf); + mpt_free_msg_frame(ioc, mf); return rc; } @@ -2738,7 +2738,7 @@ ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } @@ -2792,55 +2792,91 @@ */ ret = mptctl_do_mpt_command (karg, &uarg->MF); - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } #endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -int __init mptctl_init(void) +/* + * mptctl_probe - Installs ioctl devices per bus. + * @pdev: Pointer to pci_dev structure + * + * Returns 0 for success, non-zero for failure. + * + */ + +static int +mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err; - int i; - int where = 1; int sz; u8 *mem; - MPT_ADAPTER *ioc = NULL; - int iocnum; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - show_mptmod_ver(my_NAME, my_VERSION); + /* + * Allocate and inite a MPT_IOCTL structure + */ + sz = sizeof (MPT_IOCTL); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) { + err = -ENOMEM; + goto out_fail; + } - for (i=0; iioctl = (MPT_IOCTL *) mem; + ioc->ioctl->ioc = ioc; + init_timer (&ioc->ioctl->timer); + ioc->ioctl->timer.data = (unsigned long) ioc->ioctl; + ioc->ioctl->timer.function = mptctl_timer_expired; + init_timer (&ioc->ioctl->TMtimer); + ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl; + ioc->ioctl->TMtimer.function = mptctl_timer_expired; + sema_init(&ioc->ioctl->sem_ioc, 1); + return 0; - ioc = NULL; - if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) || - (ioc == NULL)) { - continue; - } - else { - /* This adapter instance is found. - * Allocate and inite a MPT_IOCTL structure - */ - sz = sizeof (MPT_IOCTL); - mem = kmalloc(sz, GFP_KERNEL); - if (mem == NULL) { - err = -ENOMEM; - goto out_fail; - } - - memset(mem, 0, sz); - ioc->ioctl = (MPT_IOCTL *) mem; - ioc->ioctl->ioc = ioc; - init_timer (&ioc->ioctl->timer); - ioc->ioctl->timer.data = (unsigned long) ioc->ioctl; - ioc->ioctl->timer.function = mptctl_timer_expired; - init_timer (&ioc->ioctl->TMtimer); - ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl; - ioc->ioctl->TMtimer.function = mptctl_timer_expired; - } +out_fail: + + mptctl_remove(pdev); + return err; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptctl_remove - Removed ioctl devices + * @pdev: Pointer to pci_dev structure + * + * + */ +static void +mptctl_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + kfree ( ioc->ioctl ); +} + +static struct mpt_pci_driver mptctl_driver = { + .probe = mptctl_probe, + .remove = mptctl_remove, +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int __init mptctl_init(void) +{ + int err; + int where = 1; + + show_mptmod_ver(my_NAME, my_VERSION); + + if(mpt_device_driver_register(&mptctl_driver, + MPTCTL_DRIVER) != 0 ) { + dprintk((KERN_INFO MYNAM + ": failed to register dd callbacks\n")); } #ifdef CONFIG_COMPAT @@ -2922,29 +2958,14 @@ unregister_ioctl32_conversion(HP_GETTARGETINFO); #endif - for (i=0; iioctl) { - kfree ( ioc->ioctl ); - ioc->ioctl = NULL; - } - } - } + mpt_device_driver_deregister(MPTCTL_DRIVER); + return err; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -void mptctl_exit(void) +static void mptctl_exit(void) { - int i; - MPT_ADAPTER *ioc; - int iocnum; - misc_deregister(&mptctl_miscdev); printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n", mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); @@ -2957,6 +2978,8 @@ mpt_deregister(mptctl_id); printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); + mpt_device_driver_deregister(MPTCTL_DRIVER); + #ifdef CONFIG_COMPAT unregister_ioctl32_conversion(MPTIOCINFO); unregister_ioctl32_conversion(MPTIOCINFO1); @@ -2973,20 +2996,6 @@ unregister_ioctl32_conversion(HP_GETTARGETINFO); #endif - /* Free allocated memory */ - for (i=0; iioctl) { - kfree ( ioc->ioctl ); - ioc->ioctl = NULL; - } - } - } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c --- a/drivers/message/fusion/mptlan.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/message/fusion/mptlan.c 2004-10-18 14:56:32 -07:00 @@ -177,11 +177,9 @@ static u32 max_buckets_out = 127; static u32 tx_max_out_p = 127 - 16; -static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1]; - #ifdef QLOGIC_NAA_WORKAROUND static struct NAA_Hosed *mpt_bad_naa = NULL; -rwlock_t bad_naa_lock; +rwlock_t bad_naa_lock = RW_LOCK_UNLOCKED; #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -203,7 +201,7 @@ static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) { - struct net_device *dev = mpt_landev[ioc->id]; + struct net_device *dev = ioc->netdev; int FreeReqFrame = 0; dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n", @@ -336,7 +334,7 @@ static int mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - struct net_device *dev = mpt_landev[ioc->id]; + struct net_device *dev = ioc->netdev; struct mpt_lan_priv *priv = netdev_priv(dev); dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", @@ -1334,7 +1332,7 @@ if (pSimple == NULL) { /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", /**/ __FUNCTION__); - mpt_free_msg_frame(LanCtx, mpt_dev, mf); + mpt_free_msg_frame(mpt_dev, mf); goto out; } @@ -1451,20 +1449,74 @@ return dev; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int __init mpt_lan_init (void) +static int +mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct net_device *dev; - MPT_ADAPTER *p; - int i, j; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct net_device *dev; + int i; + + for (i = 0; i < ioc->facts.NumberOfPorts; i++) { + printk(KERN_INFO MYNAM ": %s: PortNum=%x, " + "ProtocolFlags=%02Xh (%c%c%c%c)\n", + ioc->name, ioc->pfacts[i].PortNumber, + ioc->pfacts[i].ProtocolFlags, + MPT_PROTOCOL_FLAGS_c_c_c_c( + ioc->pfacts[i].ProtocolFlags)); + + if (!(ioc->pfacts[i].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_LAN)) { + printk(KERN_INFO MYNAM ": %s: Hmmm... LAN protocol " + "seems to be disabled on this adapter port!\n", + ioc->name); + continue; + } - show_mptmod_ver(LANAME, LANVER); + dev = mpt_register_lan_device(ioc, i); + if (!dev) { + printk(KERN_ERR MYNAM ": %s: Unable to register " + "port%d as a LAN device\n", ioc->name, + ioc->pfacts[i].PortNumber); + continue; + } + + printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " + "registered as '%s'\n", ioc->name, dev->name); + printk(KERN_INFO MYNAM ": %s/%s: " + "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + ioc->netdev = dev; -#ifdef QLOGIC_NAA_WORKAROUND - /* Init the global r/w lock for the bad_naa list. We want to do this - before any boards are initialized and may be used. */ - rwlock_init(&bad_naa_lock); -#endif + return 0; + } + + return -ENODEV; +} + +static void +mptlan_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct net_device *dev = ioc->netdev; + + if(dev != NULL) { + unregister_netdev(dev); + free_netdev(dev); + } +} + +static struct mpt_pci_driver mptlan_driver = { + .probe = mptlan_probe, + .remove = mptlan_remove, +}; + +static int __init mpt_lan_init (void) +{ + show_mptmod_ver(LANAME, LANVER); if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) { printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); @@ -1476,87 +1528,31 @@ dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); - if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) { - dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); - } else { + if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) { printk(KERN_ERR MYNAM ": Eieee! unable to register a reset " "handler with mptbase! The world is at an end! " "Everything is fading to black! Goodbye.\n"); return -EBUSY; } - for (j = 0; j < MPT_MAX_ADAPTERS; j++) { - mpt_landev[j] = NULL; - } - - list_for_each_entry(p, &ioc_list, list) { - for (i = 0; i < p->facts.NumberOfPorts; i++) { - printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n", - p->name, - p->pfacts[i].PortNumber, - p->pfacts[i].ProtocolFlags, - MPT_PROTOCOL_FLAGS_c_c_c_c(p->pfacts[i].ProtocolFlags)); - - if (!(p->pfacts[i].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { - printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n", - p->name); - continue; - } - - dev = mpt_register_lan_device (p, i); - if (!dev) { - printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n", - p->name, - p->pfacts[i].PortNumber); - } - printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n", - p->name, dev->name); - printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); -// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n", -// IOC_AND_NETDEV_NAMES_s_s(dev), -// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out); - j = p->id; - mpt_landev[j] = dev; - dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", - dev, j, mpt_landev[j])); - - } - } - + dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); + + if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER)) + dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n")); return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void __exit mpt_lan_exit(void) { - int i; - + mpt_device_driver_deregister(MPTLAN_DRIVER); mpt_reset_deregister(LanCtx); - for (i = 0; mpt_landev[i] != NULL; i++) { - struct net_device *dev = mpt_landev[i]; - - printk (KERN_INFO ": %s/%s: Fusion MPT LAN device unregistered\n", - IOC_AND_NETDEV_NAMES_s_s(dev)); - unregister_netdev(dev); - free_netdev(dev); - mpt_landev[i] = NULL; - } - if (LanCtx >= 0) { mpt_deregister(LanCtx); LanCtx = -1; mpt_lan_index = 0; } - - /* deregister any send/receive handler structs. I2Oism? */ } - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ module_init(mpt_lan_init); module_exit(mpt_lan_exit); diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/message/fusion/mptscsih.c 2004-10-18 14:57:19 -07:00 @@ -86,7 +86,6 @@ #include "mptbase.h" #include "mptscsih.h" -#include "isense.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #define my_NAME "Fusion MPT SCSI Host driver" @@ -100,6 +99,7 @@ /* Set string for command line args from insmod */ #ifdef MODULE char *mptscsih = NULL; +MODULE_PARM(mptscsih, "s"); #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -114,6 +114,7 @@ #define MPT_SCANDV_SOME_ERROR (0x00000004) #define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) #define MPT_SCANDV_ISSUE_SENSE (0x00000010) +#define MPT_SCANDV_FALLBACK (0x00000020) #define MPT_SCANDV_MAX_RETRIES (10) @@ -161,15 +162,12 @@ static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); -static int mptscsih_AddSGE(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt, +static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx); -static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx); -static int mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init); +static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); static void copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc); -static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx); -static void post_pendingQ_commands(MPT_SCSI_HOST *hd); static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); @@ -178,7 +176,7 @@ static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); static void mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen); -void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); +static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags); static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id); @@ -246,6 +244,7 @@ static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq); static int scandv_wait_done = 1; + /* Driver default setup */ static struct mptscsih_driver_setup @@ -323,44 +322,47 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mptscsih_getFreeChainBuffes - Function to get a free chain + * mptscsih_getFreeChainBuffer - Function to get a free chain * from the MPT_SCSI_HOST FreeChainQ. - * @hd: Pointer to the MPT_SCSI_HOST instance + * @ioc: Pointer to MPT_ADAPTER structure * @req_idx: Index of the SCSI IO request frame. (output) * * return SUCCESS or FAILED */ static inline int -mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) +mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) { MPT_FRAME_HDR *chainBuf; unsigned long flags; int rc; int chain_idx; - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if (!Q_IS_EMPTY(&hd->FreeChainQ)) { + dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n", + ioc->name)); + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (!Q_IS_EMPTY(&ioc->FreeChainQ)) { int offset; - chainBuf = hd->FreeChainQ.head; + chainBuf = ioc->FreeChainQ.head; Q_DEL_ITEM(&chainBuf->u.frame.linkage); - offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer; - chain_idx = offset / hd->ioc->req_sz; + offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; + chain_idx = offset / ioc->req_sz; rc = SUCCESS; + dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", + ioc->name, *retIndex, chainBuf)); } else { rc = FAILED; chain_idx = MPT_HOST_NO_CHAIN; + dfailprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n", + ioc->name)); } - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); *retIndex = chain_idx; - dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", - hd->ioc->name, *retIndex, chainBuf)); - return rc; } /* mptscsih_getFreeChainBuffer() */ @@ -368,14 +370,14 @@ /* * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the * SCSIIORequest_t Message Frame. - * @hd: Pointer to MPT_SCSI_HOST structure + * @ioc: Pointer to MPT_ADAPTER structure * @SCpnt: Pointer to scsi_cmnd structure * @pReq: Pointer to SCSIIORequest_t structure * * Returns ... */ static int -mptscsih_AddSGE(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt, +mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx) { char *psge; @@ -391,6 +393,7 @@ int newIndex; int ii; dma_addr_t v2; + u32 RequestNB; sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { @@ -400,25 +403,25 @@ } psge = (char *) &pReq->SGL; - frm_sz = hd->ioc->req_sz; + frm_sz = ioc->req_sz; /* Map the data portion, if any. * sges_left = 0 if no data transfer. */ if ( (sges_left = SCpnt->use_sg) ) { - sges_left = pci_map_sg(hd->ioc->pcidev, + sges_left = pci_map_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, SCpnt->sc_data_direction); if (sges_left == 0) return FAILED; } else if (SCpnt->request_bufflen) { - SCpnt->SCp.dma_handle = pci_map_single(hd->ioc->pcidev, + SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->sc_data_direction); dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", - hd->ioc->name, SCpnt, SCpnt->request_bufflen)); + ioc->name, SCpnt, SCpnt->request_bufflen)); mptscsih_add_sge((char *) &pReq->SGL, 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen, SCpnt->SCp.dma_handle); @@ -493,12 +496,16 @@ * Update the chain element * Offset and Length fields. */ - mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off); + mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); } else { /* The current buffer is the original MF * and there is no Chain buffer. */ pReq->ChainOffset = 0; + RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; + dsgprintk((MYIOC_s_ERR_FMT + "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); + ioc->RequestNB[req_idx] = RequestNB; } } else { /* At least one chain buffer is needed. @@ -513,7 +520,7 @@ */ dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", - hd->ioc->name, sg_done)); + ioc->name, sg_done)); /* Set LAST_ELEMENT flag for last non-chain element * in the buffer. Since psge points at the NEXT @@ -537,13 +544,16 @@ */ u8 nextChain = (u8) (sgeOffset >> 2); sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off); + mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); } else { /* The original MF buffer requires a chain buffer - * set the offset. * Last element in this MF is a chain element. */ pReq->ChainOffset = (u8) (sgeOffset >> 2); + RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; + dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); + ioc->RequestNB[req_idx] = RequestNB; } sges_left -= sg_done; @@ -552,19 +562,22 @@ /* NOTE: psge points to the beginning of the chain element * in current buffer. Get a chain buffer. */ - if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED) + dsgprintk((MYIOC_s_INFO_FMT + "calling getFreeChainBuffer SCSI cmd=%02x (%p)\n", + ioc->name, pReq->CDB[0], SCpnt)); + if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) return FAILED; /* Update the tracking arrays. * If chainSge == NULL, update ReqToChain, else ChainToChain */ if (chainSge) { - hd->ChainToChain[chain_idx] = newIndex; + ioc->ChainToChain[chain_idx] = newIndex; } else { - hd->ReqToChain[req_idx] = newIndex; + ioc->ReqToChain[req_idx] = newIndex; } chain_idx = newIndex; - chain_dma_off = hd->ioc->req_sz * chain_idx; + chain_dma_off = ioc->req_sz * chain_idx; /* Populate the chainSGE for the current buffer. * - Set chain buffer pointer to psge and fill @@ -576,7 +589,7 @@ /* Start the SGE for the next buffer */ - psge = (char *) (hd->ChainBuffer + chain_dma_off); + psge = (char *) (ioc->ChainBuffer + chain_dma_off); sgeOffset = 0; sg_done = 0; @@ -631,7 +644,7 @@ printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name); - mptscsih_freeChainBuffers(hd, req_idx); + mptscsih_freeChainBuffers(ioc, req_idx); return 1; } @@ -674,14 +687,15 @@ status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; scsi_state = pScsiReply->SCSIState; + scsi_status = pScsiReply->SCSIStatus; + xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); - dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", + dreplyprintk((KERN_NOTICE " Reply (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], mf, mr, sc)); - dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" - ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", - status, scsi_state, pScsiReply->SCSIStatus, - le32_to_cpu(pScsiReply->IOCLogInfo))); + dreplyprintk((KERN_NOTICE "IOCStatus=%04xh SCSIState=%02xh" + " SCSIStatus=%02xh xfer_cnt=%08xh\n", + status, scsi_state, scsi_status, xfer_cnt)); if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) copy_sense_data(sc, hd, mf, pScsiReply); @@ -701,7 +715,7 @@ * But not: DID_BUS_BUSY lest one risk * killing interrupt handler:-( */ - sc->result = STS_BUSY; + sc->result = SAM_STAT_BUSY; break; case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ @@ -731,13 +745,22 @@ break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ - sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | + sc->resid = sc->request_bufflen - xfer_cnt; + if ( xfer_cnt >= sc->underflow ) { + /* Sufficient data transfer occurred */ + sc->result = (DID_OK << 16) | scsi_status; + } else if ( xfer_cnt == 0 ) { + /* A CRC Error causes this condition; retry */ + sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); - sc->sense_buffer[0] = 0x70; - sc->sense_buffer[2] = NO_SENSE; - sc->sense_buffer[12] = 0; - sc->sense_buffer[13] = 0; - dprintk((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->target)); + sc->sense_buffer[0] = 0x70; + sc->sense_buffer[2] = NO_SENSE; + sc->sense_buffer[12] = 0; + sc->sense_buffer[13] = 0; + } else { + sc->result = DID_SOFT_ERROR << 16; + } + dreplyprintk((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->target)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ @@ -745,9 +768,7 @@ * Do upfront check for valid SenseData and give it * precedence! */ - scsi_status = pScsiReply->SCSIStatus; sc->result = (DID_OK << 16) | scsi_status; - xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* Have already saved the status and sense data */ @@ -769,12 +790,12 @@ /* Give report and update residual count. */ - dprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", + dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); - dprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); + dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); sc->resid = sc->request_bufflen - xfer_cnt; - dprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); + dreplyprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); /* Report Queue Full */ @@ -785,7 +806,8 @@ case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; + scsi_status = pScsiReply->SCSIStatus; + sc->result = (DID_OK << 16) | scsi_status; if (scsi_state == 0) { ; } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { @@ -851,7 +873,7 @@ } /* switch(status) */ - dprintk((KERN_NOTICE " sc->result set to %08xh\n", sc->result)); + dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result)); } /* end of address reply case */ /* Unmap the DMA buffers, if any. */ @@ -868,88 +890,10 @@ sc->scsi_done(sc); /* Issue the command callback */ /* Free Chain buffers */ - mptscsih_freeChainBuffers(hd, req_idx); + mptscsih_freeChainBuffers(ioc, req_idx); return 1; } -/* - * Flush all commands on the doneQ. - * Lock Q when deleting/adding members - * Lock io_request_lock for OS callback. - */ -static void -flush_doneQ(MPT_SCSI_HOST *hd) -{ - MPT_DONE_Q *buffer; - struct scsi_cmnd *SCpnt; - unsigned long flags; - - /* Flush the doneQ. - */ - dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n")); - while (1) { - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (Q_IS_EMPTY(&hd->doneQ)) { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - break; - } - - buffer = hd->doneQ.head; - /* Delete from Q - */ - Q_DEL_ITEM(buffer); - - /* Set the struct scsi_cmnd pointer - */ - SCpnt = (struct scsi_cmnd *) buffer->argp; - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - - /* Do the OS callback. - */ - SCpnt->scsi_done(SCpnt); - } - - return; -} - -/* - * Search the doneQ for a specific command. If found, delete from Q. - * Calling function will finish processing. - */ -static void -search_doneQ_for_cmd(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt) -{ - unsigned long flags; - MPT_DONE_Q *buffer; - - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->doneQ)) { - buffer = hd->doneQ.head; - do { - struct scsi_cmnd *sc = (struct scsi_cmnd *) buffer->argp; - if (SCpnt == sc) { - Q_DEL_ITEM(buffer); - SCpnt->result = sc->result; - - /* Set the struct scsi_cmnd pointer - */ - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - break; - } - } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->doneQ); - } - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - return; -} /* * mptscsih_flush_running_cmds - For each command found, search @@ -964,12 +908,11 @@ static void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { + MPT_ADAPTER *ioc = hd->ioc; struct scsi_cmnd *SCpnt; MPT_FRAME_HDR *mf; - MPT_DONE_Q *buffer; int ii; - int max = hd->ioc->req_depth; - unsigned long flags; + int max = ioc->req_depth; dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); for (ii= 0; ii < max; ii++) { @@ -978,16 +921,11 @@ /* Command found. */ - /* Search pendingQ, if found, - * delete from Q. - */ - mptscsih_search_pendingQ(hd, ii); - /* Null ScsiLookup index */ hd->ScsiLookup[ii] = NULL; - mf = MPT_INDEX_2_MFPTR(hd->ioc, ii); + mf = MPT_INDEX_2_MFPTR(ioc, ii); dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", mf, SCpnt)); @@ -997,12 +935,12 @@ */ if (scsi_device_online(SCpnt->device)) { if (SCpnt->use_sg) { - pci_unmap_sg(hd->ioc->pcidev, + pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, SCpnt->sc_data_direction); } else if (SCpnt->request_bufflen) { - pci_unmap_single(hd->ioc->pcidev, + pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle, SCpnt->request_bufflen, SCpnt->sc_data_direction); @@ -1012,37 +950,12 @@ SCpnt->host_scribble = NULL; /* Free Chain buffers */ - mptscsih_freeChainBuffers(hd, ii); + mptscsih_freeChainBuffers(ioc, ii); /* Free Message frames */ - mpt_free_msg_frame(ScsiDoneCtx, hd->ioc, mf); - -#if 1 - /* Post to doneQ, do not reply until POST phase - * of reset handler....prevents new commands from - * being queued. - */ - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->freeQ)) { - buffer = hd->freeQ.head; - Q_DEL_ITEM(buffer); - - /* Set the struct scsi_cmnd pointer - */ - buffer->argp = (void *)SCpnt; + mpt_free_msg_frame(ioc, mf); - /* Add to the doneQ - */ - Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - } else { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - SCpnt->scsi_done(SCpnt); - } -#else SCpnt->scsi_done(SCpnt); /* Issue the command callback */ -#endif - } } @@ -1087,8 +1000,8 @@ /* Cleanup */ hd->ScsiLookup[ii] = NULL; - mptscsih_freeChainBuffers(hd, ii); - mpt_free_msg_frame(ScsiDoneCtx, hd->ioc, (MPT_FRAME_HDR *)mf); + mptscsih_freeChainBuffers(hd->ioc, ii); + mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); } } @@ -1097,111 +1010,6 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mptscsih_initChainBuffers - Allocate memory for and initialize - * chain buffers, chain buffer control arrays and spinlock. - * @hd: Pointer to MPT_SCSI_HOST structure - * @init: If set, initialize the spin lock. - */ -static int -mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init) -{ - MPT_FRAME_HDR *chain; - u8 *mem; - unsigned long flags; - int sz, ii, num_chain; - int scale, num_sge; - - /* chain buffer allocation done from PrimeIocFifos */ - if (hd->ioc->fifo_pool == NULL) - return -1; - - hd->ChainBuffer = hd->ioc->chain_alloc; - hd->ChainBufferDMA = hd->ioc->chain_alloc_dma; - - dprintk((KERN_INFO " ChainBuffer @ %p(%p), sz=%d\n", - hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, hd->ioc->chain_alloc_sz)); - - /* ReqToChain size must equal the req_depth - * index = req_idx - */ - if (hd->ReqToChain == NULL) { - sz = hd->ioc->req_depth * sizeof(int); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) - return -1; - - hd->ReqToChain = (int *) mem; - } - for (ii = 0; ii < hd->ioc->req_depth; ii++) - hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN; - - /* ChainToChain size must equal the total number - * of chain buffers to be allocated. - * index = chain_idx - * - * Calculate the number of chain buffers needed(plus 1) per I/O - * then multiply the the maximum number of simultaneous cmds - * - * num_sge = num sge in request frame + last chain buffer - * scale = num sge per chain buffer if no chain element - */ - scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) - num_sge = scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); - else - num_sge = 1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); - - num_chain = 1; - while (hd->max_sge - num_sge > 0) { - num_chain++; - num_sge += (scale - 1); - } - num_chain++; - - if ((int) hd->ioc->chip_type > (int) FC929) - num_chain *= MPT_SCSI_CAN_QUEUE; - else - num_chain *= MPT_FC_CAN_QUEUE; - - hd->num_chain = num_chain; - - sz = num_chain * sizeof(int); - if (hd->ChainToChain == NULL) { - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) - return -1; - - hd->ChainToChain = (int *) mem; - } else { - mem = (u8 *) hd->ChainToChain; - } - memset(mem, 0xFF, sz); - - - /* Initialize the free chain Q. - */ - if (init) { - spin_lock_init(&hd->FreeChainQlock); - } - - spin_lock_irqsave (&hd->FreeChainQlock, flags); - Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR); - - /* Post the chain buffers to the FreeChainQ. - */ - mem = (u8 *)hd->ChainBuffer; - for (ii=0; ii < num_chain; ii++) { - chain = (MPT_FRAME_HDR *) mem; - Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR); - mem += hd->ioc->req_sz; - } - spin_unlock_irqrestore(&hd->FreeChainQlock, flags); - - return 0; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* * Hack! It might be nice to report if a device is returning QUEUE_FULL * but maybe not each and every time... */ @@ -1254,7 +1062,6 @@ struct Scsi_Host *sh; MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - MPT_DONE_Q *freedoneQ; unsigned long flags; int sz, ii; int numSGE = 0; @@ -1386,7 +1193,6 @@ hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = ioc; - hd->max_sge = sh->sg_tablesize; if ((int)ioc->chip_type > (int)FC929) hd->is_spi = 1; @@ -1399,7 +1205,7 @@ /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - sz = hd->ioc->req_depth * sizeof(void *); + sz = ioc->req_depth * sizeof(void *); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) { error = -ENOMEM; @@ -1412,37 +1218,6 @@ dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", ioc->name, hd->ScsiLookup, sz)); - if (mptscsih_initChainBuffers(hd, 1) < 0) { - error = -EINVAL; - goto mptscsih_probe_failed; - } - - /* Allocate memory for free and doneQ's - */ - sz = sh->can_queue * sizeof(MPT_DONE_Q); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } - - memset(mem, 0xFF, sz); - hd->memQ = mem; - - /* Initialize the free, done and pending Qs. - */ - Q_INIT(&hd->freeQ, MPT_DONE_Q); - Q_INIT(&hd->doneQ, MPT_DONE_Q); - Q_INIT(&hd->pendingQ, MPT_DONE_Q); - spin_lock_init(&hd->freedoneQlock); - - mem = hd->memQ; - for (ii=0; ii < sh->can_queue; ii++) { - freedoneQ = (MPT_DONE_Q *) mem; - Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); - mem += sizeof(MPT_DONE_Q); - } - /* Initialize this Scsi_Host * internal task Q. */ @@ -1474,8 +1249,7 @@ hd->resetPending = 0; hd->abortSCpnt = NULL; hd->tmPtr = NULL; - hd->numTMrequests = 0; - + /* Clear the pointer used to store * single-threaded commands, i.e., those * issued during a bus scan, dv and @@ -1500,10 +1274,10 @@ /* ioc->sh = sh; */ #ifdef MPTSCSIH_DBG_TIMEOUT - hd->ioc->timeout_hard = 0; - hd->ioc->timeout_delta = 30 * HZ; - hd->ioc->timeout_maxcnt = 0; - hd->ioc->timeout_cnt = 0; + ioc->timeout_hard = 0; + ioc->timeout_delta = 30 * HZ; + ioc->timeout_maxcnt = 0; + ioc->timeout_cnt = 0; for (ii=0; ii < 8; ii++) foo_to[ii] = NULL; #endif @@ -1511,47 +1285,41 @@ /* Update with the driver setup * values. */ - if (hd->ioc->spi_data.maxBusWidth > + if (ioc->spi_data.maxBusWidth > driver_setup.max_width) { - hd->ioc->spi_data.maxBusWidth = + ioc->spi_data.maxBusWidth = driver_setup.max_width; } - if (hd->ioc->spi_data.minSyncFactor < + if (ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac) { - hd->ioc->spi_data.minSyncFactor = + ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac; } - if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) { - hd->ioc->spi_data.maxSyncOffset = 0; + if (ioc->spi_data.minSyncFactor == MPT_ASYNC) { + ioc->spi_data.maxSyncOffset = 0; } - hd->ioc->spi_data.Saf_Te = driver_setup.saf_te; + ioc->spi_data.Saf_Te = driver_setup.saf_te; hd->negoNvram = 0; #ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION hd->negoNvram = MPT_SCSICFG_USE_NVRAM; #endif - if (driver_setup.dv == 0) { - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; - } - - hd->ioc->spi_data.forceDv = 0; + ioc->spi_data.forceDv = 0; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - hd->ioc->spi_data.dvStatus[ii] = + ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE; } - if (hd->negoNvram == 0) { - for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) - hd->ioc->spi_data.dvStatus[ii] |= - MPT_SCSICFG_DV_NOT_DONE; - } + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) + ioc->spi_data.dvStatus[ii] |= + MPT_SCSICFG_DV_NOT_DONE; ddvprintk((MYIOC_s_INFO_FMT "dv %x width %x factor %x saf_te %x\n", - hd->ioc->name, driver_setup.dv, + ioc->name, driver_setup.dv, driver_setup.max_width, driver_setup.min_sync_fac, driver_setup.saf_te)); @@ -1620,14 +1388,11 @@ hd = (MPT_SCSI_HOST *)host->hostdata; if (hd != NULL) { - int sz1, sz2, sz3, sztarget=0; - int szr2chain = 0; - int szc2chain = 0; - int szQ = 0; + int sz1, sz3, sztarget=0; mptscsih_shutdown(&pdev->dev); - sz1 = sz2 = sz3 = 0; + sz1 = sz3 = 0; if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); @@ -1635,24 +1400,6 @@ hd->ScsiLookup = NULL; } - if (hd->ReqToChain != NULL) { - szr2chain = hd->ioc->req_depth * sizeof(int); - kfree(hd->ReqToChain); - hd->ReqToChain = NULL; - } - - if (hd->ChainToChain != NULL) { - szc2chain = hd->num_chain * sizeof(int); - kfree(hd->ChainToChain); - hd->ChainToChain = NULL; - } - - if (hd->memQ != NULL) { - szQ = host->can_queue * sizeof(MPT_DONE_Q); - kfree(hd->memQ); - hd->memQ = NULL; - } - if (hd->Targets != NULL) { int max, ii; @@ -1680,9 +1427,9 @@ hd->Targets = NULL; } - dprintk((MYIOC_s_INFO_FMT - "Free'd ScsiLookup (%d) Target (%d+%d) memory\n", - hd->ioc->name, sz1, sz3, sztarget)); + dprintk((MYIOC_s_INFO_FMT + "Free'd ScsiLookup (%d) Target (%d+%d) memory\n", + hd->ioc->name, sz1, sz3, sztarget)); dprintk(("Free'd done and free Q (%d) memory\n", szQ)); /* NULL the Scsi_Host pointer @@ -1802,7 +1549,7 @@ ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER); if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { - dprintk((KERN_INFO MYNAM + devtprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); } @@ -1864,7 +1611,7 @@ * * Returns pointer to buffer where information was written. */ -const char * +static const char * mptscsih_info(struct Scsi_Host *SChost) { MPT_SCSI_HOST *h; @@ -2079,7 +1826,8 @@ * hostno: scsi host number * func: if write = 1; if read = 0 */ -int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, +static int +mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func) { MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; @@ -2114,15 +1862,13 @@ * * Returns 0. (rtn value discarded by linux scsi mid-layer) */ -int +static int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *pTarget; - MPT_DONE_Q *buffer; - unsigned long flags; int target; int lun; u32 datalen; @@ -2147,16 +1893,9 @@ (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); if (hd->resetPending) { - /* Prevent new commands from being issued - * while reloading the FW. Reset timer to 60 seconds, - * as the FW can take some time to come ready. - * For New EH, cmds on doneQ posted to FW. - */ - did_errcode = 1; - mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60)); dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); - goto did_error; + return SCSI_MLQUEUE_HOST_BUSY; } /* @@ -2165,8 +1904,7 @@ if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc)) == NULL) { dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", hd->ioc->name)); - did_errcode = 2; - goto did_error; + return SCSI_MLQUEUE_HOST_BUSY; } pScsiReq = (SCSIIORequest_t *) mf; @@ -2249,7 +1987,7 @@ (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ - rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx); + rc = mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx); } @@ -2283,7 +2021,7 @@ } /* Trying to do DV to this target, extend timeout. - * Wait to issue intil flag is clear + * Wait to issue until flag is clear */ if (dvStatus & MPT_SCSICFG_DV_PENDING) { mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); @@ -2314,64 +2052,18 @@ mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", hd->ioc->name, SCpnt, mf, my_idx)); - } else { - ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n", - hd->ioc->name, SCpnt, my_idx)); - /* Place this command on the pendingQ if possible */ - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->freeQ)) { - buffer = hd->freeQ.head; - Q_DEL_ITEM(buffer); - - /* Save the mf pointer - */ - buffer->argp = (void *)mf; - - /* Add to the pendingQ - */ - Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - } else { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - SCpnt->result = (DID_BUS_BUSY << 16); - SCpnt->scsi_done(SCpnt); - } - } - } else { - mptscsih_freeChainBuffers(hd, my_idx); - mpt_free_msg_frame(ScsiDoneCtx, hd->ioc, mf); - did_errcode = 3; - goto did_error; - } + DBG_DUMP_REQUEST_FRAME(mf) + } else + goto fail; + } else + goto fail; return 0; -did_error: - dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n", - hd->ioc->name, did_errcode, SCpnt)); - /* Just wish OS to issue a retry */ - SCpnt->result = (DID_BUS_BUSY << 16); - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->freeQ)) { - dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n", - (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); - buffer = hd->freeQ.head; - Q_DEL_ITEM(buffer); - - /* Set the scsi_cmnd pointer - */ - buffer->argp = (void *)SCpnt; - - /* Add to the doneQ - */ - Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - } else { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - SCpnt->scsi_done(SCpnt); - } - - return 0; + fail: + mptscsih_freeChainBuffers(hd->ioc, my_idx); + mpt_free_msg_frame(hd->ioc, mf); + return SCSI_MLQUEUE_HOST_BUSY; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2385,7 +2077,7 @@ * No return. */ static void -mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx) +mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) { MPT_FRAME_HDR *chain; unsigned long flags; @@ -2395,28 +2087,28 @@ /* Get the first chain index and reset * tracker state. */ - chain_idx = hd->ReqToChain[req_idx]; - hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; + chain_idx = ioc->ReqToChain[req_idx]; + ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; while (chain_idx != MPT_HOST_NO_CHAIN) { /* Save the next chain buffer index */ - next = hd->ChainToChain[chain_idx]; + next = ioc->ChainToChain[chain_idx]; /* Free this chain buffer and reset * tracker */ - hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; + ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; - chain = (MPT_FRAME_HDR *) (hd->ChainBuffer - + (chain_idx * hd->ioc->req_sz)); - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - Q_ADD_TAIL(&hd->FreeChainQ.head, + chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer + + (chain_idx * ioc->req_sz)); + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR); - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n", - hd->ioc->name, chain_idx)); + ioc->name, chain_idx)); /* handle next */ chain_idx = next; @@ -2480,12 +2172,6 @@ } spin_unlock_irqrestore(&ioc->diagLock, flags); - /* Do not do a Task Management if there are - * too many failed TMs on this adapter. - */ - if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM) - doTask = 0; - /* Wait a fixed amount of time for the TM pending flag to be cleared. * If we time out and not bus reset, then we return a FAILED status to the caller. * The call to mptscsih_tm_pending_wait() will set the pending flag if we are @@ -2593,7 +2279,7 @@ /* Return Fail to calling function if no message frames available. */ if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc)) == NULL) { - dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n", + dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", hd->ioc->name)); //return FAILED; return -999; @@ -2624,29 +2310,30 @@ pScsiTm->Reserved2[ii] = 0; pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt, ctx2abort (0x%08x), type (%d)\n", - hd->ioc->name, ctx2abort, type)); /* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake mpt_put_msg_frame(hd->ioc->id, mf); * Save the MF pointer in case the request times out. */ hd->tmPtr = mf; - hd->numTMrequests++; hd->TMtimer.expires = jiffies + timeout; add_timer(&hd->TMtimer); + dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n", + hd->ioc->name, ctx2abort, type)); + + DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm); + if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc, sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag)) != 0) { - dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!" + dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf)); - hd->numTMrequests--; hd->tmPtr = NULL; del_timer(&hd->TMtimer); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc, mf); + mpt_free_msg_frame(hd->ioc, mf); } - + return retval; } @@ -2659,10 +2346,11 @@ * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_abort(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; MPT_FRAME_HDR *mf; u32 ctx2abort; int scpnt_idx; @@ -2673,12 +2361,13 @@ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) { SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); - dtmprintk((KERN_WARNING MYNAM ": mptscsih_abort: " + dfailprintk((KERN_WARNING MYNAM ": mptscsih_abort: " "Can't locate host! (sc=%p)\n", SCpnt)); return FAILED; } + ioc = hd->ioc; if (hd->resetPending) return FAILED; @@ -2691,11 +2380,9 @@ /* Find this command */ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { - /* Cmd not found in ScsiLookup. If found in - * doneQ, delete from Q. Do OS callback. + /* Cmd not found in ScsiLookup. + * Do OS callback. */ - search_doneQ_for_cmd(hd, SCpnt); - SCpnt->result = DID_RESET << 16; dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " "Command not in the active list! (sc=%p)\n", @@ -2703,18 +2390,6 @@ return SUCCESS; } - /* If this command is pended, then timeout/hang occurred - * during DV. Post command and flush pending Q - * and then following up with the reset request. - */ - if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { - mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); - post_pendingQ_commands(hd); - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "Posting pended cmd! (sc=%p)\n", - hd->ioc->name, SCpnt)); - } - /* Most important! Set TaskMsgContext to SCpnt's MsgContext! * (the IO to be ABORT'd) * @@ -2724,7 +2399,7 @@ */ mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; - + hd->abortSCpnt = SCpnt; spin_unlock_irq(host_lock); @@ -2743,12 +2418,26 @@ */ hd->tmPending = 0; hd->tmState = TM_STATE_NONE; - + spin_lock_irq(host_lock); + + /* Unmap the DMA buffers, if any. */ + if (SCpnt->use_sg) { + pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, + SCpnt->use_sg, SCpnt->sc_data_direction); + } else if (SCpnt->request_bufflen) { + pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle, + SCpnt->request_bufflen, SCpnt->sc_data_direction); + } + hd->ScsiLookup[scpnt_idx] = NULL; + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done(SCpnt); /* Issue the command callback */ + mptscsih_freeChainBuffers(ioc, scpnt_idx); + mpt_free_msg_frame(ioc, mf); return FAILED; } spin_lock_irq(host_lock); - return FAILED; + return SUCCESS; } @@ -2761,7 +2450,7 @@ * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_dev_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; @@ -2816,7 +2505,7 @@ * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_bus_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; @@ -2839,9 +2528,6 @@ /* We are now ready to execute the task management request. */ spin_unlock_irq(host_lock); -// printk("testing start : mptscsih_schedule_reset\n"); -// mptscsih_schedule_reset(hd); -// printk("testing end: mptscsih_schedule_reset\n"); if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, SCpnt->device->channel, 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) < 0){ @@ -2871,7 +2557,7 @@ * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_host_reset(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST * hd; @@ -2937,8 +2623,7 @@ break; } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + msleep(250); } while (--loop_count); return status; @@ -2965,9 +2650,10 @@ SCSITaskMgmt_t *pScsiTmReq; MPT_SCSI_HOST *hd; unsigned long flags; - u8 tmType = 0; + u16 iocstatus; + u8 tmType; - dtmprintk((MYIOC_s_INFO_FMT "SCSI TaskMgmt completed (mf=%p,r=%p)\n", + dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", ioc->name, mf, mr)); if (ioc->sh) { /* Depending on the thread, a timer is activated for @@ -2978,7 +2664,7 @@ if (hd->tmPtr) { del_timer(&hd->TMtimer); } - dtmprintk((MYIOC_s_INFO_FMT "taskQcnt (%d)\n", + dtmprintk((MYIOC_s_WARN_FMT "taskQcnt (%d)\n", ioc->name, hd->taskQcnt)); } else { dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n", @@ -2997,18 +2683,15 @@ /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ tmType = pScsiTmReq->TaskType; - dtmprintk((KERN_INFO " TaskType = %d, TerminationCount=%d\n", - tmType, le32_to_cpu(pScsiTmReply->TerminationCount))); - + dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n", + ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount))); + DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply); + + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n", + ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo))); /* Error? (anything non-zero?) */ - if (*(u32 *)&pScsiTmReply->Reserved2[0]) { - u16 iocstatus; - - iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dtmprintk((KERN_INFO " SCSI TaskMgmt (%d) - Oops!\n", tmType)); - dtmprintk((KERN_INFO " IOCStatus = %04xh\n", iocstatus)); - dtmprintk((KERN_INFO " IOCLogInfo = %08xh\n", - le32_to_cpu(pScsiTmReply->IOCLogInfo))); + if (iocstatus) { /* clear flags and continue. */ @@ -3029,11 +2712,9 @@ } } } else { - dtmprintk((KERN_INFO " SCSI TaskMgmt SUCCESS!\n")); + dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name)); - hd->numTMrequests--; hd->abortSCpnt = NULL; - flush_doneQ(hd); } } @@ -3051,26 +2732,21 @@ /* * This is anyones guess quite frankly. */ -int +static int mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]) { int heads; int sectors; sector_t cylinders; -#ifdef CONFIG_LBD ulong dummy; -#endif heads = 64; sectors = 32; -#ifdef CONFIG_LBD + dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); -#else - cylinders = (ulong)capacity / (heads * sectors); -#endif /* * Handle extended translation size for logical drives @@ -3079,13 +2755,9 @@ if ((ulong)capacity >= 0x200000) { heads = 255; sectors = 63; -#ifdef CONFIG_LBD dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); -#else - cylinders = (ulong)capacity / (heads * sectors); -#endif } /* return result */ @@ -3107,7 +2779,7 @@ * Return non-zero if allocation fails. * Init memory once per id (not LUN). */ -int +static int mptscsih_slave_alloc(struct scsi_device *device) { struct Scsi_Host *host = device->host; @@ -3130,12 +2802,21 @@ Q_INIT(&vdev->WaitQ, void); Q_INIT(&vdev->SentQ, void); Q_INIT(&vdev->DoneQ, void); - vdev->tflags = 0; + vdev->tflags = MPT_TARGET_FLAGS_Q_YES; vdev->ioc_id = hd->ioc->id; vdev->target_id = device->id; - vdev->bus_id = hd->port; - + vdev->bus_id = device->channel; + vdev->raidVolume = 0; hd->Targets[device->id] = vdev; + if (hd->is_spi) { + if (hd->ioc->spi_data.isRaid & (1 << device->id)) { + vdev->raidVolume = 1; + ddvtprintk((KERN_INFO + "RAID Volume @ id %d\n", device->id)); + } + } else { + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + } } } vdev->num_luns++; @@ -3147,7 +2828,7 @@ * OS entry point to allow for host driver to free allocated memory * Called if no device present or device being unloaded */ -void +static void mptscsih_slave_destroy(struct scsi_device *device) { struct Scsi_Host *host = device->host; @@ -3176,15 +2857,15 @@ kfree(hd->Targets[device->id]); hd->Targets[device->id] = NULL; - if (!hd->is_spi) + if (!hd->is_spi) return; if((hd->ioc->spi_data.isRaid) && (hd->ioc->spi_data.pIocPg3)) { int i; for(i=0;iioc->spi_data.pIocPg3->NumPhysDisks && raid_volume==0;i++) - - if(device->id == + + if(device->id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID) { raid_volume=1; hd->ioc->spi_data.forceDv |= @@ -3202,7 +2883,7 @@ } } } - + return; } @@ -3212,7 +2893,7 @@ * member to 1 if a device does not support Q tags. * Return non-zero if fails. */ -int +static int mptscsih_slave_configure(struct scsi_device *device) { struct Scsi_Host *sh = device->host; @@ -3240,8 +2921,16 @@ pTarget = hd->Targets[device->id]; if (pTarget == NULL) { - /* error case - don't know about this device */ - scsi_adjust_queue_depth(device, 0, 1); + /* Driver doesn't know about this device. + * Kernel may generate a "Dummy Lun 0" which + * may become a real Lun if a + * "scsi add-single-device" command is executed + * while the driver is active (hot-plug a + * device). LSI Raid controllers need + * queue_depth set to DEV_HIGH for this reason. + */ + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + MPT_SCSI_CMD_PER_DEV_HIGH); goto slave_configure_exit; } @@ -3302,8 +2991,6 @@ SCSIIORequest_t *pReq; u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); int index; - char devFoo[96]; - IO_Info_t thisIo; /* Get target structure */ @@ -3342,35 +3029,10 @@ ioc->eventContext++; } } - - /* Print an error report for the user. - */ - thisIo.cdbPtr = sc->cmnd; - thisIo.sensePtr = sc->sense_buffer; - thisIo.SCSIStatus = pScsiReply->SCSIStatus; - thisIo.DoDisplay = 1; - if (hd->is_multipath) - sprintf(devFoo, "%d:%d:%d", - hd->ioc->id, - pReq->TargetID, - pReq->LUN[1]); - else - sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->device->id, sc->device->lun); - thisIo.DevIDStr = devFoo; -/* fubar */ - thisIo.dataPtr = NULL; - thisIo.inqPtr = NULL; - if (sc->device) { - thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */ - } - (void) mpt_ScsiHost_ErrorReport(&thisIo); - } else { dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n", hd->ioc->name)); } - - return; } static u32 @@ -3390,102 +3052,6 @@ return -1; } - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Search the pendingQ for a command with specific index. - * If found, delete and return mf pointer - * If not found, return NULL - */ -static MPT_FRAME_HDR * -mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx) -{ - unsigned long flags; - MPT_DONE_Q *buffer; - MPT_FRAME_HDR *mf = NULL; - MPT_FRAME_HDR *cmdMfPtr; - - ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name)); - cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->pendingQ)) { - buffer = hd->pendingQ.head; - do { - mf = (MPT_FRAME_HDR *) buffer->argp; - if (mf == cmdMfPtr) { - Q_DEL_ITEM(buffer); - - /* clear the arg pointer - */ - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - break; - } - mf = NULL; - } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->pendingQ); - } - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - ddvtprintk((" ...return %p\n", mf)); - return mf; -} - -/* Post all commands on the pendingQ to the FW. - * Lock Q when deleting/adding members - * Lock io_request_lock for OS callback. - */ -static void -post_pendingQ_commands(MPT_SCSI_HOST *hd) -{ - MPT_FRAME_HDR *mf; - MPT_DONE_Q *buffer; - unsigned long flags; - - /* Flush the pendingQ. - */ - ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands\n", hd->ioc->name)); - while (1) { - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (Q_IS_EMPTY(&hd->pendingQ)) { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - break; - } - - buffer = hd->pendingQ.head; - /* Delete from Q - */ - Q_DEL_ITEM(buffer); - - mf = (MPT_FRAME_HDR *) buffer->argp; - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - - if (!mf) { - /* This should never happen */ - printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, (void *) mf); - continue; - } - - mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); - -#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) - { - u16 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - struct scsi_cmnd *sc = hd->ScsiLookup[req_idx]; - printk(MYIOC_s_INFO_FMT "Issued SCSI cmd (sc=%p) idx=%d (mf=%p)\n", - hd->ioc->name, sc, req_idx, mf); - } -#endif - } - - return; -} - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) @@ -3520,14 +3086,10 @@ dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name)); /* 2. Flush running commands - * Clean drop test code - if compiled * Clean ScsiLookup (and associated memory) * AND clean mytaskQ */ - /* 2a. Drop Test Command. - */ - /* 2b. Reply to OS all known outstanding I/O commands. */ mptscsih_flush_running_cmds(hd); @@ -3538,7 +3100,7 @@ */ if (hd->cmdPtr) { del_timer(&hd->timer); - mpt_free_msg_frame(ScsiScanDvCtx, ioc, hd->cmdPtr); + mpt_free_msg_frame(ioc, hd->cmdPtr); } /* 2d. If a task management has not completed, @@ -3546,7 +3108,7 @@ */ if (hd->tmPtr) { del_timer(&hd->TMtimer); - mpt_free_msg_frame(ScsiTaskCtx, ioc, hd->tmPtr); + mpt_free_msg_frame(ioc, hd->tmPtr); } #ifdef MPTSCSIH_DBG_TIMEOUT @@ -3573,7 +3135,6 @@ /* 2. Chain Buffer initialization */ - mptscsih_initChainBuffers(hd, 0); /* 3. tmPtr clear */ @@ -3583,8 +3144,10 @@ /* 4. Renegotiate to all devices, if SCSI */ - if (hd->is_spi) + if (hd->is_spi) { + dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n")); mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM); + } /* 5. Enable new commands to be posted */ @@ -3592,7 +3155,6 @@ hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); hd->resetPending = 0; - hd->numTMrequests = 0; hd->tmState = TM_STATE_NONE; /* 6. If there was an internal command, @@ -3609,11 +3171,7 @@ hd->cmdPtr = NULL; } - /* 7. Flush doneQ - */ - flush_doneQ(hd); - - /* 8. Set flag to force DV and re-read IOC Page 3 + /* 7. Set flag to force DV and re-read IOC Page 3 */ if (hd->is_spi) { ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3; @@ -3634,7 +3192,7 @@ MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - dprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", + devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event)); switch (event) { @@ -3766,394 +3324,6 @@ .use_clustering = ENABLE_CLUSTERING, }; - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Private data... - */ -static ASCQ_Table_t *mptscsih_ASCQ_TablePtr; - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* old symsense.c stuff... */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Private data... - * To protect ourselves against those that would pass us bogus pointers - */ -static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES] - = { 0x1F, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u8 dummySenseData[SCSI_STD_SENSE_BYTES] - = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; -static u8 dummyCDB[16] - = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u8 dummyScsiData[16] - = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -static char *ScsiStatusString[] = { - "GOOD", /* 00h */ - NULL, /* 01h */ - "CHECK CONDITION", /* 02h */ - NULL, /* 03h */ - "CONDITION MET", /* 04h */ - NULL, /* 05h */ - NULL, /* 06h */ - NULL, /* 07h */ - "BUSY", /* 08h */ - NULL, /* 09h */ - NULL, /* 0Ah */ - NULL, /* 0Bh */ - NULL, /* 0Ch */ - NULL, /* 0Dh */ - NULL, /* 0Eh */ - NULL, /* 0Fh */ - "INTERMEDIATE", /* 10h */ - NULL, /* 11h */ - NULL, /* 12h */ - NULL, /* 13h */ - "INTERMEDIATE-CONDITION MET", /* 14h */ - NULL, /* 15h */ - NULL, /* 16h */ - NULL, /* 17h */ - "RESERVATION CONFLICT", /* 18h */ - NULL, /* 19h */ - NULL, /* 1Ah */ - NULL, /* 1Bh */ - NULL, /* 1Ch */ - NULL, /* 1Dh */ - NULL, /* 1Eh */ - NULL, /* 1Fh */ - NULL, /* 20h */ - NULL, /* 21h */ - "COMMAND TERMINATED", /* 22h */ - NULL, /* 23h */ - NULL, /* 24h */ - NULL, /* 25h */ - NULL, /* 26h */ - NULL, /* 27h */ - "TASK SET FULL", /* 28h */ - NULL, /* 29h */ - NULL, /* 2Ah */ - NULL, /* 2Bh */ - NULL, /* 2Ch */ - NULL, /* 2Dh */ - NULL, /* 2Eh */ - NULL, /* 2Fh */ - "ACA ACTIVE", /* 30h */ - NULL -}; - -static const char *ScsiCommonOpString[] = { - "TEST UNIT READY", /* 00h */ - "REZERO UNIT (REWIND)", /* 01h */ - NULL, /* 02h */ - "REQUEST_SENSE", /* 03h */ - "FORMAT UNIT (MEDIUM)", /* 04h */ - "READ BLOCK LIMITS", /* 05h */ - NULL, /* 06h */ - "REASSIGN BLOCKS", /* 07h */ - "READ(6)", /* 08h */ - NULL, /* 09h */ - "WRITE(6)", /* 0Ah */ - "SEEK(6)", /* 0Bh */ - NULL, /* 0Ch */ - NULL, /* 0Dh */ - NULL, /* 0Eh */ - "READ REVERSE", /* 0Fh */ - "WRITE_FILEMARKS", /* 10h */ - "SPACE(6)", /* 11h */ - "INQUIRY", /* 12h */ - NULL -}; - -static const char *SenseKeyString[] = { - "NO SENSE", /* 0h */ - "RECOVERED ERROR", /* 1h */ - "NOT READY", /* 2h */ - "MEDIUM ERROR", /* 3h */ - "HARDWARE ERROR", /* 4h */ - "ILLEGAL REQUEST", /* 5h */ - "UNIT ATTENTION", /* 6h */ - "DATA PROTECT", /* 7h */ - "BLANK CHECK", /* 8h */ - "VENDOR-SPECIFIC", /* 9h */ - "ABORTED COPY", /* Ah */ - "ABORTED COMMAND", /* Bh */ - "EQUAL (obsolete)", /* Ch */ - "VOLUME OVERFLOW", /* Dh */ - "MISCOMPARE", /* Eh */ - "RESERVED", /* Fh */ - NULL -}; - -#define SPECIAL_ASCQ(c,q) \ - (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70)) - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int dump_cdb(char *foo, unsigned char *cdb) -{ - int i, grpCode, cdbLen; - int l = 0; - - grpCode = cdb[0] >> 5; - if (grpCode < 1) - cdbLen = 6; - else if (grpCode < 3) - cdbLen = 10; - else if (grpCode == 5) - cdbLen = 12; - else - cdbLen = 16; - - for (i=0; i < cdbLen; i++) - l += sprintf(foo+l, " %02X", cdb[i]); - - return l; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Do ASC/ASCQ lookup/grindage to English readable string(s) */ -static const char * ascq_set_strings_4max( - u8 ASC, u8 ASCQ, - const char **s1, const char **s2, const char **s3, const char **s4) -{ - static const char *asc_04_part1_string = "LOGICAL UNIT "; - static const char *asc_04_part2a_string = "NOT READY, "; - static const char *asc_04_part2b_string = "IS "; - static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */ - "CAUSE NOT REPORTABLE", /* 04 00 */ - "IN PROCESS OF BECOMING READY", /* 04 01 */ - "INITIALIZING CMD. REQUIRED", /* 04 02 */ - "MANUAL INTERVENTION REQUIRED", /* 04 03 */ - /* Add " IN PROGRESS" to all the following... */ - "FORMAT", /* 04 04 */ - "REBUILD", /* 04 05 */ - "RECALCULATION", /* 04 06 */ - "OPERATION", /* 04 07 */ - "LONG WRITE", /* 04 08 */ - "SELF-TEST", /* 04 09 */ - NULL - }; - static char *asc_04_part4_string = " IN PROGRESS"; - - static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */ - "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */ - "POWER ON OCCURRED", /* 29 01 */ - "SCSI BUS RESET OCCURRED", /* 29 02 */ - "BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */ - "DEVICE INTERNAL RESET", /* 29 04 */ - "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */ - "TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */ - NULL - }; - static char *ascq_vendor_uniq = "(Vendor Unique)"; - static char *ascq_noone = "(no matching ASC/ASCQ description found)"; - int idx; - - *s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */ - - /* CHECKME! Need lock/sem? - * Update and examine for isense module presense. - */ - mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr; - - if (mptscsih_ASCQ_TablePtr == NULL) { - /* 2nd chances... */ - if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) { - *s1 = asc_04_part1_string; - *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string; - *s3 = asc_04_ascq_NN_part3_strings[ASCQ]; - /* check for " IN PROGRESS" ones */ - if (ASCQ >= 0x04) - *s4 = asc_04_part4_string; - } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1)) - *s1 = asc_29_ascq_NN_strings[ASCQ]; - /* - * Else { leave all *s[1-4] values pointing to the empty "" string } - */ - return *s1; - } - - /* - * Need to check ASC here; if it is "special," then - * the ASCQ is variable, and indicates failed component number. - * We must treat the ASCQ as a "don't care" while searching the - * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later - * on when we actually need to identify the failed component. - */ - if (SPECIAL_ASCQ(ASC,ASCQ)) - ASCQ = 0xFF; - - /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */ - for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++) - if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) { - *s1 = mptscsih_ASCQ_TablePtr[idx].Description; - return *s1; - } - - if ((ASC >= 0x80) || (ASCQ >= 0x80)) - *s1 = ascq_vendor_uniq; - else - *s1 = ascq_noone; - - return *s1; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * SCSI Information Report; desired output format... - *--- -SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION) - Key=6h (UNIT ATTENTION); FRU=03h - ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" - CDB: 00 00 00 00 00 00 - TestUnitReady - *--- - */ -/* - * SCSI Error Report; desired output format... - *--- -SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0) - SCSI_Status=02h (CHECK CONDITION) - Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady - SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00 - SenseKey=6h (UNIT ATTENTION); FRU=03h - ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" - *--- - */ - -int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop) -{ - char foo[512]; - char buf2[32]; - char *statstr; - const char *opstr; - int sk = SD_Sense_Key(ioop->sensePtr); - const char *skstr = SenseKeyString[sk]; - unsigned char asc = SD_ASC(ioop->sensePtr); - unsigned char ascq = SD_ASCQ(ioop->sensePtr); - int l; - - /* Change the error logging to only report errors on - * read and write commands. Ignore errors on other commands. - * Should this be configurable via proc? - */ - switch (ioop->cdbPtr[0]) { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_16: - case WRITE_16: - break; - default: - return 0; - } - - /* - * More quiet mode. - * Filter out common, repetitive, warning-type errors... like: - * POWER ON (06,29/00 or 06,29/01), - * SPINNING UP (02,04/01), - * LOGICAL UNIT NOT SUPPORTED (05,25/00), etc. - */ - if (sk == SK_NO_SENSE) { - return 0; - } - - if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01)) - || (sk==SK_NOT_READY && asc==0x04 && (ascq==0x01 || ascq==0x02)) - || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00) - ) - { - /* Do nothing! */ - return 0; - } - - /* Prevent the system from continually writing to the log - * if a medium is not found: 02 3A 00 - * Changer issues: TUR, Read Capacity, Table of Contents continually - */ - if (sk==SK_NOT_READY && asc==0x3A) { - if (ioop->cdbPtr == NULL) { - return 0; - } else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) || - (ioop->cdbPtr[0] == CMD_ReadCapacity) || - (ioop->cdbPtr[0] == 0x43)) { - return 0; - } - } - if (sk==SK_UNIT_ATTENTION) { - if (ioop->cdbPtr == NULL) - return 0; - else if (ioop->cdbPtr[0] == CMD_TestUnitReady) - return 0; - } - - /* - * Protect ourselves... - */ - if (ioop->cdbPtr == NULL) - ioop->cdbPtr = dummyCDB; - if (ioop->sensePtr == NULL) - ioop->sensePtr = dummySenseData; - if (ioop->inqPtr == NULL) - ioop->inqPtr = dummyInqData; - if (ioop->dataPtr == NULL) - ioop->dataPtr = dummyScsiData; - - statstr = NULL; - if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) || - ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) { - (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus); - statstr = buf2; - } - - opstr = NULL; - if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*)) - opstr = ScsiCommonOpString[ioop->cdbPtr[0]]; - else if (mpt_ScsiOpcodesPtr) - opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]]; - - l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n", - ioop->DevIDStr, - ioop->SCSIStatus, - statstr); - l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", - sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); - { - const char *x1, *x2, *x3, *x4; - x1 = x2 = x3 = x4 = ""; - x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4); - if (x1 != NULL) { - if (x1[0] != '(') - l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4); - else - l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4); - } - } - l += sprintf(foo+l, "\n CDB:"); - l += dump_cdb(foo+l, ioop->cdbPtr); - if (opstr) - l += sprintf(foo+l, " - \"%s\"", opstr); - l += sprintf(foo+l, "\n"); - - PrintF(("%s\n", foo)); - - return l; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mptscsih_initTarget - Target, LUN alloc/free functionality. @@ -4176,48 +3346,33 @@ { int indexed_lun, lun_index; VirtDevice *vdev; + ScsiCfgData *pSpi; char data_56; - dprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", + dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", hd->ioc->name, bus_id, target_id, lun, hd)); - /* Is LUN supported? If so, upper 3 bits will be 0 + /* Is LUN supported? If so, upper 2 bits will be 0 * in first byte of inquiry data. */ if (data[0] & 0xe0) return; - vdev = hd->Targets[target_id]; + if ((vdev = hd->Targets[target_id]) == NULL) { + return; + } lun_index = (lun >> 5); /* 32 luns per lun_index */ indexed_lun = (lun % 32); vdev->luns[lun_index] |= (1 << indexed_lun); - vdev->raidVolume = 0; if (hd->is_spi) { - if (hd->ioc->spi_data.isRaid & (1 << target_id)) { - vdev->raidVolume = 1; - ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id)); - } - } - - if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { - if ( dlen > 8 ) { - memcpy (vdev->inq_data, data, 8); - } else { - memcpy (vdev->inq_data, data, dlen); - } - vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; - - /* If LUN 0, tape and have not done DV, set the DV flag. - */ - if (hd->is_spi && (lun == 0) && (data[0] == SCSI_TYPE_TAPE)) { - ScsiCfgData *pSpi = &hd->ioc->spi_data; - if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) - pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; - } - - if ( (data[0] == SCSI_TYPE_PROC) && + if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { + /* Treat all Processors as SAF-TE if + * command line option is set */ + vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptscsih_writeIOCPage4(hd, target_id, bus_id); + }else if ((data[0] == TYPE_PROCESSOR) && !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { if ( dlen > 49 ) { vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; @@ -4230,30 +3385,51 @@ vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; mptscsih_writeIOCPage4(hd, target_id, bus_id); } - } else { - /* Treat all Processors as SAF-TE if - * command line option is set */ - if ( hd->ioc->spi_data.Saf_Te ) { - vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; - mptscsih_writeIOCPage4(hd, target_id, bus_id); - } } } + if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { + if ( dlen > 8 ) { + memcpy (vdev->inq_data, data, 8); + } else { + memcpy (vdev->inq_data, data, dlen); + } - data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */ - if (dlen > 56) { - if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { - /* Update the target capabilities + /* If have not done DV, set the DV flag. */ - data_56 = data[56]; - vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + pSpi = &hd->ioc->spi_data; + if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) { + if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) + pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; + } + + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + + + data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */ + if (dlen > 56) { + if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { + /* Update the target capabilities + */ + data_56 = data[56]; + vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + } + } + mptscsih_setTargetNegoParms(hd, vdev, data_56); + } else { + /* Initial Inquiry may not request enough data bytes to + * obtain byte 57. DV will; if target doesn't return + * at least 57 bytes, data[56] will be zero. */ + if (dlen > 56) { + if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { + /* Update the target capabilities + */ + data_56 = data[56]; + vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + mptscsih_setTargetNegoParms(hd, vdev, data_56); + } } } - mptscsih_setTargetNegoParms(hd, vdev, data_56); } - - dprintk((KERN_INFO " target = %p\n", vdev)); - return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -4262,12 +3438,12 @@ * the Inquiry data, adapter capabilities, and NVRAM settings. * */ -void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) +static void +mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) { ScsiCfgData *pspi_data = &hd->ioc->spi_data; int id = (int) target->target_id; int nvram; - char canQ = 0; VirtDevice *vdev; int ii; u8 width = MPT_NARROW; @@ -4276,14 +3452,6 @@ u8 version, nfactor; u8 noQas = 1; - if (!hd->is_spi) { - if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { - if (target->inq_data[7] & 0x02) - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - } - return; - } - target->negoFlags = pspi_data->noQas; /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine @@ -4293,137 +3461,152 @@ /* Set flags based on Inquiry data */ - if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { - version = target->inq_data[2] & 0x07; - if (version < 2) { - width = 0; - factor = MPT_ULTRA2; - offset = pspi_data->maxSyncOffset; - } else { - if (target->inq_data[7] & 0x20) { - width = 1; - } + version = target->inq_data[2] & 0x07; + if (version < 2) { + width = 0; + factor = MPT_ULTRA2; + offset = pspi_data->maxSyncOffset; + target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; + } else { + if (target->inq_data[7] & 0x20) { + width = 1; + } - if (target->inq_data[7] & 0x10) { - /* bits 2 & 3 show Clocking support - */ + if (target->inq_data[7] & 0x10) { + factor = pspi_data->minSyncFactor; + if (target->tflags & MPT_TARGET_FLAGS_VALID_56) { + /* bits 2 & 3 show Clocking support */ if ((byte56 & 0x0C) == 0) factor = MPT_ULTRA2; else { if ((byte56 & 0x03) == 0) factor = MPT_ULTRA160; - else + else { factor = MPT_ULTRA320; - } - offset = pspi_data->maxSyncOffset; - - /* If RAID, never disable QAS - * else if non RAID, do not disable - * QAS if bit 1 is set - * bit 1 QAS support, non-raid only - * bit 0 IU support - */ - if ((target->raidVolume == 1) || (byte56 & 0x02)) { - noQas = 0; + if (byte56 & 0x02) + { + ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id)); + noQas = 0; + } + if (target->inq_data[0] == TYPE_TAPE) { + if (byte56 & 0x01) + target->negoFlags |= MPT_TAPE_NEGO_IDP; + } + } } } else { - factor = MPT_ASYNC; - offset = 0; + ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id)); + noQas = 0; } - } + + offset = pspi_data->maxSyncOffset; - if (target->inq_data[7] & 0x02) { - canQ = 1; + /* If RAID, never disable QAS + * else if non RAID, do not disable + * QAS if bit 1 is set + * bit 1 QAS support, non-raid only + * bit 0 IU support + */ + if (target->raidVolume == 1) { + noQas = 0; + } + } else { + factor = MPT_ASYNC; + offset = 0; } + } - /* Update tflags based on NVRAM settings. (SCSI only) - */ - if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { - nvram = pspi_data->nvram[id]; - nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + if ( (target->inq_data[7] & 0x02) == 0) { + target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; + } - if (width) - width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + /* Update tflags based on NVRAM settings. (SCSI only) + */ + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = pspi_data->nvram[id]; + nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; - if (offset > 0) { - /* Ensure factor is set to the - * maximum of: adapter, nvram, inquiry - */ - if (nfactor) { - if (nfactor < pspi_data->minSyncFactor ) - nfactor = pspi_data->minSyncFactor; + if (width) + width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; - factor = max(factor, nfactor); - if (factor == MPT_ASYNC) - offset = 0; - } else { + if (offset > 0) { + /* Ensure factor is set to the + * maximum of: adapter, nvram, inquiry + */ + if (nfactor) { + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; + + factor = max(factor, nfactor); + if (factor == MPT_ASYNC) offset = 0; - factor = MPT_ASYNC; - } } else { + offset = 0; factor = MPT_ASYNC; - } } - - /* Make sure data is consistent - */ - if ((!width) && (factor < MPT_ULTRA2)) { - factor = MPT_ULTRA2; + } else { + factor = MPT_ASYNC; } + } - /* Save the data to the target structure. - */ - target->minSyncFactor = factor; - target->maxOffset = offset; - target->maxWidth = width; - if (canQ) { - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - } + /* Make sure data is consistent + */ + if ((!width) && (factor < MPT_ULTRA2)) { + factor = MPT_ULTRA2; + } - target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; + /* Save the data to the target structure. + */ + target->minSyncFactor = factor; + target->maxOffset = offset; + target->maxWidth = width; - /* Disable unused features. - */ - if (!width) - target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; - if (!offset) - target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + /* Disable unused features. + */ + if (!width) + target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; - /* GEM, processor WORKAROUND - */ - if (((target->inq_data[0] & 0x1F) == 0x03) - || ((target->inq_data[0] & 0x1F) > 0x08)) { - target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); - pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; - } else { - if (noQas && (pspi_data->noQas == 0)) { - pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; - target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; - - /* Disable QAS in a mixed configuration case - */ - - ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); - for (ii = 0; ii < id; ii++) { - if ( (vdev = hd->Targets[ii]) ) { - vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; - } - } + if (!offset) + target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + + if ( factor > MPT_ULTRA320 ) + noQas = 0; + + /* GEM, processor WORKAROUND + */ + if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) { + target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); + pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; + } else { + if (noQas && (pspi_data->noQas == 0)) { + pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; + target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + + /* Disable QAS in a mixed configuration case + */ + + ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); + for (ii = 0; ii < id; ii++) { + if ( (vdev = hd->Targets[ii]) ) { + vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + mptscsih_writeSDP1(hd, 0, ii, vdev->negoFlags); + } } } - - /* Write SDP1 on this I/O to this target */ - if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) { - mptscsih_writeSDP1(hd, 0, id, hd->negoNvram); - pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE; - } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) { - mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO); - pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO; - } } - return; + /* Write SDP1 on this I/O to this target */ + if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) { + ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id)); + mptscsih_writeSDP1(hd, 0, id, hd->negoNvram); + pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE; + } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) { + ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id)); + mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO); + pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO; + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -4437,14 +3620,18 @@ static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) { u8 cmd; + ScsiCfgData *pSpi; + ddvtprintk((" set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n", + pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0])); + if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0)) return; cmd = pReq->CDB[0]; if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) { - ScsiCfgData *pSpi = &hd->ioc->spi_data; + pSpi = &hd->ioc->spi_data; if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) { /* Set NEED_DV for all hidden disks */ @@ -4510,6 +3697,8 @@ *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT); if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0) *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS; + if (flags & MPT_TAPE_NEGO_IDP) + *requestedPtr |= 0x08000000; } else if (factor < MPT_ULTRA2) { *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT; } @@ -4624,6 +3813,16 @@ //negoFlags = MPT_TARGET_NO_NEGO_SYNC; } + /* If id is not a raid volume, get the updated + * transmission settings from the target structure. + */ + if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { + width = pTarget->maxWidth; + factor = pTarget->minSyncFactor; + offset = pTarget->maxOffset; + negoFlags = pTarget->negoFlags; + } + #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION /* Force to async and narrow if DV has not been executed * for this ID @@ -4635,21 +3834,13 @@ } #endif - /* If id is not a raid volume, get the updated - * transmission settings from the target structure. - */ - if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { - width = pTarget->maxWidth; - factor = pTarget->minSyncFactor; - offset = pTarget->maxOffset; - negoFlags = pTarget->negoFlags; - } - if (flags & MPT_SCSICFG_BLK_NEGO) negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC; mptscsih_setDevicePage1Flags(width, factor, offset, &requested, &configuration, negoFlags); + dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", + target_id, width, factor, offset, negoFlags, requested, configuration)); /* Get a MF for this command. */ @@ -4754,9 +3945,6 @@ return -EAGAIN; } - ddvprintk((MYIOC_s_INFO_FMT "writeIOCPage4 (mf=%p, id=%d)\n", - ioc->name, mf, target_id)); - /* Set the request and the data pointers. * Place data at end of MF. */ @@ -4793,9 +3981,9 @@ mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); - dsprintk((MYIOC_s_INFO_FMT - "writeIOCPage4: pgaddr 0x%x\n", - ioc->name, (target_id | (bus<<8)))); + dinitprintk((MYIOC_s_INFO_FMT + "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", + ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus)); mpt_put_msg_frame(ScsiDoneCtx, ioc, mf); @@ -4922,13 +4110,15 @@ } else { SCSIIOReply_t *pReply; u16 status; + u8 scsi_status; pReply = (SCSIIOReply_t *) mr; status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_status = pReply->SCSIStatus; ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", - status, pReply->SCSIState, pReply->SCSIStatus, + status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo))); switch(status) { @@ -4973,7 +4163,7 @@ /* save sense data in global structure */ completionCode = MPT_SCANDV_SENSE; - hd->pLocal->scsiStatus = pReply->SCSIStatus; + hd->pLocal->scsiStatus = scsi_status; sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_idx * MPT_SENSE_BUFFER_ALLOC)); @@ -4984,7 +4174,7 @@ ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n", sense_data)); } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { - if (pReq->CDB[0] == CMD_Inquiry) + if (pReq->CDB[0] == INQUIRY) completionCode = MPT_SCANDV_ISSUE_SENSE; else completionCode = MPT_SCANDV_DID_RESET; @@ -4994,11 +4184,8 @@ else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) completionCode = MPT_SCANDV_DID_RESET; else { - /* If no error, this will be equivalent - * to MPT_SCANDV_GOOD - */ completionCode = MPT_SCANDV_GOOD; - hd->pLocal->scsiStatus = pReply->SCSIStatus; + hd->pLocal->scsiStatus = scsi_status; } break; @@ -5025,7 +4212,7 @@ */ wakeup: /* Free Chain buffers (will never chain) in scan or dv */ - //mptscsih_freeChainBuffers(hd, req_idx); + //mptscsih_freeChainBuffers(ioc, req_idx); /* * Wake up the original calling thread @@ -5197,7 +4384,7 @@ /* Set command specific information */ switch (cmd) { - case CMD_Inquiry: + case INQUIRY: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5205,13 +4392,13 @@ cmdTimeout = 10; break; - case CMD_TestUnitReady: + case TEST_UNIT_READY: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; cmdTimeout = 10; break; - case CMD_StartStopUnit: + case START_STOP: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5219,7 +4406,7 @@ cmdTimeout = 15; break; - case CMD_RequestSense: + case REQUEST_SENSE: cmdLen = 6; CDB[0] = cmd; CDB[4] = io->size; @@ -5227,7 +4414,7 @@ cmdTimeout = 10; break; - case CMD_ReadBuffer: + case READ_BUFFER: cmdLen = 10; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5246,7 +4433,7 @@ cmdTimeout = 10; break; - case CMD_WriteBuffer: + case WRITE_BUFFER: cmdLen = 10; dir = MPI_SCSIIO_CONTROL_WRITE; CDB[0] = cmd; @@ -5261,21 +4448,21 @@ cmdTimeout = 10; break; - case CMD_Reserve6: + case RESERVE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; cmdTimeout = 10; break; - case CMD_Release6: + case RELEASE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; cmdTimeout = 10; break; - case CMD_SynchronizeCache: + case SYNCHRONIZE_CACHE: cmdLen = 10; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5331,7 +4518,7 @@ else pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); - if (cmd == CMD_RequestSense) { + if (cmd == REQUEST_SENSE) { pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n", hd->ioc->name, cmd)); @@ -5439,7 +4626,7 @@ /* Following parameters will not change * in this routine. */ - iocmd.cmd = CMD_SynchronizeCache; + iocmd.cmd = SYNCHRONIZE_CACHE; iocmd.flags = 0; iocmd.physDiskNum = -1; iocmd.data = NULL; @@ -5509,6 +4696,9 @@ /* Force to async, narrow */ mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested, &configuration, flags); + dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC " + "offset=0 negoFlags=%x request=%x config=%x\n", + id, flags, requested, configuration)); pcfg1Data->RequestedParameters = le32_to_cpu(requested); pcfg1Data->Reserved = 0; pcfg1Data->Configuration = le32_to_cpu(configuration); @@ -5597,8 +4787,7 @@ } spin_unlock_irqrestore(&dvtaskQ_lock, flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + msleep(250); /* DV only to SCSI adapters */ if ((int)ioc->chip_type <= (int)FC929) @@ -5646,8 +4835,7 @@ hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING; hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + msleep(250); /* If hidden phys disk, block IO's to all * raid volumes @@ -5681,11 +4869,6 @@ } } - /* Post OS IOs that were pended while - * DV running. - */ - post_pendingQ_commands(hd); - if (hd->ioc->spi_data.noQas) mptscsih_qas_check(hd, id); } @@ -5741,11 +4924,14 @@ if ((pTarget != NULL) && (!pTarget->raidVolume)) { if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) { pTarget->negoFlags |= hd->ioc->spi_data.noQas; + dnegoprintk(("writeSDP1: id=%d flags=0\n", id)); mptscsih_writeSDP1(hd, 0, ii, 0); } } else { - if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) + if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) { + dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id)); mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM); + } } } return; @@ -5824,7 +5010,7 @@ lun = 0; bus = (u8) bus_number; ddvtprintk((MYIOC_s_NOTE_FMT - "DV started: bus=%d, id %d dv @ %p\n", + "DV started: bus=%d, id=%d dv @ %p\n", ioc->name, bus, id, &dv)); /* Prep DV structure @@ -5838,8 +5024,6 @@ */ dv.cmd = MPT_GET_NVRAM_VALS; mptscsih_dv_parms(hd, &dv, NULL); - if ((!dv.max.width) && (!dv.max.offset)) - return 0; /* Prep SCSI IO structure */ @@ -5851,15 +5035,6 @@ iocmd.rsvd = iocmd.rsvd2 = 0; pTarget = hd->Targets[id]; - if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { - /* Another GEM workaround. Check peripheral device type, - * if PROCESSOR, quit DV. - */ - if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) { - pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); - return 0; - } - } /* Use tagged commands if possible. */ @@ -5959,7 +5134,7 @@ /* Finish iocmd inititialization - hidden or visible disk? */ if (ioc->spi_data.pIocPg3) { - /* Searc IOC page 3 for matching id + /* Search IOC page 3 for matching id */ Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; @@ -6001,7 +5176,7 @@ */ hd->pLocal = NULL; readPage0 = 0; - sz = SCSI_STD_INQUIRY_BYTES; + sz = SCSI_MAX_INQUIRY_BYTES; rc = MPT_SCANDV_GOOD; while (1) { ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id)); @@ -6026,7 +5201,7 @@ ((hd->ioc->facts.FWVersion.Word >= 0x01010000) && (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) { - iocmd.cmd = CMD_RequestSense; + iocmd.cmd = REQUEST_SENSE; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = 0x12; @@ -6046,10 +5221,11 @@ goto target_done; } - iocmd.cmd = CMD_Inquiry; + iocmd.cmd = INQUIRY; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = sz; + memset(pbuf1, 0x00, sz); if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; else { @@ -6057,7 +5233,7 @@ goto target_done; rc = hd->pLocal->completion; if (rc == MPT_SCANDV_GOOD) { - if (hd->pLocal->scsiStatus == STS_BUSY) { + if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) { if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0) retcode = 1; else @@ -6087,7 +5263,17 @@ /* Another GEM workaround. Check peripheral device type, * if PROCESSOR, quit DV. */ - if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08)) + if (inq0 == TYPE_PROCESSOR) { + mptscsih_initTarget(hd, + bus, + id, + lun, + pbuf1, + sz); + goto target_done; + } + + if (inq0 > 0x08) goto target_done; if (mptscsih_do_cmd(hd, &iocmd) < 0) @@ -6111,6 +5297,9 @@ if ((pbuf1[56] & 0x02) == 0) { pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS; hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; + ddvprintk((MYIOC_s_NOTE_FMT + "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n", + ioc->name, id, pbuf1[56])); } } } @@ -6127,10 +5316,11 @@ if ((!dv.now.width) && (!dv.now.offset)) goto target_done; - iocmd.cmd = CMD_Inquiry; + iocmd.cmd = INQUIRY; iocmd.data_dma = buf2_dma; iocmd.data = pbuf2; iocmd.size = sz; + memset(pbuf2, 0x00, sz); if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; else if (hd->pLocal == NULL) @@ -6183,14 +5373,26 @@ if (memcmp(pbuf1, pbuf2, sz) != 0) { if (!firstPass) doFallback = 1; - } else + } else { + ddvprintk((MYIOC_s_NOTE_FMT + "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id)); + hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE; + mptscsih_initTarget(hd, + bus, + id, + lun, + pbuf1, + sz); break; /* test complete */ + } } } else if (rc == MPT_SCANDV_ISSUE_SENSE) doFallback = 1; /* set fallback flag */ - else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE)) + else if ((rc == MPT_SCANDV_DID_RESET) || + (rc == MPT_SCANDV_SENSE) || + (rc == MPT_SCANDV_FALLBACK)) doFallback = 1; /* set fallback flag */ else goto target_done; @@ -6199,6 +5401,10 @@ } } ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id)); + + if (driver_setup.dv == 0) + goto target_done; + inq0 = (*pbuf1) & 0x1F; /* Continue only for disks @@ -6222,7 +5428,7 @@ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; - iocmd.cmd = CMD_TestUnitReady; + iocmd.cmd = TEST_UNIT_READY; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6245,14 +5451,14 @@ "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, asc, ascq)); - if (skey == SK_UNIT_ATTENTION) + if (skey == UNIT_ATTENTION) notDone++; /* repeat */ - else if ((skey == SK_NOT_READY) && + else if ((skey == NOT_READY) && (asc == 0x04)&&(ascq == 0x01)) { /* wait then repeat */ mdelay (2000); notDone++; - } else if ((skey == SK_NOT_READY) && (asc == 0x3A)) { + } else if ((skey == NOT_READY) && (asc == 0x3A)) { /* no medium, try read test anyway */ notDone = 0; } else { @@ -6266,7 +5472,7 @@ goto target_done; } - iocmd.cmd = CMD_ReadBuffer; + iocmd.cmd = READ_BUFFER; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = 4; @@ -6314,11 +5520,11 @@ ddvprintk((MYIOC_s_INFO_FMT "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, asc, ascq)); - if (skey == SK_ILLEGAL_REQUEST) { + if (skey == ILLEGAL_REQUEST) { notDone = 0; - } else if (skey == SK_UNIT_ATTENTION) { + } else if (skey == UNIT_ATTENTION) { notDone++; /* repeat */ - } else if ((skey == SK_NOT_READY) && + } else if ((skey == NOT_READY) && (asc == 0x04)&&(ascq == 0x01)) { /* wait then repeat */ mdelay (2000); @@ -6373,14 +5579,14 @@ for (patt = 0; patt < 4; patt++) { ddvprintk(("Pattern %d\n", patt)); if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) { - iocmd.cmd = CMD_TestUnitReady; + iocmd.cmd = TEST_UNIT_READY; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; - iocmd.cmd = CMD_Release6; + iocmd.cmd = RELEASE; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6402,7 +5608,7 @@ repeat = 5; while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) { - iocmd.cmd = CMD_Reserve6; + iocmd.cmd = RESERVE; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6425,7 +5631,7 @@ ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", skey, asc, ascq)); - if ((skey == SK_NOT_READY) && (asc == 0x04)&& + if ((skey == NOT_READY) && (asc == 0x04)&& (ascq == 0x01)) { /* wait then repeat */ mdelay (2000); @@ -6444,7 +5650,7 @@ } mptscsih_fillbuf(pbuf1, sz, patt, 1); - iocmd.cmd = CMD_WriteBuffer; + iocmd.cmd = WRITE_BUFFER; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = sz; @@ -6485,10 +5691,10 @@ ddvprintk((MYIOC_s_INFO_FMT "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, hd->pLocal->sense[12], hd->pLocal->sense[13])); - if (skey == SK_UNIT_ATTENTION) { + if (skey == UNIT_ATTENTION) { patt = -1; continue; - } else if (skey == SK_ILLEGAL_REQUEST) { + } else if (skey == ILLEGAL_REQUEST) { if (iocmd.flags & MPT_ICFLAG_ECHO) { if (dataBufSize >= bufsize) { iocmd.flags &= ~MPT_ICFLAG_ECHO; @@ -6506,7 +5712,7 @@ } } - iocmd.cmd = CMD_ReadBuffer; + iocmd.cmd = READ_BUFFER; iocmd.data_dma = buf2_dma; iocmd.data = pbuf2; iocmd.size = sz; @@ -6581,7 +5787,7 @@ ddvprintk((MYIOC_s_INFO_FMT "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, hd->pLocal->sense[12], hd->pLocal->sense[13])); - if (skey == SK_UNIT_ATTENTION) { + if (skey == UNIT_ATTENTION) { patt = -1; continue; } @@ -6597,7 +5803,7 @@ target_done: if (iocmd.flags & MPT_ICFLAG_RESERVED) { - iocmd.cmd = CMD_Release6; + iocmd.cmd = RELEASE; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6619,8 +5825,11 @@ if ((cfg.hdr != NULL) && (retcode == 0)){ /* If disk, not U320, disable QAS */ - if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) + if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) { hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; + ddvprintk((MYIOC_s_NOTE_FMT + "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor)); + } dv.cmd = MPT_SAVE; mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); @@ -6649,8 +5858,8 @@ if (pDvBuf) pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma); - ddvtprintk((MYIOC_s_INFO_FMT "DV Done.\n", - ioc->name)); + ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n", + ioc->name, id)); return retcode; } @@ -6730,8 +5939,8 @@ dv->max.offset = offset; dv->max.factor = factor; dv->max.flags = negoFlags; - ddvprintk((" width %d, factor %x, offset %x flags %x\n", - width, factor, offset, negoFlags)); + ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n", + id, width, factor, offset, negoFlags)); break; case MPT_UPDATE_MAX: @@ -6749,8 +5958,8 @@ dv->now.width = dv->max.width; dv->now.offset = dv->max.offset; dv->now.factor = dv->max.factor; - ddvprintk(("width %d, factor %x, offset %x, flags %x\n", - dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags)); + ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags)); break; case MPT_SET_MAX: @@ -6766,14 +5975,15 @@ if (pPage1) { mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor, dv->now.offset, &val, &configuration, dv->now.flags); + dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration)); pPage1->RequestedParameters = le32_to_cpu(val); pPage1->Reserved = 0; pPage1->Configuration = le32_to_cpu(configuration); - } - ddvprintk(("width %d, factor %x, offset %x request %x, config %x\n", - dv->now.width, dv->now.factor, dv->now.offset, val, configuration)); + ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x request=%x configuration=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration)); break; case MPT_SET_MIN: @@ -6790,12 +6000,14 @@ if (pPage1) { mptscsih_setDevicePage1Flags (width, factor, offset, &val, &configuration, negoFlags); + dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", + id, width, factor, offset, negoFlags, val, configuration)); pPage1->RequestedParameters = le32_to_cpu(val); pPage1->Reserved = 0; pPage1->Configuration = le32_to_cpu(configuration); } - ddvprintk(("width %d, factor %x, offset %x request %x config %x\n", - width, factor, offset, val, configuration)); + ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n", + id, width, factor, offset, val, configuration, negoFlags)); break; case MPT_FALLBACK: @@ -6855,6 +6067,7 @@ factor = MPT_ASYNC; } dv->max.flags |= MPT_TARGET_NO_NEGO_QAS; + dv->max.flags &= ~MPT_TAPE_NEGO_IDP; dv->now.width = width; dv->now.offset = offset; @@ -6865,21 +6078,23 @@ if (pPage1) { mptscsih_setDevicePage1Flags (width, factor, offset, &val, &configuration, dv->now.flags); + dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x flags=%x request=%x config=%x\n", + id, width, offset, factor, dv->now.flags, val, configuration)); pPage1->RequestedParameters = le32_to_cpu(val); pPage1->Reserved = 0; pPage1->Configuration = le32_to_cpu(configuration); } - ddvprintk(("Finish: offset %d, factor %x, width %d, request %x config %x\n", - dv->now.offset, dv->now.factor, dv->now.width, val, configuration)); + ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n", + id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration)); break; case MPT_SAVE: ddvprintk((MYIOC_s_NOTE_FMT "Saving to Target structure: ", hd->ioc->name)); - ddvprintk(("offset %d, factor %x, width %d \n", - dv->now.offset, dv->now.factor, dv->now.width)); + ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags)); /* Save these values to target structures * or overwrite nvram (phys disks only). diff -Nru a/drivers/message/fusion/scsi3.h b/drivers/message/fusion/scsi3.h --- a/drivers/message/fusion/scsi3.h 2004-10-18 14:56:29 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,707 +0,0 @@ -/* - * linux/drivers/message/fusion/scsi3.h - * SCSI-3 definitions and macros. - * (Ultimately) SCSI-3 definitions; for now, inheriting - * SCSI-2 definitions. - * - * Copyright (c) 1996-2004 Steven J. Ralston - * Written By: Steven J. Ralston (19960517) - * (mailto:sjralston1@netscape.net) - * (mailto:mpt_linux_developer@lsil.com) - * - * $Id: scsi3.h,v 1.9 2002/02/27 18:45:02 sralston Exp $ - */ - -#ifndef SCSI3_H_INCLUDED -#define SCSI3_H_INCLUDED -/***************************************************************************/ - -/**************************************************************************** - * - * Includes - */ -#ifdef __KERNEL__ -#include -#else - #ifndef U_STUFF_DEFINED - #define U_STUFF_DEFINED - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned int u32; - #endif -#endif - -/**************************************************************************** - * - * Defines - */ - -/* - * SCSI Commands - */ -#define CMD_TestUnitReady 0x00 -#define CMD_RezeroUnit 0x01 /* direct-access devices */ -#define CMD_Rewind 0x01 /* sequential-access devices */ -#define CMD_RequestSense 0x03 -#define CMD_FormatUnit 0x04 -#define CMD_ReassignBlock 0x07 -#define CMD_Read6 0x08 -#define CMD_Write6 0x0A -#define CMD_WriteFilemark 0x10 -#define CMD_Space 0x11 -#define CMD_Inquiry 0x12 -#define CMD_ModeSelect6 0x15 -#define CMD_ModeSense6 0x1A -#define CMD_Reserve6 0x16 -#define CMD_Release6 0x17 -#define CMD_Erase 0x19 -#define CMD_StartStopUnit 0x1b /* direct-access devices */ -#define CMD_LoadUnload 0x1b /* sequential-access devices */ -#define CMD_ReceiveDiagnostic 0x1C -#define CMD_SendDiagnostic 0x1D -#define CMD_ReadCapacity 0x25 -#define CMD_Read10 0x28 -#define CMD_Write10 0x2A -#define CMD_WriteVerify 0x2E -#define CMD_Verify 0x2F -#define CMD_SynchronizeCache 0x35 -#define CMD_ReadDefectData 0x37 -#define CMD_WriteBuffer 0x3B -#define CMD_ReadBuffer 0x3C -#define CMD_ReadLong 0x3E -#define CMD_LogSelect 0x4C -#define CMD_LogSense 0x4D -#define CMD_ModeSelect10 0x55 -#define CMD_Reserve10 0x56 -#define CMD_Release10 0x57 -#define CMD_ModeSense10 0x5A -#define CMD_PersistReserveIn 0x5E -#define CMD_PersistReserveOut 0x5F -#define CMD_ReportLuns 0xA0 - -/* - * Control byte field - */ -#define CONTROL_BYTE_NACA_BIT 0x04 -#define CONTROL_BYTE_Flag_BIT 0x02 -#define CONTROL_BYTE_Link_BIT 0x01 - -/* - * SCSI Messages - */ -#define MSG_COMPLETE 0x00 -#define MSG_EXTENDED 0x01 -#define MSG_SAVE_POINTERS 0x02 -#define MSG_RESTORE_POINTERS 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_IDERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT 0x07 -#define MSG_NOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define MSG_LINKED_CMD_COMPLETE 0x0a -#define MSG_LCMD_COMPLETE_W_FLG 0x0b -#define MSG_BUS_DEVICE_RESET 0x0c -#define MSG_ABORT_TAG 0x0d -#define MSG_CLEAR_QUEUE 0x0e -#define MSG_INITIATE_RECOVERY 0x0f - -#define MSG_RELEASE_RECOVRY 0x10 -#define MSG_TERMINATE_IO 0x11 - -#define MSG_SIMPLE_QUEUE 0x20 -#define MSG_HEAD_OF_QUEUE 0x21 -#define MSG_ORDERED_QUEUE 0x22 -#define MSG_IGNORE_WIDE_RESIDUE 0x23 - -#define MSG_IDENTIFY 0x80 -#define MSG_IDENTIFY_W_DISC 0xc0 - -/* - * SCSI Phases - */ -#define PHS_DATA_OUT 0x00 -#define PHS_DATA_IN 0x01 -#define PHS_COMMAND 0x02 -#define PHS_STATUS 0x03 -#define PHS_MSG_OUT 0x06 -#define PHS_MSG_IN 0x07 - -/* - * Statuses - */ -#define STS_GOOD 0x00 -#define STS_CHECK_CONDITION 0x02 -#define STS_CONDITION_MET 0x04 -#define STS_BUSY 0x08 -#define STS_INTERMEDIATE 0x10 -#define STS_INTERMEDIATE_CONDITION_MET 0x14 -#define STS_RESERVATION_CONFLICT 0x18 -#define STS_COMMAND_TERMINATED 0x22 -#define STS_TASK_SET_FULL 0x28 -#define STS_QUEUE_FULL 0x28 -#define STS_ACA_ACTIVE 0x30 - -#define STS_VALID_MASK 0x3e - -#define SCSI_STATUS(x) ((x) & STS_VALID_MASK) - -/* - * SCSI QTag Types - */ -#define QTAG_SIMPLE 0x20 -#define QTAG_HEAD_OF_Q 0x21 -#define QTAG_ORDERED 0x22 - -/* - * SCSI Sense Key Definitons - */ -#define SK_NO_SENSE 0x00 -#define SK_RECOVERED_ERROR 0x01 -#define SK_NOT_READY 0x02 -#define SK_MEDIUM_ERROR 0x03 -#define SK_HARDWARE_ERROR 0x04 -#define SK_ILLEGAL_REQUEST 0x05 -#define SK_UNIT_ATTENTION 0x06 -#define SK_DATA_PROTECT 0x07 -#define SK_BLANK_CHECK 0x08 -#define SK_VENDOR_SPECIFIC 0x09 -#define SK_COPY_ABORTED 0x0a -#define SK_ABORTED_COMMAND 0x0b -#define SK_EQUAL 0x0c -#define SK_VOLUME_OVERFLOW 0x0d -#define SK_MISCOMPARE 0x0e -#define SK_RESERVED 0x0f - - - -#define SCSI_MAX_INQUIRY_BYTES 96 -#define SCSI_STD_INQUIRY_BYTES 36 - -#undef USE_SCSI_COMPLETE_INQDATA -/* - * Structure definition for SCSI Inquiry Data - * - * NOTE: The following structure is 96 bytes in size - * iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define"). - * If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef") - * then the following structure is only 36 bytes in size. - * THE CHOICE IS YOURS! - */ -typedef struct SCSI_Inquiry_Data -{ -#ifdef USE_SCSI_COMPLETE_INQDATA - u8 InqByte[SCSI_MAX_INQUIRY_BYTES]; -#else - u8 InqByte[SCSI_STD_INQUIRY_BYTES]; -#endif - -/* - * the following structure works only for little-endian (Intel, - * LSB first (1234) byte order) systems with 4-byte ints. - * - u32 Periph_Device_Type : 5, - Periph_Qualifier : 3, - Device_Type_Modifier : 7, - Removable_Media : 1, - ANSI_Version : 3, - ECMA_Version : 3, - ISO_Version : 2, - Response_Data_Format : 4, - reserved_0 : 3, - AERC : 1 ; - u32 Additional_Length : 8, - reserved_1 :16, - SftReset : 1, - CmdQue : 1, - reserved_2 : 1, - Linked : 1, - Sync : 1, - WBus16 : 1, - WBus32 : 1, - RelAdr : 1 ; - u8 Vendor_ID[8]; - u8 Product_ID[16]; - u8 Revision_Level [4]; -#ifdef USE_SCSI_COMPLETE_INQDATA - u8 Vendor_Specific[20]; - u8 reserved_3[40]; -#endif - * - */ - -} SCSI_Inquiry_Data_t; - -#define INQ_PERIPHINFO_BYTE 0 -#define INQ_Periph_Qualifier_MASK 0xe0 -#define INQ_Periph_Device_Type_MASK 0x1f - -#define INQ_Peripheral_Qualifier(inqp) \ - (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5) -#define INQ_Peripheral_Device_Type(inqp) \ - (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK) - - -#define INQ_DEVTYPEMOD_BYTE 1 -#define INQ_RMB_BIT 0x80 -#define INQ_Device_Type_Modifier_MASK 0x7f - -#define INQ_Removable_Medium(inqp) \ - (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT) -#define INQ_Device_Type_Modifier(inqp) \ - (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK) - - -#define INQ_VERSIONINFO_BYTE 2 -#define INQ_ISO_Version_MASK 0xc0 -#define INQ_ECMA_Version_MASK 0x38 -#define INQ_ANSI_Version_MASK 0x07 - -#define INQ_ISO_Version(inqp) \ - (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK) -#define INQ_ECMA_Version(inqp) \ - (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK) -#define INQ_ANSI_Version(inqp) \ - (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK) - - -#define INQ_BYTE3 3 -#define INQ_AERC_BIT 0x80 -#define INQ_TrmTsk_BIT 0x40 -#define INQ_NormACA_BIT 0x20 -#define INQ_RDF_MASK 0x0F - -#define INQ_AER_Capable(inqp) \ - (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT) -#define INQ_TrmTsk(inqp) \ - (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT) -#define INQ_NormACA(inqp) \ - (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT) -#define INQ_Response_Data_Format(inqp) \ - (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK) - - -#define INQ_CAPABILITY_BYTE 7 -#define INQ_RelAdr_BIT 0x80 -#define INQ_WBus32_BIT 0x40 -#define INQ_WBus16_BIT 0x20 -#define INQ_Sync_BIT 0x10 -#define INQ_Linked_BIT 0x08 - /* INQ_Reserved BIT 0x40 */ -#define INQ_CmdQue_BIT 0x02 -#define INQ_SftRe_BIT 0x01 - -#define IS_RelAdr_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT) -#define IS_WBus32_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT) -#define IS_WBus16_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT) -#define IS_Sync_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT) -#define IS_Linked_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT) -#define IS_CmdQue_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT) -#define IS_SftRe_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT) - -#define INQ_Width_BITS \ - (INQ_WBus32_BIT | INQ_WBus16_BIT) -#define IS_Wide_DEV(inqp) \ - (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS) - - -/* - * SCSI peripheral device types - */ -#define SCSI_TYPE_DAD 0x00 /* Direct Access Device */ -#define SCSI_TYPE_SAD 0x01 /* Sequential Access Device */ -#define SCSI_TYPE_TAPE SCSI_TYPE_SAD -#define SCSI_TYPE_PRT 0x02 /* Printer */ -#define SCSI_TYPE_PROC 0x03 /* Processor */ -#define SCSI_TYPE_WORM 0x04 -#define SCSI_TYPE_CDROM 0x05 -#define SCSI_TYPE_SCAN 0x06 /* Scanner */ -#define SCSI_TYPE_OPTICAL 0x07 /* Magneto/Optical */ -#define SCSI_TYPE_CHANGER 0x08 -#define SCSI_TYPE_COMM 0x09 /* Communications device */ -#define SCSI_TYPE_UNKNOWN 0x1f -#define SCSI_TYPE_UNCONFIGURED_LUN 0x7f - -#define SCSI_TYPE_MAX_KNOWN SCSI_TYPE_COMM - -/* - * Peripheral Qualifiers - */ -#define DEVICE_PRESENT 0x00 -#define LUN_NOT_PRESENT 0x01 -#define LUN_NOT_SUPPORTED 0x03 - -/* - * ANSI Versions - */ -#ifndef SCSI_1 -#define SCSI_1 0x01 -#endif -#ifndef SCSI_2 -#define SCSI_2 0x02 -#endif -#ifndef SCSI_3 -#define SCSI_3 0x03 -#endif - - -#define SCSI_MAX_SENSE_BYTES 255 -#define SCSI_STD_SENSE_BYTES 18 -#define SCSI_PAD_SENSE_BYTES (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES) - -#undef USE_SCSI_COMPLETE_SENSE -/* - * Structure definition for SCSI Sense Data - * - * NOTE: The following structure is 255 bytes in size - * iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define"). - * If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef") - * then the following structure is only 19 bytes in size. - * THE CHOICE IS YOURS! - * - */ -typedef struct SCSI_Sense_Data -{ -#ifdef USE_SCSI_COMPLETE_SENSE - u8 SenseByte[SCSI_MAX_SENSE_BYTES]; -#else - u8 SenseByte[SCSI_STD_SENSE_BYTES]; -#endif - -/* - * the following structure works only for little-endian (Intel, - * LSB first (1234) byte order) systems with 4-byte ints. - * - u8 Error_Code :4, // 0x00 - Error_Class :3, - Valid :1 - ; - u8 Segment_Number // 0x01 - ; - u8 Sense_Key :4, // 0x02 - Reserved :1, - Incorrect_Length_Indicator:1, - End_Of_Media :1, - Filemark :1 - ; - u8 Information_MSB; // 0x03 - u8 Information_Byte2; // 0x04 - u8 Information_Byte1; // 0x05 - u8 Information_LSB; // 0x06 - u8 Additional_Length; // 0x07 - - u32 Command_Specific_Information; // 0x08 - 0x0b - - u8 Additional_Sense_Code; // 0x0c - u8 Additional_Sense_Code_Qualifier; // 0x0d - u8 Field_Replaceable_Unit_Code; // 0x0e - u8 Illegal_Req_Bit_Pointer :3, // 0x0f - Illegal_Req_Bit_Valid :1, - Illegal_Req_Reserved :2, - Illegal_Req_Cmd_Data :1, - Sense_Key_Specific_Valid :1 - ; - u16 Sense_Key_Specific_Data; // 0x10 - 0x11 - -#ifdef USE_SCSI_COMPLETE_SENSE - u8 Additional_Sense_Data[SCSI_PAD_SENSE_BYTES]; -#else - u8 Additional_Sense_Data[1]; -#endif - * - */ - -} SCSI_Sense_Data_t; - - -#define SD_ERRCODE_BYTE 0 -#define SD_Valid_BIT 0x80 -#define SD_Error_Code_MASK 0x7f -#define SD_Valid(sdp) \ - (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT) -#define SD_Error_Code(sdp) \ - (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK) - - -#define SD_SEGNUM_BYTE 1 -#define SD_Segment_Number(sdp) (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE)) - - -#define SD_SENSEKEY_BYTE 2 -#define SD_Filemark_BIT 0x80 -#define SD_EOM_BIT 0x40 -#define SD_ILI_BIT 0x20 -#define SD_Sense_Key_MASK 0x0f -#define SD_Filemark(sdp) \ - (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT) -#define SD_EOM(sdp) \ - (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT) -#define SD_ILI(sdp) \ - (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT) -#define SD_Sense_Key(sdp) \ - (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK) - - -#define SD_INFO3_BYTE 3 -#define SD_INFO2_BYTE 4 -#define SD_INFO1_BYTE 5 -#define SD_INFO0_BYTE 6 -#define SD_Information3(sdp) (int)(*((u8*)(sdp)+SD_INFO3_BYTE)) -#define SD_Information2(sdp) (int)(*((u8*)(sdp)+SD_INFO2_BYTE)) -#define SD_Information1(sdp) (int)(*((u8*)(sdp)+SD_INFO1_BYTE)) -#define SD_Information0(sdp) (int)(*((u8*)(sdp)+SD_INFO0_BYTE)) - - -#define SD_ADDL_LEN_BYTE 7 -#define SD_Additional_Sense_Length(sdp) \ - (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE)) -#define SD_Addl_Sense_Len SD_Additional_Sense_Length - - -#define SD_CMD_SPECIFIC3_BYTE 8 -#define SD_CMD_SPECIFIC2_BYTE 9 -#define SD_CMD_SPECIFIC1_BYTE 10 -#define SD_CMD_SPECIFIC0_BYTE 11 -#define SD_Cmd_Specific_Info3(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE)) -#define SD_Cmd_Specific_Info2(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE)) -#define SD_Cmd_Specific_Info1(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE)) -#define SD_Cmd_Specific_Info0(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE)) - - -#define SD_ADDL_SENSE_CODE_BYTE 12 -#define SD_Additional_Sense_Code(sdp) \ - (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE)) -#define SD_Addl_Sense_Code SD_Additional_Sense_Code -#define SD_ASC SD_Additional_Sense_Code - - -#define SD_ADDL_SENSE_CODE_QUAL_BYTE 13 -#define SD_Additional_Sense_Code_Qualifier(sdp) \ - (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE)) -#define SD_Addl_Sense_Code_Qual SD_Additional_Sense_Code_Qualifier -#define SD_ASCQ SD_Additional_Sense_Code_Qualifier - - -#define SD_FIELD_REPL_UNIT_CODE_BYTE 14 -#define SD_Field_Replaceable_Unit_Code(sdp) \ - (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE)) -#define SD_Field_Repl_Unit_Code SD_Field_Replaceable_Unit_Code -#define SD_FRUC SD_Field_Replaceable_Unit_Code -#define SD_FRU SD_Field_Replaceable_Unit_Code - - -/* - * Sense-Key Specific offsets and macros. - */ -#define SD_SKS2_BYTE 15 -#define SD_SKS_Valid_BIT 0x80 -#define SD_SKS_Cmd_Data_BIT 0x40 -#define SD_SKS_Bit_Ptr_Valid_BIT 0x08 -#define SD_SKS_Bit_Ptr_MASK 0x07 -#define SD_SKS1_BYTE 16 -#define SD_SKS0_BYTE 17 -#define SD_Sense_Key_Specific_Valid(sdp) \ - (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT) -#define SD_SKS_Valid SD_Sense_Key_Specific_Valid -#define SD_SKS_CDB_Error(sdp) \ - (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT) -#define SD_Was_Illegal_Request SD_SKS_CDB_Error -#define SD_SKS_Bit_Pointer_Valid(sdp) \ - (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT) -#define SD_SKS_Bit_Pointer(sdp) \ - (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK) -#define SD_Field_Pointer(sdp) \ - (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \ - + *((u8*)(sdp)+SD_SKS0_BYTE) ) -#define SD_Bad_Byte SD_Field_Pointer -#define SD_Actual_Retry_Count SD_Field_Pointer -#define SD_Progress_Indication SD_Field_Pointer - -/* - * Mode Sense Write Protect Mask - */ -#define WRITE_PROTECT_MASK 0X80 - -/* - * Medium Type Codes - */ -#define OPTICAL_DEFAULT 0x00 -#define OPTICAL_READ_ONLY_MEDIUM 0x01 -#define OPTICAL_WRITE_ONCE_MEDIUM 0x02 -#define OPTICAL_READ_WRITABLE_MEDIUM 0x03 -#define OPTICAL_RO_OR_WO_MEDIUM 0x04 -#define OPTICAL_RO_OR_RW_MEDIUM 0x05 -#define OPTICAL_WO_OR_RW_MEDIUM 0x06 - - - -/* - * Structure definition for READ6, WRITE6 (6-byte CDB) - */ -typedef struct SCSI_RW6_CDB -{ - u32 OpCode :8, - LBA_HI :5, /* 5 MSBit's of the LBA */ - Lun :3, - LBA_MID :8, /* NOTE: total of 21 bits in LBA */ - LBA_LO :8 ; /* Max LBA = 0x001fffff */ - u8 BlockCount; - u8 Control; -} SCSI_RW6_t; - -#define MAX_RW6_LBA ((u32)0x001fffff) - -/* - * Structure definition for READ10, WRITE10 (10-byte CDB) - * - * NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for - * the ADP-92 DAC only. In the SCSI2 spec. this same bit is defined as a - * FUA (forced unit access) bit for READs and WRITEs. Since this driver - * does not use the FUA, this bit is defined as it is used by the ADP-92. - * Also, for READ CAPACITY, only the OpCode field is used. - */ -typedef struct SCSI_RW10_CDB -{ - u8 OpCode; - u8 Reserved1; - u32 LBA; - u8 Reserved2; - u16 BlockCount; - u8 Control; -} SCSI_RW10_t; - -#define PARITY_CHECK 0x08 /* parity check bit - byte[1], bit 3 */ - - /* - * Structure definition for data returned by READ CAPACITY cmd; - * READ CAPACITY data - */ - typedef struct READ_CAP_DATA - { - u32 MaxLBA; - u32 BlockBytes; - } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t; - - -/* - * Structure definition for FORMAT UNIT CDB (6-byte CDB) - */ -typedef struct _SCSI_FORMAT_UNIT -{ - u8 OpCode; - u8 Reserved1; - u8 VendorSpecific; - u16 Interleave; - u8 Control; -} SCSI_FORMAT_UNIT_t; - -/* - * Structure definition for REQUEST SENSE (6-byte CDB) - */ -typedef struct _SCSI_REQUEST_SENSE -{ - u8 OpCode; - u8 Reserved1; - u8 Reserved2; - u8 Reserved3; - u8 AllocLength; - u8 Control; -} SCSI_REQ_SENSE_t; - -/* - * Structure definition for REPORT LUNS (12-byte CDB) - */ -typedef struct _SCSI_REPORT_LUNS -{ - u8 OpCode; - u8 Reserved1[5]; - u32 AllocationLength; - u8 Reserved2; - u8 Control; -} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t; - - /* - * (per-level) LUN information bytes - */ -/* - * Following doesn't work on ARMCC compiler - * [apparently] because it pads every struct - * to be multiple of 4 bytes! - * So SCSI_LUN_LEVELS_t winds up being 16 - * bytes instead of 8! - * - typedef struct LUN_INFO - { - u8 AddrMethod_plus_LunOrBusNumber; - u8 LunOrTarget; - } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t; - - typedef struct LUN_LEVELS - { - SCSI_LUN_INFO_t LUN_0; - SCSI_LUN_INFO_t LUN_1; - SCSI_LUN_INFO_t LUN_2; - SCSI_LUN_INFO_t LUN_3; - } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t; -*/ - /* - * All 4 levels (8 bytes) of LUN information - */ - typedef struct LUN_LEVELS - { - u8 LVL1_AddrMethod_plus_LunOrBusNumber; - u8 LVL1_LunOrTarget; - u8 LVL2_AddrMethod_plus_LunOrBusNumber; - u8 LVL2_LunOrTarget; - u8 LVL3_AddrMethod_plus_LunOrBusNumber; - u8 LVL3_LunOrTarget; - u8 LVL4_AddrMethod_plus_LunOrBusNumber; - u8 LVL4_LunOrTarget; - } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t; - - /* - * Structure definition for data returned by REPORT LUNS cmd; - * LUN reporting parameter list format - */ - typedef struct LUN_REPORT - { - u32 LunListLength; - u32 Reserved; - SCSI_LUN_LEVELS_t LunInfo[1]; - } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t; - -/**************************************************************************** - * - * Externals - */ - -/**************************************************************************** - * - * Public Typedefs & Related Defines - */ - -/**************************************************************************** - * - * Macros (embedded, above) - */ - -/**************************************************************************** - * - * Public Variables - */ - -/**************************************************************************** - * - * Public Prototypes (module entry points) - */ - - -/***************************************************************************/ -#endif diff -Nru a/drivers/message/fusion/scsiops.c b/drivers/message/fusion/scsiops.c --- a/drivers/message/fusion/scsiops.c 2004-10-18 14:55:54 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,309 +0,0 @@ - -static const char *ScsiOpcodeString[256] = { - "TEST UNIT READY\0\01", /* 00h */ - "REWIND\0\002" - "\001REZERO UNIT", /* 01h */ - "\0\0", /* 02h */ - "REQUEST SENSE\0\01", /* 03h */ - "FORMAT UNIT\0\03" - "\001FORMAT MEDIUM\0" - "\002FORMAT", /* 04h */ - "READ BLOCK LIMITS\0\1", /* 05h */ - "\0\0", /* 06h */ - "REASSIGN BLOCKS\0\02" - "\010INITIALIZE ELEMENT STATUS", /* 07h */ - "READ(06)\0\04" - "\001READ\0" - "\003RECEIVE\0" - "\011GET MESSAGE(06)", /* 08h */ - "\0\0", /* 09h */ - "WRITE(06)\0\05" - "\001WRITE\0" - "\002PRINT\0" - "\003SEND(6)\0" - "\011SEND MESSAGE(06)", /* 0Ah */ - "SEEK(06)\0\02" - "\003SLEW AND PRINT", /* 0Bh */ - "\0\0", /* 0Ch */ - "\0\0", /* 0Dh */ - "\0\0", /* 0Eh */ - "READ REVERSE\0\01", /* 0Fh */ - "WRITE FILEMARKS\0\02" - "\003SYNCRONIZE BUFFER", /* 10h */ - "SPACE(6)\0\01", /* 11h */ - "INQUIRY\0\01", /* 12h */ - "VERIFY\0\01", /* 13h */ - "RECOVER BUFFERED DATA\0\01", /* 14h */ - "MODE SELECT(06)\0\01", /* 15h */ - "RESERVE(06)\0\02" - "\010RESERVE ELEMENT(06)", /* 16h */ - "RELEASE(06)\0\02" - "\010RELEASE ELEMENT(06)", /* 17h */ - "COPY\0\01", /* 18h */ - "ERASE\0\01", /* 19h */ - "MODE SENSE(06)\0\01", /* 1Ah */ - "STOP START UNIT\0\04" - "\001LOAD UNLOAD\0" - "\002STOP PRINT\0" - "\006SCAN\0\002", /* 1Bh */ - "RECEIVE DIAGNOSTIC RESULTS\0\01", /* 1Ch */ - "SEND DIAGNOSTIC\0\01", /* 1Dh */ - "PREVENT ALLOW MEDIUM REMOVAL\0\01", /* 1Eh */ - "\0\0", /* 1Fh */ - "\0\0", /* 20h */ - "\0\0", /* 21h */ - "\0\0", /* 22h */ - "READ FORMAT CAPACITIES\0\01", /* 23h */ - "SET WINDOW\0\01", /* 24h */ - "READ CAPACITY\0\03" - "\006GET WINDOW\0" - "\037FREAD CARD CAPACITY", /* 25h */ - "\0\0", /* 26h */ - "\0\0", /* 27h */ - "READ(10)\0\02" - "\011GET MESSAGE(10)", /* 28h */ - "READ GENERATION\0\01", /* 29h */ - "WRITE(10)\0\03" - "\011SEND(10)\0" - "\011SEND MESSAGE(10)", /* 2Ah */ - "SEEK(10)\0\03" - "LOCATE(10)\0" - "POSITION TO ELEMENT", /* 2Bh */ - "ERASE(10)\0\01", /* 2Ch */ - "READ UPDATED BLOCK\0\01", /* 2Dh */ - "WRITE AND VERIFY(10)\0\01", /* 2Eh */ - "VERIFY(10)\0\01", /* 2Fh */ - "SEARCH DATA HIGH(10)\0\01", /* 30h */ - "SEARCH DATA EQUAL(10)\0\02" - "OBJECT POSITION", /* 31h */ - "SEARCH DATA LOW(10)\0\01", /* 32h */ - "SET LIMITS(10)\0\01", /* 33h */ - "PRE-FETCH(10)\0\03" - "READ POSITION\0" - "GET DATA BUFFER STATUS", /* 34h */ - "SYNCHRONIZE CACHE(10)\0\01", /* 35h */ - "LOCK UNLOCK CACHE(10)\0\01", /* 36h */ - "READ DEFECT DATA(10)\0\01", /* 37h */ - "MEDIUM SCAN\0\01", /* 38h */ - "COMPARE\0\01", /* 39h */ - "COPY AND VERIFY\0\01", /* 3Ah */ - "WRITE BUFFER\0\01", /* 3Bh */ - "READ BUFFER\0\01", /* 3Ch */ - "UPDATE BLOCK\0\01", /* 3Dh */ - "READ LONG\0\01", /* 3Eh */ - "WRITE LONG\0\01", /* 3Fh */ - "CHANGE DEFINITION\0\01", /* 40h */ - "WRITE SAME(10)\0\01", /* 41h */ - "READ SUB-CHANNEL\0\01", /* 42h */ - "READ TOC/PMA/ATIP\0\01", /* 43h */ - "REPORT DENSITY SUPPORT\0\01", /* 44h */ - "READ HEADER\0\01", /* 44h */ - "PLAY AUDIO(10)\0\01", /* 45h */ - "GET CONFIGURATION\0\01", /* 46h */ - "PLAY AUDIO MSF\0\01", /* 47h */ - "PLAY AUDIO TRACK INDEX\0\01", /* 48h */ - "PLAY TRACK RELATIVE(10)\0\01", /* 49h */ - "GET EVENT STATUS NOTIFICATION\0\01", /* 4Ah */ - "PAUSE/RESUME\0\01", /* 4Bh */ - "LOG SELECT\0\01", /* 4Ch */ - "LOG SENSE\0\01", /* 4Dh */ - "STOP PLAY/SCAN\0\01", /* 4Eh */ - "\0\0", /* 4Fh */ - "XDWRITE(10)\0\01", /* 50h */ - "XPWRITE(10)\0\02" - "READ DISC INFORMATION", /* 51h */ - "XDREAD(10)\0\01" - "READ TRACK INFORMATION", /* 52h */ - "RESERVE TRACK\0\01", /* 53h */ - "SEND OPC INFORMATION\0\01", /* 54h */ - "MODE SELECT(10)\0\01", /* 55h */ - "RESERVE(10)\0\02" - "RESERVE ELEMENT(10)", /* 56h */ - "RELEASE(10)\0\02" - "RELEASE ELEMENT(10)", /* 57h */ - "REPAIR TRACK\0\01", /* 58h */ - "READ MASTER CUE\0\01", /* 59h */ - "MODE SENSE(10)\0\01", /* 5Ah */ - "CLOSE TRACK/SESSION\0\01", /* 5Bh */ - "READ BUFFER CAPACITY\0\01", /* 5Ch */ - "SEND CUE SHEET\0\01", /* 5Dh */ - "PERSISTENT RESERVE IN\0\01", /* 5Eh */ - "PERSISTENT RESERVE OUT\0\01", /* 5Fh */ - "\0\0", /* 60h */ - "\0\0", /* 61h */ - "\0\0", /* 62h */ - "\0\0", /* 63h */ - "\0\0", /* 64h */ - "\0\0", /* 65h */ - "\0\0", /* 66h */ - "\0\0", /* 67h */ - "\0\0", /* 68h */ - "\0\0", /* 69h */ - "\0\0", /* 6Ah */ - "\0\0", /* 6Bh */ - "\0\0", /* 6Ch */ - "\0\0", /* 6Dh */ - "\0\0", /* 6Eh */ - "\0\0", /* 6Fh */ - "\0\0", /* 70h */ - "\0\0", /* 71h */ - "\0\0", /* 72h */ - "\0\0", /* 73h */ - "\0\0", /* 74h */ - "\0\0", /* 75h */ - "\0\0", /* 76h */ - "\0\0", /* 77h */ - "\0\0", /* 78h */ - "\0\0", /* 79h */ - "\0\0", /* 7Ah */ - "\0\0", /* 7Bh */ - "\0\0", /* 7Ch */ - "\0\0", /* 7Eh */ - "\0\0", /* 7Eh */ - "\0\0", /* 7Fh */ - "XDWRITE EXTENDED(16)\0\01", /* 80h */ - "REBUILD(16)\0\01", /* 81h */ - "REGENERATE(16)\0\01", /* 82h */ - "EXTENDED COPY\0\01", /* 83h */ - "RECEIVE COPY RESULTS\0\01", /* 84h */ - "ACCESS CONTROL IN [proposed]\0\01", /* 86h */ - "ACCESS CONTROL OUT [proposed]\0\01", /* 87h */ - "READ(16)\0\01", /* 88h */ - "DEVICE LOCKS [proposed]\0\01", /* 89h */ - "WRITE(16)\0\01", /* 8Ah */ - "\0\0", /* 8Bh */ - "READ ATTRIBUTES [proposed]\0\01", /* 8Ch */ - "WRITE ATTRIBUTES [proposed]\0\01", /* 8Dh */ - "WRITE AND VERIFY(16)\0\01", /* 8Eh */ - "VERIFY(16)\0\01", /* 8Fh */ - "PRE-FETCH(16)\0\01", /* 90h */ - "SYNCHRONIZE CACHE(16)\0\02" - "SPACE(16) [1]", /* 91h */ - "LOCK UNLOCK CACHE(16)\0\02" - "LOCATE(16) [1]", /* 92h */ - "WRITE SAME(16)\0\01", /* 93h */ - "[usage proposed by SCSI Socket Services project]\0\01", /* 94h */ - "[usage proposed by SCSI Socket Services project]\0\01", /* 95h */ - "[usage proposed by SCSI Socket Services project]\0\01", /* 96h */ - "[usage proposed by SCSI Socket Services project]\0\01", /* 97h */ - "MARGIN CONTROL [proposed]\0\01", /* 98h */ - "\0\0", /* 99h */ - "\0\0", /* 9Ah */ - "\0\0", /* 9Bh */ - "\0\0", /* 9Ch */ - "\0\0", /* 9Dh */ - "SERVICE ACTION IN [proposed]\0\01", /* 9Eh */ - "SERVICE ACTION OUT [proposed]\0\01", /* 9Fh */ - "REPORT LUNS\0\01", /* A0h */ - "BLANK\0\01", /* A1h */ - "SEND EVENT\0\01", /* A2h */ - "MAINTENANCE (IN)\0\02" - "SEND KEY", /* A3h */ - "MAINTENANCE (OUT)\0\02" - "REPORT KEY", /* A4h */ - "MOVE MEDIUM\0\02" - "PLAY AUDIO(12)", /* A5h */ - "EXCHANGE MEDIUM\0\02" - "LOAD/UNLOAD C/DVD", /* A6h */ - "MOVE MEDIUM ATTACHED\0\02" - "SET READ AHEAD\0\01", /* A7h */ - "READ(12)\0\02" - "GET MESSAGE(12)", /* A8h */ - "PLAY TRACK RELATIVE(12)\0\01", /* A9h */ - "WRITE(12)\0\02" - "SEND MESSAGE(12)", /* AAh */ - "\0\0", /* ABh */ - "ERASE(12)\0\02" - "GET PERFORMANCE", /* ACh */ - "READ DVD STRUCTURE\0\01", /* ADh */ - "WRITE AND VERIFY(12)\0\01", /* AEh */ - "VERIFY(12)\0\01", /* AFh */ - "SEARCH DATA HIGH(12)\0\01", /* B0h */ - "SEARCH DATA EQUAL(12)\0\01", /* B1h */ - "SEARCH DATA LOW(12)\0\01", /* B2h */ - "SET LIMITS(12)\0\01", /* B3h */ - "READ ELEMENT STATUS ATTACHED\0\01", /* B4h */ - "REQUEST VOLUME ELEMENT ADDRESS\0\01", /* B5h */ - "SEND VOLUME TAG\0\02" - "SET STREAMING", /* B6h */ - "READ DEFECT DATA(12)\0\01", /* B7h */ - "READ ELEMENT STATUS\0\01", /* B8h */ - "READ CD MSF\0\01", /* B9h */ - "REDUNDANCY GROUP (IN)\0\02" - "SCAN", /* BAh */ - "REDUNDANCY GROUP (OUT)\0\02" - "SET CD-ROM SPEED", /* BBh */ - "SPARE (IN)\0\02" - "PLAY CD", /* BCh */ - "SPARE (OUT)\0\02" - "MECHANISM STATUS", /* BDh */ - "VOLUME SET (IN)\0\02" - "READ CD", /* BEh */ - "VOLUME SET (OUT)\0\0\02" - "SEND DVD STRUCTURE", /* BFh */ - "\0\0", /* C0h */ - "\0\0", /* C1h */ - "\0\0", /* C2h */ - "\0\0", /* C3h */ - "\0\0", /* C4h */ - "\0\0", /* C5h */ - "\0\0", /* C6h */ - "\0\0", /* C7h */ - "\0\0", /* C8h */ - "\0\0", /* C9h */ - "\0\0", /* CAh */ - "\0\0", /* CBh */ - "\0\0", /* CCh */ - "\0\0", /* CDh */ - "\0\0", /* CEh */ - "\0\0", /* CFh */ - "\0\0", /* D0h */ - "\0\0", /* D1h */ - "\0\0", /* D2h */ - "\0\0", /* D3h */ - "\0\0", /* D4h */ - "\0\0", /* D5h */ - "\0\0", /* D6h */ - "\0\0", /* D7h */ - "\0\0", /* D8h */ - "\0\0", /* D9h */ - "\0\0", /* DAh */ - "\0\0", /* DBh */ - "\0\0", /* DCh */ - "\0\0", /* DEh */ - "\0\0", /* DEh */ - "\0\0", /* DFh */ - "\0\0", /* E0h */ - "\0\0", /* E1h */ - "\0\0", /* E2h */ - "\0\0", /* E3h */ - "\0\0", /* E4h */ - "\0\0", /* E5h */ - "\0\0", /* E6h */ - "\0\0", /* E7h */ - "\0\0", /* E8h */ - "\0\0", /* E9h */ - "\0\0", /* EAh */ - "\0\0", /* EBh */ - "\0\0", /* ECh */ - "\0\0", /* EDh */ - "\0\0", /* EEh */ - "\0\0", /* EFh */ - "\0\0", /* F0h */ - "\0\0", /* F1h */ - "\0\0", /* F2h */ - "\0\0", /* F3h */ - "\0\0", /* F4h */ - "\0\0", /* F5h */ - "\0\0", /* F6h */ - "\0\0", /* F7h */ - "\0\0", /* F8h */ - "\0\0", /* F9h */ - "\0\0", /* FAh */ - "\0\0", /* FBh */ - "\0\0", /* FEh */ - "\0\0", /* FEh */ - "\0\0", /* FEh */ - "\0\0" /* FFh */ -}; - diff -Nru a/drivers/message/i2o/Makefile b/drivers/message/i2o/Makefile --- a/drivers/message/i2o/Makefile 2004-10-18 14:56:48 -07:00 +++ b/drivers/message/i2o/Makefile 2004-10-18 14:56:48 -07:00 @@ -5,6 +5,7 @@ # In the future, some of these should be built conditionally. # +i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o obj-$(CONFIG_I2O) += i2o_core.o obj-$(CONFIG_I2O_CONFIG)+= i2o_config.o obj-$(CONFIG_I2O_BLOCK) += i2o_block.o diff -Nru a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/message/i2o/debug.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,571 @@ +#include +#include +#include +#include +#include + +static int verbose; +extern struct i2o_driver **i2o_drivers; +extern unsigned int i2o_max_drivers; +static void i2o_report_util_cmd(u8 cmd); +static void i2o_report_exec_cmd(u8 cmd); +void i2o_report_fail_status(u8 req_status, u32 * msg); +void i2o_report_common_status(u8 req_status); +static void i2o_report_common_dsc(u16 detailed_status); + +void i2o_dump_status_block(i2o_status_block * sb) +{ + pr_debug("Organization ID: %d\n", sb->org_id); + pr_debug("IOP ID: %d\n", sb->iop_id); + pr_debug("Host Unit ID: %d\n", sb->host_unit_id); + pr_debug("Segment Number: %d\n", sb->segment_number); + pr_debug("I2O Version: %d\n", sb->i2o_version); + pr_debug("IOP State: %d\n", sb->iop_state); + pr_debug("Messanger Type: %d\n", sb->msg_type); + pr_debug("Inbound Frame Size: %d\n", sb->inbound_frame_size); + pr_debug("Init Code: %d\n", sb->init_code); + pr_debug("Max Inbound MFrames: %d\n", sb->max_inbound_frames); + pr_debug("Current Inbound MFrames: %d\n", sb->cur_inbound_frames); + pr_debug("Max Outbound MFrames: %d\n", sb->max_outbound_frames); + pr_debug("Product ID String: %s\n", sb->product_id); + pr_debug("Expected LCT Size: %d\n", sb->expected_lct_size); + pr_debug("IOP Capabilities: %d\n", sb->iop_capabilities); + pr_debug("Desired Private MemSize: %d\n", sb->desired_mem_size); + pr_debug("Current Private MemSize: %d\n", sb->current_mem_size); + pr_debug("Current Private MemBase: %d\n", sb->current_mem_base); + pr_debug("Desired Private IO Size: %d\n", sb->desired_io_size); + pr_debug("Current Private IO Size: %d\n", sb->current_io_size); + pr_debug("Current Private IO Base: %d\n", sb->current_io_base); +}; + +/* + * Used for error reporting/debugging purposes. + * Report Cmd name, Request status, Detailed Status. + */ +void i2o_report_status(const char *severity, const char *str, + struct i2o_message *m) +{ + u32 *msg = (u32 *) m; + u8 cmd = (msg[1] >> 24) & 0xFF; + u8 req_status = (msg[4] >> 24) & 0xFF; + u16 detailed_status = msg[4] & 0xFFFF; + //struct i2o_driver *h = i2o_drivers[msg[2] & (i2o_max_drivers-1)]; + + if (cmd == I2O_CMD_UTIL_EVT_REGISTER) + return; // No status in this reply + + printk("%s%s: ", severity, str); + + if (cmd < 0x1F) // Utility cmd + i2o_report_util_cmd(cmd); + + else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd + i2o_report_exec_cmd(cmd); + else + printk("Cmd = %0#2x, ", cmd); // Other cmds + + if (msg[0] & MSG_FAIL) { + i2o_report_fail_status(req_status, msg); + return; + } + + i2o_report_common_status(req_status); + + if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF)) + i2o_report_common_dsc(detailed_status); + else + printk(" / DetailedStatus = %0#4x.\n", detailed_status); +} + +/* Used to dump a message to syslog during debugging */ +void i2o_dump_message(struct i2o_message *m) +{ +#ifdef DEBUG + u32 *msg = (u32 *) m; + int i; + printk(KERN_INFO "Dumping I2O message size %d @ %p\n", + msg[0] >> 16 & 0xffff, msg); + for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++) + printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]); +#endif +} + +/** + * i2o_report_controller_unit - print information about a tid + * @c: controller + * @d: device + * + * Dump an information block associated with a given unit (TID). The + * tables are read and a block of text is output to printk that is + * formatted intended for the user. + */ + +void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) +{ + char buf[64]; + char str[22]; + int ret; + + if (verbose == 0) + return; + + printk(KERN_INFO "Target ID %03x.\n", d->lct_data.tid); + if ((ret = i2o_parm_field_get(d, 0xF100, 3, buf, 16)) >= 0) { + buf[16] = 0; + printk(KERN_INFO " Vendor: %s\n", buf); + } + if ((ret = i2o_parm_field_get(d, 0xF100, 4, buf, 16)) >= 0) { + buf[16] = 0; + printk(KERN_INFO " Device: %s\n", buf); + } + if (i2o_parm_field_get(d, 0xF100, 5, buf, 16) >= 0) { + buf[16] = 0; + printk(KERN_INFO " Description: %s\n", buf); + } + if ((ret = i2o_parm_field_get(d, 0xF100, 6, buf, 8)) >= 0) { + buf[8] = 0; + printk(KERN_INFO " Rev: %s\n", buf); + } + + printk(KERN_INFO " Class: "); + //sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id)); + printk("%s\n", str); + + printk(KERN_INFO " Subclass: 0x%04X\n", d->lct_data.sub_class); + printk(KERN_INFO " Flags: "); + + if (d->lct_data.device_flags & (1 << 0)) + printk("C"); // ConfigDialog requested + if (d->lct_data.device_flags & (1 << 1)) + printk("U"); // Multi-user capable + if (!(d->lct_data.device_flags & (1 << 4))) + printk("P"); // Peer service enabled! + if (!(d->lct_data.device_flags & (1 << 5))) + printk("M"); // Mgmt service enabled! + printk("\n"); +} + +/* +MODULE_PARM(verbose, "i"); +MODULE_PARM_DESC(verbose, "Verbose diagnostics"); +*/ +/* + * Used for error reporting/debugging purposes. + * Following fail status are common to all classes. + * The preserved message must be handled in the reply handler. + */ +void i2o_report_fail_status(u8 req_status, u32 * msg) +{ + static char *FAIL_STATUS[] = { + "0x80", /* not used */ + "SERVICE_SUSPENDED", /* 0x81 */ + "SERVICE_TERMINATED", /* 0x82 */ + "CONGESTION", + "FAILURE", + "STATE_ERROR", + "TIME_OUT", + "ROUTING_FAILURE", + "INVALID_VERSION", + "INVALID_OFFSET", + "INVALID_MSG_FLAGS", + "FRAME_TOO_SMALL", + "FRAME_TOO_LARGE", + "INVALID_TARGET_ID", + "INVALID_INITIATOR_ID", + "INVALID_INITIATOR_CONTEX", /* 0x8F */ + "UNKNOWN_FAILURE" /* 0xFF */ + }; + + if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE) + printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status); + else + printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]); + + /* Dump some details */ + + printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n", + (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); + printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n", + (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); + printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n", + msg[5] >> 16, msg[5] & 0xFFF); + + printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF); + if (msg[4] & (1 << 16)) + printk("(FormatError), " + "this msg can never be delivered/processed.\n"); + if (msg[4] & (1 << 17)) + printk("(PathError), " + "this msg can no longer be delivered/processed.\n"); + if (msg[4] & (1 << 18)) + printk("(PathState), " + "the system state does not allow delivery.\n"); + if (msg[4] & (1 << 19)) + printk("(Congestion), resources temporarily not available;" + "do not retry immediately.\n"); +} + +/* + * Used for error reporting/debugging purposes. + * Following reply status are common to all classes. + */ +void i2o_report_common_status(u8 req_status) +{ + static char *REPLY_STATUS[] = { + "SUCCESS", + "ABORT_DIRTY", + "ABORT_NO_DATA_TRANSFER", + "ABORT_PARTIAL_TRANSFER", + "ERROR_DIRTY", + "ERROR_NO_DATA_TRANSFER", + "ERROR_PARTIAL_TRANSFER", + "PROCESS_ABORT_DIRTY", + "PROCESS_ABORT_NO_DATA_TRANSFER", + "PROCESS_ABORT_PARTIAL_TRANSFER", + "TRANSACTION_ERROR", + "PROGRESS_REPORT" + }; + + if (req_status >= ARRAY_SIZE(REPLY_STATUS)) + printk("RequestStatus = %0#2x", req_status); + else + printk("%s", REPLY_STATUS[req_status]); +} + +/* + * Used for error reporting/debugging purposes. + * Following detailed status are valid for executive class, + * utility class, DDM class and for transaction error replies. + */ +static void i2o_report_common_dsc(u16 detailed_status) +{ + static char *COMMON_DSC[] = { + "SUCCESS", + "0x01", // not used + "BAD_KEY", + "TCL_ERROR", + "REPLY_BUFFER_FULL", + "NO_SUCH_PAGE", + "INSUFFICIENT_RESOURCE_SOFT", + "INSUFFICIENT_RESOURCE_HARD", + "0x08", // not used + "CHAIN_BUFFER_TOO_LARGE", + "UNSUPPORTED_FUNCTION", + "DEVICE_LOCKED", + "DEVICE_RESET", + "INAPPROPRIATE_FUNCTION", + "INVALID_INITIATOR_ADDRESS", + "INVALID_MESSAGE_FLAGS", + "INVALID_OFFSET", + "INVALID_PARAMETER", + "INVALID_REQUEST", + "INVALID_TARGET_ADDRESS", + "MESSAGE_TOO_LARGE", + "MESSAGE_TOO_SMALL", + "MISSING_PARAMETER", + "TIMEOUT", + "UNKNOWN_ERROR", + "UNKNOWN_FUNCTION", + "UNSUPPORTED_VERSION", + "DEVICE_BUSY", + "DEVICE_NOT_AVAILABLE" + }; + + if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE) + printk(" / DetailedStatus = %0#4x.\n", detailed_status); + else + printk(" / %s.\n", COMMON_DSC[detailed_status]); +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_util_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_UTIL_NOP: + printk("UTIL_NOP, "); + break; + case I2O_CMD_UTIL_ABORT: + printk("UTIL_ABORT, "); + break; + case I2O_CMD_UTIL_CLAIM: + printk("UTIL_CLAIM, "); + break; + case I2O_CMD_UTIL_RELEASE: + printk("UTIL_CLAIM_RELEASE, "); + break; + case I2O_CMD_UTIL_CONFIG_DIALOG: + printk("UTIL_CONFIG_DIALOG, "); + break; + case I2O_CMD_UTIL_DEVICE_RESERVE: + printk("UTIL_DEVICE_RESERVE, "); + break; + case I2O_CMD_UTIL_DEVICE_RELEASE: + printk("UTIL_DEVICE_RELEASE, "); + break; + case I2O_CMD_UTIL_EVT_ACK: + printk("UTIL_EVENT_ACKNOWLEDGE, "); + break; + case I2O_CMD_UTIL_EVT_REGISTER: + printk("UTIL_EVENT_REGISTER, "); + break; + case I2O_CMD_UTIL_LOCK: + printk("UTIL_LOCK, "); + break; + case I2O_CMD_UTIL_LOCK_RELEASE: + printk("UTIL_LOCK_RELEASE, "); + break; + case I2O_CMD_UTIL_PARAMS_GET: + printk("UTIL_PARAMS_GET, "); + break; + case I2O_CMD_UTIL_PARAMS_SET: + printk("UTIL_PARAMS_SET, "); + break; + case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY: + printk("UTIL_REPLY_FAULT_NOTIFY, "); + break; + default: + printk("Cmd = %0#2x, ", cmd); + } +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_exec_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_ADAPTER_ASSIGN: + printk("EXEC_ADAPTER_ASSIGN, "); + break; + case I2O_CMD_ADAPTER_READ: + printk("EXEC_ADAPTER_READ, "); + break; + case I2O_CMD_ADAPTER_RELEASE: + printk("EXEC_ADAPTER_RELEASE, "); + break; + case I2O_CMD_BIOS_INFO_SET: + printk("EXEC_BIOS_INFO_SET, "); + break; + case I2O_CMD_BOOT_DEVICE_SET: + printk("EXEC_BOOT_DEVICE_SET, "); + break; + case I2O_CMD_CONFIG_VALIDATE: + printk("EXEC_CONFIG_VALIDATE, "); + break; + case I2O_CMD_CONN_SETUP: + printk("EXEC_CONN_SETUP, "); + break; + case I2O_CMD_DDM_DESTROY: + printk("EXEC_DDM_DESTROY, "); + break; + case I2O_CMD_DDM_ENABLE: + printk("EXEC_DDM_ENABLE, "); + break; + case I2O_CMD_DDM_QUIESCE: + printk("EXEC_DDM_QUIESCE, "); + break; + case I2O_CMD_DDM_RESET: + printk("EXEC_DDM_RESET, "); + break; + case I2O_CMD_DDM_SUSPEND: + printk("EXEC_DDM_SUSPEND, "); + break; + case I2O_CMD_DEVICE_ASSIGN: + printk("EXEC_DEVICE_ASSIGN, "); + break; + case I2O_CMD_DEVICE_RELEASE: + printk("EXEC_DEVICE_RELEASE, "); + break; + case I2O_CMD_HRT_GET: + printk("EXEC_HRT_GET, "); + break; + case I2O_CMD_ADAPTER_CLEAR: + printk("EXEC_IOP_CLEAR, "); + break; + case I2O_CMD_ADAPTER_CONNECT: + printk("EXEC_IOP_CONNECT, "); + break; + case I2O_CMD_ADAPTER_RESET: + printk("EXEC_IOP_RESET, "); + break; + case I2O_CMD_LCT_NOTIFY: + printk("EXEC_LCT_NOTIFY, "); + break; + case I2O_CMD_OUTBOUND_INIT: + printk("EXEC_OUTBOUND_INIT, "); + break; + case I2O_CMD_PATH_ENABLE: + printk("EXEC_PATH_ENABLE, "); + break; + case I2O_CMD_PATH_QUIESCE: + printk("EXEC_PATH_QUIESCE, "); + break; + case I2O_CMD_PATH_RESET: + printk("EXEC_PATH_RESET, "); + break; + case I2O_CMD_STATIC_MF_CREATE: + printk("EXEC_STATIC_MF_CREATE, "); + break; + case I2O_CMD_STATIC_MF_RELEASE: + printk("EXEC_STATIC_MF_RELEASE, "); + break; + case I2O_CMD_STATUS_GET: + printk("EXEC_STATUS_GET, "); + break; + case I2O_CMD_SW_DOWNLOAD: + printk("EXEC_SW_DOWNLOAD, "); + break; + case I2O_CMD_SW_UPLOAD: + printk("EXEC_SW_UPLOAD, "); + break; + case I2O_CMD_SW_REMOVE: + printk("EXEC_SW_REMOVE, "); + break; + case I2O_CMD_SYS_ENABLE: + printk("EXEC_SYS_ENABLE, "); + break; + case I2O_CMD_SYS_MODIFY: + printk("EXEC_SYS_MODIFY, "); + break; + case I2O_CMD_SYS_QUIESCE: + printk("EXEC_SYS_QUIESCE, "); + break; + case I2O_CMD_SYS_TAB_SET: + printk("EXEC_SYS_TAB_SET, "); + break; + default: + printk("Cmd = %#02x, ", cmd); + } +} + +void i2o_debug_state(struct i2o_controller *c) +{ + printk(KERN_INFO "%s: State = ", c->name); + switch (((i2o_status_block *) c->status_block.virt)->iop_state) { + case 0x01: + printk("INIT\n"); + break; + case 0x02: + printk("RESET\n"); + break; + case 0x04: + printk("HOLD\n"); + break; + case 0x05: + printk("READY\n"); + break; + case 0x08: + printk("OPERATIONAL\n"); + break; + case 0x10: + printk("FAILED\n"); + break; + case 0x11: + printk("FAULTED\n"); + break; + default: + printk("%x (unknown !!)\n", + ((i2o_status_block *) c->status_block.virt)->iop_state); + } +}; + +void i2o_systab_debug(struct i2o_sys_tbl *sys_tbl) +{ + u32 *table; + int count; + u32 size; + + table = (u32 *) sys_tbl; + size = sizeof(struct i2o_sys_tbl) + sys_tbl->num_entries + * sizeof(struct i2o_sys_tbl_entry); + + for (count = 0; count < (size >> 2); count++) + printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]); +} + +void i2o_dump_hrt(struct i2o_controller *c) +{ + u32 *rows = (u32 *) c->hrt.virt; + u8 *p = (u8 *) c->hrt.virt; + u8 *d; + int count; + int length; + int i; + int state; + + if (p[3] != 0) { + printk(KERN_ERR + "%s: HRT table for controller is too new a version.\n", + c->name); + return; + } + + count = p[0] | (p[1] << 8); + length = p[2]; + + printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n", + c->name, count, length << 2); + + rows += 2; + + for (i = 0; i < count; i++) { + printk(KERN_INFO "Adapter %08X: ", rows[0]); + p = (u8 *) (rows + 1); + d = (u8 *) (rows + 2); + state = p[1] << 8 | p[0]; + + printk("TID %04X:[", state & 0xFFF); + state >>= 12; + if (state & (1 << 0)) + printk("H"); /* Hidden */ + if (state & (1 << 2)) { + printk("P"); /* Present */ + if (state & (1 << 1)) + printk("C"); /* Controlled */ + } + if (state > 9) + printk("*"); /* Hard */ + + printk("]:"); + + switch (p[3] & 0xFFFF) { + case 0: + /* Adapter private bus - easy */ + printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", + p[2], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + case 1: + /* ISA bus */ + printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", + p[2], d[2], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + + case 2: /* EISA bus */ + printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + + case 3: /* MCA bus */ + printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + + case 4: /* PCI bus */ + printk("PCI %d: Bus %d Device %d Function %d", + p[2], d[2], d[1], d[0]); + break; + + case 0x80: /* Other */ + default: + printk("Unsupported bus type."); + break; + } + printk("\n"); + rows += length; + } +} + +EXPORT_SYMBOL(i2o_dump_status_block); +EXPORT_SYMBOL(i2o_dump_message); diff -Nru a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/message/i2o/device.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,674 @@ +/* + * Functions to handle I2O devices + * + * Copyright (C) 2004 Markus Lidel + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Fixes/additions: + * Markus Lidel + * initial version. + */ + +#include +#include + +/* Exec OSM functions */ +extern struct bus_type i2o_bus_type; + +/** + * i2o_device_issue_claim - claim or release a device + * @dev: I2O device to claim or release + * @cmd: claim or release command + * @type: type of claim + * + * Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent + * is set by cmd. dev is the I2O device which should be claim or + * released and the type is the claim type (see the I2O spec). + * + * Returs 0 on success or negative error code on failure. + */ +static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, + u32 type) +{ + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]); + writel(type, &msg->body[0]); + + return i2o_msg_post_wait(dev->iop, m, 60); +}; + +/** + * i2o_device_claim - claim a device for use by an OSM + * @dev: I2O device to claim + * @drv: I2O driver which wants to claim the device + * + * Do the leg work to assign a device to a given OSM. If the claim succeed + * the owner of the rimary. If the attempt fails a negative errno code + * is returned. On success zero is returned. + */ +int i2o_device_claim(struct i2o_device *dev) +{ + int rc = 0; + + down(&dev->lock); + + rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY); + if (!rc) + pr_debug("claim of device %d succeded\n", dev->lct_data.tid); + else + pr_debug("claim of device %d failed %d\n", dev->lct_data.tid, + rc); + + up(&dev->lock); + + return rc; +}; + +/** + * i2o_device_claim_release - release a device that the OSM is using + * @dev: device to release + * @drv: driver which claimed the device + * + * Drop a claim by an OSM on a given I2O device. + * + * AC - some devices seem to want to refuse an unclaim until they have + * finished internal processing. It makes sense since you don't want a + * new device to go reconfiguring the entire system until you are done. + * Thus we are prepared to wait briefly. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_device_claim_release(struct i2o_device *dev) +{ + int tries; + int rc = 0; + + down(&dev->lock); + + /* + * If the controller takes a nonblocking approach to + * releases we have to sleep/poll for a few times. + */ + for (tries = 0; tries < 10; tries++) { + rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE, + I2O_CLAIM_PRIMARY); + if (!rc) + break; + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } + + if (!rc) + pr_debug("claim release of device %d succeded\n", + dev->lct_data.tid); + else + pr_debug("claim release of device %d failed %d\n", + dev->lct_data.tid, rc); + + up(&dev->lock); + + return rc; +}; + +/** + * i2o_device_release - release the memory for a I2O device + * @dev: I2O device which should be released + * + * Release the allocated memory. This function is called if refcount of + * device reaches 0 automatically. + */ +static void i2o_device_release(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + + pr_debug("Release I2O device %s\n", dev->bus_id); + + kfree(i2o_dev); +}; + +/** + * i2o_device_class_release - Remove I2O device attributes + * @cd: I2O class device which is added to the I2O device class + * + * Removes attributes from the I2O device again. Also search each device + * on the controller for I2O devices which refert to this device as parent + * or user and remove this links also. + */ +static void i2o_device_class_release(struct class_device *cd) +{ + struct i2o_device *i2o_dev, *tmp; + struct i2o_controller *c; + + i2o_dev = to_i2o_device(cd->dev); + c = i2o_dev->iop; + + sysfs_remove_link(&i2o_dev->device.kobj, "parent"); + sysfs_remove_link(&i2o_dev->device.kobj, "user"); + + list_for_each_entry(tmp, &c->devices, list) { + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "parent"); + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "user"); + } +}; + +/* I2O device class */ +static struct class i2o_device_class = { + .name = "i2o_device", + .release = i2o_device_class_release +}; + +/** + * i2o_device_alloc - Allocate a I2O device and initialize it + * + * Allocate the memory for a I2O device and initialize locks and lists + * + * Returns the allocated I2O device or a negative error code if the device + * could not be allocated. + */ +static struct i2o_device *i2o_device_alloc(void) +{ + struct i2o_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + memset(dev, 0, sizeof(*dev)); + + INIT_LIST_HEAD(&dev->list); + init_MUTEX(&dev->lock); + + dev->device.bus = &i2o_bus_type; + dev->device.release = &i2o_device_release; + dev->classdev.class = &i2o_device_class; + dev->classdev.dev = &dev->device; + + return dev; +}; + +/** + * i2o_device_add - allocate a new I2O device and add it to the IOP + * @iop: I2O controller where the device is on + * @entry: LCT entry of the I2O device + * + * Allocate a new I2O device and initialize it with the LCT entry. The + * device is appended to the device list of the controller. + * + * Returns a pointer to the I2O device on success or negative error code + * on failure. + */ +struct i2o_device *i2o_device_add(struct i2o_controller *c, + i2o_lct_entry * entry) +{ + struct i2o_device *dev; + + dev = i2o_device_alloc(); + if (IS_ERR(dev)) { + printk(KERN_ERR "i2o: unable to allocate i2o device\n"); + return dev; + } + + dev->lct_data = *entry; + + snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit, + dev->lct_data.tid); + + snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit, + dev->lct_data.tid); + + dev->iop = c; + dev->device.parent = &c->device; + + device_register(&dev->device); + + list_add_tail(&dev->list, &c->devices); + + class_device_register(&dev->classdev); + + i2o_driver_notify_device_add_all(dev); + + pr_debug("I2O device %s added\n", dev->device.bus_id); + + return dev; +}; + +/** + * i2o_device_remove - remove an I2O device from the I2O core + * @dev: I2O device which should be released + * + * Is used on I2O controller removal or LCT modification, when the device + * is removed from the system. Note that the device could still hang + * around until the refcount reaches 0. + */ +void i2o_device_remove(struct i2o_device *i2o_dev) +{ + i2o_driver_notify_device_remove_all(i2o_dev); + class_device_unregister(&i2o_dev->classdev); + list_del(&i2o_dev->list); + device_unregister(&i2o_dev->device); +}; + +/** + * i2o_device_parse_lct - Parse a previously fetched LCT and create devices + * @c: I2O controller from which the LCT should be parsed. + * + * The Logical Configuration Table tells us what we can talk to on the + * board. For every entry we create an I2O device, which is registered in + * the I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_device_parse_lct(struct i2o_controller *c) +{ + struct i2o_device *dev, *tmp; + i2o_lct *lct; + int i; + int max; + + down(&c->lct_lock); + + if (c->lct) + kfree(c->lct); + + lct = c->dlct.virt; + + c->lct = kmalloc(lct->table_size * 4, GFP_KERNEL); + if (!c->lct) { + up(&c->lct_lock); + return -ENOMEM; + } + + if (lct->table_size * 4 > c->dlct.len) { + memcpy_fromio(c->lct, c->dlct.virt, c->dlct.len); + up(&c->lct_lock); + return -EAGAIN; + } + + memcpy_fromio(c->lct, c->dlct.virt, lct->table_size * 4); + + lct = c->lct; + + max = (lct->table_size - 3) / 9; + + pr_debug("LCT has %d entries (LCT size: %d)\n", max, lct->table_size); + + /* remove devices, which are not in the LCT anymore */ + list_for_each_entry_safe(dev, tmp, &c->devices, list) { + int found = 0; + + for (i = 0; i < max; i++) { + if (lct->lct_entry[i].tid == dev->lct_data.tid) { + found = 1; + break; + } + } + + if (!found) + i2o_device_remove(dev); + } + + /* add new devices, which are new in the LCT */ + for (i = 0; i < max; i++) { + int found = 0; + + list_for_each_entry_safe(dev, tmp, &c->devices, list) { + if (lct->lct_entry[i].tid == dev->lct_data.tid) { + found = 1; + break; + } + } + + if (!found) + i2o_device_add(c, &lct->lct_entry[i]); + } + up(&c->lct_lock); + + return 0; +}; + +/** + * i2o_device_class_show_class_id - Displays class id of I2O device + * @cd: class device of which the class id should be displayed + * @buf: buffer into which the class id should be printed + * + * Returns the number of bytes which are printed into the buffer. + */ +static ssize_t i2o_device_class_show_class_id(struct class_device *cd, + char *buf) +{ + struct i2o_device *dev = to_i2o_device(cd->dev); + + sprintf(buf, "%03x\n", dev->lct_data.class_id); + return strlen(buf) + 1; +}; + +/** + * i2o_device_class_show_tid - Displays TID of I2O device + * @cd: class device of which the TID should be displayed + * @buf: buffer into which the class id should be printed + * + * Returns the number of bytes which are printed into the buffer. + */ +static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf) +{ + struct i2o_device *dev = to_i2o_device(cd->dev); + + sprintf(buf, "%03x\n", dev->lct_data.tid); + return strlen(buf) + 1; +}; + +/* I2O device class attributes */ +static CLASS_DEVICE_ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id, + NULL); +static CLASS_DEVICE_ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL); + +/** + * i2o_device_class_add - Adds attributes to the I2O device + * @cd: I2O class device which is added to the I2O device class + * + * This function get called when a I2O device is added to the class. It + * creates the attributes for each device and creates user/parent symlink + * if necessary. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_device_class_add(struct class_device *cd) +{ + struct i2o_device *i2o_dev, *tmp; + struct i2o_controller *c; + + i2o_dev = to_i2o_device(cd->dev); + c = i2o_dev->iop; + + class_device_create_file(cd, &class_device_attr_class_id); + class_device_create_file(cd, &class_device_attr_tid); + + /* create user entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); + if (tmp) + sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, + "user"); + + /* create user entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "user"); + + /* create parent entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); + if (tmp) + sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, + "parent"); + + /* create parent entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "parent"); + + return 0; +}; + +/* I2O device class interface */ +static struct class_interface i2o_device_class_interface = { + .class = &i2o_device_class, + .add = i2o_device_class_add +}; + +/* + * Run time support routines + */ + +/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET + * + * This function can be used for all UtilParamsGet/Set operations. + * The OperationList is given in oplist-buffer, + * and results are returned in reslist-buffer. + * Note that the minimum sized reslist is 8 bytes and contains + * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. + */ + +int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist, + int oplen, void *reslist, int reslen) +{ + struct i2o_message *msg; + u32 m; + u32 *res32 = (u32 *) reslist; + u32 *restmp = (u32 *) reslist; + int len = 0; + int i = 0; + int rc; + struct i2o_dma res; + struct i2o_controller *c = i2o_dev->iop; + struct device *dev = &c->pdev->dev; + + res.virt = NULL; + + if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL)) + return -ENOMEM; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) { + i2o_dma_free(dev, &res); + return -ETIMEDOUT; + } + + i = 0; + writel(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid, + &msg->u.head[1]); + writel(0, &msg->body[i++]); + writel(0x4C000000 | oplen, &msg->body[i++]); /* OperationList */ + memcpy_toio(&msg->body[i], oplist, oplen); + i += (oplen / 4 + (oplen % 4 ? 1 : 0)); + writel(0xD0000000 | res.len, &msg->body[i++]); /* ResultList */ + writel(res.phys, &msg->body[i++]); + + writel(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) | + SGL_OFFSET_5, &msg->u.head[0]); + + rc = i2o_msg_post_wait_mem(c, m, 10, &res); + + /* This only looks like a memory leak - don't "fix" it. */ + if (rc == -ETIMEDOUT) + return rc; + + memcpy_fromio(reslist, res.virt, res.len); + i2o_dma_free(dev, &res); + + /* Query failed */ + if (rc) + return rc; + /* + * Calculate number of bytes of Result LIST + * We need to loop through each Result BLOCK and grab the length + */ + restmp = res32 + 1; + len = 1; + for (i = 0; i < (res32[0] & 0X0000FFFF); i++) { + if (restmp[0] & 0x00FF0000) { /* BlockStatus != SUCCESS */ + printk(KERN_WARNING + "%s - Error:\n ErrorInfoSize = 0x%02x, " + "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", + (cmd == + I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" : + "PARAMS_GET", res32[1] >> 24, + (res32[1] >> 16) & 0xFF, res32[1] & 0xFFFF); + + /* + * If this is the only request,than we return an error + */ + if ((res32[0] & 0x0000FFFF) == 1) { + return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */ + } + } + len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ + restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ + } + return (len << 2); /* bytes used by result list */ +} + +/* + * Query one field group value or a whole scalar group. + */ +int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field, + void *buf, int buflen) +{ + u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; + u8 resblk[8 + buflen]; /* 8 bytes for header */ + int size; + + if (field == -1) /* whole group */ + opblk[4] = -1; + + size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk, + sizeof(opblk), resblk, sizeof(resblk)); + + memcpy(buf, resblk + 8, buflen); /* cut off header */ + + if (size > buflen) + return buflen; + + return size; +} + +/* + * Set a scalar group value or a whole group. + */ +int i2o_parm_field_set(struct i2o_device *i2o_dev, int group, int field, + void *buf, int buflen) +{ + u16 *opblk; + u8 resblk[8 + buflen]; /* 8 bytes for header */ + int size; + + opblk = kmalloc(buflen + 64, GFP_KERNEL); + if (opblk == NULL) { + printk(KERN_ERR "i2o: no memory for operation buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = I2O_PARAMS_FIELD_SET; + opblk[3] = group; + + if (field == -1) { /* whole group */ + opblk[4] = -1; + memcpy(opblk + 5, buf, buflen); + } else { /* single field */ + + opblk[4] = 1; + opblk[5] = field; + memcpy(opblk + 6, buf, buflen); + } + + size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_SET, opblk, + 12 + buflen, resblk, sizeof(resblk)); + + kfree(opblk); + if (size > buflen) + return buflen; + + return size; +} + +/* + * if oper == I2O_PARAMS_TABLE_GET, get from all rows + * if fieldcount == -1 return all fields + * ibuf and ibuflen are unused (use NULL, 0) + * else return specific fields + * ibuf contains fieldindexes + * + * if oper == I2O_PARAMS_LIST_GET, get from specific rows + * if fieldcount == -1 return all fields + * ibuf contains rowcount, keyvalues + * else return specific fields + * fieldcount is # of fieldindexes + * ibuf contains fieldindexes, rowcount, keyvalues + * + * You could also use directly function i2o_issue_params(). + */ +int i2o_parm_table_get(struct i2o_device *dev, int oper, int group, + int fieldcount, void *ibuf, int ibuflen, void *resblk, + int reslen) +{ + u16 *opblk; + int size; + + size = 10 + ibuflen; + if (size % 4) + size += 4 - size % 4; + + opblk = kmalloc(size, GFP_KERNEL); + if (opblk == NULL) { + printk(KERN_ERR "i2o: no memory for query buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = oper; + opblk[3] = group; + opblk[4] = fieldcount; + memcpy(opblk + 5, ibuf, ibuflen); /* other params */ + + size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk, + size, resblk, reslen); + + kfree(opblk); + if (size > reslen) + return reslen; + + return size; +} + +/** + * i2o_device_init - Initialize I2O devices + * + * Registers the I2O device class. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_device_init(void) +{ + int rc; + + rc = class_register(&i2o_device_class); + if (rc) + return rc; + + return class_interface_register(&i2o_device_class_interface); +}; + +/** + * i2o_device_exit - I2O devices exit function + * + * Unregisters the I2O device class. + */ +void i2o_device_exit(void) +{ + class_interface_register(&i2o_device_class_interface); + class_unregister(&i2o_device_class); +}; + +EXPORT_SYMBOL(i2o_device_claim); +EXPORT_SYMBOL(i2o_device_claim_release); +EXPORT_SYMBOL(i2o_parm_field_get); +EXPORT_SYMBOL(i2o_parm_field_set); +EXPORT_SYMBOL(i2o_parm_table_get); +EXPORT_SYMBOL(i2o_parm_issue); diff -Nru a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/message/i2o/driver.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,367 @@ +/* + * Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs + * + * Copyright (C) 2004 Markus Lidel + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Fixes/additions: + * Markus Lidel + * initial version. + */ + +#include +#include +#include +#include + + +/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */ +unsigned int i2o_max_drivers = I2O_MAX_DRIVERS; +module_param_named(max_drivers, i2o_max_drivers, uint, 0); +MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support"); + +/* I2O drivers lock and array */ +static spinlock_t i2o_drivers_lock = SPIN_LOCK_UNLOCKED; +static struct i2o_driver **i2o_drivers; + +/** + * i2o_bus_match - Tell if a I2O device class id match the class ids of + * the I2O driver (OSM) + * + * @dev: device which should be verified + * @drv: the driver to match against + * + * Used by the bus to check if the driver wants to handle the device. + * + * Returns 1 if the class ids of the driver match the class id of the + * device, otherwise 0. + */ +static int i2o_bus_match(struct device *dev, struct device_driver *drv) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_driver *i2o_drv = to_i2o_driver(drv); + struct i2o_class_id *ids = i2o_drv->classes; + + if (ids) + while (ids->class_id != I2O_CLASS_END) { + if (ids->class_id == i2o_dev->lct_data.class_id) + return 1; + ids++; + } + return 0; +}; + +/* I2O bus type */ +struct bus_type i2o_bus_type = { + .name = "i2o", + .match = i2o_bus_match, +}; + +/** + * i2o_driver_register - Register a I2O driver (OSM) in the I2O core + * @drv: I2O driver which should be registered + * + * Registers the OSM drv in the I2O core and creates an event queues if + * necessary. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_driver_register(struct i2o_driver *drv) +{ + struct i2o_controller *c; + int i; + int rc = 0; + unsigned long flags; + + pr_debug("Register driver %s\n", drv->name); + + if (drv->event) { + drv->event_queue = create_workqueue(drv->name); + if (!drv->event_queue) { + printk(KERN_ERR "i2o: Could not initialize event queue " + "for driver %s\n", drv->name); + return -EFAULT; + } + pr_debug("Event queue initialized for driver %s\n", drv->name); + } else + drv->event_queue = NULL; + + drv->driver.name = drv->name; + drv->driver.bus = &i2o_bus_type; + + spin_lock_irqsave(&i2o_drivers_lock, flags); + + for (i = 0; i2o_drivers[i]; i++) + if (i >= i2o_max_drivers) { + printk(KERN_ERR "i2o: too many drivers registered, " + "increase max_drivers\n"); + spin_unlock_irqrestore(&i2o_drivers_lock, flags); + return -EFAULT; + } + + drv->context = i; + i2o_drivers[i] = drv; + + spin_unlock_irqrestore(&i2o_drivers_lock, flags); + + pr_debug("driver %s gets context id %d\n", drv->name, drv->context); + + list_for_each_entry(c, &i2o_controllers, list) { + struct i2o_device *i2o_dev; + + i2o_driver_notify_controller_add(drv, c); + list_for_each_entry(i2o_dev, &c->devices, list) + i2o_driver_notify_device_add(drv, i2o_dev); + } + + + rc = driver_register(&drv->driver); + if (rc) + destroy_workqueue(drv->event_queue); + + return rc; +}; + +/** + * i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core + * @drv: I2O driver which should be unregistered + * + * Unregisters the OSM drv from the I2O core and cleanup event queues if + * necessary. + */ +void i2o_driver_unregister(struct i2o_driver *drv) +{ + struct i2o_controller *c; + unsigned long flags; + + pr_debug("unregister driver %s\n", drv->name); + + driver_unregister(&drv->driver); + + list_for_each_entry(c, &i2o_controllers, list) { + struct i2o_device *i2o_dev; + + list_for_each_entry(i2o_dev, &c->devices, list) + i2o_driver_notify_device_remove(drv, i2o_dev); + + i2o_driver_notify_controller_remove(drv, c); + } + + spin_lock_irqsave(&i2o_drivers_lock, flags); + i2o_drivers[drv->context] = NULL; + spin_unlock_irqrestore(&i2o_drivers_lock, flags); + + if (drv->event_queue) { + destroy_workqueue(drv->event_queue); + drv->event_queue = NULL; + pr_debug("event queue removed for %s\n", drv->name); + } +}; + +/** + * i2o_driver_dispatch - dispatch an I2O reply message + * @c: I2O controller of the message + * @m: I2O message number + * @msg: I2O message to be delivered + * + * The reply is delivered to the driver from which the original message + * was. This function is only called from interrupt context. + * + * Returns 0 on success and the message should not be flushed. Returns > 0 + * on success and if the message should be flushed afterwords. Returns + * negative error code on failure (the message will be flushed too). + */ +int i2o_driver_dispatch(struct i2o_controller *c, u32 m, + struct i2o_message *msg) +{ + struct i2o_driver *drv; + u32 context = readl(&msg->u.s.icntxt); + + if (likely(context < i2o_max_drivers)) { + spin_lock(&i2o_drivers_lock); + drv = i2o_drivers[context]; + spin_unlock(&i2o_drivers_lock); + + if (unlikely(!drv)) { + printk(KERN_WARNING "i2o: Spurious reply to unknown " + "driver %d\n", context); + return -EIO; + } + + if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) { + struct i2o_device *dev, *tmp; + struct i2o_event *evt; + u16 size; + u16 tid; + + tid = readl(&msg->u.head[1]) & 0x1fff; + + pr_debug("%s: event received from device %d\n", c->name, + tid); + + /* cut of header from message size (in 32-bit words) */ + size = (readl(&msg->u.head[0]) >> 16) - 5; + + evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC); + if (!evt) + return -ENOMEM; + memset(evt, 0, size * 4 + sizeof(*evt)); + + evt->size = size; + memcpy_fromio(&evt->tcntxt, &msg->u.s.tcntxt, + (size + 2) * 4); + + list_for_each_entry_safe(dev, tmp, &c->devices, list) + if (dev->lct_data.tid == tid) { + evt->i2o_dev = dev; + break; + } + + INIT_WORK(&evt->work, (void (*)(void *))drv->event, + evt); + queue_work(drv->event_queue, &evt->work); + return 1; + } + + if (likely(drv->reply)) + return drv->reply(c, m, msg); + else + pr_debug("%s: Reply to driver %s, but no reply function" + " defined!\n", c->name, drv->name); + return -EIO; + } else + printk(KERN_WARNING "i2o: Spurious reply to unknown driver " + "%d\n", readl(&msg->u.s.icntxt)); + return -EIO; +} + +/** + * i2o_driver_notify_controller_add_all - Send notify of added controller + * to all I2O drivers + * + * Send notifications to all registered drivers that a new controller was + * added. + */ +void i2o_driver_notify_controller_add_all(struct i2o_controller *c) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_controller_add(drv, c); + } +} + +/** + * i2o_driver_notify_controller_remove_all - Send notify of removed + * controller to all I2O drivers + * + * Send notifications to all registered drivers that a controller was + * removed. + */ +void i2o_driver_notify_controller_remove_all(struct i2o_controller *c) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_controller_remove(drv, c); + } +} + +/** + * i2o_driver_notify_device_add_all - Send notify of added device to all + * I2O drivers + * + * Send notifications to all registered drivers that a device was added. + */ +void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_device_add(drv, i2o_dev); + } +} + +/** + * i2o_driver_notify_device_remove_all - Send notify of removed device to + * all I2O drivers + * + * Send notifications to all registered drivers that a device was removed. + */ +void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_device_remove(drv, i2o_dev); + } +} + +/** + * i2o_driver_init - initialize I2O drivers (OSMs) + * + * Registers the I2O bus and allocate memory for the array of OSMs. + * + * Returns 0 on success or negative error code on failure. + */ +int __init i2o_driver_init(void) +{ + int rc = 0; + + if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64) || + ((i2o_max_drivers ^ (i2o_max_drivers - 1)) != + (2 * i2o_max_drivers - 1))) { + printk(KERN_WARNING "i2o: max_drivers set to %d, but must be " + ">=2 and <= 64 and a power of 2\n", i2o_max_drivers); + i2o_max_drivers = I2O_MAX_DRIVERS; + } + printk(KERN_INFO "i2o: max_drivers=%d\n", i2o_max_drivers); + + i2o_drivers = + kmalloc(i2o_max_drivers * sizeof(*i2o_drivers), GFP_KERNEL); + if (!i2o_drivers) + return -ENOMEM; + + memset(i2o_drivers, 0, i2o_max_drivers * sizeof(*i2o_drivers)); + + rc = bus_register(&i2o_bus_type); + + if (rc < 0) + kfree(i2o_drivers); + + return rc; +}; + +/** + * i2o_driver_exit - clean up I2O drivers (OSMs) + * + * Unregisters the I2O bus and free driver array. + */ +void __exit i2o_driver_exit(void) +{ + bus_unregister(&i2o_bus_type); + kfree(i2o_drivers); +}; + +EXPORT_SYMBOL(i2o_driver_register); +EXPORT_SYMBOL(i2o_driver_unregister); +EXPORT_SYMBOL(i2o_driver_notify_controller_add_all); +EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all); +EXPORT_SYMBOL(i2o_driver_notify_device_add_all); +EXPORT_SYMBOL(i2o_driver_notify_device_remove_all); diff -Nru a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/message/i2o/exec-osm.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,505 @@ +/* + * Executive OSM + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * A lot of the I2O message side code from this is taken from the Red + * Creek RCPCI45 adapter driver by Red Creek Communications + * + * Fixes/additions: + * Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen + * Deepak Saxena + * Boji T Kannanthanam + * Alan Cox : + * Ported to Linux 2.5. + * Markus Lidel : + * Minor fixes for 2.6. + * Markus Lidel : + * Support for sysfs included. + */ + +#include +#include + +struct i2o_driver i2o_exec_driver; + +/* Module internal functions from other sources */ +extern int i2o_device_parse_lct(struct i2o_controller *); + +/* global wait list for POST WAIT */ +static LIST_HEAD(i2o_exec_wait_list); + +/* Wait struct needed for POST WAIT */ +struct i2o_exec_wait { + wait_queue_head_t *wq; /* Pointer to Wait queue */ + struct i2o_dma dma; /* DMA buffers to free on failure */ + u32 tcntxt; /* transaction context from reply */ + int complete; /* 1 if reply received otherwise 0 */ + u32 m; /* message id */ + struct i2o_message *msg; /* pointer to the reply message */ + struct list_head list; /* node in global wait list */ +}; + +/* Exec OSM class handling definition */ +static struct i2o_class_id i2o_exec_class_id[] = { + {I2O_CLASS_EXECUTIVE}, + {I2O_CLASS_END} +}; + +/** + * i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it + * + * Allocate the i2o_exec_wait struct and initialize the wait. + * + * Returns i2o_exec_wait pointer on success or negative error code on + * failure. + */ +static struct i2o_exec_wait *i2o_exec_wait_alloc(void) +{ + struct i2o_exec_wait *wait; + + wait = kmalloc(sizeof(*wait), GFP_KERNEL); + if (!wait) + return ERR_PTR(-ENOMEM); + + memset(wait, 0, sizeof(*wait)); + + INIT_LIST_HEAD(&wait->list); + + return wait; +}; + +/** + * i2o_exec_wait_free - Free a i2o_exec_wait struct + * @i2o_exec_wait: I2O wait data which should be cleaned up + */ +static void i2o_exec_wait_free(struct i2o_exec_wait *wait) +{ + kfree(wait); +}; + +/** + * i2o_msg_post_wait_mem - Post and wait a message with DMA buffers + * @c: controller + * @m: message to post + * @timeout: time in seconds to wait + * @dma: i2o_dma struct of the DMA buffer to free on failure + * + * This API allows an OSM to post a message and then be told whether or + * not the system received a successful reply. If the message times out + * then the value '-ETIMEDOUT' is returned. This is a special case. In + * this situation the message may (should) complete at an indefinite time + * in the future. When it completes it will use the memory buffer + * attached to the request. If -ETIMEDOUT is returned then the memory + * buffer must not be freed. Instead the event completion will free them + * for you. In all other cases the buffer are your problem. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long + timeout, struct i2o_dma *dma) +{ + DECLARE_WAIT_QUEUE_HEAD(wq); + DEFINE_WAIT(wait); + struct i2o_exec_wait *iwait; + static u32 tcntxt = 0x80000000; + struct i2o_message *msg = c->in_queue.virt + m; + int rc = 0; + + iwait = i2o_exec_wait_alloc(); + if (!iwait) + return -ENOMEM; + + if (tcntxt == 0xffffffff) + tcntxt = 0x80000000; + + if (dma) + iwait->dma = *dma; + + /* + * Fill in the message initiator context and transaction context. + * We will only use transaction contexts >= 0x80000000 for POST WAIT, + * so we could find a POST WAIT reply easier in the reply handler. + */ + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + iwait->tcntxt = tcntxt++; + writel(iwait->tcntxt, &msg->u.s.tcntxt); + + /* + * Post the message to the controller. At some point later it will + * return. If we time out before it returns then complete will be zero. + */ + i2o_msg_post(c, m); + + if (!iwait->complete) { + iwait->wq = &wq; + /* + * we add elements add the head, because if a entry in the list + * will never be removed, we have to iterate over it every time + */ + list_add(&iwait->list, &i2o_exec_wait_list); + + prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); + + if (!iwait->complete) + schedule_timeout(timeout * HZ); + + finish_wait(&wq, &wait); + + iwait->wq = NULL; + } + + barrier(); + + if (iwait->complete) { + if (readl(&iwait->msg->body[0]) >> 24) + rc = readl(&iwait->msg->body[0]) & 0xff; + i2o_flush_reply(c, iwait->m); + i2o_exec_wait_free(iwait); + } else { + /* + * We cannot remove it now. This is important. When it does + * terminate (which it must do if the controller has not + * died...) then it will otherwise scribble on stuff. + * + * FIXME: try abort message + */ + if (dma) + dma->virt = NULL; + + rc = -ETIMEDOUT; + } + + return rc; +}; + +/** + * i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP + * @c: I2O controller which answers + * @m: message id + * @msg: pointer to the I2O reply message + * + * This function is called in interrupt context only. If the reply reached + * before the timeout, the i2o_exec_wait struct is filled with the message + * and the task will be waked up. The task is now responsible for returning + * the message m back to the controller! If the message reaches us after + * the timeout clean up the i2o_exec_wait struct (including allocated + * DMA buffer). + * + * Return 0 on success and if the message m should not be given back to the + * I2O controller, or >0 on success and if the message should be given back + * afterwords. Returns negative error code on failure. In this case the + * message must also be given back to the controller. + */ +static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, + struct i2o_message *msg) +{ + struct i2o_exec_wait *wait, *tmp; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + int rc = 1; + u32 context; + + context = readl(&msg->u.s.tcntxt); + + /* + * We need to search through the i2o_exec_wait_list to see if the given + * message is still outstanding. If not, it means that the IOP took + * longer to respond to the message than we had allowed and timer has + * already expired. Not much we can do about that except log it for + * debug purposes, increase timeout, and recompile. + */ + spin_lock(&lock); + list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) { + if (wait->tcntxt == context) { + list_del(&wait->list); + + wait->m = m; + wait->msg = msg; + wait->complete = 1; + + barrier(); + + if (wait->wq) { + wake_up_interruptible(wait->wq); + rc = 0; + } else { + struct device *dev; + + dev = &c->pdev->dev; + + pr_debug("timedout reply received!\n"); + i2o_dma_free(dev, &wait->dma); + i2o_exec_wait_free(wait); + rc = -1; + } + + spin_unlock(&lock); + + return rc; + } + } + + spin_unlock(&lock); + + pr_debug("i2o: Bogus reply in POST WAIT (tr-context: %08x)!\n", + context); + + return -1; +}; + +/** + * i2o_exec_probe - Called if a new I2O device (executive class) appears + * @dev: I2O device which should be probed + * + * Registers event notification for every event from Executive device. The + * return is always 0, because we want all devices of class Executive. + * + * Returns 0 on success. + */ +static int i2o_exec_probe(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + + i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); + + i2o_dev->iop->exec = i2o_dev; + + return 0; +}; + +/** + * i2o_exec_remove - Called on I2O device removal + * @dev: I2O device which was removed + * + * Unregisters event notification from Executive I2O device. + * + * Returns 0 on success. + */ +static int i2o_exec_remove(struct device *dev) +{ + i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0); + + return 0; +}; + +/** + * i2o_exec_lct_modified - Called on LCT NOTIFY reply + * @c: I2O controller on which the LCT has modified + * + * This function handles asynchronus LCT NOTIFY replies. It parses the + * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY + * again. + */ +static void i2o_exec_lct_modified(struct i2o_controller *c) +{ + if (i2o_device_parse_lct(c) == -EAGAIN) + i2o_exec_lct_notify(c, 0); +}; + +/** + * i2o_exec_reply - I2O Executive reply handler + * @c: I2O controller from which the reply comes + * @m: message id + * @msg: pointer to the I2O reply message + * + * This function is always called from interrupt context. If a POST WAIT + * reply was received, pass it to the complete function. If a LCT NOTIFY + * reply was received, a new event is created to handle the update. + * + * Returns 0 on success and if the reply should not be flushed or > 0 + * on success and if the reply should be flushed. Returns negative error + * code on failure and if the reply should be flushed. + */ +static int i2o_exec_reply(struct i2o_controller *c, u32 m, + struct i2o_message *msg) +{ + if (readl(&msg->u.head[0]) & MSG_FAIL) { // Fail bit is set + struct i2o_message *pmsg; /* preserved message */ + u32 pm; + + pm = readl(&msg->body[3]); + + pmsg = c->in_queue.virt + pm; + + i2o_report_status(KERN_INFO, "i2o_core", msg); + + /* Release the preserved msg by resubmitting it as a NOP */ + i2o_msg_nop(c, pm); + + /* If reply to i2o_post_wait failed, return causes a timeout */ + return -1; + } + + if (readl(&msg->u.s.tcntxt) & 0x80000000) + return i2o_msg_post_wait_complete(c, m, msg); + + if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) { + struct work_struct *work; + + pr_debug("%s: LCT notify received\n", c->name); + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) + return -ENOMEM; + + INIT_WORK(work, (void (*)(void *))i2o_exec_lct_modified, c); + queue_work(i2o_exec_driver.event_queue, work); + return 1; + } + + /* + * If this happens, we want to dump the message to the syslog so + * it can be sent back to the card manufacturer by the end user + * to aid in debugging. + * + */ + printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" + "Message dumped to syslog\n", c->name); + i2o_dump_message(msg); + + return -EFAULT; +} + +/** + * i2o_exec_event - Event handling function + * @evt: Event which occurs + * + * Handles events send by the Executive device. At the moment does not do + * anything useful. + */ +static void i2o_exec_event(struct i2o_event *evt) +{ + printk(KERN_INFO "Event received from device: %d\n", + evt->i2o_dev->lct_data.tid); + kfree(evt); +}; + +/** + * i2o_exec_lct_get - Get the IOP's Logical Configuration Table + * @c: I2O controller from which the LCT should be fetched + * + * Send a LCT NOTIFY request to the controller, and wait + * I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is + * to large, retry it. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_exec_lct_get(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + int i = 0; + int rc = -EAGAIN; + + for (i = 1; i <= I2O_LCT_GET_TRIES; i++) { + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(0xffffffff, &msg->body[0]); + writel(0x00000000, &msg->body[1]); + writel(0xd0000000 | c->dlct.len, &msg->body[2]); + writel(c->dlct.phys, &msg->body[3]); + + rc = i2o_msg_post_wait(c, m, I2O_TIMEOUT_LCT_GET); + if (rc < 0) + break; + + rc = i2o_device_parse_lct(c); + if (rc != -EAGAIN) + break; + } + + return rc; +} + +/** + * i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request + * @c: I2O controller to which the request should be send + * @change_ind: change indicator + * + * This function sends a LCT NOTIFY request to the I2O controller with + * the change indicator change_ind. If the change_ind == 0 the controller + * replies immediately after the request. If change_ind > 0 the reply is + * send after change indicator of the LCT is > change_ind. + */ +int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) +{ + i2o_status_block *sb = c->status_block.virt; + struct device *dev; + struct i2o_message *msg; + u32 m; + + dev = &c->pdev->dev; + + if (i2o_dma_realloc(dev, &c->dlct, sb->expected_lct_size, GFP_KERNEL)) + return -ENOMEM; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0, &msg->u.s.tcntxt); /* FIXME */ + writel(0xffffffff, &msg->body[0]); + writel(change_ind, &msg->body[1]); + writel(0xd0000000 | c->dlct.len, &msg->body[2]); + writel(c->dlct.phys, &msg->body[3]); + + i2o_msg_post(c, m); + + return 0; +}; + +/* Exec OSM driver struct */ +struct i2o_driver i2o_exec_driver = { + .name = "exec-osm", + .reply = i2o_exec_reply, + .event = i2o_exec_event, + .classes = i2o_exec_class_id, + .driver = { + .probe = i2o_exec_probe, + .remove = i2o_exec_remove, + }, +}; + +/** + * i2o_exec_init - Registers the Exec OSM + * + * Registers the Exec OSM in the I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +int __init i2o_exec_init(void) +{ + return i2o_driver_register(&i2o_exec_driver); +}; + +/** + * i2o_exec_exit - Removes the Exec OSM + * + * Unregisters the Exec OSM from the I2O core. + */ +void __exit i2o_exec_exit(void) +{ + i2o_driver_unregister(&i2o_exec_driver); +}; + +EXPORT_SYMBOL(i2o_msg_post_wait_mem); +EXPORT_SYMBOL(i2o_exec_lct_get); +EXPORT_SYMBOL(i2o_exec_lct_notify); diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c --- a/drivers/message/i2o/i2o_block.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/message/i2o/i2o_block.c 2004-10-18 14:56:48 -07:00 @@ -1,463 +1,426 @@ /* - * I2O Random Block Storage Class OSM + * Block OSM * - * (C) Copyright 1999-2002 Red Hat - * - * Written by Alan Cox, Building Number Three Ltd - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * For the purpose of avoiding doubt the preferred form of the work - * for making modifications shall be a standards compliant form such - * gzipped tar and not one requiring a proprietary or patent encumbered - * tool to unpack. - * - * This is a beta test release. Most of the good code was taken - * from the nbd driver by Pavel Machek, who in turn took some of it - * from loop.c. Isn't free software great for reusability 8) - * - * Fixes/additions: - * Steve Ralston: - * Multiple device handling error fixes, - * Added a queue depth. - * Alan Cox: - * FC920 has an rmw bug. Dont or in the end marker. - * Removed queue walk, fixed for 64bitness. - * Rewrote much of the code over time - * Added indirect block lists - * Handle 64K limits on many controllers - * Don't use indirects on the Promise (breaks) - * Heavily chop down the queue depths - * Deepak Saxena: - * Independent queues per IOP - * Support for dynamic device creation/deletion - * Code cleanup - * Support for larger I/Os through merge* functions - * (taken from DAC960 driver) - * Boji T Kannanthanam: - * Set the I2O Block devices to be detected in increasing - * order of TIDs during boot. - * Search and set the I2O block device that we boot off from as - * the first device to be claimed (as /dev/i2o/hda) - * Properly attach/detach I2O gendisk structure from the system - * gendisk list. The I2O block devices now appear in - * /proc/partitions. - * Markus Lidel : - * Minor bugfixes for 2.6. + * Copyright (C) 1999-2002 Red Hat Software * - * To do: - * Serial number scanning to find duplicates for FC multipathing + * Written by Alan Cox, Building Number Three Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * For the purpose of avoiding doubt the preferred form of the work + * for making modifications shall be a standards compliant form such + * gzipped tar and not one requiring a proprietary or patent encumbered + * tool to unpack. + * + * Fixes/additions: + * Steve Ralston: + * Multiple device handling error fixes, + * Added a queue depth. + * Alan Cox: + * FC920 has an rmw bug. Dont or in the end marker. + * Removed queue walk, fixed for 64bitness. + * Rewrote much of the code over time + * Added indirect block lists + * Handle 64K limits on many controllers + * Don't use indirects on the Promise (breaks) + * Heavily chop down the queue depths + * Deepak Saxena: + * Independent queues per IOP + * Support for dynamic device creation/deletion + * Code cleanup + * Support for larger I/Os through merge* functions + * (taken from DAC960 driver) + * Boji T Kannanthanam: + * Set the I2O Block devices to be detected in increasing + * order of TIDs during boot. + * Search and set the I2O block device that we boot off + * from as the first device to be claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure from the + * system gendisk list. The I2O block devices now appear in + * /proc/partitions. + * Markus Lidel : + * Minor bugfixes for 2.6. */ -#include - #include -#include -#include -#include -#include -#include -#include -#include -#include #include + +#include + +#include #include -#include -#include #include -#include -#include -#include -#include +#include "i2o_block.h" -#include -#include -#include -#include -#include -#include - -#define MAJOR_NR I2O_MAJOR - -#define MAX_I2OB 16 - -#define MAX_I2OB_DEPTH 8 -#define MAX_I2OB_RETRIES 4 - -//#define DRIVERDEBUG -#ifdef DRIVERDEBUG -#define DEBUG( s ) printk( s ) -#else -#define DEBUG( s ) -#endif +static struct i2o_driver i2o_block_driver; -/* - * Events that this OSM is interested in - */ -#define I2OB_EVENT_MASK (I2O_EVT_IND_BSA_VOLUME_LOAD | \ - I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ - I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ - I2O_EVT_IND_BSA_CAPACITY_CHANGE | \ - I2O_EVT_IND_BSA_SCSI_SMART ) +/* global Block OSM request mempool */ +static struct i2o_block_mempool i2o_blk_req_pool; +/* Block OSM class handling definition */ +static struct i2o_class_id i2o_block_class_id[] = { + {I2O_CLASS_RANDOM_BLOCK_STORAGE}, + {I2O_CLASS_END} +}; -/* - * Some of these can be made smaller later +/** + * i2o_block_device_free - free the memory of the I2O Block device + * @dev: I2O Block device, which should be cleaned up + * + * Frees the request queue, gendisk and the i2o_block_device structure. */ +static void i2o_block_device_free(struct i2o_block_device *dev) +{ + blk_cleanup_queue(dev->gd->queue); -static int i2ob_context; -static struct block_device_operations i2ob_fops; + put_disk(dev->gd); -/* - * I2O Block device descriptor + kfree(dev); +}; + +/** + * i2o_block_remove - remove the I2O Block device from the system again + * @dev: I2O Block device which should be removed + * + * Remove gendisk from system and free all allocated memory. + * + * Always returns 0. */ -struct i2ob_device +static int i2o_block_remove(struct device *dev) { - struct i2o_controller *controller; - struct i2o_device *i2odev; - int unit; - int tid; - int flags; - int refcnt; - struct request *head, *tail; - request_queue_t *req_queue; - int max_segments; - int max_direct; /* Not yet used properly */ - int done_flag; - int depth; - int rcache; - int wcache; - int power; - int index; - int media_change_flag; - u32 max_sectors; - struct gendisk *gd; + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev); + + printk(KERN_INFO "block-osm: Device removed %s\n", + i2o_blk_dev->gd->disk_name); + + i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0); + + del_gendisk(i2o_blk_dev->gd); + + dev_set_drvdata(dev, NULL); + + i2o_device_claim_release(i2o_dev); + + i2o_block_device_free(i2o_blk_dev); + + return 0; }; -/* - * FIXME: - * We should cache align these to avoid ping-ponging lines on SMP - * boxes under heavy I/O load... +/** + * i2o_block_device flush - Flush all dirty data of I2O device dev + * @dev: I2O device which should be flushed + * + * Flushes all dirty data on device dev. + * + * Returns 0 on success or negative error code on failure. */ - -struct i2ob_request +static int i2o_block_device_flush(struct i2o_device *dev) { - struct i2ob_request *next; - struct request *req; - int num; - int sg_dma_direction; - int sg_nents; - struct scatterlist sg_table[16]; + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_CFLUSH << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(60 << 16, &msg->body[0]); + pr_debug("Flushing...\n"); + + return i2o_msg_post_wait(dev->iop, m, 60); }; -/* - * Per IOP request queue information +/** + * i2o_block_device_mount - Mount (load) the media of device dev + * @dev: I2O device which should receive the mount request + * @media_id: Media Identifier + * + * Load a media into drive. Identifier should be set to -1, because the + * spec does not support any other value. * - * We have a separate request_queue_t per IOP so that a heavilly - * loaded I2O block device on an IOP does not starve block devices - * across all I2O controllers. - * - */ -struct i2ob_iop_queue -{ - unsigned int queue_depth; - struct i2ob_request request_queue[MAX_I2OB_DEPTH]; - struct i2ob_request *i2ob_qhead; - request_queue_t *req_queue; - spinlock_t lock; + * Returns 0 on success or negative error code on failure. + */ +static int i2o_block_device_mount(struct i2o_device *dev, u32 media_id) +{ + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_MMOUNT << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(-1, &msg->body[0]); + writel(0, &msg->body[1]); + pr_debug("Mounting...\n"); + + return i2o_msg_post_wait(dev->iop, m, 2); }; -static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS]; -/* - * Each I2O disk is one of these. +/** + * i2o_block_device_lock - Locks the media of device dev + * @dev: I2O device which should receive the lock request + * @media_id: Media Identifier + * + * Lock media of device dev to prevent removal. The media identifier + * should be set to -1, because the spec does not support any other value. + * + * Returns 0 on success or negative error code on failure. */ +static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id) +{ + struct i2o_message *msg; + u32 m; -static struct i2ob_device i2ob_dev[MAX_I2OB]; -static int i2ob_dev_count = 0; + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_MLOCK << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(-1, &msg->body[0]); + pr_debug("Locking...\n"); -/* - * Mutex and spin lock for event handling synchronization - * evt_msg contains the last event. + return i2o_msg_post_wait(dev->iop, m, 2); +}; + +/** + * i2o_block_device_unlock - Unlocks the media of device dev + * @dev: I2O device which should receive the unlocked request + * @media_id: Media Identifier + * + * Unlocks the media in device dev. The media identifier should be set to + * -1, because the spec does not support any other value. + * + * Returns 0 on success or negative error code on failure. */ -static DECLARE_MUTEX_LOCKED(i2ob_evt_sem); -static DECLARE_COMPLETION(i2ob_thread_dead); -static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED; -static u32 evt_msg[MSG_FRAME_SIZE]; - -static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *, - struct i2o_message *); -static void i2ob_new_device(struct i2o_controller *, struct i2o_device *); -static void i2ob_del_device(struct i2o_controller *, struct i2o_device *); -static void i2ob_reboot_event(void); -static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); -static void i2ob_end_request(struct request *); -static void i2ob_request(request_queue_t *); -static int i2ob_init_iop(unsigned int); -static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); -static int i2ob_evt(void *); - -static int evt_pid = 0; -static int evt_running = 0; -static int scan_unit = 0; +static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id) +{ + struct i2o_message *msg; + u32 m; -/* - * I2O OSM registration structure...keeps getting bigger and bigger :) + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_MUNLOCK << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(media_id, &msg->body[0]); + pr_debug("Unlocking...\n"); + + return i2o_msg_post_wait(dev->iop, m, 2); +}; + +/** + * i2o_block_device_power - Power management for device dev + * @dev: I2O device which should receive the power management request + * @operation: Operation which should be send + * + * Send a power management request to the device dev. + * + * Returns 0 on success or negative error code on failure. */ -static struct i2o_handler i2o_block_handler = +static int i2o_block_device_power(struct i2o_block_device *dev, u8 op) { - i2o_block_reply, - i2ob_new_device, - i2ob_del_device, - i2ob_reboot_event, - "I2O Block OSM", - 0, - I2O_CLASS_RANDOM_BLOCK_STORAGE + struct i2o_device *i2o_dev = dev->i2o_dev; + struct i2o_controller *c = i2o_dev->iop; + struct i2o_message *msg; + u32 m; + int rc; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_POWER << 24 | HOST_TID << 12 | i2o_dev->lct_data. + tid, &msg->u.head[1]); + writel(op << 24, &msg->body[0]); + pr_debug("Power...\n"); + + rc = i2o_msg_post_wait(c, m, 60); + if (!rc) + dev->power = op; + + return rc; }; /** - * i2ob_get - Get an I2O message - * @dev: I2O block device + * i2o_block_request_alloc - Allocate an I2O block request struct + * + * Allocates an I2O block request struct and initialize the list. * - * Get a message from the FIFO used for this block device. The message is returned - * or the I2O 'no message' value of 0xFFFFFFFF if nothing is available. + * Returns a i2o_block_request pointer on success or negative error code + * on failure. */ +static inline struct i2o_block_request *i2o_block_request_alloc(void) +{ + struct i2o_block_request *ireq; + + ireq = mempool_alloc(i2o_blk_req_pool.pool, GFP_ATOMIC); + if (!ireq) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&ireq->queue); + + return ireq; +}; -static u32 i2ob_get(struct i2ob_device *dev) +/** + * i2o_block_request_free - Frees a I2O block request + * @ireq: I2O block request which should be freed + * + * Fres the allocated memory (give it back to the request mempool). + */ +static inline void i2o_block_request_free(struct i2o_block_request *ireq) { - struct i2o_controller *c=dev->controller; - return I2O_POST_READ32(c); -} + mempool_free(ireq, i2o_blk_req_pool.pool); +}; -static int i2ob_build_sglist(struct i2ob_device *dev, struct i2ob_request *ireq) +/** + * i2o_block_sglist_alloc - Allocate the SG list and map it + * @ireq: I2O block request + * + * Builds the SG list and map it into to be accessable by the controller. + * + * Returns the number of elements in the SG list or 0 on failure. + */ +static inline int i2o_block_sglist_alloc(struct i2o_block_request *ireq) { - struct scatterlist *sg = ireq->sg_table; + struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev; int nents; - nents = blk_rq_map_sg(dev->req_queue, ireq->req, ireq->sg_table); - + nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table); + if (rq_data_dir(ireq->req) == READ) ireq->sg_dma_direction = PCI_DMA_FROMDEVICE; else ireq->sg_dma_direction = PCI_DMA_TODEVICE; - ireq->sg_nents = pci_map_sg(dev->controller->pdev, sg, nents, ireq->sg_dma_direction); + ireq->sg_nents = dma_map_sg(dev, ireq->sg_table, nents, + ireq->sg_dma_direction); + return ireq->sg_nents; -} +}; -void i2ob_free_sglist(struct i2ob_device *dev, struct i2ob_request *ireq) -{ - struct pci_dev *pdev = dev->controller->pdev; - struct scatterlist *sg = ireq->sg_table; - int nents = ireq->sg_nents; - pci_unmap_sg(pdev, sg, nents, ireq->sg_dma_direction); -} - /** - * i2ob_send - Turn a request into a message and send it - * @m: Message offset - * @dev: I2O device - * @ireq: Request structure - * @unit: Device identity - * - * Generate an I2O BSAREAD request. This interface function is called for devices that - * appear to explode when they are fed indirect chain pointers (notably right now this - * appears to afflict Promise hardwre, so be careful what you feed the hardware - * - * No cleanup is done by this interface. It is done on the interrupt side when the - * reply arrives - */ - -static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, int unit) -{ - struct i2o_controller *c = dev->controller; - int tid = dev->tid; - void *msg; - void *mptr; - u64 offset; - struct request *req = ireq->req; - int count = req->nr_sectors<<9; - struct scatterlist *sg; - int sgnum; - int i; + * i2o_block_sglist_free - Frees the SG list + * @ireq: I2O block request from which the SG should be freed + * + * Frees the SG list from the I2O block request. + */ +static inline void i2o_block_sglist_free(struct i2o_block_request *ireq) +{ + struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev; - // printk(KERN_INFO "i2ob_send called\n"); - /* Map the message to a virtual address */ - msg = c->msg_virt + m; - - sgnum = i2ob_build_sglist(dev, ireq); - - /* FIXME: if we have no resources how should we get out of this */ - if(sgnum == 0) - BUG(); - - /* - * Build the message based on the request. - */ - i2o_raw_writel(i2ob_context|(unit<<8), msg+8); - i2o_raw_writel(ireq->num, msg+12); - i2o_raw_writel(req->nr_sectors << 9, msg+20); + dma_unmap_sg(dev, ireq->sg_table, ireq->sg_nents, + ireq->sg_dma_direction); +}; - /* - * Mask out partitions from now on - */ - - /* This can be optimised later - just want to be sure its right for - starters */ - offset = ((u64)req->sector) << 9; - i2o_raw_writel( offset & 0xFFFFFFFF, msg+24); - i2o_raw_writel(offset>>32, msg+28); - mptr=msg+32; - - sg = ireq->sg_table; - if(rq_data_dir(req) == READ) - { - DEBUG("READ\n"); - i2o_raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); - for(i = sgnum; i > 0; i--) - { - if(i != 1) - i2o_raw_writel(0x10000000|sg_dma_len(sg), mptr); - else - i2o_raw_writel(0xD0000000|sg_dma_len(sg), mptr); - i2o_raw_writel(sg_dma_address(sg), mptr+4); - mptr += 8; - count -= sg_dma_len(sg); - sg++; - } - switch(dev->rcache) - { - case CACHE_NULL: - i2o_raw_writel(0, msg+16);break; - case CACHE_PREFETCH: - i2o_raw_writel(0x201F0008, msg+16);break; - case CACHE_SMARTFETCH: - if(req->nr_sectors > 16) - i2o_raw_writel(0x201F0008, msg+16); - else - i2o_raw_writel(0x001F0000, msg+16); - break; - } - -// printk("Reading %d entries %d bytes.\n", -// mptr-msg-8, req->nr_sectors<<9); - } - else if(rq_data_dir(req) == WRITE) - { - DEBUG("WRITE\n"); - i2o_raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); - for(i = sgnum; i > 0; i--) - { - if(i != 1) - i2o_raw_writel(0x14000000|sg_dma_len(sg), mptr); - else - i2o_raw_writel(0xD4000000|sg_dma_len(sg), mptr); - i2o_raw_writel(sg_dma_address(sg), mptr+4); - mptr += 8; - count -= sg_dma_len(sg); - sg++; - } +/** + * i2o_block_prep_req_fn - Allocates I2O block device specific struct + * @q: request queue for the request + * @req: the request to prepare + * + * Allocate the necessary i2o_block_request struct and connect it to + * the request. This is needed that we not loose the SG list later on. + * + * Returns BLKPREP_OK on success or BLKPREP_DEFER on failure. + */ +static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) +{ + struct i2o_block_device *i2o_blk_dev = q->queuedata; + struct i2o_block_request *ireq; - switch(dev->wcache) - { - case CACHE_NULL: - i2o_raw_writel(0, msg+16);break; - case CACHE_WRITETHROUGH: - i2o_raw_writel(0x001F0008, msg+16);break; - case CACHE_WRITEBACK: - i2o_raw_writel(0x001F0010, msg+16);break; - case CACHE_SMARTBACK: - if(req->nr_sectors > 16) - i2o_raw_writel(0x001F0004, msg+16); - else - i2o_raw_writel(0x001F0010, msg+16); - break; - case CACHE_SMARTTHROUGH: - if(req->nr_sectors > 16) - i2o_raw_writel(0x001F0004, msg+16); - else - i2o_raw_writel(0x001F0010, msg+16); + /* request is already processed by us, so return */ + if (req->flags & REQ_SPECIAL) { + pr_debug("REQ_SPECIAL already set!\n"); + req->flags |= REQ_DONTPREP; + return BLKPREP_OK; + } + + /* connect the i2o_block_request to the request */ + if (!req->special) { + ireq = i2o_block_request_alloc(); + if (unlikely(IS_ERR(ireq))) { + pr_debug("unable to allocate i2o_block_request!\n"); + return BLKPREP_DEFER; } - -// printk("Writing %d entries %d bytes.\n", -// mptr-msg-8, req->nr_sectors<<9); - } - i2o_raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); - - if(count != 0) - { - printk(KERN_ERR "Request count botched by %d.\n", count); - } - i2o_post_message(c,m); - i2ob_queues[c->unit]->queue_depth ++; + ireq->i2o_blk_dev = i2o_blk_dev; + req->special = ireq; + ireq->req = req; + } else + ireq = req->special; - return 0; -} + /* do not come back here */ + req->flags |= REQ_DONTPREP | REQ_SPECIAL; -/* - * Remove a request from the _locked_ request list. We update both the - * list chain and if this is the last item the tail pointer. Caller - * must hold the lock. - */ - -static inline void i2ob_unhook_request(struct i2ob_request *ireq, - unsigned int iop) -{ - ireq->next = i2ob_queues[iop]->i2ob_qhead; - i2ob_queues[iop]->i2ob_qhead = ireq; -} + return BLKPREP_OK; +}; -/* - * Request completion handler +/** + * i2o_block_delayed_request_fn - delayed request queue function + * delayed_request: the delayed request with the queue to start + * + * If the request queue is stopped for a disk, and there is no open + * request, a new event is created, which calls this function to start + * the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never + * be started again. */ - -static inline void i2ob_end_request(struct request *req) +static void i2o_block_delayed_request_fn(void *delayed_request) { - /* FIXME - pci unmap the request */ - - /* - * Loop until all of the buffers that are linked - * to this request have been marked updated and - * unlocked. - */ - - while (end_that_request_first( req, !req->errors, req->hard_cur_sectors )); + struct i2o_block_delayed_request *dreq = delayed_request; + struct request_queue *q = dreq->queue; + unsigned long flags; - /* - * It is now ok to complete the request. - */ - end_that_request_last( req ); - DEBUG("IO COMPLETED\n"); -} + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + kfree(dreq); +}; -/* - * OSM reply handler. This gets all the message replies +/** + * i2o_block_reply - Block OSM reply handler. + * @c: I2O controller from which the message arrives + * @m: message id of reply + * qmsg: the actuall I2O message reply + * + * This function gets all the message replies. + * */ - -static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +static int i2o_block_reply(struct i2o_controller *c, u32 m, + struct i2o_message *msg) { - unsigned long flags; - struct i2ob_request *ireq = NULL; + struct i2o_block_request *ireq; + struct request *req; + struct i2o_block_device *dev; + struct request_queue *q; u8 st; - u32 *m = (u32 *)msg; - u8 unit = m[2]>>8; - struct i2ob_device *dev = &i2ob_dev[unit]; + unsigned long flags; - /* - * FAILed message - */ - if(m[0] & (1<<13)) - { - DEBUG("FAIL"); + /* FAILed message */ + if (unlikely(readl(&msg->u.head[0]) & (1 << 13))) { + struct i2o_message *pmsg; + u32 pm; + + printk(KERN_WARNING "FAIL"); /* * FAILed message from controller * We increment the error count and abort it @@ -468,65 +431,85 @@ * better be on the safe side since no one really follows * the spec to the book :) */ - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - ireq->req->errors++; + pm = readl(&msg->body[3]); + pmsg = c->in_queue.virt + pm; + + req = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt)); + if (unlikely(!req)) { + printk(KERN_ERR "block-osm: NULL reply received!\n"); + return -1; + } + + ireq = req->special; + dev = ireq->i2o_blk_dev; + q = dev->gd->queue; + + req->errors++; + + spin_lock_irqsave(q->queue_lock, flags); + + while (end_that_request_chunk(req, !req->errors, + readl(&pmsg->body[1]))) ; + end_that_request_last(req); + + dev->open_queue_depth--; + list_del(&ireq->queue); + blk_start_queue(q); + + spin_unlock_irqrestore(q->queue_lock, flags); - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); - /* Now flush the message by making it a NOP */ - m[0]&=0x00FFFFFF; - m[0]|=(I2O_CMD_UTIL_NOP)<<24; - i2o_post_message(c, (unsigned long) m - (unsigned long) c->msg_virt); + i2o_msg_nop(c, pm); - return; + return -1; } - if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) - { - spin_lock(&i2ob_evt_lock); - memcpy(evt_msg, msg, (m[0]>>16)<<2); - spin_unlock(&i2ob_evt_lock); - up(&i2ob_evt_sem); - return; + req = i2o_cntxt_list_get(c, readl(&msg->u.s.tcntxt)); + if (unlikely(!req)) { + printk(KERN_ERR "block-osm: NULL reply received!\n"); + return -1; } - if(!dev->i2odev) - { + ireq = req->special; + dev = ireq->i2o_blk_dev; + q = dev->gd->queue; + + if (unlikely(!dev->i2o_dev)) { /* * This is HACK, but Intel Integrated RAID allows user - * to delete a volume that is claimed, locked, and in use + * to delete a volume that is claimed, locked, and in use * by the OS. We have to check for a reply from a - * non-existent device and flag it as an error or the system + * non-existent device and flag it as an error or the system * goes kaput... */ - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - ireq->req->errors++; - printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n"); - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); - return; - } + req->errors++; + printk(KERN_WARNING + "I2O Block: Data transfer to deleted device!\n"); + spin_lock_irqsave(q->queue_lock, flags); + while (end_that_request_chunk + (req, !req->errors, readl(&msg->body[1]))) ; + end_that_request_last(req); + + dev->open_queue_depth--; + list_del(&ireq->queue); + blk_start_queue(q); + + spin_unlock_irqrestore(q->queue_lock, flags); + return -1; + } /* - * Lets see what is cooking. We stuffed the - * request in the context. + * Lets see what is cooking. We stuffed the + * request in the context. */ - - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - st=m[4]>>24; - if(st!=0) - { + st = readl(&msg->body[0]) >> 24; + + if (st != 0) { int err; - char *bsa_errors[] = - { - "Success", - "Media Error", + char *bsa_errors[] = { + "Success", + "Media Error", "Failure communicating to device", "Device Failure", "Device is not ready", @@ -540,61 +523,62 @@ "Device has reset", "Volume has changed, waiting for acknowledgement" }; - - err = m[4]&0xFFFF; - + + err = readl(&msg->body[0]) & 0xffff; + /* - * Device not ready means two things. One is that the - * the thing went offline (but not a removal media) + * Device not ready means two things. One is that the + * the thing went offline (but not a removal media) * - * The second is that you have a SuperTrak 100 and the - * firmware got constipated. Unlike standard i2o card - * setups the supertrak returns an error rather than - * blocking for the timeout in these cases. + * The second is that you have a SuperTrak 100 and the + * firmware got constipated. Unlike standard i2o card + * setups the supertrak returns an error rather than + * blocking for the timeout in these cases. * - * Don't stick a supertrak100 into cache aggressive modes + * Don't stick a supertrak100 into cache aggressive modes */ - - - printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, - bsa_errors[m[4]&0XFFFF]); - if(m[4]&0x00FF0000) - printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); + + printk(KERN_ERR "\n/dev/%s error: %s", dev->gd->disk_name, + bsa_errors[readl(&msg->body[0]) & 0xffff]); + if (readl(&msg->body[0]) & 0x00ff0000) + printk(" - DDM attempted %d retries", + (readl(&msg->body[0]) >> 16) & 0x00ff); printk(".\n"); - ireq->req->errors++; - } - else - ireq->req->errors = 0; + req->errors++; + } else + req->errors = 0; - /* - * Dequeue the request. We use irqsave locks as one day we - * may be running polled controllers from a BH... - */ - - i2ob_free_sglist(dev, ireq); - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - i2ob_queues[c->unit]->queue_depth --; - - /* - * We may be able to do more I/O - */ - - i2ob_request(dev->gd->queue); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); -} + if (!end_that_request_chunk(req, !req->errors, readl(&msg->body[1]))) { + add_disk_randomness(req->rq_disk); + spin_lock_irqsave(q->queue_lock, flags); -/* - * Event handler. Needs to be a separate thread b/c we may have - * to do things like scan a partition table, or query parameters - * which cannot be done from an interrupt or from a bottom half. - */ -static int i2ob_evt(void *dummy) + end_that_request_last(req); + + dev->open_queue_depth--; + list_del(&ireq->queue); + blk_start_queue(q); + + spin_unlock_irqrestore(q->queue_lock, flags); + + i2o_block_sglist_free(ireq); + i2o_block_request_free(ireq); + } else + printk(KERN_ERR "still remaining chunks\n"); + + return 1; +}; + +static void i2o_block_event(struct i2o_event *evt) +{ + printk(KERN_INFO "block-osm: event received\n"); +}; + +#if 0 +static int i2o_block_event(void *dummy) { unsigned int evt; unsigned long flags; - struct i2ob_device *dev; + struct i2o_block_device *dev; int unit; //The only event that has data is the SCSI_SMART event. struct i2o_reply { @@ -604,24 +588,22 @@ u8 ASCQ; u16 pad; u8 data[16]; - } *evt_local; + } *evt_local; daemonize("i2oblock"); allow_signal(SIGKILL); evt_running = 1; - while(1) - { - if(down_interruptible(&i2ob_evt_sem)) - { + while (1) { + if (down_interruptible(&i2ob_evt_sem)) { evt_running = 0; printk("exiting..."); break; } /* - * Keep another CPU/interrupt from overwriting the + * Keep another CPU/interrupt from overwriting the * message while we're reading it * * We stuffed the unit in the TxContext and grab the event mask @@ -634,20 +616,19 @@ unit = le32_to_cpu(evt_local->header[3]); evt = le32_to_cpu(evt_local->evt_indicator); - dev = &i2ob_dev[unit]; - switch(evt) - { + dev = &i2o_blk_dev[unit]; + switch (evt) { /* * New volume loaded on same TID, so we just re-install. * The TID/controller don't change as it is the same * I2O device. It's just new media that we have to * rescan. */ - case I2O_EVT_IND_BSA_VOLUME_LOAD: + case I2O_EVT_IND_BSA_VOLUME_LOAD: { - i2ob_install_device(dev->i2odev->controller, - dev->i2odev, unit); - add_disk(dev->gd); + i2ob_install_device(dev->i2o_device->iop, + dev->i2o_device, unit); + add_disk(dev->gendisk); break; } @@ -657,144 +638,108 @@ * have media, so we don't want to clear the controller or * device pointer. */ - case I2O_EVT_IND_BSA_VOLUME_UNLOAD: + case I2O_EVT_IND_BSA_VOLUME_UNLOAD: { - struct gendisk *p = dev->gd; - blk_queue_max_sectors(dev->gd->queue, 0); + struct gendisk *p = dev->gendisk; + blk_queue_max_sectors(dev->gendisk->queue, 0); del_gendisk(p); put_disk(p); - dev->gd = NULL; + dev->gendisk = NULL; dev->media_change_flag = 1; break; } - case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: - printk(KERN_WARNING "%s: Attempt to eject locked media\n", - dev->i2odev->dev_name); - break; + case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: + printk(KERN_WARNING + "%s: Attempt to eject locked media\n", + dev->i2o_device->dev_name); + break; /* * The capacity has changed and we are going to be - * updating the max_sectors and other information + * updating the max_sectors and other information * about this disk. We try a revalidate first. If * the block device is in use, we don't want to * do that as there may be I/Os bound for the disk - * at the moment. In that case we read the size + * at the moment. In that case we read the size * from the device and update the information ourselves * and the user can later force a partition table * update through an ioctl. */ - case I2O_EVT_IND_BSA_CAPACITY_CHANGE: + case I2O_EVT_IND_BSA_CAPACITY_CHANGE: { u64 size; - if(i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) - i2ob_query_device(dev, 0x0000, 4, &size, 8); - - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - set_capacity(dev->gd, size>>9); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); + if (i2ob_query_device(dev, 0x0004, 0, &size, 8) + != 0) + i2ob_query_device(dev, 0x0000, 4, &size, + 8); + + spin_lock_irqsave(dev->req_queue->queue_lock, + flags); + set_capacity(dev->gendisk, size >> 9); + spin_unlock_irqrestore(dev->req_queue-> + queue_lock, flags); break; } - /* + /* * We got a SCSI SMART event, we just log the relevant * information and let the user decide what they want * to do with the information. */ - case I2O_EVT_IND_BSA_SCSI_SMART: + case I2O_EVT_IND_BSA_SCSI_SMART: { char buf[16]; - printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",dev->i2odev->dev_name); - evt_local->data[16]='\0'; - sprintf(buf,"%s",&evt_local->data[0]); - printk(KERN_INFO " Disk Serial#:%s\n",buf); - printk(KERN_INFO " ASC 0x%02x \n",evt_local->ASC); - printk(KERN_INFO " ASCQ 0x%02x \n",evt_local->ASCQ); + printk(KERN_INFO + "I2O Block: %s received a SCSI SMART Event\n", + dev->i2o_device->dev_name); + evt_local->data[16] = '\0'; + sprintf(buf, "%s", &evt_local->data[0]); + printk(KERN_INFO " Disk Serial#:%s\n", + buf); + printk(KERN_INFO " ASC 0x%02x \n", + evt_local->ASC); + printk(KERN_INFO " ASCQ 0x%02x \n", + evt_local->ASCQ); break; } - + /* - * Non event + * Non event */ - - case 0: - break; - + + case 0: + break; + /* * An event we didn't ask for. Call the card manufacturer * and tell them to fix their firmware :) */ - - case 0x20: - /* - * If a promise card reports 0x20 event then the brown stuff - * hit the fan big time. The card seems to recover but loses - * the pending writes. Deeply ungood except for testing fsck - */ - if(dev->i2odev->controller->promise) - panic("I2O controller firmware failed. Reboot and force a filesystem check.\n"); - default: - printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n" - KERN_INFO " Blame the I2O card manufacturer 8)\n", - dev->i2odev->dev_name, evt); - break; - } - }; - - complete_and_exit(&i2ob_thread_dead,0); - return 0; -} - -/* - * The I2O block driver is listed as one of those that pulls the - * front entry off the queue before processing it. This is important - * to remember here. If we drop the io lock then CURRENT will change - * on us. We must unlink CURRENT in this routine before we return, if - * we use it. - */ - -static void i2ob_request(request_queue_t *q) -{ - struct request *req; - struct i2ob_request *ireq; - struct i2ob_device *dev; - u32 m; - - while ((req = elv_next_request(q)) != NULL) { - dev = req->rq_disk->private_data; - - /* - * Queue depths probably belong with some kind of - * generic IOP commit control. Certainly it's not right - * its global! - */ - if(i2ob_queues[dev->unit]->queue_depth >= dev->depth) - break; - - /* Get a message */ - m = i2ob_get(dev); - if(m==0xFFFFFFFF) - { - if(i2ob_queues[dev->unit]->queue_depth == 0) - printk(KERN_ERR "i2o_block: message queue and request queue empty!!\n"); + case 0x20: + /* + * If a promise card reports 0x20 event then the brown stuff + * hit the fan big time. The card seems to recover but loses + * the pending writes. Deeply ungood except for testing fsck + */ + if (dev->i2o_device->iop->promise) + panic + ("I2O controller firmware failed. Reboot and force a filesystem check.\n"); + default: + printk(KERN_INFO + "%s: Received event 0x%X we didn't register for\n" + KERN_INFO + " Blame the I2O card manufacturer 8)\n", + dev->i2o_device->dev_name, evt); break; } - /* - * Everything ok, so pull from kernel queue onto our queue - */ - req->errors = 0; - blkdev_dequeue_request(req); - - ireq = i2ob_queues[dev->unit]->i2ob_qhead; - i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; - ireq->req = req; + }; - i2ob_send(m, dev, ireq, dev->index); - } + complete_and_exit(&i2ob_thread_dead, 0); + return 0; } - +#endif /* * SCSI-CAM for ioctl geometry mapping @@ -803,8 +748,8 @@ * * LBA -> CHS mapping table taken from: * - * "Incorporating the I2O Architecture into BIOS for Intel Architecture - * Platforms" + * "Incorporating the I2O Architecture into BIOS for Intel Architecture + * Platforms" * * This is an I2O document that is only available to I2O members, * not developers. @@ -825,865 +770,647 @@ #define BLOCK_SIZE_42G 8806400 #define BLOCK_SIZE_84G 17612800 -static void i2o_block_biosparam( - unsigned long capacity, - unsigned short *cyls, - unsigned char *hds, - unsigned char *secs) -{ - unsigned long heads, sectors, cylinders; +static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls, + unsigned char *hds, unsigned char *secs) +{ + unsigned long heads, sectors, cylinders; - sectors = 63L; /* Maximize sectors per track */ - if(capacity <= BLOCK_SIZE_528M) + sectors = 63L; /* Maximize sectors per track */ + if (capacity <= BLOCK_SIZE_528M) heads = 16; - else if(capacity <= BLOCK_SIZE_1G) + else if (capacity <= BLOCK_SIZE_1G) heads = 32; - else if(capacity <= BLOCK_SIZE_21G) + else if (capacity <= BLOCK_SIZE_21G) heads = 64; - else if(capacity <= BLOCK_SIZE_42G) + else if (capacity <= BLOCK_SIZE_42G) heads = 128; else heads = 255; cylinders = (unsigned long)capacity / (heads * sectors); - *cyls = (unsigned short) cylinders; /* Stuff return values */ - *secs = (unsigned char) sectors; - *hds = (unsigned char) heads; + *cyls = (unsigned short)cylinders; /* Stuff return values */ + *secs = (unsigned char)sectors; + *hds = (unsigned char)heads; } -/* - * Issue device specific ioctl calls. +/** + * i2o_block_open - Open the block device + * + * Power up the device, mount and lock the media. This function is called, + * if the block device is opened for access. + * + * Returns 0 on success or negative error code on failure. */ - -static int i2ob_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int i2o_block_open(struct inode *inode, struct file *file) { - struct gendisk *disk = inode->i_bdev->bd_disk; - struct i2ob_device *dev = disk->private_data; - void __user *argp = (void __user *)arg; + struct i2o_block_device *dev = inode->i_bdev->bd_disk->private_data; - /* Anyone capable of this syscall can do *real bad* things */ + if (!dev->i2o_dev) + return -ENODEV; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry g; - i2o_block_biosparam(get_capacity(disk), - &g.cylinders, &g.heads, &g.sectors); - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(argp, &g, sizeof(g))?-EFAULT:0; - } - - case BLKI2OGRSTRAT: - return put_user(dev->rcache, (int __user *)argp); - case BLKI2OGWSTRAT: - return put_user(dev->wcache, (int __user *)argp); - case BLKI2OSRSTRAT: - if(arg<0||arg>CACHE_SMARTFETCH) - return -EINVAL; - dev->rcache = arg; - break; - case BLKI2OSWSTRAT: - if(arg!=0 && (argCACHE_SMARTBACK)) - return -EINVAL; - dev->wcache = arg; - break; - } - return -ENOTTY; -} + if (dev->power > 0x1f) + i2o_block_device_power(dev, 0x02); -/* - * Close the block device down + i2o_block_device_mount(dev->i2o_dev, -1); + + i2o_block_device_lock(dev->i2o_dev, -1); + + pr_debug("Ready.\n"); + + return 0; +}; + +/** + * i2o_block_release - Release the I2O block device + * + * Unlock and unmount the media, and power down the device. Gets called if + * the block device is closed. + * + * Returns 0 on success or negative error code on failure. */ - -static int i2ob_release(struct inode *inode, struct file *file) +static int i2o_block_release(struct inode *inode, struct file *file) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct i2ob_device *dev = disk->private_data; + struct i2o_block_device *dev = disk->private_data; + u8 operation; /* * This is to deail with the case of an application * opening a device and then the device dissapears while * it's in use, and then the application tries to release - * it. ex: Unmounting a deleted RAID volume at reboot. + * it. ex: Unmounting a deleted RAID volume at reboot. * If we send messages, it will just cause FAILs since * the TID no longer exists. */ - if(!dev->i2odev) + if (!dev->i2o_dev) return 0; - if (dev->refcnt <= 0) - printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); - dev->refcnt--; - if(dev->refcnt==0) - { - /* - * Flush the onboard cache on unmount - */ - u32 msg[5]; - int *query_done = &dev->done_flag; - msg[0] = (FIVE_WORD_MSG_SIZE|SGL_OFFSET_0); - msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = 60<<16; - DEBUG("Flushing..."); - i2o_post_wait(dev->controller, msg, 20, 60); + i2o_block_device_flush(dev->i2o_dev); - /* - * Unlock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = -1; - DEBUG("Unlocking..."); - i2o_post_wait(dev->controller, msg, 20, 2); - DEBUG("Unlocked.\n"); - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid; - if(dev->flags & (1<<3|1<<4)) /* Removable */ - msg[4] = 0x21 << 24; - else - msg[4] = 0x24 << 24; + i2o_block_device_unlock(dev->i2o_dev, -1); - if(i2o_post_wait(dev->controller, msg, 20, 60)==0) - dev->power = 0x24; + if (dev->flags & (1 << 3 | 1 << 4)) /* Removable */ + operation = 0x21; + else + operation = 0x24; - /* - * Now unclaim the device. - */ + i2o_block_device_power(dev, operation); - if (i2o_release_device(dev->i2odev, &i2o_block_handler)) - printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); - - DEBUG("Unclaim\n"); - } return 0; } -/* - * Open the block device. +/** + * i2o_block_ioctl - Issue device specific ioctl calls. + * @cmd: ioctl command + * @arg: arg + * + * Handles ioctl request for the block device. + * + * Return 0 on success or negative error on failure. */ - -static int i2ob_open(struct inode *inode, struct file *file) +static int i2o_block_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct i2ob_device *dev = disk->private_data; + struct i2o_block_device *dev = disk->private_data; + void __user *argp = (void __user *)arg; - if(!dev->i2odev) - return -ENODEV; - - if(dev->refcnt++==0) - { - u32 msg[6]; - - DEBUG("Claim "); - if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) - { - dev->refcnt--; - printk(KERN_INFO "I2O Block: Could not open device\n"); - return -EBUSY; - } - DEBUG("Claimed "); - /* - * Power up if needed - */ + /* Anyone capable of this syscall can do *real bad* things */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; - if(dev->power > 0x1f) + switch (cmd) { + case HDIO_GETGEO: { - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid; - msg[4] = 0x02 << 24; - if(i2o_post_wait(dev->controller, msg, 20, 60) == 0) - dev->power = 0x02; + struct hd_geometry g; + i2o_block_biosparam(get_capacity(disk), + &g.cylinders, &g.heads, &g.sectors); + g.start = get_start_sect(inode->i_bdev); + return copy_to_user(argp, &g, sizeof(g)) ? -EFAULT : 0; } - /* - * Mount the media if needed. Note that we don't use - * the lock bit. Since we have to issue a lock if it - * refuses a mount (quite possible) then we might as - * well just send two messages out. - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; - msg[4] = -1; - msg[5] = 0; - DEBUG("Mount "); - i2o_post_wait(dev->controller, msg, 24, 2); - - /* - * Lock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; - msg[4] = -1; - DEBUG("Lock "); - i2o_post_wait(dev->controller, msg, 20, 2); - DEBUG("Ready.\n"); - } - return 0; -} + case BLKI2OGRSTRAT: + return put_user(dev->rcache, (int __user *)arg); + case BLKI2OGWSTRAT: + return put_user(dev->wcache, (int __user *)arg); + case BLKI2OSRSTRAT: + if (arg < 0 || arg > CACHE_SMARTFETCH) + return -EINVAL; + dev->rcache = arg; + break; + case BLKI2OSWSTRAT: + if (arg != 0 + && (arg < CACHE_WRITETHROUGH || arg > CACHE_SMARTBACK)) + return -EINVAL; + dev->wcache = arg; + break; + } + return -ENOTTY; +}; -/* - * Issue a device query +/** + * i2o_block_media_changed - Have we seen a media change? + * @disk: gendisk which should be verified + * + * Verifies if the media has changed. + * + * Returns 1 if the media was changed or 0 otherwise. */ - -static int i2ob_query_device(struct i2ob_device *dev, int table, - int field, void *buf, int buflen) +static int i2o_block_media_changed(struct gendisk *disk) { - return i2o_query_scalar(dev->controller, dev->tid, - table, field, buf, buflen); -} + struct i2o_block_device *p = disk->private_data; + if (p->media_change_flag) { + p->media_change_flag = 0; + return 1; + } + return 0; +} -/* - * Install the I2O block device we found. +/** + * i2o_block_transfer - Transfer a request to/from the I2O controller + * @req: the request which should be transfered + * + * This function converts the request into a I2O message. The necessary + * DMA buffers are allocated and after everything is setup post the message + * to the I2O controller. No cleanup is done by this function. It is done + * on the interrupt side when the reply arrives. + * + * Return 0 on success or negative error code on failure. */ - -static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit) +static int i2o_block_transfer(struct request *req) { - u64 size; - u32 blocksize; - u8 type; - u16 power; - u32 flags, status; - struct i2ob_device *dev=&i2ob_dev[unit]; - struct gendisk *disk; - request_queue_t *q; - int segments; + struct i2o_block_device *dev = req->rq_disk->private_data; + struct i2o_controller *c = dev->i2o_dev->iop; + int tid = dev->i2o_dev->lct_data.tid; + struct i2o_message *msg; + void *mptr; + struct i2o_block_request *ireq = req->special; + struct scatterlist *sg; + int sgnum; + int i; + u32 m; + u32 tcntxt; + u32 sg_flags; + int rc; + m = i2o_msg_get(c, &msg); + if (m == I2O_QUEUE_EMPTY) { + rc = -EBUSY; + goto exit; + } - /* - * For logging purposes... - */ - printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", - d->lct_data.tid, unit); + tcntxt = i2o_cntxt_list_add(c, req); + if (!tcntxt) { + rc = -ENOMEM; + goto nop_msg; + } - /* - * If this is the first I2O block device found on this IOP, - * we need to initialize all the queue data structures - * before any I/O can be performed. If it fails, this - * device is useless. - */ - if(!i2ob_queues[c->unit]) { - if(i2ob_init_iop(c->unit)) - return 1; + if ((sgnum = i2o_block_sglist_alloc(ireq)) <= 0) { + rc = -ENOMEM; + goto context_remove; } - q = i2ob_queues[c->unit]->req_queue; + /* Build the message based on the request. */ + writel(i2o_block_driver.context, &msg->u.s.icntxt); + writel(tcntxt, &msg->u.s.tcntxt); + writel(req->nr_sectors << 9, &msg->body[1]); - /* - * This will save one level of lookup/indirection in critical - * code so that we can directly get the queue ptr from the - * device instead of having to go the IOP data structure. - */ - dev->req_queue = q; + writel((((u64) req->sector) << 9) & 0xffffffff, &msg->body[2]); + writel(req->sector >> 23, &msg->body[3]); - /* - * Allocate a gendisk structure and initialize it - */ - disk = alloc_disk(16); - if (!disk) - return 1; + mptr = &msg->body[4]; - dev->gd = disk; - /* initialize gendik structure */ - disk->major = MAJOR_NR; - disk->first_minor = unit<<4; - disk->queue = q; - disk->fops = &i2ob_fops; - sprintf(disk->disk_name, "i2o/hd%c", 'a' + unit); - disk->private_data = dev; + sg = ireq->sg_table; - /* - * Ask for the current media data. If that isn't supported - * then we ask for the device capacity data - */ - if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 - || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) - { - i2ob_query_device(dev, 0x0000, 3, &blocksize, 4); - i2ob_query_device(dev, 0x0000, 4, &size, 8); + if (rq_data_dir(req) == READ) { + writel(I2O_CMD_BLOCK_READ << 24 | HOST_TID << 12 | tid, + &msg->u.head[1]); + sg_flags = 0x10000000; + switch (dev->rcache) { + case CACHE_NULL: + writel(0, &msg->body[0]); + break; + case CACHE_PREFETCH: + writel(0x201F0008, &msg->body[0]); + break; + case CACHE_SMARTFETCH: + if (req->nr_sectors > 16) + writel(0x201F0008, &msg->body[0]); + else + writel(0x001F0000, &msg->body[0]); + break; + } + } else { + writel(I2O_CMD_BLOCK_WRITE << 24 | HOST_TID << 12 | tid, + &msg->u.head[1]); + sg_flags = 0x14000000; + switch (dev->wcache) { + case CACHE_NULL: + writel(0, &msg->body[0]); + break; + case CACHE_WRITETHROUGH: + writel(0x001F0008, &msg->body[0]); + break; + case CACHE_WRITEBACK: + writel(0x001F0010, &msg->body[0]); + break; + case CACHE_SMARTBACK: + if (req->nr_sectors > 16) + writel(0x001F0004, &msg->body[0]); + else + writel(0x001F0010, &msg->body[0]); + break; + case CACHE_SMARTTHROUGH: + if (req->nr_sectors > 16) + writel(0x001F0004, &msg->body[0]); + else + writel(0x001F0010, &msg->body[0]); + } } - - if(i2ob_query_device(dev, 0x0000, 2, &power, 2)!=0) - power = 0; - i2ob_query_device(dev, 0x0000, 5, &flags, 4); - i2ob_query_device(dev, 0x0000, 6, &status, 4); - set_capacity(disk, size>>9); - /* - * Max number of Scatter-Gather Elements - */ + for (i = sgnum; i > 0; i--) { + if (i == 1) + sg_flags |= 0x80000000; + writel(sg_flags | sg_dma_len(sg), mptr); + writel(sg_dma_address(sg), mptr + 4); + mptr += 8; + sg++; + } + + writel(I2O_MESSAGE_SIZE + (((unsigned long)mptr - + (unsigned long)&msg->u.head[0]) >> 2) | SGL_OFFSET_8, + &msg->u.head[0]); - dev->power = power; /* Save power state in device proper */ - dev->flags = flags; + i2o_msg_post(c, m); - segments = (d->controller->status_block->inbound_frame_size - 7) / 2; + list_add_tail(&ireq->queue, &dev->open_queue); + dev->open_queue_depth++; - if(segments > 16) - segments = 16; - - dev->power = power; /* Save power state */ - dev->flags = flags; /* Keep the type info */ - - blk_queue_max_sectors(q, 96); /* 256 might be nicer but many controllers - explode on 65536 or higher */ - blk_queue_max_phys_segments(q, segments); - blk_queue_max_hw_segments(q, segments); - - dev->rcache = CACHE_SMARTFETCH; - dev->wcache = CACHE_WRITETHROUGH; - - if(d->controller->battery == 0) - dev->wcache = CACHE_WRITETHROUGH; - - if(d->controller->promise) - dev->wcache = CACHE_WRITETHROUGH; - - if(d->controller->short_req) - { - blk_queue_max_sectors(q, 8); - blk_queue_max_phys_segments(q, 8); - blk_queue_max_hw_segments(q, 8); - } - - strcpy(d->dev_name, disk->disk_name); - strcpy(disk->devfs_name, disk->disk_name); - - printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n", - d->dev_name, dev->max_segments, dev->depth, dev->max_sectors<<9); - - i2ob_query_device(dev, 0x0000, 0, &type, 1); - - printk(KERN_INFO "%s: ", d->dev_name); - switch(type) - { - case 0: printk("Disk Storage");break; - case 4: printk("WORM");break; - case 5: printk("CD-ROM");break; - case 7: printk("Optical device");break; - default: - printk("Type %d", type); - } - if(status&(1<<10)) - printk("(RAID)"); + return 0; - if((flags^status)&(1<<4|1<<3)) /* Missing media or device */ - { - printk(KERN_INFO " Not loaded.\n"); - /* Device missing ? */ - if((flags^status)&(1<<4)) - return 1; - } - else - { - printk(": %dMB, %d byte sectors", - (int)(size>>20), blocksize); - } - if(status&(1<<0)) - { - u32 cachesize; - i2ob_query_device(dev, 0x0003, 0, &cachesize, 4); - cachesize>>=10; - if(cachesize>4095) - printk(", %dMb cache", cachesize>>10); - else - printk(", %dKb cache", cachesize); - } - printk(".\n"); - printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", - d->dev_name, dev->max_sectors); + context_remove: + i2o_cntxt_list_remove(c, req); - /* - * Register for the events we're interested in and that the - * device actually supports. - */ + nop_msg: + i2o_msg_nop(c, m); - i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, - (I2OB_EVENT_MASK & d->lct_data.event_capabilities)); - return 0; -} + exit: + return rc; +}; -/* - * Initialize IOP specific queue structures. This is called - * once for each IOP that has a block device sitting behind it. +/** + * i2o_block_request_fn - request queue handling function + * q: request queue from which the request could be fetched + * + * Takes the next request from the queue, transfers it and if no error + * occurs dequeue it from the queue. On arrival of the reply the message + * will be processed further. If an error occurs requeue the request. */ -static int i2ob_init_iop(unsigned int unit) +static void i2o_block_request_fn(struct request_queue *q) { - int i; + struct request *req; - i2ob_queues[unit] = (struct i2ob_iop_queue *) kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); - if(!i2ob_queues[unit]) - { - printk(KERN_WARNING "Could not allocate request queue for I2O block device!\n"); - return -1; - } + while (!blk_queue_plugged(q)) { + req = elv_next_request(q); + if (!req) + break; - for(i = 0; i< MAX_I2OB_DEPTH; i++) - { - i2ob_queues[unit]->request_queue[i].next = &i2ob_queues[unit]->request_queue[i+1]; - i2ob_queues[unit]->request_queue[i].num = i; - } - - /* Queue is MAX_I2OB + 1... */ - i2ob_queues[unit]->request_queue[i].next = NULL; - i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0]; - i2ob_queues[unit]->queue_depth = 0; - - i2ob_queues[unit]->lock = SPIN_LOCK_UNLOCKED; - i2ob_queues[unit]->req_queue = blk_init_queue(i2ob_request, &i2ob_queues[unit]->lock); - if (!i2ob_queues[unit]->req_queue) { - kfree(i2ob_queues[unit]); - return -1; - } + if (blk_fs_request(req)) { + struct i2o_block_delayed_request *dreq; + struct i2o_block_request *ireq = req->special; + unsigned int queue_depth; + + queue_depth = ireq->i2o_blk_dev->open_queue_depth; + + if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) + if (!i2o_block_transfer(req)) { + blkdev_dequeue_request(req); + continue; + } - i2ob_queues[unit]->req_queue->queuedata = &i2ob_queues[unit]; + if (queue_depth) + break; - return 0; -} + /* stop the queue and retry later */ + dreq = kmalloc(sizeof(*dreq), GFP_ATOMIC); + if (!dreq) + continue; -/* - * Probe the I2O subsytem for block class devices + dreq->queue = q; + INIT_WORK(&dreq->work, i2o_block_delayed_request_fn, + dreq); + + printk(KERN_INFO "block-osm: transfer error\n"); + if (!queue_delayed_work(i2o_block_driver.event_queue, + &dreq->work, + I2O_BLOCK_RETRY_TIME)) + kfree(dreq); + else { + blk_stop_queue(q); + break; + } + } else + end_request(req, 0); + } +}; + +/* I2O Block device operations definition */ +static struct block_device_operations i2o_block_fops = { + .owner = THIS_MODULE, + .open = i2o_block_open, + .release = i2o_block_release, + .ioctl = i2o_block_ioctl, + .media_changed = i2o_block_media_changed +}; + +/** + * i2o_block_device_alloc - Allocate memory for a I2O Block device + * + * Allocate memory for the i2o_block_device struct, gendisk and request + * queue and initialize them as far as no additional information is needed. + * + * Returns a pointer to the allocated I2O Block device on succes or a + * negative error code on failure. */ -static void i2ob_scan(int bios) +static struct i2o_block_device *i2o_block_device_alloc(void) { - int i; - int warned = 0; + struct i2o_block_device *dev; + struct gendisk *gd; + struct request_queue *queue; + int rc; - struct i2o_device *d, *b=NULL; - struct i2o_controller *c; - - for(i=0; i< MAX_I2O_CONTROLLERS; i++) - { - c=i2o_find_controller(i); - - if(c==NULL) - continue; + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR "block-osm: Insufficient memory to allocate " + "I2O Block disk.\n"); + rc = -ENOMEM; + goto exit; + } + memset(dev, 0, sizeof(*dev)); - /* - * The device list connected to the I2O Controller is doubly linked - * Here we traverse the end of the list , and start claiming devices - * from that end. This assures that within an I2O controller atleast - * the newly created volumes get claimed after the older ones, thus - * mapping to same major/minor (and hence device file name) after - * every reboot. - * The exception being: - * 1. If there was a TID reuse. - * 2. There was more than one I2O controller. - */ + INIT_LIST_HEAD(&dev->open_queue); + spin_lock_init(&dev->lock); + dev->rcache = CACHE_PREFETCH; + dev->wcache = CACHE_WRITEBACK; - if(!bios) - { - for (d=c->devices;d!=NULL;d=d->next) - if(d->next == NULL) - b = d; - } - else - b = c->devices; + /* allocate a gendisk with 16 partitions */ + gd = alloc_disk(16); + if (!gd) { + printk(KERN_ERR "block-osm: Insufficient memory to allocate " + "gendisk.\n"); + rc = -ENOMEM; + goto cleanup_dev; + } - while(b != NULL) - { - d=b; - if(bios) - b = b->next; - else - b = b->prev; + /* initialize the request queue */ + queue = blk_init_queue(i2o_block_request_fn, &dev->lock); + if (!queue) { + printk(KERN_ERR "block-osm: Insufficient memory to allocate " + "request queue.\n"); + rc = -ENOMEM; + goto cleanup_queue; + } - if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) - continue; + blk_queue_prep_rq(queue, i2o_block_prep_req_fn); - if(d->lct_data.user_tid != 0xFFF) - continue; + gd->major = I2O_MAJOR; + gd->queue = queue; + gd->fops = &i2o_block_fops; + gd->private_data = dev; - if(bios) - { - if(d->lct_data.bios_info != 0x80) - continue; - printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid); - } - else - { - if(d->lct_data.bios_info == 0x80) - continue; /*Already claimed on pass 1 */ - } + dev->gd = gd; - if(scan_unitiop; + struct gendisk *gd; + struct request_queue *queue; + static int unit = 0; + int rc; + u64 size; + u32 blocksize; + u16 power; + u32 flags, status; + int segments; -/* - * New device notification handler. Called whenever a new - * I2O block storage device is added to the system. - * - * Should we spin lock around this to keep multiple devs from - * getting updated at the same time? - * - */ -void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d) -{ - struct i2ob_device *dev; - int unit = 0; - - printk(KERN_INFO "i2o_block: New device detected\n"); - printk(KERN_INFO " Controller %d Tid %d\n",c->unit, d->lct_data.tid); - - /* Check for available space */ - if(i2ob_dev_count>=MAX_I2OB) - { - printk(KERN_ERR "i2o_block: No more devices allowed!\n"); - return; - } - for(unit = 0; unit < MAX_I2OB; unit ++) - { - if(!i2ob_dev[unit].i2odev) - break; + /* skip devices which are used by IOP */ + if (i2o_dev->lct_data.user_tid != 0xfff) { + pr_debug("skipping used device %03x\n", i2o_dev->lct_data.tid); + return -ENODEV; } - if(i2o_claim_device(d, &i2o_block_handler)) - { - printk(KERN_INFO "i2o_block: Unable to claim device. Installation aborted\n"); - return; - } - - dev = &i2ob_dev[unit]; - dev->i2odev = d; - dev->controller = c; - dev->tid = d->lct_data.tid; - dev->unit = c->unit; - - if(i2ob_install_device(c,d,unit)) { - i2o_release_device(d, &i2o_block_handler); - printk(KERN_ERR "i2o_block: Could not install new device\n"); - } - else - { - i2o_release_device(d, &i2o_block_handler); - add_disk(dev->gd); - i2ob_dev_count++; - i2o_device_notify_on(d, &i2o_block_handler); + printk(KERN_INFO "block-osm: New device detected (TID: %03x)\n", + i2o_dev->lct_data.tid); + + if (i2o_device_claim(i2o_dev)) { + printk(KERN_WARNING "block-osm: Unable to claim device. " + "Installation aborted\n"); + rc = -EFAULT; + goto exit; } - return; -} + i2o_blk_dev = i2o_block_device_alloc(); + if (IS_ERR(i2o_blk_dev)) { + printk(KERN_ERR "block-osm: could not alloc a new I2O block" + "device"); + rc = PTR_ERR(i2o_blk_dev); + goto claim_release; + } -/* - * Deleted device notification handler. Called when a device we - * are talking to has been deleted by the user or some other - * mysterious fource outside the kernel. - */ -void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d) -{ - int unit = 0; - unsigned long flags; - struct i2ob_device *dev; + i2o_blk_dev->i2o_dev = i2o_dev; + dev_set_drvdata(dev, i2o_blk_dev); - for(unit = 0; unit < MAX_I2OB; unit ++) - { - dev = &i2ob_dev[unit]; - if(dev->i2odev == d) - { - printk(KERN_INFO " /dev/%s: Controller %d Tid %d\n", - d->dev_name, c->unit, d->lct_data.tid); - break; - } - } + /* setup gendisk */ + gd = i2o_blk_dev->gd; + gd->first_minor = unit << 4; + sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit); + sprintf(gd->devfs_name, "i2o/hd%c", 'a' + unit); + gd->driverfs_dev = &i2o_dev->device; + + /* setup request queue */ + queue = gd->queue; + queue->queuedata = i2o_blk_dev; + + blk_queue_max_phys_segments(queue, I2O_MAX_SEGMENTS); + blk_queue_max_sectors(queue, I2O_MAX_SECTORS); - printk(KERN_INFO "I2O Block Device Deleted\n"); + if (c->short_req) + segments = 8; + else { + i2o_status_block *sb; - if(unit >= MAX_I2OB) - { - printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n"); - return; + sb = c->status_block.virt; + + segments = (sb->inbound_frame_size - + sizeof(struct i2o_message) / 4 - 4) / 2; } - spin_lock_irqsave(dev->req_queue->queue_lock, flags); + blk_queue_max_hw_segments(queue, segments); + + pr_debug("max sectors: %d\n", I2O_MAX_SECTORS); + pr_debug("phys segments: %d\n", I2O_MAX_SEGMENTS); + pr_debug("hw segments: %d\n", segments); /* - * Need to do this...we somtimes get two events from the IRTOS - * in a row and that causes lots of problems. + * Ask for the current media data. If that isn't supported + * then we ask for the device capacity data */ - i2o_device_notify_off(d, &i2o_block_handler); + if (i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) != 0 + || i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) != 0) { + i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4); + i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8); + } + pr_debug("blocksize: %d\n", blocksize); - /* - * This will force errors when i2ob_get_queue() is called - * by the kenrel. - */ - if(dev->gd) { - struct gendisk *gd = dev->gd; - gd->queue = NULL; - del_gendisk(gd); - put_disk(gd); - dev->gd = NULL; - } - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); - dev->req_queue = NULL; - dev->i2odev = NULL; - dev->refcnt = 0; - dev->tid = 0; - - /* - * Do we need this? - * The media didn't really change...the device is just gone - */ - dev->media_change_flag = 1; + if (i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2)) + power = 0; + i2o_parm_field_get(i2o_dev, 0x0000, 5, &flags, 4); + i2o_parm_field_get(i2o_dev, 0x0000, 6, &status, 4); - i2ob_dev_count--; -} + set_capacity(gd, size >> 9); -/* - * Have we seen a media change ? - */ -static int i2ob_media_change(struct gendisk *disk) -{ - struct i2ob_device *p = disk->private_data; - if(p->media_change_flag) - { - p->media_change_flag=0; - return 1; - } - return 0; -} + i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0xffffffff); -static int i2ob_revalidate(struct gendisk *disk) -{ - struct i2ob_device *p = disk->private_data; - return i2ob_install_device(p->controller, p->i2odev, p->index); -} + add_disk(gd); -/* - * Reboot notifier. This is called by i2o_core when the system - * shuts down. - */ -static void i2ob_reboot_event(void) -{ - int i; - - for(i=0;irefcnt!=0) - { - /* - * Flush the onboard cache - */ - u32 msg[5]; - int *query_done = &dev->done_flag; - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = 60<<16; - - DEBUG("Flushing..."); - i2o_post_wait(dev->controller, msg, 20, 60); + unit++; - DEBUG("Unlocking..."); - /* - * Unlock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = -1; - i2o_post_wait(dev->controller, msg, 20, 2); - - DEBUG("Unlocked.\n"); - } - } -} + return 0; -static struct block_device_operations i2ob_fops = -{ - .owner = THIS_MODULE, - .open = i2ob_open, - .release = i2ob_release, - .ioctl = i2ob_ioctl, - .media_changed = i2ob_media_change, - .revalidate_disk= i2ob_revalidate, + claim_release: + i2o_device_claim_release(i2o_dev); + + exit: + return rc; }; -/* - * And here should be modules and kernel interface - * (Just smiley confuses emacs :-) - */ +/* Block OSM driver struct */ +static struct i2o_driver i2o_block_driver = { + .name = "block-osm", + .event = i2o_block_event, + .reply = i2o_block_reply, + .classes = i2o_block_class_id, + .driver = { + .probe = i2o_block_probe, + .remove = i2o_block_remove, + }, +}; -static int i2o_block_init(void) +/** + * i2o_block_init - Block OSM initialization function + * + * Allocate the slab and mempool for request structs, registers i2o_block + * block device and finally register the Block OSM in the I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_block_init(void) { - int i; + int rc; + int size; printk(KERN_INFO "I2O Block Storage OSM v0.9\n"); printk(KERN_INFO " (c) Copyright 1999-2001 Red Hat Software.\n"); - - /* - * Register the block device interfaces - */ - if (register_blkdev(MAJOR_NR, "i2o_block")) - return -EIO; + /* Allocate request mempool and slab */ + size = sizeof(struct i2o_block_request); + i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0, + SLAB_HWCACHE_ALIGN, NULL, + NULL); + if (!i2o_blk_req_pool.slab) { + printk(KERN_ERR "block-osm: can't init request slab\n"); + rc = -ENOMEM; + goto exit; + } + + i2o_blk_req_pool.pool = mempool_create(I2O_REQ_MEMPOOL_SIZE, + mempool_alloc_slab, + mempool_free_slab, + i2o_blk_req_pool.slab); + if (!i2o_blk_req_pool.pool) { + printk(KERN_ERR "block-osm: can't init request mempool\n"); + rc = -ENOMEM; + goto free_slab; + } + + /* Register the block device interfaces */ + rc = register_blkdev(I2O_MAJOR, "i2o_block"); + if (rc) { + printk(KERN_ERR "block-osm: unable to register block device\n"); + goto free_mempool; + } #ifdef MODULE - printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR); + printk(KERN_INFO "block-osm: registered device at major %d\n", + I2O_MAJOR); #endif - /* - * Set up the queue - */ - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - i2ob_queues[i] = NULL; - - /* - * Now fill in the boiler plate - */ - - for (i = 0; i < MAX_I2OB; i++) { - struct i2ob_device *dev = &i2ob_dev[i]; - dev->index = i; - dev->refcnt = 0; - dev->flags = 0; - dev->controller = NULL; - dev->i2odev = NULL; - dev->tid = 0; - dev->head = NULL; - dev->tail = NULL; - dev->depth = MAX_I2OB_DEPTH; - dev->max_sectors = 2; - dev->gd = NULL; - } - - /* - * Register the OSM handler as we will need this to probe for - * drives, geometry and other goodies. - */ - - if(i2o_install_handler(&i2o_block_handler)<0) - { - unregister_blkdev(MAJOR_NR, "i2o_block"); - printk(KERN_ERR "i2o_block: unable to register OSM.\n"); - return -EINVAL; - } - i2ob_context = i2o_block_handler.context; - - /* - * Initialize event handling thread - */ - init_MUTEX_LOCKED(&i2ob_evt_sem); - evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND); - if(evt_pid < 0) - { - printk(KERN_ERR "i2o_block: Could not initialize event thread. Aborting\n"); - i2o_remove_handler(&i2o_block_handler); - return 0; + /* Register Block OSM into I2O core */ + rc = i2o_driver_register(&i2o_block_driver); + if (rc) { + printk(KERN_ERR "block-osm: Could not register Block driver\n"); + goto unregister_blkdev; } - i2ob_probe(); - return 0; - unregister_blkdev(MAJOR_NR, "i2o_block"); - return -ENOMEM; -} + unregister_blkdev: + unregister_blkdev(I2O_MAJOR, "i2o_block"); + free_mempool: + mempool_destroy(i2o_blk_req_pool.pool); -static void i2o_block_exit(void) -{ - int i; - - if(evt_running) { - printk(KERN_INFO "Killing I2O block threads..."); - i = kill_proc(evt_pid, SIGKILL, 1); - if(!i) { - printk("waiting...\n"); - } - /* Be sure it died */ - wait_for_completion(&i2ob_thread_dead); - printk("done.\n"); - } + free_slab: + kmem_cache_destroy(i2o_blk_req_pool.slab); - /* - * Unregister for updates from any devices..otherwise we still - * get them and the core jumps to random memory :O - */ - if(i2ob_dev_count) { - struct i2o_device *d; - for(i = 0; i < MAX_I2OB; i++) - if((d = i2ob_dev[i].i2odev)) - i2ob_del_device(d->controller, d); - } - - /* - * We may get further callbacks for ourself. The i2o_core - * code handles this case reasonably sanely. The problem here - * is we shouldn't get them .. but a couple of cards feel - * obliged to tell us stuff we don't care about. - * - * This isnt ideal at all but will do for now. - */ - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - - /* - * Flush the OSM - */ + exit: + return rc; +}; - i2o_remove_handler(&i2o_block_handler); +/** + * i2o_block_exit - Block OSM exit function + * + * Unregisters Block OSM from I2O core, unregisters i2o_block block device + * and frees the mempool and slab. + */ +static void __exit i2o_block_exit(void) +{ + /* Unregister I2O Block OSM from I2O core */ + i2o_driver_unregister(&i2o_block_driver); - /* - * Return the block device - */ - if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) - printk("i2o_block: cleanup_module failed\n"); + /* Unregister block device */ + unregister_blkdev(I2O_MAJOR, "i2o_block"); - /* - * release request queue - */ - for (i = 0; i < MAX_I2O_CONTROLLERS; i ++) - if(i2ob_queues[i]) { - blk_cleanup_queue(i2ob_queues[i]->req_queue); - kfree(i2ob_queues[i]); - } -} + /* Free request mempool and slab */ + mempool_destroy(i2o_blk_req_pool.pool); + kmem_cache_destroy(i2o_blk_req_pool.slab); +}; MODULE_AUTHOR("Red Hat"); MODULE_DESCRIPTION("I2O Block Device OSM"); diff -Nru a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/message/i2o/i2o_block.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,99 @@ +/* + * Block OSM structures/API + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * For the purpose of avoiding doubt the preferred form of the work + * for making modifications shall be a standards compliant form such + * gzipped tar and not one requiring a proprietary or patent encumbered + * tool to unpack. + * + * Fixes/additions: + * Steve Ralston: + * Multiple device handling error fixes, + * Added a queue depth. + * Alan Cox: + * FC920 has an rmw bug. Dont or in the end marker. + * Removed queue walk, fixed for 64bitness. + * Rewrote much of the code over time + * Added indirect block lists + * Handle 64K limits on many controllers + * Don't use indirects on the Promise (breaks) + * Heavily chop down the queue depths + * Deepak Saxena: + * Independent queues per IOP + * Support for dynamic device creation/deletion + * Code cleanup + * Support for larger I/Os through merge* functions + * (taken from DAC960 driver) + * Boji T Kannanthanam: + * Set the I2O Block devices to be detected in increasing + * order of TIDs during boot. + * Search and set the I2O block device that we boot off + * from as the first device to be claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure from the + * system gendisk list. The I2O block devices now appear in + * /proc/partitions. + * Markus Lidel : + * Minor bugfixes for 2.6. + */ + +#ifndef I2O_BLOCK_OSM_H +#define I2O_BLOCK_OSM_H + +#define I2O_BLOCK_RETRY_TIME HZ/4 +#define I2O_BLOCK_MAX_OPEN_REQUESTS 50 + +/* I2O Block OSM mempool struct */ +struct i2o_block_mempool { + kmem_cache_t *slab; + mempool_t *pool; +}; + +/* I2O Block device descriptor */ +struct i2o_block_device { + struct i2o_device *i2o_dev; /* pointer to I2O device */ + struct gendisk *gd; + spinlock_t lock; /* queue lock */ + struct list_head open_queue; /* list of transfered, but unfinished + requests */ + unsigned int open_queue_depth; /* number of requests in the queue */ + + int rcache; /* read cache flags */ + int wcache; /* write cache flags */ + int flags; + int power; /* power state */ + int media_change_flag; /* media changed flag */ +}; + +/* I2O Block device request */ +struct i2o_block_request +{ + struct list_head queue; + struct request *req; /* corresponding request */ + struct i2o_block_device *i2o_blk_dev; /* I2O block device */ + int sg_dma_direction; /* direction of DMA buffer read/write */ + int sg_nents; /* number of SG elements */ + struct scatterlist sg_table[I2O_MAX_SEGMENTS]; /* SG table */ +}; + +/* I2O Block device delayed request */ +struct i2o_block_delayed_request +{ + struct work_struct work; + struct request_queue *queue; +}; + +#endif diff -Nru a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c --- a/drivers/message/i2o/i2o_config.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/message/i2o/i2o_config.c 2004-10-18 14:57:03 -07:00 @@ -2,7 +2,7 @@ * I2O Configuration Interface Driver * * (C) Copyright 1999-2002 Red Hat - * + * * Written by Alan Cox, Building Number Three Ltd * * Fixes/additions: @@ -41,63 +41,53 @@ #include #include #include +#include +#include +#include #include #include -static int i2o_cfg_context = -1; -static void *page_buf; +extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int); + static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; #define MODINC(x,y) ((x) = ((x) + 1) % (y)) struct sg_simple_element { - u32 flag_count; + u32 flag_count; u32 addr_bus; }; -struct i2o_cfg_info -{ - struct file* fp; +struct i2o_cfg_info { + struct file *fp; struct fasync_struct *fasync; struct i2o_evt_info event_q[I2O_EVT_Q_LEN]; - u16 q_in; // Queue head index - u16 q_out; // Queue tail index - u16 q_len; // Queue length - u16 q_lost; // Number of lost events - u32 q_id; // Event queue ID...used as tx_context - struct i2o_cfg_info *next; + u16 q_in; // Queue head index + u16 q_out; // Queue tail index + u16 q_len; // Queue length + u16 q_lost; // Number of lost events + ulong q_id; // Event queue ID...used as tx_context + struct i2o_cfg_info *next; }; static struct i2o_cfg_info *open_files = NULL; -static int i2o_cfg_info_id = 0; - -static int ioctl_getiops(unsigned long); -static int ioctl_gethrt(unsigned long); -static int ioctl_getlct(unsigned long); -static int ioctl_parms(unsigned long, unsigned int); -static int ioctl_html(unsigned long); -static int ioctl_swdl(unsigned long); -static int ioctl_swul(unsigned long); -static int ioctl_swdel(unsigned long); -static int ioctl_validate(unsigned long); -static int ioctl_evt_reg(unsigned long, struct file *); -static int ioctl_evt_get(unsigned long, struct file *); -static int ioctl_passthru(unsigned long); -static int cfg_fasync(int, struct file*, int); +static ulong i2o_cfg_info_id = 0; +#if 0 /* * This is the callback for any message we have posted. The message itself * will be returned to the message pool when we return from the IRQ * * This runs in irq context so be short and sweet. */ -static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) +static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, + struct i2o_message *m) { - u32 *msg = (u32 *)m; + u32 *msg = (u32 *) m; if (msg[0] & MSG_FAIL) { - u32 *preserved_msg = (u32*)(c->msg_virt + msg[7]); + u32 *preserved_msg = (u32 *) (c->msg_virt + msg[7]); printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n"); @@ -109,26 +99,25 @@ i2o_post_message(c, msg[7]); } - if (msg[4] >> 24) // ReqStatus != SUCCESS - i2o_report_status(KERN_INFO,"i2o_config", msg); + if (msg[4] >> 24) // ReqStatus != SUCCESS + i2o_report_status(KERN_INFO, "i2o_config", msg); - if(m->function == I2O_CMD_UTIL_EVT_REGISTER) - { + if (m->function == I2O_CMD_UTIL_EVT_REGISTER) { struct i2o_cfg_info *inf; - for(inf = open_files; inf; inf = inf->next) - if(inf->q_id == msg[3]) + for (inf = open_files; inf; inf = inf->next) + if (inf->q_id == i2o_cntxt_list_get(c, msg[3])) break; // // If this is the case, it means that we're getting // events for a file descriptor that's been close()'d // w/o the user unregistering for events first. - // The code currently assumes that the user will + // The code currently assumes that the user will // take care of unregistering for events before closing // a file. - // - // TODO: + // + // TODO: // Should we track event registartion and deregister // for events when a file is close()'d so this doesn't // happen? That would get rid of the search through @@ -137,8 +126,8 @@ // it would mean having all sorts of tables to track // what each file is registered for...I think the // current method is simpler. - DS - // - if(!inf) + // + if (!inf) return; inf->event_q[inf->q_in].id.iop = c->unit; @@ -149,278 +138,167 @@ // Data size = msg size - reply header // inf->event_q[inf->q_in].data_size = (m->size - 5) * 4; - if(inf->event_q[inf->q_in].data_size) - memcpy(inf->event_q[inf->q_in].evt_data, - (unsigned char *)(msg + 5), - inf->event_q[inf->q_in].data_size); + if (inf->event_q[inf->q_in].data_size) + memcpy(inf->event_q[inf->q_in].evt_data, + (unsigned char *)(msg + 5), + inf->event_q[inf->q_in].data_size); spin_lock(&i2o_config_lock); MODINC(inf->q_in, I2O_EVT_Q_LEN); - if(inf->q_len == I2O_EVT_Q_LEN) - { + if (inf->q_len == I2O_EVT_Q_LEN) { MODINC(inf->q_out, I2O_EVT_Q_LEN); inf->q_lost++; - } - else - { + } else { // Keep I2OEVTGET on another CPU from touching this inf->q_len++; } spin_unlock(&i2o_config_lock); - -// printk(KERN_INFO "File %p w/id %d has %d events\n", -// inf->fp, inf->q_id, inf->q_len); +// printk(KERN_INFO "File %p w/id %d has %d events\n", +// inf->fp, inf->q_id, inf->q_len); kill_fasync(&inf->fasync, SIGIO, POLL_IN); } return; } +#endif /* * Each of these describes an i2o message handler. They are * multiplexed by the i2o_core code */ - -struct i2o_handler cfg_handler= -{ - i2o_cfg_reply, - NULL, - NULL, - NULL, - "Configuration", - 0, - 0xffffffff // All classes -}; - -static ssize_t cfg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - printk(KERN_INFO "i2o_config write not yet supported\n"); - return 0; -} - - -static ssize_t cfg_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) -{ - return 0; -} +struct i2o_driver i2o_config_driver = { + .name = "Config-OSM" +}; -/* - * IOCTL Handler - */ -static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, - unsigned long arg) +static int i2o_cfg_getiops(unsigned long arg) { - int ret; - - switch(cmd) - { - case I2OGETIOPS: - ret = ioctl_getiops(arg); - break; - - case I2OHRTGET: - ret = ioctl_gethrt(arg); - break; - - case I2OLCTGET: - ret = ioctl_getlct(arg); - break; - - case I2OPARMSET: - ret = ioctl_parms(arg, I2OPARMSET); - break; - - case I2OPARMGET: - ret = ioctl_parms(arg, I2OPARMGET); - break; - - case I2OSWDL: - ret = ioctl_swdl(arg); - break; - - case I2OSWUL: - ret = ioctl_swul(arg); - break; - - case I2OSWDEL: - ret = ioctl_swdel(arg); - break; - - case I2OVALIDATE: - ret = ioctl_validate(arg); - break; - - case I2OHTML: - ret = ioctl_html(arg); - break; - - case I2OEVTREG: - ret = ioctl_evt_reg(arg, fp); - break; + struct i2o_controller *c; + u8 __user *user_iop_table = (void __user *)arg; + u8 tmp[MAX_I2O_CONTROLLERS]; - case I2OEVTGET: - ret = ioctl_evt_get(arg, fp); - break; + memset(tmp, 0, MAX_I2O_CONTROLLERS); - case I2OPASSTHRU: - ret = ioctl_passthru(arg); - break; + if (!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS)) + return -EFAULT; - default: - ret = -EINVAL; - } + list_for_each_entry(c, &i2o_controllers, list) + tmp[c->unit] = 1; - return ret; -} + __copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS); -int ioctl_getiops(unsigned long arg) -{ - u8 __user *user_iop_table = (void __user *)arg; - struct i2o_controller *c = NULL; - int i; - u8 foo[MAX_I2O_CONTROLLERS]; - - if(!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS)) - return -EFAULT; - - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - c = i2o_find_controller(i); - if(c) - { - foo[i] = 1; - if(pci_set_dma_mask(c->pdev, 0xffffffff)) - { - printk(KERN_WARNING "i2o_config : No suitable DMA available on controller %d\n", i); - i2o_unlock_controller(c); - continue; - } - - i2o_unlock_controller(c); - } - else - { - foo[i] = 0; - } - } - - __copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS); return 0; -} +}; -int ioctl_gethrt(unsigned long arg) +static int i2o_cfg_gethrt(unsigned long arg) { struct i2o_controller *c; - struct i2o_cmd_hrtlct __user *cmd = (void __user *)arg; + struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg; struct i2o_cmd_hrtlct kcmd; i2o_hrt *hrt; int len; u32 reslen; int ret = 0; - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) return -EFAULT; - if(get_user(reslen, kcmd.reslen) < 0) + if (get_user(reslen, kcmd.reslen) < 0) return -EFAULT; - if(kcmd.resbuf == NULL) + if (kcmd.resbuf == NULL) return -EFAULT; - c = i2o_find_controller(kcmd.iop); - if(!c) + c = i2o_find_iop(kcmd.iop); + if (!c) return -ENXIO; - - hrt = (i2o_hrt *)c->hrt; - i2o_unlock_controller(c); + hrt = (i2o_hrt *) c->hrt.virt; len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); - + /* We did a get user...so assuming mem is ok...is this bad? */ put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOBUFS; - if(copy_to_user(kcmd.resbuf, (void*)hrt, len)) + if (len > reslen) + ret = -ENOBUFS; + if (copy_to_user(kcmd.resbuf, (void *)hrt, len)) ret = -EFAULT; return ret; -} +}; -int ioctl_getlct(unsigned long arg) +static int i2o_cfg_getlct(unsigned long arg) { struct i2o_controller *c; - struct i2o_cmd_hrtlct __user *cmd = (void __user *)arg; + struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg; struct i2o_cmd_hrtlct kcmd; i2o_lct *lct; int len; int ret = 0; u32 reslen; - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) return -EFAULT; - if(get_user(reslen, kcmd.reslen) < 0) + if (get_user(reslen, kcmd.reslen) < 0) return -EFAULT; - if(kcmd.resbuf == NULL) + if (kcmd.resbuf == NULL) return -EFAULT; - c = i2o_find_controller(kcmd.iop); - if(!c) + c = i2o_find_iop(kcmd.iop); + if (!c) return -ENXIO; - lct = (i2o_lct *)c->lct; - i2o_unlock_controller(c); + lct = (i2o_lct *) c->lct; len = (unsigned int)lct->table_size << 2; put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOBUFS; - else if(copy_to_user(kcmd.resbuf, (void*)lct, len)) + if (len > reslen) + ret = -ENOBUFS; + else if (copy_to_user(kcmd.resbuf, lct, len)) ret = -EFAULT; return ret; -} +}; -static int ioctl_parms(unsigned long arg, unsigned int type) +static int i2o_cfg_parms(unsigned long arg, unsigned int type) { int ret = 0; struct i2o_controller *c; - struct i2o_cmd_psetget __user *cmd = (void __user *)arg; + struct i2o_device *dev; + struct i2o_cmd_psetget __user *cmd = + (struct i2o_cmd_psetget __user *)arg; struct i2o_cmd_psetget kcmd; u32 reslen; u8 *ops; u8 *res; - int len; + int len = 0; - u32 i2o_cmd = (type == I2OPARMGET ? - I2O_CMD_UTIL_PARAMS_GET : - I2O_CMD_UTIL_PARAMS_SET); + u32 i2o_cmd = (type == I2OPARMGET ? + I2O_CMD_UTIL_PARAMS_GET : I2O_CMD_UTIL_PARAMS_SET); - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) + if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) return -EFAULT; - if(get_user(reslen, kcmd.reslen)) + if (get_user(reslen, kcmd.reslen)) return -EFAULT; - c = i2o_find_controller(kcmd.iop); - if(!c) + c = i2o_find_iop(kcmd.iop); + if (!c) return -ENXIO; - ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL); - if(!ops) - { - i2o_unlock_controller(c); + dev = i2o_iop_find_device(c, kcmd.tid); + if (!dev) + return -ENXIO; + + ops = (u8 *) kmalloc(kcmd.oplen, GFP_KERNEL); + if (!ops) return -ENOMEM; - } - if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) - { - i2o_unlock_controller(c); + if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) { kfree(ops); return -EFAULT; } @@ -429,404 +307,309 @@ * It's possible to have a _very_ large table * and that the user asks for all of it at once... */ - res = (u8*)kmalloc(65536, GFP_KERNEL); - if(!res) - { - i2o_unlock_controller(c); + res = (u8 *) kmalloc(65536, GFP_KERNEL); + if (!res) { kfree(ops); return -ENOMEM; } - len = i2o_issue_params(i2o_cmd, c, kcmd.tid, - ops, kcmd.oplen, res, 65536); - i2o_unlock_controller(c); + len = i2o_parm_issue(dev, i2o_cmd, ops, kcmd.oplen, res, 65536); kfree(ops); - + if (len < 0) { kfree(res); return -EAGAIN; } put_user(len, kcmd.reslen); - if(len > reslen) + if (len > reslen) ret = -ENOBUFS; - else if(copy_to_user(kcmd.resbuf, res, len)) + else if (copy_to_user(kcmd.resbuf, res, len)) ret = -EFAULT; kfree(res); return ret; -} +}; -int ioctl_html(unsigned long arg) +static int i2o_cfg_swdl(unsigned long arg) { - struct i2o_html __user *cmd = (void __user *)arg; - struct i2o_html kcmd; + struct i2o_sw_xfer kxfer; + struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; + unsigned char maxfrag = 0, curfrag = 1; + struct i2o_dma buffer; + struct i2o_message *msg; + u32 m; + unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; - u8 *res = NULL; - void *query = NULL; - dma_addr_t query_phys, res_phys; - int ret = 0; - int token; - u32 len; - u32 reslen; - u32 msg[MSG_FRAME_SIZE]; - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html))) - { - printk(KERN_INFO "i2o_config: can't copy html cmd\n"); + if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + return -EFAULT; + + if (get_user(swlen, kxfer.swlen) < 0) return -EFAULT; - } - if(get_user(reslen, kcmd.reslen) < 0) - { - printk(KERN_INFO "i2o_config: can't copy html reslen\n"); + if (get_user(maxfrag, kxfer.maxfrag) < 0) return -EFAULT; - } - if(!kcmd.resbuf) - { - printk(KERN_INFO "i2o_config: NULL html buffer\n"); + if (get_user(curfrag, kxfer.curfrag) < 0) return -EFAULT; - } - c = i2o_find_controller(kcmd.iop); - if(!c) + if (curfrag == maxfrag) + fragsize = swlen - (maxfrag - 1) * 8192; + + if (!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) + return -EFAULT; + + c = i2o_find_iop(kxfer.iop); + if (!c) return -ENXIO; - if(kcmd.qlen) /* Check for post data */ - { - query = pci_alloc_consistent(c->pdev, kcmd.qlen, &query_phys); - if(!query) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - if(copy_from_user(query, kcmd.qbuf, kcmd.qlen)) - { - i2o_unlock_controller(c); - printk(KERN_INFO "i2o_config: could not get query\n"); - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); - return -EFAULT; - } - } + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; - res = pci_alloc_consistent(c->pdev, 65536, &res_phys); - if(!res) - { - i2o_unlock_controller(c); - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); + if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { + i2o_msg_nop(c, m); return -ENOMEM; } - msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid; - msg[2] = i2o_cfg_context; - msg[3] = 0; - msg[4] = kcmd.page; - msg[5] = 0xD0000000|65536; - msg[6] = res_phys; - if(!kcmd.qlen) /* Check for post data */ - msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; - else - { - msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[5] = 0x50000000|65536; - msg[7] = 0xD4000000|(kcmd.qlen); - msg[8] = query_phys; - } - /* - Wait for a considerable time till the Controller - does its job before timing out. The controller might - take more time to process this request if there are - many devices connected to it. - */ - token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res, query_phys, res_phys, kcmd.qlen, 65536); - if(token < 0) - { - printk(KERN_DEBUG "token = %#10x\n", token); - i2o_unlock_controller(c); - - if(token != -ETIMEDOUT) - { - pci_free_consistent(c->pdev, 65536, res, res_phys); - if(kcmd.qlen) - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); - } - return token; - } - i2o_unlock_controller(c); + __copy_from_user(buffer.virt, kxfer.buf, fragsize); - len = strnlen(res, 65536); - put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOMEM; - if(copy_to_user(kcmd.resbuf, res, len)) - ret = -EFAULT; + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); + writel(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + writel((((u32) kxfer.flags) << 24) | (((u32) kxfer.sw_type) << 16) | + (((u32) maxfrag) << 8) | (((u32) curfrag)), &msg->body[0]); + writel(swlen, &msg->body[1]); + writel(kxfer.sw_id, &msg->body[2]); + writel(0xD0000000 | fragsize, &msg->body[3]); + writel(buffer.phys, &msg->body[4]); - pci_free_consistent(c->pdev, 65536, res, res_phys); - if(kcmd.qlen) - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); +// printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); + status = i2o_msg_post_wait_mem(c, m, 60, &buffer); - return ret; -} - -int ioctl_swdl(unsigned long arg) + if (status != -ETIMEDOUT) + i2o_dma_free(&c->pdev->dev, &buffer); + + if (status != I2O_POST_WAIT_OK) { + // it fails if you try and send frags out of order + // and for some yet unknown reasons too + printk(KERN_INFO + "i2o_config: swdl failed, DetailedStatus = %d\n", + status); + return status; + } + + return 0; +}; + +static int i2o_cfg_swul(unsigned long arg) { struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer __user *pxfer = (void __user *)arg; + struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; unsigned char maxfrag = 0, curfrag = 1; - unsigned char *buffer; - u32 msg[9]; + struct i2o_dma buffer; + struct i2o_message *msg; + u32 m; unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; - dma_addr_t buffer_phys; - if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; - if(get_user(swlen, kxfer.swlen) < 0) + if (get_user(swlen, kxfer.swlen) < 0) return -EFAULT; - if(get_user(maxfrag, kxfer.maxfrag) < 0) + if (get_user(maxfrag, kxfer.maxfrag) < 0) return -EFAULT; - if(get_user(curfrag, kxfer.curfrag) < 0) + if (get_user(curfrag, kxfer.curfrag) < 0) return -EFAULT; - if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; + if (curfrag == maxfrag) + fragsize = swlen - (maxfrag - 1) * 8192; - if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) + if (!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize)) return -EFAULT; - - c = i2o_find_controller(kxfer.iop); - if(!c) + + c = i2o_find_iop(kxfer.iop); + if (!c) return -ENXIO; - buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); - if (buffer==NULL) - { - i2o_unlock_controller(c); + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { + i2o_msg_nop(c, m); return -ENOMEM; } - __copy_from_user(buffer, kxfer.buf, fragsize); - msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; - msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) | - (((u32)maxfrag)<<8) | (((u32)curfrag)); - msg[5]= swlen; - msg[6]= kxfer.sw_id; - msg[7]= (0xD0000000 | fragsize); - msg[8]= buffer_phys; - -// printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); - - i2o_unlock_controller(c); - if(status != -ETIMEDOUT) - pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); - - if (status != I2O_POST_WAIT_OK) - { - // it fails if you try and send frags out of order - // and for some yet unknown reasons too - printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); + writel(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + writel((u32) kxfer.flags << 24 | (u32) kxfer. + sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag, + &msg->body[0]); + writel(swlen, &msg->body[1]); + writel(kxfer.sw_id, &msg->body[2]); + writel(0xD0000000 | fragsize, &msg->body[3]); + writel(buffer.phys, &msg->body[4]); + +// printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); + status = i2o_msg_post_wait_mem(c, m, 60, &buffer); + + if (status != I2O_POST_WAIT_OK) { + if (status != -ETIMEDOUT) + i2o_dma_free(&c->pdev->dev, &buffer); + + printk(KERN_INFO + "i2o_config: swul failed, DetailedStatus = %d\n", + status); return status; } - return 0; -} + __copy_to_user(kxfer.buf, buffer.virt, fragsize); + i2o_dma_free(&c->pdev->dev, &buffer); -int ioctl_swul(unsigned long arg) -{ - struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer __user *pxfer = (void __user *)arg; - unsigned char maxfrag = 0, curfrag = 1; - unsigned char *buffer; - u32 msg[9]; - unsigned int status = 0, swlen = 0, fragsize = 8192; - struct i2o_controller *c; - dma_addr_t buffer_phys; - - if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) - return -EFAULT; - - if(get_user(swlen, kxfer.swlen) < 0) - return -EFAULT; - - if(get_user(maxfrag, kxfer.maxfrag) < 0) - return -EFAULT; - - if(get_user(curfrag, kxfer.curfrag) < 0) - return -EFAULT; - - if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; - - if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize)) - return -EFAULT; - - c = i2o_find_controller(kxfer.iop); - if(!c) - return -ENXIO; - - buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); - if (buffer==NULL) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - - msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; - msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag; - msg[5]= swlen; - msg[6]= kxfer.sw_id; - msg[7]= (0xD0000000 | fragsize); - msg[8]= buffer_phys; - -// printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); - i2o_unlock_controller(c); - - if (status != I2O_POST_WAIT_OK) - { - if(status != -ETIMEDOUT) - pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); - printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); - return status; - } - - __copy_to_user(kxfer.buf, buffer, fragsize); - pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); - return 0; -} +}; -int ioctl_swdel(unsigned long arg) +static int i2o_cfg_swdel(unsigned long arg) { struct i2o_controller *c; struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer __user *pxfer = (void __user *)arg; - u32 msg[7]; + struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; + struct i2o_message *msg; + u32 m; unsigned int swlen; int token; - + if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; - + if (get_user(swlen, kxfer.swlen) < 0) return -EFAULT; - - c = i2o_find_controller(kxfer.iop); + + c = i2o_find_iop(kxfer.iop); if (!c) return -ENXIO; - msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = (u32)i2o_cfg_context; - msg[3] = 0; - msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16; - msg[5] = swlen; - msg[6] = kxfer.sw_id; - - token = i2o_post_wait(c, msg, sizeof(msg), 10); - i2o_unlock_controller(c); - - if (token != I2O_POST_WAIT_OK) - { - printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token); + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + writel(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + writel((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16, + &msg->body[0]); + writel(swlen, &msg->body[1]); + writel(kxfer.sw_id, &msg->body[2]); + + token = i2o_msg_post_wait(c, m, 10); + + if (token != I2O_POST_WAIT_OK) { + printk(KERN_INFO + "i2o_config: swdel failed, DetailedStatus = %d\n", + token); return -ETIMEDOUT; } - + return 0; -} +}; -int ioctl_validate(unsigned long arg) +static int i2o_cfg_validate(unsigned long arg) { - int token; - int iop = (int)arg; - u32 msg[4]; - struct i2o_controller *c; - - c=i2o_find_controller(iop); - if (!c) - return -ENXIO; - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop; - msg[2] = (u32)i2o_cfg_context; - msg[3] = 0; - - token = i2o_post_wait(c, msg, sizeof(msg), 10); - i2o_unlock_controller(c); - - if (token != I2O_POST_WAIT_OK) - { - printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n", - token); - return -ETIMEDOUT; - } + int token; + int iop = (int)arg; + struct i2o_message *msg; + u32 m; + struct i2o_controller *c; + + c = i2o_find_iop(iop); + if (!c) + return -ENXIO; - return 0; -} + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + + token = i2o_msg_post_wait(c, m, 10); + + if (token != I2O_POST_WAIT_OK) { + printk(KERN_INFO "Can't validate configuration, ErrorStatus = " + "%d\n", token); + return -ETIMEDOUT; + } -static int ioctl_evt_reg(unsigned long arg, struct file *fp) + return 0; +}; + +static int i2o_cfg_evt_reg(unsigned long arg, struct file *fp) { - u32 msg[5]; - struct i2o_evt_id __user *pdesc = (void __user *)arg; + struct i2o_message *msg; + u32 m; + struct i2o_evt_id __user *pdesc = (struct i2o_evt_id __user *)arg; struct i2o_evt_id kdesc; - struct i2o_controller *iop; + struct i2o_controller *c; struct i2o_device *d; if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id))) return -EFAULT; /* IOP exists? */ - iop = i2o_find_controller(kdesc.iop); - if(!iop) + c = i2o_find_iop(kdesc.iop); + if (!c) return -ENXIO; - i2o_unlock_controller(iop); /* Device exists? */ - for(d = iop->devices; d; d = d->next) - if(d->lct_data.tid == kdesc.tid) - break; - - if(!d) + d = i2o_iop_find_device(c, kdesc.tid); + if (!d) return -ENODEV; - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid; - msg[2] = (u32)i2o_cfg_context; - msg[3] = (u32)fp->private_data; - msg[4] = kdesc.evt_mask; + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | kdesc.tid, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(i2o_cntxt_list_add(c, fp->private_data), &msg->u.head[3]); + writel(kdesc.evt_mask, &msg->body[0]); - i2o_post_this(iop, msg, 20); + i2o_msg_post(c, m); return 0; -} +} -static int ioctl_evt_get(unsigned long arg, struct file *fp) +static int i2o_cfg_evt_get(unsigned long arg, struct file *fp) { - u32 id = (u32)fp->private_data; struct i2o_cfg_info *p = NULL; - struct i2o_evt_get __user *uget = (void __user *)arg; + struct i2o_evt_get __user *uget = (struct i2o_evt_get __user *)arg; struct i2o_evt_get kget; unsigned long flags; - for(p = open_files; p; p = p->next) - if(p->q_id == id) + for (p = open_files; p; p = p->next) + if (p->q_id == (ulong) fp->private_data) break; - if(!p->q_len) - { + if (!p->q_len) return -ENOENT; - return 0; - } memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); MODINC(p->q_out, I2O_EVT_Q_LEN); @@ -836,16 +619,236 @@ kget.lost = p->q_lost; spin_unlock_irqrestore(&i2o_config_lock, flags); - if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) + if (copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) return -EFAULT; return 0; } -static int ioctl_passthru(unsigned long arg) +#ifdef CONFIG_COMPAT +static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg, + struct file *file) { - struct i2o_cmd_passthru __user *cmd = (void __user *) arg; + struct i2o_cmd_passthru32 __user *cmd; + struct i2o_controller *c; + u32 __user *user_msg; + u32 *reply = NULL; + u32 __user *user_reply = NULL; + u32 size = 0; + u32 reply_size = 0; + u32 rcode = 0; + struct i2o_dma sg_list[SG_TABLESIZE]; + u32 sg_offset = 0; + u32 sg_count = 0; + u32 i = 0; + i2o_status_block *sb; + struct i2o_message *msg; + u32 m; + unsigned int iop; + + cmd = (struct i2o_cmd_passthru32 __user *)arg; + + if (get_user(iop, &cmd->iop) || get_user(i, &cmd->msg)) + return -EFAULT; + + user_msg = compat_ptr(i); + + c = i2o_find_iop(iop); + if (!c) { + pr_debug("controller %d not found\n", iop); + return -ENXIO; + } + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + + sb = c->status_block.virt; + + if (get_user(size, &user_msg[0])) { + printk(KERN_WARNING "unable to get size!\n"); + return -EFAULT; + } + size = size >> 16; + + if (size > sb->inbound_frame_size) { + pr_debug("size of message > inbound_frame_size"); + return -EFAULT; + } + + user_reply = &user_msg[size]; + + size <<= 2; // Convert to bytes + + /* Copy in the user's I2O command */ + if (copy_from_user(msg, user_msg, size)) { + printk(KERN_WARNING "unable to copy user message\n"); + return -EFAULT; + } + i2o_dump_message(msg); + + if (get_user(reply_size, &user_reply[0]) < 0) + return -EFAULT; + + reply_size >>= 16; + reply_size <<= 2; + + reply = kmalloc(reply_size, GFP_KERNEL); + if (!reply) { + printk(KERN_WARNING "%s: Could not allocate reply buffer\n", + c->name); + return -ENOMEM; + } + memset(reply, 0, reply_size); + + sg_offset = (msg->u.head[0] >> 4) & 0x0f; + + writel(i2o_config_driver.context, &msg->u.s.icntxt); + writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt); + + memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE); + if (sg_offset) { + struct sg_simple_element *sg; + + if (sg_offset * 4 >= size) { + rcode = -EFAULT; + goto cleanup; + } + // TODO 64bit fix + sg = (struct sg_simple_element *)((&msg->u.head[0]) + + sg_offset); + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); + if (sg_count > SG_TABLESIZE) { + printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n", + c->name, sg_count); + kfree(reply); + return -EINVAL; + } + + for (i = 0; i < sg_count; i++) { + int sg_size; + struct i2o_dma *p; + + if (!(sg[i].flag_count & 0x10000000 + /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) { + printk(KERN_DEBUG + "%s:Bad SG element %d - not simple (%x)\n", + c->name, i, sg[i].flag_count); + rcode = -EINVAL; + goto cleanup; + } + sg_size = sg[i].flag_count & 0xffffff; + p = &(sg_list[i]); + /* Allocate memory for the transfer */ + if (i2o_dma_alloc + (&c->pdev->dev, p, sg_size, + PCI_DMA_BIDIRECTIONAL)) { + printk(KERN_DEBUG + "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", + c->name, sg_size, i, sg_count); + rcode = -ENOMEM; + goto cleanup; + } + /* Copy in the user's SG buffer if necessary */ + if (sg[i]. + flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) { + // TODO 64bit fix + if (copy_from_user + (p->virt, (void __user *)(unsigned long)sg[i].addr_bus, + sg_size)) { + printk(KERN_DEBUG + "%s: Could not copy SG buf %d FROM user\n", + c->name, i); + rcode = -EFAULT; + goto cleanup; + } + } + //TODO 64bit fix + sg[i].addr_bus = (u32) p->phys; + } + } + + rcode = i2o_msg_post_wait(c, m, 60); + if (rcode) + goto cleanup; + + if (sg_offset) { + u32 msg[128]; + /* Copy back the Scatter Gather buffers back to user space */ + u32 j; + // TODO 64bit fix + struct sg_simple_element *sg; + int sg_size; + printk(KERN_INFO "sg_offset\n"); + + // re-acquire the original message to handle correctly the sg copy operation + memset(&msg, 0, MSG_FRAME_SIZE * 4); + // get user msg size in u32s + if (get_user(size, &user_msg[0])) { + rcode = -EFAULT; + goto cleanup; + } + size = size >> 16; + size *= 4; + /* Copy in the user's I2O command */ + if (copy_from_user(msg, user_msg, size)) { + rcode = -EFAULT; + goto cleanup; + } + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); + + // TODO 64bit fix + sg = (struct sg_simple_element *)(msg + sg_offset); + for (j = 0; j < sg_count; j++) { + /* Copy out the SG list to user's buffer if necessary */ + if (! + (sg[j]. + flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) { + sg_size = sg[j].flag_count & 0xffffff; + // TODO 64bit fix + if (copy_to_user + ((void __user *)(u64) sg[j].addr_bus, + sg_list[j].virt, sg_size)) { + printk(KERN_WARNING + "%s: Could not copy %p TO user %x\n", + c->name, sg_list[j].virt, + sg[j].addr_bus); + rcode = -EFAULT; + goto cleanup; + } + } + } + } + + /* Copy back the reply to user space */ + if (reply_size) { + // we wrote our own values for context - now restore the user supplied ones + printk(KERN_INFO "reply_size\n"); + if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) { + printk(KERN_WARNING + "%s: Could not copy message context FROM user\n", + c->name); + rcode = -EFAULT; + } + if (copy_to_user(user_reply, reply, reply_size)) { + printk(KERN_WARNING + "%s: Could not copy reply TO user\n", c->name); + rcode = -EFAULT; + } + } + + cleanup: + kfree(reply); + printk(KERN_INFO "rcode: %d\n", rcode); + return rcode; +} + +#else + +static int i2o_cfg_passthru(unsigned long arg) +{ + struct i2o_cmd_passthru __user *cmd = + (struct i2o_cmd_passthru __user *)arg; struct i2o_controller *c; - u32 msg[MSG_FRAME_SIZE]; u32 __user *user_msg; u32 *reply = NULL; u32 __user *user_reply = NULL; @@ -858,64 +861,88 @@ int sg_index = 0; u32 i = 0; void *p = NULL; + i2o_status_block *sb; + struct i2o_message *msg; + u32 m; unsigned int iop; if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg)) return -EFAULT; - c = i2o_find_controller(iop); - if (!c) - return -ENXIO; + c = i2o_find_iop(iop); + if (!c) { + pr_debug("controller %d not found\n", iop); + return -ENXIO; + } + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + + sb = c->status_block.virt; - memset(&msg, 0, MSG_FRAME_SIZE*4); - if(get_user(size, &user_msg[0])) + if (get_user(size, &user_msg[0])) return -EFAULT; - size = size>>16; + size = size >> 16; - user_reply = &user_msg[size]; - if(size > MSG_FRAME_SIZE) + if (size > sb->inbound_frame_size) { + pr_debug("size of message > inbound_frame_size"); return -EFAULT; - size *= 4; // Convert to bytes + } + + user_reply = &user_msg[size]; + + size <<= 2; // Convert to bytes /* Copy in the user's I2O command */ - if(copy_from_user(msg, user_msg, size)) + if (copy_from_user(msg, user_msg, size)) return -EFAULT; - if(get_user(reply_size, &user_reply[0]) < 0) + + if (get_user(reply_size, &user_reply[0]) < 0) return -EFAULT; - reply_size = reply_size>>16; - reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); - if(!reply) { - printk(KERN_WARNING"%s: Could not allocate reply buffer\n",c->name); + reply_size >>= 16; + reply_size <<= 2; + + reply = kmalloc(reply_size, GFP_KERNEL); + if (!reply) { + printk(KERN_WARNING "%s: Could not allocate reply buffer\n", + c->name); return -ENOMEM; } - memset(reply, 0, REPLY_FRAME_SIZE*4); - sg_offset = (msg[0]>>4)&0x0f; - msg[2] = (u32)i2o_cfg_context; - msg[3] = (u32)reply; + memset(reply, 0, reply_size); + + sg_offset = (msg->u.head[0] >> 4) & 0x0f; - memset(sg_list,0, sizeof(sg_list[0])*SG_TABLESIZE); - if(sg_offset) { + writel(i2o_config_driver.context, &msg->u.s.icntxt); + writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt); + + memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE); + if (sg_offset) { struct sg_simple_element *sg; - if(sg_offset * 4 >= size) { + if (sg_offset * 4 >= size) { rcode = -EFAULT; goto cleanup; } // TODO 64bit fix - sg = (struct sg_simple_element*) (msg+sg_offset); - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); + sg = (struct sg_simple_element *)((&msg->u.head[0]) + + sg_offset); + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); if (sg_count > SG_TABLESIZE) { - printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", c->name,sg_count); - kfree (reply); + printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n", + c->name, sg_count); + kfree(reply); return -EINVAL; } - for(i = 0; i < sg_count; i++) { + for (i = 0; i < sg_count; i++) { int sg_size; - if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) { - printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",c->name,i, sg[i].flag_count); + if (!(sg[i].flag_count & 0x10000000 + /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) { + printk(KERN_DEBUG + "%s:Bad SG element %d - not simple (%x)\n", + c->name, i, sg[i].flag_count); rcode = -EINVAL; goto cleanup; } @@ -923,61 +950,78 @@ /* Allocate memory for the transfer */ p = kmalloc(sg_size, GFP_KERNEL); if (!p) { - printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", c->name,sg_size,i,sg_count); + printk(KERN_DEBUG + "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", + c->name, sg_size, i, sg_count); rcode = -ENOMEM; goto cleanup; } - sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. + sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. /* Copy in the user's SG buffer if necessary */ - if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) { + if (sg[i]. + flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) { // TODO 64bit fix - if (copy_from_user(p,(void __user *)sg[i].addr_bus, sg_size)) { - printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",c->name,i); + if (copy_from_user + (p, (void __user *)sg[i].addr_bus, + sg_size)) { + printk(KERN_DEBUG + "%s: Could not copy SG buf %d FROM user\n", + c->name, i); rcode = -EFAULT; goto cleanup; } } //TODO 64bit fix - sg[i].addr_bus = (u32)virt_to_bus(p); + sg[i].addr_bus = virt_to_bus(p); } } - rcode = i2o_post_wait(c, msg, size, 60); - if(rcode) + rcode = i2o_msg_post_wait(c, m, 60); + if (rcode) goto cleanup; - if(sg_offset) { + if (sg_offset) { + u32 msg[128]; /* Copy back the Scatter Gather buffers back to user space */ u32 j; // TODO 64bit fix - struct sg_simple_element* sg; + struct sg_simple_element *sg; int sg_size; + printk(KERN_INFO "sg_offset\n"); // re-acquire the original message to handle correctly the sg copy operation - memset(&msg, 0, MSG_FRAME_SIZE*4); + memset(&msg, 0, MSG_FRAME_SIZE * 4); // get user msg size in u32s if (get_user(size, &user_msg[0])) { rcode = -EFAULT; goto cleanup; } - size = size>>16; + size = size >> 16; size *= 4; /* Copy in the user's I2O command */ - if (copy_from_user (msg, user_msg, size)) { + if (copy_from_user(msg, user_msg, size)) { rcode = -EFAULT; goto cleanup; } - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); - // TODO 64bit fix - sg = (struct sg_simple_element*)(msg + sg_offset); + // TODO 64bit fix + sg = (struct sg_simple_element *)(msg + sg_offset); for (j = 0; j < sg_count; j++) { /* Copy out the SG list to user's buffer if necessary */ - if (!(sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) { + if (! + (sg[j]. + flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) { sg_size = sg[j].flag_count & 0xffffff; // TODO 64bit fix - if (copy_to_user((void __user *)sg[j].addr_bus,sg_list[j], sg_size)) { - printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",c->name, sg_list[j], sg[j].addr_bus); + if (copy_to_user + ((void __user *)sg[j].addr_bus, sg_list[j], + sg_size)) { + printk(KERN_WARNING + "%s: Could not copy %p TO user %x\n", + c->name, sg_list[j], + sg[j].addr_bus); rcode = -EFAULT; goto cleanup; } @@ -986,37 +1030,109 @@ } /* Copy back the reply to user space */ - if (reply_size) { + if (reply_size) { // we wrote our own values for context - now restore the user supplied ones - if(copy_from_user(reply+2, user_msg+2, sizeof(u32)*2)) { - printk(KERN_WARNING"%s: Could not copy message context FROM user\n",c->name); + printk(KERN_INFO "reply_size\n"); + if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) { + printk(KERN_WARNING + "%s: Could not copy message context FROM user\n", + c->name); rcode = -EFAULT; } - if(copy_to_user(user_reply, reply, reply_size)) { - printk(KERN_WARNING"%s: Could not copy reply TO user\n",c->name); + if (copy_to_user(user_reply, reply, reply_size)) { + printk(KERN_WARNING + "%s: Could not copy reply TO user\n", c->name); rcode = -EFAULT; } } -cleanup: + cleanup: kfree(reply); - i2o_unlock_controller(c); return rcode; } +#endif + +/* + * IOCTL Handler + */ +static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, + unsigned long arg) +{ + int ret; + + switch (cmd) { + case I2OGETIOPS: + ret = i2o_cfg_getiops(arg); + break; + + case I2OHRTGET: + ret = i2o_cfg_gethrt(arg); + break; + + case I2OLCTGET: + ret = i2o_cfg_getlct(arg); + break; + + case I2OPARMSET: + ret = i2o_cfg_parms(arg, I2OPARMSET); + break; + + case I2OPARMGET: + ret = i2o_cfg_parms(arg, I2OPARMGET); + break; + + case I2OSWDL: + ret = i2o_cfg_swdl(arg); + break; + + case I2OSWUL: + ret = i2o_cfg_swul(arg); + break; + + case I2OSWDEL: + ret = i2o_cfg_swdel(arg); + break; + + case I2OVALIDATE: + ret = i2o_cfg_validate(arg); + break; + + case I2OEVTREG: + ret = i2o_cfg_evt_reg(arg, fp); + break; + + case I2OEVTGET: + ret = i2o_cfg_evt_get(arg, fp); + break; + +#ifndef CONFIG_COMPAT + case I2OPASSTHRU: + ret = i2o_cfg_passthru(arg); + break; +#endif + + default: + pr_debug("i2o_config: unknown ioctl called!\n"); + ret = -EINVAL; + } + + return ret; +} static int cfg_open(struct inode *inode, struct file *file) { - struct i2o_cfg_info *tmp = - (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL); + struct i2o_cfg_info *tmp = + (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), + GFP_KERNEL); unsigned long flags; - if(!tmp) + if (!tmp) return -ENOMEM; - file->private_data = (void*)(i2o_cfg_info_id++); + file->private_data = (void *)(i2o_cfg_info_id++); tmp->fp = file; tmp->fasync = NULL; - tmp->q_id = (u32)file->private_data; + tmp->q_id = (ulong) file->private_data; tmp->q_len = 0; tmp->q_in = 0; tmp->q_out = 0; @@ -1026,13 +1142,28 @@ spin_lock_irqsave(&i2o_config_lock, flags); open_files = tmp; spin_unlock_irqrestore(&i2o_config_lock, flags); - + return 0; } +static int cfg_fasync(int fd, struct file *fp, int on) +{ + ulong id = (ulong) fp->private_data; + struct i2o_cfg_info *p; + + for (p = open_files; p; p = p->next) + if (p->q_id == id) + break; + + if (!p) + return -EBADF; + + return fasync_helper(fd, fp, on, &p->fasync); +} + static int cfg_release(struct inode *inode, struct file *file) { - u32 id = (u32)file->private_data; + ulong id = (ulong) file->private_data; struct i2o_cfg_info *p1, *p2; unsigned long flags; @@ -1040,14 +1171,12 @@ p1 = p2 = NULL; spin_lock_irqsave(&i2o_config_lock, flags); - for(p1 = open_files; p1; ) - { - if(p1->q_id == id) - { + for (p1 = open_files; p1;) { + if (p1->q_id == id) { - if(p1->fasync) + if (p1->fasync) cfg_fasync(-1, file, 0); - if(p2) + if (p2) p2->next = p1->next; else open_files = p1->next; @@ -1064,83 +1193,55 @@ return 0; } -static int cfg_fasync(int fd, struct file *fp, int on) -{ - u32 id = (u32)fp->private_data; - struct i2o_cfg_info *p; - - for(p = open_files; p; p = p->next) - if(p->q_id == id) - break; - - if(!p) - return -EBADF; - - return fasync_helper(fd, fp, on, &p->fasync); -} - -static struct file_operations config_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cfg_read, - .write = cfg_write, - .ioctl = cfg_ioctl, - .open = cfg_open, - .release = cfg_release, - .fasync = cfg_fasync, +static struct file_operations config_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = i2o_cfg_ioctl, + .open = cfg_open, + .release = cfg_release, + .fasync = cfg_fasync, }; static struct miscdevice i2o_miscdev = { I2O_MINOR, "i2octl", &config_fops -}; +}; static int __init i2o_config_init(void) { printk(KERN_INFO "I2O configuration manager v 0.04.\n"); printk(KERN_INFO " (C) Copyright 1999 Red Hat Software\n"); - - if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) - { - printk(KERN_ERR "i2o_config: no memory for page buffer.\n"); - return -ENOBUFS; - } - if(misc_register(&i2o_miscdev) < 0) - { + + if (misc_register(&i2o_miscdev) < 0) { printk(KERN_ERR "i2o_config: can't register device.\n"); - kfree(page_buf); return -EBUSY; } /* - * Install our handler + * Install our handler */ - if(i2o_install_handler(&cfg_handler)<0) - { - kfree(page_buf); + if (i2o_driver_register(&i2o_config_driver)) { printk(KERN_ERR "i2o_config: handler register failed.\n"); misc_deregister(&i2o_miscdev); return -EBUSY; } - /* - * The low 16bits of the transaction context must match this - * for everything we post. Otherwise someone else gets our mail - */ - i2o_cfg_context = cfg_handler.context; +#ifdef CONFIG_COMPAT + register_ioctl32_conversion(I2OPASSTHRU32, i2o_cfg_passthru32); + register_ioctl32_conversion(I2OGETIOPS, (void *)sys_ioctl); +#endif return 0; } static void i2o_config_exit(void) { +#ifdef CONFIG_COMPAT + unregister_ioctl32_conversion(I2OPASSTHRU32); + unregister_ioctl32_conversion(I2OGETIOPS); +#endif misc_deregister(&i2o_miscdev); - - if(page_buf) - kfree(page_buf); - if(i2o_cfg_context != -1) - i2o_remove_handler(&cfg_handler); + i2o_driver_unregister(&i2o_config_driver); } - + MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Configuration"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c --- a/drivers/message/i2o/i2o_core.c 2004-10-18 14:56:33 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,3978 +0,0 @@ -/* - * Core I2O structure management - * - * (C) Copyright 1999-2002 Red Hat Software - * - * Written by Alan Cox, Building Number Three Ltd - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * A lot of the I2O message side code from this is taken from the - * Red Creek RCPCI45 adapter driver by Red Creek Communications - * - * Fixes/additions: - * Philipp Rumpf - * Juha Sievänen - * Auvo Häkkinen - * Deepak Saxena - * Boji T Kannanthanam - * Alan Cox : - * Ported to Linux 2.5. - * Markus Lidel : - * Minor fixes for 2.6. - * - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#ifdef CONFIG_MTRR -#include -#endif // CONFIG_MTRR - -#include "i2o_lan.h" - -//#define DRIVERDEBUG - -#ifdef DRIVERDEBUG -#define dprintk(s, args...) printk(s, ## args) -#else -#define dprintk(s, args...) -#endif - -/* OSM table */ -static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES]; - -/* Controller list */ -static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS]; -struct i2o_controller *i2o_controller_chain; -int i2o_num_controllers; - -/* Initiator Context for Core message */ -static int core_context; - -/* Initialization && shutdown functions */ -void i2o_sys_init(void); -static void i2o_sys_shutdown(void); -static int i2o_reset_controller(struct i2o_controller *); -static int i2o_reboot_event(struct notifier_block *, unsigned long , void *); -static int i2o_online_controller(struct i2o_controller *); -static int i2o_init_outbound_q(struct i2o_controller *); -static int i2o_post_outbound_messages(struct i2o_controller *); - -/* Reply handler */ -static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, - struct i2o_message *); - -/* Various helper functions */ -static int i2o_lct_get(struct i2o_controller *); -static int i2o_lct_notify(struct i2o_controller *); -static int i2o_hrt_get(struct i2o_controller *); - -static int i2o_build_sys_table(void); -static int i2o_systab_send(struct i2o_controller *c); - -/* I2O core event handler */ -static int i2o_core_evt(void *); -static int evt_pid; -static int evt_running; - -/* Dynamic LCT update handler */ -static int i2o_dyn_lct(void *); - -void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *); - -static void i2o_pci_dispose(struct i2o_controller *c); - -/* - * I2O System Table. Contains information about - * all the IOPs in the system. Used to inform IOPs - * about each other's existence. - * - * sys_tbl_ver is the CurrentChangeIndicator that is - * used by IOPs to track changes. - */ -static struct i2o_sys_tbl *sys_tbl; -static int sys_tbl_ind; -static int sys_tbl_len; - -/* - * This spin lock is used to keep a device from being - * added and deleted concurrently across CPUs or interrupts. - * This can occur when a user creates a device and immediatelly - * deletes it before the new_dev_notify() handler is called. - */ -static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED; - -/* - * Structures and definitions for synchronous message posting. - * See i2o_post_wait() for description. - */ -struct i2o_post_wait_data -{ - int *status; /* Pointer to status block on caller stack */ - int *complete; /* Pointer to completion flag on caller stack */ - u32 id; /* Unique identifier */ - wait_queue_head_t *wq; /* Wake up for caller (NULL for dead) */ - struct i2o_post_wait_data *next; /* Chain */ - void *mem[2]; /* Memory blocks to recover on failure path */ - dma_addr_t phys[2]; /* Physical address of blocks to recover */ - u32 size[2]; /* Size of blocks to recover */ -}; - -static struct i2o_post_wait_data *post_wait_queue; -static u32 post_wait_id; // Unique ID for each post_wait -static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED; -static void i2o_post_wait_complete(struct i2o_controller *, u32, int); - -/* OSM descriptor handler */ -static struct i2o_handler i2o_core_handler = -{ - (void *)i2o_core_reply, - NULL, - NULL, - NULL, - "I2O core layer", - 0, - I2O_CLASS_EXECUTIVE -}; - -/* - * Used when queueing a reply to be handled later - */ - -struct reply_info -{ - struct i2o_controller *iop; - u32 msg[MSG_FRAME_SIZE]; -}; -static struct reply_info evt_reply; -static struct reply_info events[I2O_EVT_Q_LEN]; -static int evt_in; -static int evt_out; -static int evt_q_len; -#define MODINC(x,y) ((x) = ((x) + 1) % (y)) - -/* - * I2O configuration spinlock. This isnt a big deal for contention - * so we have one only - */ - -static DECLARE_MUTEX(i2o_configuration_lock); - -/* - * Event spinlock. Used to keep event queue sane and from - * handling multiple events simultaneously. - */ -static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED; - -/* - * Semaphore used to synchronize event handling thread with - * interrupt handler. - */ - -static DECLARE_MUTEX(evt_sem); -static DECLARE_COMPLETION(evt_dead); -static DECLARE_WAIT_QUEUE_HEAD(evt_wait); - -static struct notifier_block i2o_reboot_notifier = -{ - i2o_reboot_event, - NULL, - 0 -}; - -/* - * Config options - */ - -static int verbose; - -#if BITS_PER_LONG == 64 -/** - * i2o_context_list_add - append an ptr to the context list and return a - * matching context id. - * @ptr: pointer to add to the context list - * @c: controller to which the context list belong - * returns context id, which could be used in the transaction context - * field. - * - * Because the context field in I2O is only 32-bit large, on 64-bit the - * pointer is to large to fit in the context field. The i2o_context_list - * functiones map pointers to context fields. - */ -u32 i2o_context_list_add(void *ptr, struct i2o_controller *c) { - u32 context = 1; - struct i2o_context_list_element **entry = &c->context_list; - struct i2o_context_list_element *element; - unsigned long flags; - - spin_lock_irqsave(&c->context_list_lock, flags); - while(*entry && ((*entry)->flags & I2O_CONTEXT_LIST_USED)) { - if((*entry)->context >= context) - context = (*entry)->context + 1; - entry = &((*entry)->next); - } - - if(!*entry) { - if(unlikely(!context)) { - spin_unlock_irqrestore(&c->context_list_lock, flags); - printk(KERN_EMERG "i2o_core: context list overflow\n"); - return 0; - } - - element = kmalloc(sizeof(struct i2o_context_list_element), GFP_KERNEL); - if(!element) { - printk(KERN_EMERG "i2o_core: could not allocate memory for context list element\n"); - return 0; - } - element->context = context; - element->next = NULL; - *entry = element; - } else - element = *entry; - - element->ptr = ptr; - element->flags = I2O_CONTEXT_LIST_USED; - - spin_unlock_irqrestore(&c->context_list_lock, flags); - dprintk(KERN_DEBUG "i2o_core: add context to list %p -> %d\n", ptr, context); - return context; -} - -/** - * i2o_context_list_remove - remove a ptr from the context list and return - * the matching context id. - * @ptr: pointer to be removed from the context list - * @c: controller to which the context list belong - * returns context id, which could be used in the transaction context - * field. - */ -u32 i2o_context_list_remove(void *ptr, struct i2o_controller *c) { - struct i2o_context_list_element **entry = &c->context_list; - struct i2o_context_list_element *element; - u32 context; - unsigned long flags; - - spin_lock_irqsave(&c->context_list_lock, flags); - while(*entry && ((*entry)->ptr != ptr)) - entry = &((*entry)->next); - - if(unlikely(!*entry)) { - spin_unlock_irqrestore(&c->context_list_lock, flags); - printk(KERN_WARNING "i2o_core: could not remove nonexistent ptr %p\n", ptr); - return 0; - } - - element = *entry; - - context = element->context; - element->ptr = NULL; - element->flags |= I2O_CONTEXT_LIST_DELETED; - - spin_unlock_irqrestore(&c->context_list_lock, flags); - dprintk(KERN_DEBUG "i2o_core: markt as deleted in context list %p -> %d\n", ptr, context); - return context; -} - -/** - * i2o_context_list_get - get a ptr from the context list and remove it - * from the list. - * @context: context id to which the pointer belong - * @c: controller to which the context list belong - * returns pointer to the matching context id - */ -void *i2o_context_list_get(u32 context, struct i2o_controller *c) { - struct i2o_context_list_element **entry = &c->context_list; - struct i2o_context_list_element *element; - void *ptr; - int count = 0; - unsigned long flags; - - spin_lock_irqsave(&c->context_list_lock, flags); - while(*entry && ((*entry)->context != context)) { - entry = &((*entry)->next); - count ++; - } - - if(unlikely(!*entry)) { - spin_unlock_irqrestore(&c->context_list_lock, flags); - printk(KERN_WARNING "i2o_core: context id %d not found\n", context); - return NULL; - } - - element = *entry; - ptr = element->ptr; - if(count >= I2O_CONTEXT_LIST_MIN_LENGTH) { - *entry = (*entry)->next; - kfree(element); - } else { - element->ptr = NULL; - element->flags &= !I2O_CONTEXT_LIST_USED; - } - - spin_unlock_irqrestore(&c->context_list_lock, flags); - dprintk(KERN_DEBUG "i2o_core: get ptr from context list %d -> %p\n", context, ptr); - return ptr; -} -#endif - -/* - * I2O Core reply handler - */ -static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, - struct i2o_message *m) -{ - u32 *msg=(u32 *)m; - u32 status; - u32 context = msg[2]; - - if (msg[0] & MSG_FAIL) // Fail bit is set - { - u32 *preserved_msg = (u32*)(c->msg_virt + msg[7]); - - i2o_report_status(KERN_INFO, "i2o_core", msg); - i2o_dump_message(preserved_msg); - - /* If the failed request needs special treatment, - * it should be done here. */ - - /* Release the preserved msg by resubmitting it as a NOP */ - - preserved_msg[0] = cpu_to_le32(THREE_WORD_MSG_SIZE | SGL_OFFSET_0); - preserved_msg[1] = cpu_to_le32(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0); - preserved_msg[2] = 0; - i2o_post_message(c, msg[7]); - - /* If reply to i2o_post_wait failed, return causes a timeout */ - - return; - } - -#ifdef DRIVERDEBUG - i2o_report_status(KERN_INFO, "i2o_core", msg); -#endif - - if(msg[2]&0x80000000) // Post wait message - { - if (msg[4] >> 24) - status = (msg[4] & 0xFFFF); - else - status = I2O_POST_WAIT_OK; - - i2o_post_wait_complete(c, context, status); - return; - } - - if(m->function == I2O_CMD_UTIL_EVT_REGISTER) - { - memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2); - events[evt_in].iop = c; - - spin_lock(&i2o_evt_lock); - MODINC(evt_in, I2O_EVT_Q_LEN); - if(evt_q_len == I2O_EVT_Q_LEN) - MODINC(evt_out, I2O_EVT_Q_LEN); - else - evt_q_len++; - spin_unlock(&i2o_evt_lock); - - up(&evt_sem); - wake_up_interruptible(&evt_wait); - return; - } - - if(m->function == I2O_CMD_LCT_NOTIFY) - { - up(&c->lct_sem); - return; - } - - /* - * If this happens, we want to dump the message to the syslog so - * it can be sent back to the card manufacturer by the end user - * to aid in debugging. - * - */ - printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" - "Message dumped to syslog\n", - c->name); - i2o_dump_message(msg); - - return; -} - -/** - * i2o_install_handler - install a message handler - * @h: Handler structure - * - * Install an I2O handler - these handle the asynchronous messaging - * from the card once it has initialised. If the table of handlers is - * full then -ENOSPC is returned. On a success 0 is returned and the - * context field is set by the function. The structure is part of the - * system from this time onwards. It must not be freed until it has - * been uninstalled - */ - -int i2o_install_handler(struct i2o_handler *h) -{ - int i; - down(&i2o_configuration_lock); - for(i=0;icontext = i; - i2o_handlers[i]=h; - up(&i2o_configuration_lock); - return 0; - } - } - up(&i2o_configuration_lock); - return -ENOSPC; -} - -/** - * i2o_remove_handler - remove an i2o message handler - * @h: handler - * - * Remove a message handler previously installed with i2o_install_handler. - * After this function returns the handler object can be freed or re-used - */ - -int i2o_remove_handler(struct i2o_handler *h) -{ - i2o_handlers[h->context]=NULL; - return 0; -} - - -/* - * Each I2O controller has a chain of devices on it. - * Each device has a pointer to its LCT entry to be used - * for fun purposes. - */ - -/** - * i2o_install_device - attach a device to a controller - * @c: controller - * @d: device - * - * Add a new device to an i2o controller. This can be called from - * non interrupt contexts only. It adds the device and marks it as - * unclaimed. The device memory becomes part of the kernel and must - * be uninstalled before being freed or reused. Zero is returned - * on success. - */ - -int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) -{ - int i; - - down(&i2o_configuration_lock); - d->controller=c; - d->owner=NULL; - d->next=c->devices; - d->prev=NULL; - if (c->devices != NULL) - c->devices->prev=d; - c->devices=d; - *d->dev_name = 0; - - for(i = 0; i < I2O_MAX_MANAGERS; i++) - d->managers[i] = NULL; - - up(&i2o_configuration_lock); - return 0; -} - -/* we need this version to call out of i2o_delete_controller */ - -int __i2o_delete_device(struct i2o_device *d) -{ - struct i2o_device **p; - int i; - - p=&(d->controller->devices); - - /* - * Hey we have a driver! - * Check to see if the driver wants us to notify it of - * device deletion. If it doesn't we assume that it - * is unsafe to delete a device with an owner and - * fail. - */ - if(d->owner) - { - if(d->owner->dev_del_notify) - { - dprintk(KERN_INFO "Device has owner, notifying\n"); - d->owner->dev_del_notify(d->controller, d); - if(d->owner) - { - printk(KERN_WARNING - "Driver \"%s\" did not release device!\n", d->owner->name); - return -EBUSY; - } - } - else - return -EBUSY; - } - - /* - * Tell any other users who are talking to this device - * that it's going away. We assume that everything works. - */ - for(i=0; i < I2O_MAX_MANAGERS; i++) - { - if(d->managers[i] && d->managers[i]->dev_del_notify) - d->managers[i]->dev_del_notify(d->controller, d); - } - - while(*p!=NULL) - { - if(*p==d) - { - /* - * Destroy - */ - *p=d->next; - kfree(d); - return 0; - } - p=&((*p)->next); - } - printk(KERN_ERR "i2o_delete_device: passed invalid device.\n"); - return -EINVAL; -} - -/** - * i2o_delete_device - remove an i2o device - * @d: device to remove - * - * This function unhooks a device from a controller. The device - * will not be unhooked if it has an owner who does not wish to free - * it, or if the owner lacks a dev_del_notify function. In that case - * -EBUSY is returned. On success 0 is returned. Other errors cause - * negative errno values to be returned - */ - -int i2o_delete_device(struct i2o_device *d) -{ - int ret; - - down(&i2o_configuration_lock); - - /* - * Seek, locate - */ - - ret = __i2o_delete_device(d); - - up(&i2o_configuration_lock); - - return ret; -} - -/** - * i2o_install_controller - attach a controller - * @c: controller - * - * Add a new controller to the i2o layer. This can be called from - * non interrupt contexts only. It adds the controller and marks it as - * unused with no devices. If the tables are full or memory allocations - * fail then a negative errno code is returned. On success zero is - * returned and the controller is bound to the system. The structure - * must not be freed or reused until being uninstalled. - */ - -int i2o_install_controller(struct i2o_controller *c) -{ - int i; - down(&i2o_configuration_lock); - for(i=0;idlct = (i2o_lct*)pci_alloc_consistent(c->pdev, 8192, &c->dlct_phys); - if(c->dlct==NULL) - { - up(&i2o_configuration_lock); - return -ENOMEM; - } - i2o_controllers[i]=c; - c->devices = NULL; - c->next=i2o_controller_chain; - i2o_controller_chain=c; - c->unit = i; - c->page_frame = NULL; - c->hrt = NULL; - c->hrt_len = 0; - c->lct = NULL; - c->status_block = NULL; - sprintf(c->name, "i2o/iop%d", i); - i2o_num_controllers++; - init_MUTEX_LOCKED(&c->lct_sem); - up(&i2o_configuration_lock); - return 0; - } - } - printk(KERN_ERR "No free i2o controller slots.\n"); - up(&i2o_configuration_lock); - return -EBUSY; -} - -/** - * i2o_delete_controller - delete a controller - * @c: controller - * - * Remove an i2o controller from the system. If the controller or its - * devices are busy then -EBUSY is returned. On a failure a negative - * errno code is returned. On success zero is returned. - */ - -int i2o_delete_controller(struct i2o_controller *c) -{ - struct i2o_controller **p; - int users; - char name[16]; - int stat; - - dprintk(KERN_INFO "Deleting controller %s\n", c->name); - - /* - * Clear event registration as this can cause weird behavior - */ - if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) - i2o_event_register(c, core_context, 0, 0, 0); - - down(&i2o_configuration_lock); - if((users=atomic_read(&c->users))) - { - dprintk(KERN_INFO "I2O: %d users for controller %s\n", users, - c->name); - up(&i2o_configuration_lock); - return -EBUSY; - } - while(c->devices) - { - if(__i2o_delete_device(c->devices)<0) - { - /* Shouldnt happen */ - I2O_IRQ_WRITE32(c, 0xFFFFFFFF); - c->enabled = 0; - up(&i2o_configuration_lock); - return -EBUSY; - } - } - - /* - * If this is shutdown time, the thread's already been killed - */ - if(c->lct_running) { - stat = kill_proc(c->lct_pid, SIGKILL, 1); - if(!stat) { - int count = 10 * 100; - while(c->lct_running && --count) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR - "%s: LCT thread still running!\n", - c->name); - } - } - - p=&i2o_controller_chain; - - while(*p) - { - if(*p==c) - { - /* Ask the IOP to switch to RESET state */ - i2o_reset_controller(c); - - /* Release IRQ */ - i2o_pci_dispose(c); - - *p=c->next; - up(&i2o_configuration_lock); - - if(c->page_frame) - { - pci_unmap_single(c->pdev, c->page_frame_map, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE); - kfree(c->page_frame); - } - if(c->hrt) - pci_free_consistent(c->pdev, c->hrt_len, c->hrt, c->hrt_phys); - if(c->lct) - pci_free_consistent(c->pdev, c->lct->table_size << 2, c->lct, c->lct_phys); - if(c->status_block) - pci_free_consistent(c->pdev, sizeof(i2o_status_block), c->status_block, c->status_block_phys); - if(c->dlct) - pci_free_consistent(c->pdev, 8192, c->dlct, c->dlct_phys); - - i2o_controllers[c->unit]=NULL; - memcpy(name, c->name, strlen(c->name)+1); - kfree(c); - dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name); - - i2o_num_controllers--; - return 0; - } - p=&((*p)->next); - } - up(&i2o_configuration_lock); - printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); - return -ENOENT; -} - -/** - * i2o_unlock_controller - unlock a controller - * @c: controller to unlock - * - * Take a lock on an i2o controller. This prevents it being deleted. - * i2o controllers are not refcounted so a deletion of an in use device - * will fail, not take affect on the last dereference. - */ - -void i2o_unlock_controller(struct i2o_controller *c) -{ - atomic_dec(&c->users); -} - -/** - * i2o_find_controller - return a locked controller - * @n: controller number - * - * Returns a pointer to the controller object. The controller is locked - * on return. NULL is returned if the controller is not found. - */ - -struct i2o_controller *i2o_find_controller(int n) -{ - struct i2o_controller *c; - - if(n<0 || n>=MAX_I2O_CONTROLLERS) - return NULL; - - down(&i2o_configuration_lock); - c=i2o_controllers[n]; - if(c!=NULL) - atomic_inc(&c->users); - up(&i2o_configuration_lock); - return c; -} - -/** - * i2o_issue_claim - claim or release a device - * @cmd: command - * @c: controller to claim for - * @tid: i2o task id - * @type: type of claim - * - * Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent - * is set by cmd. The tid is the task id of the object to claim and the - * type is the claim type (see the i2o standard) - * - * Zero is returned on success. - */ - -static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type) -{ - u32 msg[5]; - - msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = cmd << 24 | HOST_TID<<12 | tid; - msg[3] = 0; - msg[4] = type; - - return i2o_post_wait(c, msg, sizeof(msg), 60); -} - -/* - * i2o_claim_device - claim a device for use by an OSM - * @d: device to claim - * @h: handler for this device - * - * Do the leg work to assign a device to a given OSM on Linux. The - * kernel updates the internal handler data for the device and then - * performs an I2O claim for the device, attempting to claim the - * device as primary. If the attempt fails a negative errno code - * is returned. On success zero is returned. - */ - -int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h) -{ - int ret = 0; - - down(&i2o_configuration_lock); - if (d->owner) { - printk(KERN_INFO "Device claim called, but dev already owned by %s!", - h->name); - ret = -EBUSY; - goto out; - } - d->owner=h; - - if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, - I2O_CLAIM_PRIMARY)) - { - d->owner = NULL; - ret = -EBUSY; - } -out: - up(&i2o_configuration_lock); - return ret; -} - -/** - * i2o_release_device - release a device that the OSM is using - * @d: device to claim - * @h: handler for this device - * - * Drop a claim by an OSM on a given I2O device. The handler is cleared - * and 0 is returned on success. - * - * AC - some devices seem to want to refuse an unclaim until they have - * finished internal processing. It makes sense since you don't want a - * new device to go reconfiguring the entire system until you are done. - * Thus we are prepared to wait briefly. - */ - -int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) -{ - int err = 0; - int tries; - - down(&i2o_configuration_lock); - if (d->owner != h) { - printk(KERN_INFO "Claim release called, but not owned by %s!\n", - h->name); - up(&i2o_configuration_lock); - return -ENOENT; - } - - for(tries=0;tries<10;tries++) - { - d->owner = NULL; - - /* - * If the controller takes a nonblocking approach to - * releases we have to sleep/poll for a few times. - */ - - if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) ) - { - err = -ENXIO; - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); - } - else - { - err=0; - break; - } - } - up(&i2o_configuration_lock); - return err; -} - -/** - * i2o_device_notify_on - Enable deletion notifiers - * @d: device for notification - * @h: handler to install - * - * Called by OSMs to let the core know that they want to be - * notified if the given device is deleted from the system. - */ - -int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h) -{ - int i; - - if(d->num_managers == I2O_MAX_MANAGERS) - return -ENOSPC; - - for(i = 0; i < I2O_MAX_MANAGERS; i++) - { - if(!d->managers[i]) - { - d->managers[i] = h; - break; - } - } - - d->num_managers++; - - return 0; -} - -/** - * i2o_device_notify_off - Remove deletion notifiers - * @d: device for notification - * @h: handler to remove - * - * Called by OSMs to let the core know that they no longer - * are interested in the fate of the given device. - */ -int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h) -{ - int i; - - for(i=0; i < I2O_MAX_MANAGERS; i++) - { - if(d->managers[i] == h) - { - d->managers[i] = NULL; - d->num_managers--; - return 0; - } - } - - return -ENOENT; -} - -/** - * i2o_event_register - register interest in an event - * @c: Controller to register interest with - * @tid: I2O task id - * @init_context: initiator context to use with this notifier - * @tr_context: transaction context to use with this notifier - * @evt_mask: mask of events - * - * Create and posts an event registration message to the task. No reply - * is waited for, or expected. Errors in posting will be reported. - */ - -int i2o_event_register(struct i2o_controller *c, u32 tid, - u32 init_context, u32 tr_context, u32 evt_mask) -{ - u32 msg[5]; // Not performance critical, so we just - // i2o_post_this it instead of building it - // in IOP memory - - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid; - msg[2] = init_context; - msg[3] = tr_context; - msg[4] = evt_mask; - - return i2o_post_this(c, msg, sizeof(msg)); -} - -/* - * i2o_event_ack - acknowledge an event - * @c: controller - * @msg: pointer to the UTIL_EVENT_REGISTER reply we received - * - * We just take a pointer to the original UTIL_EVENT_REGISTER reply - * message and change the function code since that's what spec - * describes an EventAck message looking like. - */ - -int i2o_event_ack(struct i2o_controller *c, u32 *msg) -{ - struct i2o_message *m = (struct i2o_message *)msg; - - m->function = I2O_CMD_UTIL_EVT_ACK; - - return i2o_post_wait(c, msg, m->size * 4, 2); -} - -/* - * Core event handler. Runs as a separate thread and is woken - * up whenever there is an Executive class event. - */ -static int i2o_core_evt(void *reply_data) -{ - struct reply_info *reply = (struct reply_info *) reply_data; - u32 *msg = reply->msg; - struct i2o_controller *c = NULL; - unsigned long flags; - - daemonize("i2oevtd"); - allow_signal(SIGKILL); - - evt_running = 1; - - while(1) - { - if(down_interruptible(&evt_sem)) - { - dprintk(KERN_INFO "I2O event thread dead\n"); - printk("exiting..."); - evt_running = 0; - complete_and_exit(&evt_dead, 0); - } - - /* - * Copy the data out of the queue so that we don't have to lock - * around the whole function and just around the qlen update - */ - spin_lock_irqsave(&i2o_evt_lock, flags); - memcpy(reply, &events[evt_out], sizeof(struct reply_info)); - MODINC(evt_out, I2O_EVT_Q_LEN); - evt_q_len--; - spin_unlock_irqrestore(&i2o_evt_lock, flags); - - c = reply->iop; - dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]); - - /* - * We do not attempt to delete/quiesce/etc. the controller if - * some sort of error indidication occurs. We may want to do - * so in the future, but for now we just let the user deal with - * it. One reason for this is that what to do with an error - * or when to send what ćrror is not really agreed on, so - * we get errors that may not be fatal but just look like they - * are...so let the user deal with it. - */ - switch(msg[4]) - { - case I2O_EVT_IND_EXEC_RESOURCE_LIMITS: - printk(KERN_ERR "%s: Out of resources\n", c->name); - break; - - case I2O_EVT_IND_EXEC_POWER_FAIL: - printk(KERN_ERR "%s: Power failure\n", c->name); - break; - - case I2O_EVT_IND_EXEC_HW_FAIL: - { - char *fail[] = - { - "Unknown Error", - "Power Lost", - "Code Violation", - "Parity Error", - "Code Execution Exception", - "Watchdog Timer Expired" - }; - - if(msg[5] <= 6) - printk(KERN_ERR "%s: Hardware Failure: %s\n", - c->name, fail[msg[5]]); - else - printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name); - - break; - } - - /* - * New device created - * - Create a new i2o_device entry - * - Inform all interested drivers about this device's existence - */ - case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY: - { - struct i2o_device *d = (struct i2o_device *) - kmalloc(sizeof(struct i2o_device), GFP_KERNEL); - int i; - - if (d == NULL) { - printk(KERN_EMERG "i2oevtd: out of memory\n"); - break; - } - memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry)); - - d->next = NULL; - d->controller = c; - d->flags = 0; - - i2o_report_controller_unit(c, d); - i2o_install_device(c,d); - - for(i = 0; i < MAX_I2O_MODULES; i++) - { - if(i2o_handlers[i] && - i2o_handlers[i]->new_dev_notify && - (i2o_handlers[i]->class&d->lct_data.class_id)) - { - spin_lock(&i2o_dev_lock); - i2o_handlers[i]->new_dev_notify(c,d); - spin_unlock(&i2o_dev_lock); - } - } - - break; - } - - /* - * LCT entry for a device has been modified, so update it - * internally. - */ - case I2O_EVT_IND_EXEC_MODIFIED_LCT: - { - struct i2o_device *d; - i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5]; - - for(d = c->devices; d; d = d->next) - { - if(d->lct_data.tid == new_lct->tid) - { - memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry)); - break; - } - } - break; - } - - case I2O_EVT_IND_CONFIGURATION_FLAG: - printk(KERN_WARNING "%s requires user configuration\n", c->name); - break; - - case I2O_EVT_IND_GENERAL_WARNING: - printk(KERN_WARNING "%s: Warning notification received!" - "Check configuration for errors!\n", c->name); - break; - - case I2O_EVT_IND_EVT_MASK_MODIFIED: - /* Well I guess that was us hey .. */ - break; - - default: - printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]); - break; - } - } - - return 0; -} - -/* - * Dynamic LCT update. This compares the LCT with the currently - * installed devices to check for device deletions..this needed b/c there - * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so - * we can't just have the event handler do this...annoying - * - * This is a hole in the spec that will hopefully be fixed someday. - */ -static int i2o_dyn_lct(void *foo) -{ - struct i2o_controller *c = (struct i2o_controller *)foo; - struct i2o_device *d = NULL; - struct i2o_device *d1 = NULL; - int i = 0; - int found = 0; - int entries; - void *tmp; - - daemonize("iop%d_lctd", c->unit); - allow_signal(SIGKILL); - - c->lct_running = 1; - - while(1) - { - down_interruptible(&c->lct_sem); - if(signal_pending(current)) - { - dprintk(KERN_ERR "%s: LCT thread dead\n", c->name); - c->lct_running = 0; - return 0; - } - - entries = c->dlct->table_size; - entries -= 3; - entries /= 9; - - dprintk(KERN_INFO "%s: Dynamic LCT Update\n",c->name); - dprintk(KERN_INFO "%s: Dynamic LCT contains %d entries\n", c->name, entries); - - if(!entries) - { - printk(KERN_INFO "%s: Empty LCT???\n", c->name); - continue; - } - - /* - * Loop through all the devices on the IOP looking for their - * LCT data in the LCT. We assume that TIDs are not repeated. - * as that is the only way to really tell. It's been confirmed - * by the IRTOS vendor(s?) that TIDs are not reused until they - * wrap arround(4096), and I doubt a system will up long enough - * to create/delete that many devices. - */ - for(d = c->devices; d; ) - { - found = 0; - d1 = d->next; - - for(i = 0; i < entries; i++) - { - if(d->lct_data.tid == c->dlct->lct_entry[i].tid) - { - found = 1; - break; - } - } - if(!found) - { - dprintk(KERN_INFO "i2o_core: Deleted device!\n"); - spin_lock(&i2o_dev_lock); - i2o_delete_device(d); - spin_unlock(&i2o_dev_lock); - } - d = d1; - } - - /* - * Tell LCT to renotify us next time there is a change - */ - i2o_lct_notify(c); - - /* - * Copy new LCT into public LCT - * - * Possible race if someone is reading LCT while we are copying - * over it. If this happens, we'll fix it then. but I doubt that - * the LCT will get updated often enough or will get read by - * a user often enough to worry. - */ - if(c->lct->table_size < c->dlct->table_size) - { - dma_addr_t phys; - tmp = c->lct; - c->lct = pci_alloc_consistent(c->pdev, c->dlct->table_size<<2, &phys); - if(!c->lct) - { - printk(KERN_ERR "%s: No memory for LCT!\n", c->name); - c->lct = tmp; - continue; - } - pci_free_consistent(tmp, c->lct->table_size << 2, c->lct, c->lct_phys); - c->lct_phys = phys; - } - memcpy(c->lct, c->dlct, c->dlct->table_size<<2); - } - - return 0; -} - -/** - * i2o_run_queue - process pending events on a controller - * @c: controller to process - * - * This is called by the bus specific driver layer when an interrupt - * or poll of this card interface is desired. - */ - -void i2o_run_queue(struct i2o_controller *c) -{ - struct i2o_message *m; - u32 mv; - u32 *msg; - - /* - * Old 960 steppings had a bug in the I2O unit that caused - * the queue to appear empty when it wasn't. - */ - if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) - mv=I2O_REPLY_READ32(c); - - while(mv!=0xFFFFFFFF) - { - struct i2o_handler *i; - /* Map the message from the page frame map to kernel virtual */ - /* m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); */ - m=(struct i2o_message *)bus_to_virt(mv); - msg=(u32*)m; - - /* - * Ensure this message is seen coherently but cachably by - * the processor - */ - - pci_dma_sync_single_for_cpu(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE); - - /* - * Despatch it - */ - - i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; - if(i && i->reply) - i->reply(i,c,m); - else - { - printk(KERN_WARNING "I2O: Spurious reply to handler %d\n", - m->initiator_context&(MAX_I2O_MODULES-1)); - } - i2o_flush_reply(c,mv); - mb(); - - /* That 960 bug again... */ - if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) - mv=I2O_REPLY_READ32(c); - } -} - - -/** - * i2o_get_class_name - do i2o class name lookup - * @class: class number - * - * Return a descriptive string for an i2o class - */ - -const char *i2o_get_class_name(int class) -{ - int idx = 16; - static char *i2o_class_name[] = { - "Executive", - "Device Driver Module", - "Block Device", - "Tape Device", - "LAN Interface", - "WAN Interface", - "Fibre Channel Port", - "Fibre Channel Device", - "SCSI Device", - "ATE Port", - "ATE Device", - "Floppy Controller", - "Floppy Device", - "Secondary Bus Port", - "Peer Transport Agent", - "Peer Transport", - "Unknown" - }; - - switch(class&0xFFF) - { - case I2O_CLASS_EXECUTIVE: - idx = 0; break; - case I2O_CLASS_DDM: - idx = 1; break; - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - idx = 2; break; - case I2O_CLASS_SEQUENTIAL_STORAGE: - idx = 3; break; - case I2O_CLASS_LAN: - idx = 4; break; - case I2O_CLASS_WAN: - idx = 5; break; - case I2O_CLASS_FIBRE_CHANNEL_PORT: - idx = 6; break; - case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: - idx = 7; break; - case I2O_CLASS_SCSI_PERIPHERAL: - idx = 8; break; - case I2O_CLASS_ATE_PORT: - idx = 9; break; - case I2O_CLASS_ATE_PERIPHERAL: - idx = 10; break; - case I2O_CLASS_FLOPPY_CONTROLLER: - idx = 11; break; - case I2O_CLASS_FLOPPY_DEVICE: - idx = 12; break; - case I2O_CLASS_BUS_ADAPTER_PORT: - idx = 13; break; - case I2O_CLASS_PEER_TRANSPORT_AGENT: - idx = 14; break; - case I2O_CLASS_PEER_TRANSPORT: - idx = 15; break; - } - - return i2o_class_name[idx]; -} - - -/** - * i2o_wait_message - obtain an i2o message from the IOP - * @c: controller - * @why: explanation - * - * This function waits up to 5 seconds for a message slot to be - * available. If no message is available it prints an error message - * that is expected to be what the message will be used for (eg - * "get_status"). 0xFFFFFFFF is returned on a failure. - * - * On a success the message is returned. This is the physical page - * frame offset address from the read port. (See the i2o spec) - */ - -u32 i2o_wait_message(struct i2o_controller *c, char *why) -{ - long time=jiffies; - u32 m; - while((m=I2O_POST_READ32(c))==0xFFFFFFFF) - { - if((jiffies-time)>=5*HZ) - { - dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", - c->name, why); - return 0xFFFFFFFF; - } - schedule(); - barrier(); - } - return m; -} - -/** - * i2o_report_controller_unit - print information about a tid - * @c: controller - * @d: device - * - * Dump an information block associated with a given unit (TID). The - * tables are read and a block of text is output to printk that is - * formatted intended for the user. - */ - -void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) -{ - char buf[64]; - char str[22]; - int ret; - int unit = d->lct_data.tid; - - if(verbose==0) - return; - - printk(KERN_INFO "Target ID %d.\n", unit); - if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0) - { - buf[16]=0; - printk(KERN_INFO " Vendor: %s\n", buf); - } - if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0) - { - buf[16]=0; - printk(KERN_INFO " Device: %s\n", buf); - } - if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0) - { - buf[16]=0; - printk(KERN_INFO " Description: %s\n", buf); - } - if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0) - { - buf[8]=0; - printk(KERN_INFO " Rev: %s\n", buf); - } - - printk(KERN_INFO " Class: "); - sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id)); - printk("%s\n", str); - - printk(KERN_INFO " Subclass: 0x%04X\n", d->lct_data.sub_class); - printk(KERN_INFO " Flags: "); - - if(d->lct_data.device_flags&(1<<0)) - printk("C"); // ConfigDialog requested - if(d->lct_data.device_flags&(1<<1)) - printk("U"); // Multi-user capable - if(!(d->lct_data.device_flags&(1<<4))) - printk("P"); // Peer service enabled! - if(!(d->lct_data.device_flags&(1<<5))) - printk("M"); // Mgmt service enabled! - printk("\n"); - -} - - -/* - * Parse the hardware resource table. Right now we print it out - * and don't do a lot with it. We should collate these and then - * interact with the Linux resource allocation block. - * - * Lets prove we can read it first eh ? - * - * This is full of endianisms! - */ - -static int i2o_parse_hrt(struct i2o_controller *c) -{ -#ifdef DRIVERDEBUG - u32 *rows=(u32*)c->hrt; - u8 *p=(u8 *)c->hrt; - u8 *d; - int count; - int length; - int i; - int state; - - if(p[3]!=0) - { - printk(KERN_ERR "%s: HRT table for controller is too new a version.\n", - c->name); - return -1; - } - - count=p[0]|(p[1]<<8); - length = p[2]; - - printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n", - c->name, count, length<<2); - - rows+=2; - - for(i=0;i>=12; - if(state&(1<<0)) - printk("H"); /* Hidden */ - if(state&(1<<2)) - { - printk("P"); /* Present */ - if(state&(1<<1)) - printk("C"); /* Controlled */ - } - if(state>9) - printk("*"); /* Hard */ - - printk("]:"); - - switch(p[3]&0xFFFF) - { - case 0: - /* Adapter private bus - easy */ - printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", - p[2], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - case 1: - /* ISA bus */ - printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", - p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - - case 2: /* EISA bus */ - printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X", - p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - - case 3: /* MCA bus */ - printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", - p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - - case 4: /* PCI bus */ - printk("PCI %d: Bus %d Device %d Function %d", - p[2], d[2], d[1], d[0]); - break; - - case 0x80: /* Other */ - default: - printk("Unsupported bus type."); - break; - } - printk("\n"); - rows+=length; - } -#endif - return 0; -} - -/* - * The logical configuration table tells us what we can talk to - * on the board. Most of the stuff isn't interesting to us. - */ - -static int i2o_parse_lct(struct i2o_controller *c) -{ - int i; - int max; - int tid; - struct i2o_device *d; - i2o_lct *lct = c->lct; - - if (lct == NULL) { - printk(KERN_ERR "%s: LCT is empty???\n", c->name); - return -1; - } - - max = lct->table_size; - max -= 3; - max /= 9; - - printk(KERN_INFO "%s: LCT has %d entries.\n", c->name, max); - - if(lct->iop_flags&(1<<0)) - printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name); - - for(i=0;icontroller = c; - d->next = NULL; - - memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); - - d->flags = 0; - tid = d->lct_data.tid; - - i2o_report_controller_unit(c, d); - - i2o_install_device(c, d); - } - return 0; -} - - -/** - * i2o_quiesce_controller - quiesce controller - * @c: controller - * - * Quiesce an IOP. Causes IOP to make external operation quiescent - * (i2o 'READY' state). Internal operation of the IOP continues normally. - */ - -int i2o_quiesce_controller(struct i2o_controller *c) -{ - u32 msg[4]; - int ret; - - i2o_status_get(c); - - /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ - - if ((c->status_block->iop_state != ADAPTER_STATE_READY) && - (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) - { - return 0; - } - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; - msg[3] = 0; - - /* Long timeout needed for quiesce if lots of devices */ - - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) - printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n", - c->name, -ret); - else - dprintk(KERN_INFO "%s: Quiesced.\n", c->name); - - i2o_status_get(c); // Entered READY state - return ret; -} - -/** - * i2o_enable_controller - move controller from ready to operational - * @c: controller - * - * Enable IOP. This allows the IOP to resume external operations and - * reverses the effect of a quiesce. In the event of an error a negative - * errno code is returned. - */ - -int i2o_enable_controller(struct i2o_controller *c) -{ - u32 msg[4]; - int ret; - - i2o_status_get(c); - - /* Enable only allowed on READY state */ - if(c->status_block->iop_state != ADAPTER_STATE_READY) - return -EINVAL; - - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - - /* How long of a timeout do we need? */ - - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) - printk(KERN_ERR "%s: Could not enable (status=%#x).\n", - c->name, -ret); - else - dprintk(KERN_INFO "%s: Enabled.\n", c->name); - - i2o_status_get(c); // entered OPERATIONAL state - - return ret; -} - -/** - * i2o_clear_controller - clear a controller - * @c: controller - * - * Clear an IOP to HOLD state, ie. terminate external operations, clear all - * input queues and prepare for a system restart. IOP's internal operation - * continues normally and the outbound queue is alive. - * The IOP is not expected to rebuild its LCT. - */ - -int i2o_clear_controller(struct i2o_controller *c) -{ - struct i2o_controller *iop; - u32 msg[4]; - int ret; - - /* Quiesce all IOPs first */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - i2o_quiesce_controller(iop); - - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; - msg[3]=0; - - if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30))) - printk(KERN_INFO "%s: Unable to clear (status=%#x).\n", - c->name, -ret); - else - dprintk(KERN_INFO "%s: Cleared.\n",c->name); - - i2o_status_get(c); - - /* Enable other IOPs */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - if (iop != c) - i2o_enable_controller(iop); - - return ret; -} - - -/** - * i2o_reset_controller - reset an IOP - * @c: controller to reset - * - * Reset the IOP into INIT state and wait until IOP gets into RESET state. - * Terminate all external operations, clear IOP's inbound and outbound - * queues, terminate all DDMs, and reload the IOP's operating environment - * and all local DDMs. The IOP rebuilds its LCT. - */ - -static int i2o_reset_controller(struct i2o_controller *c) -{ - struct i2o_controller *iop; - u32 m; - u8 *status; - dma_addr_t status_phys; - u32 *msg; - long time; - - /* Quiesce all IOPs first */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - { - if(!iop->dpt) - i2o_quiesce_controller(iop); - } - - m=i2o_wait_message(c, "AdapterReset"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - msg=(u32 *)(c->msg_virt+m); - - status = pci_alloc_consistent(c->pdev, 4, &status_phys); - if(status == NULL) { - printk(KERN_ERR "IOP reset failed - no free memory.\n"); - return -ENOMEM; - } - memset(status, 0, 4); - - msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=core_context; - msg[3]=0; - msg[4]=0; - msg[5]=0; - msg[6]=status_phys; - msg[7]=0; /* 64bit host FIXME */ - - i2o_post_message(c,m); - - /* Wait for a reply */ - time=jiffies; - while(*status==0) - { - if((jiffies-time)>=20*HZ) - { - printk(KERN_ERR "IOP reset timeout.\n"); - /* The controller still may respond and overwrite - * status_phys, LEAK it to prevent memory corruption. - */ - return -ETIMEDOUT; - } - schedule(); - barrier(); - } - - if (*status==I2O_CMD_IN_PROGRESS) - { - /* - * Once the reset is sent, the IOP goes into the INIT state - * which is indeterminate. We need to wait until the IOP - * has rebooted before we can let the system talk to - * it. We read the inbound Free_List until a message is - * available. If we can't read one in the given ammount of - * time, we assume the IOP could not reboot properly. - */ - - dprintk(KERN_INFO "%s: Reset in progress, waiting for reboot...\n", - c->name); - - time = jiffies; - m = I2O_POST_READ32(c); - while(m == 0XFFFFFFFF) - { - if((jiffies-time) >= 30*HZ) - { - printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", - c->name); - /* The controller still may respond and - * overwrite status_phys, LEAK it to prevent - * memory corruption. - */ - return -ETIMEDOUT; - } - schedule(); - barrier(); - m = I2O_POST_READ32(c); - } - i2o_flush_reply(c,m); - } - - /* If IopReset was rejected or didn't perform reset, try IopClear */ - - i2o_status_get(c); - if (status[0] == I2O_CMD_REJECTED || - c->status_block->iop_state != ADAPTER_STATE_RESET) - { - printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); - i2o_clear_controller(c); - } - else - dprintk(KERN_INFO "%s: Reset completed.\n", c->name); - - /* Enable other IOPs */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - if (iop != c) - i2o_enable_controller(iop); - - pci_free_consistent(c->pdev, 4, status, status_phys); - return 0; -} - - -/** - * i2o_status_get - get the status block for the IOP - * @c: controller - * - * Issue a status query on the controller. This updates the - * attached status_block. If the controller fails to reply or an - * error occurs then a negative errno code is returned. On success - * zero is returned and the status_blok is updated. - */ - -int i2o_status_get(struct i2o_controller *c) -{ - long time; - u32 m; - u32 *msg; - u8 *status_block; - - if (c->status_block == NULL) - { - c->status_block = (i2o_status_block *) - pci_alloc_consistent(c->pdev, sizeof(i2o_status_block), &c->status_block_phys); - if (c->status_block == NULL) - { - printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", - c->name); - return -ENOMEM; - } - } - - status_block = (u8*)c->status_block; - memset(c->status_block,0,sizeof(i2o_status_block)); - - m=i2o_wait_message(c, "StatusGet"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - msg=(u32 *)(c->msg_virt+m); - - msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=core_context; - msg[3]=0; - msg[4]=0; - msg[5]=0; - msg[6]=c->status_block_phys; - msg[7]=0; /* 64bit host FIXME */ - msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ - - i2o_post_message(c,m); - - /* Wait for a reply */ - - time=jiffies; - while(status_block[87]!=0xFF) - { - if((jiffies-time)>=5*HZ) - { - printk(KERN_ERR "%s: Get status timeout.\n",c->name); - return -ETIMEDOUT; - } - yield(); - barrier(); - } - -#ifdef DRIVERDEBUG - printk(KERN_INFO "%s: State = ", c->name); - switch (c->status_block->iop_state) { - case 0x01: - printk("INIT\n"); - break; - case 0x02: - printk("RESET\n"); - break; - case 0x04: - printk("HOLD\n"); - break; - case 0x05: - printk("READY\n"); - break; - case 0x08: - printk("OPERATIONAL\n"); - break; - case 0x10: - printk("FAILED\n"); - break; - case 0x11: - printk("FAULTED\n"); - break; - default: - printk("%x (unknown !!)\n",c->status_block->iop_state); -} -#endif - - return 0; -} - -/* - * Get the Hardware Resource Table for the device. - * The HRT contains information about possible hidden devices - * but is mostly useless to us - */ -int i2o_hrt_get(struct i2o_controller *c) -{ - u32 msg[6]; - int ret, size = sizeof(i2o_hrt); - int loops = 3; /* we only try 3 times to get the HRT, this should be - more then enough. Worst case should be 2 times.*/ - - /* First read just the header to figure out the real size */ - - do { - /* first we allocate the memory for the HRT */ - if (c->hrt == NULL) { - c->hrt=pci_alloc_consistent(c->pdev, size, &c->hrt_phys); - if (c->hrt == NULL) { - printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name); - return -ENOMEM; - } - c->hrt_len = size; - } - - msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; - msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[3]= 0; - msg[4]= (0xD0000000 | c->hrt_len); /* Simple transaction */ - msg[5]= c->hrt_phys; /* Dump it here */ - - ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL, c->hrt_phys, 0, c->hrt_len, 0); - - if(ret == -ETIMEDOUT) - { - /* The HRT block we used is in limbo somewhere. When the iop wakes up - we will recover it */ - c->hrt = NULL; - c->hrt_len = 0; - return ret; - } - - if(ret<0) - { - printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", - c->name, -ret); - return ret; - } - - if (c->hrt->num_entries * c->hrt->entry_len << 2 > c->hrt_len) { - size = c->hrt->num_entries * c->hrt->entry_len << 2; - pci_free_consistent(c->pdev, c->hrt_len, c->hrt, c->hrt_phys); - c->hrt_len = 0; - c->hrt = NULL; - } - loops --; - } while (c->hrt == NULL && loops > 0); - - if(c->hrt == NULL) - { - printk(KERN_ERR "%s: Unable to get HRT after three tries, giving up\n", c->name); - return -1; - } - - i2o_parse_hrt(c); // just for debugging - - return 0; -} - -/* - * Send the I2O System Table to the specified IOP - * - * The system table contains information about all the IOPs in the - * system. It is build and then sent to each IOP so that IOPs can - * establish connections between each other. - * - */ -static int i2o_systab_send(struct i2o_controller *iop) -{ - u32 msg[12]; - dma_addr_t sys_tbl_phys; - int ret; - struct resource *root; - u32 *privbuf = kmalloc(16, GFP_KERNEL); - if(privbuf == NULL) - return -ENOMEM; - - - if(iop->status_block->current_mem_size < iop->status_block->desired_mem_size) - { - struct resource *res = &iop->mem_resource; - res->name = iop->pdev->bus->name; - res->flags = IORESOURCE_MEM; - res->start = 0; - res->end = 0; - printk("%s: requires private memory resources.\n", iop->name); - root = pci_find_parent_resource(iop->pdev, res); - if(root==NULL) - printk("Can't find parent resource!\n"); - if(root && allocate_resource(root, res, - iop->status_block->desired_mem_size, - iop->status_block->desired_mem_size, - iop->status_block->desired_mem_size, - 1<<20, /* Unspecified, so use 1Mb and play safe */ - NULL, - NULL)>=0) - { - iop->mem_alloc = 1; - iop->status_block->current_mem_size = 1 + res->end - res->start; - iop->status_block->current_mem_base = res->start; - printk(KERN_INFO "%s: allocated %ld bytes of PCI memory at 0x%08lX.\n", - iop->name, 1+res->end-res->start, res->start); - } - } - if(iop->status_block->current_io_size < iop->status_block->desired_io_size) - { - struct resource *res = &iop->io_resource; - res->name = iop->pdev->bus->name; - res->flags = IORESOURCE_IO; - res->start = 0; - res->end = 0; - printk("%s: requires private memory resources.\n", iop->name); - root = pci_find_parent_resource(iop->pdev, res); - if(root==NULL) - printk("Can't find parent resource!\n"); - if(root && allocate_resource(root, res, - iop->status_block->desired_io_size, - iop->status_block->desired_io_size, - iop->status_block->desired_io_size, - 1<<20, /* Unspecified, so use 1Mb and play safe */ - NULL, - NULL)>=0) - { - iop->io_alloc = 1; - iop->status_block->current_io_size = 1 + res->end - res->start; - iop->status_block->current_mem_base = res->start; - printk(KERN_INFO "%s: allocated %ld bytes of PCI I/O at 0x%08lX.\n", - iop->name, 1+res->end-res->start, res->start); - } - } - else - { - privbuf[0] = iop->status_block->current_mem_base; - privbuf[1] = iop->status_block->current_mem_size; - privbuf[2] = iop->status_block->current_io_base; - privbuf[3] = iop->status_block->current_io_size; - } - - msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; - msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[3] = 0; - msg[4] = (0<<16) | ((iop->unit+2) ); /* Host 0 IOP ID (unit + 2) */ - msg[5] = 0; /* Segment 0 */ - - /* - * Provide three SGL-elements: - * System table (SysTab), Private memory space declaration and - * Private i/o space declaration - * - * Nasty one here. We can't use pci_alloc_consistent to send the - * same table to everyone. We have to go remap it for them all - */ - - sys_tbl_phys = pci_map_single(iop->pdev, sys_tbl, sys_tbl_len, PCI_DMA_TODEVICE); - msg[6] = 0x54000000 | sys_tbl_phys; - - msg[7] = sys_tbl_phys; - msg[8] = 0x54000000 | privbuf[1]; - msg[9] = privbuf[0]; - msg[10] = 0xD4000000 | privbuf[3]; - msg[11] = privbuf[2]; - - ret=i2o_post_wait(iop, msg, sizeof(msg), 120); - - pci_unmap_single(iop->pdev, sys_tbl_phys, sys_tbl_len, PCI_DMA_TODEVICE); - - if(ret==-ETIMEDOUT) - { - printk(KERN_ERR "%s: SysTab setup timed out.\n", iop->name); - } - else if(ret<0) - { - printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", - iop->name, -ret); - } - else - { - dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); - } - i2o_status_get(iop); // Entered READY state - - kfree(privbuf); - return ret; - - } - -/* - * Initialize I2O subsystem. - */ -void __init i2o_sys_init(void) -{ - struct i2o_controller *iop, *niop = NULL; - - printk(KERN_INFO "Activating I2O controllers...\n"); - printk(KERN_INFO "This may take a few minutes if there are many devices\n"); - - /* In INIT state, Activate IOPs */ - for (iop = i2o_controller_chain; iop; iop = niop) { - dprintk(KERN_INFO "Calling i2o_activate_controller for %s...\n", - iop->name); - niop = iop->next; - if (i2o_activate_controller(iop) < 0) - i2o_delete_controller(iop); - } - - /* Active IOPs in HOLD state */ - -rebuild_sys_tab: - if (i2o_controller_chain == NULL) - return; - - /* - * If build_sys_table fails, we kill everything and bail - * as we can't init the IOPs w/o a system table - */ - dprintk(KERN_INFO "i2o_core: Calling i2o_build_sys_table...\n"); - if (i2o_build_sys_table() < 0) { - i2o_sys_shutdown(); - return; - } - - /* If IOP don't get online, we need to rebuild the System table */ - for (iop = i2o_controller_chain; iop; iop = niop) { - niop = iop->next; - dprintk(KERN_INFO "Calling i2o_online_controller for %s...\n", iop->name); - if (i2o_online_controller(iop) < 0) { - i2o_delete_controller(iop); - goto rebuild_sys_tab; - } - } - - /* Active IOPs now in OPERATIONAL state */ - - /* - * Register for status updates from all IOPs - */ - for(iop = i2o_controller_chain; iop; iop=iop->next) { - - /* Create a kernel thread to deal with dynamic LCT updates */ - iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND); - - /* Update change ind on DLCT */ - iop->dlct->change_ind = iop->lct->change_ind; - - /* Start dynamic LCT updates */ - i2o_lct_notify(iop); - - /* Register for all events from IRTOS */ - i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF); - } -} - -/** - * i2o_sys_shutdown - shutdown I2O system - * - * Bring down each i2o controller and then return. Each controller - * is taken through an orderly shutdown - */ - -static void i2o_sys_shutdown(void) -{ - struct i2o_controller *iop, *niop; - - /* Delete all IOPs from the controller chain */ - /* that will reset all IOPs too */ - - for (iop = i2o_controller_chain; iop; iop = niop) { - niop = iop->next; - i2o_delete_controller(iop); - } -} - -/** - * i2o_activate_controller - bring controller up to HOLD - * @iop: controller - * - * This function brings an I2O controller into HOLD state. The adapter - * is reset if necessary and then the queues and resource table - * are read. -1 is returned on a failure, 0 on success. - * - */ - -int i2o_activate_controller(struct i2o_controller *iop) -{ - /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ - /* In READY state, Get status */ - - if (i2o_status_get(iop) < 0) { - printk(KERN_INFO "Unable to obtain status of %s, " - "attempting a reset.\n", iop->name); - if (i2o_reset_controller(iop) < 0) - return -1; - } - - if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) { - printk(KERN_CRIT "%s: hardware fault\n", iop->name); - return -1; - } - - if (iop->status_block->i2o_version > I2OVER15) { - printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O Specification.\n", - iop->name); - return -1; - } - - if (iop->status_block->iop_state == ADAPTER_STATE_READY || - iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || - iop->status_block->iop_state == ADAPTER_STATE_HOLD || - iop->status_block->iop_state == ADAPTER_STATE_FAILED) - { - dprintk(KERN_INFO "%s: Already running, trying to reset...\n", - iop->name); - if (i2o_reset_controller(iop) < 0) - return -1; - } - - if (i2o_init_outbound_q(iop) < 0) - return -1; - - if (i2o_post_outbound_messages(iop)) - return -1; - - /* In HOLD state */ - - if (i2o_hrt_get(iop) < 0) - return -1; - - return 0; -} - - -/** - * i2o_init_outbound_queue - setup the outbound queue - * @c: controller - * - * Clear and (re)initialize IOP's outbound queue. Returns 0 on - * success or a negative errno code on a failure. - */ - -int i2o_init_outbound_q(struct i2o_controller *c) -{ - u8 *status; - dma_addr_t status_phys; - u32 m; - u32 *msg; - u32 time; - - dprintk(KERN_INFO "%s: Initializing Outbound Queue...\n", c->name); - m=i2o_wait_message(c, "OutboundInit"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - msg=(u32 *)(c->msg_virt+m); - - status = pci_alloc_consistent(c->pdev, 4, &status_phys); - if (status==NULL) { - printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n", - c->name); - return -ENOMEM; - } - memset(status, 0, 4); - - msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; - msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= core_context; - msg[3]= 0x0106; /* Transaction context */ - msg[4]= 4096; /* Host page frame size */ - /* Frame size is in words. 256 bytes a frame for now */ - msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size in words and Initcode */ - msg[6]= 0xD0000004; /* Simple SG LE, EOB */ - msg[7]= status_phys; - - i2o_post_message(c,m); - - barrier(); - time=jiffies; - while(status[0] < I2O_CMD_REJECTED) - { - if((jiffies-time)>=30*HZ) - { - if(status[0]==0x00) - printk(KERN_ERR "%s: Ignored queue initialize request.\n", - c->name); - else - printk(KERN_ERR "%s: Outbound queue initialize timeout.\n", - c->name); - pci_free_consistent(c->pdev, 4, status, status_phys); - return -ETIMEDOUT; - } - yield(); - barrier(); - } - - if(status[0] != I2O_CMD_COMPLETED) - { - printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name); - pci_free_consistent(c->pdev, 4, status, status_phys); - return -ETIMEDOUT; - } - pci_free_consistent(c->pdev, 4, status, status_phys); - return 0; -} - -/** - * i2o_post_outbound_messages - fill message queue - * @c: controller - * - * Allocate a message frame and load the messages into the IOP. The - * function returns zero on success or a negative errno code on - * failure. - */ - -int i2o_post_outbound_messages(struct i2o_controller *c) -{ - int i; - u32 m; - /* Alloc space for IOP's outbound queue message frames */ - - c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); - if(c->page_frame==NULL) { - printk(KERN_ERR "%s: Outbound Q initialize failed; out of memory.\n", - c->name); - return -ENOMEM; - } - - c->page_frame_map = pci_map_single(c->pdev, c->page_frame, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE); - - if(c->page_frame_map == 0) - { - kfree(c->page_frame); - printk(KERN_ERR "%s: Unable to map outbound queue.\n", c->name); - return -ENOMEM; - } - - m = c->page_frame_map; - - /* Post frames */ - - for(i=0; i< NMBR_MSG_FRAMES; i++) { - I2O_REPLY_WRITE32(c,m); - mb(); - m += (MSG_FRAME_SIZE << 2); - } - - return 0; -} - -/* - * Get the IOP's Logical Configuration Table - */ -int i2o_lct_get(struct i2o_controller *c) -{ - u32 msg[8]; - int ret, size = c->status_block->expected_lct_size; - - do { - if (c->lct == NULL) { - c->lct = pci_alloc_consistent(c->pdev, size, &c->lct_phys); - if(c->lct == NULL) { - printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", - c->name); - return -ENOMEM; - } - } - memset(c->lct, 0, size); - - msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - /* msg[2] filled in i2o_post_wait */ - msg[3] = 0; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = 0x00000000; /* Report now */ - msg[6] = 0xD0000000|size; - msg[7] = c->lct_phys; - - ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL, c->lct_phys, 0, size, 0); - - if(ret == -ETIMEDOUT) - { - c->lct = NULL; - return ret; - } - - if(ret<0) - { - printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", - c->name, -ret); - return ret; - } - - if (c->lct->table_size << 2 > size) { - int new_size = c->lct->table_size << 2; - pci_free_consistent(c->pdev, size, c->lct, c->lct_phys); - size = new_size; - c->lct = NULL; - } - } while (c->lct == NULL); - - if ((ret=i2o_parse_lct(c)) < 0) - return ret; - - return 0; -} - -/* - * Like above, but used for async notification. The main - * difference is that we keep track of the CurrentChangeIndiicator - * so that we only get updates when it actually changes. - * - */ -int i2o_lct_notify(struct i2o_controller *c) -{ - u32 msg[8]; - - msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = core_context; - msg[3] = 0xDEADBEEF; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = c->dlct->change_ind+1; /* Next change */ - msg[6] = 0xD0000000|8192; - msg[7] = c->dlct_phys; - - return i2o_post_this(c, msg, sizeof(msg)); -} - -/* - * Bring a controller online into OPERATIONAL state. - */ - -int i2o_online_controller(struct i2o_controller *iop) -{ - u32 v; - - if (i2o_systab_send(iop) < 0) - return -1; - - /* In READY state */ - - dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name); - if (i2o_enable_controller(iop) < 0) - return -1; - - /* In OPERATIONAL state */ - - dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name); - if (i2o_lct_get(iop) < 0) - return -1; - - /* Check battery status */ - - iop->battery = 0; - if(i2o_query_scalar(iop, ADAPTER_TID, 0x0000, 4, &v, 4)>=0) - { - if(v&16) - iop->battery = 1; - } - - return 0; -} - -/* - * Build system table - * - * The system table contains information about all the IOPs in the - * system (duh) and is used by the Executives on the IOPs to establish - * peer2peer connections. We're not supporting peer2peer at the moment, - * but this will be needed down the road for things like lan2lan forwarding. - */ -static int i2o_build_sys_table(void) -{ - struct i2o_controller *iop = NULL; - struct i2o_controller *niop = NULL; - int count = 0; - - sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs - (i2o_num_controllers) * - sizeof(struct i2o_sys_tbl_entry); - - if(sys_tbl) - kfree(sys_tbl); - - sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL); - if(!sys_tbl) { - printk(KERN_CRIT "SysTab Set failed. Out of memory.\n"); - return -ENOMEM; - } - memset((void*)sys_tbl, 0, sys_tbl_len); - - sys_tbl->num_entries = i2o_num_controllers; - sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */ - sys_tbl->change_ind = sys_tbl_ind++; - - for(iop = i2o_controller_chain; iop; iop = niop) - { - niop = iop->next; - - /* - * Get updated IOP state so we have the latest information - * - * We should delete the controller at this point if it - * doesn't respond since if it's not on the system table - * it is techninically not part of the I2O subsyßtem... - */ - if(i2o_status_get(iop)) { - printk(KERN_ERR "%s: Deleting b/c could not get status while" - "attempting to build system table\n", iop->name); - i2o_delete_controller(iop); - sys_tbl->num_entries--; - continue; // try the next one - } - - sys_tbl->iops[count].org_id = iop->status_block->org_id; - sys_tbl->iops[count].iop_id = iop->unit + 2; - sys_tbl->iops[count].seg_num = 0; - sys_tbl->iops[count].i2o_version = - iop->status_block->i2o_version; - sys_tbl->iops[count].iop_state = - iop->status_block->iop_state; - sys_tbl->iops[count].msg_type = - iop->status_block->msg_type; - sys_tbl->iops[count].frame_size = - iop->status_block->inbound_frame_size; - sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ?? - sys_tbl->iops[count].iop_capabilities = - iop->status_block->iop_capabilities; - sys_tbl->iops[count].inbound_low = (u32)iop->post_port; - sys_tbl->iops[count].inbound_high = 0; // FIXME: 64-bit support - - count++; - } - -#ifdef DRIVERDEBUG -{ - u32 *table; - table = (u32*)sys_tbl; - for(count = 0; count < (sys_tbl_len >>2); count++) - printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]); -} -#endif - - return 0; -} - - -/* - * Run time support routines - */ - -/* - * Generic "post and forget" helpers. This is less efficient - we do - * a memcpy for example that isnt strictly needed, but for most uses - * this is simply not worth optimising - */ - -int i2o_post_this(struct i2o_controller *c, u32 *data, int len) -{ - u32 m; - u32 *msg; - unsigned long t=jiffies; - - do - { - mb(); - m = I2O_POST_READ32(c); - } - while(m==0xFFFFFFFF && (jiffies-t)name); - return -ETIMEDOUT; - } - msg = (u32 *)(c->msg_virt + m); - memcpy_toio(msg, data, len); - i2o_post_message(c,m); - return 0; -} - -/** - * i2o_post_wait_mem - I2O query/reply with DMA buffers - * @c: controller - * @msg: message to send - * @len: length of message - * @timeout: time in seconds to wait - * @mem1: attached memory buffer 1 - * @mem2: attached memory buffer 2 - * @phys1: physical address of buffer 1 - * @phys2: physical address of buffer 2 - * @size1: size of buffer 1 - * @size2: size of buffer 2 - * - * This core API allows an OSM to post a message and then be told whether - * or not the system received a successful reply. - * - * If the message times out then the value '-ETIMEDOUT' is returned. This - * is a special case. In this situation the message may (should) complete - * at an indefinite time in the future. When it completes it will use the - * memory buffers attached to the request. If -ETIMEDOUT is returned then - * the memory buffers must not be freed. Instead the event completion will - * free them for you. In all other cases the buffers are your problem. - * - * Pass NULL for unneeded buffers. - */ - -int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2, dma_addr_t phys1, dma_addr_t phys2, int size1, int size2) -{ - DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); - DECLARE_WAITQUEUE(wait, current); - int complete = 0; - int status; - unsigned long flags = 0; - struct i2o_post_wait_data *wait_data = - kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL); - - if(!wait_data) - return -ENOMEM; - - /* - * Create a new notification object - */ - wait_data->status = &status; - wait_data->complete = &complete; - wait_data->mem[0] = mem1; - wait_data->mem[1] = mem2; - wait_data->phys[0] = phys1; - wait_data->phys[1] = phys2; - wait_data->size[0] = size1; - wait_data->size[1] = size2; - - /* - * Queue the event with its unique id - */ - spin_lock_irqsave(&post_wait_lock, flags); - - wait_data->next = post_wait_queue; - post_wait_queue = wait_data; - wait_data->id = (++post_wait_id) & 0x7fff; - wait_data->wq = &wq_i2o_post; - - spin_unlock_irqrestore(&post_wait_lock, flags); - - /* - * Fill in the message id - */ - - msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); - - /* - * Post the message to the controller. At some point later it - * will return. If we time out before it returns then - * complete will be zero. From the point post_this returns - * the wait_data may have been deleted. - */ - - add_wait_queue(&wq_i2o_post, &wait); - set_current_state(TASK_INTERRUPTIBLE); - if ((status = i2o_post_this(c, msg, len))==0) { - schedule_timeout(HZ * timeout); - } - else - { - remove_wait_queue(&wq_i2o_post, &wait); - return -EIO; - } - remove_wait_queue(&wq_i2o_post, &wait); - - if(signal_pending(current)) - status = -EINTR; - - spin_lock_irqsave(&post_wait_lock, flags); - barrier(); /* Be sure we see complete as it is locked */ - if(!complete) - { - /* - * Mark the entry dead. We cannot remove it. This is important. - * When it does terminate (which it must do if the controller hasnt - * died..) then it will otherwise scribble on stuff. - * !complete lets us safely check if the entry is still - * allocated and thus we can write into it - */ - wait_data->wq = NULL; - status = -ETIMEDOUT; - } - else - { - /* Debugging check - remove me soon */ - if(status == -ETIMEDOUT) - { - printk("TIMEDOUT BUG!\n"); - status = -EIO; - } - } - /* And the wait_data is not leaked either! */ - spin_unlock_irqrestore(&post_wait_lock, flags); - return status; -} - -/** - * i2o_post_wait - I2O query/reply - * @c: controller - * @msg: message to send - * @len: length of message - * @timeout: time in seconds to wait - * - * This core API allows an OSM to post a message and then be told whether - * or not the system received a successful reply. - */ - -int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) -{ - return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL, 0, 0, 0, 0); -} - -/* - * i2o_post_wait is completed and we want to wake up the - * sleeping proccess. Called by core's reply handler. - */ - -static void i2o_post_wait_complete(struct i2o_controller *c, u32 context, int status) -{ - struct i2o_post_wait_data **p1, *q; - unsigned long flags; - - /* - * We need to search through the post_wait - * queue to see if the given message is still - * outstanding. If not, it means that the IOP - * took longer to respond to the message than we - * had allowed and timer has already expired. - * Not much we can do about that except log - * it for debug purposes, increase timeout, and recompile - * - * Lock needed to keep anyone from moving queue pointers - * around while we're looking through them. - */ - - spin_lock_irqsave(&post_wait_lock, flags); - - for(p1 = &post_wait_queue; *p1!=NULL; p1 = &((*p1)->next)) - { - q = (*p1); - if(q->id == ((context >> 16) & 0x7fff)) { - /* - * Delete it - */ - - *p1 = q->next; - - /* - * Live or dead ? - */ - - if(q->wq) - { - /* Live entry - wakeup and set status */ - *q->status = status; - *q->complete = 1; - wake_up(q->wq); - } - else - { - /* - * Free resources. Caller is dead - */ - - if(q->mem[0]) - pci_free_consistent(c->pdev, q->size[0], q->mem[0], q->phys[0]); - if(q->mem[1]) - pci_free_consistent(c->pdev, q->size[1], q->mem[1], q->phys[1]); - - printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n"); - } - kfree(q); - spin_unlock(&post_wait_lock); - return; - } - } - spin_unlock(&post_wait_lock); - - printk(KERN_DEBUG "i2o_post_wait: Bogus reply!\n"); -} - -/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET - * - * This function can be used for all UtilParamsGet/Set operations. - * The OperationList is given in oplist-buffer, - * and results are returned in reslist-buffer. - * Note that the minimum sized reslist is 8 bytes and contains - * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. - */ - -int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, - void *oplist, int oplen, void *reslist, int reslen) -{ - u32 msg[9]; - u32 *res32 = (u32*)reslist; - u32 *restmp = (u32*)reslist; - int len = 0; - int i = 0; - int wait_status; - u32 *opmem, *resmem; - dma_addr_t opmem_phys, resmem_phys; - - /* Get DMAable memory */ - opmem = pci_alloc_consistent(iop->pdev, oplen, &opmem_phys); - if(opmem == NULL) - return -ENOMEM; - memcpy(opmem, oplist, oplen); - - resmem = pci_alloc_consistent(iop->pdev, reslen, &resmem_phys); - if(resmem == NULL) - { - pci_free_consistent(iop->pdev, oplen, opmem, opmem_phys); - return -ENOMEM; - } - - msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; - msg[1] = cmd << 24 | HOST_TID << 12 | tid; - msg[3] = 0; - msg[4] = 0; - msg[5] = 0x54000000 | oplen; /* OperationList */ - msg[6] = opmem_phys; - msg[7] = 0xD0000000 | reslen; /* ResultList */ - msg[8] = resmem_phys; - - wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem, opmem_phys, resmem_phys, oplen, reslen); - - /* - * This only looks like a memory leak - don't "fix" it. - */ - if(wait_status == -ETIMEDOUT) - return wait_status; - - memcpy(reslist, resmem, reslen); - pci_free_consistent(iop->pdev, reslen, resmem, resmem_phys); - pci_free_consistent(iop->pdev, oplen, opmem, opmem_phys); - - /* Query failed */ - if(wait_status != 0) - return wait_status; - /* - * Calculate number of bytes of Result LIST - * We need to loop through each Result BLOCK and grab the length - */ - restmp = res32 + 1; - len = 1; - for(i = 0; i < (res32[0]&0X0000FFFF); i++) - { - if(restmp[0]&0x00FF0000) /* BlockStatus != SUCCESS */ - { - printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, " - "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", - (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" - : "PARAMS_GET", - res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF); - - /* - * If this is the only request,than we return an error - */ - if((res32[0]&0x0000FFFF) == 1) - { - return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */ - } - } - len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ - restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ - } - return (len << 2); /* bytes used by result list */ -} - -/* - * Query one scalar group value or a whole scalar group. - */ -int i2o_query_scalar(struct i2o_controller *iop, int tid, - int group, int field, void *buf, int buflen) -{ - u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; - u8 resblk[8+buflen]; /* 8 bytes for header */ - int size; - - if (field == -1) /* whole group */ - opblk[4] = -1; - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, - opblk, sizeof(opblk), resblk, sizeof(resblk)); - - memcpy(buf, resblk+8, buflen); /* cut off header */ - - if(size>buflen) - return buflen; - return size; -} - -/* - * Set a scalar group value or a whole group. - */ -int i2o_set_scalar(struct i2o_controller *iop, int tid, - int group, int field, void *buf, int buflen) -{ - u16 *opblk; - u8 resblk[8+buflen]; /* 8 bytes for header */ - int size; - - opblk = kmalloc(buflen+64, GFP_KERNEL); - if (opblk == NULL) - { - printk(KERN_ERR "i2o: no memory for operation buffer.\n"); - return -ENOMEM; - } - - opblk[0] = 1; /* operation count */ - opblk[1] = 0; /* pad */ - opblk[2] = I2O_PARAMS_FIELD_SET; - opblk[3] = group; - - if(field == -1) { /* whole group */ - opblk[4] = -1; - memcpy(opblk+5, buf, buflen); - } - else /* single field */ - { - opblk[4] = 1; - opblk[5] = field; - memcpy(opblk+6, buf, buflen); - } - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, - opblk, 12+buflen, resblk, sizeof(resblk)); - - kfree(opblk); - if(size>buflen) - return buflen; - return size; -} - -/* - * if oper == I2O_PARAMS_TABLE_GET, get from all rows - * if fieldcount == -1 return all fields - * ibuf and ibuflen are unused (use NULL, 0) - * else return specific fields - * ibuf contains fieldindexes - * - * if oper == I2O_PARAMS_LIST_GET, get from specific rows - * if fieldcount == -1 return all fields - * ibuf contains rowcount, keyvalues - * else return specific fields - * fieldcount is # of fieldindexes - * ibuf contains fieldindexes, rowcount, keyvalues - * - * You could also use directly function i2o_issue_params(). - */ -int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group, - int fieldcount, void *ibuf, int ibuflen, - void *resblk, int reslen) -{ - u16 *opblk; - int size; - - opblk = kmalloc(10 + ibuflen, GFP_KERNEL); - if (opblk == NULL) - { - printk(KERN_ERR "i2o: no memory for query buffer.\n"); - return -ENOMEM; - } - - opblk[0] = 1; /* operation count */ - opblk[1] = 0; /* pad */ - opblk[2] = oper; - opblk[3] = group; - opblk[4] = fieldcount; - memcpy(opblk+5, ibuf, ibuflen); /* other params */ - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, - opblk, 10+ibuflen, resblk, reslen); - - kfree(opblk); - if(size>reslen) - return reslen; - return size; -} - -/* - * Clear table group, i.e. delete all rows. - */ -int i2o_clear_table(struct i2o_controller *iop, int tid, int group) -{ - u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group }; - u8 resblk[32]; /* min 8 bytes for result header */ - - return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, - opblk, sizeof(opblk), resblk, sizeof(resblk)); -} - -/* - * Add a new row into a table group. - * - * if fieldcount==-1 then we add whole rows - * buf contains rowcount, keyvalues - * else just specific fields are given, rest use defaults - * buf contains fieldindexes, rowcount, keyvalues - */ -int i2o_row_add_table(struct i2o_controller *iop, int tid, - int group, int fieldcount, void *buf, int buflen) -{ - u16 *opblk; - u8 resblk[32]; /* min 8 bytes for header */ - int size; - - opblk = kmalloc(buflen+64, GFP_KERNEL); - if (opblk == NULL) - { - printk(KERN_ERR "i2o: no memory for operation buffer.\n"); - return -ENOMEM; - } - - opblk[0] = 1; /* operation count */ - opblk[1] = 0; /* pad */ - opblk[2] = I2O_PARAMS_ROW_ADD; - opblk[3] = group; - opblk[4] = fieldcount; - memcpy(opblk+5, buf, buflen); - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, - opblk, 10+buflen, resblk, sizeof(resblk)); - - kfree(opblk); - if(size>buflen) - return buflen; - return size; -} - - -/* - * Used for error reporting/debugging purposes. - * Following fail status are common to all classes. - * The preserved message must be handled in the reply handler. - */ -void i2o_report_fail_status(u8 req_status, u32* msg) -{ - static char *FAIL_STATUS[] = { - "0x80", /* not used */ - "SERVICE_SUSPENDED", /* 0x81 */ - "SERVICE_TERMINATED", /* 0x82 */ - "CONGESTION", - "FAILURE", - "STATE_ERROR", - "TIME_OUT", - "ROUTING_FAILURE", - "INVALID_VERSION", - "INVALID_OFFSET", - "INVALID_MSG_FLAGS", - "FRAME_TOO_SMALL", - "FRAME_TOO_LARGE", - "INVALID_TARGET_ID", - "INVALID_INITIATOR_ID", - "INVALID_INITIATOR_CONTEX", /* 0x8F */ - "UNKNOWN_FAILURE" /* 0xFF */ - }; - - if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE) - printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status); - else - printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]); - - /* Dump some details */ - - printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n", - (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); - printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n", - (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); - printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n", - msg[5] >> 16, msg[5] & 0xFFF); - - printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF); - if (msg[4] & (1<<16)) - printk("(FormatError), " - "this msg can never be delivered/processed.\n"); - if (msg[4] & (1<<17)) - printk("(PathError), " - "this msg can no longer be delivered/processed.\n"); - if (msg[4] & (1<<18)) - printk("(PathState), " - "the system state does not allow delivery.\n"); - if (msg[4] & (1<<19)) - printk("(Congestion), resources temporarily not available;" - "do not retry immediately.\n"); -} - -/* - * Used for error reporting/debugging purposes. - * Following reply status are common to all classes. - */ -void i2o_report_common_status(u8 req_status) -{ - static char *REPLY_STATUS[] = { - "SUCCESS", - "ABORT_DIRTY", - "ABORT_NO_DATA_TRANSFER", - "ABORT_PARTIAL_TRANSFER", - "ERROR_DIRTY", - "ERROR_NO_DATA_TRANSFER", - "ERROR_PARTIAL_TRANSFER", - "PROCESS_ABORT_DIRTY", - "PROCESS_ABORT_NO_DATA_TRANSFER", - "PROCESS_ABORT_PARTIAL_TRANSFER", - "TRANSACTION_ERROR", - "PROGRESS_REPORT" - }; - - if (req_status >= ARRAY_SIZE(REPLY_STATUS)) - printk("RequestStatus = %0#2x", req_status); - else - printk("%s", REPLY_STATUS[req_status]); -} - -/* - * Used for error reporting/debugging purposes. - * Following detailed status are valid for executive class, - * utility class, DDM class and for transaction error replies. - */ -static void i2o_report_common_dsc(u16 detailed_status) -{ - static char *COMMON_DSC[] = { - "SUCCESS", - "0x01", // not used - "BAD_KEY", - "TCL_ERROR", - "REPLY_BUFFER_FULL", - "NO_SUCH_PAGE", - "INSUFFICIENT_RESOURCE_SOFT", - "INSUFFICIENT_RESOURCE_HARD", - "0x08", // not used - "CHAIN_BUFFER_TOO_LARGE", - "UNSUPPORTED_FUNCTION", - "DEVICE_LOCKED", - "DEVICE_RESET", - "INAPPROPRIATE_FUNCTION", - "INVALID_INITIATOR_ADDRESS", - "INVALID_MESSAGE_FLAGS", - "INVALID_OFFSET", - "INVALID_PARAMETER", - "INVALID_REQUEST", - "INVALID_TARGET_ADDRESS", - "MESSAGE_TOO_LARGE", - "MESSAGE_TOO_SMALL", - "MISSING_PARAMETER", - "TIMEOUT", - "UNKNOWN_ERROR", - "UNKNOWN_FUNCTION", - "UNSUPPORTED_VERSION", - "DEVICE_BUSY", - "DEVICE_NOT_AVAILABLE" - }; - - if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE) - printk(" / DetailedStatus = %0#4x.\n", detailed_status); - else - printk(" / %s.\n", COMMON_DSC[detailed_status]); -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_lan_dsc(u16 detailed_status) -{ - static char *LAN_DSC[] = { // Lan detailed status code strings - "SUCCESS", - "DEVICE_FAILURE", - "DESTINATION_NOT_FOUND", - "TRANSMIT_ERROR", - "TRANSMIT_ABORTED", - "RECEIVE_ERROR", - "RECEIVE_ABORTED", - "DMA_ERROR", - "BAD_PACKET_DETECTED", - "OUT_OF_MEMORY", - "BUCKET_OVERRUN", - "IOP_INTERNAL_ERROR", - "CANCELED", - "INVALID_TRANSACTION_CONTEXT", - "DEST_ADDRESS_DETECTED", - "DEST_ADDRESS_OMITTED", - "PARTIAL_PACKET_RETURNED", - "TEMP_SUSPENDED_STATE", // last Lan detailed status code - "INVALID_REQUEST" // general detailed status code - }; - - if (detailed_status > I2O_DSC_INVALID_REQUEST) - printk(" / %0#4x.\n", detailed_status); - else - printk(" / %s.\n", LAN_DSC[detailed_status]); -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_util_cmd(u8 cmd) -{ - switch (cmd) { - case I2O_CMD_UTIL_NOP: - printk("UTIL_NOP, "); - break; - case I2O_CMD_UTIL_ABORT: - printk("UTIL_ABORT, "); - break; - case I2O_CMD_UTIL_CLAIM: - printk("UTIL_CLAIM, "); - break; - case I2O_CMD_UTIL_RELEASE: - printk("UTIL_CLAIM_RELEASE, "); - break; - case I2O_CMD_UTIL_CONFIG_DIALOG: - printk("UTIL_CONFIG_DIALOG, "); - break; - case I2O_CMD_UTIL_DEVICE_RESERVE: - printk("UTIL_DEVICE_RESERVE, "); - break; - case I2O_CMD_UTIL_DEVICE_RELEASE: - printk("UTIL_DEVICE_RELEASE, "); - break; - case I2O_CMD_UTIL_EVT_ACK: - printk("UTIL_EVENT_ACKNOWLEDGE, "); - break; - case I2O_CMD_UTIL_EVT_REGISTER: - printk("UTIL_EVENT_REGISTER, "); - break; - case I2O_CMD_UTIL_LOCK: - printk("UTIL_LOCK, "); - break; - case I2O_CMD_UTIL_LOCK_RELEASE: - printk("UTIL_LOCK_RELEASE, "); - break; - case I2O_CMD_UTIL_PARAMS_GET: - printk("UTIL_PARAMS_GET, "); - break; - case I2O_CMD_UTIL_PARAMS_SET: - printk("UTIL_PARAMS_SET, "); - break; - case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY: - printk("UTIL_REPLY_FAULT_NOTIFY, "); - break; - default: - printk("Cmd = %0#2x, ",cmd); - } -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_exec_cmd(u8 cmd) -{ - switch (cmd) { - case I2O_CMD_ADAPTER_ASSIGN: - printk("EXEC_ADAPTER_ASSIGN, "); - break; - case I2O_CMD_ADAPTER_READ: - printk("EXEC_ADAPTER_READ, "); - break; - case I2O_CMD_ADAPTER_RELEASE: - printk("EXEC_ADAPTER_RELEASE, "); - break; - case I2O_CMD_BIOS_INFO_SET: - printk("EXEC_BIOS_INFO_SET, "); - break; - case I2O_CMD_BOOT_DEVICE_SET: - printk("EXEC_BOOT_DEVICE_SET, "); - break; - case I2O_CMD_CONFIG_VALIDATE: - printk("EXEC_CONFIG_VALIDATE, "); - break; - case I2O_CMD_CONN_SETUP: - printk("EXEC_CONN_SETUP, "); - break; - case I2O_CMD_DDM_DESTROY: - printk("EXEC_DDM_DESTROY, "); - break; - case I2O_CMD_DDM_ENABLE: - printk("EXEC_DDM_ENABLE, "); - break; - case I2O_CMD_DDM_QUIESCE: - printk("EXEC_DDM_QUIESCE, "); - break; - case I2O_CMD_DDM_RESET: - printk("EXEC_DDM_RESET, "); - break; - case I2O_CMD_DDM_SUSPEND: - printk("EXEC_DDM_SUSPEND, "); - break; - case I2O_CMD_DEVICE_ASSIGN: - printk("EXEC_DEVICE_ASSIGN, "); - break; - case I2O_CMD_DEVICE_RELEASE: - printk("EXEC_DEVICE_RELEASE, "); - break; - case I2O_CMD_HRT_GET: - printk("EXEC_HRT_GET, "); - break; - case I2O_CMD_ADAPTER_CLEAR: - printk("EXEC_IOP_CLEAR, "); - break; - case I2O_CMD_ADAPTER_CONNECT: - printk("EXEC_IOP_CONNECT, "); - break; - case I2O_CMD_ADAPTER_RESET: - printk("EXEC_IOP_RESET, "); - break; - case I2O_CMD_LCT_NOTIFY: - printk("EXEC_LCT_NOTIFY, "); - break; - case I2O_CMD_OUTBOUND_INIT: - printk("EXEC_OUTBOUND_INIT, "); - break; - case I2O_CMD_PATH_ENABLE: - printk("EXEC_PATH_ENABLE, "); - break; - case I2O_CMD_PATH_QUIESCE: - printk("EXEC_PATH_QUIESCE, "); - break; - case I2O_CMD_PATH_RESET: - printk("EXEC_PATH_RESET, "); - break; - case I2O_CMD_STATIC_MF_CREATE: - printk("EXEC_STATIC_MF_CREATE, "); - break; - case I2O_CMD_STATIC_MF_RELEASE: - printk("EXEC_STATIC_MF_RELEASE, "); - break; - case I2O_CMD_STATUS_GET: - printk("EXEC_STATUS_GET, "); - break; - case I2O_CMD_SW_DOWNLOAD: - printk("EXEC_SW_DOWNLOAD, "); - break; - case I2O_CMD_SW_UPLOAD: - printk("EXEC_SW_UPLOAD, "); - break; - case I2O_CMD_SW_REMOVE: - printk("EXEC_SW_REMOVE, "); - break; - case I2O_CMD_SYS_ENABLE: - printk("EXEC_SYS_ENABLE, "); - break; - case I2O_CMD_SYS_MODIFY: - printk("EXEC_SYS_MODIFY, "); - break; - case I2O_CMD_SYS_QUIESCE: - printk("EXEC_SYS_QUIESCE, "); - break; - case I2O_CMD_SYS_TAB_SET: - printk("EXEC_SYS_TAB_SET, "); - break; - default: - printk("Cmd = %#02x, ",cmd); - } -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_lan_cmd(u8 cmd) -{ - switch (cmd) { - case LAN_PACKET_SEND: - printk("LAN_PACKET_SEND, "); - break; - case LAN_SDU_SEND: - printk("LAN_SDU_SEND, "); - break; - case LAN_RECEIVE_POST: - printk("LAN_RECEIVE_POST, "); - break; - case LAN_RESET: - printk("LAN_RESET, "); - break; - case LAN_SUSPEND: - printk("LAN_SUSPEND, "); - break; - default: - printk("Cmd = %0#2x, ",cmd); - } -} - -/* - * Used for error reporting/debugging purposes. - * Report Cmd name, Request status, Detailed Status. - */ -void i2o_report_status(const char *severity, const char *str, u32 *msg) -{ - u8 cmd = (msg[1]>>24)&0xFF; - u8 req_status = (msg[4]>>24)&0xFF; - u16 detailed_status = msg[4]&0xFFFF; - struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)]; - - if (cmd == I2O_CMD_UTIL_EVT_REGISTER) - return; // No status in this reply - - printk("%s%s: ", severity, str); - - if (cmd < 0x1F) // Utility cmd - i2o_report_util_cmd(cmd); - - else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd - i2o_report_exec_cmd(cmd); - - else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) - i2o_report_lan_cmd(cmd); // LAN cmd - else - printk("Cmd = %0#2x, ", cmd); // Other cmds - - if (msg[0] & MSG_FAIL) { - i2o_report_fail_status(req_status, msg); - return; - } - - i2o_report_common_status(req_status); - - if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF)) - i2o_report_common_dsc(detailed_status); - else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) - i2o_report_lan_dsc(detailed_status); - else - printk(" / DetailedStatus = %0#4x.\n", detailed_status); -} - -/* Used to dump a message to syslog during debugging */ -void i2o_dump_message(u32 *msg) -{ -#ifdef DRIVERDEBUG - int i; - printk(KERN_INFO "Dumping I2O message size %d @ %p\n", - msg[0]>>16&0xffff, msg); - for(i = 0; i < ((msg[0]>>16)&0xffff); i++) - printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]); -#endif -} - -/* - * I2O reboot/shutdown notification. - * - * - Call each OSM's reboot notifier (if one exists) - * - Quiesce each IOP in the system - * - * Each IOP has to be quiesced before we can ensure that the system - * can be properly shutdown as a transaction that has already been - * acknowledged still needs to be placed in permanent store on the IOP. - * The SysQuiesce causes the IOP to force all HDMs to complete their - * transactions before returning, so only at that point is it safe - * - */ -static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void -*p) -{ - int i = 0; - struct i2o_controller *c = NULL; - - if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF) - return NOTIFY_DONE; - - printk(KERN_INFO "Shutting down I2O system.\n"); - printk(KERN_INFO - " This could take a few minutes if there are many devices attached\n"); - - for(i = 0; i < MAX_I2O_MODULES; i++) - { - if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify) - i2o_handlers[i]->reboot_notify(); - } - - for(c = i2o_controller_chain; c; c = c->next) - { - if(i2o_quiesce_controller(c)) - { - printk(KERN_WARNING "i2o: Could not quiesce %s.\n" - "Verify setup on next system power up.\n", - c->name); - } - } - - printk(KERN_INFO "I2O system down.\n"); - return NOTIFY_DONE; -} - - - - -/** - * i2o_pci_dispose - Free bus specific resources - * @c: I2O controller - * - * Disable interrupts and then free interrupt, I/O and mtrr resources - * used by this controller. Called by the I2O core on unload. - */ - -static void i2o_pci_dispose(struct i2o_controller *c) -{ - I2O_IRQ_WRITE32(c,0xFFFFFFFF); - if(c->irq > 0) - free_irq(c->irq, c); - iounmap(c->base_virt); - if(c->raptor) - iounmap(c->msg_virt); - -#ifdef CONFIG_MTRR - if(c->mtrr_reg0 > 0) - mtrr_del(c->mtrr_reg0, 0, 0); - if(c->mtrr_reg1 > 0) - mtrr_del(c->mtrr_reg1, 0, 0); -#endif -} - -/** - * i2o_pci_interrupt - Bus specific interrupt handler - * @irq: interrupt line - * @dev_id: cookie - * - * Handle an interrupt from a PCI based I2O controller. This turns out - * to be rather simple. We keep the controller pointer in the cookie. - */ - -static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) -{ - struct i2o_controller *c = dev_id; - i2o_run_queue(c); - return IRQ_HANDLED; -} - -/** - * i2o_pci_install - Install a PCI i2o controller - * @dev: PCI device of the I2O controller - * - * Install a PCI (or in theory AGP) i2o controller. Devices are - * initialized, configured and registered with the i2o core subsystem. Be - * very careful with ordering. There may be pending interrupts. - * - * To Do: Add support for polled controllers - */ - -int __init i2o_pci_install(struct pci_dev *dev) -{ - struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller), - GFP_KERNEL); - void *bar0_virt; - void *bar1_virt; - unsigned long bar0_phys = 0; - unsigned long bar1_phys = 0; - unsigned long bar0_size = 0; - unsigned long bar1_size = 0; - - int i; - - if(c==NULL) - { - printk(KERN_ERR "i2o: Insufficient memory to add controller.\n"); - return -ENOMEM; - } - memset(c, 0, sizeof(*c)); - - c->irq = -1; - c->dpt = 0; - c->raptor = 0; - c->short_req = 0; - c->pdev = dev; - -#if BITS_PER_LONG == 64 - c->context_list_lock = SPIN_LOCK_UNLOCKED; -#endif - - /* - * Cards that fall apart if you hit them with large I/O - * loads... - */ - - if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630) - { - c->short_req = 1; - printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n"); - } - - if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) - { - c->promise = 1; - printk(KERN_INFO "I2O: Promise workarounds activated.\n"); - } - - /* - * Cards that go bananas if you quiesce them before you reset - * them - */ - - if(dev->vendor == PCI_VENDOR_ID_DPT) { - c->dpt=1; - if(dev->device == 0xA511) - c->raptor=1; - } - - for(i=0; i<6; i++) - { - /* Skip I/O spaces */ - if(!(pci_resource_flags(dev, i) & IORESOURCE_IO)) - { - if(!bar0_phys) - { - bar0_phys = pci_resource_start(dev, i); - bar0_size = pci_resource_len(dev, i); - if(!c->raptor) - break; - } - else - { - bar1_phys = pci_resource_start(dev, i); - bar1_size = pci_resource_len(dev, i); - break; - } - } - } - - if(i==6) - { - printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n"); - kfree(c); - return -EINVAL; - } - - - /* Map the I2O controller */ - if(!c->raptor) - printk(KERN_INFO "i2o: PCI I2O controller at %08lX size=%ld\n", bar0_phys, bar0_size); - else - printk(KERN_INFO "i2o: PCI I2O controller\n BAR0 at 0x%08lX size=%ld\n BAR1 at 0x%08lX size=%ld\n", bar0_phys, bar0_size, bar1_phys, bar1_size); - - bar0_virt = ioremap(bar0_phys, bar0_size); - if(bar0_virt==0) - { - printk(KERN_ERR "i2o: Unable to map controller.\n"); - kfree(c); - return -EINVAL; - } - - if(c->raptor) - { - bar1_virt = ioremap(bar1_phys, bar1_size); - if(bar1_virt==0) - { - printk(KERN_ERR "i2o: Unable to map controller.\n"); - kfree(c); - iounmap(bar0_virt); - return -EINVAL; - } - } else { - bar1_virt = bar0_virt; - bar1_phys = bar0_phys; - bar1_size = bar0_size; - } - - c->irq_mask = bar0_virt+0x34; - c->post_port = bar0_virt+0x40; - c->reply_port = bar0_virt+0x44; - - c->base_phys = bar0_phys; - c->base_virt = bar0_virt; - c->msg_phys = bar1_phys; - c->msg_virt = bar1_virt; - - /* - * Enable Write Combining MTRR for IOP's memory region - */ -#ifdef CONFIG_MTRR - c->mtrr_reg0 = mtrr_add(c->base_phys, bar0_size, MTRR_TYPE_WRCOMB, 1); - /* - * If it is an INTEL i960 I/O processor then set the first 64K to - * Uncacheable since the region contains the Messaging unit which - * shouldn't be cached. - */ - c->mtrr_reg1 = -1; - if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT) - { - printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); - c->mtrr_reg1 = mtrr_add(c->base_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); - if(c->mtrr_reg1< 0) - { - printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); - mtrr_del(c->mtrr_reg0, c->msg_phys, bar1_size); - c->mtrr_reg0 = -1; - } - } - if(c->raptor) - c->mtrr_reg1 = mtrr_add(c->msg_phys, bar1_size, MTRR_TYPE_WRCOMB, 1); - -#endif - - I2O_IRQ_WRITE32(c,0xFFFFFFFF); - - i = i2o_install_controller(c); - - if(i<0) - { - printk(KERN_ERR "i2o: Unable to install controller.\n"); - kfree(c); - iounmap(bar0_virt); - if(c->raptor) - iounmap(bar1_virt); - return i; - } - - c->irq = dev->irq; - if(c->irq) - { - i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ, - c->name, c); - if(i<0) - { - printk(KERN_ERR "%s: unable to allocate interrupt %d.\n", - c->name, dev->irq); - c->irq = -1; - i2o_delete_controller(c); - iounmap(bar0_virt); - if(c->raptor) - iounmap(bar1_virt); - return -EBUSY; - } - } - - printk(KERN_INFO "%s: Installed at IRQ%d\n", c->name, dev->irq); - I2O_IRQ_WRITE32(c,0x0); - c->enabled = 1; - return 0; -} - -/** - * i2o_pci_scan - Scan the pci bus for controllers - * - * Scan the PCI devices on the system looking for any device which is a - * memory of the Intelligent, I2O class. We attempt to set up each such device - * and register it with the core. - * - * Returns the number of controllers registered - * - * Note; Do not change this to a hot plug interface. I2O 1.5 itself - * does not support hot plugging. - */ - -int __init i2o_pci_scan(void) -{ - struct pci_dev *dev = NULL; - int count=0; - - printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); - - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) - { - if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O && - (dev->vendor!=PCI_VENDOR_ID_DPT || dev->device!=0xA511)) - continue; - - if((dev->class>>8)==PCI_CLASS_INTELLIGENT_I2O && - (dev->class&0xFF)>1) - { - printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n"); - continue; - } - if (pci_enable_device(dev)) - continue; - printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n", - dev->bus->number, dev->devfn); - if(pci_set_dma_mask(dev, 0xffffffff)) - { - printk(KERN_WARNING "I2O controller on bus %d at %d : No suitable DMA available\n", dev->bus->number, dev->devfn); - continue; - } - pci_set_master(dev); - if(i2o_pci_install(dev)==0) - count++; - } - if(count) - printk(KERN_INFO "i2o: %d I2O controller%s found and installed.\n", count, - count==1?"":"s"); - return count?count:-ENODEV; -} - -static int i2o_core_init(void) -{ - printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); - if (i2o_install_handler(&i2o_core_handler) < 0) - { - printk(KERN_ERR "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); - return 0; - } - - core_context = i2o_core_handler.context; - - /* - * Initialize event handling thread - */ - - init_MUTEX_LOCKED(&evt_sem); - evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND); - if(evt_pid < 0) - { - printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); - i2o_remove_handler(&i2o_core_handler); - return 0; - } - else - printk(KERN_INFO "I2O: Event thread created as pid %d\n", evt_pid); - - i2o_pci_scan(); - if(i2o_num_controllers) - i2o_sys_init(); - - register_reboot_notifier(&i2o_reboot_notifier); - - return 0; -} - -static void i2o_core_exit(void) -{ - int stat; - - unregister_reboot_notifier(&i2o_reboot_notifier); - - if(i2o_num_controllers) - i2o_sys_shutdown(); - - /* - * If this is shutdown time, the thread has already been killed - */ - if(evt_running) { - printk("Terminating i2o threads..."); - stat = kill_proc(evt_pid, SIGKILL, 1); - if(!stat) { - printk("waiting...\n"); - wait_for_completion(&evt_dead); - } - printk("done.\n"); - } - i2o_remove_handler(&i2o_core_handler); -} - -module_init(i2o_core_init); -module_exit(i2o_core_exit); - -MODULE_PARM(verbose, "i"); -MODULE_PARM_DESC(verbose, "Verbose diagnostics"); - -MODULE_AUTHOR("Red Hat Software"); -MODULE_DESCRIPTION("I2O Core"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(i2o_controller_chain); -EXPORT_SYMBOL(i2o_num_controllers); -EXPORT_SYMBOL(i2o_find_controller); -EXPORT_SYMBOL(i2o_unlock_controller); -EXPORT_SYMBOL(i2o_status_get); -EXPORT_SYMBOL(i2o_install_handler); -EXPORT_SYMBOL(i2o_remove_handler); -EXPORT_SYMBOL(i2o_install_controller); -EXPORT_SYMBOL(i2o_delete_controller); -EXPORT_SYMBOL(i2o_run_queue); -EXPORT_SYMBOL(i2o_claim_device); -EXPORT_SYMBOL(i2o_release_device); -EXPORT_SYMBOL(i2o_device_notify_on); -EXPORT_SYMBOL(i2o_device_notify_off); -EXPORT_SYMBOL(i2o_post_this); -EXPORT_SYMBOL(i2o_post_wait); -EXPORT_SYMBOL(i2o_post_wait_mem); -EXPORT_SYMBOL(i2o_query_scalar); -EXPORT_SYMBOL(i2o_set_scalar); -EXPORT_SYMBOL(i2o_query_table); -EXPORT_SYMBOL(i2o_clear_table); -EXPORT_SYMBOL(i2o_row_add_table); -EXPORT_SYMBOL(i2o_issue_params); -EXPORT_SYMBOL(i2o_event_register); -EXPORT_SYMBOL(i2o_event_ack); -EXPORT_SYMBOL(i2o_report_status); -EXPORT_SYMBOL(i2o_dump_message); -EXPORT_SYMBOL(i2o_get_class_name); -EXPORT_SYMBOL(i2o_context_list_add); -EXPORT_SYMBOL(i2o_context_list_get); -EXPORT_SYMBOL(i2o_context_list_remove); diff -Nru a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c --- a/drivers/message/i2o/i2o_proc.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/message/i2o/i2o_proc.c 2004-10-18 14:56:33 -07:00 @@ -1,39 +1,33 @@ /* - * procfs handler for Linux I2O subsystem + * procfs handler for Linux I2O subsystem * - * (c) Copyright 1999 Deepak Saxena - * - * Originally written by Deepak Saxena(deepak@plexity.net) - * - * This program is free software. You can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This is an initial test release. The code is based on the design - * of the ide procfs system (drivers/block/ide-proc.c). Some code - * taken from i2o-core module by Alan Cox. - * - * DISCLAIMER: This code is still under development/test and may cause - * your system to behave unpredictably. Use at your own discretion. - * - * LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI), - * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI) - * University of Helsinki, Department of Computer Science - */ - -/* - * set tabstop=3 - */ - -/* - * TODO List + * (c) Copyright 1999 Deepak Saxena + * + * Originally written by Deepak Saxena(deepak@plexity.net) * - * - Add support for any version 2.0 spec changes once 2.0 IRTOS is - * is available to test with - * - Clean up code to use official structure definitions + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This is an initial test release. The code is based on the design of the + * ide procfs system (drivers/block/ide-proc.c). Some code taken from + * i2o-core module by Alan Cox. + * + * DISCLAIMER: This code is still under development/test and may cause + * your system to behave unpredictably. Use at your own discretion. + * + * + * Fixes/additions: + * Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI), + * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI) + * University of Helsinki, Department of Computer Science + * LAN entries + * Markus Lidel + * Changes for new I2O API */ +#define I2O_MAX_MODULES 4 // FIXME! #define FMT_U64_HEX "0x%08x%08x" #define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64)) @@ -54,188 +48,198 @@ #include #include -#include "i2o_lan.h" - -/* - * Structure used to define /proc entries - */ -typedef struct _i2o_proc_entry_t -{ - char *name; /* entry name */ - mode_t mode; /* mode */ - read_proc_t *read_proc; /* read func */ - write_proc_t *write_proc; /* write func */ - struct file_operations *fops_proc; /* file operations func */ +/* Structure used to define /proc entries */ +typedef struct _i2o_proc_entry_t { + char *name; /* entry name */ + mode_t mode; /* mode */ + struct file_operations *fops; /* open function */ } i2o_proc_entry; -// #define DRIVERDEBUG - -static int i2o_seq_show_lct(struct seq_file *, void *); -static int i2o_seq_show_hrt(struct seq_file *, void *); -static int i2o_seq_show_status(struct seq_file *, void *); - -static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_driver_store(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_drivers_stored(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_phys_device(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_claimed(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_users(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_authorized_users(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_dev_identity(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_ddm_identity(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_sensors(char *, char **, off_t, int, int *, void *); - -static int print_serial_number(char *, int, u8 *, int); - -static int i2o_proc_create_entries(void *, i2o_proc_entry *, - struct proc_dir_entry *); -static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *); -static int i2o_proc_add_controller(struct i2o_controller *, - struct proc_dir_entry * ); -static void i2o_proc_remove_controller(struct i2o_controller *, - struct proc_dir_entry * ); -static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *); -static void i2o_proc_remove_device(struct i2o_device *); -static int create_i2o_procfs(void); -static int destroy_i2o_procfs(void); -static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *); -static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *); - -static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int, - int *, void *); -static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int, - int *, void *); -static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *, - void *); - +/* global I2O /proc/i2o entry */ static struct proc_dir_entry *i2o_proc_dir_root; -/* - * I2O OSM descriptor - */ -static struct i2o_handler i2o_proc_handler = -{ - NULL, - i2o_proc_new_dev, - i2o_proc_dev_del, - NULL, - "I2O procfs Layer", - 0, - 0xffffffff // All classes +/* proc OSM driver struct */ +static struct i2o_driver i2o_proc_driver = { + .name = "proc-osm", }; -static int i2o_seq_open_hrt(struct inode *inode, struct file *file) +static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len) { - return single_open(file, i2o_seq_show_hrt, PDE(inode)->data); -}; + int i; -struct file_operations i2o_seq_fops_hrt = { - .open = i2o_seq_open_hrt, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; + /* 19990419 -sralston + * The I2O v1.5 (and v2.0 so far) "official specification" + * got serial numbers WRONG! + * Apparently, and despite what Section 3.4.4 says and + * Figure 3-35 shows (pg 3-39 in the pdf doc), + * the convention / consensus seems to be: + * + First byte is SNFormat + * + Second byte is SNLen (but only if SNFormat==7 (?)) + * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format + */ + switch (serialno[0]) { + case I2O_SNFORMAT_BINARY: /* Binary */ + seq_printf(seq, "0x"); + for (i = 0; i < serialno[1]; i++) { + seq_printf(seq, "%02X", serialno[2 + i]); + } + break; -static int i2o_seq_open_lct(struct inode *inode, struct file *file) -{ - return single_open(file, i2o_seq_show_lct, PDE(inode)->data); -}; + case I2O_SNFORMAT_ASCII: /* ASCII */ + if (serialno[1] < ' ') { /* printable or SNLen? */ + /* sanity */ + max_len = + (max_len < serialno[1]) ? max_len : serialno[1]; + serialno[1 + max_len] = '\0'; + + /* just print it */ + seq_printf(seq, "%s", &serialno[2]); + } else { + /* print chars for specified length */ + for (i = 0; i < serialno[1]; i++) { + seq_printf(seq, "%c", serialno[2 + i]); + } + } + break; -struct file_operations i2o_seq_fops_lct = { - .open = i2o_seq_open_lct, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; + case I2O_SNFORMAT_UNICODE: /* UNICODE */ + seq_printf(seq, "UNICODE Format. Can't Display\n"); + break; -static int i2o_seq_open_status(struct inode *inode, struct file *file) -{ - return single_open(file, i2o_seq_show_status, PDE(inode)->data); -}; + case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ + seq_printf(seq, + "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", + serialno[2], serialno[3], + serialno[4], serialno[5], serialno[6], serialno[7]); + break; -struct file_operations i2o_seq_fops_status = { - .open = i2o_seq_open_status, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; + case I2O_SNFORMAT_WAN: /* WAN MAC Address */ + /* FIXME: Figure out what a WAN access address looks like?? */ + seq_printf(seq, "WAN Access Address"); + break; -/* - * IOP specific entries...write field just in case someone - * ever wants one. - */ -static i2o_proc_entry generic_iop_entries[] = -{ - {"hrt", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_hrt}, - {"lct", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_lct}, - {"status", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_status}, - {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL, NULL}, - {"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL, NULL}, - {"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL, NULL}, - {"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; +/* plus new in v2.0 */ + case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ + /* FIXME: Figure out what a LAN-64 address really looks like?? */ + seq_printf(seq, + "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", + serialno[8], serialno[9], + serialno[2], serialno[3], + serialno[4], serialno[5], serialno[6], serialno[7]); + break; + + case I2O_SNFORMAT_DDM: /* I2O DDM */ + seq_printf(seq, + "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh", + *(u16 *) & serialno[2], + *(u16 *) & serialno[4], *(u16 *) & serialno[6]); + break; + + case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */ + case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */ + /* FIXME: Figure if this is even close?? */ + seq_printf(seq, + "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n", + *(u32 *) & serialno[2], + *(u32 *) & serialno[6], + *(u32 *) & serialno[10], *(u32 *) & serialno[14]); + break; -/* - * Device specific entries - */ -static i2o_proc_entry generic_dev_entries[] = -{ - {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL, NULL}, - {"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL, NULL}, - {"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL, NULL}, - {"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL, NULL}, - {"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL, NULL}, - {"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL, NULL}, - {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL, NULL}, - {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL, NULL}, - {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL, NULL}, - {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL, NULL}, - {"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; + case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ + case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ + default: + seq_printf(seq, "Unknown data format (0x%02x)", serialno[0]); + break; + } -/* - * Storage unit specific entries (SCSI Periph, BS) with device names + return 0; +} + +/** + * i2o_get_class_name - do i2o class name lookup + * @class: class number + * + * Return a descriptive string for an i2o class */ -static i2o_proc_entry rbs_dev_entries[] = +static const char *i2o_get_class_name(int class) { - {"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL, NULL}, - {NULL, 0, NULL, NULL} -}; + int idx = 16; + static char *i2o_class_name[] = { + "Executive", + "Device Driver Module", + "Block Device", + "Tape Device", + "LAN Interface", + "WAN Interface", + "Fibre Channel Port", + "Fibre Channel Device", + "SCSI Device", + "ATE Port", + "ATE Device", + "Floppy Controller", + "Floppy Device", + "Secondary Bus Port", + "Peer Transport Agent", + "Peer Transport", + "Unknown" + }; + + switch (class & 0xfff) { + case I2O_CLASS_EXECUTIVE: + idx = 0; + break; + case I2O_CLASS_DDM: + idx = 1; + break; + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + idx = 2; + break; + case I2O_CLASS_SEQUENTIAL_STORAGE: + idx = 3; + break; + case I2O_CLASS_LAN: + idx = 4; + break; + case I2O_CLASS_WAN: + idx = 5; + break; + case I2O_CLASS_FIBRE_CHANNEL_PORT: + idx = 6; + break; + case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: + idx = 7; + break; + case I2O_CLASS_SCSI_PERIPHERAL: + idx = 8; + break; + case I2O_CLASS_ATE_PORT: + idx = 9; + break; + case I2O_CLASS_ATE_PERIPHERAL: + idx = 10; + break; + case I2O_CLASS_FLOPPY_CONTROLLER: + idx = 11; + break; + case I2O_CLASS_FLOPPY_DEVICE: + idx = 12; + break; + case I2O_CLASS_BUS_ADAPTER_PORT: + idx = 13; + break; + case I2O_CLASS_PEER_TRANSPORT_AGENT: + idx = 14; + break; + case I2O_CLASS_PEER_TRANSPORT: + idx = 15; + break; + } + + return i2o_class_name[idx]; +} #define SCSI_TABLE_SIZE 13 -static char *scsi_devices[] = -{ +static char *scsi_devices[] = { "Direct-Access Read/Write", "Sequential-Access Storage", "Printer", @@ -251,307 +255,267 @@ "Array Controller Device" }; -/* private */ - -/* - * Generic LAN specific entries - * - * Should groups with r/w entries have their own subdirectory? - * - */ -static i2o_proc_entry lan_entries[] = -{ - {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL, NULL}, - {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL, NULL}, - {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR, - i2o_proc_read_lan_mcast_addr, NULL, NULL}, - {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR, - i2o_proc_read_lan_batch_control, NULL, NULL}, - {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL, NULL}, - {"lan_media_operation", S_IFREG|S_IRUGO, - i2o_proc_read_lan_media_operation, NULL, NULL}, - {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL, NULL}, - {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL, NULL}, - {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL, NULL}, - - {"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - -/* - * Port specific LAN entries - * - */ -static i2o_proc_entry lan_eth_entries[] = -{ - {"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - -static i2o_proc_entry lan_tr_entries[] = -{ - {"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - -static i2o_proc_entry lan_fddi_entries[] = -{ - {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - - -static char *chtostr(u8 *chars, int n) +static char *chtostr(u8 * chars, int n) { char tmp[256]; tmp[0] = 0; - return strncat(tmp, (char *)chars, n); + return strncat(tmp, (char *)chars, n); } -static int i2o_report_query_status(char *buf, int block_status, char *group) +static int i2o_report_query_status(struct seq_file *seq, int block_status, + char *group) { - switch (block_status) - { + switch (block_status) { case -ETIMEDOUT: - return sprintf(buf, "Timeout reading group %s.\n",group); + return seq_printf(seq, "Timeout reading group %s.\n", group); case -ENOMEM: - return sprintf(buf, "No free memory to read the table.\n"); + return seq_printf(seq, "No free memory to read the table.\n"); case -I2O_PARAMS_STATUS_INVALID_GROUP_ID: - return sprintf(buf, "Group %s not supported.\n", group); + return seq_printf(seq, "Group %s not supported.\n", group); default: - return sprintf(buf, "Error reading group %s. BlockStatus 0x%02X\n", - group, -block_status); + return seq_printf(seq, + "Error reading group %s. BlockStatus 0x%02X\n", + group, -block_status); } } -static char* bus_strings[] = -{ - "Local Bus", - "ISA", - "EISA", - "MCA", +static char *bus_strings[] = { + "Local Bus", + "ISA", + "EISA", + "MCA", "PCI", - "PCMCIA", - "NUBUS", + "PCMCIA", + "NUBUS", "CARDBUS" }; -static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; - int i2o_seq_show_hrt(struct seq_file *seq, void *v) { struct i2o_controller *c = (struct i2o_controller *)seq->private; - i2o_hrt *hrt = (i2o_hrt *)c->hrt; + i2o_hrt *hrt = (i2o_hrt *) c->hrt.virt; u32 bus; int i; - if(hrt->hrt_version) - { - seq_printf(seq, "HRT table for controller is too new a version.\n"); + if (hrt->hrt_version) { + seq_printf(seq, + "HRT table for controller is too new a version.\n"); return 0; } seq_printf(seq, "HRT has %d entries of %d bytes each.\n", - hrt->num_entries, hrt->entry_len << 2); + hrt->num_entries, hrt->entry_len << 2); - for(i = 0; i < hrt->num_entries; i++) - { + for (i = 0; i < hrt->num_entries; i++) { seq_printf(seq, "Entry %d:\n", i); seq_printf(seq, " Adapter ID: %0#10x\n", - hrt->hrt_entry[i].adapter_id); + hrt->hrt_entry[i].adapter_id); seq_printf(seq, " Controlling tid: %0#6x\n", - hrt->hrt_entry[i].parent_tid); + hrt->hrt_entry[i].parent_tid); - if(hrt->hrt_entry[i].bus_type != 0x80) - { + if (hrt->hrt_entry[i].bus_type != 0x80) { bus = hrt->hrt_entry[i].bus_type; - seq_printf(seq, " %s Information\n", bus_strings[bus]); + seq_printf(seq, " %s Information\n", + bus_strings[bus]); + + switch (bus) { + case I2O_BUS_LOCAL: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.local_bus. + LbBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x\n", + hrt->hrt_entry[i].bus.local_bus. + LbBaseMemoryAddress); + break; - switch(bus) - { - case I2O_BUS_LOCAL: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x\n", - hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress); - break; - - case I2O_BUS_ISA: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress); - seq_printf(seq, " CSN: %0#4x,", - hrt->hrt_entry[i].bus.isa_bus.CSN); - break; - - case I2O_BUS_EISA: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress); - seq_printf(seq, " Slot: %0#4x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber); - break; - - case I2O_BUS_MCA: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress); - seq_printf(seq, " Slot: %0#4x,", - hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber); - break; - - case I2O_BUS_PCI: - seq_printf(seq, " Bus: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciBusNumber); - seq_printf(seq, " Dev: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber); - seq_printf(seq, " Func: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber); - seq_printf(seq, " Vendor: %0#6x", - hrt->hrt_entry[i].bus.pci_bus.PciVendorID); - seq_printf(seq, " Device: %0#6x\n", - hrt->hrt_entry[i].bus.pci_bus.PciDeviceID); - break; + case I2O_BUS_ISA: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.isa_bus. + IsaBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.isa_bus. + IsaBaseMemoryAddress); + seq_printf(seq, " CSN: %0#4x,", + hrt->hrt_entry[i].bus.isa_bus.CSN); + break; + + case I2O_BUS_EISA: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.eisa_bus. + EisaBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.eisa_bus. + EisaBaseMemoryAddress); + seq_printf(seq, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.eisa_bus. + EisaSlotNumber); + break; + + case I2O_BUS_MCA: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.mca_bus. + McaBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.mca_bus. + McaBaseMemoryAddress); + seq_printf(seq, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.mca_bus. + McaSlotNumber); + break; + + case I2O_BUS_PCI: + seq_printf(seq, " Bus: %0#4x", + hrt->hrt_entry[i].bus.pci_bus. + PciBusNumber); + seq_printf(seq, " Dev: %0#4x", + hrt->hrt_entry[i].bus.pci_bus. + PciDeviceNumber); + seq_printf(seq, " Func: %0#4x", + hrt->hrt_entry[i].bus.pci_bus. + PciFunctionNumber); + seq_printf(seq, " Vendor: %0#6x", + hrt->hrt_entry[i].bus.pci_bus. + PciVendorID); + seq_printf(seq, " Device: %0#6x\n", + hrt->hrt_entry[i].bus.pci_bus. + PciDeviceID); + break; - default: - seq_printf(seq, " Unsupported Bus Type\n"); + default: + seq_printf(seq, " Unsupported Bus Type\n"); } - } - else + } else seq_printf(seq, " Unknown Bus Type\n"); } - + return 0; } int i2o_seq_show_lct(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)seq->private; - i2o_lct *lct = (i2o_lct *)c->lct; + struct i2o_controller *c = (struct i2o_controller *)seq->private; + i2o_lct *lct = (i2o_lct *) c->lct; int entries; int i; #define BUS_TABLE_SIZE 3 - static char *bus_ports[] = - { + static char *bus_ports[] = { "Generic Bus", "SCSI Bus", "Fibre Channel Bus" }; - entries = (lct->table_size - 3)/9; + entries = (lct->table_size - 3) / 9; seq_printf(seq, "LCT contains %d %s\n", entries, - entries == 1 ? "entry" : "entries"); - if(lct->boot_tid) + entries == 1 ? "entry" : "entries"); + if (lct->boot_tid) seq_printf(seq, "Boot Device @ ID %d\n", lct->boot_tid); seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind); - for(i = 0; i < entries; i++) - { + for (i = 0; i < entries; i++) { seq_printf(seq, "Entry %d\n", i); - seq_printf(seq, " Class, SubClass : %s", i2o_get_class_name(lct->lct_entry[i].class_id)); - + seq_printf(seq, " Class, SubClass : %s", + i2o_get_class_name(lct->lct_entry[i].class_id)); + /* - * Classes which we'll print subclass info for + * Classes which we'll print subclass info for */ - switch(lct->lct_entry[i].class_id & 0xFFF) - { - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - switch(lct->lct_entry[i].sub_class) - { - case 0x00: - seq_printf(seq, ", Direct-Access Read/Write"); - break; - - case 0x04: - seq_printf(seq, ", WORM Drive"); - break; - - case 0x05: - seq_printf(seq, ", CD-ROM Drive"); - break; - - case 0x07: - seq_printf(seq, ", Optical Memory Device"); - break; - - default: - seq_printf(seq, ", Unknown (0x%02x)", - lct->lct_entry[i].sub_class); - break; - } - break; - - case I2O_CLASS_LAN: - switch(lct->lct_entry[i].sub_class & 0xFF) - { - case 0x30: - seq_printf(seq, ", Ethernet"); - break; - - case 0x40: - seq_printf(seq, ", 100base VG"); - break; - - case 0x50: - seq_printf(seq, ", IEEE 802.5/Token-Ring"); - break; - - case 0x60: - seq_printf(seq, ", ANSI X3T9.5 FDDI"); - break; - - case 0x70: - seq_printf(seq, ", Fibre Channel"); - break; - - default: - seq_printf(seq, ", Unknown Sub-Class (0x%02x)", - lct->lct_entry[i].sub_class & 0xFF); - break; - } - break; - - case I2O_CLASS_SCSI_PERIPHERAL: - if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) - seq_printf(seq, ", %s", - scsi_devices[lct->lct_entry[i].sub_class]); - else - seq_printf(seq, ", Unknown Device Type"); - break; - - case I2O_CLASS_BUS_ADAPTER_PORT: - if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) - seq_printf(seq, ", %s", - bus_ports[lct->lct_entry[i].sub_class]); - else - seq_printf(seq, ", Unknown Bus Type"); + switch (lct->lct_entry[i].class_id & 0xFFF) { + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + switch (lct->lct_entry[i].sub_class) { + case 0x00: + seq_printf(seq, ", Direct-Access Read/Write"); + break; + + case 0x04: + seq_printf(seq, ", WORM Drive"); + break; + + case 0x05: + seq_printf(seq, ", CD-ROM Drive"); + break; + + case 0x07: + seq_printf(seq, ", Optical Memory Device"); + break; + + default: + seq_printf(seq, ", Unknown (0x%02x)", + lct->lct_entry[i].sub_class); + break; + } + break; + + case I2O_CLASS_LAN: + switch (lct->lct_entry[i].sub_class & 0xFF) { + case 0x30: + seq_printf(seq, ", Ethernet"); + break; + + case 0x40: + seq_printf(seq, ", 100base VG"); + break; + + case 0x50: + seq_printf(seq, ", IEEE 802.5/Token-Ring"); + break; + + case 0x60: + seq_printf(seq, ", ANSI X3T9.5 FDDI"); break; + + case 0x70: + seq_printf(seq, ", Fibre Channel"); + break; + + default: + seq_printf(seq, ", Unknown Sub-Class (0x%02x)", + lct->lct_entry[i].sub_class & 0xFF); + break; + } + break; + + case I2O_CLASS_SCSI_PERIPHERAL: + if (lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) + seq_printf(seq, ", %s", + scsi_devices[lct->lct_entry[i]. + sub_class]); + else + seq_printf(seq, ", Unknown Device Type"); + break; + + case I2O_CLASS_BUS_ADAPTER_PORT: + if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) + seq_printf(seq, ", %s", + bus_ports[lct->lct_entry[i]. + sub_class]); + else + seq_printf(seq, ", Unknown Bus Type"); + break; } seq_printf(seq, "\n"); - - seq_printf(seq, " Local TID : 0x%03x\n", lct->lct_entry[i].tid); - seq_printf(seq, " User TID : 0x%03x\n", lct->lct_entry[i].user_tid); + + seq_printf(seq, " Local TID : 0x%03x\n", + lct->lct_entry[i].tid); + seq_printf(seq, " User TID : 0x%03x\n", + lct->lct_entry[i].user_tid); seq_printf(seq, " Parent TID : 0x%03x\n", - lct->lct_entry[i].parent_tid); + lct->lct_entry[i].parent_tid); seq_printf(seq, " Identity Tag : 0x%x%x%x%x%x%x%x%x\n", - lct->lct_entry[i].identity_tag[0], - lct->lct_entry[i].identity_tag[1], - lct->lct_entry[i].identity_tag[2], - lct->lct_entry[i].identity_tag[3], - lct->lct_entry[i].identity_tag[4], - lct->lct_entry[i].identity_tag[5], - lct->lct_entry[i].identity_tag[6], - lct->lct_entry[i].identity_tag[7]); + lct->lct_entry[i].identity_tag[0], + lct->lct_entry[i].identity_tag[1], + lct->lct_entry[i].identity_tag[2], + lct->lct_entry[i].identity_tag[3], + lct->lct_entry[i].identity_tag[4], + lct->lct_entry[i].identity_tag[5], + lct->lct_entry[i].identity_tag[6], + lct->lct_entry[i].identity_tag[7]); seq_printf(seq, " Change Indicator : %0#10x\n", - lct->lct_entry[i].change_ind); + lct->lct_entry[i].change_ind); seq_printf(seq, " Event Capab Mask : %0#10x\n", - lct->lct_entry[i].device_flags); + lct->lct_entry[i].device_flags); } return 0; @@ -559,17 +523,17 @@ int i2o_seq_show_status(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)seq->private; + struct i2o_controller *c = (struct i2o_controller *)seq->private; char prodstr[25]; int version; - - i2o_status_get(c); // reread the status block + i2o_status_block *sb = c->status_block.virt; + + i2o_status_get(c); // reread the status block - seq_printf(seq, "Organization ID : %0#6x\n", - c->status_block->org_id); + seq_printf(seq, "Organization ID : %0#6x\n", sb->org_id); + + version = sb->i2o_version; - version = c->status_block->i2o_version; - /* FIXME for Spec 2.0 if (version == 0x02) { seq_printf(seq, "Lowest I2O version supported: "); @@ -599,170 +563,171 @@ } } */ - seq_printf(seq, "IOP ID : %0#5x\n", - c->status_block->iop_id); - seq_printf(seq, "Host Unit ID : %0#6x\n", - c->status_block->host_unit_id); - seq_printf(seq, "Segment Number : %0#5x\n", - c->status_block->segment_number); + seq_printf(seq, "IOP ID : %0#5x\n", sb->iop_id); + seq_printf(seq, "Host Unit ID : %0#6x\n", sb->host_unit_id); + seq_printf(seq, "Segment Number : %0#5x\n", sb->segment_number); seq_printf(seq, "I2O version : "); switch (version) { - case 0x00: - seq_printf(seq, "1.0\n"); - break; - case 0x01: - seq_printf(seq, "1.5\n"); - break; - case 0x02: - seq_printf(seq, "2.0\n"); - break; - default: - seq_printf(seq, "Unknown version\n"); + case 0x00: + seq_printf(seq, "1.0\n"); + break; + case 0x01: + seq_printf(seq, "1.5\n"); + break; + case 0x02: + seq_printf(seq, "2.0\n"); + break; + default: + seq_printf(seq, "Unknown version\n"); } seq_printf(seq, "IOP State : "); - switch (c->status_block->iop_state) { - case 0x01: - seq_printf(seq, "INIT\n"); - break; + switch (sb->iop_state) { + case 0x01: + seq_printf(seq, "INIT\n"); + break; - case 0x02: - seq_printf(seq, "RESET\n"); - break; + case 0x02: + seq_printf(seq, "RESET\n"); + break; - case 0x04: - seq_printf(seq, "HOLD\n"); - break; + case 0x04: + seq_printf(seq, "HOLD\n"); + break; - case 0x05: - seq_printf(seq, "READY\n"); - break; + case 0x05: + seq_printf(seq, "READY\n"); + break; - case 0x08: - seq_printf(seq, "OPERATIONAL\n"); - break; + case 0x08: + seq_printf(seq, "OPERATIONAL\n"); + break; - case 0x10: - seq_printf(seq, "FAILED\n"); - break; + case 0x10: + seq_printf(seq, "FAILED\n"); + break; - case 0x11: - seq_printf(seq, "FAULTED\n"); - break; + case 0x11: + seq_printf(seq, "FAULTED\n"); + break; - default: - seq_printf(seq, "Unknown\n"); - break; + default: + seq_printf(seq, "Unknown\n"); + break; } seq_printf(seq, "Messenger Type : "); - switch (c->status_block->msg_type) { - case 0x00: - seq_printf(seq, "Memory mapped\n"); - break; - case 0x01: - seq_printf(seq, "Memory mapped only\n"); - break; - case 0x02: - seq_printf(seq,"Remote only\n"); - break; - case 0x03: - seq_printf(seq, "Memory mapped and remote\n"); - break; - default: - seq_printf(seq, "Unknown\n"); + switch (sb->msg_type) { + case 0x00: + seq_printf(seq, "Memory mapped\n"); + break; + case 0x01: + seq_printf(seq, "Memory mapped only\n"); + break; + case 0x02: + seq_printf(seq, "Remote only\n"); + break; + case 0x03: + seq_printf(seq, "Memory mapped and remote\n"); + break; + default: + seq_printf(seq, "Unknown\n"); } seq_printf(seq, "Inbound Frame Size : %d bytes\n", - c->status_block->inbound_frame_size<<2); + sb->inbound_frame_size << 2); seq_printf(seq, "Max Inbound Frames : %d\n", - c->status_block->max_inbound_frames); + sb->max_inbound_frames); seq_printf(seq, "Current Inbound Frames : %d\n", - c->status_block->cur_inbound_frames); + sb->cur_inbound_frames); seq_printf(seq, "Max Outbound Frames : %d\n", - c->status_block->max_outbound_frames); + sb->max_outbound_frames); /* Spec doesn't say if NULL terminated or not... */ - memcpy(prodstr, c->status_block->product_id, 24); + memcpy(prodstr, sb->product_id, 24); prodstr[24] = '\0'; seq_printf(seq, "Product ID : %s\n", prodstr); seq_printf(seq, "Expected LCT Size : %d bytes\n", - c->status_block->expected_lct_size); + sb->expected_lct_size); seq_printf(seq, "IOP Capabilities\n"); seq_printf(seq, " Context Field Size Support : "); - switch (c->status_block->iop_capabilities & 0x0000003) { - case 0: - seq_printf(seq, "Supports only 32-bit context fields\n"); - break; - case 1: - seq_printf(seq, "Supports only 64-bit context fields\n"); - break; - case 2: - seq_printf(seq, "Supports 32-bit and 64-bit context fields, " - "but not concurrently\n"); - break; - case 3: - seq_printf(seq, "Supports 32-bit and 64-bit context fields " - "concurrently\n"); - break; - default: - seq_printf(seq, "0x%08x\n",c->status_block->iop_capabilities); + switch (sb->iop_capabilities & 0x0000003) { + case 0: + seq_printf(seq, "Supports only 32-bit context fields\n"); + break; + case 1: + seq_printf(seq, "Supports only 64-bit context fields\n"); + break; + case 2: + seq_printf(seq, "Supports 32-bit and 64-bit context fields, " + "but not concurrently\n"); + break; + case 3: + seq_printf(seq, "Supports 32-bit and 64-bit context fields " + "concurrently\n"); + break; + default: + seq_printf(seq, "0x%08x\n", sb->iop_capabilities); } seq_printf(seq, " Current Context Field Size : "); - switch (c->status_block->iop_capabilities & 0x0000000C) { - case 0: - seq_printf(seq, "not configured\n"); - break; - case 4: - seq_printf(seq, "Supports only 32-bit context fields\n"); - break; - case 8: - seq_printf(seq, "Supports only 64-bit context fields\n"); - break; - case 12: - seq_printf(seq, "Supports both 32-bit or 64-bit context fields " - "concurrently\n"); - break; - default: - seq_printf(seq, "\n"); + switch (sb->iop_capabilities & 0x0000000C) { + case 0: + seq_printf(seq, "not configured\n"); + break; + case 4: + seq_printf(seq, "Supports only 32-bit context fields\n"); + break; + case 8: + seq_printf(seq, "Supports only 64-bit context fields\n"); + break; + case 12: + seq_printf(seq, "Supports both 32-bit or 64-bit context fields " + "concurrently\n"); + break; + default: + seq_printf(seq, "\n"); } seq_printf(seq, " Inbound Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported"); + (sb-> + iop_capabilities & 0x00000010) ? "Supported" : + "Not supported"); seq_printf(seq, " Outbound Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported"); + (sb-> + iop_capabilities & 0x00000020) ? "Supported" : + "Not supported"); seq_printf(seq, " Peer to Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported"); + (sb-> + iop_capabilities & 0x00000040) ? "Supported" : + "Not supported"); seq_printf(seq, "Desired private memory size : %d kB\n", - c->status_block->desired_mem_size>>10); + sb->desired_mem_size >> 10); seq_printf(seq, "Allocated private memory size : %d kB\n", - c->status_block->current_mem_size>>10); + sb->current_mem_size >> 10); seq_printf(seq, "Private memory base address : %0#10x\n", - c->status_block->current_mem_base); + sb->current_mem_base); seq_printf(seq, "Desired private I/O size : %d kB\n", - c->status_block->desired_io_size>>10); + sb->desired_io_size >> 10); seq_printf(seq, "Allocated private I/O size : %d kB\n", - c->status_block->current_io_size>>10); + sb->current_io_size >> 10); seq_printf(seq, "Private I/O base address : %0#10x\n", - c->status_block->current_io_base); + sb->current_io_base); return 0; } -int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_hw(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; static u32 work32[5]; - static u8 *work8 = (u8*)work32; - static u16 *work16 = (u16*)work32; + static u8 *work8 = (u8 *) work32; + static u16 *work16 = (u16 *) work32; int token; u32 hwcap; - static char *cpu_table[] = - { + static char *cpu_table[] = { "Intel 80960 series", "AMD2900 series", "Motorola 68000 series", @@ -773,397 +738,350 @@ "Intel x86 series" }; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(c, ADAPTER_TID, 0x0000, -1, &work32, sizeof(work32)); + token = + i2o_parm_field_get(c->exec, 0x0000, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0000 IOP Hardware"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0x0000 IOP Hardware"); + return 0; } - len += sprintf(buf+len, "I2O Vendor ID : %0#6x\n", work16[0]); - len += sprintf(buf+len, "Product ID : %0#6x\n", work16[1]); - len += sprintf(buf+len, "CPU : "); - if(work8[16] > 8) - len += sprintf(buf+len, "Unknown\n"); + seq_printf(seq, "I2O Vendor ID : %0#6x\n", work16[0]); + seq_printf(seq, "Product ID : %0#6x\n", work16[1]); + seq_printf(seq, "CPU : "); + if (work8[16] > 8) + seq_printf(seq, "Unknown\n"); else - len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]); + seq_printf(seq, "%s\n", cpu_table[work8[16]]); /* Anyone using ProcessorVersion? */ - - len += sprintf(buf+len, "RAM : %dkB\n", work32[1]>>10); - len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10); - hwcap = work32[3]; - len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap); - len += sprintf(buf+len, " [%s] Self booting\n", - (hwcap&0x00000001) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Upgradable IRTOS\n", - (hwcap&0x00000002) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Supports downloading DDMs\n", - (hwcap&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Supports installing DDMs\n", - (hwcap&0x00000008) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Battery-backed RAM\n", - (hwcap&0x00000010) ? "+" : "-"); + seq_printf(seq, "RAM : %dkB\n", work32[1] >> 10); + seq_printf(seq, "Non-Volatile Mem : %dkB\n", work32[2] >> 10); - spin_unlock(&i2o_proc_lock); + hwcap = work32[3]; + seq_printf(seq, "Capabilities : 0x%08x\n", hwcap); + seq_printf(seq, " [%s] Self booting\n", + (hwcap & 0x00000001) ? "+" : "-"); + seq_printf(seq, " [%s] Upgradable IRTOS\n", + (hwcap & 0x00000002) ? "+" : "-"); + seq_printf(seq, " [%s] Supports downloading DDMs\n", + (hwcap & 0x00000004) ? "+" : "-"); + seq_printf(seq, " [%s] Supports installing DDMs\n", + (hwcap & 0x00000008) ? "+" : "-"); + seq_printf(seq, " [%s] Battery-backed RAM\n", + (hwcap & 0x00000010) ? "+" : "-"); - return len; + return 0; } - /* Executive group 0003h - Executing DDM List (table) */ -int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_ddm_table(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; int token; int i; typedef struct _i2o_exec_execute_ddm_table { u16 ddm_tid; - u8 module_type; - u8 reserved; + u8 module_type; + u8 reserved; u16 i2o_vendor_id; u16 module_id; - u8 module_name_version[28]; + u8 module_name_version[28]; u32 data_size; u32 code_size; } i2o_exec_execute_ddm_table; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; - i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES]; + i2o_exec_execute_ddm_table ddm_table[I2O_MAX_MODULES]; } *result; i2o_exec_execute_ddm_table ddm_table; result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) + if (!result) return -ENOMEM; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - c, ADAPTER_TID, - 0x0003, -1, - NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0003, -1, + NULL, 0, result, sizeof(*result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0003 Executing DDM List"); + i2o_report_query_status(seq, token, + "0x0003 Executing DDM List"); goto out; } - len += sprintf(buf+len, "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n"); - ddm_table=result->ddm_table[0]; + seq_printf(seq, + "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n"); + ddm_table = result->ddm_table[0]; - for(i=0; i < result->row_count; ddm_table=result->ddm_table[++i]) - { - len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF); + for (i = 0; i < result->row_count; ddm_table = result->ddm_table[++i]) { + seq_printf(seq, "0x%03x ", ddm_table.ddm_tid & 0xFFF); - switch(ddm_table.module_type) - { + switch (ddm_table.module_type) { case 0x01: - len += sprintf(buf+len, "Downloaded DDM "); - break; + seq_printf(seq, "Downloaded DDM "); + break; case 0x22: - len += sprintf(buf+len, "Embedded DDM "); + seq_printf(seq, "Embedded DDM "); break; default: - len += sprintf(buf+len, " "); + seq_printf(seq, " "); } - len += sprintf(buf+len, "%-#7x", ddm_table.i2o_vendor_id); - len += sprintf(buf+len, "%-#8x", ddm_table.module_id); - len += sprintf(buf+len, "%-29s", chtostr(ddm_table.module_name_version, 28)); - len += sprintf(buf+len, "%9d ", ddm_table.data_size); - len += sprintf(buf+len, "%8d", ddm_table.code_size); + seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id); + seq_printf(seq, "%-#8x", ddm_table.module_id); + seq_printf(seq, "%-29s", + chtostr(ddm_table.module_name_version, 28)); + seq_printf(seq, "%9d ", ddm_table.data_size); + seq_printf(seq, "%8d", ddm_table.code_size); - len += sprintf(buf+len, "\n"); + seq_printf(seq, "\n"); } -out: - spin_unlock(&i2o_proc_lock); + out: kfree(result); - return len; + return 0; } - /* Executive group 0004h - Driver Store (scalar) */ -int i2o_proc_read_driver_store(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_driver_store(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; u32 work32[8]; int token; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32, sizeof(work32)); + token = + i2o_parm_field_get(c->exec, 0x0004, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0004 Driver Store"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0x0004 Driver Store"); + return 0; } - len += sprintf(buf+len, "Module limit : %d\n" - "Module count : %d\n" - "Current space : %d kB\n" - "Free space : %d kB\n", - work32[0], work32[1], work32[2]>>10, work32[3]>>10); + seq_printf(seq, "Module limit : %d\n" + "Module count : %d\n" + "Current space : %d kB\n" + "Free space : %d kB\n", + work32[0], work32[1], work32[2] >> 10, work32[3] >> 10); - spin_unlock(&i2o_proc_lock); - - return len; + return 0; } - /* Executive group 0005h - Driver Store Table (table) */ -int i2o_proc_read_drivers_stored(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v) { typedef struct _i2o_driver_store { u16 stored_ddm_index; - u8 module_type; - u8 reserved; + u8 module_type; + u8 reserved; u16 i2o_vendor_id; u16 module_id; - u8 module_name_version[28]; - u8 date[8]; + u8 module_name_version[28]; + u8 date[8]; u32 module_size; u32 mpb_size; u32 module_flags; } i2o_driver_store_table; - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; int token; int i; - typedef struct - { + typedef struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; - i2o_driver_store_table dst[MAX_I2O_MODULES]; + i2o_driver_store_table dst[I2O_MAX_MODULES]; } i2o_driver_result_table; - + i2o_driver_result_table *result; i2o_driver_store_table *dst; - - len = 0; - result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL); - if(result == NULL) + if (result == NULL) return -ENOMEM; - spin_lock(&i2o_proc_lock); - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - c, ADAPTER_TID, 0x0005, -1, NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0005, -1, + NULL, 0, result, sizeof(*result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0005 DRIVER STORE TABLE"); - spin_unlock(&i2o_proc_lock); + i2o_report_query_status(seq, token, + "0x0005 DRIVER STORE TABLE"); kfree(result); - return len; + return 0; } - len += sprintf(buf+len, "# Module_type Vendor Mod_id Module_name Vrs" - "Date Mod_size Par_size Flags\n"); - for(i=0, dst=&result->dst[0]; i < result->row_count; dst=&result->dst[++i]) - { - len += sprintf(buf+len, "%-3d", dst->stored_ddm_index); - switch(dst->module_type) - { + seq_printf(seq, + "# Module_type Vendor Mod_id Module_name Vrs" + "Date Mod_size Par_size Flags\n"); + for (i = 0, dst = &result->dst[0]; i < result->row_count; + dst = &result->dst[++i]) { + seq_printf(seq, "%-3d", dst->stored_ddm_index); + switch (dst->module_type) { case 0x01: - len += sprintf(buf+len, "Downloaded DDM "); - break; + seq_printf(seq, "Downloaded DDM "); + break; case 0x22: - len += sprintf(buf+len, "Embedded DDM "); + seq_printf(seq, "Embedded DDM "); break; default: - len += sprintf(buf+len, " "); + seq_printf(seq, " "); } #if 0 - if(c->i2oversion == 0x02) - len += sprintf(buf+len, "%-d", dst->module_state); + if (c->i2oversion == 0x02) + seq_printf(seq, "%-d", dst->module_state); #endif - len += sprintf(buf+len, "%-#7x", dst->i2o_vendor_id); - len += sprintf(buf+len, "%-#8x", dst->module_id); - len += sprintf(buf+len, "%-29s", chtostr(dst->module_name_version,28)); - len += sprintf(buf+len, "%-9s", chtostr(dst->date,8)); - len += sprintf(buf+len, "%8d ", dst->module_size); - len += sprintf(buf+len, "%8d ", dst->mpb_size); - len += sprintf(buf+len, "0x%04x", dst->module_flags); + seq_printf(seq, "%-#7x", dst->i2o_vendor_id); + seq_printf(seq, "%-#8x", dst->module_id); + seq_printf(seq, "%-29s", chtostr(dst->module_name_version, 28)); + seq_printf(seq, "%-9s", chtostr(dst->date, 8)); + seq_printf(seq, "%8d ", dst->module_size); + seq_printf(seq, "%8d ", dst->mpb_size); + seq_printf(seq, "0x%04x", dst->module_flags); #if 0 - if(c->i2oversion == 0x02) - len += sprintf(buf+len, "%d", - dst->notification_level); + if (c->i2oversion == 0x02) + seq_printf(seq, "%d", dst->notification_level); #endif - len += sprintf(buf+len, "\n"); + seq_printf(seq, "\n"); } - spin_unlock(&i2o_proc_lock); kfree(result); - return len; + return 0; } - /* Generic group F000h - Params Descriptor (table) */ -int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_groups(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; u8 properties; - typedef struct _i2o_group_info - { + typedef struct _i2o_group_info { u16 group_number; u16 field_count; u16 row_count; - u8 properties; - u8 reserved; + u8 properties; + u8 reserved; } i2o_group_info; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; i2o_group_info group[256]; } *result; result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) + if (!result) return -ENOMEM; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0, + result, sizeof(*result)); if (token < 0) { - len = i2o_report_query_status(buf+len, token, "0xF000 Params Descriptor"); + i2o_report_query_status(seq, token, "0xF000 Params Descriptor"); goto out; } - len += sprintf(buf+len, "# Group FieldCount RowCount Type Add Del Clear\n"); + seq_printf(seq, + "# Group FieldCount RowCount Type Add Del Clear\n"); - for (i=0; i < result->row_count; i++) - { - len += sprintf(buf+len, "%-3d", i); - len += sprintf(buf+len, "0x%04X ", result->group[i].group_number); - len += sprintf(buf+len, "%10d ", result->group[i].field_count); - len += sprintf(buf+len, "%8d ", result->group[i].row_count); + for (i = 0; i < result->row_count; i++) { + seq_printf(seq, "%-3d", i); + seq_printf(seq, "0x%04X ", result->group[i].group_number); + seq_printf(seq, "%10d ", result->group[i].field_count); + seq_printf(seq, "%8d ", result->group[i].row_count); properties = result->group[i].properties; - if (properties & 0x1) len += sprintf(buf+len, "Table "); - else len += sprintf(buf+len, "Scalar "); - if (properties & 0x2) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - if (properties & 0x4) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - if (properties & 0x8) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); + if (properties & 0x1) + seq_printf(seq, "Table "); + else + seq_printf(seq, "Scalar "); + if (properties & 0x2) + seq_printf(seq, " + "); + else + seq_printf(seq, " - "); + if (properties & 0x4) + seq_printf(seq, " + "); + else + seq_printf(seq, " - "); + if (properties & 0x8) + seq_printf(seq, " + "); + else + seq_printf(seq, " - "); - len += sprintf(buf+len, "\n"); + seq_printf(seq, "\n"); } if (result->more_flag) - len += sprintf(buf+len, "There is more...\n"); -out: - spin_unlock(&i2o_proc_lock); + seq_printf(seq, "There is more...\n"); + out: kfree(result); - return len; + return 0; } - /* Generic group F001h - Physical Device Table (table) */ -int i2o_proc_read_phys_device(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_phys_device(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; u32 adapter_id[64]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF001, -1, NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF001, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF001 Physical Device Table"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF001 Physical Device Table"); + return 0; } if (result.row_count) - len += sprintf(buf+len, "# AdapterId\n"); + seq_printf(seq, "# AdapterId\n"); - for (i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x\n", result.adapter_id[i]); + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%-2d", i); + seq_printf(seq, "%#7x\n", result.adapter_id[i]); } if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "There is more...\n"); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } /* Generic group F002h - Claimed Table (table) */ -int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_claimed(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; @@ -1171,434 +1089,356 @@ u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; u16 claimed_tid[64]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF002, -1, NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF002, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF002 Claimed Table"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF002 Claimed Table"); + return 0; } if (result.row_count) - len += sprintf(buf+len, "# ClaimedTid\n"); + seq_printf(seq, "# ClaimedTid\n"); - for (i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x\n", result.claimed_tid[i]); + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%-2d", i); + seq_printf(seq, "%#7x\n", result.claimed_tid[i]); } if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "There is more...\n"); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } /* Generic group F003h - User Table (table) */ -int i2o_proc_read_users(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_users(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - typedef struct _i2o_user_table - { + typedef struct _i2o_user_table { u16 instance; u16 user_tid; u8 claim_type; - u8 reserved1; - u16 reserved2; + u8 reserved1; + u16 reserved2; } i2o_user_table; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; i2o_user_table user[64]; } *result; result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) + if (!result) return -ENOMEM; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF003, -1, NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF003, -1, NULL, 0, + result, sizeof(*result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF003 User Table"); + i2o_report_query_status(seq, token, "0xF003 User Table"); goto out; } - len += sprintf(buf+len, "# Instance UserTid ClaimType\n"); + seq_printf(seq, "# Instance UserTid ClaimType\n"); - for(i=0; i < result->row_count; i++) - { - len += sprintf(buf+len, "%-3d", i); - len += sprintf(buf+len, "%#8x ", result->user[i].instance); - len += sprintf(buf+len, "%#7x ", result->user[i].user_tid); - len += sprintf(buf+len, "%#9x\n", result->user[i].claim_type); + for (i = 0; i < result->row_count; i++) { + seq_printf(seq, "%-3d", i); + seq_printf(seq, "%#8x ", result->user[i].instance); + seq_printf(seq, "%#7x ", result->user[i].user_tid); + seq_printf(seq, "%#9x\n", result->user[i].claim_type); } if (result->more_flag) - len += sprintf(buf+len, "There is more...\n"); -out: - spin_unlock(&i2o_proc_lock); + seq_printf(seq, "There is more...\n"); + out: kfree(result); - return len; + return 0; } /* Generic group F005h - Private message extensions (table) (optional) */ -int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_priv_msgs(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - typedef struct _i2o_private - { + typedef struct _i2o_private { u16 ext_instance; u16 organization_id; u16 x_function_code; } i2o_private; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; i2o_private extension[64]; } result; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF000, -1, - NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF005 Private Message Extensions (optional)"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF005 Private Message Extensions (optional)"); + return 0; } - - len += sprintf(buf+len, "Instance# OrgId FunctionCode\n"); - for(i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%0#9x ", result.extension[i].ext_instance); - len += sprintf(buf+len, "%0#6x ", result.extension[i].organization_id); - len += sprintf(buf+len, "%0#6x", result.extension[i].x_function_code); + seq_printf(seq, "Instance# OrgId FunctionCode\n"); - len += sprintf(buf+len, "\n"); - } + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%0#9x ", result.extension[i].ext_instance); + seq_printf(seq, "%0#6x ", result.extension[i].organization_id); + seq_printf(seq, "%0#6x", result.extension[i].x_function_code); - if(result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "\n"); + } - spin_unlock(&i2o_proc_lock); + if (result.more_flag) + seq_printf(seq, "There is more...\n"); - return len; + return 0; } - /* Generic group F006h - Authorized User Table (table) */ -int i2o_proc_read_authorized_users(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_authorized_users(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; u32 alternate_tid[64]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF006, -1, - NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF006, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF006 Autohorized User Table"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF006 Autohorized User Table"); + return 0; } if (result.row_count) - len += sprintf(buf+len, "# AlternateTid\n"); + seq_printf(seq, "# AlternateTid\n"); - for(i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x ", result.alternate_tid[i]); + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%-2d", i); + seq_printf(seq, "%#7x ", result.alternate_tid[i]); } if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "There is more...\n"); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } - /* Generic group F100h - Device Identity (scalar) */ -int i2o_proc_read_dev_identity(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_dev_identity(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number - // == (allow) 512d bytes (max) - static u16 *work16 = (u16*)work32; + struct i2o_device *d = (struct i2o_device *)seq->private; + static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number + // == (allow) 512d bytes (max) + static u16 *work16 = (u16 *) work32; int token; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF100, -1, - &work32, sizeof(work32)); + token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token ,"0xF100 Device Identity"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF100 Device Identity"); + return 0; } - - len += sprintf(buf, "Device Class : %s\n", i2o_get_class_name(work16[0])); - len += sprintf(buf+len, "Owner TID : %0#5x\n", work16[2]); - len += sprintf(buf+len, "Parent TID : %0#5x\n", work16[3]); - len += sprintf(buf+len, "Vendor info : %s\n", chtostr((u8 *)(work32+2), 16)); - len += sprintf(buf+len, "Product info : %s\n", chtostr((u8 *)(work32+6), 16)); - len += sprintf(buf+len, "Description : %s\n", chtostr((u8 *)(work32+10), 16)); - len += sprintf(buf+len, "Product rev. : %s\n", chtostr((u8 *)(work32+14), 8)); - len += sprintf(buf+len, "Serial number : "); - len = print_serial_number(buf, len, - (u8*)(work32+16), - /* allow for SNLen plus - * possible trailing '\0' - */ - sizeof(work32)-(16*sizeof(u32))-2 - ); - len += sprintf(buf+len, "\n"); + seq_printf(seq, "Device Class : %s\n", i2o_get_class_name(work16[0])); + seq_printf(seq, "Owner TID : %0#5x\n", work16[2]); + seq_printf(seq, "Parent TID : %0#5x\n", work16[3]); + seq_printf(seq, "Vendor info : %s\n", + chtostr((u8 *) (work32 + 2), 16)); + seq_printf(seq, "Product info : %s\n", + chtostr((u8 *) (work32 + 6), 16)); + seq_printf(seq, "Description : %s\n", + chtostr((u8 *) (work32 + 10), 16)); + seq_printf(seq, "Product rev. : %s\n", + chtostr((u8 *) (work32 + 14), 8)); + + seq_printf(seq, "Serial number : "); + print_serial_number(seq, (u8 *) (work32 + 16), + /* allow for SNLen plus + * possible trailing '\0' + */ + sizeof(work32) - (16 * sizeof(u32)) - 2); + seq_printf(seq, "\n"); - spin_unlock(&i2o_proc_lock); - - return len; + return 0; } - -int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_dev_name(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; - - if ( d->dev_name[0] == '\0' ) - return 0; + struct i2o_device *d = (struct i2o_device *)seq->private; - len = sprintf(buf, "%s\n", d->dev_name); + seq_printf(seq, "%s\n", d->device.bus_id); - return len; + return 0; } - /* Generic group F101h - DDM Identity (scalar) */ -int i2o_proc_read_ddm_identity(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; - struct - { + struct { u16 ddm_tid; u8 module_name[24]; u8 module_rev[8]; u8 sn_format; u8 serial_number[12]; - u8 pad[256]; // allow up to 256 byte (max) serial number - } result; + u8 pad[256]; // allow up to 256 byte (max) serial number + } result; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF101, -1, - &result, sizeof(result)); + token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF101 DDM Identity"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF101 DDM Identity"); + return 0; } - len += sprintf(buf, "Registering DDM TID : 0x%03x\n", result.ddm_tid); - len += sprintf(buf+len, "Module name : %s\n", chtostr(result.module_name, 24)); - len += sprintf(buf+len, "Module revision : %s\n", chtostr(result.module_rev, 8)); - - len += sprintf(buf+len, "Serial number : "); - len = print_serial_number(buf, len, result.serial_number, sizeof(result)-36); - /* allow for SNLen plus possible trailing '\0' */ + seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid); + seq_printf(seq, "Module name : %s\n", + chtostr(result.module_name, 24)); + seq_printf(seq, "Module revision : %s\n", + chtostr(result.module_rev, 8)); + + seq_printf(seq, "Serial number : "); + print_serial_number(seq, result.serial_number, sizeof(result) - 36); + /* allow for SNLen plus possible trailing '\0' */ - len += sprintf(buf+len, "\n"); + seq_printf(seq, "\n"); - spin_unlock(&i2o_proc_lock); - - return len; + return 0; } /* Generic group F102h - User Information (scalar) */ -int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_uinfo(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; - struct - { + struct { u8 device_name[64]; u8 service_name[64]; u8 physical_location[64]; u8 instance_number[4]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF102, -1, - &result, sizeof(result)); + token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF102 User Information"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF102 User Information"); + return 0; } - len += sprintf(buf, "Device name : %s\n", chtostr(result.device_name, 64)); - len += sprintf(buf+len, "Service name : %s\n", chtostr(result.service_name, 64)); - len += sprintf(buf+len, "Physical name : %s\n", chtostr(result.physical_location, 64)); - len += sprintf(buf+len, "Instance number : %s\n", chtostr(result.instance_number, 4)); + seq_printf(seq, "Device name : %s\n", + chtostr(result.device_name, 64)); + seq_printf(seq, "Service name : %s\n", + chtostr(result.service_name, 64)); + seq_printf(seq, "Physical name : %s\n", + chtostr(result.physical_location, 64)); + seq_printf(seq, "Instance number : %s\n", + chtostr(result.instance_number, 4)); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } /* Generic group F103h - SGL Operating Limits (scalar) */ -int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_sgl_limits(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; static u32 work32[12]; - static u16 *work16 = (u16 *)work32; - static u8 *work8 = (u8 *)work32; + static u16 *work16 = (u16 *) work32; + static u8 *work8 = (u8 *) work32; int token; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF103, -1, - &work32, sizeof(work32)); + token = i2o_parm_field_get(d, 0xF103, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF103 SGL Operating Limits"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF103 SGL Operating Limits"); + return 0; } - len += sprintf(buf, "SGL chain size : %d\n", work32[0]); - len += sprintf(buf+len, "Max SGL chain size : %d\n", work32[1]); - len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]); - len += sprintf(buf+len, "SGL frag count : %d\n", work16[6]); - len += sprintf(buf+len, "Max SGL frag count : %d\n", work16[7]); - len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]); + seq_printf(seq, "SGL chain size : %d\n", work32[0]); + seq_printf(seq, "Max SGL chain size : %d\n", work32[1]); + seq_printf(seq, "SGL chain size target : %d\n", work32[2]); + seq_printf(seq, "SGL frag count : %d\n", work16[6]); + seq_printf(seq, "Max SGL frag count : %d\n", work16[7]); + seq_printf(seq, "SGL frag count target : %d\n", work16[8]); +/* FIXME if (d->i2oversion == 0x02) { - len += sprintf(buf+len, "SGL data alignment : %d\n", work16[8]); - len += sprintf(buf+len, "SGL addr limit : %d\n", work8[20]); - len += sprintf(buf+len, "SGL addr sizes supported : "); - if (work8[21] & 0x01) - len += sprintf(buf+len, "32 bit "); - if (work8[21] & 0x02) - len += sprintf(buf+len, "64 bit "); - if (work8[21] & 0x04) - len += sprintf(buf+len, "96 bit "); - if (work8[21] & 0x08) - len += sprintf(buf+len, "128 bit "); - len += sprintf(buf+len, "\n"); +*/ + seq_printf(seq, "SGL data alignment : %d\n", work16[8]); + seq_printf(seq, "SGL addr limit : %d\n", work8[20]); + seq_printf(seq, "SGL addr sizes supported : "); + if (work8[21] & 0x01) + seq_printf(seq, "32 bit "); + if (work8[21] & 0x02) + seq_printf(seq, "64 bit "); + if (work8[21] & 0x04) + seq_printf(seq, "96 bit "); + if (work8[21] & 0x08) + seq_printf(seq, "128 bit "); + seq_printf(seq, "\n"); +/* } +*/ - spin_unlock(&i2o_proc_lock); - - return len; + return 0; } /* Generic group F200h - Sensors (scalar) */ -int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_sensors(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; - struct - { + struct { u16 sensor_instance; - u8 component; + u8 component; u16 component_instance; - u8 sensor_class; - u8 sensor_type; - u8 scaling_exponent; + u8 sensor_class; + u8 sensor_type; + u8 scaling_exponent; u32 actual_reading; u32 minimum_reading; u32 low2lowcat_treshold; @@ -1615,1795 +1455,663 @@ u32 hicat2high_treshold; u32 hi2hicat_treshold; u32 maximum_reading; - u8 sensor_state; + u8 sensor_state; u16 event_enable; } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF200, -1, - &result, sizeof(result)); + + token = i2o_parm_field_get(d, 0xF200, -1, &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF200 Sensors (optional)"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF200 Sensors (optional)"); + return 0; } - - len += sprintf(buf+len, "Sensor instance : %d\n", result.sensor_instance); - len += sprintf(buf+len, "Component : %d = ", result.component); - switch (result.component) - { - case 0: len += sprintf(buf+len, "Other"); - break; - case 1: len += sprintf(buf+len, "Planar logic Board"); - break; - case 2: len += sprintf(buf+len, "CPU"); - break; - case 3: len += sprintf(buf+len, "Chassis"); - break; - case 4: len += sprintf(buf+len, "Power Supply"); - break; - case 5: len += sprintf(buf+len, "Storage"); - break; - case 6: len += sprintf(buf+len, "External"); - break; - } - len += sprintf(buf+len,"\n"); + seq_printf(seq, "Sensor instance : %d\n", result.sensor_instance); - len += sprintf(buf+len, "Component instance : %d\n", result.component_instance); - len += sprintf(buf+len, "Sensor class : %s\n", - result.sensor_class ? "Analog" : "Digital"); - - len += sprintf(buf+len, "Sensor type : %d = ",result.sensor_type); - switch (result.sensor_type) - { - case 0: len += sprintf(buf+len, "Other\n"); - break; - case 1: len += sprintf(buf+len, "Thermal\n"); - break; - case 2: len += sprintf(buf+len, "DC voltage (DC volts)\n"); - break; - case 3: len += sprintf(buf+len, "AC voltage (AC volts)\n"); - break; - case 4: len += sprintf(buf+len, "DC current (DC amps)\n"); - break; - case 5: len += sprintf(buf+len, "AC current (AC volts)\n"); - break; - case 6: len += sprintf(buf+len, "Door open\n"); - break; - case 7: len += sprintf(buf+len, "Fan operational\n"); - break; - } - - len += sprintf(buf+len, "Scaling exponent : %d\n", result.scaling_exponent); - len += sprintf(buf+len, "Actual reading : %d\n", result.actual_reading); - len += sprintf(buf+len, "Minimum reading : %d\n", result.minimum_reading); - len += sprintf(buf+len, "Low2LowCat treshold : %d\n", result.low2lowcat_treshold); - len += sprintf(buf+len, "LowCat2Low treshold : %d\n", result.lowcat2low_treshold); - len += sprintf(buf+len, "LowWarn2Low treshold : %d\n", result.lowwarn2low_treshold); - len += sprintf(buf+len, "Low2LowWarn treshold : %d\n", result.low2lowwarn_treshold); - len += sprintf(buf+len, "Norm2LowWarn treshold : %d\n", result.norm2lowwarn_treshold); - len += sprintf(buf+len, "LowWarn2Norm treshold : %d\n", result.lowwarn2norm_treshold); - len += sprintf(buf+len, "Nominal reading : %d\n", result.nominal_reading); - len += sprintf(buf+len, "HiWarn2Norm treshold : %d\n", result.hiwarn2norm_treshold); - len += sprintf(buf+len, "Norm2HiWarn treshold : %d\n", result.norm2hiwarn_treshold); - len += sprintf(buf+len, "High2HiWarn treshold : %d\n", result.high2hiwarn_treshold); - len += sprintf(buf+len, "HiWarn2High treshold : %d\n", result.hiwarn2high_treshold); - len += sprintf(buf+len, "HiCat2High treshold : %d\n", result.hicat2high_treshold); - len += sprintf(buf+len, "High2HiCat treshold : %d\n", result.hi2hicat_treshold); - len += sprintf(buf+len, "Maximum reading : %d\n", result.maximum_reading); + seq_printf(seq, "Component : %d = ", result.component); + switch (result.component) { + case 0: + seq_printf(seq, "Other"); + break; + case 1: + seq_printf(seq, "Planar logic Board"); + break; + case 2: + seq_printf(seq, "CPU"); + break; + case 3: + seq_printf(seq, "Chassis"); + break; + case 4: + seq_printf(seq, "Power Supply"); + break; + case 5: + seq_printf(seq, "Storage"); + break; + case 6: + seq_printf(seq, "External"); + break; + } + seq_printf(seq, "\n"); + + seq_printf(seq, "Component instance : %d\n", + result.component_instance); + seq_printf(seq, "Sensor class : %s\n", + result.sensor_class ? "Analog" : "Digital"); + + seq_printf(seq, "Sensor type : %d = ", result.sensor_type); + switch (result.sensor_type) { + case 0: + seq_printf(seq, "Other\n"); + break; + case 1: + seq_printf(seq, "Thermal\n"); + break; + case 2: + seq_printf(seq, "DC voltage (DC volts)\n"); + break; + case 3: + seq_printf(seq, "AC voltage (AC volts)\n"); + break; + case 4: + seq_printf(seq, "DC current (DC amps)\n"); + break; + case 5: + seq_printf(seq, "AC current (AC volts)\n"); + break; + case 6: + seq_printf(seq, "Door open\n"); + break; + case 7: + seq_printf(seq, "Fan operational\n"); + break; + } + + seq_printf(seq, "Scaling exponent : %d\n", + result.scaling_exponent); + seq_printf(seq, "Actual reading : %d\n", result.actual_reading); + seq_printf(seq, "Minimum reading : %d\n", result.minimum_reading); + seq_printf(seq, "Low2LowCat treshold : %d\n", + result.low2lowcat_treshold); + seq_printf(seq, "LowCat2Low treshold : %d\n", + result.lowcat2low_treshold); + seq_printf(seq, "LowWarn2Low treshold : %d\n", + result.lowwarn2low_treshold); + seq_printf(seq, "Low2LowWarn treshold : %d\n", + result.low2lowwarn_treshold); + seq_printf(seq, "Norm2LowWarn treshold : %d\n", + result.norm2lowwarn_treshold); + seq_printf(seq, "LowWarn2Norm treshold : %d\n", + result.lowwarn2norm_treshold); + seq_printf(seq, "Nominal reading : %d\n", result.nominal_reading); + seq_printf(seq, "HiWarn2Norm treshold : %d\n", + result.hiwarn2norm_treshold); + seq_printf(seq, "Norm2HiWarn treshold : %d\n", + result.norm2hiwarn_treshold); + seq_printf(seq, "High2HiWarn treshold : %d\n", + result.high2hiwarn_treshold); + seq_printf(seq, "HiWarn2High treshold : %d\n", + result.hiwarn2high_treshold); + seq_printf(seq, "HiCat2High treshold : %d\n", + result.hicat2high_treshold); + seq_printf(seq, "High2HiCat treshold : %d\n", + result.hi2hicat_treshold); + seq_printf(seq, "Maximum reading : %d\n", result.maximum_reading); + + seq_printf(seq, "Sensor state : %d = ", result.sensor_state); + switch (result.sensor_state) { + case 0: + seq_printf(seq, "Normal\n"); + break; + case 1: + seq_printf(seq, "Abnormal\n"); + break; + case 2: + seq_printf(seq, "Unknown\n"); + break; + case 3: + seq_printf(seq, "Low Catastrophic (LoCat)\n"); + break; + case 4: + seq_printf(seq, "Low (Low)\n"); + break; + case 5: + seq_printf(seq, "Low Warning (LoWarn)\n"); + break; + case 6: + seq_printf(seq, "High Warning (HiWarn)\n"); + break; + case 7: + seq_printf(seq, "High (High)\n"); + break; + case 8: + seq_printf(seq, "High Catastrophic (HiCat)\n"); + break; + } + + seq_printf(seq, "Event_enable : 0x%02X\n", result.event_enable); + seq_printf(seq, " [%s] Operational state change. \n", + (result.event_enable & 0x01) ? "+" : "-"); + seq_printf(seq, " [%s] Low catastrophic. \n", + (result.event_enable & 0x02) ? "+" : "-"); + seq_printf(seq, " [%s] Low reading. \n", + (result.event_enable & 0x04) ? "+" : "-"); + seq_printf(seq, " [%s] Low warning. \n", + (result.event_enable & 0x08) ? "+" : "-"); + seq_printf(seq, + " [%s] Change back to normal from out of range state. \n", + (result.event_enable & 0x10) ? "+" : "-"); + seq_printf(seq, " [%s] High warning. \n", + (result.event_enable & 0x20) ? "+" : "-"); + seq_printf(seq, " [%s] High reading. \n", + (result.event_enable & 0x40) ? "+" : "-"); + seq_printf(seq, " [%s] High catastrophic. \n", + (result.event_enable & 0x80) ? "+" : "-"); - len += sprintf(buf+len, "Sensor state : %d = ", result.sensor_state); - switch (result.sensor_state) - { - case 0: len += sprintf(buf+len, "Normal\n"); - break; - case 1: len += sprintf(buf+len, "Abnormal\n"); - break; - case 2: len += sprintf(buf+len, "Unknown\n"); - break; - case 3: len += sprintf(buf+len, "Low Catastrophic (LoCat)\n"); - break; - case 4: len += sprintf(buf+len, "Low (Low)\n"); - break; - case 5: len += sprintf(buf+len, "Low Warning (LoWarn)\n"); - break; - case 6: len += sprintf(buf+len, "High Warning (HiWarn)\n"); - break; - case 7: len += sprintf(buf+len, "High (High)\n"); - break; - case 8: len += sprintf(buf+len, "High Catastrophic (HiCat)\n"); - break; - } - - len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable); - len += sprintf(buf+len, " [%s] Operational state change. \n", - (result.event_enable & 0x01) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low catastrophic. \n", - (result.event_enable & 0x02) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low reading. \n", - (result.event_enable & 0x04) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low warning. \n", - (result.event_enable & 0x08) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Change back to normal from out of range state. \n", - (result.event_enable & 0x10) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High warning. \n", - (result.event_enable & 0x20) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High reading. \n", - (result.event_enable & 0x40) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High catastrophic. \n", - (result.event_enable & 0x80) ? "+" : "-" ); - - spin_unlock(&i2o_proc_lock); - return len; + return 0; } - -static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len) +static int i2o_seq_open_hrt(struct inode *inode, struct file *file) { - int i; - - /* 19990419 -sralston - * The I2O v1.5 (and v2.0 so far) "official specification" - * got serial numbers WRONG! - * Apparently, and despite what Section 3.4.4 says and - * Figure 3-35 shows (pg 3-39 in the pdf doc), - * the convention / consensus seems to be: - * + First byte is SNFormat - * + Second byte is SNLen (but only if SNFormat==7 (?)) - * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format - */ - switch(serialno[0]) - { - case I2O_SNFORMAT_BINARY: /* Binary */ - pos += sprintf(buff+pos, "0x"); - for(i = 0; i < serialno[1]; i++) - { - pos += sprintf(buff+pos, "%02X", serialno[2+i]); - } - break; - - case I2O_SNFORMAT_ASCII: /* ASCII */ - if ( serialno[1] < ' ' ) /* printable or SNLen? */ - { - /* sanity */ - max_len = (max_len < serialno[1]) ? max_len : serialno[1]; - serialno[1+max_len] = '\0'; - - /* just print it */ - pos += sprintf(buff+pos, "%s", &serialno[2]); - } - else - { - /* print chars for specified length */ - for(i = 0; i < serialno[1]; i++) - { - pos += sprintf(buff+pos, "%c", serialno[2+i]); - } - } - break; - - case I2O_SNFORMAT_UNICODE: /* UNICODE */ - pos += sprintf(buff+pos, "UNICODE Format. Can't Display\n"); - break; - - case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ - pos += sprintf(buff+pos, - "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", - serialno[2], serialno[3], - serialno[4], serialno[5], - serialno[6], serialno[7]); - break; - - case I2O_SNFORMAT_WAN: /* WAN MAC Address */ - /* FIXME: Figure out what a WAN access address looks like?? */ - pos += sprintf(buff+pos, "WAN Access Address"); - break; - -/* plus new in v2.0 */ - case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ - /* FIXME: Figure out what a LAN-64 address really looks like?? */ - pos += sprintf(buff+pos, - "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", - serialno[8], serialno[9], - serialno[2], serialno[3], - serialno[4], serialno[5], - serialno[6], serialno[7]); - break; - - - case I2O_SNFORMAT_DDM: /* I2O DDM */ - pos += sprintf(buff+pos, - "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh", - *(u16*)&serialno[2], - *(u16*)&serialno[4], - *(u16*)&serialno[6]); - break; - - case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */ - case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */ - /* FIXME: Figure if this is even close?? */ - pos += sprintf(buff+pos, - "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n", - *(u32*)&serialno[2], - *(u32*)&serialno[6], - *(u32*)&serialno[10], - *(u32*)&serialno[14]); - break; - - - case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ - case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ - default: - pos += sprintf(buff+pos, "Unknown data format (0x%02x)", - serialno[0]); - break; - } - - return pos; -} + return single_open(file, i2o_seq_show_hrt, PDE(inode)->data); +}; -const char * i2o_get_connector_type(int conn) +static int i2o_seq_open_lct(struct inode *inode, struct file *file) { - int idx = 16; - static char *i2o_connector_type[] = { - "OTHER", - "UNKNOWN", - "AUI", - "UTP", - "BNC", - "RJ45", - "STP DB9", - "FIBER MIC", - "APPLE AUI", - "MII", - "DB9", - "HSSDC", - "DUPLEX SC FIBER", - "DUPLEX ST FIBER", - "TNC/BNC", - "HW DEFAULT" - }; - - switch(conn) - { - case 0x00000000: - idx = 0; - break; - case 0x00000001: - idx = 1; - break; - case 0x00000002: - idx = 2; - break; - case 0x00000003: - idx = 3; - break; - case 0x00000004: - idx = 4; - break; - case 0x00000005: - idx = 5; - break; - case 0x00000006: - idx = 6; - break; - case 0x00000007: - idx = 7; - break; - case 0x00000008: - idx = 8; - break; - case 0x00000009: - idx = 9; - break; - case 0x0000000A: - idx = 10; - break; - case 0x0000000B: - idx = 11; - break; - case 0x0000000C: - idx = 12; - break; - case 0x0000000D: - idx = 13; - break; - case 0x0000000E: - idx = 14; - break; - case 0xFFFFFFFF: - idx = 15; - break; - } - - return i2o_connector_type[idx]; -} - + return single_open(file, i2o_seq_show_lct, PDE(inode)->data); +}; -const char * i2o_get_connection_type(int conn) +static int i2o_seq_open_status(struct inode *inode, struct file *file) { - int idx = 0; - static char *i2o_connection_type[] = { - "Unknown", - "AUI", - "10BASE5", - "FIORL", - "10BASE2", - "10BROAD36", - "10BASE-T", - "10BASE-FP", - "10BASE-FB", - "10BASE-FL", - "100BASE-TX", - "100BASE-FX", - "100BASE-T4", - "1000BASE-SX", - "1000BASE-LX", - "1000BASE-CX", - "1000BASE-T", - "100VG-ETHERNET", - "100VG-TOKEN RING", - "4MBIT TOKEN RING", - "16 Mb Token Ring", - "125 MBAUD FDDI", - "Point-to-point", - "Arbitrated loop", - "Public loop", - "Fabric", - "Emulation", - "Other", - "HW default" - }; - - switch(conn) - { - case I2O_LAN_UNKNOWN: - idx = 0; - break; - case I2O_LAN_AUI: - idx = 1; - break; - case I2O_LAN_10BASE5: - idx = 2; - break; - case I2O_LAN_FIORL: - idx = 3; - break; - case I2O_LAN_10BASE2: - idx = 4; - break; - case I2O_LAN_10BROAD36: - idx = 5; - break; - case I2O_LAN_10BASE_T: - idx = 6; - break; - case I2O_LAN_10BASE_FP: - idx = 7; - break; - case I2O_LAN_10BASE_FB: - idx = 8; - break; - case I2O_LAN_10BASE_FL: - idx = 9; - break; - case I2O_LAN_100BASE_TX: - idx = 10; - break; - case I2O_LAN_100BASE_FX: - idx = 11; - break; - case I2O_LAN_100BASE_T4: - idx = 12; - break; - case I2O_LAN_1000BASE_SX: - idx = 13; - break; - case I2O_LAN_1000BASE_LX: - idx = 14; - break; - case I2O_LAN_1000BASE_CX: - idx = 15; - break; - case I2O_LAN_1000BASE_T: - idx = 16; - break; - case I2O_LAN_100VG_ETHERNET: - idx = 17; - break; - case I2O_LAN_100VG_TR: - idx = 18; - break; - case I2O_LAN_4MBIT: - idx = 19; - break; - case I2O_LAN_16MBIT: - idx = 20; - break; - case I2O_LAN_125MBAUD: - idx = 21; - break; - case I2O_LAN_POINT_POINT: - idx = 22; - break; - case I2O_LAN_ARB_LOOP: - idx = 23; - break; - case I2O_LAN_PUBLIC_LOOP: - idx = 24; - break; - case I2O_LAN_FABRIC: - idx = 25; - break; - case I2O_LAN_EMULATION: - idx = 26; - break; - case I2O_LAN_OTHER: - idx = 27; - break; - case I2O_LAN_DEFAULT: - idx = 28; - break; - } - - return i2o_connection_type[idx]; -} - + return single_open(file, i2o_seq_show_status, PDE(inode)->data); +}; -/* LAN group 0000h - Device info (scalar) */ -int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_hw(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[56]; - static u8 *work8 = (u8*)work32; - static u16 *work16 = (u16*)work32; - static u64 *work64 = (u64*)work32; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0000, -1, &work32, 56*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "LAN Type : "); - switch (work16[0]) - { - case 0x0030: - len += sprintf(buf+len, "Ethernet, "); - break; - case 0x0040: - len += sprintf(buf+len, "100Base VG, "); - break; - case 0x0050: - len += sprintf(buf+len, "Token Ring, "); - break; - case 0x0060: - len += sprintf(buf+len, "FDDI, "); - break; - case 0x0070: - len += sprintf(buf+len, "Fibre Channel, "); - break; - default: - len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]); - break; - } - - if (work16[1]&0x00000001) - len += sprintf(buf+len, "emulated LAN, "); - else - len += sprintf(buf+len, "physical LAN port, "); - - if (work16[1]&0x00000002) - len += sprintf(buf+len, "full duplex\n"); - else - len += sprintf(buf+len, "simplex\n"); - - len += sprintf(buf+len, "Address format : "); - switch(work8[4]) { - case 0x00: - len += sprintf(buf+len, "IEEE 48bit\n"); - break; - case 0x01: - len += sprintf(buf+len, "FC IEEE\n"); - break; - default: - len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]); - break; - } - - len += sprintf(buf+len, "State : "); - switch(work8[5]) - { - case 0x00: - len += sprintf(buf+len, "Unknown\n"); - break; - case 0x01: - len += sprintf(buf+len, "Unclaimed\n"); - break; - case 0x02: - len += sprintf(buf+len, "Operational\n"); - break; - case 0x03: - len += sprintf(buf+len, "Suspended\n"); - break; - case 0x04: - len += sprintf(buf+len, "Resetting\n"); - break; - case 0x05: - len += sprintf(buf+len, "ERROR: "); - if(work16[3]&0x0001) - len += sprintf(buf+len, "TxCU inoperative "); - if(work16[3]&0x0002) - len += sprintf(buf+len, "RxCU inoperative "); - if(work16[3]&0x0004) - len += sprintf(buf+len, "Local mem alloc "); - len += sprintf(buf+len, "\n"); - break; - case 0x06: - len += sprintf(buf+len, "Operational no Rx\n"); - break; - case 0x07: - len += sprintf(buf+len, "Suspended no Rx\n"); - break; - default: - len += sprintf(buf+len, "Unspecified\n"); - break; - } - - len += sprintf(buf+len, "Min packet size : %d\n", work32[2]); - len += sprintf(buf+len, "Max packet size : %d\n", work32[3]); - len += sprintf(buf+len, "HW address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[16],work8[17],work8[18],work8[19], - work8[20],work8[21],work8[22],work8[23]); - - len += sprintf(buf+len, "Max Tx wire speed : %d bps\n", (int)work64[3]); - len += sprintf(buf+len, "Max Rx wire speed : %d bps\n", (int)work64[4]); - - len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]); - len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]); - - spin_unlock(&i2o_proc_lock); - return len; -} + return single_open(file, i2o_seq_show_hw, PDE(inode)->data); +}; -/* LAN group 0001h - MAC address table (scalar) */ -int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_ddm_table(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[48]; - static u8 *work8 = (u8*)work32; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0001, -1, &work32, 48*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Active address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[0],work8[1],work8[2],work8[3], - work8[4],work8[5],work8[6],work8[7]); - len += sprintf(buf+len, "Current address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[8],work8[9],work8[10],work8[11], - work8[12],work8[13],work8[14],work8[15]); - len += sprintf(buf+len, "Functional address mask : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[16],work8[17],work8[18],work8[19], - work8[20],work8[21],work8[22],work8[23]); - - len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]); - len += sprintf(buf+len," [%s] Unicast packets supported\n", - (work32[7]&0x00000001)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous mode supported\n", - (work32[7]&0x00000002)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous multicast mode supported\n", - (work32[7]&0x00000004)?"+":"-"); - len += sprintf(buf+len," [%s] Broadcast reception disabling supported\n", - (work32[7]&0x00000100)?"+":"-"); - len += sprintf(buf+len," [%s] Multicast reception disabling supported\n", - (work32[7]&0x00000200)?"+":"-"); - len += sprintf(buf+len," [%s] Functional address disabling supported\n", - (work32[7]&0x00000400)?"+":"-"); - len += sprintf(buf+len," [%s] MAC reporting supported\n", - (work32[7]&0x00000800)?"+":"-"); - - len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]); - len += sprintf(buf+len," [%s] Unicast packets disable\n", - (work32[6]&0x00000001)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous mode enable\n", - (work32[6]&0x00000002)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous multicast mode enable\n", - (work32[6]&0x00000004)?"+":"-"); - len += sprintf(buf+len," [%s] Broadcast packets disable\n", - (work32[6]&0x00000100)?"+":"-"); - len += sprintf(buf+len," [%s] Multicast packets disable\n", - (work32[6]&0x00000200)?"+":"-"); - len += sprintf(buf+len," [%s] Functional address disable\n", - (work32[6]&0x00000400)?"+":"-"); - - if (work32[7]&0x00000800) { - len += sprintf(buf+len, " MAC reporting mode : "); - if (work32[6]&0x00000800) - len += sprintf(buf+len, "Pass only priority MAC packets to user\n"); - else if (work32[6]&0x00001000) - len += sprintf(buf+len, "Pass all MAC packets to user\n"); - else if (work32[6]&0x00001800) - len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n"); - else - len += sprintf(buf+len, "Do not pass MAC packets to user\n"); - } - len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]); - len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n", - work32[9]); - len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n", - work32[10]); - - spin_unlock(&i2o_proc_lock); - - return len; -} + return single_open(file, i2o_seq_show_ddm_table, PDE(inode)->data); +}; -/* LAN group 0002h - Multicast MAC address table (table) */ -int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +static int i2o_seq_open_driver_store(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - u8 mc_addr[8]; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u8 mc_addr[256][8]; - } *result; - - result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) - return -ENOMEM; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, 0x0002, -1, - NULL, 0, result, sizeof(*result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x002 LAN Multicast MAC Address"); - goto out; - } - - for (i = 0; i < result->row_count; i++) - { - memcpy(mc_addr, result->mc_addr[i], 8); - - len += sprintf(buf+len, "MC MAC address[%d]: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - i, mc_addr[0], mc_addr[1], mc_addr[2], - mc_addr[3], mc_addr[4], mc_addr[5], - mc_addr[6], mc_addr[7]); - } -out: - spin_unlock(&i2o_proc_lock); - kfree(result); - return len; -} + return single_open(file, i2o_seq_show_driver_store, PDE(inode)->data); +}; -/* LAN group 0003h - Batch Control (scalar) */ -int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +static int i2o_seq_open_drivers_stored(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[9]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0003, -1, &work32, 9*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Batch mode "); - if (work32[0]&0x00000001) - len += sprintf(buf+len, "disabled"); - else - len += sprintf(buf+len, "enabled"); - if (work32[0]&0x00000002) - len += sprintf(buf+len, " (current setting)"); - if (work32[0]&0x00000004) - len += sprintf(buf+len, ", forced"); - else - len += sprintf(buf+len, ", toggle"); - len += sprintf(buf+len, "\n"); - - len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]); - len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]); - len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]); - len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]); - - spin_unlock(&i2o_proc_lock); - return len; -} + return single_open(file, i2o_seq_show_drivers_stored, PDE(inode)->data); +}; -/* LAN group 0004h - LAN Operation (scalar) */ -int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_groups(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[5]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; + return single_open(file, i2o_seq_show_groups, PDE(inode)->data); +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0004, -1, &work32, 20); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]); - len += sprintf(buf+len, "Transmission error reporting : %s\n", - (work32[1]&1)?"on":"off"); - len += sprintf(buf+len, "Bad packet handling : %s\n", - (work32[1]&0x2)?"by host":"by DDM"); - len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); - - len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]); - len += sprintf(buf+len, " [%s] HW CRC suppression\n", - (work32[3]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW IPv4 checksum\n", - (work32[3]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW TCP checksum\n", - (work32[3]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW UDP checksum\n", - (work32[3]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW RSVP checksum\n", - (work32[3]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW ICMP checksum\n", - (work32[3]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback suppression enable\n", - (work32[3]&0x00002000) ? "+" : "-"); - - len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]); - len += sprintf(buf+len, " [%s] FCS in payload\n", - (work32[4]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW IPv4 checksum validation\n", - (work32[4]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW TCP checksum validation\n", - (work32[4]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW UDP checksum validation\n", - (work32[4]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW RSVP checksum validation\n", - (work32[4]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW ICMP checksum validation\n", - (work32[4]&0x00001000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0005h - Media operation (scalar) */ -int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +static int i2o_seq_open_phys_device(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u32 connector_type; - u32 connection_type; - u64 current_tx_wire_speed; - u64 current_rx_wire_speed; - u8 duplex_mode; - u8 link_status; - u8 reserved; - u8 duplex_mode_target; - u32 connector_type_target; - u32 connection_type_target; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0005, -1, &result, sizeof(result)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Connector type : %s\n", - i2o_get_connector_type(result.connector_type)); - len += sprintf(buf+len, "Connection type : %s\n", - i2o_get_connection_type(result.connection_type)); - - len += sprintf(buf+len, "Current Tx wire speed : %d bps\n", (int)result.current_tx_wire_speed); - len += sprintf(buf+len, "Current Rx wire speed : %d bps\n", (int)result.current_rx_wire_speed); - len += sprintf(buf+len, "Duplex mode : %s duplex\n", - (result.duplex_mode)?"Full":"Half"); - - len += sprintf(buf+len, "Link status : "); - switch (result.link_status) - { - case 0x00: - len += sprintf(buf+len, "Unknown\n"); - break; - case 0x01: - len += sprintf(buf+len, "Normal\n"); - break; - case 0x02: - len += sprintf(buf+len, "Failure\n"); - break; - case 0x03: - len += sprintf(buf+len, "Reset\n"); - break; - default: - len += sprintf(buf+len, "Unspecified\n"); - } - - len += sprintf(buf+len, "Duplex mode target : "); - switch (result.duplex_mode_target){ - case 0: - len += sprintf(buf+len, "Half duplex\n"); - break; - case 1: - len += sprintf(buf+len, "Full duplex\n"); - break; - default: - len += sprintf(buf+len, "\n"); - } - - len += sprintf(buf+len, "Connector type target : %s\n", - i2o_get_connector_type(result.connector_type_target)); - len += sprintf(buf+len, "Connection type target : %s\n", - i2o_get_connection_type(result.connection_type_target)); - - spin_unlock(&i2o_proc_lock); - return len; -} + return single_open(file, i2o_seq_show_phys_device, PDE(inode)->data); +}; -/* LAN group 0006h - Alternate address (table) (optional) */ -int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_claimed(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - u8 alt_addr[8]; - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u8 alt_addr[256][8]; - } *result; - - result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) - return -ENOMEM; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0x0006, -1, NULL, 0, result, sizeof(*result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0006 LAN Alternate Address (optional)"); - goto out; - } - - for (i=0; i < result->row_count; i++) - { - memcpy(alt_addr,result->alt_addr[i],8); - len += sprintf(buf+len, "Alternate address[%d]: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - i, alt_addr[0], alt_addr[1], alt_addr[2], - alt_addr[3], alt_addr[4], alt_addr[5], - alt_addr[6], alt_addr[7]); - } -out: - spin_unlock(&i2o_proc_lock); - kfree(result); - return len; -} - + return single_open(file, i2o_seq_show_claimed, PDE(inode)->data); +}; -/* LAN group 0007h - Transmit info (scalar) */ -int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_users(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[8]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; + return single_open(file, i2o_seq_show_users, PDE(inode)->data); +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0007, -1, &work32, 8*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Tx Max SG elements per packet : %d\n", work32[0]); - len += sprintf(buf+len, "Tx Max SG elements per chain : %d\n", work32[1]); - len += sprintf(buf+len, "Tx Max outstanding packets : %d\n", work32[2]); - len += sprintf(buf+len, "Tx Max packets per request : %d\n", work32[3]); - - len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]); - len += sprintf(buf+len, " [%s] No DA in SGL\n", - (work32[4]&0x00000002) ? "+" : "-"); - len += sprintf(buf+len, " [%s] CRC suppression\n", - (work32[4]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] MAC insertion\n", - (work32[4]&0x00000010) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RIF insertion\n", - (work32[4]&0x00000020) ? "+" : "-"); - len += sprintf(buf+len, " [%s] IPv4 checksum generation\n", - (work32[4]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] TCP checksum generation\n", - (work32[4]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] UDP checksum generation\n", - (work32[4]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RSVP checksum generation\n", - (work32[4]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] ICMP checksum generation\n", - (work32[4]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback enabled\n", - (work32[4]&0x00010000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback suppression enabled\n", - (work32[4]&0x00020000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0008h - Receive info (scalar) */ -int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_priv_msgs(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[8]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0008, -1, &work32, 8*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf ,"Rx Max size of chain element : %d\n", work32[0]); - len += sprintf(buf+len, "Rx Max Buckets : %d\n", work32[1]); - len += sprintf(buf+len, "Rx Max Buckets in Reply : %d\n", work32[3]); - len += sprintf(buf+len, "Rx Max Packets in Bucket : %d\n", work32[4]); - len += sprintf(buf+len, "Rx Max Buckets in Post : %d\n", work32[5]); - - len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]); - len += sprintf(buf+len, " [%s] FCS reception\n", - (work32[2]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] IPv4 checksum validation \n", - (work32[2]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] TCP checksum validation \n", - (work32[2]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] UDP checksum validation \n", - (work32[2]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RSVP checksum validation \n", - (work32[2]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] ICMP checksum validation \n", - (work32[2]&0x00001000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -static int i2o_report_opt_field(char *buf, char *field_name, - int field_nbr, int supp_fields, u64 *value) -{ - if (supp_fields & (1 << field_nbr)) - return sprintf(buf, "%-24s : " FMT_U64_HEX "\n", field_name, U64_VAL(value)); - else - return sprintf(buf, "%-24s : Not supported\n", field_name); -} - -/* LAN group 0100h - LAN Historical statistics (scalar) */ -/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */ -/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics (scalar) */ -/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics (scalar) */ + return single_open(file, i2o_seq_show_priv_msgs, PDE(inode)->data); +}; -int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_authorized_users(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u64 tx_packets; - u64 tx_bytes; - u64 rx_packets; - u64 rx_bytes; - u64 tx_errors; - u64 rx_errors; - u64 rx_dropped; - u64 adapter_resets; - u64 adapter_suspends; - } stats; // 0x0100 - - static u64 supp_groups[4]; // 0x0180 - - struct - { - u64 tx_retries; - u64 tx_directed_bytes; - u64 tx_directed_packets; - u64 tx_multicast_bytes; - u64 tx_multicast_packets; - u64 tx_broadcast_bytes; - u64 tx_broadcast_packets; - u64 tx_group_addr_packets; - u64 tx_short_packets; - } tx_stats; // 0x0182 - - struct - { - u64 rx_crc_errors; - u64 rx_directed_bytes; - u64 rx_directed_packets; - u64 rx_multicast_bytes; - u64 rx_multicast_packets; - u64 rx_broadcast_bytes; - u64 rx_broadcast_packets; - u64 rx_group_addr_packets; - u64 rx_short_packets; - u64 rx_long_packets; - u64 rx_runt_packets; - } rx_stats; // 0x0183 - - struct - { - u64 ipv4_generate; - u64 ipv4_validate_success; - u64 ipv4_validate_errors; - u64 tcp_generate; - u64 tcp_validate_success; - u64 tcp_validate_errors; - u64 udp_generate; - u64 udp_validate_success; - u64 udp_validate_errors; - u64 rsvp_generate; - u64 rsvp_validate_success; - u64 rsvp_validate_errors; - u64 icmp_generate; - u64 icmp_validate_success; - u64 icmp_validate_errors; - } chksum_stats; // 0x0184 - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0100, -1, &stats, sizeof(stats)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Tx packets : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_packets)); - len += sprintf(buf+len, "Tx bytes : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_bytes)); - len += sprintf(buf+len, "Rx packets : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_packets)); - len += sprintf(buf+len, "Rx bytes : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_bytes)); - len += sprintf(buf+len, "Tx errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_errors)); - len += sprintf(buf+len, "Rx errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_errors)); - len += sprintf(buf+len, "Rx dropped : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_dropped)); - len += sprintf(buf+len, "Adapter resets : " FMT_U64_HEX "\n", - U64_VAL(&stats.adapter_resets)); - len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n", - U64_VAL(&stats.adapter_suspends)); - - /* Optional statistics follows */ - /* Get 0x0180 to see which optional groups/fields are supported */ - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0180, -1, &supp_groups, sizeof(supp_groups)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x180 LAN Supported Optional Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - if (supp_groups[1]) /* 0x0182 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0182, -1, &tx_stats, sizeof(tx_stats)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x182 LAN Optional Tx Historical Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "==== Optional TX statistics (group 0182h)\n"); - - len += i2o_report_opt_field(buf+len, "Tx RetryCount", - 0, supp_groups[1], &tx_stats.tx_retries); - len += i2o_report_opt_field(buf+len, "Tx DirectedBytes", - 1, supp_groups[1], &tx_stats.tx_directed_bytes); - len += i2o_report_opt_field(buf+len, "Tx DirectedPackets", - 2, supp_groups[1], &tx_stats.tx_directed_packets); - len += i2o_report_opt_field(buf+len, "Tx MulticastBytes", - 3, supp_groups[1], &tx_stats.tx_multicast_bytes); - len += i2o_report_opt_field(buf+len, "Tx MulticastPackets", - 4, supp_groups[1], &tx_stats.tx_multicast_packets); - len += i2o_report_opt_field(buf+len, "Tx BroadcastBytes", - 5, supp_groups[1], &tx_stats.tx_broadcast_bytes); - len += i2o_report_opt_field(buf+len, "Tx BroadcastPackets", - 6, supp_groups[1], &tx_stats.tx_broadcast_packets); - len += i2o_report_opt_field(buf+len, "Tx TotalGroupAddrPackets", - 7, supp_groups[1], &tx_stats.tx_group_addr_packets); - len += i2o_report_opt_field(buf+len, "Tx TotalPacketsTooShort", - 8, supp_groups[1], &tx_stats.tx_short_packets); - } - - if (supp_groups[2]) /* 0x0183 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0183, -1, &rx_stats, sizeof(rx_stats)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats"); - spin_unlock(&i2o_proc_lock); - return len; - } + return single_open(file, i2o_seq_show_authorized_users, + PDE(inode)->data); +}; - len += sprintf(buf+len, "==== Optional RX statistics (group 0183h)\n"); +static int i2o_seq_open_dev_identity(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_dev_identity, PDE(inode)->data); +}; - len += i2o_report_opt_field(buf+len, "Rx CRCErrorCount", - 0, supp_groups[2], &rx_stats.rx_crc_errors); - len += i2o_report_opt_field(buf+len, "Rx DirectedBytes", - 1, supp_groups[2], &rx_stats.rx_directed_bytes); - len += i2o_report_opt_field(buf+len, "Rx DirectedPackets", - 2, supp_groups[2], &rx_stats.rx_directed_packets); - len += i2o_report_opt_field(buf+len, "Rx MulticastBytes", - 3, supp_groups[2], &rx_stats.rx_multicast_bytes); - len += i2o_report_opt_field(buf+len, "Rx MulticastPackets", - 4, supp_groups[2], &rx_stats.rx_multicast_packets); - len += i2o_report_opt_field(buf+len, "Rx BroadcastBytes", - 5, supp_groups[2], &rx_stats.rx_broadcast_bytes); - len += i2o_report_opt_field(buf+len, "Rx BroadcastPackets", - 6, supp_groups[2], &rx_stats.rx_broadcast_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalGroupAddrPackets", - 7, supp_groups[2], &rx_stats.rx_group_addr_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooShort", - 8, supp_groups[2], &rx_stats.rx_short_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooLong", - 9, supp_groups[2], &rx_stats.rx_long_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsRunt", - 10, supp_groups[2], &rx_stats.rx_runt_packets); - } - - if (supp_groups[3]) /* 0x0184 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0184, -1, &chksum_stats, sizeof(chksum_stats)); +static int i2o_seq_open_ddm_identity(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_ddm_identity, PDE(inode)->data); +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x184 LAN Optional Chksum Historical Stats"); - spin_unlock(&i2o_proc_lock); - return len; - } +static int i2o_seq_open_uinfo(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_uinfo, PDE(inode)->data); +}; - len += sprintf(buf+len, "==== Optional CHKSUM statistics (group 0x0184)\n"); +static int i2o_seq_open_sgl_limits(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_sgl_limits, PDE(inode)->data); +}; - len += i2o_report_opt_field(buf+len, "IPv4 Generate", - 0, supp_groups[3], &chksum_stats.ipv4_generate); - len += i2o_report_opt_field(buf+len, "IPv4 ValidateSuccess", - 1, supp_groups[3], &chksum_stats.ipv4_validate_success); - len += i2o_report_opt_field(buf+len, "IPv4 ValidateError", - 2, supp_groups[3], &chksum_stats.ipv4_validate_errors); - len += i2o_report_opt_field(buf+len, "TCP Generate", - 3, supp_groups[3], &chksum_stats.tcp_generate); - len += i2o_report_opt_field(buf+len, "TCP ValidateSuccess", - 4, supp_groups[3], &chksum_stats.tcp_validate_success); - len += i2o_report_opt_field(buf+len, "TCP ValidateError", - 5, supp_groups[3], &chksum_stats.tcp_validate_errors); - len += i2o_report_opt_field(buf+len, "UDP Generate", - 6, supp_groups[3], &chksum_stats.udp_generate); - len += i2o_report_opt_field(buf+len, "UDP ValidateSuccess", - 7, supp_groups[3], &chksum_stats.udp_validate_success); - len += i2o_report_opt_field(buf+len, "UDP ValidateError", - 8, supp_groups[3], &chksum_stats.udp_validate_errors); - len += i2o_report_opt_field(buf+len, "RSVP Generate", - 9, supp_groups[3], &chksum_stats.rsvp_generate); - len += i2o_report_opt_field(buf+len, "RSVP ValidateSuccess", - 10, supp_groups[3], &chksum_stats.rsvp_validate_success); - len += i2o_report_opt_field(buf+len, "RSVP ValidateError", - 11, supp_groups[3], &chksum_stats.rsvp_validate_errors); - len += i2o_report_opt_field(buf+len, "ICMP Generate", - 12, supp_groups[3], &chksum_stats.icmp_generate); - len += i2o_report_opt_field(buf+len, "ICMP ValidateSuccess", - 13, supp_groups[3], &chksum_stats.icmp_validate_success); - len += i2o_report_opt_field(buf+len, "ICMP ValidateError", - 14, supp_groups[3], &chksum_stats.icmp_validate_errors); - } - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0200h - Required Ethernet Statistics (scalar) */ -/* LAN group 0280h - Optional Ethernet Statistics Supported (scalar) */ -/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */ -int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +static int i2o_seq_open_sensors(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - int token; + return single_open(file, i2o_seq_show_sensors, PDE(inode)->data); +}; - struct - { - u64 rx_align_errors; - u64 tx_one_collisions; - u64 tx_multiple_collisions; - u64 tx_deferred; - u64 tx_late_collisions; - u64 tx_max_collisions; - u64 tx_carrier_lost; - u64 tx_excessive_deferrals; - } stats; +static int i2o_seq_open_dev_name(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_dev_name, PDE(inode)->data); +}; - static u64 supp_fields; - struct - { - u64 rx_overrun; - u64 tx_underrun; - u64 tx_heartbeat_failure; - } hist_stats; +static struct file_operations i2o_seq_fops_lct = { + .open = i2o_seq_open_lct, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - spin_lock(&i2o_proc_lock); - len = 0; +static struct file_operations i2o_seq_fops_hrt = { + .open = i2o_seq_open_hrt, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0200, -1, &stats, sizeof(stats)); +static struct file_operations i2o_seq_fops_status = { + .open = i2o_seq_open_status, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0200 LAN Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Rx alignment errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_align_errors)); - len += sprintf(buf+len, "Tx one collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_one_collisions)); - len += sprintf(buf+len, "Tx multicollisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_multiple_collisions)); - len += sprintf(buf+len, "Tx deferred : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_deferred)); - len += sprintf(buf+len, "Tx late collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_late_collisions)); - len += sprintf(buf+len, "Tx max collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_max_collisions)); - len += sprintf(buf+len, "Tx carrier lost : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_carrier_lost)); - len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_excessive_deferrals)); +static struct file_operations i2o_seq_fops_hw = { + .open = i2o_seq_open_hw, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - /* Optional Ethernet statistics follows */ - /* Get 0x0280 to see which optional fields are supported */ +static struct file_operations i2o_seq_fops_ddm_table = { + .open = i2o_seq_open_ddm_table, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0280, -1, &supp_fields, sizeof(supp_fields)); +static struct file_operations i2o_seq_fops_driver_store = { + .open = i2o_seq_open_driver_store, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0280 LAN Supported Optional Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_drivers_stored = { + .open = i2o_seq_open_drivers_stored, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (supp_fields) /* 0x0281 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0281, -1, &stats, sizeof(stats)); +static struct file_operations i2o_seq_fops_groups = { + .open = i2o_seq_open_groups, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0281 LAN Optional Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_phys_device = { + .open = i2o_seq_open_phys_device, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - len += sprintf(buf+len, "==== Optional ETHERNET statistics (group 0x0281)\n"); +static struct file_operations i2o_seq_fops_claimed = { + .open = i2o_seq_open_claimed, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - len += i2o_report_opt_field(buf+len, "Rx Overrun", - 0, supp_fields, &hist_stats.rx_overrun); - len += i2o_report_opt_field(buf+len, "Tx Underrun", - 1, supp_fields, &hist_stats.tx_underrun); - len += i2o_report_opt_field(buf+len, "Tx HeartbeatFailure", - 2, supp_fields, &hist_stats.tx_heartbeat_failure); - } +static struct file_operations i2o_seq_fops_users = { + .open = i2o_seq_open_users, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - spin_unlock(&i2o_proc_lock); - return len; -} +static struct file_operations i2o_seq_fops_priv_msgs = { + .open = i2o_seq_open_priv_msgs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; -/* LAN group 0300h - Required Token Ring Statistics (scalar) */ -/* LAN group 0380h, 0381h - Optional Statistics not yet defined (TODO) */ -int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u64 work64[13]; - int token; +static struct file_operations i2o_seq_fops_authorized_users = { + .open = i2o_seq_open_authorized_users, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - static char *ring_status[] = - { - "", - "", - "", - "", - "", - "Ring Recovery", - "Single Station", - "Counter Overflow", - "Remove Received", - "", - "Auto-Removal Error 1", - "Lobe Wire Fault", - "Transmit Beacon", - "Soft Error", - "Hard Error", - "Signal Loss" - }; +static struct file_operations i2o_seq_fops_dev_name = { + .open = i2o_seq_open_dev_name, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - spin_lock(&i2o_proc_lock); - len = 0; +static struct file_operations i2o_seq_fops_dev_identity = { + .open = i2o_seq_open_dev_identity, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0300, -1, &work64, sizeof(work64)); +static struct file_operations i2o_seq_fops_ddm_identity = { + .open = i2o_seq_open_ddm_identity, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0300 Token Ring Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "LineErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[0])); - len += sprintf(buf+len, "LostFrames : " FMT_U64_HEX "\n", - U64_VAL(&work64[1])); - len += sprintf(buf+len, "ACError : " FMT_U64_HEX "\n", - U64_VAL(&work64[2])); - len += sprintf(buf+len, "TxAbortDelimiter : " FMT_U64_HEX "\n", - U64_VAL(&work64[3])); - len += sprintf(buf+len, "BursErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[4])); - len += sprintf(buf+len, "FrameCopiedErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[5])); - len += sprintf(buf+len, "FrequencyErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[6])); - len += sprintf(buf+len, "InternalErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[7])); - len += sprintf(buf+len, "LastRingStatus : %s\n", ring_status[work64[8]]); - len += sprintf(buf+len, "TokenError : " FMT_U64_HEX "\n", - U64_VAL(&work64[9])); - len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n", - U64_VAL(&work64[10])); - len += sprintf(buf+len, "LastRingID : " FMT_U64_HEX "\n", - U64_VAL(&work64[11])); - len += sprintf(buf+len, "LastBeaconType : " FMT_U64_HEX "\n", - U64_VAL(&work64[12])); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0400h - Required FDDI Statistics (scalar) */ -/* LAN group 0480h, 0481h - Optional Statistics, not yet defined (TODO) */ -int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u64 work64[11]; - int token; +static struct file_operations i2o_seq_fops_uinfo = { + .open = i2o_seq_open_uinfo, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - static char *conf_state[] = - { - "Isolated", - "Local a", - "Local b", - "Local ab", - "Local s", - "Wrap a", - "Wrap b", - "Wrap ab", - "Wrap s", - "C-Wrap a", - "C-Wrap b", - "C-Wrap s", - "Through", - }; +static struct file_operations i2o_seq_fops_sgl_limits = { + .open = i2o_seq_open_sgl_limits, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - static char *ring_state[] = - { - "Isolated", - "Non-op", - "Rind-op", - "Detect", - "Non-op-Dup", - "Ring-op-Dup", - "Directed", - "Trace" - }; +static struct file_operations i2o_seq_fops_sensors = { + .open = i2o_seq_open_sensors, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - static char *link_state[] = - { - "Off", - "Break", - "Trace", - "Connect", - "Next", - "Signal", - "Join", - "Verify", - "Active", - "Maintenance" - }; +/* + * IOP specific entries...write field just in case someone + * ever wants one. + */ +static i2o_proc_entry i2o_proc_generic_iop_entries[] = { + {"hrt", S_IFREG | S_IRUGO, &i2o_seq_fops_hrt}, + {"lct", S_IFREG | S_IRUGO, &i2o_seq_fops_lct}, + {"status", S_IFREG | S_IRUGO, &i2o_seq_fops_status}, + {"hw", S_IFREG | S_IRUGO, &i2o_seq_fops_hw}, + {"ddm_table", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_table}, + {"driver_store", S_IFREG | S_IRUGO, &i2o_seq_fops_driver_store}, + {"drivers_stored", S_IFREG | S_IRUGO, &i2o_seq_fops_drivers_stored}, + {NULL, 0, NULL} +}; - spin_lock(&i2o_proc_lock); - len = 0; +/* + * Device specific entries + */ +static i2o_proc_entry generic_dev_entries[] = { + {"groups", S_IFREG | S_IRUGO, &i2o_seq_fops_groups}, + {"phys_dev", S_IFREG | S_IRUGO, &i2o_seq_fops_phys_device}, + {"claimed", S_IFREG | S_IRUGO, &i2o_seq_fops_claimed}, + {"users", S_IFREG | S_IRUGO, &i2o_seq_fops_users}, + {"priv_msgs", S_IFREG | S_IRUGO, &i2o_seq_fops_priv_msgs}, + {"authorized_users", S_IFREG | S_IRUGO, &i2o_seq_fops_authorized_users}, + {"dev_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_identity}, + {"ddm_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_identity}, + {"user_info", S_IFREG | S_IRUGO, &i2o_seq_fops_uinfo}, + {"sgl_limits", S_IFREG | S_IRUGO, &i2o_seq_fops_sgl_limits}, + {"sensors", S_IFREG | S_IRUGO, &i2o_seq_fops_sensors}, + {NULL, 0, NULL} +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0400, -1, &work64, sizeof(work64)); +/* + * Storage unit specific entries (SCSI Periph, BS) with device names + */ +static i2o_proc_entry rbs_dev_entries[] = { + {"dev_name", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_name}, + {NULL, 0, NULL} +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0400 FDDI Required Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "ConfigurationState : %s\n", conf_state[work64[0]]); - len += sprintf(buf+len, "UpstreamNode : " FMT_U64_HEX "\n", - U64_VAL(&work64[1])); - len += sprintf(buf+len, "DownStreamNode : " FMT_U64_HEX "\n", - U64_VAL(&work64[2])); - len += sprintf(buf+len, "FrameErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[3])); - len += sprintf(buf+len, "FramesLost : " FMT_U64_HEX "\n", - U64_VAL(&work64[4])); - len += sprintf(buf+len, "RingMgmtState : %s\n", ring_state[work64[5]]); - len += sprintf(buf+len, "LCTFailures : " FMT_U64_HEX "\n", - U64_VAL(&work64[6])); - len += sprintf(buf+len, "LEMRejects : " FMT_U64_HEX "\n", - U64_VAL(&work64[7])); - len += sprintf(buf+len, "LEMCount : " FMT_U64_HEX "\n", - U64_VAL(&work64[8])); - len += sprintf(buf+len, "LConnectionState : %s\n", - link_state[work64[9]]); - - spin_unlock(&i2o_proc_lock); - return len; -} - -static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry, - struct proc_dir_entry *parent) -{ - struct proc_dir_entry *ent; - - while(pentry->name != NULL) - { - ent = create_proc_entry(pentry->name, pentry->mode, parent); - if(!ent) return -1; +/** + * i2o_proc_create_entries - Creates proc dir entries + * @dir: proc dir entry under which the entries should be placed + * @i2o_pe: pointer to the entries which should be added + * @data: pointer to I2O controller or device + * + * Create proc dir entries for a I2O controller or I2O device. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_proc_create_entries(struct proc_dir_entry *dir, + i2o_proc_entry * i2o_pe, void *data) +{ + struct proc_dir_entry *tmp; - ent->data = data; - ent->read_proc = pentry->read_proc; - ent->write_proc = pentry->write_proc; - if(pentry->fops_proc) - ent->proc_fops = pentry->fops_proc; + while (i2o_pe->name) { + tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir); + if (!tmp) + return -1; - ent->nlink = 1; + tmp->data = data; + tmp->proc_fops = i2o_pe->fops; - pentry++; + i2o_pe++; } return 0; } -static void i2o_proc_remove_entries(i2o_proc_entry *pentry, - struct proc_dir_entry *parent) -{ - while(pentry->name != NULL) - { - remove_proc_entry(pentry->name, parent); - pentry++; - } -} - -static int i2o_proc_add_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *root ) +/** + * i2o_proc_subdir_remove - Remove child entries from a proc entry + * @dir: proc dir entry from which the childs should be removed + * + * Iterate over each i2o proc entry under dir and remove it. If the child + * also has entries, remove them too. + */ +static void i2o_proc_subdir_remove(struct proc_dir_entry *dir) { - struct proc_dir_entry *dir, *dir1; - struct i2o_device *dev; - char buff[10]; - - sprintf(buff, "iop%d", pctrl->unit); - - dir = proc_mkdir(buff, root); - if(!dir) - return -1; - - pctrl->proc_entry = dir; - - i2o_proc_create_entries(pctrl, generic_iop_entries, dir); - - for(dev = pctrl->devices; dev; dev = dev->next) - { - sprintf(buff, "%0#5x", dev->lct_data.tid); - - dir1 = proc_mkdir(buff, dir); - dev->proc_entry = dir1; - - if(!dir1) - printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n"); - - i2o_proc_add_device(dev, dir1); + struct proc_dir_entry *pe, *tmp; + pe = dir->subdir; + while (pe) { + tmp = pe->next; + i2o_proc_subdir_remove(pe); + remove_proc_entry(pe->name, dir); + pe = tmp; } +}; - return 0; -} - -void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d) +/** + * i2o_proc_device_add - Add an I2O device to the proc dir + * @dir: proc dir entry to which the device should be added + * @dev: I2O device which should be added + * + * Add an I2O device to the proc dir entry dir and create the entries for + * the device depending on the class of the I2O device. + */ +static void i2o_proc_device_add(struct proc_dir_entry *dir, + struct i2o_device *dev) { char buff[10]; + struct proc_dir_entry *devdir; + i2o_proc_entry *i2o_pe = NULL; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit); -#endif - sprintf(buff, "%0#5x", d->lct_data.tid); + sprintf(buff, "%03x", dev->lct_data.tid); - d->proc_entry = proc_mkdir(buff, c->proc_entry); + pr_debug("Adding device /proc/i2o/iop%d/%s\n", dev->iop->unit, buff); - if(!d->proc_entry) - { + devdir = proc_mkdir(buff, dir); + if (!devdir) { printk(KERN_WARNING "i2o: Could not allocate procdir!\n"); return; } - i2o_proc_add_device(d, d->proc_entry); -} + devdir->data = dev; -void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir) -{ - i2o_proc_create_entries(dev, generic_dev_entries, dir); + i2o_proc_create_entries(devdir, generic_dev_entries, dev); /* Inform core that we want updates about this device's status */ - i2o_device_notify_on(dev, &i2o_proc_handler); - switch(dev->lct_data.class_id) - { - case I2O_CLASS_SCSI_PERIPHERAL: - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - i2o_proc_create_entries(dev, rbs_dev_entries, dir); - break; - case I2O_CLASS_LAN: - i2o_proc_create_entries(dev, lan_entries, dir); - switch(dev->lct_data.sub_class) - { - case I2O_LAN_ETHERNET: - i2o_proc_create_entries(dev, lan_eth_entries, dir); - break; - case I2O_LAN_FDDI: - i2o_proc_create_entries(dev, lan_fddi_entries, dir); - break; - case I2O_LAN_TR: - i2o_proc_create_entries(dev, lan_tr_entries, dir); - break; - default: - break; - } - break; - default: - break; + switch (dev->lct_data.class_id) { + case I2O_CLASS_SCSI_PERIPHERAL: + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + i2o_pe = rbs_dev_entries; + break; + default: + break; } + if (i2o_pe) + i2o_proc_create_entries(devdir, i2o_pe, dev); } -static void i2o_proc_remove_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *parent) +/** + * i2o_proc_iop_add - Add an I2O controller to the i2o proc tree + * @dir: parent proc dir entry + * @c: I2O controller which should be added + * + * Add the entries to the parent proc dir entry. Also each device is added + * to the controllers proc dir entry. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_proc_iop_add(struct proc_dir_entry *dir, + struct i2o_controller *c) { - char buff[10]; + struct proc_dir_entry *iopdir; struct i2o_device *dev; + char buff[10]; - /* Remove unused device entries */ - for(dev=pctrl->devices; dev; dev=dev->next) - i2o_proc_remove_device(dev); + snprintf(buff, 10, "iop%d", c->unit); - if(!atomic_read(&pctrl->proc_entry->count)) - { - sprintf(buff, "iop%d", pctrl->unit); + pr_debug("Adding IOP /proc/i2o/%s\n", buff); - i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); - remove_proc_entry(buff, parent); - pctrl->proc_entry = NULL; - } -} + iopdir = proc_mkdir(buff, dir); + if (!iopdir) + return -1; -void i2o_proc_remove_device(struct i2o_device *dev) -{ - struct proc_dir_entry *de=dev->proc_entry; - char dev_id[10]; + iopdir->data = c; - sprintf(dev_id, "%0#5x", dev->lct_data.tid); + i2o_proc_create_entries(iopdir, i2o_proc_generic_iop_entries, c); - i2o_device_notify_off(dev, &i2o_proc_handler); - /* Would it be safe to remove _files_ even if they are in use? */ - if((de) && (!atomic_read(&de->count))) - { - i2o_proc_remove_entries(generic_dev_entries, de); - switch(dev->lct_data.class_id) - { - case I2O_CLASS_SCSI_PERIPHERAL: - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - i2o_proc_remove_entries(rbs_dev_entries, de); - break; - case I2O_CLASS_LAN: - { - i2o_proc_remove_entries(lan_entries, de); - switch(dev->lct_data.sub_class) - { - case I2O_LAN_ETHERNET: - i2o_proc_remove_entries(lan_eth_entries, de); - break; - case I2O_LAN_FDDI: - i2o_proc_remove_entries(lan_fddi_entries, de); - break; - case I2O_LAN_TR: - i2o_proc_remove_entries(lan_tr_entries, de); - break; - } - } - } - remove_proc_entry(dev_id, dev->controller->proc_entry); - } + list_for_each_entry(dev, &c->devices, list) + i2o_proc_device_add(iopdir, dev); + + return 0; } - -void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d) + +/** + * i2o_proc_iop_remove - Removes an I2O controller from the i2o proc tree + * @dir: parent proc dir entry + * @c: I2O controller which should be removed + * + * Iterate over each i2o proc entry and search controller c. If it is found + * remove it from the tree. + */ +static void i2o_proc_iop_remove(struct proc_dir_entry *dir, + struct i2o_controller *c) { -#ifdef DRIVERDEBUG - printk(KERN_INFO "Deleting device %d from iop%d\n", - d->lct_data.tid, c->unit); -#endif + struct proc_dir_entry *pe, *tmp; - i2o_proc_remove_device(d); + pe = dir->subdir; + while (pe) { + tmp = pe->next; + if (pe->data == c) { + i2o_proc_subdir_remove(pe); + remove_proc_entry(pe->name, dir); + } + pr_debug("Removing IOP /proc/i2o/iop%d\n", c->unit); + pe = tmp; + } } -static int create_i2o_procfs(void) +/** + * i2o_proc_fs_create - Create the i2o proc fs. + * + * Iterate over each I2O controller and create the entries for it. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_proc_fs_create(void) { - struct i2o_controller *pctrl = NULL; - int i; + struct i2o_controller *c; i2o_proc_dir_root = proc_mkdir("i2o", NULL); - if(!i2o_proc_dir_root) + if (!i2o_proc_dir_root) return -1; + i2o_proc_dir_root->owner = THIS_MODULE; - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - pctrl = i2o_find_controller(i); - if(pctrl) - { - i2o_proc_add_controller(pctrl, i2o_proc_dir_root); - i2o_unlock_controller(pctrl); - } - }; + list_for_each_entry(c, &i2o_controllers, list) + i2o_proc_iop_add(i2o_proc_dir_root, c); return 0; -} +}; -static int __exit destroy_i2o_procfs(void) +/** + * i2o_proc_fs_destroy - Cleanup the all i2o proc entries + * + * Iterate over each I2O controller and remove the entries for it. + * + * Returns 0 on success or negative error code on failure. + */ +static int __exit i2o_proc_fs_destroy(void) { - struct i2o_controller *pctrl = NULL; - int i; + struct i2o_controller *c; - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - pctrl = i2o_find_controller(i); - if(pctrl) - { - i2o_proc_remove_controller(pctrl, i2o_proc_dir_root); - i2o_unlock_controller(pctrl); - } - } + list_for_each_entry(c, &i2o_controllers, list) + i2o_proc_iop_remove(i2o_proc_dir_root, c); - if(!atomic_read(&i2o_proc_dir_root->count)) - remove_proc_entry("i2o", NULL); - else - return -1; + remove_proc_entry("i2o", NULL); return 0; -} +}; -int __init i2o_proc_init(void) +/** + * i2o_proc_init - Init function for procfs + * + * Registers Proc OSM and creates procfs entries. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_proc_init(void) { - if (i2o_install_handler(&i2o_proc_handler) < 0) - { - printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n"); - return 0; - } + int rc; - if(create_i2o_procfs()) - return -EBUSY; + rc = i2o_driver_register(&i2o_proc_driver); + if (rc) + return rc; + + rc = i2o_proc_fs_create(); + if (rc) { + i2o_driver_unregister(&i2o_proc_driver); + return rc; + } return 0; -} +}; + +/** + * i2o_proc_exit - Exit function for procfs + * + * Unregisters Proc OSM and removes procfs entries. + */ +static void __exit i2o_proc_exit(void) +{ + i2o_driver_unregister(&i2o_proc_driver); + i2o_proc_fs_destroy(); +}; MODULE_AUTHOR("Deepak Saxena"); MODULE_DESCRIPTION("I2O procfs Handler"); MODULE_LICENSE("GPL"); -static void __exit i2o_proc_exit(void) -{ - destroy_i2o_procfs(); - i2o_remove_handler(&i2o_proc_handler); -} - -#ifdef MODULE module_init(i2o_proc_init); -#endif module_exit(i2o_proc_exit); - diff -Nru a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c --- a/drivers/message/i2o/i2o_scsi.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/message/i2o/i2o_scsi.c 2004-10-18 14:56:49 -07:00 @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any @@ -19,13 +19,13 @@ * * o Each (bus,lun) is a logical device in I2O. We keep a map * table. We spoof failed selection for unmapped units - * o Request sense buffers can come back for free. + * o Request sense buffers can come back for free. * o Scatter gather is a bit dynamic. We have to investigate at * setup time. * o Some of our resources are dynamically shared. The i2o core * needs a message reservation protocol to avoid swap v net * deadlocking. We need to back off queue requests. - * + * * In general the firmware wants to help. Where its help isn't performance * useful we just ignore the aid. Its not worth the code in truth. * @@ -40,7 +40,6 @@ * Fix the resource management problems. */ - #include #include #include @@ -53,79 +52,229 @@ #include #include #include +#include +#include + #include #include #include #include -#include -#include #include -#include -#include #include - +#include +#include #define VERSION_STRING "Version 0.1.2" -//#define DRIVERDEBUG +static struct i2o_driver i2o_scsi_driver; -#ifdef DRIVERDEBUG -#define dprintk(s, args...) printk(s, ## args) -#else -#define dprintk(s, args...) -#endif +static int i2o_scsi_max_id = 16; +static int i2o_scsi_max_lun = 8; + +struct i2o_scsi_host { + struct Scsi_Host *scsi_host; /* pointer to the SCSI host */ + struct i2o_controller *iop; /* pointer to the I2O controller */ + struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */ +}; + +static struct scsi_host_template i2o_scsi_host_template; #define I2O_SCSI_CAN_QUEUE 4 -#define MAXHOSTS 32 -struct i2o_scsi_host -{ - struct i2o_controller *controller; - s16 task[16][8]; /* Allow 16 devices for now */ - unsigned long tagclock[16][8]; /* Tag clock for queueing */ - s16 bus_task; /* The adapter TID */ +/* SCSI OSM class handling definition */ +static struct i2o_class_id i2o_scsi_class_id[] = { + {I2O_CLASS_SCSI_PERIPHERAL}, + {I2O_CLASS_END} }; -static int scsi_context; -static int lun_done; -static int i2o_scsi_hosts; - -static u32 *retry[32]; -static struct i2o_controller *retry_ctrl[32]; -static struct timer_list retry_timer; -static spinlock_t retry_lock = SPIN_LOCK_UNLOCKED; -static int retry_ct = 0; +static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c) +{ + struct i2o_scsi_host *i2o_shost; + struct i2o_device *i2o_dev; + struct Scsi_Host *scsi_host; + int max_channel = 0; + u8 type; + int i; + size_t size; + i2o_status_block *sb; -static atomic_t queue_depth; + list_for_each_entry(i2o_dev, &c->devices, list) + if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) { + if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* SCSI bus */ + max_channel++; + } -/* - * SG Chain buffer support... + if (!max_channel) { + printk(KERN_WARNING "scsi-osm: no channels found on %s\n", + c->name); + return ERR_PTR(-EFAULT); + } + + size = max_channel * sizeof(struct i2o_device *) + + sizeof(struct i2o_scsi_host); + + scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size); + if (!scsi_host) { + printk(KERN_WARNING "scsi-osm: Could not allocate SCSI host\n"); + return ERR_PTR(-ENOMEM); + } + + scsi_host->max_channel = max_channel - 1; + scsi_host->max_id = i2o_scsi_max_id; + scsi_host->max_lun = i2o_scsi_max_lun; + scsi_host->this_id = c->unit; + + sb = c->status_block.virt; + + scsi_host->sg_tablesize = (sb->inbound_frame_size - + sizeof(struct i2o_message) / 4 - 6) / 2; + + i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata; + i2o_shost->scsi_host = scsi_host; + i2o_shost->iop = c; + + i = 0; + list_for_each_entry(i2o_dev, &c->devices, list) + if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) { + if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* only SCSI bus */ + i2o_shost->channel[i++] = i2o_dev; + + if (i >= max_channel) + break; + } + + return i2o_shost; +}; + +/** + * i2o_scsi_get_host - Get an I2O SCSI host + * @c: I2O controller to for which to get the SCSI host + * + * If the I2O controller already exists as SCSI host, the SCSI host + * is returned, otherwise the I2O controller is added to the SCSI + * core. + * + * Returns pointer to the I2O SCSI host on success or NULL on failure. */ +static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c) +{ + return c->driver_data[i2o_scsi_driver.context]; +}; -#define SG_MAX_FRAGS 64 +/** + * i2o_scsi_remove - Remove I2O device from SCSI core + * @dev: device which should be removed + * + * Removes the I2O device from the SCSI core again. + * + * Returns 0 on success. + */ +static int i2o_scsi_remove(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_controller *c = i2o_dev->iop; + struct i2o_scsi_host *i2o_shost; + struct scsi_device *scsi_dev; -/* - * FIXME: we should allocate one of these per bus we find as we - * locate them not in a lump at boot. + i2o_shost = i2o_scsi_get_host(c); + + shost_for_each_device(scsi_dev, i2o_shost->scsi_host) + if (scsi_dev->hostdata == i2o_dev) { + scsi_remove_device(scsi_dev); + scsi_device_put(scsi_dev); + break; + } + + return 0; +}; + +/** + * i2o_scsi_probe - verify if dev is a I2O SCSI device and install it + * @dev: device to verify if it is a I2O SCSI device + * + * Retrieve channel, id and lun for I2O device. If everthing goes well + * register the I2O device as SCSI device on the I2O SCSI controller. + * + * Returns 0 on success or negative error code on failure. */ - -typedef struct _chain_buf +static int i2o_scsi_probe(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_controller *c = i2o_dev->iop; + struct i2o_scsi_host *i2o_shost; + struct Scsi_Host *scsi_host; + struct i2o_device *parent; + struct scsi_device *scsi_dev; + u32 id; + u64 lun; + int channel = -1; + int i; + + i2o_shost = i2o_scsi_get_host(c); + if (!i2o_shost) + return -EFAULT; + + scsi_host = i2o_shost->scsi_host; + + if (i2o_parm_field_get(i2o_dev, 0, 3, &id, 4) < 0) + return -EFAULT; + + if (id >= scsi_host->max_id) { + printk(KERN_WARNING "scsi-osm: SCSI device id (%d) >= max_id " + "of I2O host (%d)", id, scsi_host->max_id); + return -EFAULT; + } + + if (i2o_parm_field_get(i2o_dev, 0, 4, &lun, 8) < 0) + return -EFAULT; + if (lun >= scsi_host->max_lun) { + printk(KERN_WARNING "scsi-osm: SCSI device id (%d) >= max_lun " + "of I2O host (%d)", (unsigned int)lun, + scsi_host->max_lun); + return -EFAULT; + } + + parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid); + if (!parent) { + printk(KERN_WARNING "scsi-osm: can not find parent of device " + "%03x\n", i2o_dev->lct_data.tid); + return -EFAULT; + } + + for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++) + if (i2o_shost->channel[i] == parent) + channel = i; + + if (channel == -1) { + printk(KERN_WARNING "scsi-osm: can not find channel of device " + "%03x\n", i2o_dev->lct_data.tid); + return -EFAULT; + } + + scsi_dev = + __scsi_add_device(i2o_shost->scsi_host, channel, id, lun, i2o_dev); + + if (!scsi_dev) { + printk(KERN_WARNING "scsi-osm: can not add SCSI device " + "%03x\n", i2o_dev->lct_data.tid); + return -EFAULT; + } + + pr_debug("Added new SCSI device %03x (cannel: %d, id: %d, lun: %d)\n", + i2o_dev->lct_data.tid, channel, id, (unsigned int)lun); + + return 0; +}; + +static const char *i2o_scsi_info(struct Scsi_Host *SChost) { - u32 sg_flags_cnt[SG_MAX_FRAGS]; - u32 sg_buf[SG_MAX_FRAGS]; -} chain_buf; - -#define SG_CHAIN_BUF_SZ sizeof(chain_buf) - -#define SG_MAX_BUFS (i2o_num_controllers * I2O_SCSI_CAN_QUEUE) -#define SG_CHAIN_POOL_SZ (SG_MAX_BUFS * SG_CHAIN_BUF_SZ) - -static int max_sg_len = 0; -static chain_buf *sg_chain_pool = NULL; -static int sg_chain_tag = 0; -static int sg_max_frags = SG_MAX_FRAGS; + struct i2o_scsi_host *hostdata; + hostdata = (struct i2o_scsi_host *)SChost->hostdata; + return hostdata->iop->name; +} +#if 0 /** * i2o_retry_run - retry on timeout * @f: unused @@ -136,16 +285,16 @@ * and its default handler should be this in the core, and this * call a 2nd "I give up" handler in the OSM ? */ - + static void i2o_retry_run(unsigned long f) { int i; unsigned long flags; - + spin_lock_irqsave(&retry_lock, flags); - for(i=0;i 0 + * on success and if the reply should be flushed. Returns negative error + * code on failure and if the reply should be flushed. */ - -static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +static int i2o_scsi_reply(struct i2o_controller *c, u32 m, + struct i2o_message *msg) { - struct scsi_cmnd *current_command; - spinlock_t *lock; - u32 *m = (u32 *)msg; - u8 as,ds,st; - unsigned long flags; + struct scsi_cmnd *cmd; + struct device *dev; + u8 as, ds, st; + + cmd = i2o_cntxt_list_get(c, readl(&msg->u.s.tcntxt)); + + if (msg->u.head[0] & (1 << 13)) { + struct i2o_message *pmsg; /* preserved message */ + u32 pm; + + pm = readl(&msg->body[3]); + + pmsg = c->in_queue.virt + pm; - if(m[0] & (1<<13)) - { printk("IOP fail.\n"); printk("From %d To %d Cmd %d.\n", - (m[1]>>12)&0xFFF, - m[1]&0xFFF, - m[1]>>24); - printk("Failure Code %d.\n", m[4]>>24); - if(m[4]&(1<<16)) + (msg->u.head[1] >> 12) & 0xFFF, + msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24); + printk("Failure Code %d.\n", msg->body[0] >> 24); + if (msg->body[0] & (1 << 16)) printk("Format error.\n"); - if(m[4]&(1<<17)) + if (msg->body[0] & (1 << 17)) printk("Path error.\n"); - if(m[4]&(1<<18)) + if (msg->body[0] & (1 << 18)) printk("Path State.\n"); - if(m[4]&(1<<18)) + if (msg->body[0] & (1 << 18)) printk("Congestion.\n"); - - m=(u32 *)bus_to_virt(m[7]); - printk("Failing message is %p.\n", m); - - /* This isnt a fast path .. */ - spin_lock_irqsave(&retry_lock, flags); - - if((m[4]&(1<<18)) && retry_ct < 32) - { - retry_ctrl[retry_ct]=c; - retry[retry_ct]=m; - if(!retry_ct++) - { - retry_timer.expires=jiffies+1; - add_timer(&retry_timer); - } - spin_unlock_irqrestore(&retry_lock, flags); - } - else - { - spin_unlock_irqrestore(&retry_lock, flags); - /* Create a scsi error for this */ - current_command = (struct scsi_cmnd *)i2o_context_list_get(m[3], c); - if(!current_command) - return; - - lock = current_command->device->host->host_lock; - printk("Aborted %ld\n", current_command->serial_number); - - spin_lock_irqsave(lock, flags); - current_command->result = DID_ERROR << 16; - current_command->scsi_done(current_command); - spin_unlock_irqrestore(lock, flags); - - /* Now flush the message by making it a NOP */ - m[0]&=0x00FFFFFF; - m[0]|=(I2O_CMD_UTIL_NOP)<<24; - i2o_post_message(c,virt_to_bus(m)); - } - return; + + printk("Failing message is %p.\n", pmsg); + + cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt)); + if (!cmd) + return 1; + + printk("Aborted %ld\n", cmd->serial_number); + cmd->result = DID_ERROR << 16; + cmd->scsi_done(cmd); + + /* Now flush the message by making it a NOP */ + i2o_msg_nop(c, pm); + + return 1; } - - prefetchw(&queue_depth); - - + /* - * Low byte is device status, next is adapter status, - * (then one byte reserved), then request status. + * Low byte is device status, next is adapter status, + * (then one byte reserved), then request status. */ - ds=(u8)le32_to_cpu(m[4]); - as=(u8)le32_to_cpu(m[4]>>8); - st=(u8)le32_to_cpu(m[4]>>24); - - dprintk(KERN_INFO "i2o got a scsi reply %08X: ", m[0]); - dprintk(KERN_INFO "m[2]=%08X: ", m[2]); - dprintk(KERN_INFO "m[4]=%08X\n", m[4]); - - if(m[2]&0x80000000) - { - if(m[2]&0x40000000) - { - dprintk(KERN_INFO "Event.\n"); - lun_done=1; - return; - } - printk(KERN_INFO "i2o_scsi: bus reset completed.\n"); - return; - } + ds = (u8) readl(&msg->body[0]); + as = (u8) (readl(&msg->body[0]) >> 8); + st = (u8) (readl(&msg->body[0]) >> 24); - current_command = (struct scsi_cmnd *)i2o_context_list_get(m[3], c); - /* - * Is this a control request coming back - eg an abort ? + * Is this a control request coming back - eg an abort ? */ - - atomic_dec(&queue_depth); - if(current_command==NULL) - { - if(st) - dprintk(KERN_WARNING "SCSI abort: %08X", m[4]); - dprintk(KERN_INFO "SCSI abort completed.\n"); - return; + if (!cmd) { + if (st) + printk(KERN_WARNING "SCSI abort: %08X", + readl(&msg->body[0])); + printk(KERN_INFO "SCSI abort completed.\n"); + return -EFAULT; } - - dprintk(KERN_INFO "Completed %ld\n", current_command->serial_number); - - if(st == 0x06) - { - if(le32_to_cpu(m[5]) < current_command->underflow) - { - int i; - printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n", - le32_to_cpu(m[5]), current_command->underflow); - printk("Cmd: "); - for(i=0;i<15;i++) - printk("%02X ", current_command->cmnd[i]); - printk(".\n"); - } - else st=0; - } - - if(st) - { - /* An error has occurred */ - dprintk(KERN_WARNING "SCSI error %08X", m[4]); - - if (as == 0x0E) - /* SCSI Reset */ - current_command->result = DID_RESET << 16; - else if (as == 0x0F) - current_command->result = DID_PARITY << 16; - else - current_command->result = DID_ERROR << 16; - } - else - /* - * It worked maybe ? - */ - current_command->result = DID_OK << 16 | ds; - - if (current_command->use_sg) { - pci_unmap_sg(c->pdev, - (struct scatterlist *)current_command->buffer, - current_command->use_sg, - current_command->sc_data_direction); - } else if (current_command->request_bufflen) { - pci_unmap_single(c->pdev, - (dma_addr_t)((long)current_command->SCp.ptr), - current_command->request_bufflen, - current_command->sc_data_direction); - } - - lock = current_command->device->host->host_lock; - spin_lock_irqsave(lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(lock, flags); - return; -} + pr_debug("Completed %ld\n", cmd->serial_number); -struct i2o_handler i2o_scsi_handler = { - .reply = i2o_scsi_reply, - .name = "I2O SCSI OSM", - .class = I2O_CLASS_SCSI_PERIPHERAL, -}; + if (st) { + u32 count, error; + /* An error has occurred */ -/** - * i2o_find_lun - report the lun of an i2o device - * @c: i2o controller owning the device - * @d: i2o disk device - * @target: filled in with target id - * @lun: filled in with target lun - * - * Query an I2O device to find out its SCSI lun and target numbering. We - * don't currently handle some of the fancy SCSI-3 stuff although our - * querying is sufficient to do so. - */ - -static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) -{ - u8 reply[8]; - - if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0) - return -1; - - *target=reply[0]; - - if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0) - return -1; + switch (st) { + case 0x06: + count = readl(&msg->body[1]); + if (count < cmd->underflow) { + int i; + printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X" + "\n", count, cmd->underflow); + printk("Cmd: "); + for (i = 0; i < 15; i++) + printk("%02X ", cmd->cmnd[i]); + printk(".\n"); + cmd->result = (DID_ERROR << 16); + } + break; - *lun=reply[1]; + default: + error = readl(&msg->body[0]); - dprintk(KERN_INFO "SCSI (%d,%d)\n", *target, *lun); - return 0; -} + printk(KERN_ERR "scsi-osm: SCSI error %08x\n", error); -/** - * i2o_scsi_init - initialize an i2o device for scsi - * @c: i2o controller owning the device - * @d: scsi controller - * @shpnt: scsi device we wish it to become - * - * Enumerate the scsi peripheral/fibre channel peripheral class - * devices that are children of the controller. From that we build - * a translation map for the command queue code. Since I2O works on - * its own tid's we effectively have to think backwards to get what - * the midlayer wants - */ - -static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) -{ - struct i2o_device *unit; - struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata; - int lun; - int target; - - h->controller=c; - h->bus_task=d->lct_data.tid; - - for(target=0;target<16;target++) - for(lun=0;lun<8;lun++) - h->task[target][lun] = -1; - - for(unit=c->devices;unit!=NULL;unit=unit->next) - { - dprintk(KERN_INFO "Class %03X, parent %d, want %d.\n", - unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid); - - /* Only look at scsi and fc devices */ - if ( (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL) - && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) - ) - continue; - - /* On our bus ? */ - dprintk(KERN_INFO "Found a disk (%d).\n", unit->lct_data.tid); - if ((unit->lct_data.parent_tid == d->lct_data.tid) - || (unit->lct_data.parent_tid == d->lct_data.parent_tid) - ) - { - u16 limit; - dprintk(KERN_INFO "Its ours.\n"); - if(i2o_find_lun(c, unit, &target, &lun)==-1) - { - printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid); - continue; + if ((error & 0xff) == 0x02 /*CHECK_CONDITION */ ) { + int i; + u32 len = sizeof(cmd->sense_buffer); + len = (len > 40) ? 40 : len; + // Copy over the sense data + memcpy(cmd->sense_buffer, (void *)&msg->body[3], + len); + for (i = 0; i <= len; i++) + printk(KERN_INFO "%02x\n", + cmd->sense_buffer[i]); + if (cmd->sense_buffer[0] == 0x70 + && cmd->sense_buffer[2] == DATA_PROTECT) { + /* This is to handle an array failed */ + cmd->result = (DID_TIME_OUT << 16); + printk(KERN_WARNING "%s: SCSI Data " + "Protect-Device (%d,%d,%d) " + "hba_status=0x%x, dev_status=" + "0x%x, cmd=0x%x\n", c->name, + (u32) cmd->device->channel, + (u32) cmd->device->id, + (u32) cmd->device->lun, + (error >> 8) & 0xff, + error & 0xff, cmd->cmnd[0]); + } else + cmd->result = (DID_ERROR << 16); + + break; } - dprintk(KERN_INFO "Found disk %d %d.\n", target, lun); - h->task[target][lun]=unit->lct_data.tid; - h->tagclock[target][lun]=jiffies; - - /* Get the max fragments/request */ - i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2); - - /* sanity */ - if ( limit == 0 ) - { - printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n"); - limit = 1; + + switch (as) { + case 0x0E: + /* SCSI Reset */ + cmd->result = DID_RESET << 16; + break; + + case 0x0F: + cmd->result = DID_PARITY << 16; + break; + + default: + cmd->result = DID_ERROR << 16; + break; } - - shpnt->sg_tablesize = limit; - dprintk(KERN_INFO "i2o_scsi: set scatter-gather to %d.\n", - shpnt->sg_tablesize); + break; } - } -} -/** - * i2o_scsi_detect - probe for I2O scsi devices - * @tpnt: scsi layer template - * - * I2O is a little odd here. The I2O core already knows what the - * devices are. It also knows them by disk and tape as well as - * by controller. We register each I2O scsi class object as a - * scsi controller and then let the enumeration fake up the rest - */ - -static int i2o_scsi_detect(struct scsi_host_template * tpnt) -{ - struct Scsi_Host *shpnt = NULL; - int i; - int count; + cmd->scsi_done(cmd); + return 1; + } - printk(KERN_INFO "i2o_scsi.c: %s\n", VERSION_STRING); + cmd->result = DID_OK << 16 | ds; - if(i2o_install_handler(&i2o_scsi_handler)<0) - { - printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n"); - return 0; - } - scsi_context = i2o_scsi_handler.context; - - if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL) - { - printk(KERN_INFO "i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); - printk(KERN_INFO "i2o_scsi: SG chaining DISABLED!\n"); - sg_max_frags = 11; - } - else - { - printk(KERN_INFO " chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); - printk(KERN_INFO " (%d byte buffers X %d can_queue X %d i2o controllers)\n", - SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers); - sg_max_frags = SG_MAX_FRAGS; // 64 - } - - init_timer(&retry_timer); - retry_timer.data = 0UL; - retry_timer.function = i2o_retry_run; - -// printk("SCSI OSM at %d.\n", scsi_context); - - for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - struct i2o_controller *c=i2o_find_controller(i); - struct i2o_device *d; - /* - * This controller doesn't exist. - */ - - if(c==NULL) - continue; - - /* - * Fixme - we need some altered device locking. This - * is racing with device addition in theory. Easy to fix. - */ - - for(d=c->devices;d!=NULL;d=d->next) - { - /* - * bus_adapter, SCSI (obsolete), or FibreChannel busses only - */ - if( (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter -// && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT - ) - continue; - - shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); - if(shpnt==NULL) - continue; - shpnt->unique_id = (u32)d; - shpnt->io_port = 0; - shpnt->n_io_port = 0; - shpnt->irq = 0; - shpnt->this_id = /* Good question */15; - i2o_scsi_init(c, d, shpnt); - count++; - } - } - i2o_scsi_hosts = count; - - if(count==0) - { - if(sg_chain_pool!=NULL) - { - kfree(sg_chain_pool); - sg_chain_pool = NULL; - } - flush_pending(); - del_timer(&retry_timer); - i2o_remove_handler(&i2o_scsi_handler); + cmd->scsi_done(cmd); + + dev = &c->pdev->dev; + if (cmd->use_sg) + dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer, + cmd->use_sg, cmd->sc_data_direction); + else if (cmd->request_bufflen) + dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr), + cmd->request_bufflen, cmd->sc_data_direction); + + return 1; +}; + +/** + * i2o_scsi_notify_controller_add - Retrieve notifications of added + * controllers + * @c: the controller which was added + * + * If a I2O controller is added, we catch the notification to add a + * corresponding Scsi_Host. + */ +void i2o_scsi_notify_controller_add(struct i2o_controller *c) +{ + struct i2o_scsi_host *i2o_shost; + int rc; + + i2o_shost = i2o_scsi_host_alloc(c); + if (IS_ERR(i2o_shost)) { + printk(KERN_ERR "scsi-osm: Could not initialize" + " SCSI host\n"); + return; } - - return count; -} -static int i2o_scsi_release(struct Scsi_Host *host) -{ - if(--i2o_scsi_hosts==0) - { - if(sg_chain_pool!=NULL) - { - kfree(sg_chain_pool); - sg_chain_pool = NULL; - } - flush_pending(); - del_timer(&retry_timer); - i2o_remove_handler(&i2o_scsi_handler); + rc = scsi_add_host(i2o_shost->scsi_host, &c->device); + if (rc) { + printk(KERN_ERR "scsi-osm: Could not add SCSI " + "host\n"); + scsi_host_put(i2o_shost->scsi_host); + return; } - scsi_unregister(host); + c->driver_data[i2o_scsi_driver.context] = i2o_shost; - return 0; -} + pr_debug("new I2O SCSI host added\n"); +}; +/** + * i2o_scsi_notify_controller_remove - Retrieve notifications of removed + * controllers + * @c: the controller which was removed + * + * If a I2O controller is removed, we catch the notification to remove the + * corresponding Scsi_Host. + */ +void i2o_scsi_notify_controller_remove(struct i2o_controller *c) +{ + struct i2o_scsi_host *i2o_shost; + i2o_shost = i2o_scsi_get_host(c); + if (!i2o_shost) + return; -static const char *i2o_scsi_info(struct Scsi_Host *SChost) -{ - struct i2o_scsi_host *hostdata; - hostdata = (struct i2o_scsi_host *)SChost->hostdata; - return(&hostdata->controller->name[0]); -} + c->driver_data[i2o_scsi_driver.context] = NULL; + + scsi_remove_host(i2o_shost->scsi_host); + scsi_host_put(i2o_shost->scsi_host); + pr_debug("I2O SCSI host removed\n"); +}; + +/* SCSI OSM driver struct */ +static struct i2o_driver i2o_scsi_driver = { + .name = "scsi-osm", + .reply = i2o_scsi_reply, + .classes = i2o_scsi_class_id, + .notify_controller_add = i2o_scsi_notify_controller_add, + .notify_controller_remove = i2o_scsi_notify_controller_remove, + .driver = { + .probe = i2o_scsi_probe, + .remove = i2o_scsi_remove, + }, +}; /** - * i2o_scsi_queuecommand - queue a SCSI command + * i2o_scsi_queuecommand - queue a SCSI command * @SCpnt: scsi command pointer * @done: callback for completion * - * Issue a scsi comamnd asynchronously. Return 0 on success or 1 if - * we hit an error (normally message queue congestion). The only + * Issue a scsi command asynchronously. Return 0 on success or 1 if + * we hit an error (normally message queue congestion). The only * minor complication here is that I2O deals with the device addressing * so we have to map the bus/dev/lun back to an I2O handle as well - * as faking absent devices ourself. + * as faking absent devices ourself. * * Locks: takes the controller lock on error path only */ - + static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, void (*done) (struct scsi_cmnd *)) { - int i; - int tid; struct i2o_controller *c; - struct scsi_cmnd *current_command; struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 *msg, *mptr; + struct i2o_device *i2o_dev; + struct device *dev; + int tid; + struct i2o_message *msg; u32 m; - u32 *lenptr; - int direction; - int scsidir; - u32 len; - u32 reqlen; - u32 tag; - unsigned long flags; - - static int max_qd = 1; - + u32 scsi_flags, sg_flags; + u32 *mptr, *lenptr; + u32 len, reqlen; + int i; + /* - * Do the incoming paperwork + * Do the incoming paperwork */ - + + i2o_dev = SCpnt->device->hostdata; host = SCpnt->device->host; - hostdata = (struct i2o_scsi_host *)host->hostdata; - - c = hostdata->controller; - prefetch(c); - prefetchw(&queue_depth); + c = i2o_dev->iop; + dev = &c->pdev->dev; SCpnt->scsi_done = done; - - if(SCpnt->device->id > 15) - { - printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->device->id); - return -1; - } - - tid = hostdata->task[SCpnt->device->id][SCpnt->device->lun]; - - dprintk(KERN_INFO "qcmd: Tid = %d\n", tid); - - current_command = SCpnt; /* set current command */ - current_command->scsi_done = done; /* set ptr to done function */ - - /* We don't have such a device. Pretend we did the command - and that selection timed out */ - - if(tid == -1) - { + + if (unlikely(!i2o_dev)) { + printk(KERN_WARNING "scsi-osm: no I2O device in request\n"); SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } - - dprintk(KERN_INFO "Real scsi messages.\n"); + + tid = i2o_dev->lct_data.tid; + + pr_debug("qcmd: Tid = %03x\n", tid); + pr_debug("Real scsi messages.\n"); /* - * Obtain an I2O message. If there are none free then - * throw it back to the scsi layer - */ - - m = le32_to_cpu(I2O_POST_READ32(c)); - if(m==0xFFFFFFFF) - return 1; + * Obtain an I2O message. If there are none free then + * throw it back to the scsi layer + */ + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return SCSI_MLQUEUE_HOST_BUSY; - msg = (u32 *)(c->msg_virt + m); - /* - * Put together a scsi execscb message + * Put together a scsi execscb message */ - + len = SCpnt->request_bufflen; - direction = 0x00000000; // SGL IN (osm<--iop) - - if (SCpnt->sc_data_direction == DMA_NONE) { - scsidir = 0x00000000; // DATA NO XFER - } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { - direction = 0x04000000; // SGL OUT (osm-->iop) - scsidir = 0x80000000; // DATA OUT (iop-->dev) - } else if(SCpnt->sc_data_direction == DMA_FROM_DEVICE) { - scsidir = 0x40000000; // DATA IN (iop<--dev) - } else { + + switch (SCpnt->sc_data_direction) { + case PCI_DMA_NONE: + scsi_flags = 0x00000000; // DATA NO XFER + sg_flags = 0x00000000; + break; + + case PCI_DMA_TODEVICE: + scsi_flags = 0x80000000; // DATA OUT (iop-->dev) + sg_flags = 0x14000000; + break; + + case PCI_DMA_FROMDEVICE: + scsi_flags = 0x40000000; // DATA IN (iop<--dev) + sg_flags = 0x10000000; + break; + + default: /* Unknown - kill the command */ SCpnt->result = DID_NO_CONNECT << 16; - - /* We must lock the request queue while completing */ - spin_lock_irqsave(host->host_lock, flags); done(SCpnt); - spin_unlock_irqrestore(host->host_lock, flags); return 0; } - - i2o_raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]); - i2o_raw_writel(scsi_context, &msg[2]); /* So the I2O layer passes to us */ - i2o_raw_writel(i2o_context_list_add(SCpnt, c), &msg[3]); /* We want the SCSI control block back */ + writel(I2O_CMD_SCSI_EXEC << 24 | HOST_TID << 12 | tid, &msg->u.head[1]); + writel(i2o_scsi_driver.context, &msg->u.s.icntxt); + + /* We want the SCSI control block back */ + writel(i2o_cntxt_list_add(c, SCpnt), &msg->u.s.tcntxt); /* LSI_920_PCI_QUIRK * - * Intermittant observations of msg frame word data corruption - * observed on msg[4] after: - * WRITE, READ-MODIFY-WRITE - * operations. 19990606 -sralston + * Intermittant observations of msg frame word data corruption + * observed on msg[4] after: + * WRITE, READ-MODIFY-WRITE + * operations. 19990606 -sralston * - * (Hence we build this word via tag. Its good practice anyway - * we don't want fetches over PCI needlessly) + * (Hence we build this word via tag. Its good practice anyway + * we don't want fetches over PCI needlessly) */ - tag=0; - + /* Attach tags to the devices */ /* - * Attach tags to the devices - */ - if(SCpnt->device->tagged_supported) - { - /* - * Some drives are too stupid to handle fairness issues - * with tagged queueing. We throw in the odd ordered - * tag to stop them starving themselves. - */ - if((jiffies - hostdata->tagclock[SCpnt->device->id][SCpnt->device->lun]) > (5*HZ)) - { - tag=0x01800000; /* ORDERED! */ - hostdata->tagclock[SCpnt->device->id][SCpnt->device->lun]=jiffies; - } - else - { - /* Hmmm... I always see value of 0 here, - * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston - */ - if(SCpnt->tag == HEAD_OF_QUEUE_TAG) - tag=0x01000000; - else if(SCpnt->tag == ORDERED_QUEUE_TAG) - tag=0x01800000; - } - } + if(SCpnt->device->tagged_supported) { + if(SCpnt->tag == HEAD_OF_QUEUE_TAG) + scsi_flags |= 0x01000000; + else if(SCpnt->tag == ORDERED_QUEUE_TAG) + scsi_flags |= 0x01800000; + } + */ /* Direction, disconnect ok, tag, CDBLen */ - i2o_raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]); + writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, &msg->body[0]); - mptr=msg+5; + mptr = &msg->body[1]; - /* - * Write SCSI command into the message - always 16 byte block - */ - + /* Write SCSI command into the message - always 16 byte block */ memcpy_toio(mptr, SCpnt->cmnd, 16); - mptr+=4; - lenptr=mptr++; /* Remember me - fill in when we know */ - + mptr += 4; + lenptr = mptr++; /* Remember me - fill in when we know */ + reqlen = 12; // SINGLE SGE - - /* - * Now fill in the SGList and command - * - * FIXME: we need to set the sglist limits according to the - * message size of the I2O controller. We might only have room - * for 6 or so worst case - */ - - if(SCpnt->use_sg) - { - struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; + + /* Now fill in the SGList and command */ + if (SCpnt->use_sg) { + struct scatterlist *sg; int sg_count; - int chain = 0; - + + sg = SCpnt->request_buffer; len = 0; - sg_count = pci_map_sg(c->pdev, sg, SCpnt->use_sg, - SCpnt->sc_data_direction); + sg_count = dma_map_sg(dev, sg, SCpnt->use_sg, + SCpnt->sc_data_direction); - /* FIXME: handle fail */ - if(!sg_count) - BUG(); - - if((sg_max_frags > 11) && (SCpnt->use_sg > 11)) - { - chain = 1; - /* - * Need to chain! - */ - i2o_raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++); - i2o_raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr); - mptr = (u32*)(sg_chain_pool + sg_chain_tag); - if (SCpnt->use_sg > max_sg_len) - { - max_sg_len = SCpnt->use_sg; - printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n", - SCpnt, SCpnt->use_sg, sg_chain_tag); - } - if ( ++sg_chain_tag == SG_MAX_BUFS ) - sg_chain_tag = 0; - for(i = 0 ; i < SCpnt->use_sg; i++) - { - *mptr++=cpu_to_le32(direction|0x10000000|sg_dma_len(sg)); - len+=sg_dma_len(sg); - *mptr++=cpu_to_le32(sg_dma_address(sg)); - sg++; - } - mptr[-2]=cpu_to_le32(direction|0xD0000000|sg_dma_len(sg-1)); - } - else - { - for(i = 0 ; i < SCpnt->use_sg; i++) - { - i2o_raw_writel(direction|0x10000000|sg_dma_len(sg), mptr++); - len+=sg->length; - i2o_raw_writel(sg_dma_address(sg), mptr++); - sg++; - } + if (unlikely(sg_count <= 0)) + return -ENOMEM; - /* Make this an end of list. Again evade the 920 bug and - unwanted PCI read traffic */ - - i2o_raw_writel(direction|0xD0000000|sg_dma_len(sg-1), &mptr[-2]); - } - - if(!chain) - reqlen = mptr - msg; - - i2o_raw_writel(len, lenptr); - - if(len != SCpnt->underflow) - printk("Cmd len %08X Cmd underflow %08X\n", - len, SCpnt->underflow); - } - else - { - dprintk(KERN_INFO "non sg for %p, %d\n", SCpnt->request_buffer, - SCpnt->request_bufflen); - i2o_raw_writel(len = SCpnt->request_bufflen, lenptr); - if(len == 0) - { - reqlen = 9; + for (i = SCpnt->use_sg; i > 0; i--) { + if (i == 1) + sg_flags |= 0xC0000000; + writel(sg_flags | sg_dma_len(sg), mptr++); + writel(sg_dma_address(sg), mptr++); + len += sg_dma_len(sg); + sg++; } - else - { + + reqlen = mptr - &msg->u.head[0]; + writel(len, lenptr); + } else { + len = SCpnt->request_bufflen; + + writel(len, lenptr); + + if (len > 0) { dma_addr_t dma_addr; - dma_addr = pci_map_single(c->pdev, - SCpnt->request_buffer, - SCpnt->request_bufflen, - SCpnt->sc_data_direction); - if(dma_addr == 0) - BUG(); /* How to handle ?? */ - SCpnt->SCp.ptr = (char *)(unsigned long) dma_addr; - i2o_raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++); - i2o_raw_writel(dma_addr, mptr++); - } + + dma_addr = dma_map_single(dev, SCpnt->request_buffer, + SCpnt->request_bufflen, + SCpnt->sc_data_direction); + if (!dma_addr) + return -ENOMEM; + + SCpnt->SCp.ptr = (void *)(unsigned long)dma_addr; + sg_flags |= 0xC0000000; + writel(sg_flags | SCpnt->request_bufflen, mptr++); + writel(dma_addr, mptr++); + } else + reqlen = 9; } - - /* - * Stick the headers on - */ - i2o_raw_writel(reqlen<<16 | SGL_OFFSET_10, msg); - + /* Stick the headers on */ + writel(reqlen << 16 | SGL_OFFSET_10, &msg->u.head[0]); + /* Queue the message */ - i2o_post_message(c,m); - - atomic_inc(&queue_depth); - - if(atomic_read(&queue_depth)> max_qd) - { - max_qd=atomic_read(&queue_depth); - printk("Queue depth now %d.\n", max_qd); - } - - mb(); - dprintk(KERN_INFO "Issued %ld\n", current_command->serial_number); - + i2o_msg_post(c, m); + + pr_debug("Issued %ld\n", SCpnt->serial_number); + return 0; -} +}; /** - * i2o_scsi_abort - abort a running command + * i2o_scsi_abort - abort a running command * @SCpnt: command to abort * * Ask the I2O controller to abort a command. This is an asynchrnous - * process and our callback handler will see the command complete - * with an aborted message if it succeeds. + * process and our callback handler will see the command complete with an + * aborted message if it succeeds. * - * Locks: no locks are held or needed + * Returns 0 if the command is successfully aborted or negative error code + * on failure. */ - -static int i2o_scsi_abort(struct scsi_cmnd * SCpnt) +int i2o_scsi_abort(struct scsi_cmnd *SCpnt) { + struct i2o_device *i2o_dev; struct i2o_controller *c; - struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 msg[5]; + struct i2o_message *msg; + u32 m; int tid; int status = FAILED; - - printk(KERN_WARNING "i2o_scsi: Aborting command block.\n"); - - host = SCpnt->device->host; - hostdata = (struct i2o_scsi_host *)host->hostdata; - tid = hostdata->task[SCpnt->device->id][SCpnt->device->lun]; - if(tid==-1) - { - printk(KERN_ERR "i2o_scsi: Impossible command to abort!\n"); - return status; - } - c = hostdata->controller; - - spin_unlock_irq(host->host_lock); - - msg[0] = FIVE_WORD_MSG_SIZE; - msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid; - msg[2] = scsi_context; - msg[3] = 0; - msg[4] = i2o_context_list_remove(SCpnt, c); - if(i2o_post_wait(c, msg, sizeof(msg), 240)) - status = SUCCESS; - - spin_lock_irq(host->host_lock); - return status; -} - -/** - * i2o_scsi_bus_reset - Issue a SCSI reset - * @SCpnt: the command that caused the reset - * - * Perform a SCSI bus reset operation. In I2O this is just a message - * we pass. I2O can do clever multi-initiator and shared reset stuff - * but we don't support this. - * - * Locks: called with no lock held, requires no locks. - */ - -static int i2o_scsi_bus_reset(struct scsi_cmnd * SCpnt) -{ - int tid; - struct i2o_controller *c; - struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 m; - void *msg; - unsigned long timeout; - - - /* - * Find the TID for the bus - */ - - - host = SCpnt->device->host; - spin_unlock_irq(host->host_lock); - - printk(KERN_WARNING "i2o_scsi: Attempting to reset the bus.\n"); - - hostdata = (struct i2o_scsi_host *)host->hostdata; - tid = hostdata->bus_task; - c = hostdata->controller; + printk(KERN_WARNING "i2o_scsi: Aborting command block.\n"); - /* - * Now send a SCSI reset request. Any remaining commands - * will be aborted by the IOP. We need to catch the reply - * possibly ? - */ + i2o_dev = SCpnt->device->hostdata; + c = i2o_dev->iop; + tid = i2o_dev->lct_data.tid; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return SCSI_MLQUEUE_HOST_BUSY; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid, + &msg->u.head[1]); + writel(i2o_cntxt_list_get_ptr(c, SCpnt), &msg->body[0]); - timeout = jiffies+2*HZ; - do - { - m = le32_to_cpu(I2O_POST_READ32(c)); - if(m != 0xFFFFFFFF) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - mb(); - } - while(time_before(jiffies, timeout)); - - - msg = c->msg_virt + m; - i2o_raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, msg); - i2o_raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, msg+4); - i2o_raw_writel(scsi_context|0x80000000, msg+8); - /* We use the top bit to split controller and unit transactions */ - /* Now store unit,tid so we can tie the completion back to a specific device */ - __raw_writel(c->unit << 16 | tid, msg+12); - wmb(); - - /* We want the command to complete after we return */ - spin_lock_irq(host->host_lock); - i2o_post_message(c,m); + if (i2o_msg_post_wait(c, m, I2O_TIMEOUT_SCSI_SCB_ABORT)) + status = SUCCESS; - /* Should we wait for the reset to complete ? */ - return SUCCESS; + return status; } /** * i2o_scsi_bios_param - Invent disk geometry - * @sdev: scsi device + * @sdev: scsi device * @dev: block layer device * @capacity: size in sectors * @ip: geometry array * - * This is anyones guess quite frankly. We use the same rules everyone + * This is anyones guess quite frankly. We use the same rules everyone * else appears to and hope. It seems to work. */ - -static int i2o_scsi_bios_param(struct scsi_device * sdev, - struct block_device *dev, sector_t capacity, int *ip) + +static int i2o_scsi_bios_param(struct scsi_device *sdev, + struct block_device *dev, sector_t capacity, + int *ip) { int size; @@ -1023,25 +819,64 @@ return 0; } -MODULE_AUTHOR("Red Hat Software"); -MODULE_LICENSE("GPL"); +static struct scsi_host_template i2o_scsi_host_template = { + .proc_name = "SCSI-OSM", + .name = "I2O SCSI Peripheral OSM", + .info = i2o_scsi_info, + .queuecommand = i2o_scsi_queuecommand, + .eh_abort_handler = i2o_scsi_abort, + .bios_param = i2o_scsi_bios_param, + .can_queue = I2O_SCSI_CAN_QUEUE, + .sg_tablesize = 8, + .cmd_per_lun = 6, + .use_clustering = ENABLE_CLUSTERING, +}; + +/* +int +i2o_scsi_queuecommand(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) +{ + printk(KERN_INFO "queuecommand\n"); + return SCSI_MLQUEUE_HOST_BUSY; +}; +*/ + +/** + * i2o_scsi_init - SCSI OSM initialization function + * + * Register SCSI OSM into I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_scsi_init(void) +{ + int rc; + printk(KERN_INFO "I2O SCSI Peripheral OSM\n"); -static struct scsi_host_template driver_template = { - .proc_name = "i2o_scsi", - .name = "I2O SCSI Layer", - .detect = i2o_scsi_detect, - .release = i2o_scsi_release, - .info = i2o_scsi_info, - .queuecommand = i2o_scsi_queuecommand, - .eh_abort_handler = i2o_scsi_abort, - .eh_bus_reset_handler = i2o_scsi_bus_reset, - .bios_param = i2o_scsi_bios_param, - .can_queue = I2O_SCSI_CAN_QUEUE, - .this_id = 15, - .sg_tablesize = 8, - .cmd_per_lun = 6, - .use_clustering = ENABLE_CLUSTERING, + /* Register SCSI OSM into I2O core */ + rc = i2o_driver_register(&i2o_scsi_driver); + if (rc) { + printk(KERN_ERR "scsi-osm: Could not register SCSI driver\n"); + return rc; + } + + return 0; }; -#include "../../scsi/scsi_module.c" +/** + * i2o_scsi_exit - SCSI OSM exit function + * + * Unregisters SCSI OSM from I2O core. + */ +static void __exit i2o_scsi_exit(void) +{ + /* Unregister I2O SCSI OSM from I2O core */ + i2o_driver_unregister(&i2o_scsi_driver); +}; + +MODULE_AUTHOR("Red Hat Software"); +MODULE_LICENSE("GPL"); + +module_init(i2o_scsi_init); +module_exit(i2o_scsi_exit); diff -Nru a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/message/i2o/iop.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,1258 @@ +/* + * Functions to handle I2O controllers and I2O message handling + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * A lot of the I2O message side code from this is taken from the + * Red Creek RCPCI45 adapter driver by Red Creek Communications + * + * Fixes/additions: + * Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen + * Deepak Saxena + * Boji T Kannanthanam + * Alan Cox : + * Ported to Linux 2.5. + * Markus Lidel : + * Minor fixes for 2.6. + */ + +#include +#include + +/* global I2O controller list */ +LIST_HEAD(i2o_controllers); + +/* + * global I2O System Table. Contains information about all the IOPs in the + * system. Used to inform IOPs about each others existence. + */ +static struct i2o_dma i2o_systab; + +/* Module internal functions from other sources */ +extern struct i2o_driver i2o_exec_driver; +extern int i2o_exec_lct_get(struct i2o_controller *); +extern void i2o_device_remove(struct i2o_device *); + +extern int __init i2o_driver_init(void); +extern void __exit i2o_driver_exit(void); +extern int __init i2o_exec_init(void); +extern void __exit i2o_exec_exit(void); +extern int __init i2o_pci_init(void); +extern void __exit i2o_pci_exit(void); +extern int i2o_device_init(void); +extern void i2o_device_exit(void); + +/** + * i2o_msg_nop - Returns a message which is not used + * @c: I2O controller from which the message was created + * @m: message which should be returned + * + * If you fetch a message via i2o_msg_get, and can't use it, you must + * return the message with this function. Otherwise the message frame + * is lost. + */ +void i2o_msg_nop(struct i2o_controller *c, u32 m) +{ + struct i2o_message *msg = c->in_queue.virt + m; + + writel(THREE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(0, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + i2o_msg_post(c, m); +}; + +/** + * i2o_msg_get_wait - obtain an I2O message from the IOP + * @c: I2O controller + * @msg: pointer to a I2O message pointer + * @wait: how long to wait until timeout + * + * This function waits up to wait seconds for a message slot to be + * available. + * + * On a success the message is returned and the pointer to the message is + * set in msg. The returned message is the physical page frame offset + * address from the read port (see the i2o spec). If no message is + * available returns I2O_QUEUE_EMPTY and msg is leaved untouched. + */ +u32 i2o_msg_get_wait(struct i2o_controller *c, struct i2o_message **msg, + int wait) +{ + unsigned long timeout = jiffies + wait * HZ; + u32 m; + + while ((m = i2o_msg_get(c, msg)) == I2O_QUEUE_EMPTY) { + if (time_after(jiffies, timeout)) { + pr_debug("%s: Timeout waiting for message frame.\n", + c->name); + return I2O_QUEUE_EMPTY; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + return m; +}; + +#if BITS_PER_LONG == 64 +/** + * i2o_cntxt_list_add - Append a pointer to context list and return a id + * @c: controller to which the context list belong + * @ptr: pointer to add to the context list + * + * Because the context field in I2O is only 32-bit large, on 64-bit the + * pointer is to large to fit in the context field. The i2o_cntxt_list + * functions therefore map pointers to context fields. + * + * Returns context id > 0 on success or 0 on failure. + */ +u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr) +{ + struct i2o_context_list_element *entry; + unsigned long flags; + + if (!ptr) + printk(KERN_ERR "NULL pointer found!\n"); + + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + printk(KERN_ERR "i2o: Could not allocate memory for context " + "list element\n"); + return 0; + } + + entry->ptr = ptr; + entry->timestamp = jiffies; + INIT_LIST_HEAD(&entry->list); + + spin_lock_irqsave(&c->context_list_lock, flags); + + if (unlikely(atomic_inc_and_test(&c->context_list_counter))) + atomic_inc(&c->context_list_counter); + + entry->context = atomic_read(&c->context_list_counter); + + list_add(&entry->list, &c->context_list); + + spin_unlock_irqrestore(&c->context_list_lock, flags); + + pr_debug("Add context to list %p -> %d\n", ptr, context); + + return entry->context; +}; + +/** + * i2o_cntxt_list_remove - Remove a pointer from the context list + * @c: controller to which the context list belong + * @ptr: pointer which should be removed from the context list + * + * Removes a previously added pointer from the context list and returns + * the matching context id. + * + * Returns context id on succes or 0 on failure. + */ +u32 i2o_cntxt_list_remove(struct i2o_controller *c, void *ptr) +{ + struct i2o_context_list_element *entry; + u32 context = 0; + unsigned long flags; + + spin_lock_irqsave(&c->context_list_lock, flags); + list_for_each_entry(entry, &c->context_list, list) + if (entry->ptr == ptr) { + list_del(&entry->list); + context = entry->context; + kfree(entry); + break; + } + spin_unlock_irqrestore(&c->context_list_lock, flags); + + if (!context) + printk(KERN_WARNING "i2o: Could not remove nonexistent ptr " + "%p\n", ptr); + + pr_debug("remove ptr from context list %d -> %p\n", context, ptr); + + return context; +}; + +/** + * i2o_cntxt_list_get - Get a pointer from the context list and remove it + * @c: controller to which the context list belong + * @context: context id to which the pointer belong + * + * Returns pointer to the matching context id on success or NULL on + * failure. + */ +void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context) +{ + struct i2o_context_list_element *entry; + unsigned long flags; + void *ptr = NULL; + + spin_lock_irqsave(&c->context_list_lock, flags); + list_for_each_entry(entry, &c->context_list, list) + if (entry->context == context) { + list_del(&entry->list); + ptr = entry->ptr; + kfree(entry); + break; + } + spin_unlock_irqrestore(&c->context_list_lock, flags); + + if (!ptr) + printk(KERN_WARNING "i2o: context id %d not found\n", context); + + pr_debug("get ptr from context list %d -> %p\n", context, ptr); + + return ptr; +}; + +/** + * i2o_cntxt_list_get_ptr - Get a context id from the context list + * @c: controller to which the context list belong + * @ptr: pointer to which the context id should be fetched + * + * Returns context id which matches to the pointer on succes or 0 on + * failure. + */ +u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr) +{ + struct i2o_context_list_element *entry; + u32 context = 0; + unsigned long flags; + + spin_lock_irqsave(&c->context_list_lock, flags); + list_for_each_entry(entry, &c->context_list, list) + if (entry->ptr == ptr) { + context = entry->context; + break; + } + spin_unlock_irqrestore(&c->context_list_lock, flags); + + if (!context) + printk(KERN_WARNING "i2o: Could not find nonexistent ptr " + "%p\n", ptr); + + pr_debug("get context id from context list %p -> %d\n", ptr, context); + + return context; +}; +#endif + +/** + * i2o_iop_find - Find an I2O controller by id + * @unit: unit number of the I2O controller to search for + * + * Lookup the I2O controller on the controller list. + * + * Returns pointer to the I2O controller on success or NULL if not found. + */ +struct i2o_controller *i2o_find_iop(int unit) +{ + struct i2o_controller *c; + + list_for_each_entry(c, &i2o_controllers, list) { + if (c->unit == unit) + return c; + } + + return NULL; +}; + +/** + * i2o_iop_find_device - Find a I2O device on an I2O controller + * @c: I2O controller where the I2O device hangs on + * @tid: TID of the I2O device to search for + * + * Searches the devices of the I2O controller for a device with TID tid and + * returns it. + * + * Returns a pointer to the I2O device if found, otherwise NULL. + */ +struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid) +{ + struct i2o_device *dev; + + list_for_each_entry(dev, &c->devices, list) + if (dev->lct_data.tid == tid) + return dev; + + return NULL; +}; + +/** + * i2o_quiesce_controller - quiesce controller + * @c: controller + * + * Quiesce an IOP. Causes IOP to make external operation quiescent + * (i2o 'READY' state). Internal operation of the IOP continues normally. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_quiesce(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + i2o_status_block *sb = c->status_block.virt; + int rc; + + i2o_status_get(c); + + /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ + if ((sb->iop_state != ADAPTER_STATE_READY) && + (sb->iop_state != ADAPTER_STATE_OPERATIONAL)) + return 0; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SYS_QUIESCE << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + /* Long timeout needed for quiesce if lots of devices */ + if ((rc = i2o_msg_post_wait(c, m, 240))) + printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: Quiesced.\n", c->name); + + i2o_status_get(c); // Entered READY state + + return rc; +}; + +/** + * i2o_iop_enable - move controller from ready to OPERATIONAL + * @c: I2O controller + * + * Enable IOP. This allows the IOP to resume external operations and + * reverses the effect of a quiesce. Returns zero or an error code if + * an error occurs. + */ +static int i2o_iop_enable(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + i2o_status_block *sb = c->status_block.virt; + int rc; + + i2o_status_get(c); + + /* Enable only allowed on READY state */ + if (sb->iop_state != ADAPTER_STATE_READY) + return -EINVAL; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + /* How long of a timeout do we need? */ + if ((rc = i2o_msg_post_wait(c, m, 240))) + printk(KERN_ERR "%s: Could not enable (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: Enabled.\n", c->name); + + i2o_status_get(c); // entered OPERATIONAL state + + return rc; +}; + +/** + * i2o_iop_quiesce_all - Quiesce all I2O controllers on the system + * + * Quiesce all I2O controllers which are connected to the system. + */ +static inline void i2o_iop_quiesce_all(void) +{ + struct i2o_controller *c, *tmp; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) { + if (!c->no_quiesce) + i2o_iop_quiesce(c); + } +}; + +/** + * i2o_iop_enable_all - Enables all controllers on the system + * + * Enables all I2O controllers which are connected to the system. + */ +static inline void i2o_iop_enable_all(void) +{ + struct i2o_controller *c, *tmp; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) + i2o_iop_enable(c); +}; + +/** + * i2o_clear_controller - Bring I2O controller into HOLD state + * @c: controller + * + * Clear an IOP to HOLD state, ie. terminate external operations, clear all + * input queues and prepare for a system restart. IOP's internal operation + * continues normally and the outbound queue is alive. The IOP is not + * expected to rebuild its LCT. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_clear(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + int rc; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + /* Quiesce all IOPs first */ + i2o_iop_quiesce_all(); + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + if ((rc = i2o_msg_post_wait(c, m, 30))) + printk(KERN_INFO "%s: Unable to clear (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: Cleared.\n", c->name); + + /* Enable all IOPs */ + i2o_iop_enable_all(); + + i2o_status_get(c); + + return rc; +} + +/** + * i2o_iop_reset - reset an I2O controller + * @c: controller to reset + * + * Reset the IOP into INIT state and wait until IOP gets into RESET state. + * Terminate all external operations, clear IOP's inbound and outbound + * queues, terminate all DDMs, and reload the IOP's operating environment + * and all local DDMs. The IOP rebuilds its LCT. + */ +static int i2o_iop_reset(struct i2o_controller *c) +{ + u8 *status = c->status.virt; + struct i2o_message *msg; + u32 m; + unsigned long timeout; + i2o_status_block *sb = c->status_block.virt; + int rc = 0; + + pr_debug("Resetting controller\n"); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + memset(status, 0, 4); + + /* Quiesce all IOPs first */ + i2o_iop_quiesce_all(); + + writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0, &msg->u.s.tcntxt); //FIXME: use reasonable transaction context + writel(0, &msg->body[0]); + writel(0, &msg->body[1]); + writel(i2o_ptr_low((void *)c->status.phys), &msg->body[2]); + writel(i2o_ptr_high((void *)c->status.phys), &msg->body[3]); + + i2o_msg_post(c, m); + + /* Wait for a reply */ + timeout = jiffies + I2O_TIMEOUT_RESET * HZ; + while (!*status) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "IOP reset timeout.\n"); + rc = -ETIMEDOUT; + goto exit; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + rmb(); + } + + if (*status == I2O_CMD_IN_PROGRESS) { + /* + * Once the reset is sent, the IOP goes into the INIT state + * which is indeterminate. We need to wait until the IOP + * has rebooted before we can let the system talk to + * it. We read the inbound Free_List until a message is + * available. If we can't read one in the given ammount of + * time, we assume the IOP could not reboot properly. + */ + pr_debug("%s: Reset in progress, waiting for reboot...\n", + c->name); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); + while (m == I2O_QUEUE_EMPTY) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "IOP reset timeout.\n"); + rc = -ETIMEDOUT; + goto exit; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); + } + i2o_msg_nop(c, m); + } + + /* from here all quiesce commands are safe */ + c->no_quiesce = 0; + + /* If IopReset was rejected or didn't perform reset, try IopClear */ + i2o_status_get(c); + if (*status == I2O_CMD_REJECTED || sb->iop_state != ADAPTER_STATE_RESET) { + printk(KERN_WARNING "%s: Reset rejected, trying to clear\n", + c->name); + i2o_iop_clear(c); + } else + pr_debug("%s: Reset completed.\n", c->name); + + exit: + /* Enable all IOPs */ + i2o_iop_enable_all(); + + return rc; +}; + +/** + * i2o_iop_init_outbound_queue - setup the outbound message queue + * @c: I2O controller + * + * Clear and (re)initialize IOP's outbound queue and post the message + * frames to the IOP. + * + * Returns 0 on success or a negative errno code on failure. + */ +int i2o_iop_init_outbound_queue(struct i2o_controller *c) +{ + u8 *status = c->status.virt; + u32 m; + struct i2o_message *msg; + ulong timeout; + int i; + + pr_debug("%s: Initializing Outbound Queue...\n", c->name); + + memset(status, 0, 4); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0x0106, &msg->u.s.tcntxt); /* FIXME: why 0x0106, maybe in + Spec? */ + writel(PAGE_SIZE, &msg->body[0]); + writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]); /* Outbound msg frame + size in words and Initcode */ + writel(0xd0000004, &msg->body[2]); + writel(i2o_ptr_low((void *)c->status.phys), &msg->body[3]); + writel(i2o_ptr_high((void *)c->status.phys), &msg->body[4]); + + i2o_msg_post(c, m); + + timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ; + while (*status <= I2O_CMD_IN_PROGRESS) { + if (time_after(jiffies, timeout)) { + printk(KERN_WARNING "%s: Timeout Initializing\n", + c->name); + return -ETIMEDOUT; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + rmb(); + } + + m = c->out_queue.phys; + + /* Post frames */ + for (i = 0; i < NMBR_MSG_FRAMES; i++) { + i2o_flush_reply(c, m); + m += MSG_FRAME_SIZE * 4; + } + + return 0; +} + +/** + * i2o_iop_activate - Bring controller up to HOLD + * @c: controller + * + * This function brings an I2O controller into HOLD state. The adapter + * is reset if necessary and then the queues and resource table are read. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_activate(struct i2o_controller *c) +{ + i2o_status_block *sb = c->status_block.virt; + int rc; + /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ + /* In READY state, Get status */ + + rc = i2o_status_get(c); + if (rc) { + printk(KERN_INFO "Unable to obtain status of %s, " + "attempting a reset.\n", c->name); + if (i2o_iop_reset(c)) + return rc; + } + + if (sb->i2o_version > I2OVER15) { + printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O " + "Specification.\n", c->name); + return -ENODEV; + } + + switch (sb->iop_state) { + case ADAPTER_STATE_FAULTED: + printk(KERN_CRIT "%s: hardware fault\n", c->name); + return -ENODEV; + + case ADAPTER_STATE_READY: + case ADAPTER_STATE_OPERATIONAL: + case ADAPTER_STATE_HOLD: + case ADAPTER_STATE_FAILED: + pr_debug("already running, trying to reset...\n"); + if (i2o_iop_reset(c)) + return -ENODEV; + } + + rc = i2o_iop_init_outbound_queue(c); + if (rc) + return rc; + + /* In HOLD state */ + + rc = i2o_hrt_get(c); + if (rc) + return rc; + + return 0; +}; + +/** + * i2o_iop_systab_set - Set the I2O System Table of the specified IOP + * @c: I2O controller to which the system table should be send + * + * Before the systab could be set i2o_systab_build() must be called. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_systab_set(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + i2o_status_block *sb = c->status_block.virt; + struct device *dev = &c->pdev->dev; + struct resource *root; + int rc; + + if (sb->current_mem_size < sb->desired_mem_size) { + struct resource *res = &c->mem_resource; + res->name = c->pdev->bus->name; + res->flags = IORESOURCE_MEM; + res->start = 0; + res->end = 0; + printk("%s: requires private memory resources.\n", c->name); + root = pci_find_parent_resource(c->pdev, res); + if (root == NULL) + printk("Can't find parent resource!\n"); + if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ + NULL, NULL) >= 0) { + c->mem_alloc = 1; + sb->current_mem_size = 1 + res->end - res->start; + sb->current_mem_base = res->start; + printk(KERN_INFO + "%s: allocated %ld bytes of PCI memory at 0x%08lX.\n", + c->name, 1 + res->end - res->start, res->start); + } + } + + if (sb->current_io_size < sb->desired_io_size) { + struct resource *res = &c->io_resource; + res->name = c->pdev->bus->name; + res->flags = IORESOURCE_IO; + res->start = 0; + res->end = 0; + printk("%s: requires private memory resources.\n", c->name); + root = pci_find_parent_resource(c->pdev, res); + if (root == NULL) + printk("Can't find parent resource!\n"); + if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ + NULL, NULL) >= 0) { + c->io_alloc = 1; + sb->current_io_size = 1 + res->end - res->start; + sb->current_mem_base = res->start; + printk(KERN_INFO + "%s: allocated %ld bytes of PCI I/O at 0x%08lX.\n", + c->name, 1 + res->end - res->start, res->start); + } + } + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len, + PCI_DMA_TODEVICE); + if (!i2o_systab.phys) { + i2o_msg_nop(c, m); + return -ENOMEM; + } + + writel(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + /* + * Provide three SGL-elements: + * System table (SysTab), Private memory space declaration and + * Private i/o space declaration + * + * FIXME: is this still true? + * Nasty one here. We can't use dma_alloc_coherent to send the + * same table to everyone. We have to go remap it for them all + */ + + writel(c->unit + 2, &msg->body[0]); + writel(0, &msg->body[1]); + writel(0x54000000 | i2o_systab.phys, &msg->body[2]); + writel(i2o_systab.phys, &msg->body[3]); + writel(0x54000000 | sb->current_mem_size, &msg->body[4]); + writel(sb->current_mem_base, &msg->body[5]); + writel(0xd4000000 | sb->current_io_size, &msg->body[6]); + writel(sb->current_io_base, &msg->body[6]); + + rc = i2o_msg_post_wait(c, m, 120); + + dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len, + PCI_DMA_TODEVICE); + + if (rc < 0) + printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: SysTab set.\n", c->name); + + i2o_status_get(c); // Entered READY state + + return rc; +} + +/** + * i2o_iop_online - Bring a controller online into OPERATIONAL state. + * @c: I2O controller + * + * Send the system table and enable the I2O controller. + * + * Returns 0 on success or negativer error code on failure. + */ +static int i2o_iop_online(struct i2o_controller *c) +{ + int rc; + + rc = i2o_iop_systab_set(c); + if (rc) + return rc; + + /* In READY state */ + pr_debug("%s: Attempting to enable...\n", c->name); + rc = i2o_iop_enable(c); + if (rc) + return rc; + + return 0; +}; + +/** + * i2o_iop_remove - Remove the I2O controller from the I2O core + * @c: I2O controller + * + * Remove the I2O controller from the I2O core. If devices are attached to + * the controller remove these also and finally reset the controller. + */ +void i2o_iop_remove(struct i2o_controller *c) +{ + struct i2o_device *dev, *tmp; + + pr_debug("Deleting controller %s\n", c->name); + + i2o_driver_notify_controller_remove_all(c); + + list_del(&c->list); + + list_for_each_entry_safe(dev, tmp, &c->devices, list) + i2o_device_remove(dev); + + /* Ask the IOP to switch to RESET state */ + i2o_iop_reset(c); +} + +/** + * i2o_systab_build - Build system table + * + * The system table contains information about all the IOPs in the system + * (duh) and is used by the Executives on the IOPs to establish peer2peer + * connections. We're not supporting peer2peer at the moment, but this + * will be needed down the road for things like lan2lan forwarding. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_systab_build(void) +{ + struct i2o_controller *c, *tmp; + int num_controllers = 0; + u32 change_ind = 0; + int count = 0; + struct i2o_sys_tbl *systab = i2o_systab.virt; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) + num_controllers++; + + if (systab) { + change_ind = systab->change_ind; + kfree(i2o_systab.virt); + } + + /* Header + IOPs */ + i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers * + sizeof(struct i2o_sys_tbl_entry); + + systab = i2o_systab.virt = kmalloc(i2o_systab.len, GFP_KERNEL); + if (!systab) { + printk(KERN_ERR "i2o: unable to allocate memory for System " + "Table\n"); + return -ENOMEM; + } + memset(systab, 0, i2o_systab.len); + + systab->version = I2OVERSION; + systab->change_ind = change_ind + 1; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) { + i2o_status_block *sb; + + if (count >= num_controllers) { + printk(KERN_ERR "i2o: controller added while building " + "system table\n"); + break; + } + + sb = c->status_block.virt; + + /* + * Get updated IOP state so we have the latest information + * + * We should delete the controller at this point if it + * doesn't respond since if it's not on the system table + * it is techninically not part of the I2O subsystem... + */ + if (unlikely(i2o_status_get(c))) { + printk(KERN_ERR "%s: Deleting b/c could not get status" + " while attempting to build system table\n", + c->name); + i2o_iop_remove(c); + continue; // try the next one + } + + systab->iops[count].org_id = sb->org_id; + systab->iops[count].iop_id = c->unit + 2; + systab->iops[count].seg_num = 0; + systab->iops[count].i2o_version = sb->i2o_version; + systab->iops[count].iop_state = sb->iop_state; + systab->iops[count].msg_type = sb->msg_type; + systab->iops[count].frame_size = sb->inbound_frame_size; + systab->iops[count].last_changed = change_ind; + systab->iops[count].iop_capabilities = sb->iop_capabilities; + systab->iops[count].inbound_low = i2o_ptr_low(c->post_port); + systab->iops[count].inbound_high = i2o_ptr_high(c->post_port); + + count++; + } + + systab->num_entries = count; + + return 0; +}; + +/** + * i2o_parse_hrt - Parse the hardware resource table. + * @c: I2O controller + * + * We don't do anything with it except dumping it (in debug mode). + * + * Returns 0. + */ +static int i2o_parse_hrt(struct i2o_controller *c) +{ + i2o_dump_hrt(c); + return 0; +}; + +/** + * i2o_status_get - Get the status block from the I2O controller + * @c: I2O controller + * + * Issue a status query on the controller. This updates the attached + * status block. The status block could then be accessed through + * c->status_block. + * + * Returns 0 on sucess or negative error code on failure. + */ +int i2o_status_get(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + u8 *status_block; + unsigned long timeout; + + status_block = (u8 *) c->status_block.virt; + memset(status_block, 0, sizeof(i2o_status_block)); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0, &msg->u.s.tcntxt); // FIXME: use resonable transaction context + writel(0, &msg->body[0]); + writel(0, &msg->body[1]); + writel(i2o_ptr_low((void *)c->status_block.phys), &msg->body[2]); + writel(i2o_ptr_high((void *)c->status_block.phys), &msg->body[3]); + writel(sizeof(i2o_status_block), &msg->body[4]); /* always 88 bytes */ + + i2o_msg_post(c, m); + + /* Wait for a reply */ + timeout = jiffies + I2O_TIMEOUT_STATUS_GET * HZ; + while (status_block[87] != 0xFF) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "%s: Get status timeout.\n", c->name); + return -ETIMEDOUT; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + rmb(); + } + +#ifdef DEBUG + i2o_debug_state(c); +#endif + + return 0; +} + +/* + * i2o_hrt_get - Get the Hardware Resource Table from the I2O controller + * @c: I2O controller from which the HRT should be fetched + * + * The HRT contains information about possible hidden devices but is + * mostly useless to us. + * + * Returns 0 on success or negativer error code on failure. + */ +int i2o_hrt_get(struct i2o_controller *c) +{ + int rc; + int i; + i2o_hrt *hrt = c->hrt.virt; + u32 size = sizeof(i2o_hrt); + struct device *dev = &c->pdev->dev; + + for (i = 0; i < I2O_HRT_GET_TRIES; i++) { + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(SIX_WORD_MSG_SIZE | SGL_OFFSET_4, &msg->u.head[0]); + writel(I2O_CMD_HRT_GET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(0xd0000000 | c->hrt.len, &msg->body[0]); + writel(c->hrt.phys, &msg->body[1]); + + rc = i2o_msg_post_wait_mem(c, m, 20, &c->hrt); + + if (rc < 0) { + printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", + c->name, -rc); + return rc; + } + + size = hrt->num_entries * hrt->entry_len << 2; + if (size > c->hrt.len) { + if (i2o_dma_realloc(dev, &c->hrt, size, GFP_KERNEL)) + return -ENOMEM; + else + hrt = c->hrt.virt; + } else + return i2o_parse_hrt(c); + } + + printk(KERN_ERR "%s: Unable to get HRT after %d tries, giving up\n", + c->name, I2O_HRT_GET_TRIES); + + return -EBUSY; +} + +/** + * i2o_iop_alloc - Allocate and initialize a i2o_controller struct + * + * Allocate the necessary memory for a i2o_controller struct and + * initialize the lists. + * + * Returns a pointer to the I2O controller or a negative error code on + * failure. + */ +struct i2o_controller *i2o_iop_alloc(void) +{ + static int unit = 0; /* 0 and 1 are NULL IOP and Local Host */ + struct i2o_controller *c; + + c = kmalloc(sizeof(*c), GFP_KERNEL); + if (!c) { + printk(KERN_ERR "i2o: Insufficient memory to allocate the " + "controller.\n"); + return ERR_PTR(-ENOMEM); + } + memset(c, 0, sizeof(*c)); + + INIT_LIST_HEAD(&c->devices); + c->lock = SPIN_LOCK_UNLOCKED; + init_MUTEX(&c->lct_lock); + c->unit = unit++; + sprintf(c->name, "iop%d", c->unit); + +#if BITS_PER_LONG == 64 + c->context_list_lock = SPIN_LOCK_UNLOCKED; + atomic_set(&c->context_list_counter, 0); + INIT_LIST_HEAD(&c->context_list); +#endif + + return c; +}; + +/** + * i2o_iop_free - Free the i2o_controller struct + * @c: I2O controller to free + */ +void i2o_iop_free(struct i2o_controller *c) +{ + kfree(c); +}; + +/** + * i2o_iop_add - Initialize the I2O controller and add him to the I2O core + * @c: controller + * + * Initialize the I2O controller and if no error occurs add him to the I2O + * core. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_iop_add(struct i2o_controller *c) +{ + int rc; + + printk(KERN_INFO "%s: Activating I2O controller...\n", c->name); + printk(KERN_INFO "%s: This may take a few minutes if there are many " + "devices\n", c->name); + + if ((rc = i2o_iop_activate(c))) { + printk(KERN_ERR "%s: controller could not activated\n", + c->name); + i2o_iop_reset(c); + return rc; + } + + pr_debug("building sys table %s...\n", c->name); + + if ((rc = i2o_systab_build())) { + i2o_iop_reset(c); + return rc; + } + + pr_debug("online controller %s...\n", c->name); + + if ((rc = i2o_iop_online(c))) { + i2o_iop_reset(c); + return rc; + } + + pr_debug("getting LCT %s...\n", c->name); + + if ((rc = i2o_exec_lct_get(c))) { + i2o_iop_reset(c); + return rc; + } + + list_add(&c->list, &i2o_controllers); + + i2o_driver_notify_controller_add_all(c); + + printk(KERN_INFO "%s: Controller added\n", c->name); + + return 0; +}; + +/** + * i2o_event_register - Turn on/off event notification for a I2O device + * @dev: I2O device which should receive the event registration request + * @drv: driver which want to get notified + * @tcntxt: transaction context to use with this notifier + * @evt_mask: mask of events + * + * Create and posts an event registration message to the task. No reply + * is waited for, or expected. If you do not want further notifications, + * call the i2o_event_register again with a evt_mask of 0. + * + * Returns 0 on success or -ETIMEDOUT if no message could be fetched for + * sending the request. + */ +int i2o_event_register(struct i2o_device *dev, struct i2o_driver *drv, + int tcntxt, u32 evt_mask) +{ + struct i2o_controller *c = dev->iop; + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | dev->lct_data. + tid, &msg->u.head[1]); + writel(drv->context, &msg->u.s.icntxt); + writel(tcntxt, &msg->u.s.tcntxt); + writel(evt_mask, &msg->body[0]); + + i2o_msg_post(c, m); + + return 0; +}; + +/** + * i2o_iop_init - I2O main initialization function + * + * Initialize the I2O drivers (OSM) functions, register the Executive OSM, + * initialize the I2O PCI part and finally initialize I2O device stuff. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_iop_init(void) +{ + int rc = 0; + + printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); + + rc = i2o_device_init(); + if (rc) + goto exit; + + rc = i2o_driver_init(); + if (rc) + goto device_exit; + + rc = i2o_exec_init(); + if (rc) + goto driver_exit; + + rc = i2o_pci_init(); + if (rc < 0) + goto exec_exit; + + return 0; + + exec_exit: + i2o_exec_exit(); + + driver_exit: + i2o_driver_exit(); + + device_exit: + i2o_device_exit(); + + exit: + return rc; +} + +/** + * i2o_iop_exit - I2O main exit function + * + * Removes I2O controllers from PCI subsystem and shut down OSMs. + */ +static void __exit i2o_iop_exit(void) +{ + i2o_pci_exit(); + i2o_exec_exit(); + i2o_driver_exit(); + i2o_device_exit(); +}; + +module_init(i2o_iop_init); +module_exit(i2o_iop_exit); + +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Core"); +MODULE_LICENSE("GPL"); + +#if BITS_PER_LONG == 64 +EXPORT_SYMBOL(i2o_cntxt_list_add); +EXPORT_SYMBOL(i2o_cntxt_list_get); +EXPORT_SYMBOL(i2o_cntxt_list_remove); +EXPORT_SYMBOL(i2o_cntxt_list_get_ptr); +#endif +EXPORT_SYMBOL(i2o_msg_get_wait); +EXPORT_SYMBOL(i2o_msg_nop); +EXPORT_SYMBOL(i2o_find_iop); +EXPORT_SYMBOL(i2o_iop_find_device); +EXPORT_SYMBOL(i2o_event_register); +EXPORT_SYMBOL(i2o_status_get); +EXPORT_SYMBOL(i2o_hrt_get); +EXPORT_SYMBOL(i2o_controllers); diff -Nru a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/message/i2o/pci.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,528 @@ +/* + * PCI handling of I2O controller + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * A lot of the I2O message side code from this is taken from the Red + * Creek RCPCI45 adapter driver by Red Creek Communications + * + * Fixes/additions: + * Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen + * Deepak Saxena + * Boji T Kannanthanam + * Alan Cox : + * Ported to Linux 2.5. + * Markus Lidel : + * Minor fixes for 2.6. + * Markus Lidel : + * Support for sysfs included. + */ + +#include +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif // CONFIG_MTRR + +/* Module internal functions from other sources */ +extern struct i2o_controller *i2o_iop_alloc(void); +extern void i2o_iop_free(struct i2o_controller *); + +extern int i2o_iop_add(struct i2o_controller *); +extern void i2o_iop_remove(struct i2o_controller *); + +extern int i2o_driver_dispatch(struct i2o_controller *, u32, + struct i2o_message *); + +/* PCI device id table for all I2O controllers */ +static struct pci_device_id __devinitdata i2o_pci_ids[] = { + {PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)}, + {PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)}, + {0} +}; + +/** + * i2o_dma_realloc - Realloc DMA memory + * @dev: struct device pointer to the PCI device of the I2O controller + * @addr: pointer to a i2o_dma struct DMA buffer + * @len: new length of memory + * @gfp_mask: GFP mask + * + * If there was something allocated in the addr, free it first. If len > 0 + * than try to allocate it and write the addresses back to the addr + * structure. If len == 0 set the virtual address to NULL. + * + * Returns the 0 on success or negative error code on failure. + */ +int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len, + unsigned int gfp_mask) +{ + i2o_dma_free(dev, addr); + + if (len) + return i2o_dma_alloc(dev, addr, len, gfp_mask); + + return 0; +}; + +/** + * i2o_pci_free - Frees the DMA memory for the I2O controller + * @c: I2O controller to free + * + * Remove all allocated DMA memory and unmap memory IO regions. If MTRR + * is enabled, also remove it again. + */ +static void __devexit i2o_pci_free(struct i2o_controller *c) +{ + struct device *dev; + + dev = &c->pdev->dev; + + i2o_dma_free(dev, &c->out_queue); + i2o_dma_free(dev, &c->status_block); + if (c->lct) + kfree(c->lct); + i2o_dma_free(dev, &c->dlct); + i2o_dma_free(dev, &c->hrt); + i2o_dma_free(dev, &c->status); + +#ifdef CONFIG_MTRR + if (c->mtrr_reg0 >= 0) + mtrr_del(c->mtrr_reg0, 0, 0); + if (c->mtrr_reg1 >= 0) + mtrr_del(c->mtrr_reg1, 0, 0); +#endif + + if (c->raptor && c->in_queue.virt) + iounmap(c->in_queue.virt); + + if (c->base.virt) + iounmap(c->base.virt); +} + +/** + * i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller + * @c: I2O controller + * + * Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All + * IO mappings are also done here. If MTRR is enabled, also do add memory + * regions here. + * + * Returns 0 on success or negative error code on failure. + */ +static int __devinit i2o_pci_alloc(struct i2o_controller *c) +{ + struct pci_dev *pdev = c->pdev; + struct device *dev = &pdev->dev; + int i; + + for (i = 0; i < 6; i++) { + /* Skip I/O spaces */ + if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + if (!c->base.phys) { + c->base.phys = pci_resource_start(pdev, i); + c->base.len = pci_resource_len(pdev, i); + + /* + * If we know what card it is, set the size + * correctly. Code is taken from dpt_i2o.c + */ + if(pdev->device == 0xa501) { + if(pdev->subsystem_device >= 0xc032 && + pdev->subsystem_device <= 0xc03b) { + if(c->base.len > 0x400000) + c->base.len = 0x400000; + } else { + if(c->base.len > 0x100000) + c->base.len = 0x100000; + } + } + if (!c->raptor) + break; + } else { + c->in_queue.phys = pci_resource_start(pdev, i); + c->in_queue.len = pci_resource_len(pdev, i); + break; + } + } + } + + if (i == 6) { + printk(KERN_ERR "i2o: I2O controller has no memory regions" + " defined.\n"); + i2o_pci_free(c); + return -EINVAL; + } + + /* Map the I2O controller */ + if (c->raptor) { + printk(KERN_INFO "i2o: PCI I2O controller\n"); + printk(KERN_INFO " BAR0 at 0x%08lX size=%ld\n", + (unsigned long)c->base.phys, (unsigned long)c->base.len); + printk(KERN_INFO " BAR1 at 0x%08lX size=%ld\n", + (unsigned long)c->in_queue.phys, + (unsigned long)c->in_queue.len); + } else + printk(KERN_INFO "i2o: PCI I2O controller at %08lX size=%ld\n", + (unsigned long)c->base.phys, (unsigned long)c->base.len); + + c->base.virt = ioremap(c->base.phys, c->base.len); + if (!c->base.virt) { + printk(KERN_ERR "i2o: Unable to map controller.\n"); + return -ENOMEM; + } + + if (c->raptor) { + c->in_queue.virt = ioremap(c->in_queue.phys, c->in_queue.len); + if (!c->in_queue.virt) { + printk(KERN_ERR "i2o: Unable to map controller.\n"); + i2o_pci_free(c); + return -ENOMEM; + } + } else + c->in_queue = c->base; + + c->irq_mask = c->base.virt + 0x34; + c->post_port = c->base.virt + 0x40; + c->reply_port = c->base.virt + 0x44; + +#ifdef CONFIG_MTRR + /* Enable Write Combining MTRR for IOP's memory region */ + c->mtrr_reg0 = mtrr_add(c->in_queue.phys, c->in_queue.len, + MTRR_TYPE_WRCOMB, 1); + c->mtrr_reg1 = -1; + + if (c->mtrr_reg0 < 0) + printk(KERN_WARNING "i2o: could not enable write combining " + "MTRR\n"); + else + printk(KERN_INFO "i2o: using write combining MTRR\n"); + + /* + * If it is an INTEL i960 I/O processor then set the first 64K to + * Uncacheable since the region contains the messaging unit which + * shouldn't be cached. + */ + if ((pdev->vendor == PCI_VENDOR_ID_INTEL || + pdev->vendor == PCI_VENDOR_ID_DPT) && !c->raptor) { + printk(KERN_INFO "i2o: MTRR workaround for Intel i960 processor" + "\n"); + c->mtrr_reg1 = mtrr_add(c->base.phys, 0x10000, + MTRR_TYPE_UNCACHABLE, 1); + + if (c->mtrr_reg1 < 0) { + printk(KERN_WARNING "i2o_pci: Error in setting " + "MTRR_TYPE_UNCACHABLE\n"); + mtrr_del(c->mtrr_reg0, c->in_queue.phys, + c->in_queue.len); + c->mtrr_reg0 = -1; + } + } +#endif + + if (i2o_dma_alloc(dev, &c->status, 4, GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt), GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->dlct, 8192, GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block), + GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->out_queue, MSG_POOL_SIZE, GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + pci_set_drvdata(pdev, c); + + return 0; +} + +/** + * i2o_pci_interrupt - Interrupt handler for I2O controller + * @irq: interrupt line + * @dev_id: pointer to the I2O controller + * @r: pointer to registers + * + * Handle an interrupt from a PCI based I2O controller. This turns out + * to be rather simple. We keep the controller pointer in the cookie. + */ +static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) +{ + struct i2o_controller *c = dev_id; + struct device *dev = &c->pdev->dev; + struct i2o_message *m; + u32 mv; + u32 *msg; + + /* + * Old 960 steppings had a bug in the I2O unit that caused + * the queue to appear empty when it wasn't. + */ + mv = I2O_REPLY_READ32(c); + if (mv == I2O_QUEUE_EMPTY) { + mv = I2O_REPLY_READ32(c); + if (unlikely(mv == I2O_QUEUE_EMPTY)) { + return IRQ_NONE; + } else + pr_debug("960 bug detected\n"); + } + + while (mv != I2O_QUEUE_EMPTY) { + /* + * Map the message from the page frame map to kernel virtual. + * Because bus_to_virt is deprecated, we have calculate the + * location by ourself! + */ + m = (struct i2o_message *)(mv - + (unsigned long)c->out_queue.phys + + (unsigned long)c->out_queue.virt); + + msg = (u32 *) m; + + /* + * Ensure this message is seen coherently but cachably by + * the processor + */ + dma_sync_single_for_cpu(dev, c->out_queue.phys, MSG_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + + /* dispatch it */ + if (i2o_driver_dispatch(c, mv, m)) + /* flush it if result != 0 */ + i2o_flush_reply(c, mv); + + /* + * That 960 bug again... + */ + mv = I2O_REPLY_READ32(c); + if (mv == I2O_QUEUE_EMPTY) + mv = I2O_REPLY_READ32(c); + } + return IRQ_HANDLED; +} + +/** + * i2o_pci_irq_enable - Allocate interrupt for I2O controller + * + * Allocate an interrupt for the I2O controller, and activate interrupts + * on the I2O controller. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_pci_irq_enable(struct i2o_controller *c) +{ + struct pci_dev *pdev = c->pdev; + int rc; + + I2O_IRQ_WRITE32(c, 0xffffffff); + + if (pdev->irq) { + rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ, + c->name, c); + if (rc < 0) { + printk(KERN_ERR "%s: unable to allocate interrupt %d." + "\n", c->name, pdev->irq); + return rc; + } + } + + I2O_IRQ_WRITE32(c, 0x00000000); + + printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq); + + return 0; +} + +/** + * i2o_pci_irq_disable - Free interrupt for I2O controller + * @c: I2O controller + * + * Disable interrupts in I2O controller and then free interrupt. + */ +static void i2o_pci_irq_disable(struct i2o_controller *c) +{ + I2O_IRQ_WRITE32(c, 0xffffffff); + + if (c->pdev->irq > 0) + free_irq(c->pdev->irq, c); +} + +/** + * i2o_pci_probe - Probe the PCI device for an I2O controller + * @dev: PCI device to test + * @id: id which matched with the PCI device id table + * + * Probe the PCI device for any device which is a memory of the + * Intelligent, I2O class or an Adaptec Zero Channel Controller. We + * attempt to set up each such device and register it with the core. + * + * Returns 0 on success or negative error code on failure. + */ +static int __devinit i2o_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct i2o_controller *c; + int rc; + + printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); + + if ((pdev->class & 0xff) > 1) { + printk(KERN_WARNING "i2o: I2O controller found but does not " + "support I2O 1.5 (skipping).\n"); + return -ENODEV; + } + + if ((rc = pci_enable_device(pdev))) { + printk(KERN_WARNING "i2o: I2O controller found but could not be" + " enabled.\n"); + return rc; + } + + printk(KERN_INFO "i2o: I2O controller found on bus %d at %d.\n", + pdev->bus->number, pdev->devfn); + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_WARNING "i2o: I2O controller on bus %d at %d: No " + "suitable DMA available!\n", pdev->bus->number, + pdev->devfn); + rc = -ENODEV; + goto disable; + } + + pci_set_master(pdev); + + c = i2o_iop_alloc(); + if (IS_ERR(c)) { + printk(KERN_ERR "i2o: memory for I2O controller could not be " + "allocated\n"); + rc = PTR_ERR(c); + goto disable; + } + + c->pdev = pdev; + c->device = pdev->dev; + + /* Cards that fall apart if you hit them with large I/O loads... */ + if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) { + c->short_req = 1; + printk(KERN_INFO "i2o: Symbios FC920 workarounds activated.\n"); + } + + if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) { + c->promise = 1; + printk(KERN_INFO "i2o: Promise workarounds activated.\n"); + } + + /* Cards that go bananas if you quiesce them before you reset them. */ + if (pdev->vendor == PCI_VENDOR_ID_DPT) { + c->no_quiesce = 1; + if (pdev->device == 0xa511) + c->raptor = 1; + } + + if ((rc = i2o_pci_alloc(c))) { + printk(KERN_ERR "i2o: DMA / IO allocation for I2O controller " + " failed\n"); + goto free_controller; + } + + if (i2o_pci_irq_enable(c)) { + printk(KERN_ERR "i2o: unable to enable interrupts for I2O " + "controller\n"); + goto free_pci; + } + + if ((rc = i2o_iop_add(c))) + goto uninstall; + + return 0; + + uninstall: + i2o_pci_irq_disable(c); + + free_pci: + i2o_pci_free(c); + + free_controller: + i2o_iop_free(c); + + disable: + pci_disable_device(pdev); + + return rc; +} + +/** + * i2o_pci_remove - Removes a I2O controller from the system + * pdev: I2O controller which should be removed + * + * Reset the I2O controller, disable interrupts and remove all allocated + * resources. + */ +static void __devexit i2o_pci_remove(struct pci_dev *pdev) +{ + struct i2o_controller *c; + c = pci_get_drvdata(pdev); + + i2o_iop_remove(c); + i2o_pci_irq_disable(c); + i2o_pci_free(c); + + printk(KERN_INFO "%s: Controller removed.\n", c->name); + + i2o_iop_free(c); + pci_disable_device(pdev); +}; + +/* PCI driver for I2O controller */ +static struct pci_driver i2o_pci_driver = { + .name = "I2O controller", + .id_table = i2o_pci_ids, + .probe = i2o_pci_probe, + .remove = __devexit_p(i2o_pci_remove), +}; + +/** + * i2o_pci_init - registers I2O PCI driver in PCI subsystem + * + * Returns > 0 on success or negative error code on failure. + */ +int __init i2o_pci_init(void) +{ + return pci_register_driver(&i2o_pci_driver); +}; + +/** + * i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem + */ +void __exit i2o_pci_exit(void) +{ + pci_unregister_driver(&i2o_pci_driver); +}; + +EXPORT_SYMBOL(i2o_dma_realloc); diff -Nru a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c --- a/drivers/misc/ibmasm/module.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/misc/ibmasm/module.c 2004-10-18 14:56:33 -07:00 @@ -62,10 +62,17 @@ int result = -ENOMEM; struct service_processor *sp; + if (pci_enable_device(pdev)) { + printk(KERN_ERR "%s: can't enable PCI device at %s\n", + DRIVER_NAME, pci_name(pdev)); + return -ENODEV; + } + sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL); if (sp == NULL) { dev_err(&pdev->dev, "Failed to allocate memory\n"); - return result; + result = -ENOMEM; + goto error_kmalloc; } memset(sp, 0, sizeof(struct service_processor)); @@ -148,6 +155,8 @@ ibmasm_event_buffer_exit(sp); error_eventbuffer: kfree(sp); +error_kmalloc: + pci_disable_device(pdev); return result; } @@ -166,6 +175,7 @@ iounmap(sp->base_address); ibmasm_event_buffer_exit(sp); kfree(sp); + pci_disable_device(pdev); } static struct pci_device_id ibmasm_pci_table[] = diff -Nru a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/Kconfig 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,52 @@ +# +# MMC subsystem configuration +# + +menu "MMC/SD Card support" + +config MMC + tristate "MMC support" + help + MMC is the "multi-media card" bus protocol. + + If you want MMC support, you should say Y here and also + to the specific driver for your MMC interface. + +config MMC_DEBUG + bool "MMC debugging" + depends on MMC != n + help + This is an option for use by developers; most people should + say N here. This enables MMC core and driver debugging. + +config MMC_BLOCK + tristate "MMC block device driver" + depends on MMC + default y + help + Say Y here to enable the MMC block device driver support. + This provides a block device driver, which you can use to + mount the filesystem. Almost everyone wishing MMC support + should say Y or M here. + +config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA && MMC + help + This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card + Interface (PL180 and PL181) support. If you have an ARM(R) + platform with a Multimedia Card slot, say Y or M here. + + If unsure, say N. + +config MMC_PXA + tristate "Intel PXA255 Multimedia Card Interface support" + depends on ARCH_PXA && MMC + help + This selects the Intel(R) PXA(R) Multimedia card Interface. + If you have a PXA(R) platform with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + +endmenu diff -Nru a/drivers/mmc/Makefile b/drivers/mmc/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/Makefile 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,21 @@ +# +# Makefile for the kernel mmc device drivers. +# + +# +# Core +# +obj-$(CONFIG_MMC) += mmc_core.o + +# +# Media drivers +# +obj-$(CONFIG_MMC_BLOCK) += mmc_block.o + +# +# Host drivers +# +obj-$(CONFIG_MMC_ARMMMCI) += mmci.o +obj-$(CONFIG_MMC_PXA) += pxamci.o + +mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o diff -Nru a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmc.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,913 @@ +/* + * linux/drivers/mmc/mmc.c + * + * Copyright (C) 2003-2004 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mmc.h" + +#ifdef CONFIG_MMC_DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) do { } while (0) +#endif + +#define CMD_RETRIES 3 + +/* + * OCR Bit positions to 10s of Vdd mV. + */ +static const unsigned short mmc_ocr_bit_to_vdd[] = { + 150, 155, 160, 165, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 260, 270, 280, + 290, 300, 310, 320, 330, 340, 350, 360 +}; + +static const unsigned int tran_exp[] = { + 10000, 100000, 1000000, 10000000, + 0, 0, 0, 0 +}; + +static const unsigned char tran_mant[] = { + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + +static const unsigned int tacc_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, +}; + +static const unsigned int tacc_mant[] = { + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + + +/** + * mmc_request_done - finish processing an MMC command + * @host: MMC host which completed command + * @mrq: MMC request which completed + * + * MMC drivers should call this function when they have completed + * their processing of a command. This should be called before the + * data part of the command has completed. + */ +void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + int err = mrq->cmd->error; + DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode, + err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + + if (err && cmd->retries) { + cmd->retries--; + cmd->error = 0; + host->ops->request(host, mrq); + } else if (mrq->done) { + mrq->done(mrq); + } +} + +EXPORT_SYMBOL(mmc_request_done); + +/** + * mmc_start_request - start a command on a host + * @host: MMC host to start command on + * @mrq: MMC request to start + * + * Queue a command on the specified host. We expect the + * caller to be holding the host lock with interrupts disabled. + */ +void +mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) +{ + DBG("MMC: starting cmd %02x arg %08x flags %08x\n", + mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); + + WARN_ON(host->card_busy == NULL); + + mrq->cmd->error = 0; + mrq->cmd->mrq = mrq; + if (mrq->data) { + mrq->cmd->data = mrq->data; + mrq->data->error = 0; + mrq->data->mrq = mrq; + if (mrq->stop) { + mrq->data->stop = mrq->stop; + mrq->stop->error = 0; + mrq->stop->mrq = mrq; + } + } + host->ops->request(host, mrq); +} + +EXPORT_SYMBOL(mmc_start_request); + +static void mmc_wait_done(struct mmc_request *mrq) +{ + complete(mrq->done_data); +} + +int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) +{ + DECLARE_COMPLETION(complete); + + mrq->done_data = &complete; + mrq->done = mmc_wait_done; + + mmc_start_request(host, mrq); + + wait_for_completion(&complete); + + return 0; +} + +EXPORT_SYMBOL(mmc_wait_for_req); + +/** + * mmc_wait_for_cmd - start a command and wait for completion + * @host: MMC host to start command + * @cmd: MMC command to start + * @retries: maximum number of retries + * + * Start a new MMC command for a host, and wait for the command + * to complete. Return any error that occurred while the command + * was executing. Do not attempt to parse the response. + */ +int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) +{ + struct mmc_request mrq; + + BUG_ON(host->card_busy == NULL); + + memset(&mrq, 0, sizeof(struct mmc_request)); + + memset(cmd->resp, 0, sizeof(cmd->resp)); + cmd->retries = retries; + + mrq.cmd = cmd; + cmd->data = NULL; + + mmc_wait_for_req(host, &mrq); + + return cmd->error; +} + +EXPORT_SYMBOL(mmc_wait_for_cmd); + + + +/** + * __mmc_claim_host - exclusively claim a host + * @host: mmc host to claim + * @card: mmc card to claim host for + * + * Claim a host for a set of operations. If a valid card + * is passed and this wasn't the last card selected, select + * the card before returning. + * + * Note: you should use mmc_card_claim_host or mmc_claim_host. + */ +int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int err = 0; + + add_wait_queue(&host->wq, &wait); + spin_lock_irqsave(&host->lock, flags); + while (1) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (host->card_busy == NULL) + break; + spin_unlock_irqrestore(&host->lock, flags); + schedule(); + spin_lock_irqsave(&host->lock, flags); + } + set_current_state(TASK_RUNNING); + host->card_busy = card; + spin_unlock_irqrestore(&host->lock, flags); + remove_wait_queue(&host->wq, &wait); + + if (card != (void *)-1 && host->card_selected != card) { + struct mmc_command cmd; + + host->card_selected = card; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + } + + return err; +} + +EXPORT_SYMBOL(__mmc_claim_host); + +/** + * mmc_release_host - release a host + * @host: mmc host to release + * + * Release a MMC host, allowing others to claim the host + * for their operations. + */ +void mmc_release_host(struct mmc_host *host) +{ + unsigned long flags; + + BUG_ON(host->card_busy == NULL); + + spin_lock_irqsave(&host->lock, flags); + host->card_busy = NULL; + spin_unlock_irqrestore(&host->lock, flags); + + wake_up(&host->wq); +} + +EXPORT_SYMBOL(mmc_release_host); + +/* + * Ensure that no card is selected. + */ +static void mmc_deselect_cards(struct mmc_host *host) +{ + struct mmc_command cmd; + + if (host->card_selected) { + host->card_selected = NULL; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE; + + mmc_wait_for_cmd(host, &cmd, 0); + } +} + + +static inline void mmc_delay(unsigned int ms) +{ + if (ms < HZ / 1000) { + yield(); + mdelay(ms); + } else { + msleep_interruptible (ms); + } +} + +/* + * Mask off any voltages we don't support and select + * the lowest voltage + */ +static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) +{ + int bit; + + ocr &= host->ocr_avail; + + bit = ffs(ocr); + if (bit) { + bit -= 1; + + ocr = 3 << bit; + + host->ios.vdd = bit; + host->ops->set_ios(host, &host->ios); + } else { + ocr = 0; + } + + return ocr; +} + +#define UNSTUFF_BITS(resp,start,size) \ + ({ \ + const u32 __mask = (1 << (size)) - 1; \ + const int __off = 3 - ((start) / 32); \ + const int __shft = (start) & 31; \ + u32 __res; \ + \ + __res = resp[__off] >> __shft; \ + if ((size) + __shft >= 32) \ + __res |= resp[__off-1] << (32 - __shft); \ + __res & __mask; \ + }) + +/* + * Given the decoded CSD structure, decode the raw CID to our CID structure. + */ +static void mmc_decode_cid(struct mmc_card *card) +{ + u32 *resp = card->raw_cid; + + memset(&card->cid, 0, sizeof(struct mmc_cid)); + + /* + * The selection of the format here is guesswork based upon + * information people have sent to date. + */ + switch (card->csd.mmca_vsn) { + case 0: /* MMC v1.? */ + case 1: /* MMC v1.4 */ + card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); + card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); + card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); + card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); + card->cid.serial = UNSTUFF_BITS(resp, 16, 24); + card->cid.month = UNSTUFF_BITS(resp, 12, 4); + card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + break; + + case 2: /* MMC v2.x ? */ + case 3: /* MMC v3.x ? */ + card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); + card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); + card->cid.serial = UNSTUFF_BITS(resp, 16, 32); + card->cid.month = UNSTUFF_BITS(resp, 12, 4); + card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + break; + + default: + printk("%s: card has unknown MMCA version %d\n", + card->host->host_name, card->csd.mmca_vsn); + mmc_card_set_bad(card); + break; + } +} + +/* + * Given a 128-bit response, decode to our card CSD structure. + */ +static void mmc_decode_csd(struct mmc_card *card) +{ + struct mmc_csd *csd = &card->csd; + unsigned int e, m, csd_struct; + u32 *resp = card->raw_csd; + + /* + * We only understand CSD structure v1.1 and v2. + * v2 has extra information in bits 15, 11 and 10. + */ + csd_struct = UNSTUFF_BITS(resp, 126, 2); + if (csd_struct != 1 && csd_struct != 2) { + printk("%s: unrecognised CSD structure version %d\n", + card->host->host_name, csd_struct); + mmc_card_set_bad(card); + return; + } + + csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); +} + +/* + * Locate a MMC card on this MMC host given a raw CID. + */ +static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid) +{ + struct mmc_card *card; + + list_for_each_entry(card, &host->cards, node) { + if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0) + return card; + } + return NULL; +} + +/* + * Allocate a new MMC card, and assign a unique RCA. + */ +static struct mmc_card * +mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca) +{ + struct mmc_card *card, *c; + unsigned int rca = *frca; + + card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + mmc_init_card(card, host); + memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid)); + + again: + list_for_each_entry(c, &host->cards, node) + if (c->rca == rca) { + rca++; + goto again; + } + + card->rca = rca; + + *frca = rca; + + return card; +} + +/* + * Tell attached cards to go to IDLE state + */ +static void mmc_idle_cards(struct mmc_host *host) +{ + struct mmc_command cmd; + + cmd.opcode = MMC_GO_IDLE_STATE; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE; + + mmc_wait_for_cmd(host, &cmd, 0); + + mmc_delay(1); +} + +/* + * Apply power to the MMC stack. + */ +static void mmc_power_up(struct mmc_host *host) +{ + int bit = fls(host->ocr_avail) - 1; + + host->ios.vdd = bit; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.power_mode = MMC_POWER_UP; + host->ops->set_ios(host, &host->ios); + + mmc_delay(1); + + host->ios.clock = host->f_min; + host->ios.power_mode = MMC_POWER_ON; + host->ops->set_ios(host, &host->ios); + + mmc_delay(2); +} + +static void mmc_power_off(struct mmc_host *host) +{ + host->ios.clock = 0; + host->ios.vdd = 0; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.power_mode = MMC_POWER_OFF; + host->ops->set_ios(host, &host->ios); +} + +static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + cmd.opcode = MMC_SEND_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R3; + + for (i = 100; i; i--) { + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err != MMC_ERR_NONE) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + + err = MMC_ERR_TIMEOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + +/* + * Discover cards by requesting their CID. If this command + * times out, it is not an error; there are no further cards + * to be discovered. Add new cards to the list. + * + * Create a mmc_card entry for each discovered card, assigning + * it an RCA, and save the raw CID for decoding later. + */ +static void mmc_discover_cards(struct mmc_host *host) +{ + struct mmc_card *card; + unsigned int first_rca = 1, err; + + while (1) { + struct mmc_command cmd; + + cmd.opcode = MMC_ALL_SEND_CID; + cmd.arg = 0; + cmd.flags = MMC_RSP_R2; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err == MMC_ERR_TIMEOUT) { + err = MMC_ERR_NONE; + break; + } + if (err != MMC_ERR_NONE) { + printk(KERN_ERR "%s: error requesting CID: %d\n", + host->host_name, err); + break; + } + + card = mmc_find_card(host, cmd.resp); + if (!card) { + card = mmc_alloc_card(host, cmd.resp, &first_rca); + if (IS_ERR(card)) { + err = PTR_ERR(card); + break; + } + list_add(&card->node, &host->cards); + } + + card->state &= ~MMC_STATE_DEAD; + + cmd.opcode = MMC_SET_RELATIVE_ADDR; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + mmc_card_set_dead(card); + } +} + +static void mmc_read_csds(struct mmc_host *host) +{ + struct mmc_card *card; + + list_for_each_entry(card, &host->cards, node) { + struct mmc_command cmd; + int err; + + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + + cmd.opcode = MMC_SEND_CSD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R2; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd)); + + mmc_decode_csd(card); + mmc_decode_cid(card); + } +} + +static unsigned int mmc_calculate_clock(struct mmc_host *host) +{ + struct mmc_card *card; + unsigned int max_dtr = host->f_max; + + list_for_each_entry(card, &host->cards, node) + if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) + max_dtr = card->csd.max_dtr; + + DBG("MMC: selected %d.%03dMHz transfer rate\n", + max_dtr / 1000000, (max_dtr / 1000) % 1000); + + return max_dtr; +} + +/* + * Check whether cards we already know about are still present. + * We do this by requesting status, and checking whether a card + * responds. + * + * A request for status does not cause a state change in data + * transfer mode. + */ +static void mmc_check_cards(struct mmc_host *host) +{ + struct list_head *l, *n; + + mmc_deselect_cards(host); + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + struct mmc_command cmd; + int err; + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err == MMC_ERR_NONE) + continue; + + mmc_card_set_dead(card); + } +} + +static void mmc_setup(struct mmc_host *host) +{ + if (host->ios.power_mode != MMC_POWER_ON) { + int err; + u32 ocr; + + mmc_power_up(host); + mmc_idle_cards(host); + + err = mmc_send_op_cond(host, 0, &ocr); + if (err != MMC_ERR_NONE) + return; + + host->ocr = mmc_select_voltage(host, ocr); + + /* + * Since we're changing the OCR value, we seem to + * need to tell some cards to go back to the idle + * state. We wait 1ms to give cards time to + * respond. + */ + if (host->ocr) + mmc_idle_cards(host); + } else { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.clock = host->f_min; + host->ops->set_ios(host, &host->ios); + + /* + * We should remember the OCR mask from the existing + * cards, and detect the new cards OCR mask, combine + * the two and re-select the VDD. However, if we do + * change VDD, we should do an idle, and then do a + * full re-initialisation. We would need to notify + * drivers so that they can re-setup the cards as + * well, while keeping their queues at bay. + * + * For the moment, we take the easy way out - if the + * new cards don't like our currently selected VDD, + * they drop off the bus. + */ + } + + if (host->ocr == 0) + return; + + /* + * Send the selected OCR multiple times... until the cards + * all get the idea that they should be ready for CMD2. + * (My SanDisk card seems to need this.) + */ + mmc_send_op_cond(host, host->ocr, NULL); + + mmc_discover_cards(host); + + /* + * Ok, now switch to push-pull mode. + */ + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + host->ops->set_ios(host, &host->ios); + + mmc_read_csds(host); +} + + +/** + * mmc_detect_change - process change of state on a MMC socket + * @host: host which changed state. + * + * All we know is that card(s) have been inserted or removed + * from the socket(s). We don't know which socket or cards. + */ +void mmc_detect_change(struct mmc_host *host) +{ + schedule_work(&host->detect); +} + +EXPORT_SYMBOL(mmc_detect_change); + + +static void mmc_rescan(void *data) +{ + struct mmc_host *host = data; + struct list_head *l, *n; + + mmc_claim_host(host); + + if (host->ios.power_mode == MMC_POWER_ON) + mmc_check_cards(host); + + mmc_setup(host); + + if (!list_empty(&host->cards)) { + /* + * (Re-)calculate the fastest clock rate which the + * attached cards and the host support. + */ + host->ios.clock = mmc_calculate_clock(host); + host->ops->set_ios(host, &host->ios); + } + + mmc_release_host(host); + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + + /* + * If this is a new and good card, register it. + */ + if (!mmc_card_present(card) && !mmc_card_dead(card)) { + if (mmc_register_card(card)) + mmc_card_set_dead(card); + else + mmc_card_set_present(card); + } + + /* + * If this card is dead, destroy it. + */ + if (mmc_card_dead(card)) { + list_del(&card->node); + mmc_remove_card(card); + } + } + + /* + * If we discover that there are no cards on the + * bus, turn off the clock and power down. + */ + if (list_empty(&host->cards)) + mmc_power_off(host); +} + + +/** + * mmc_alloc_host - initialise the per-host structure. + * @extra: sizeof private data structure + * @dev: pointer to host device model structure + * + * Initialise the per-host structure. + */ +struct mmc_host *mmc_alloc_host(int extra, struct device *dev) +{ + struct mmc_host *host; + + host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); + if (host) { + memset(host, 0, sizeof(struct mmc_host) + extra); + + spin_lock_init(&host->lock); + init_waitqueue_head(&host->wq); + INIT_LIST_HEAD(&host->cards); + INIT_WORK(&host->detect, mmc_rescan, host); + + host->dev = dev; + + /* + * By default, hosts do not support SGIO or large requests. + * They have to set these according to their abilities. + */ + host->max_hw_segs = 1; + host->max_phys_segs = 1; + host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); + host->max_seg_size = PAGE_CACHE_SIZE; + } + + return host; +} + +EXPORT_SYMBOL(mmc_alloc_host); + +/** + * mmc_add_host - initialise host hardware + * @host: mmc host + */ +int mmc_add_host(struct mmc_host *host) +{ + static unsigned int host_num; + + snprintf(host->host_name, sizeof(host->host_name), + "mmc%d", host_num++); + + mmc_power_off(host); + mmc_detect_change(host); + + return 0; +} + +EXPORT_SYMBOL(mmc_add_host); + +/** + * mmc_remove_host - remove host hardware + * @host: mmc host + * + * Unregister and remove all cards associated with this host, + * and power down the MMC bus. + */ +void mmc_remove_host(struct mmc_host *host) +{ + struct list_head *l, *n; + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + + mmc_remove_card(card); + } + + mmc_power_off(host); +} + +EXPORT_SYMBOL(mmc_remove_host); + +/** + * mmc_free_host - free the host structure + * @host: mmc host + * + * Free the host once all references to it have been dropped. + */ +void mmc_free_host(struct mmc_host *host) +{ + flush_scheduled_work(); + kfree(host); +} + +EXPORT_SYMBOL(mmc_free_host); + +#ifdef CONFIG_PM + +/** + * mmc_suspend_host - suspend a host + * @host: mmc host + * @state: suspend mode (PM_SUSPEND_xxx) + */ +int mmc_suspend_host(struct mmc_host *host, u32 state) +{ + mmc_claim_host(host); + mmc_deselect_cards(host); + mmc_power_off(host); + mmc_release_host(host); + + return 0; +} + +EXPORT_SYMBOL(mmc_suspend_host); + +/** + * mmc_resume_host - resume a previously suspended host + * @host: mmc host + */ +int mmc_resume_host(struct mmc_host *host) +{ + mmc_detect_change(host); + + return 0; +} + +EXPORT_SYMBOL(mmc_resume_host); + +#endif + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmc.h 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,16 @@ +/* + * linux/drivers/mmc/mmc.h + * + * Copyright (C) 2003 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _MMC_H +#define _MMC_H +/* core-internal functions */ +void mmc_init_card(struct mmc_card *card, struct mmc_host *host); +int mmc_register_card(struct mmc_card *card); +void mmc_remove_card(struct mmc_card *card); +#endif diff -Nru a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmc_block.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,495 @@ +/* + * Block driver for media (i.e., flash cards) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Author: Andrew Christian + * 28 May 2002 + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "mmc_queue.h" + +/* + * max 8 partitions per card + */ +#define MMC_SHIFT 3 + +static int major; + +/* + * There is one mmc_blk_data per slot. + */ +struct mmc_blk_data { + spinlock_t lock; + struct gendisk *disk; + struct mmc_queue queue; + + unsigned int usage; + unsigned int block_bits; +}; + +static DECLARE_MUTEX(open_lock); + +static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) +{ + struct mmc_blk_data *md; + + down(&open_lock); + md = disk->private_data; + if (md && md->usage == 0) + md = NULL; + if (md) + md->usage++; + up(&open_lock); + + return md; +} + +static void mmc_blk_put(struct mmc_blk_data *md) +{ + down(&open_lock); + md->usage--; + if (md->usage == 0) { + put_disk(md->disk); + mmc_cleanup_queue(&md->queue); + kfree(md); + } + up(&open_lock); +} + +static int mmc_blk_open(struct inode *inode, struct file *filp) +{ + struct mmc_blk_data *md; + int ret = -ENXIO; + + md = mmc_blk_get(inode->i_bdev->bd_disk); + if (md) { + if (md->usage == 2) + check_disk_change(inode->i_bdev); + ret = 0; + } + + return ret; +} + +static int mmc_blk_release(struct inode *inode, struct file *filp) +{ + struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data; + + mmc_blk_put(md); + return 0; +} + +static int +mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct block_device *bdev = inode->i_bdev; + + if (cmd == HDIO_GETGEO) { + struct hd_geometry geo; + + memset(&geo, 0, sizeof(struct hd_geometry)); + + geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16); + geo.heads = 4; + geo.sectors = 16; + geo.start = get_start_sect(bdev); + + return copy_to_user((void __user *)arg, &geo, sizeof(geo)) + ? -EFAULT : 0; + } + + return -ENOTTY; +} + +static struct block_device_operations mmc_bdops = { + .open = mmc_blk_open, + .release = mmc_blk_release, + .ioctl = mmc_blk_ioctl, + .owner = THIS_MODULE, +}; + +struct mmc_blk_request { + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; +}; + +static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req) +{ + struct mmc_blk_data *md = mq->data; + int stat = BLKPREP_OK; + + /* + * If we have no device, we haven't finished initialising. + */ + if (!md || !mq->card) { + printk(KERN_ERR "%s: killing request - no device/host\n", + req->rq_disk->disk_name); + stat = BLKPREP_KILL; + } + + return stat; +} + +static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) +{ + struct mmc_blk_data *md = mq->data; + struct mmc_card *card = md->queue.card; + int ret; + + if (mmc_card_claim_host(card)) + goto cmd_err; + + do { + struct mmc_blk_request brq; + struct mmc_command cmd; + + memset(&brq, 0, sizeof(struct mmc_blk_request)); + brq.mrq.cmd = &brq.cmd; + brq.mrq.data = &brq.data; + + brq.cmd.arg = req->sector << 9; + brq.cmd.flags = MMC_RSP_R1; + brq.data.req = req; + brq.data.timeout_ns = card->csd.tacc_ns * 10; + brq.data.timeout_clks = card->csd.tacc_clks * 10; + brq.data.blksz_bits = md->block_bits; + brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); + brq.stop.opcode = MMC_STOP_TRANSMISSION; + brq.stop.arg = 0; + brq.stop.flags = MMC_RSP_R1B; + + if (rq_data_dir(req) == READ) { + brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; + brq.data.flags |= MMC_DATA_READ; + } else { + brq.cmd.opcode = MMC_WRITE_BLOCK; + brq.cmd.flags = MMC_RSP_R1B; + brq.data.flags |= MMC_DATA_WRITE; + brq.data.blocks = 1; + } + brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL; + + mmc_wait_for_req(card->host, &brq.mrq); + if (brq.cmd.error) { + printk(KERN_ERR "%s: error %d sending read/write command\n", + req->rq_disk->disk_name, brq.cmd.error); + goto cmd_err; + } + + if (brq.data.error) { + printk(KERN_ERR "%s: error %d transferring data\n", + req->rq_disk->disk_name, brq.data.error); + goto cmd_err; + } + + if (brq.stop.error) { + printk(KERN_ERR "%s: error %d sending stop command\n", + req->rq_disk->disk_name, brq.stop.error); + goto cmd_err; + } + + do { + int err; + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + err = mmc_wait_for_cmd(card->host, &cmd, 5); + if (err) { + printk(KERN_ERR "%s: error %d requesting status\n", + req->rq_disk->disk_name, err); + goto cmd_err; + } + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + +#if 0 + if (cmd.resp[0] & ~0x00000900) + printk(KERN_ERR "%s: status = %08x\n", + req->rq_disk->disk_name, cmd.resp[0]); + if (mmc_decode_status(cmd.resp)) + goto cmd_err; +#endif + + /* + * A block was successfully transferred. + */ + spin_lock_irq(&md->lock); + ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); + if (!ret) { + /* + * The whole request completed successfully. + */ + add_disk_randomness(req->rq_disk); + blkdev_dequeue_request(req); + end_that_request_last(req); + } + spin_unlock_irq(&md->lock); + } while (ret); + + mmc_card_release_host(card); + + return 1; + + cmd_err: + mmc_card_release_host(card); + + /* + * This is a little draconian, but until we get proper + * error handling sorted out here, its the best we can + * do - especially as some hosts have no idea how much + * data was transferred before the error occurred. + */ + spin_lock_irq(&md->lock); + do { + ret = end_that_request_chunk(req, 0, + req->current_nr_sectors << 9); + } while (ret); + + add_disk_randomness(req->rq_disk); + blkdev_dequeue_request(req); + end_that_request_last(req); + spin_unlock_irq(&md->lock); + + return 0; +} + +#define MMC_NUM_MINORS (256 >> MMC_SHIFT) + +static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; + +static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) +{ + struct mmc_blk_data *md; + int devidx, ret; + + devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); + if (devidx >= MMC_NUM_MINORS) + return ERR_PTR(-ENOSPC); + __set_bit(devidx, dev_use); + + md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); + if (md) { + memset(md, 0, sizeof(struct mmc_blk_data)); + + md->disk = alloc_disk(1 << MMC_SHIFT); + if (md->disk == NULL) { + kfree(md); + md = ERR_PTR(-ENOMEM); + goto out; + } + + spin_lock_init(&md->lock); + md->usage = 1; + + ret = mmc_init_queue(&md->queue, card, &md->lock); + if (ret) { + put_disk(md->disk); + kfree(md); + md = ERR_PTR(ret); + goto out; + } + md->queue.prep_fn = mmc_blk_prep_rq; + md->queue.issue_fn = mmc_blk_issue_rq; + md->queue.data = md; + + md->disk->major = major; + md->disk->first_minor = devidx << MMC_SHIFT; + md->disk->fops = &mmc_bdops; + md->disk->private_data = md; + md->disk->queue = md->queue.queue; + md->disk->driverfs_dev = &card->dev; + + sprintf(md->disk->disk_name, "mmcblk%d", devidx); + sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); + + md->block_bits = card->csd.read_blkbits; + + blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); + set_capacity(md->disk, card->csd.capacity); + } + out: + return md; +} + +static int +mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) +{ + struct mmc_command cmd; + int err; + + mmc_card_claim_host(card); + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = 1 << card->csd.read_blkbits; + cmd.flags = MMC_RSP_R1; + err = mmc_wait_for_cmd(card->host, &cmd, 5); + mmc_card_release_host(card); + + if (err) { + printk(KERN_ERR "%s: unable to set block size to %d: %d\n", + md->disk->disk_name, cmd.arg, err); + return -EINVAL; + } + + return 0; +} + +static int mmc_blk_probe(struct mmc_card *card) +{ + struct mmc_blk_data *md; + int err; + + if (card->csd.cmdclass & ~0x1ff) + return -ENODEV; + + if (card->csd.read_blkbits < 9) { + printk(KERN_WARNING "%s: read blocksize too small (%u)\n", + mmc_card_id(card), 1 << card->csd.read_blkbits); + return -ENODEV; + } + + md = mmc_blk_alloc(card); + if (IS_ERR(md)) + return PTR_ERR(md); + + err = mmc_blk_set_blksize(md, card); + if (err) + goto out; + + printk(KERN_INFO "%s: %s %s %dKiB\n", + md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), + (card->csd.capacity << card->csd.read_blkbits) / 1024); + + mmc_set_drvdata(card, md); + add_disk(md->disk); + return 0; + + out: + mmc_blk_put(md); + + return err; +} + +static void mmc_blk_remove(struct mmc_card *card) +{ + struct mmc_blk_data *md = mmc_get_drvdata(card); + + if (md) { + int devidx; + + del_gendisk(md->disk); + + /* + * I think this is needed. + */ + md->disk->queue = NULL; + + devidx = md->disk->first_minor >> MMC_SHIFT; + __clear_bit(devidx, dev_use); + + mmc_blk_put(md); + } + mmc_set_drvdata(card, NULL); +} + +#ifdef CONFIG_PM +static int mmc_blk_suspend(struct mmc_card *card, u32 state) +{ + struct mmc_blk_data *md = mmc_get_drvdata(card); + + if (md) { + mmc_queue_suspend(&md->queue); + } + return 0; +} + +static int mmc_blk_resume(struct mmc_card *card) +{ + struct mmc_blk_data *md = mmc_get_drvdata(card); + + if (md) { + mmc_blk_set_blksize(md, card); + mmc_queue_resume(&md->queue); + } + return 0; +} +#else +#define mmc_blk_suspend NULL +#define mmc_blk_resume NULL +#endif + +static struct mmc_driver mmc_driver = { + .drv = { + .name = "mmcblk", + }, + .probe = mmc_blk_probe, + .remove = mmc_blk_remove, + .suspend = mmc_blk_suspend, + .resume = mmc_blk_resume, +}; + +static int __init mmc_blk_init(void) +{ + int res = -ENOMEM; + + res = register_blkdev(major, "mmc"); + if (res < 0) { + printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n", + major, res); + goto out; + } + if (major == 0) + major = res; + + devfs_mk_dir("mmc"); + return mmc_register_driver(&mmc_driver); + + out: + return res; +} + +static void __exit mmc_blk_exit(void) +{ + mmc_unregister_driver(&mmc_driver); + devfs_remove("mmc"); + unregister_blkdev(major, "mmc"); +} + +module_init(mmc_blk_init); +module_exit(mmc_blk_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver"); + +module_param(major, int, 0444); +MODULE_PARM_DESC(major, "specify the major device number for MMC block driver"); diff -Nru a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmc_queue.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,222 @@ +/* + * linux/drivers/mmc/mmc_queue.c + * + * Copyright (C) 2003 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include + +#include +#include +#include "mmc_queue.h" + +#define MMC_QUEUE_EXIT (1 << 0) +#define MMC_QUEUE_SUSPENDED (1 << 1) + +/* + * Prepare a MMC request. Essentially, this means passing the + * preparation off to the media driver. The media driver will + * create a mmc_io_request in req->special. + */ +static int mmc_prep_request(struct request_queue *q, struct request *req) +{ + struct mmc_queue *mq = q->queuedata; + int ret = BLKPREP_KILL; + + if (req->flags & REQ_SPECIAL) { + /* + * Special commands already have the command + * blocks already setup in req->special. + */ + BUG_ON(!req->special); + + ret = BLKPREP_OK; + } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + /* + * Block I/O requests need translating according + * to the protocol. + */ + ret = mq->prep_fn(mq, req); + } else { + /* + * Everything else is invalid. + */ + blk_dump_rq_flags(req, "MMC bad request"); + } + + if (ret == BLKPREP_OK) + req->flags |= REQ_DONTPREP; + + return ret; +} + +static int mmc_queue_thread(void *d) +{ + struct mmc_queue *mq = d; + struct request_queue *q = mq->queue; + DECLARE_WAITQUEUE(wait, current); + + /* + * Set iothread to ensure that we aren't put to sleep by + * the process freezing. We handle suspension ourselves. + */ + current->flags |= PF_MEMALLOC|PF_NOFREEZE; + + daemonize("mmcqd"); + + complete(&mq->thread_complete); + + down(&mq->thread_sem); + add_wait_queue(&mq->thread_wq, &wait); + do { + struct request *req = NULL; + + spin_lock_irq(q->queue_lock); + set_current_state(TASK_INTERRUPTIBLE); + if (!blk_queue_plugged(q)) + mq->req = req = elv_next_request(q); + spin_unlock(q->queue_lock); + + if (!req) { + if (mq->flags & MMC_QUEUE_EXIT) + break; + up(&mq->thread_sem); + schedule(); + down(&mq->thread_sem); + continue; + } + set_current_state(TASK_RUNNING); + + mq->issue_fn(mq, req); + } while (1); + remove_wait_queue(&mq->thread_wq, &wait); + up(&mq->thread_sem); + + complete_and_exit(&mq->thread_complete, 0); + return 0; +} + +/* + * Generic MMC request handler. This is called for any queue on a + * particular host. When the host is not busy, we look for a request + * on any queue on this host, and attempt to issue it. This may + * not be the queue we were asked to process. + */ +static void mmc_request(request_queue_t *q) +{ + struct mmc_queue *mq = q->queuedata; + + if (!mq->req) + wake_up(&mq->thread_wq); +} + +/** + * mmc_init_queue - initialise a queue structure. + * @mq: mmc queue + * @card: mmc card to attach this queue + * @lock: queue lock + * + * Initialise a MMC card request queue. + */ +int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) +{ + struct mmc_host *host = card->host; + u64 limit = BLK_BOUNCE_HIGH; + int ret; + + if (host->dev->dma_mask && *host->dev->dma_mask) + limit = *host->dev->dma_mask; + + mq->card = card; + mq->queue = blk_init_queue(mmc_request, lock); + if (!mq->queue) + return -ENOMEM; + + blk_queue_prep_rq(mq->queue, mmc_prep_request); + blk_queue_bounce_limit(mq->queue, limit); + blk_queue_max_sectors(mq->queue, host->max_sectors); + blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); + blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); + blk_queue_max_segment_size(mq->queue, host->max_seg_size); + + mq->queue->queuedata = mq; + mq->req = NULL; + + init_completion(&mq->thread_complete); + init_waitqueue_head(&mq->thread_wq); + init_MUTEX(&mq->thread_sem); + + ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); + if (ret < 0) { + blk_cleanup_queue(mq->queue); + } else { + wait_for_completion(&mq->thread_complete); + init_completion(&mq->thread_complete); + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL(mmc_init_queue); + +void mmc_cleanup_queue(struct mmc_queue *mq) +{ + mq->flags |= MMC_QUEUE_EXIT; + wake_up(&mq->thread_wq); + wait_for_completion(&mq->thread_complete); + blk_cleanup_queue(mq->queue); + + mq->card = NULL; +} +EXPORT_SYMBOL(mmc_cleanup_queue); + +/** + * mmc_queue_suspend - suspend a MMC request queue + * @mq: MMC queue to suspend + * + * Stop the block request queue, and wait for our thread to + * complete any outstanding requests. This ensures that we + * won't suspend while a request is being processed. + */ +void mmc_queue_suspend(struct mmc_queue *mq) +{ + request_queue_t *q = mq->queue; + unsigned long flags; + + if (!(mq->flags & MMC_QUEUE_SUSPENDED)) { + mq->flags |= MMC_QUEUE_SUSPENDED; + + spin_lock_irqsave(q->queue_lock, flags); + blk_stop_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + + down(&mq->thread_sem); + } +} +EXPORT_SYMBOL(mmc_queue_suspend); + +/** + * mmc_queue_resume - resume a previously suspended MMC request queue + * @mq: MMC queue to resume + */ +void mmc_queue_resume(struct mmc_queue *mq) +{ + request_queue_t *q = mq->queue; + unsigned long flags; + + if (mq->flags & MMC_QUEUE_SUSPENDED) { + mq->flags &= ~MMC_QUEUE_SUSPENDED; + + up(&mq->thread_sem); + + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + } +} +EXPORT_SYMBOL(mmc_queue_resume); diff -Nru a/drivers/mmc/mmc_queue.h b/drivers/mmc/mmc_queue.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmc_queue.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,32 @@ +#ifndef MMC_QUEUE_H +#define MMC_QUEUE_H + +struct request; +struct task_struct; + +struct mmc_queue { + struct mmc_card *card; + struct completion thread_complete; + wait_queue_head_t thread_wq; + struct semaphore thread_sem; + unsigned int flags; + struct request *req; + int (*prep_fn)(struct mmc_queue *, struct request *); + int (*issue_fn)(struct mmc_queue *, struct request *); + void *data; + struct request_queue *queue; +}; + +struct mmc_io_request { + struct request *rq; + int num; + struct mmc_command selcmd; /* mmc_queue private */ + struct mmc_command cmd[4]; /* max 4 commands */ +}; + +extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *); +extern void mmc_cleanup_queue(struct mmc_queue *); +extern void mmc_queue_suspend(struct mmc_queue *); +extern void mmc_queue_resume(struct mmc_queue *); + +#endif diff -Nru a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmc_sysfs.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,241 @@ +/* + * linux/drivers/mmc/mmc_sysfs.c + * + * Copyright (C) 2003 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * MMC sysfs/driver model support. + */ +#include +#include +#include + +#include +#include + +#include "mmc.h" + +#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) +#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) + +static void mmc_release_card(struct device *dev) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + + kfree(card); +} + +/* + * This currently matches any MMC driver to any MMC card - drivers + * themselves make the decision whether to drive this card in their + * probe method. However, we force "bad" cards to fail. + */ +static int mmc_bus_match(struct device *dev, struct device_driver *drv) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + return !mmc_card_bad(card); +} + +static int +mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf, + int buf_size) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + char ccc[13]; + int i = 0; + +#define add_env(fmt,val) \ + ({ \ + int len, ret = -ENOMEM; \ + if (i < num_envp) { \ + envp[i++] = buf; \ + len = snprintf(buf, buf_size, fmt, val) + 1; \ + buf_size -= len; \ + buf += len; \ + if (buf_size >= 0) \ + ret = 0; \ + } \ + ret; \ + }) + + for (i = 0; i < 12; i++) + ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0'; + ccc[12] = '\0'; + + i = 0; + add_env("MMC_CCC=%s", ccc); + add_env("MMC_MANFID=%06x", card->cid.manfid); + add_env("MMC_NAME=%s", mmc_card_name(card)); + add_env("MMC_OEMID=%04x", card->cid.oemid); + + return 0; +} + +static int mmc_bus_suspend(struct device *dev, u32 state) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + int ret = 0; + + if (dev->driver && drv->suspend) + ret = drv->suspend(card, state); + return ret; +} + +static int mmc_bus_resume(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + int ret = 0; + + if (dev->driver && drv->resume) + ret = drv->resume(card); + return ret; +} + +static struct bus_type mmc_bus_type = { + .name = "mmc", + .match = mmc_bus_match, + .hotplug = mmc_bus_hotplug, + .suspend = mmc_bus_suspend, + .resume = mmc_bus_resume, +}; + + +static int mmc_drv_probe(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + + return drv->probe(card); +} + +static int mmc_drv_remove(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + + drv->remove(card); + + return 0; +} + + +/** + * mmc_register_driver - register a media driver + * @drv: MMC media driver + */ +int mmc_register_driver(struct mmc_driver *drv) +{ + drv->drv.bus = &mmc_bus_type; + drv->drv.probe = mmc_drv_probe; + drv->drv.remove = mmc_drv_remove; + return driver_register(&drv->drv); +} + +EXPORT_SYMBOL(mmc_register_driver); + +/** + * mmc_unregister_driver - unregister a media driver + * @drv: MMC media driver + */ +void mmc_unregister_driver(struct mmc_driver *drv) +{ + drv->drv.bus = &mmc_bus_type; + driver_unregister(&drv->drv); +} + +EXPORT_SYMBOL(mmc_unregister_driver); + + +#define MMC_ATTR(name, fmt, args...) \ +static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \ +{ \ + struct mmc_card *card = dev_to_mmc_card(dev); \ + return sprintf(buf, fmt, args); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL) + +MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], + card->raw_cid[2], card->raw_cid[3]); +MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], + card->raw_csd[2], card->raw_csd[3]); +MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); +MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev); +MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev); +MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid); +MMC_ATTR(name, "%s\n", card->cid.prod_name); +MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid); +MMC_ATTR(serial, "0x%08x\n", card->cid.serial); + +static struct device_attribute *mmc_dev_attributes[] = { + &dev_attr_cid, + &dev_attr_csd, + &dev_attr_date, + &dev_attr_fwrev, + &dev_attr_hwrev, + &dev_attr_manfid, + &dev_attr_name, + &dev_attr_oemid, + &dev_attr_serial, +}; + +/* + * Internal function. Initialise a MMC card structure. + */ +void mmc_init_card(struct mmc_card *card, struct mmc_host *host) +{ + memset(card, 0, sizeof(struct mmc_card)); + card->host = host; + device_initialize(&card->dev); + card->dev.parent = card->host->dev; + card->dev.bus = &mmc_bus_type; + card->dev.release = mmc_release_card; +} + +/* + * Internal function. Register a new MMC card with the driver model. + */ +int mmc_register_card(struct mmc_card *card) +{ + int ret, i; + + snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), + "%s:%04x", card->host->host_name, card->rca); + + ret = device_add(&card->dev); + if (ret == 0) + for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++) + device_create_file(&card->dev, mmc_dev_attributes[i]); + + return ret; +} + +/* + * Internal function. Unregister a new MMC card with the + * driver model, and (eventually) free it. + */ +void mmc_remove_card(struct mmc_card *card) +{ + if (mmc_card_present(card)) + device_del(&card->dev); + + put_device(&card->dev); +} + + +static int __init mmc_init(void) +{ + return bus_register(&mmc_bus_type); +} + +static void __exit mmc_exit(void) +{ + bus_unregister(&mmc_bus_type); +} + +module_init(mmc_init); +module_exit(mmc_exit); diff -Nru a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmci.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,679 @@ +/* + * linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mmci.h" + +#define DRIVER_NAME "mmci-pl18x" + +#ifdef CONFIG_MMC_DEBUG +#define DBG(host,fmt,args...) \ + pr_debug("%s: %s: " fmt, host->mmc->host_name, __func__ , args) +#else +#define DBG(host,fmt,args...) do { } while (0) +#endif + +static unsigned int fmax = 515633; + +static void +mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) +{ + writel(0, host->base + MMCICOMMAND); + + host->mrq = NULL; + host->cmd = NULL; + + if (mrq->data) + mrq->data->bytes_xfered = host->data_xfered; + + /* + * Need to drop the host lock here; mmc_request_done may call + * back into the driver... + */ + spin_unlock(&host->lock); + mmc_request_done(host->mmc, mrq); + spin_lock(&host->lock); +} + +static void mmci_stop_data(struct mmci_host *host) +{ + writel(0, host->base + MMCIDATACTRL); + writel(0, host->base + MMCIMASK1); + host->data = NULL; +} + +static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) +{ + unsigned int datactrl, timeout, irqmask; + void *base; + + DBG(host, "blksz %04x blks %04x flags %08x\n", + 1 << data->blksz_bits, data->blocks, data->flags); + + host->data = data; + host->size = data->blocks << data->blksz_bits; + host->data_xfered = 0; + + mmci_init_sg(host, data); + + timeout = data->timeout_clks + + ((unsigned long long)data->timeout_ns * host->cclk) / + 1000000000ULL; + + base = host->base; + writel(timeout, base + MMCIDATATIMER); + writel(host->size, base + MMCIDATALENGTH); + + datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4; + if (data->flags & MMC_DATA_READ) { + datactrl |= MCI_DPSM_DIRECTION; + irqmask = MCI_RXFIFOHALFFULLMASK; + } else { + /* + * We don't actually need to include "FIFO empty" here + * since its implicit in "FIFO half empty". + */ + irqmask = MCI_TXFIFOHALFEMPTYMASK; + } + + writel(datactrl, base + MMCIDATACTRL); + writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); + writel(irqmask, base + MMCIMASK1); +} + +static void +mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) +{ + void *base = host->base; + + DBG(host, "op %02x arg %08x flags %08x\n", + cmd->opcode, cmd->arg, cmd->flags); + + if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { + writel(0, base + MMCICOMMAND); + udelay(1); + } + + c |= cmd->opcode | MCI_CPSM_ENABLE; + switch (cmd->flags & MMC_RSP_MASK) { + case MMC_RSP_NONE: + default: + break; + case MMC_RSP_LONG: + c |= MCI_CPSM_LONGRSP; + case MMC_RSP_SHORT: + c |= MCI_CPSM_RESPONSE; + break; + } + if (/*interrupt*/0) + c |= MCI_CPSM_INTERRUPT; + + host->cmd = cmd; + + writel(cmd->arg, base + MMCIARGUMENT); + writel(c, base + MMCICOMMAND); +} + +static void +mmci_data_irq(struct mmci_host *host, struct mmc_data *data, + unsigned int status) +{ + if (status & MCI_DATABLOCKEND) { + host->data_xfered += 1 << data->blksz_bits; + } + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + if (status & MCI_DATACRCFAIL) + data->error = MMC_ERR_BADCRC; + else if (status & MCI_DATATIMEOUT) + data->error = MMC_ERR_TIMEOUT; + else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) + data->error = MMC_ERR_FIFO; + status |= MCI_DATAEND; + } + if (status & MCI_DATAEND) { + mmci_stop_data(host); + + if (!data->stop) { + mmci_request_end(host, data->mrq); + } else { + mmci_start_command(host, data->stop, 0); + } + } +} + +static void +mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + unsigned int status) +{ + void *base = host->base; + + host->cmd = NULL; + + cmd->resp[0] = readl(base + MMCIRESPONSE0); + cmd->resp[1] = readl(base + MMCIRESPONSE1); + cmd->resp[2] = readl(base + MMCIRESPONSE2); + cmd->resp[3] = readl(base + MMCIRESPONSE3); + + if (status & MCI_CMDTIMEOUT) { + cmd->error = MMC_ERR_TIMEOUT; + } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { + cmd->error = MMC_ERR_BADCRC; + } + + if (!cmd->data || cmd->error != MMC_ERR_NONE) { + mmci_request_end(host, cmd->mrq); + } else if (!(cmd->data->flags & MMC_DATA_READ)) { + mmci_start_data(host, cmd->data); + } +} + +static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) +{ + void *base = host->base; + char *ptr = buffer; + u32 status; + + do { + int count = host->size - (readl(base + MMCIFIFOCNT) << 2); + + if (count > remain) + count = remain; + + if (count <= 0) + break; + + readsl(base + MMCIFIFO, ptr, count >> 2); + + ptr += count; + remain -= count; + + if (remain == 0) + break; + + status = readl(base + MMCISTATUS); + } while (status & MCI_RXDATAAVLBL); + + return ptr - buffer; +} + +static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) +{ + void *base = host->base; + char *ptr = buffer; + + do { + unsigned int count, maxcnt; + + maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; + count = min(remain, maxcnt); + + writesl(base + MMCIFIFO, ptr, count >> 2); + + ptr += count; + remain -= count; + + if (remain == 0) + break; + + status = readl(base + MMCISTATUS); + } while (status & MCI_TXFIFOHALFEMPTY); + + return ptr - buffer; +} + +/* + * PIO data transfer IRQ handler. + */ +static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmci_host *host = dev_id; + void *base = host->base; + u32 status; + + status = readl(base + MMCISTATUS); + + DBG(host, "irq1 %08x\n", status); + + do { + unsigned long flags; + unsigned int remain, len; + char *buffer; + + /* + * For write, we only need to test the half-empty flag + * here - if the FIFO is completely empty, then by + * definition it is more than half empty. + * + * For read, check for data available. + */ + if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) + break; + + /* + * Map the current scatter buffer. + */ + buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; + remain = host->sg_ptr->length - host->sg_off; + + len = 0; + if (status & MCI_RXACTIVE) + len = mmci_pio_read(host, buffer, remain); + if (status & MCI_TXACTIVE) + len = mmci_pio_write(host, buffer, remain, status); + + /* + * Unmap the buffer. + */ + mmci_kunmap_atomic(host, &flags); + + host->sg_off += len; + host->size -= len; + remain -= len; + + if (remain) + break; + + if (!mmci_next_sg(host)) + break; + + status = readl(base + MMCISTATUS); + } while (1); + + /* + * If we're nearing the end of the read, switch to + * "any data available" mode. + */ + if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) + writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + + /* + * If we run out of data, disable the data IRQs; this + * prevents a race where the FIFO becomes empty before + * the chip itself has disabled the data path, and + * stops us racing with our data end IRQ. + */ + if (host->size == 0) { + writel(0, base + MMCIMASK1); + writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); + } + + return IRQ_HANDLED; +} + +/* + * Handle completion of command and data transfers. + */ +static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmci_host *host = dev_id; + u32 status; + int ret = 0; + + spin_lock(&host->lock); + + do { + struct mmc_command *cmd; + struct mmc_data *data; + + status = readl(host->base + MMCISTATUS); + status &= readl(host->base + MMCIMASK0); + writel(status, host->base + MMCICLEAR); + + DBG(host, "irq0 %08x\n", status); + + data = host->data; + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| + MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) + mmci_data_irq(host, data, status); + + cmd = host->cmd; + if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) + mmci_cmd_irq(host, cmd, status); + + ret = 1; + } while (status); + + spin_unlock(&host->lock); + + return IRQ_RETVAL(ret); +} + +static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmci_host *host = mmc_priv(mmc); + + WARN_ON(host->mrq != NULL); + + spin_lock_irq(&host->lock); + + host->mrq = mrq; + + if (mrq->data && mrq->data->flags & MMC_DATA_READ) + mmci_start_data(host, mrq->data); + + mmci_start_command(host, mrq->cmd, 0); + + spin_unlock_irq(&host->lock); +} + +static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmci_host *host = mmc_priv(mmc); + u32 clk = 0, pwr = 0; + + DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n", + ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); + + if (ios->clock) { + if (ios->clock >= host->mclk) { + clk = MCI_CLK_BYPASS; + host->cclk = host->mclk; + } else { + clk = host->mclk / (2 * ios->clock) - 1; + if (clk > 256) + clk = 255; + host->cclk = host->mclk / (2 * (clk + 1)); + } + clk |= MCI_CLK_ENABLE; + } + + if (host->plat->translate_vdd) + pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); + + switch (ios->power_mode) { + case MMC_POWER_OFF: + break; + case MMC_POWER_UP: + pwr |= MCI_PWR_UP; + break; + case MMC_POWER_ON: + pwr |= MCI_PWR_ON; + break; + } + + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) + pwr |= MCI_ROD; + + writel(clk, host->base + MMCICLOCK); + + if (host->pwr != pwr) { + host->pwr = pwr; + writel(pwr, host->base + MMCIPOWER); + } +} + +static struct mmc_host_ops mmci_ops = { + .request = mmci_request, + .set_ios = mmci_set_ios, +}; + +static void mmci_check_status(unsigned long data) +{ + struct mmci_host *host = (struct mmci_host *)data; + unsigned int status; + + status = host->plat->status(mmc_dev(host->mmc)); + if (status ^ host->oldstat) + mmc_detect_change(host->mmc); + + host->oldstat = status; + mod_timer(&host->timer, jiffies + HZ); +} + +static int mmci_probe(struct amba_device *dev, void *id) +{ + struct mmc_platform_data *plat = dev->dev.platform_data; + struct mmci_host *host; + struct mmc_host *mmc; + int ret; + + /* must have platform data */ + if (!plat) { + ret = -EINVAL; + goto out; + } + + ret = amba_request_regions(dev, DRIVER_NAME); + if (ret) + goto out; + + mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); + if (!mmc) { + ret = -ENOMEM; + goto rel_regions; + } + + host = mmc_priv(mmc); + host->clk = clk_get(&dev->dev, "MCLK"); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + host->clk = NULL; + goto host_free; + } + + ret = clk_use(host->clk); + if (ret) + goto clk_free; + + ret = clk_enable(host->clk); + if (ret) + goto clk_unuse; + + host->plat = plat; + host->mclk = clk_get_rate(host->clk); + host->mmc = mmc; + host->base = ioremap(dev->res.start, SZ_4K); + if (!host->base) { + ret = -ENOMEM; + goto clk_disable; + } + + mmc->ops = &mmci_ops; + mmc->f_min = (host->mclk + 511) / 512; + mmc->f_max = min(host->mclk, fmax); + mmc->ocr_avail = plat->ocr_mask; + + /* + * We can do SGIO + */ + mmc->max_hw_segs = 16; + mmc->max_phys_segs = 16; + + /* + * Since we only have a 16-bit data length register, we must + * ensure that we don't exceed 2^16-1 bytes in a single request. + * Choose 64 (512-byte) sectors as the limit. + */ + mmc->max_sectors = 64; + + /* + * Set the maximum segment size. Since we aren't doing DMA + * (yet) we are only limited by the data length register. + */ + mmc->max_seg_size = mmc->max_sectors << 9; + + spin_lock_init(&host->lock); + + writel(0, host->base + MMCIMASK0); + writel(0, host->base + MMCIMASK1); + writel(0xfff, host->base + MMCICLEAR); + + ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host); + if (ret) + goto unmap; + + ret = request_irq(dev->irq[1], mmci_pio_irq, SA_SHIRQ, DRIVER_NAME " (pio)", host); + if (ret) + goto irq0_free; + + writel(MCI_IRQENABLE, host->base + MMCIMASK0); + + amba_set_drvdata(dev, mmc); + + mmc_add_host(mmc); + + printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n", + mmc->host_name, amba_rev(dev), amba_config(dev), + dev->res.start, dev->irq[0], dev->irq[1]); + + init_timer(&host->timer); + host->timer.data = (unsigned long)host; + host->timer.function = mmci_check_status; + host->timer.expires = jiffies + HZ; + add_timer(&host->timer); + + return 0; + + irq0_free: + free_irq(dev->irq[0], host); + unmap: + iounmap(host->base); + clk_disable: + clk_disable(host->clk); + clk_unuse: + clk_unuse(host->clk); + clk_free: + clk_put(host->clk); + host_free: + mmc_free_host(mmc); + rel_regions: + amba_release_regions(dev); + out: + return ret; +} + +static int mmci_remove(struct amba_device *dev) +{ + struct mmc_host *mmc = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + + del_timer_sync(&host->timer); + + mmc_remove_host(mmc); + + writel(0, host->base + MMCIMASK0); + writel(0, host->base + MMCIMASK1); + + writel(0, host->base + MMCICOMMAND); + writel(0, host->base + MMCIDATACTRL); + + free_irq(dev->irq[0], host); + free_irq(dev->irq[1], host); + + iounmap(host->base); + clk_disable(host->clk); + clk_unuse(host->clk); + clk_put(host->clk); + + mmc_free_host(mmc); + + amba_release_regions(dev); + } + + return 0; +} + +#ifdef CONFIG_PM +static int mmci_suspend(struct amba_device *dev, u32 state) +{ + struct mmc_host *mmc = amba_get_drvdata(dev); + int ret = 0; + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + + ret = mmc_suspend_host(mmc, state); + if (ret == 0) + writel(0, host->base + MMCIMASK0); + } + + return ret; +} + +static int mmci_resume(struct amba_device *dev) +{ + struct mmc_host *mmc = amba_get_drvdata(dev); + int ret = 0; + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + + writel(MCI_IRQENABLE, host->base + MMCIMASK0); + + ret = mmc_resume_host(mmc); + } + + return ret; +} +#else +#define mmci_suspend NULL +#define mmci_resume NULL +#endif + +static struct amba_id mmci_ids[] = { + { + .id = 0x00041180, + .mask = 0x000fffff, + }, + { + .id = 0x00041181, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver mmci_driver = { + .drv = { + .name = DRIVER_NAME, + }, + .probe = mmci_probe, + .remove = mmci_remove, + .suspend = mmci_suspend, + .resume = mmci_resume, + .id_table = mmci_ids, +}; + +static int __init mmci_init(void) +{ + return amba_driver_register(&mmci_driver); +} + +static void __exit mmci_exit(void) +{ + amba_driver_unregister(&mmci_driver); +} + +module_init(mmci_init); +module_exit(mmci_exit); +module_param(fmax, uint, 0444); + +MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/mmci.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,183 @@ +/* + * linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define MMCIPOWER 0x000 +#define MCI_PWR_OFF 0x00 +#define MCI_PWR_UP 0x02 +#define MCI_PWR_ON 0x03 +#define MCI_OD (1 << 6) +#define MCI_ROD (1 << 7) + +#define MMCICLOCK 0x004 +#define MCI_CLK_ENABLE (1 << 8) +#define MCI_CLK_PWRSAVE (1 << 9) +#define MCI_CLK_BYPASS (1 << 10) + +#define MMCIARGUMENT 0x008 +#define MMCICOMMAND 0x00c +#define MCI_CPSM_RESPONSE (1 << 6) +#define MCI_CPSM_LONGRSP (1 << 7) +#define MCI_CPSM_INTERRUPT (1 << 8) +#define MCI_CPSM_PENDING (1 << 9) +#define MCI_CPSM_ENABLE (1 << 10) + +#define MMCIRESPCMD 0x010 +#define MMCIRESPONSE0 0x014 +#define MMCIRESPONSE1 0x018 +#define MMCIRESPONSE2 0x01c +#define MMCIRESPONSE3 0x020 +#define MMCIDATATIMER 0x024 +#define MMCIDATALENGTH 0x028 +#define MMCIDATACTRL 0x02c +#define MCI_DPSM_ENABLE (1 << 0) +#define MCI_DPSM_DIRECTION (1 << 1) +#define MCI_DPSM_MODE (1 << 2) +#define MCI_DPSM_DMAENABLE (1 << 3) + +#define MMCIDATACNT 0x030 +#define MMCISTATUS 0x034 +#define MCI_CMDCRCFAIL (1 << 0) +#define MCI_DATACRCFAIL (1 << 1) +#define MCI_CMDTIMEOUT (1 << 2) +#define MCI_DATATIMEOUT (1 << 3) +#define MCI_TXUNDERRUN (1 << 4) +#define MCI_RXOVERRUN (1 << 5) +#define MCI_CMDRESPEND (1 << 6) +#define MCI_CMDSENT (1 << 7) +#define MCI_DATAEND (1 << 8) +#define MCI_DATABLOCKEND (1 << 10) +#define MCI_CMDACTIVE (1 << 11) +#define MCI_TXACTIVE (1 << 12) +#define MCI_RXACTIVE (1 << 13) +#define MCI_TXFIFOHALFEMPTY (1 << 14) +#define MCI_RXFIFOHALFFULL (1 << 15) +#define MCI_TXFIFOFULL (1 << 16) +#define MCI_RXFIFOFULL (1 << 17) +#define MCI_TXFIFOEMPTY (1 << 18) +#define MCI_RXFIFOEMPTY (1 << 19) +#define MCI_TXDATAAVLBL (1 << 20) +#define MCI_RXDATAAVLBL (1 << 21) + +#define MMCICLEAR 0x038 +#define MCI_CMDCRCFAILCLR (1 << 0) +#define MCI_DATACRCFAILCLR (1 << 1) +#define MCI_CMDTIMEOUTCLR (1 << 2) +#define MCI_DATATIMEOUTCLR (1 << 3) +#define MCI_TXUNDERRUNCLR (1 << 4) +#define MCI_RXOVERRUNCLR (1 << 5) +#define MCI_CMDRESPENDCLR (1 << 6) +#define MCI_CMDSENTCLR (1 << 7) +#define MCI_DATAENDCLR (1 << 8) +#define MCI_DATABLOCKENDCLR (1 << 10) + +#define MMCIMASK0 0x03c +#define MCI_CMDCRCFAILMASK (1 << 0) +#define MCI_DATACRCFAILMASK (1 << 1) +#define MCI_CMDTIMEOUTMASK (1 << 2) +#define MCI_DATATIMEOUTMASK (1 << 3) +#define MCI_TXUNDERRUNMASK (1 << 4) +#define MCI_RXOVERRUNMASK (1 << 5) +#define MCI_CMDRESPENDMASK (1 << 6) +#define MCI_CMDSENTMASK (1 << 7) +#define MCI_DATAENDMASK (1 << 8) +#define MCI_DATABLOCKENDMASK (1 << 10) +#define MCI_CMDACTIVEMASK (1 << 11) +#define MCI_TXACTIVEMASK (1 << 12) +#define MCI_RXACTIVEMASK (1 << 13) +#define MCI_TXFIFOHALFEMPTYMASK (1 << 14) +#define MCI_RXFIFOHALFFULLMASK (1 << 15) +#define MCI_TXFIFOFULLMASK (1 << 16) +#define MCI_RXFIFOFULLMASK (1 << 17) +#define MCI_TXFIFOEMPTYMASK (1 << 18) +#define MCI_RXFIFOEMPTYMASK (1 << 19) +#define MCI_TXDATAAVLBLMASK (1 << 20) +#define MCI_RXDATAAVLBLMASK (1 << 21) + +#define MMCIMASK1 0x040 +#define MMCIFIFOCNT 0x048 +#define MMCIFIFO 0x080 /* to 0x0bc */ + +#define MCI_IRQENABLE \ + (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ + MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ + MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) + +/* + * The size of the FIFO in bytes. + */ +#define MCI_FIFOSIZE (16*4) + +#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) + +#define NR_SG 16 + +struct clk; + +struct mmci_host { + void *base; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + struct mmc_host *mmc; + struct clk *clk; + + unsigned int data_xfered; + + spinlock_t lock; + + unsigned int mclk; + unsigned int cclk; + u32 pwr; + struct mmc_platform_data *plat; + + struct timer_list timer; + unsigned int oldstat; + + struct scatterlist sg[NR_SG]; + unsigned int sg_len; + + /* pio stuff */ + struct scatterlist *sg_ptr; + unsigned int sg_off; + unsigned int size; +}; + +static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) +{ + struct scatterlist *sg = host->sg; + struct request *req = data->req; + + /* + * Ideally, we want the higher levels to pass us a scatter list. + */ + host->sg_len = blk_rq_map_sg(req->q, req, sg); + host->sg_ptr = sg; + host->sg_off = 0; +} + +static inline int mmci_next_sg(struct mmci_host *host) +{ + host->sg_ptr++; + host->sg_off = 0; + return --host->sg_len; +} + +static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags) +{ + struct scatterlist *sg = host->sg_ptr; + + local_irq_save(*flags); + return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; +} + +static inline void mmci_kunmap_atomic(struct mmci_host *host, unsigned long *flags) +{ + kunmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); + local_irq_restore(*flags); +} diff -Nru a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/pxamci.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,604 @@ +/* + * linux/drivers/mmc/pxa.c - PXA MMCI driver + * + * Copyright (C) 2003 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This hardware is really sick: + * - No way to clear interrupts. + * - Have to turn off the clock whenever we touch the device. + * - Doesn't tell you how many data blocks were transferred. + * Yuck! + * + * 1 and 3 byte data transfers not supported + * max block length up to 1023 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "pxamci.h" + +#ifdef CONFIG_MMC_DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) do { } while (0) +#endif + +struct pxamci_host { + struct mmc_host *mmc; + spinlock_t lock; + struct resource *res; + void *base; + int irq; + int dma; + unsigned int clkrt; + unsigned int cmdat; + unsigned int imask; + unsigned int power_mode; + struct pxamci_platform_data *pdata; + + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + + dma_addr_t sg_dma; + struct pxa_dma_desc *sg_cpu; + + dma_addr_t dma_buf; + unsigned int dma_size; + unsigned int dma_dir; +}; + +/* + * The base MMC clock rate + */ +#define CLOCKRATE 20000000 + +static inline unsigned int ns_to_clocks(unsigned int ns) +{ + return (ns * (CLOCKRATE / 1000000) + 999) / 1000; +} + +static void pxamci_stop_clock(struct pxamci_host *host) +{ + if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { + unsigned long timeout = 10000; + unsigned int v; + + writel(STOP_CLOCK, host->base + MMC_STRPCL); + + do { + v = readl(host->base + MMC_STAT); + if (!(v & STAT_CLK_EN)) + break; + udelay(1); + } while (timeout--); + + if (v & STAT_CLK_EN) + dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); + } +} + +static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->imask &= ~mask; + writel(host->imask, host->base + MMC_I_MASK); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->imask |= mask; + writel(host->imask, host->base + MMC_I_MASK); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) +{ + unsigned int nob = data->blocks; + unsigned int timeout, size; + dma_addr_t dma; + u32 dcmd; + int i; + + host->data = data; + + if (data->flags & MMC_DATA_STREAM) + nob = 0xffff; + + writel(nob, host->base + MMC_NOB); + writel(1 << data->blksz_bits, host->base + MMC_BLKLEN); + + timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks; + writel((timeout + 255) / 256, host->base + MMC_RDTO); + + if (data->flags & MMC_DATA_READ) { + host->dma_dir = DMA_FROM_DEVICE; + dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; + DRCMRTXMMC = 0; + DRCMRRXMMC = host->dma | DRCMR_MAPVLD; + } else { + host->dma_dir = DMA_TO_DEVICE; + dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; + DRCMRRXMMC = 0; + DRCMRTXMMC = host->dma | DRCMR_MAPVLD; + } + + dcmd |= DCMD_BURST32 | DCMD_WIDTH1; + + host->dma_size = data->blocks << data->blksz_bits; + host->dma_buf = dma_map_single(mmc_dev(host->mmc), data->req->buffer, + host->dma_size, host->dma_dir); + + for (i = 0, size = host->dma_size, dma = host->dma_buf; size; i++) { + u32 len = size; + + if (len > DCMD_LENGTH) + len = 0x1000; + + if (data->flags & MMC_DATA_READ) { + host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; + host->sg_cpu[i].dtadr = dma; + } else { + host->sg_cpu[i].dsadr = dma; + host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; + } + host->sg_cpu[i].dcmd = dcmd | len; + + dma += len; + size -= len; + + if (size) { + host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * + sizeof(struct pxa_dma_desc); + } else { + host->sg_cpu[i].ddadr = DDADR_STOP; + } + } + wmb(); + + DDADR(host->dma) = host->sg_dma; + DCSR(host->dma) = DCSR_RUN; +} + +static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) +{ + WARN_ON(host->cmd != NULL); + host->cmd = cmd; + + if (cmd->flags & MMC_RSP_BUSY) + cmdat |= CMDAT_BUSY; + + switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) { + case MMC_RSP_SHORT | MMC_RSP_CRC: + cmdat |= CMDAT_RESP_SHORT; + break; + case MMC_RSP_SHORT: + cmdat |= CMDAT_RESP_R3; + break; + case MMC_RSP_LONG | MMC_RSP_CRC: + cmdat |= CMDAT_RESP_R2; + break; + default: + break; + } + + writel(cmd->opcode, host->base + MMC_CMD); + writel(cmd->arg >> 16, host->base + MMC_ARGH); + writel(cmd->arg & 0xffff, host->base + MMC_ARGL); + writel(cmdat, host->base + MMC_CMDAT); + writel(host->clkrt, host->base + MMC_CLKRT); + + writel(START_CLOCK, host->base + MMC_STRPCL); + + pxamci_enable_irq(host, END_CMD_RES); +} + +static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) +{ + DBG("PXAMCI: request done\n"); + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + mmc_request_done(host->mmc, mrq); +} + +static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) +{ + struct mmc_command *cmd = host->cmd; + int i; + u32 v; + + if (!cmd) + return 0; + + host->cmd = NULL; + + /* + * Did I mention this is Sick. We always need to + * discard the upper 8 bits of the first 16-bit word. + */ + v = readl(host->base + MMC_RES) & 0xffff; + for (i = 0; i < 4; i++) { + u32 w1 = readl(host->base + MMC_RES) & 0xffff; + u32 w2 = readl(host->base + MMC_RES) & 0xffff; + cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; + v = w2; + } + + if (stat & STAT_TIME_OUT_RESPONSE) { + cmd->error = MMC_ERR_TIMEOUT; + } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { + cmd->error = MMC_ERR_BADCRC; + } + + pxamci_disable_irq(host, END_CMD_RES); + if (host->data && cmd->error == MMC_ERR_NONE) { + pxamci_enable_irq(host, DATA_TRAN_DONE); + } else { + pxamci_finish_request(host, host->mrq); + } + + return 1; +} + +static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) +{ + struct mmc_data *data = host->data; + + if (!data) + return 0; + + DCSR(host->dma) = 0; + dma_unmap_single(mmc_dev(host->mmc), host->dma_buf, host->dma_size, + host->dma_dir); + + if (stat & STAT_READ_TIME_OUT) + data->error = MMC_ERR_TIMEOUT; + else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) + data->error = MMC_ERR_BADCRC; + + /* + * There appears to be a hardware design bug here. There seems to + * be no way to find out how much data was transferred to the card. + * This means that if there was an error on any block, we mark all + * data blocks as being in error. + */ + if (data->error == MMC_ERR_NONE) + data->bytes_xfered = data->blocks << data->blksz_bits; + else + data->bytes_xfered = 0; + + pxamci_disable_irq(host, DATA_TRAN_DONE); + + host->data = NULL; + if (host->mrq->stop && data->error == MMC_ERR_NONE) { + pxamci_stop_clock(host); + pxamci_start_cmd(host, host->mrq->stop, 0); + } else { + pxamci_finish_request(host, host->mrq); + } + + return 1; +} + +static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) +{ + struct pxamci_host *host = devid; + unsigned int ireg; + int handled = 0; + + ireg = readl(host->base + MMC_I_REG); + + DBG("PXAMCI: irq %08x\n", ireg); + + if (ireg) { + unsigned stat = readl(host->base + MMC_STAT); + + DBG("PXAMCI: stat %08x\n", stat); + + if (ireg & END_CMD_RES) + handled |= pxamci_cmd_done(host, stat); + if (ireg & DATA_TRAN_DONE) + handled |= pxamci_data_done(host, stat); + } + + return IRQ_RETVAL(handled); +} + +static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct pxamci_host *host = mmc_priv(mmc); + unsigned int cmdat; + + WARN_ON(host->mrq != NULL); + + host->mrq = mrq; + + pxamci_stop_clock(host); + + cmdat = host->cmdat; + host->cmdat &= ~CMDAT_INIT; + + if (mrq->data) { + pxamci_setup_data(host, mrq->data); + + cmdat &= ~CMDAT_BUSY; + cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; + if (mrq->data->flags & MMC_DATA_WRITE) + cmdat |= CMDAT_WRITE; + + if (mrq->data->flags & MMC_DATA_STREAM) + cmdat |= CMDAT_STREAM; + } + + pxamci_start_cmd(host, mrq->cmd, cmdat); +} + +static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct pxamci_host *host = mmc_priv(mmc); + + DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", + ios->clock, ios->power_mode, ios->vdd / 100, + ios->vdd % 100); + + if (ios->clock) { + unsigned int clk = CLOCKRATE / ios->clock; + if (CLOCKRATE / clk > ios->clock) + clk <<= 1; + host->clkrt = fls(clk) - 1; + + /* + * we write clkrt on the next command + */ + } else if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { + /* + * Ensure that the clock is off. + */ + writel(STOP_CLOCK, host->base + MMC_STRPCL); + } + + if (host->power_mode != ios->power_mode) { + host->power_mode = ios->power_mode; + + if (host->pdata && host->pdata->setpower) + host->pdata->setpower(mmc->dev, ios->vdd); + + if (ios->power_mode == MMC_POWER_ON) + host->cmdat |= CMDAT_INIT; + } + + DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n", + host->clkrt, host->cmdat); +} + +static struct mmc_host_ops pxamci_ops = { + .request = pxamci_request, + .set_ios = pxamci_set_ios, +}; + +static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs) +{ + printk(KERN_ERR "DMA%d: IRQ???\n", dma); + DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; +} + +static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs) +{ + mmc_detect_change(devid); + return IRQ_HANDLED; +} + +static int pxamci_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mmc_host *mmc; + struct pxamci_host *host = NULL; + struct resource *r; + int ret, irq; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!r || irq == NO_IRQ) + return -ENXIO; + + r = request_mem_region(r->start, SZ_4K, "PXAMCI"); + if (!r) + return -EBUSY; + + mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + mmc->ops = &pxamci_ops; + mmc->f_min = 312500; + mmc->f_max = 20000000; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->dma = -1; + host->pdata = pdev->dev.platform_data; + mmc->ocr_avail = host->pdata ? + host->pdata->ocr_mask : + MMC_VDD_32_33|MMC_VDD_33_34; + + host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); + if (!host->sg_cpu) { + ret = -ENOMEM; + goto out; + } + + spin_lock_init(&host->lock); + host->res = r; + host->irq = irq; + host->imask = TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| + END_CMD_RES|PRG_DONE|DATA_TRAN_DONE; + + host->base = ioremap(r->start, SZ_4K); + if (!host->base) { + ret = -ENOMEM; + goto out; + } + + /* + * Ensure that the host controller is shut down, and setup + * with our defaults. + */ + pxamci_stop_clock(host); + writel(0, host->base + MMC_SPI); + writel(64, host->base + MMC_RESTO); + writel(host->imask, host->base + MMC_I_MASK); + + pxa_gpio_mode(GPIO6_MMCCLK_MD); + pxa_gpio_mode(GPIO8_MMCCS0_MD); + pxa_set_cken(CKEN12_MMC, 1); + + host->dma = pxa_request_dma("PXAMCI", DMA_PRIO_LOW, pxamci_dma_irq, host); + if (host->dma < 0) { + ret = -EBUSY; + goto out; + } + + ret = request_irq(host->irq, pxamci_irq, 0, "PXAMCI", host); + if (ret) + goto out; + + dev_set_drvdata(dev, mmc); + + if (host->pdata && host->pdata->init) + host->pdata->init(dev, pxamci_detect_irq, mmc); + + mmc_add_host(mmc); + + return 0; + + out: + if (host) { + if (host->dma >= 0) + pxa_free_dma(host->dma); + if (host->base) + iounmap(host->base); + if (host->sg_cpu) + dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); + } + if (mmc) + mmc_free_host(mmc); + release_resource(r); + return ret; +} + +static int pxamci_remove(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + if (mmc) { + struct pxamci_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->exit) + host->pdata->exit(dev, mmc); + + mmc_remove_host(mmc); + + pxamci_stop_clock(host); + writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| + END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, + host->base + MMC_I_MASK); + + pxa_set_cken(CKEN12_MMC, 0); + + free_irq(host->irq, host); + pxa_free_dma(host->dma); + iounmap(host->base); + dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); + + pxa_set_cken(CKEN12_MMC, 0); + + release_resource(host->res); + + mmc_free_host(mmc); + } + return 0; +} + +#ifdef CONFIG_PM +static int pxamci_suspend(struct device *dev, u32 state, u32 level) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + int ret = 0; + + if (mmc && level == SUSPEND_DISABLE) + ret = mmc_suspend_host(mmc, state); + + return ret; +} + +static int pxamci_resume(struct device *dev, u32 level) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + int ret = 0; + + if (mmc && level == RESUME_ENABLE) + ret = mmc_resume_host(mmc); + + return ret; +} +#else +#define pxamci_suspend NULL +#define pxamci_resume NULL +#endif + +static struct device_driver pxamci_driver = { + .name = "pxa2xx-mci", + .bus = &platform_bus_type, + .probe = pxamci_probe, + .remove = pxamci_remove, + .suspend = pxamci_suspend, + .resume = pxamci_resume, +}; + +static int __init pxamci_init(void) +{ + return driver_register(&pxamci_driver); +} + +static void __exit pxamci_exit(void) +{ + driver_unregister(&pxamci_driver); +} + +module_init(pxamci_init); +module_exit(pxamci_exit); + +MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mmc/pxamci.h b/drivers/mmc/pxamci.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/pxamci.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,94 @@ +#undef MMC_STRPCL +#undef MMC_STAT +#undef MMC_CLKRT +#undef MMC_SPI +#undef MMC_CMDAT +#undef MMC_RESTO +#undef MMC_RDTO +#undef MMC_BLKLEN +#undef MMC_NOB +#undef MMC_PRTBUF +#undef MMC_I_MASK +#undef END_CMD_RES +#undef PRG_DONE +#undef DATA_TRAN_DONE +#undef MMC_I_REG +#undef MMC_CMD +#undef MMC_ARGH +#undef MMC_ARGL +#undef MMC_RES +#undef MMC_RXFIFO +#undef MMC_TXFIFO + +#define MMC_STRPCL 0x0000 +#define STOP_CLOCK (1 << 0) +#define START_CLOCK (2 << 0) + +#define MMC_STAT 0x0004 +#define STAT_END_CMD_RES (1 << 13) +#define STAT_PRG_DONE (1 << 12) +#define STAT_DATA_TRAN_DONE (1 << 11) +#define STAT_CLK_EN (1 << 8) +#define STAT_RECV_FIFO_FULL (1 << 7) +#define STAT_XMIT_FIFO_EMPTY (1 << 6) +#define STAT_RES_CRC_ERR (1 << 5) +#define STAT_SPI_READ_ERROR_TOKEN (1 << 4) +#define STAT_CRC_READ_ERROR (1 << 3) +#define STAT_CRC_WRITE_ERROR (1 << 2) +#define STAT_TIME_OUT_RESPONSE (1 << 1) +#define STAT_READ_TIME_OUT (1 << 0) + +#define MMC_CLKRT 0x0008 /* 3 bit */ + +#define MMC_SPI 0x000c +#define SPI_CS_ADDRESS (1 << 3) +#define SPI_CS_EN (1 << 2) +#define CRC_ON (1 << 1) +#define SPI_EN (1 << 0) + +#define MMC_CMDAT 0x0010 +#define CMDAT_DMAEN (1 << 7) +#define CMDAT_INIT (1 << 6) +#define CMDAT_BUSY (1 << 5) +#define CMDAT_STREAM (1 << 4) /* 1 = stream */ +#define CMDAT_WRITE (1 << 3) /* 1 = write */ +#define CMDAT_DATAEN (1 << 2) +#define CMDAT_RESP_NONE (0 << 0) +#define CMDAT_RESP_SHORT (1 << 0) +#define CMDAT_RESP_R2 (2 << 0) +#define CMDAT_RESP_R3 (3 << 0) + +#define MMC_RESTO 0x0014 /* 7 bit */ + +#define MMC_RDTO 0x0018 /* 16 bit */ + +#define MMC_BLKLEN 0x001c /* 10 bit */ + +#define MMC_NOB 0x0020 /* 16 bit */ + +#define MMC_PRTBUF 0x0024 +#define BUF_PART_FULL (1 << 0) + +#define MMC_I_MASK 0x0028 +#define TXFIFO_WR_REQ (1 << 6) +#define RXFIFO_RD_REQ (1 << 5) +#define CLK_IS_OFF (1 << 4) +#define STOP_CMD (1 << 3) +#define END_CMD_RES (1 << 2) +#define PRG_DONE (1 << 1) +#define DATA_TRAN_DONE (1 << 0) + +#define MMC_I_REG 0x002c +/* same as MMC_I_MASK */ + +#define MMC_CMD 0x0030 + +#define MMC_ARGH 0x0034 /* 16 bit */ + +#define MMC_ARGL 0x0038 /* 16 bit */ + +#define MMC_RES 0x003c /* 16 bit */ + +#define MMC_RXFIFO 0x0040 /* 8 bit */ + +#define MMC_TXFIFO 0x0044 /* 8 bit */ diff -Nru a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c --- a/drivers/mtd/chips/cfi_cmdset_0001.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/mtd/chips/cfi_cmdset_0001.c 2004-10-18 14:56:27 -07:00 @@ -603,6 +603,8 @@ } spin_unlock(&shared->lock); } + } else { + spin_unlock(&shared->lock); } } @@ -1437,8 +1439,7 @@ spin_unlock(chip->mutex); INVALIDATE_CACHED_RANGE(map, adr, len); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((chip->erase_time*HZ)/(2*1000)); + msleep(chip->erase_time / 2); spin_lock(chip->mutex); /* FIXME. Use a timer to check this, and return immediately. */ diff -Nru a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c --- a/drivers/mtd/chips/jedec_probe.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/mtd/chips/jedec_probe.c 2004-10-18 14:57:04 -07:00 @@ -29,6 +29,7 @@ #define MANUFACTURER_AMD 0x0001 #define MANUFACTURER_ATMEL 0x001f #define MANUFACTURER_FUJITSU 0x0004 +#define MANUFACTURER_HYUNDAI 0x00AD #define MANUFACTURER_INTEL 0x0089 #define MANUFACTURER_MACRONIX 0x00C2 #define MANUFACTURER_PMC 0x009D @@ -56,6 +57,7 @@ #define AM29F040 0x00A4 #define AM29LV040B 0x004F #define AM29F032B 0x0041 +#define AM29F002T 0x00B0 /* Atmel */ #define AT49BV512 0x0003 @@ -77,6 +79,8 @@ #define MBM29LV400TC 0x22B9 #define MBM29LV400BC 0x22BA +/* Hyundai */ +#define HY29F002T 0x00B0 /* Intel */ #define I28F004B3T 0x00d4 @@ -106,6 +110,7 @@ #define MX29LV160T 0x22C4 #define MX29LV160B 0x2249 #define MX29F016 0x00AD +#define MX29F002T 0x00B0 #define MX29F004T 0x0045 #define MX29F004B 0x0046 @@ -507,6 +512,17 @@ ERASEINFO(0x10000,8), } }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F002T, + .name = "AMD AM29F002T", + .DevSize = SIZE_256KiB, + .NumEraseRegions = 4, + .regions = {ERASEINFO(0x10000,3), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { .mfr_id = MANUFACTURER_ATMEL, .dev_id = AT49BV512, .name = "Atmel AT49BV512", @@ -752,6 +768,17 @@ ERASEINFO(0x04000,1) } }, { + .mfr_id = MANUFACTURER_HYUNDAI, + .dev_id = HY29F002T, + .name = "Hyundai HY29F002T", + .DevSize = SIZE_256KiB, + .NumEraseRegions = 4, + .regions = {ERASEINFO(0x10000,3), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { .mfr_id = MANUFACTURER_INTEL, .dev_id = I28F004B3B, .name = "Intel 28F004B3B", @@ -1135,6 +1162,17 @@ ERASEINFO(0x10000,7), } }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F002T, + .name = "Macronix MX29F002T", + .DevSize = SIZE_256KiB, + .NumEraseRegions = 4, + .regions = {ERASEINFO(0x10000,3), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { .mfr_id = MANUFACTURER_PMC, .dev_id = PM49FL002, .name = "PMC Pm49FL002", @@ -1209,7 +1247,7 @@ .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - regions: {ERASEINFO(0x01000,64), + .regions = {ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1221,7 +1259,7 @@ .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - regions: {ERASEINFO(0x01000,64), + .regions = {ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1570,7 +1608,7 @@ ERASEINFO(0x02000, 2), ERASEINFO(0x04000, 1), } - } + } }; diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig --- a/drivers/mtd/maps/Kconfig 2004-10-18 14:57:04 -07:00 +++ b/drivers/mtd/maps/Kconfig 2004-10-18 14:57:04 -07:00 @@ -473,6 +473,15 @@ IXDP425 and Coyote. If you have an IXP4xx based board and would like to use the flash chips on it, say 'Y'. +config MTD_IXP2000 + tristate "CFI Flash device mapped on Intel IXP2000 based systems" + depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 + help + This enables MTD access to flash devices on platforms based + on Intel's IXP2000 family of network processors such as the + IXDP2400 and IXDP2401. If you have an IXP2000 based board and + would like to use the flash chips on it, say 'Y'. + config MTD_EPXA10DB tristate "CFI Flash device mapped on Epxa10db" depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile 2004-10-18 14:55:46 -07:00 +++ b/drivers/mtd/maps/Makefile 2004-10-18 14:55:46 -07:00 @@ -62,5 +62,6 @@ obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o obj-$(CONFIG_MTD_MPC1211) += mpc1211.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o +obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c --- a/drivers/mtd/maps/amd76xrom.c 2004-10-18 14:56:21 -07:00 +++ b/drivers/mtd/maps/amd76xrom.c 2004-10-18 14:56:21 -07:00 @@ -26,7 +26,7 @@ struct amd76xrom_map_info { struct map_info map; struct mtd_info *mtd; - unsigned long window_addr; + void __iomem * window_addr; u32 window_start, window_size; struct pci_dev *pdev; struct resource window_rsrc; @@ -57,7 +57,7 @@ del_mtd_device(info->mtd); map_destroy(info->mtd); info->mtd = NULL; - info->map.virt = 0; + info->map.virt = NULL; } if (info->rom_rsrc.parent) release_resource(&info->rom_rsrc); @@ -65,8 +65,8 @@ release_resource(&info->window_rsrc); if (info->window_addr) { - iounmap((void *)(info->window_addr)); - info->window_addr = 0; + iounmap(info->window_addr); + info->window_addr = NULL; } } @@ -136,8 +136,7 @@ printk(KERN_NOTICE MOD_NAME " window : %x at %x\n", window->size, window->start); /* For write accesses caches are useless */ - info->window_addr = - (unsigned long)ioremap_nocache(window->start, + info->window_addr = ioremap_nocache(window->start, window->size); if (!info->window_addr) { @@ -163,8 +162,8 @@ } if (info->mtd) goto found_mtd; } - iounmap((void *)(info->window_addr)); - info->window_addr = 0; + iounmap(info->window_addr); + info->window_addr = NULL; /* Disable writes through the rom window */ pci_read_config_byte(pdev, 0x40, &byte); diff -Nru a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c --- a/drivers/mtd/maps/ceiva.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/mtd/maps/ceiva.c 2004-10-18 14:56:28 -07:00 @@ -103,7 +103,7 @@ unsigned long base; unsigned long size; int width; - void *vbase; + void __iomem *vbase; struct map_info *map; struct mtd_info *mtd; struct resource *res; @@ -150,7 +150,7 @@ break; } - clps[i].map->virt = (unsigned long)clps[i].vbase; + clps[i].map->virt = clps[i].vbase; clps[i].map->bankwidth = clps[i].width; clps[i].map->size = clps[i].size; diff -Nru a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c --- a/drivers/mtd/maps/edb7312.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/mtd/maps/edb7312.c 2004-10-18 14:57:05 -07:00 @@ -71,14 +71,14 @@ #endif -static int mtd_parts_nb = 0; -static struct mtd_partition *mtd_parts = 0; +static int mtd_parts_nb; +static struct mtd_partition *mtd_parts; int __init init_edb7312nor(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; - const char *part_type = 0; + const char *part_type = NULL; printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", WINDOW_SIZE, WINDOW_ADDR); @@ -92,7 +92,7 @@ simple_map_init(&edb7312nor_map); - mymtd = 0; + mymtd = NULL; type = rom_probe_types; for(; !mymtd && *type; type++) { mymtd = do_map_probe(*type, &edb7312nor_map); diff -Nru a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c --- a/drivers/mtd/maps/impa7.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/mtd/maps/impa7.c 2004-10-18 14:56:17 -07:00 @@ -77,7 +77,7 @@ { static const char *rom_probe_types[] = PROBETYPES; const char **type; - const char *part_type = 0; + const char *part_type = NULL; int i; static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { { WINDOW_ADDR0, WINDOW_SIZE0 }, @@ -99,7 +99,7 @@ } simple_map_init(&impa7_map[i]); - impa7_mtd[i] = 0; + impa7_mtd[i] = NULL; type = rom_probe_types; for(; !impa7_mtd[i] && *type; type++) { impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]); diff -Nru a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/maps/ixp2000.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,281 @@ +/* + * $Id: ixp2000.c,v 1.1 2004/09/02 00:13:41 dsaxena Exp $ + * + * drivers/mtd/maps/ixp2000.c + * + * Mapping for the Intel XScale IXP2000 based systems + * + * Copyright (C) 2002 Intel Corp. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Original Author: Naeem M Afzal + * Maintainer: Deepak Saxena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct ixp2000_flash_info { + struct mtd_info *mtd; + struct map_info map; + struct mtd_partition *partitions; + struct resource *res; + int nr_banks; +}; + +static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) +{ + unsigned long (*set_bank)(unsigned long) = + (unsigned long(*)(unsigned long))map->map_priv_2; + + return (set_bank ? set_bank(ofs) : ofs); +} + +#ifdef __ARMEB__ +/* + * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which + * causes the lower address bits to be XORed with 0x11 on 8 bit accesses + * and XORed with 0x10 on 16 bit accesses. See the spec update, erratta 44. + */ +static int errata44_workaround = 0; + +static inline unsigned long address_fix8_write(unsigned long addr) +{ + if (errata44_workaround) { + return (addr ^ 3); + } + return addr; +} +#else + +#define address_fix8_write(x) (x) +#endif + +static map_word ixp2000_flash_read8(struct map_info *map, unsigned long ofs) +{ + map_word val; + + val.x[0] = *((u8 *)(map->map_priv_1 + flash_bank_setup(map, ofs))); + return val; +} + +/* + * We can't use the standard memcpy due to the broken SlowPort + * address translation on rev A0 and A1 silicon and the fact that + * we have banked flash. + */ +static void ixp2000_flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + from = flash_bank_setup(map, from); + while(len--) + *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); +} + +static void ixp2000_flash_write8(struct map_info *map, map_word d, unsigned long ofs) +{ + *(__u8 *) (address_fix8_write(map->map_priv_1 + + flash_bank_setup(map, ofs))) = d.x[0]; +} + +static void ixp2000_flash_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + to = flash_bank_setup(map, to); + while(len--) { + unsigned long tmp = address_fix8_write(map->map_priv_1 + to++); + *(__u8 *)(tmp) = *(__u8 *)(from++); + } +} + + +static int ixp2000_flash_remove(struct device *_dev) +{ + struct platform_device *dev = to_platform_device(_dev); + struct flash_platform_data *plat = dev->dev.platform_data; + struct ixp2000_flash_info *info = dev_get_drvdata(&dev->dev); + + dev_set_drvdata(&dev->dev, NULL); + + if(!info) + return 0; + + if (info->mtd) { + del_mtd_partitions(info->mtd); + map_destroy(info->mtd); + } + if (info->map.map_priv_1) + iounmap((void *) info->map.map_priv_1); + + if (info->partitions) + kfree(info->partitions); + + if (info->res) { + release_resource(info->res); + kfree(info->res); + } + + if (plat->exit) + plat->exit(); + + return 0; +} + + +static int ixp2000_flash_probe(struct device *_dev) +{ + static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + struct platform_device *dev = to_platform_device(_dev); + struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; + struct flash_platform_data *plat; + struct ixp2000_flash_info *info; + unsigned long window_size; + int err = -1; + + if (!ixp_data) + return -ENODEV; + + plat = ixp_data->platform_data; + if (!plat) + return -ENODEV; + + window_size = dev->resource->end - dev->resource->start + 1; + dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dM)\n", + ixp_data->nr_banks, ((u32)window_size >> 20)); + + if (plat->width != 1) { + dev_err(_dev, "IXP2000 MTD map only supports 8-bit mode, asking for %d\n", + plat->width * 8); + return -EIO; + } + + info = kmalloc(sizeof(struct ixp2000_flash_info), GFP_KERNEL); + if(!info) { + err = -ENOMEM; + goto Error; + } + memzero(info, sizeof(struct ixp2000_flash_info)); + + dev_set_drvdata(&dev->dev, info); + + /* + * Tell the MTD layer we're not 1:1 mapped so that it does + * not attempt to do a direct access on us. + */ + info->map.phys = NO_XIP; + + info->nr_banks = ixp_data->nr_banks; + info->map.size = ixp_data->nr_banks * window_size; + info->map.bankwidth = 1; + + /* + * map_priv_2 is used to store a ptr to to the bank_setup routine + */ + info->map.map_priv_2 = (u32) ixp_data->bank_setup; + + info->map.name = dev->dev.bus_id; + info->map.read = ixp2000_flash_read8; + info->map.write = ixp2000_flash_write8; + info->map.copy_from = ixp2000_flash_copy_from; + info->map.copy_to = ixp2000_flash_copy_to; + + info->res = request_mem_region(dev->resource->start, + dev->resource->end - dev->resource->start + 1, + dev->dev.bus_id); + if (!info->res) { + dev_err(_dev, "Could not reserve memory region\n"); + err = -ENOMEM; + goto Error; + } + + info->map.map_priv_1 = + (unsigned long) ioremap(dev->resource->start, + dev->resource->end - dev->resource->start + 1); + if (!info->map.map_priv_1) { + dev_err(_dev, "Failed to ioremap flash region\n"); + err = -EIO; + goto Error; + } + + /* + * Setup read mode for FLASH + */ + *IXP2000_SLOWPORT_FRM = 1; + +#if defined(__ARMEB__) + /* + * Enable errata 44 workaround for NPUs with broken slowport + */ + + errata44_workaround = ixp2000_has_broken_slowport(); + dev_info(_dev, "Errata 44 workaround %s\n", + errata44_workaround ? "enabled" : "disabled"); +#endif + + info->mtd = do_map_probe(plat->map_name, &info->map); + if (!info->mtd) { + dev_err(_dev, "map_probe failed\n"); + err = -ENXIO; + goto Error; + } + info->mtd->owner = THIS_MODULE; + + err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); + if (err > 0) { + err = add_mtd_partitions(info->mtd, info->partitions, err); + if(err) + dev_err(_dev, "Could not parse partitions\n"); + } + + if (err) + goto Error; + + return 0; + +Error: + ixp2000_flash_remove(_dev); + return err; +} + +static struct device_driver ixp2000_flash_driver = { + .name = "IXP2000-Flash", + .bus = &platform_bus_type, + .probe = &ixp2000_flash_probe, + .remove = &ixp2000_flash_remove +}; + +static int __init ixp2000_flash_init(void) +{ + return driver_register(&ixp2000_flash_driver); +} + +static void __exit ixp2000_flash_exit(void) +{ + driver_unregister(&ixp2000_flash_driver); +} + +module_init(ixp2000_flash_init); +module_exit(ixp2000_flash_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena "); + diff -Nru a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c --- a/drivers/mtd/maps/ixp4xx.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/mtd/maps/ixp4xx.c 2004-10-18 14:55:54 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: ixp4xx.c,v 1.3 2004/07/12 22:38:29 dwmw2 Exp $ + * $Id: ixp4xx.c,v 1.6 2004/09/17 00:25:06 gleixner Exp $ * * drivers/mtd/maps/ixp4xx.c * @@ -69,9 +69,22 @@ dest[len - 1] = BYTE0(src[i]); } +/* + * Unaligned writes are ignored, causing the 8-bit + * probe to fail and proceed to the 16-bit probe (which succeeds). + */ +static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) +{ + if (!(adr & 1)) + *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; +} + +/* + * Fast write16 function without the probing check above + */ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) { - *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; + *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; } struct ixp4xx_flash_info { @@ -88,6 +101,7 @@ struct platform_device *dev = to_platform_device(_dev); struct flash_platform_data *plat = dev->dev.platform_data; struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); + map_word d; dev_set_drvdata(&dev->dev, NULL); @@ -97,7 +111,8 @@ /* * This is required for a soft reboot to work. */ - ixp4xx_write16(&info->map, 0xff, 0x55 * 0x2); + d.x[0] = 0xff; + ixp4xx_write16(&info->map, d, 0x55 * 0x2); if (info->mtd) { del_mtd_partitions(info->mtd); @@ -169,7 +184,7 @@ info->map.bankwidth = 2; info->map.name = dev->dev.bus_id; info->map.read = ixp4xx_read16, - info->map.write = ixp4xx_write16, + info->map.write = ixp4xx_probe_write16, info->map.copy_from = ixp4xx_copy_from, info->res = request_mem_region(dev->resource->start, @@ -182,7 +197,7 @@ } info->map.map_priv_1 = - (unsigned long) ioremap(dev->resource->start, + (void __iomem *) ioremap(dev->resource->start, dev->resource->end - dev->resource->start + 1); if (!info->map.map_priv_1) { printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); @@ -197,6 +212,9 @@ goto Error; } info->mtd->owner = THIS_MODULE; + + /* Use the fast version */ + info->map.write = ixp4xx_write16, err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); if (err > 0) { diff -Nru a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c --- a/drivers/mtd/maps/lubbock-flash.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/mtd/maps/lubbock-flash.c 2004-10-18 14:56:48 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: lubbock-flash.c,v 1.15 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: lubbock-flash.c,v 1.18 2004/09/28 18:54:40 nico Exp $ * * Map driver for the Lubbock developer platform. * @@ -15,11 +15,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include @@ -82,16 +84,14 @@ lubbock_maps[flashboot].name = "Lubbock Boot ROM"; for (i = 0; i < 2; i++) { - lubbock_maps[i].virt = (unsigned long)ioremap(lubbock_maps[i].phys, WINDOW_SIZE); + lubbock_maps[i].virt = (void __iomem *)ioremap(lubbock_maps[i].phys, WINDOW_SIZE); if (!lubbock_maps[i].virt) { printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name); if (!ret) ret = -ENOMEM; continue; } - lubbock_maps[i].cached = __ioremap(lubbock_maps[i].phys, - WINDOW_SIZE, - L_PTE_CACHEABLE, 1); + lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE); if (!lubbock_maps[i].cached) printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name); simple_map_init(&lubbock_maps[i]); diff -Nru a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c --- a/drivers/mtd/maps/nettel.c 2004-10-18 14:56:21 -07:00 +++ b/drivers/mtd/maps/nettel.c 2004-10-18 14:56:21 -07:00 @@ -180,7 +180,7 @@ if (mtd) { nettel_erase.mtd = mtd; nettel_erase.callback = nettel_erasecallback; - nettel_erase.callback = 0; + nettel_erase.callback = NULL; nettel_erase.addr = 0; nettel_erase.len = mtd->size; nettel_erase.priv = (u_long) &wait_q; diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c --- a/drivers/mtd/maps/sa1100-flash.c 2004-10-18 14:56:20 -07:00 +++ b/drivers/mtd/maps/sa1100-flash.c 2004-10-18 14:56:20 -07:00 @@ -885,7 +885,7 @@ unsigned long base; unsigned long size; int width; - void *vbase; + void __iomem *vbase; void (*set_vpp)(struct map_info *, int); struct map_info *map; struct mtd_info *mtd; @@ -932,7 +932,7 @@ break; } - sa[i].map->virt = (unsigned long)sa[i].vbase; + sa[i].map->virt = sa[i].vbase; sa[i].map->phys = sa[i].base; sa[i].map->set_vpp = sa[i].set_vpp; sa[i].map->bankwidth = sa[i].width; diff -Nru a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c --- a/drivers/mtd/maps/tqm8xxl.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/mtd/maps/tqm8xxl.c 2004-10-18 14:56:17 -07:00 @@ -50,7 +50,7 @@ static struct map_info* map_banks[FLASH_BANK_MAX]; static struct mtd_part_def part_banks[FLASH_BANK_MAX]; static unsigned long num_banks; -static unsigned long start_scan_addr; +static void __iomem *start_scan_addr; /* * Here are partition information for all known TQM8xxL series devices. @@ -121,7 +121,7 @@ flash_size = bd->bi_flashsize; //request maximum flash size address space - start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); + start_scan_addr = ioremap(flash_addr, flash_size); if (!start_scan_addr) { printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); return -EIO; @@ -231,7 +231,7 @@ } } error: - iounmap((void *)start_scan_addr); + iounmap(start_scan_addr); return ret; } @@ -250,7 +250,7 @@ } if (start_scan_addr) { - iounmap((void *)start_scan_addr); + iounmap(start_scan_addr); start_scan_addr = 0; } } diff -Nru a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c --- a/drivers/mtd/maps/uclinux.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/mtd/maps/uclinux.c 2004-10-18 14:57:03 -07:00 @@ -69,10 +69,9 @@ printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", (int) mapp->map_priv_2, (int) mapp->size); - mapp->virt = (unsigned long) - ioremap_nocache(mapp->phys, mapp->size); + mapp->virt = ioremap_nocache(mapp->phys, mapp->size); - if (mapp->virt == 0) { + if (!mapp->virt) { printk("uclinux[mtd]: ioremap_nocache() failed\n"); return(-EIO); } @@ -82,7 +81,7 @@ mtd = do_map_probe("map_ram", mapp); if (!mtd) { printk("uclinux[mtd]: failed to find a mapping?\n"); - iounmap((void *) mapp->virt); + iounmap(mapp->virt); return(-ENXIO); } diff -Nru a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c --- a/drivers/mtd/nftlmount.c 2004-10-18 14:56:34 -07:00 +++ b/drivers/mtd/nftlmount.c 2004-10-18 14:56:34 -07:00 @@ -269,7 +269,8 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, int check_oob) { - int i, retlen; + int i; + size_t retlen; u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize]; for (i = 0; i < len; i += SECTORSIZE) { @@ -366,7 +367,8 @@ { unsigned int block, i, status; struct nftl_bci bci; - int sectors_per_block, retlen; + int sectors_per_block; + size_t retlen; sectors_per_block = nftl->EraseSize / SECTORSIZE; block = first_block; diff -Nru a/drivers/net/3c507.c b/drivers/net/3c507.c --- a/drivers/net/3c507.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/3c507.c 2004-10-18 14:56:49 -07:00 @@ -294,6 +294,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad); static void init_82586_mem(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static void init_rx_bufs(struct net_device *); static int io = 0x300; static int irq; @@ -612,7 +613,6 @@ } if ((status & 0x0070) != 0x0040 && netif_running(dev)) { - static void init_rx_bufs(struct net_device *); /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ if (net_debug) diff -Nru a/drivers/net/3c527.c b/drivers/net/3c527.c --- a/drivers/net/3c527.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/net/3c527.c 2004-10-18 14:56:32 -07:00 @@ -751,18 +751,15 @@ rx_base=lp->rx_chain; - for(i=0; irx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); - skb_reserve(lp->rx_ring[i].skb, 18); - - if(lp->rx_ring[i].skb==NULL) - { - for(;i>=0;i--) + if (lp->rx_ring[i].skb==NULL) { + for (;i>=0;i--) kfree_skb(lp->rx_ring[i].skb); return -ENOBUFS; } - + skb_reserve(lp->rx_ring[i].skb, 18); + p=isa_bus_to_virt(lp->base+rx_base); p->control=0; diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c --- a/drivers/net/3c59x.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/net/3c59x.c 2004-10-18 14:55:53 -07:00 @@ -695,7 +695,7 @@ Wn2_ResetOptions=12, }; enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, + Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8, }; #define BFEXT(value, offset, bitcount) \ @@ -723,7 +723,8 @@ Media_LnkBeat = 0x0800, }; enum Window7 { /* Window 7: Bus Master control. */ - Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, + Wn7_MasterAddr = 0, Wn7_VlanEtherType=4, Wn7_MasterLen = 6, + Wn7_MasterStatus = 12, }; /* Boomerang bus master control registers. */ enum MasterCtrl { @@ -819,7 +820,8 @@ pm_state_valid:1, /* power_state[] has sane contents */ open:1, medialock:1, - must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ + must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ + large_frames:1; /* accept large frames */ int drv_flags; u16 status_enable; u16 intr_enable; @@ -900,10 +902,14 @@ static void update_stats(long ioaddr, struct net_device *dev); static struct net_device_stats *vortex_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); +#ifdef CONFIG_PCI static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#endif static void vortex_tx_timeout(struct net_device *dev); static void acpi_set_WOL(struct net_device *dev); static struct ethtool_ops vortex_ethtool_ops; +static void set_8021q_mode(struct net_device *dev, int enable); + /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Option count limit only -- unlimited interfaces are supported. */ @@ -1164,6 +1170,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; + vp->large_frames = mtu > 1500; vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; vp->io_size = vci->io_size; @@ -1290,6 +1297,13 @@ for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); } + /* Unfortunately an all zero eeprom passes the checksum and this + gets found in the wild in failure cases. Crypto is hard 8) */ + if (!is_valid_ether_addr(dev->dev_addr)) { + retval = -EINVAL; + printk(KERN_ERR "*** EEPROM MAC address is invalid.\n"); + goto free_ring; /* With every pack */ + } EL3WINDOW(2); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); @@ -1468,7 +1482,9 @@ dev->stop = vortex_close; dev->get_stats = vortex_get_stats; +#ifdef CONFIG_PCI dev->do_ioctl = vortex_ioctl; +#endif dev->ethtool_ops = &vortex_ethtool_ops; dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; @@ -1616,7 +1632,7 @@ /* Set the full-duplex bit. */ outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0) | + (vp->large_frames ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); @@ -1700,6 +1716,8 @@ } /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); + /* enable 802.1q tagged frames */ + set_8021q_mode(dev, 1); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ // issue_and_wait(dev, SetTxStart|0x07ff); @@ -1842,7 +1860,7 @@ /* Set the full-duplex bit. */ EL3WINDOW(3); outw( (vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0) | + (vp->large_frames ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) @@ -2068,6 +2086,8 @@ issue_and_wait(dev, RxReset|0x07); /* Set the Rx filter to the current state. */ set_rx_mode(dev); + /* enable 802.1q VLAN tagged frames */ + set_8021q_mode(dev, 1); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ outw(AckIntr | HostError, ioaddr + EL3_CMD); } @@ -2672,6 +2692,9 @@ outw(RxDisable, ioaddr + EL3_CMD); outw(TxDisable, ioaddr + EL3_CMD); + /* Disable receiving 802.1q tagged frames */ + set_8021q_mode(dev, 0); + if (dev->if_port == XCVR_10base2) /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); @@ -2868,6 +2891,7 @@ .get_drvinfo = vortex_get_drvinfo, }; +#ifdef CONFIG_PCI static int vortex_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct vortex_private *vp = netdev_priv(dev); @@ -2925,6 +2949,7 @@ return err; } +#endif /* Pre-Cyclone chips have no documented multicast filter, so the only @@ -2946,6 +2971,61 @@ outw(new_mode, ioaddr + EL3_CMD); } + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +/* Setup the card so that it can receive frames with an 802.1q VLAN tag. + Note that this must be done after each RxReset due to some backwards + compatibility logic in the Cyclone and Tornado ASICs */ + +/* The Ethernet Type used for 802.1q tagged frames */ +#define VLAN_ETHER_TYPE 0x8100 + +static void set_8021q_mode(struct net_device *dev, int enable) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + int old_window = inw(ioaddr + EL3_CMD); + int mac_ctrl; + + if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) { + /* cyclone and tornado chipsets can recognize 802.1q + * tagged frames and treat them correctly */ + + int max_pkt_size = dev->mtu+14; /* MTU+Ethernet header */ + if (enable) + max_pkt_size += 4; /* 802.1Q VLAN tag */ + + EL3WINDOW(3); + outw(max_pkt_size, ioaddr+Wn3_MaxPktSize); + + /* set VlanEtherType to let the hardware checksumming + treat tagged frames correctly */ + EL3WINDOW(7); + outw(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType); + } else { + /* on older cards we have to enable large frames */ + + vp->large_frames = dev->mtu > 1500 || enable; + + EL3WINDOW(3); + mac_ctrl = inw(ioaddr+Wn3_MAC_Ctrl); + if (vp->large_frames) + mac_ctrl |= 0x40; + else + mac_ctrl &= ~0x40; + outw(mac_ctrl, ioaddr+Wn3_MAC_Ctrl); + } + + EL3WINDOW(old_window); +} +#else + +static void set_8021q_mode(struct net_device *dev, int enable) +{ +} + + +#endif /* MII transceiver control section. Read and write the MII registers using software-generated serial diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c --- a/drivers/net/8139cp.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/8139cp.c 2004-10-18 14:56:29 -07:00 @@ -1698,7 +1698,7 @@ } /* Configure DMA attributes. */ - if ((sizeof(dma_addr_t) > 32) && + if ((sizeof(dma_addr_t) > 4) && !pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL) && !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { pci_using_dac = 1; diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/net/8139too.c 2004-10-18 14:55:46 -07:00 @@ -593,6 +593,7 @@ int time_to_die; struct mii_if_info mii; unsigned int regs_len; + unsigned long fifo_copy_timeout; }; MODULE_AUTHOR ("Jeff Garzik "); @@ -613,7 +614,7 @@ static int mdio_read (struct net_device *dev, int phy_id, int location); static void mdio_write (struct net_device *dev, int phy_id, int location, int val); -static inline void rtl8139_start_thread(struct net_device *dev); +static void rtl8139_start_thread(struct net_device *dev); static void rtl8139_tx_timeout (struct net_device *dev); static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, @@ -1643,7 +1644,7 @@ complete_and_exit (&tp->thr_exited, 0); } -static inline void rtl8139_start_thread(struct net_device *dev) +static void rtl8139_start_thread(struct net_device *dev) { struct rtl8139_private *tp = dev->priv; @@ -1927,6 +1928,24 @@ } #endif +static void rtl8139_isr_ack(struct rtl8139_private *tp) +{ + void *ioaddr = tp->mmio_addr; + u16 status; + + status = RTL_R16 (IntrStatus) & RxAckBits; + + /* Clear out errors and receive interrupts */ + if (likely(status != 0)) { + if (unlikely(status & (RxFIFOOver | RxOverflow))) { + tp->stats.rx_errors++; + if (status & RxFIFOOver) + tp->stats.rx_fifo_errors++; + } + RTL_W16_F (IntrStatus, RxAckBits); + } +} + static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, int budget) { @@ -1934,9 +1953,10 @@ int received = 0; unsigned char *rx_ring = tp->rx_ring; unsigned int cur_rx = tp->cur_rx; + unsigned int rx_size = 0; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, + " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); @@ -1944,10 +1964,8 @@ && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { u32 ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; - unsigned int rx_size; unsigned int pkt_size; struct sk_buff *skb; - u16 status; rmb(); @@ -1976,10 +1994,24 @@ * since EarlyRx is disabled. */ if (unlikely(rx_size == 0xfff0)) { + if (!tp->fifo_copy_timeout) + tp->fifo_copy_timeout = jiffies + 2; + else if (time_after(jiffies, tp->fifo_copy_timeout)) { + DPRINTK ("%s: hung FIFO. Reset.", dev->name); + rx_size = 0; + goto no_early_rx; + } + if (netif_msg_intr(tp)) { + printk(KERN_DEBUG "%s: fifo copy in progress.", + dev->name); + } tp->xstats.early_rx++; - goto done; + break; } +no_early_rx: + tp->fifo_copy_timeout = 0; + /* If Rx err or invalid rx_size/rx_status received * (which happens if we get lost in the ring), * Rx process gets reset, so we abort any further @@ -1989,7 +2021,8 @@ (rx_size < 8) || (!(rx_status & RxStatusOK)))) { rtl8139_rx_err (rx_status, dev, tp, ioaddr); - return -1; + received = -1; + goto out; } /* Malloc up new buffer, compatible with net-2e. */ @@ -2025,19 +2058,11 @@ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; RTL_W16 (RxBufPtr, (u16) (cur_rx - 16)); - /* Clear out errors and receive interrupts */ - status = RTL_R16 (IntrStatus) & RxAckBits; - if (likely(status != 0)) { - if (unlikely(status & (RxFIFOOver | RxOverflow))) { - tp->stats.rx_errors++; - if (status & RxFIFOOver) - tp->stats.rx_fifo_errors++; - } - RTL_W16_F (IntrStatus, RxAckBits); - } + rtl8139_isr_ack(tp); } - done: + if (unlikely(!received || rx_size == 0xfff0)) + rtl8139_isr_ack(tp); #if RTL8139_DEBUG > 1 DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," @@ -2047,6 +2072,15 @@ #endif tp->cur_rx = cur_rx; + + /* + * The receive buffer should be mostly empty. + * Tell NAPI to reenable the Rx irq. + */ + if (tp->fifo_copy_timeout) + received = budget; + +out: return received; } diff -Nru a/drivers/net/8390.c b/drivers/net/8390.c --- a/drivers/net/8390.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/net/8390.c 2004-10-18 14:55:55 -07:00 @@ -41,6 +41,8 @@ module by all drivers that require it. Alan Cox : Spinlocking work, added 'BUG_83C690' Paul Gortmaker : Separate out Tx timeout code from Tx path. + Paul Gortmaker : Remove old unused single Tx buffer code. + Hayato Fujiwara : Add m32r support. Sources: The National Semiconductor LAN Databook, and the 3Com 3c503 databook. @@ -218,6 +220,15 @@ int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; +#if defined(CONFIG_M32R) && defined(CONFIG_SMP) + unsigned long icucr; + + local_irq_save(flags); + icucr = inl(ICUCR1); + icucr |= M32R_ICUCR_ISMOD11; + outl(icucr, ICUCR1); + local_irq_restore(flags); +#endif ei_local->stat.tx_errors++; spin_lock_irqsave(&ei_local->page_lock, flags); @@ -289,8 +300,6 @@ send_length = ETH_ZLEN < length ? length : ETH_ZLEN; -#ifdef EI_PINGPONG - /* * We have two Tx slots available for use. Find the first free * slot, and then perform some sanity checks. With two Tx bufs, @@ -309,7 +318,7 @@ } else if (ei_local->tx2 == 0) { - output_page = ei_local->tx_start_page + TX_1X_PAGES; + output_page = ei_local->tx_start_page + TX_PAGES/2; ei_local->tx2 = send_length; if (ei_debug && ei_local->tx1 > 0) printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", @@ -366,28 +375,6 @@ else netif_start_queue(dev); -#else /* EI_PINGPONG */ - - /* - * Only one Tx buffer in use. You need two Tx bufs to come close to - * back-to-back transmits. Expect a 20 -> 25% performance hit on - * reasonable hardware if you only use one Tx buffer. - */ - - if (length == send_length) - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); - else { - memset(scratch, 0, ETH_ZLEN); - memcpy(scratch, skb->data, skb->len); - ei_block_output(dev, ETH_ZLEN, scratch, ei_local->tx_start_page); - } - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - dev->trans_start = jiffies; - netif_stop_queue(dev); - -#endif /* EI_PINGPONG */ - /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -590,8 +577,6 @@ outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */ -#ifdef EI_PINGPONG - /* * There are two Tx buffers, see which one finished, and trigger * the send of another one if it exists. @@ -633,13 +618,6 @@ } // else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n", // dev->name, ei_local->lasttx); - -#else /* EI_PINGPONG */ - /* - * Single Tx buffer: mark it free so another packet can be loaded. - */ - ei_local->txing = 0; -#endif /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h --- a/drivers/net/8390.h 2004-10-18 14:56:48 -07:00 +++ b/drivers/net/8390.h 2004-10-18 14:56:48 -07:00 @@ -12,17 +12,7 @@ #include #include -#define TX_2X_PAGES 12 -#define TX_1X_PAGES 6 - -/* Should always use two Tx slots to get back-to-back transmits. */ -#define EI_PINGPONG - -#ifdef EI_PINGPONG -#define TX_PAGES TX_2X_PAGES -#else -#define TX_PAGES TX_1X_PAGES -#endif +#define TX_PAGES 12 /* Two Tx slots */ #define ETHER_ADDR_LEN 6 diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig 2004-10-18 14:56:50 -07:00 +++ b/drivers/net/Kconfig 2004-10-18 14:56:50 -07:00 @@ -200,7 +200,7 @@ config MACE tristate "MACE (Power Mac ethernet) support" - depends on NET_ETHERNET && PPC_PMAC + depends on NET_ETHERNET && PPC_PMAC && PPC32 select CRC32 help Power Macintoshes and clones with Ethernet built-in on the @@ -223,7 +223,7 @@ config BMAC tristate "BMAC (G3 ethernet) support" - depends on NET_ETHERNET && PPC_PMAC + depends on NET_ETHERNET && PPC_PMAC && PPC32 select CRC32 help Say Y for support of BMAC Ethernet interfaces. These are used on G3 @@ -817,7 +817,7 @@ tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6) + depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R) help This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it @@ -1075,7 +1075,7 @@ config NE2000 tristate "NE2000/NE1000 support" - depends on NET_ISA || (Q40 && m) + depends on NET_ISA || (Q40 && m) || M32R select CRC32 ---help--- If you have a network (Ethernet) card of this type, say Y and read @@ -1353,7 +1353,7 @@ config CS89x0 tristate "CS89x0 support" - depends on NET_PCI && ISA + depends on NET_PCI && (ISA || ARCH_IXDP2X01) ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the @@ -1746,12 +1746,13 @@ tristate "VIA Velocity support" depends on NET_PCI && PCI select CRC32 + select CRC_CCITT select MII help If you have a VIA "Velocity" based network card say Y here. To compile this driver as a module, choose M here. The module - will be called via-rhine. + will be called via-velocity. config LAN_SAA9730 bool "Philips SAA9730 Ethernet support (EXPERIMENTAL)" @@ -2043,6 +2044,23 @@ To compile this driver as a module, choose M here: the module will be called r8169. This is recommended. +config R8169_NAPI + bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)" + depends on R8169 && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + See for more + information. + + If in doubt, say N. + config SK98LIN tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support" depends on PCI @@ -2130,6 +2148,45 @@ To compile this driver as a module, choose M here: the module will be called tg3. This is recommended. + +config GIANFAR + tristate "Gianfar Ethernet" + depends on 85xx + help + This driver supports the Gigabit TSEC on the MPC85xx + family of chips, and the FEC on the 8540 + +config GFAR_NAPI + bool "NAPI Support" + depends on GIANFAR + +config MV643XX_ETH + tristate "MV-643XX Ethernet support" + depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX + help + This driver supports the gigabit Ethernet on the Marvell MV643XX + chipset which is used in the Momenco Ocelot C and Jaguar ATX. + +config MV643XX_ETH_0 + bool "MV-643XX Port 0" + depends on MV643XX_ETH + help + This enables support for Port 0 of the Marvell MV643XX Gigabit + Ethernet. + +config MV643XX_ETH_1 + bool "MV-643XX Port 1" + depends on MV643XX_ETH + help + This enables support for Port 1 of the Marvell MV643XX Gigabit + Ethernet. + +config MV643XX_ETH_2 + bool "MV-643XX Port 2" + depends on MV643XX_ETH + help + This enables support for Port 2 of the Marvell MV643XX Gigabit + Ethernet. endmenu diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile 2004-10-18 14:56:27 -07:00 +++ b/drivers/net/Makefile 2004-10-18 14:56:27 -07:00 @@ -10,6 +10,9 @@ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_GIANFAR) += gianfar_driver.o + +gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o # # link order important here @@ -94,6 +97,8 @@ obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o + +obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c --- a/drivers/net/acenic.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/acenic.c 2004-10-18 14:56:29 -07:00 @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -425,13 +426,15 @@ MODULE_AUTHOR("Jes Sorensen "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); -MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i"); + +static int num_params; +module_param_array(link, int, num_params, 0); +module_param_array(trace, int, num_params, 0); +module_param_array(tx_coal_tick, int, num_params, 0); +module_param_array(max_tx_desc, int, num_params, 0); +module_param_array(rx_coal_tick, int, num_params, 0); +module_param_array(max_rx_desc, int, num_params, 0); +module_param_array(tx_ratio, int, num_params, 0); MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state"); MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level"); MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives"); @@ -474,6 +477,7 @@ ap = dev->priv; ap->pdev = pdev; + ap->name = pci_name(pdev); dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; #if ACENIC_DO_VLAN @@ -516,7 +520,7 @@ if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { printk(KERN_INFO "%s: Enabling PCI Memory Mapped " "access - was not enabled by BIOS/Firmware\n", - dev->name); + ap->name); ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY; pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); @@ -539,55 +543,40 @@ if (!ap->regs) { printk(KERN_ERR "%s: Unable to map I/O register, " "AceNIC %i will be disabled.\n", - dev->name, boards_found); + ap->name, boards_found); goto fail_free_netdev; } switch(pdev->vendor) { case PCI_VENDOR_ID_ALTEON: if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { - strncpy(ap->name, "Farallon PN9100-T " - "Gigabit Ethernet", sizeof (ap->name)); printk(KERN_INFO "%s: Farallon PN9100-T ", - dev->name); + ap->name); } else { - strncpy(ap->name, "AceNIC Gigabit Ethernet", - sizeof (ap->name)); printk(KERN_INFO "%s: Alteon AceNIC ", - dev->name); + ap->name); } break; case PCI_VENDOR_ID_3COM: - strncpy(ap->name, "3Com 3C985 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); + printk(KERN_INFO "%s: 3Com 3C985 ", ap->name); break; case PCI_VENDOR_ID_NETGEAR: - strncpy(ap->name, "NetGear GA620 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: NetGear GA620 ", dev->name); + printk(KERN_INFO "%s: NetGear GA620 ", ap->name); break; case PCI_VENDOR_ID_DEC: if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { - strncpy(ap->name, "Farallon PN9000-SX " - "Gigabit Ethernet", sizeof (ap->name)); printk(KERN_INFO "%s: Farallon PN9000-SX ", - dev->name); + ap->name); break; } case PCI_VENDOR_ID_SGI: - strncpy(ap->name, "SGI AceNIC Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: SGI AceNIC ", dev->name); + printk(KERN_INFO "%s: SGI AceNIC ", ap->name); break; default: - strncpy(ap->name, "Unknown AceNIC based Gigabit " - "Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); + printk(KERN_INFO "%s: Unknown AceNIC ", ap->name); break; } - ap->name [sizeof (ap->name) - 1] = '\0'; printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); #ifdef __sparc__ printk("irq %s\n", __irq_itoa(pdev->irq)); @@ -622,6 +611,7 @@ printk(KERN_ERR "acenic: device registration failed\n"); goto fail_uninit; } + ap->name = dev->name; if (ap->pci_using_dac) dev->features |= NETIF_F_HIGHDMA; @@ -641,7 +631,7 @@ static void __devexit acenic_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; short i; @@ -752,7 +742,7 @@ static void ace_free_descriptors(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); int size; if (ap->rx_std_ring != NULL) { @@ -802,7 +792,7 @@ static int ace_allocate_descriptors(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); int size; size = (sizeof(struct rx_desc) * @@ -873,7 +863,7 @@ { struct ace_private *ap; - ap = dev->priv; + ap = netdev_priv(dev); ace_free_descriptors(dev); @@ -921,7 +911,7 @@ short i; unsigned char cache_size; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; board_idx = ap->board_idx; @@ -1387,7 +1377,7 @@ if (board_idx == BOARD_IDX_OVERFLOW) { printk(KERN_WARNING "%s: more than %i NICs detected, " "ignoring module parameters!\n", - dev->name, ACE_MAX_MOD_PARMS); + ap->name, ACE_MAX_MOD_PARMS); } else if (board_idx >= 0) { if (tx_coal_tick[board_idx]) writel(tx_coal_tick[board_idx], @@ -1426,7 +1416,7 @@ if (option & 0x01) { printk(KERN_INFO "%s: Setting half duplex link\n", - dev->name); + ap->name); tmp &= ~LNK_FULL_DUPLEX; } if (option & 0x02) @@ -1439,7 +1429,7 @@ tmp |= LNK_1000MB; if ((option & 0x70) == 0) { printk(KERN_WARNING "%s: No media speed specified, " - "forcing auto negotiation\n", dev->name); + "forcing auto negotiation\n", ap->name); tmp |= LNK_NEGOTIATE | LNK_1000MB | LNK_100MB | LNK_10MB; } @@ -1447,12 +1437,12 @@ tmp |= LNK_NEG_FCTL; else printk(KERN_INFO "%s: Disabling flow control " - "negotiation\n", dev->name); + "negotiation\n", ap->name); if (option & 0x200) tmp |= LNK_RX_FLOW_CTL_Y; if ((option & 0x400) && (ap->version >= 2)) { printk(KERN_INFO "%s: Enabling TX flow control\n", - dev->name); + ap->name); tmp |= LNK_TX_FLOW_CTL_Y; } } @@ -1509,7 +1499,7 @@ cpu_relax(); if (!ap->fw_running) { - printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name); + printk(KERN_ERR "%s: Firmware NOT running!\n", ap->name); ace_dump_trace(ap); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); @@ -1542,13 +1532,13 @@ ace_load_std_rx_ring(ap, RX_RING_SIZE); else printk(KERN_ERR "%s: Someone is busy refilling the RX ring\n", - dev->name); + ap->name); if (ap->version >= 2) { if (!test_and_set_bit(0, &ap->mini_refill_busy)) ace_load_mini_rx_ring(ap, RX_MINI_SIZE); else printk(KERN_ERR "%s: Someone is busy refilling " - "the RX mini ring\n", dev->name); + "the RX mini ring\n", ap->name); } return 0; @@ -1564,7 +1554,7 @@ struct ace_regs *regs; int board_idx; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; board_idx = ap->board_idx; @@ -1604,7 +1594,7 @@ static void ace_watchdog(struct net_device *data) { struct net_device *dev = data; - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; /* @@ -1878,13 +1868,13 @@ { struct ace_private *ap; - ap = dev->priv; + ap = netdev_priv(dev); while (evtcsm != evtprd) { switch (ap->evt_ring[evtcsm].evt) { case E_FW_RUNNING: printk(KERN_INFO "%s: Firmware up and running\n", - dev->name); + ap->name); ap->fw_running = 1; wmb(); break; @@ -1899,7 +1889,7 @@ u32 state = readl(&ap->regs->GigLnkState); printk(KERN_WARNING "%s: Optical link UP " "(%s Duplex, Flow Control: %s%s)\n", - dev->name, + ap->name, state & LNK_FULL_DUPLEX ? "Full":"Half", state & LNK_TX_FLOW_CTL_Y ? "TX " : "", state & LNK_RX_FLOW_CTL_Y ? "RX" : ""); @@ -1907,15 +1897,15 @@ } case E_C_LINK_DOWN: printk(KERN_WARNING "%s: Optical link DOWN\n", - dev->name); + ap->name); break; case E_C_LINK_10_100: printk(KERN_WARNING "%s: 10/100BaseT link " - "UP\n", dev->name); + "UP\n", ap->name); break; default: printk(KERN_ERR "%s: Unknown optical link " - "state %02x\n", dev->name, code); + "state %02x\n", ap->name, code); } break; } @@ -1923,19 +1913,19 @@ switch(ap->evt_ring[evtcsm].code) { case E_C_ERR_INVAL_CMD: printk(KERN_ERR "%s: invalid command error\n", - dev->name); + ap->name); break; case E_C_ERR_UNIMP_CMD: printk(KERN_ERR "%s: unimplemented command " - "error\n", dev->name); + "error\n", ap->name); break; case E_C_ERR_BAD_CFG: printk(KERN_ERR "%s: bad config error\n", - dev->name); + ap->name); break; default: printk(KERN_ERR "%s: unknown error %02x\n", - dev->name, ap->evt_ring[evtcsm].code); + ap->name, ap->evt_ring[evtcsm].code); } break; case E_RESET_JUMBO_RNG: @@ -1964,13 +1954,13 @@ ap->jumbo = 0; ap->rx_jumbo_skbprd = 0; printk(KERN_INFO "%s: Jumbo ring flushed\n", - dev->name); + ap->name); clear_bit(0, &ap->jumbo_refill_busy); break; } default: printk(KERN_ERR "%s: Unhandled event 0x%02x\n", - dev->name, ap->evt_ring[evtcsm].evt); + ap->name, ap->evt_ring[evtcsm].evt); } evtcsm = (evtcsm + 1) % EVT_RING_ENTRIES; } @@ -1981,7 +1971,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); u32 idx; int mini_count = 0, std_count = 0; @@ -2108,7 +2098,7 @@ static inline void ace_tx_int(struct net_device *dev, u32 txcsm, u32 idx) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); do { struct sk_buff *skb; @@ -2181,7 +2171,7 @@ u32 txcsm, rxretcsm, rxretprd; u32 evtcsm, evtprd; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; /* @@ -2304,7 +2294,7 @@ #if ACENIC_DO_VLAN static void ace_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); unsigned long flags; local_irq_save(flags); @@ -2319,7 +2309,7 @@ static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); unsigned long flags; local_irq_save(flags); @@ -2340,7 +2330,7 @@ struct ace_regs *regs; struct cmd cmd; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; if (!(ap->fw_running)) { @@ -2407,7 +2397,7 @@ */ netif_stop_queue(dev); - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; if (ap->promisc) { @@ -2522,7 +2512,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; struct tx_desc *desc; u32 idx, flagsize; @@ -2661,7 +2651,7 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; if (new_mtu > ACE_JUMBO_MTU) @@ -2698,7 +2688,7 @@ static int ace_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; u32 link; @@ -2751,7 +2741,7 @@ static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; u32 link, speed; @@ -2814,7 +2804,7 @@ static void ace_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); strlcpy(info->driver, "acenic", sizeof(info->driver)); snprintf(info->version, sizeof(info->version), "%i.%i.%i", @@ -2844,7 +2834,7 @@ da = (u8 *)dev->dev_addr; - regs = ((struct ace_private *)dev->priv)->regs; + regs = ((struct ace_private *)netdev_priv(dev))->regs; writel(da[0] << 8 | da[1], ®s->MacAddrHi); writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5], ®s->MacAddrLo); @@ -2860,7 +2850,7 @@ static void ace_set_multicast_list(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; struct cmd cmd; @@ -2914,7 +2904,7 @@ static struct net_device_stats *ace_get_stats(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_mac_stats *mac_stats = (struct ace_mac_stats *)ap->regs->Stats; @@ -2997,12 +2987,12 @@ struct ace_private *ap; struct ace_regs *regs; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; if (!(readl(®s->CpuCtrl) & CPU_HALTED)) { printk(KERN_ERR "%s: trying to download firmware while the " - "CPU is running!\n", dev->name); + "CPU is running!\n", ap->name); return -EFAULT; } @@ -3178,6 +3168,7 @@ static int __init read_eeprom_byte(struct net_device *dev, unsigned long offset) { + struct ace_private *ap; struct ace_regs *regs; unsigned long flags; u32 local; @@ -3187,10 +3178,11 @@ if (!dev) { printk(KERN_ERR "No device!\n"); result = -ENODEV; - goto eeprom_read_error; + goto out; } - regs = ((struct ace_private *)dev->priv)->regs; + ap = netdev_priv(dev); + regs = ap->regs; /* * Don't take interrupts on this CPU will bit banging @@ -3203,7 +3195,7 @@ eeprom_prep(regs, EEPROM_WRITE_SELECT); if (eeprom_check_ack(regs)) { local_irq_restore(flags); - printk(KERN_ERR "%s: Unable to sync eeprom\n", dev->name); + printk(KERN_ERR "%s: Unable to sync eeprom\n", ap->name); result = -EIO; goto eeprom_read_error; } @@ -3212,7 +3204,7 @@ if (eeprom_check_ack(regs)) { local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set address byte 0\n", - dev->name); + ap->name); result = -EIO; goto eeprom_read_error; } @@ -3221,7 +3213,7 @@ if (eeprom_check_ack(regs)) { local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set address byte 1\n", - dev->name); + ap->name); result = -EIO; goto eeprom_read_error; } @@ -3231,7 +3223,7 @@ if (eeprom_check_ack(regs)) { local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set READ_SELECT\n", - dev->name); + ap->name); result = -EIO; goto eeprom_read_error; } @@ -3288,7 +3280,7 @@ eeprom_read_error: printk(KERN_ERR "%s: Unable to read eeprom byte 0x%02lx\n", - dev->name, offset); + ap->name, offset); goto out; } diff -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h --- a/drivers/net/acenic.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/acenic.h 2004-10-18 14:56:29 -07:00 @@ -693,7 +693,7 @@ int board_idx; u16 pci_command; u8 pci_latency; - char name[48]; + const char *name; #ifdef INDEX_DEBUG spinlock_t debug_lock __attribute__ ((aligned (SMP_CACHE_BYTES))); diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c --- a/drivers/net/amd8111e.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/amd8111e.c 2004-10-18 14:56:33 -07:00 @@ -719,7 +719,7 @@ return 0; } -#if CONFIG_AMD8111E_NAPI +#ifdef CONFIG_AMD8111E_NAPI /* This function handles the driver receive operation in polling mode */ static int amd8111e_rx_poll(struct net_device *dev, int * budget) { diff -Nru a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c --- a/drivers/net/arcnet/arc-rimi.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/arcnet/arc-rimi.c 2004-10-18 14:55:54 -07:00 @@ -231,7 +231,7 @@ static int arcrimi_reset(struct net_device *dev, int really_reset) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); @@ -252,7 +252,7 @@ static void arcrimi_setmask(struct net_device *dev, int mask) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; AINTMASK(mask); } @@ -260,7 +260,7 @@ static int arcrimi_status(struct net_device *dev) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; return ASTATUS(); } @@ -268,7 +268,7 @@ static void arcrimi_command(struct net_device *dev, int cmd) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; ACOMMAND(cmd); } @@ -277,7 +277,7 @@ void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -286,7 +286,7 @@ void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c --- a/drivers/net/arcnet/arcnet.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/net/arcnet/arcnet.c 2004-10-18 14:56:48 -07:00 @@ -401,7 +401,8 @@ lp->rfc1201.sequence = 1; /* bring up the hardware driver */ - lp->hw.open(dev); + if (lp->hw.open) + lp->hw.open(dev); if (dev->dev_addr[0] == 0) BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " diff -Nru a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c --- a/drivers/net/arcnet/com90xx.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/net/arcnet/com90xx.c 2004-10-18 14:56:48 -07:00 @@ -566,7 +566,7 @@ void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -575,7 +575,7 @@ void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c --- a/drivers/net/b44.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/b44.c 2004-10-18 14:56:29 -07:00 @@ -98,13 +98,24 @@ static void b44_init_rings(struct b44 *); static void b44_init_hw(struct b44 *); +static inline unsigned long br32(const struct b44 *bp, unsigned long reg) +{ + return readl(bp->regs + reg); +} + +static inline void bw32(const struct b44 *bp, + unsigned long reg, unsigned long val) +{ + writel(val, bp->regs + reg); +} + static int b44_wait_bit(struct b44 *bp, unsigned long reg, u32 bit, unsigned long timeout, const int clear) { unsigned long i; for (i = 0; i < timeout; i++) { - u32 val = br32(reg); + u32 val = br32(bp, reg); if (clear && !(val & bit)) break; @@ -168,7 +179,7 @@ static u32 ssb_get_core_rev(struct b44 *bp) { - return (br32(B44_SBIDHIGH) & SBIDHIGH_RC_MASK); + return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); } static u32 ssb_pci_setup(struct b44 *bp, u32 cores) @@ -180,13 +191,13 @@ ssb_get_addr(bp, SBID_REG_PCI, 0)); pci_rev = ssb_get_core_rev(bp); - val = br32(B44_SBINTVEC); + val = br32(bp, B44_SBINTVEC); val |= cores; - bw32(B44_SBINTVEC, val); + bw32(bp, B44_SBINTVEC, val); - val = br32(SSB_PCI_TRANS_2); + val = br32(bp, SSB_PCI_TRANS_2); val |= SSB_PCI_PREF | SSB_PCI_BURST; - bw32(SSB_PCI_TRANS_2, val); + bw32(bp, SSB_PCI_TRANS_2, val); pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig); @@ -195,18 +206,18 @@ static void ssb_core_disable(struct b44 *bp) { - if (br32(B44_SBTMSLOW) & SBTMSLOW_RESET) + if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) return; - bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); - bw32(B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(B44_SBTMSLOW); + br32(bp, B44_SBTMSLOW); udelay(1); - bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); + br32(bp, B44_SBTMSLOW); udelay(1); } @@ -215,31 +226,31 @@ u32 val; ssb_core_disable(bp); - bw32(B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); + br32(bp, B44_SBTMSLOW); udelay(1); /* Clear SERR if set, this is a hw bug workaround. */ - if (br32(B44_SBTMSHIGH) & SBTMSHIGH_SERR) - bw32(B44_SBTMSHIGH, 0); + if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) + bw32(bp, B44_SBTMSHIGH, 0); - val = br32(B44_SBIMSTATE); + val = br32(bp, B44_SBIMSTATE); if (val & (SBIMSTATE_IBE | SBIMSTATE_TO)) - bw32(B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); + bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); - bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); + br32(bp, B44_SBTMSLOW); udelay(1); - bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); + br32(bp, B44_SBTMSLOW); udelay(1); } static int ssb_core_unit(struct b44 *bp) { #if 0 - u32 val = br32(B44_SBADMATCH0); + u32 val = br32(bp, B44_SBADMATCH0); u32 base; type = val & SBADMATCH0_TYPE_MASK; @@ -263,7 +274,7 @@ static int ssb_is_core_up(struct b44 *bp) { - return ((br32(B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) + return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) == SBTMSLOW_CLOCK); } @@ -275,19 +286,19 @@ val |= ((u32) data[3]) << 16; val |= ((u32) data[4]) << 8; val |= ((u32) data[5]) << 0; - bw32(B44_CAM_DATA_LO, val); + bw32(bp, B44_CAM_DATA_LO, val); val = (CAM_DATA_HI_VALID | (((u32) data[0]) << 8) | (((u32) data[1]) << 0)); - bw32(B44_CAM_DATA_HI, val); - bw32(B44_CAM_CTRL, (CAM_CTRL_WRITE | + bw32(bp, B44_CAM_DATA_HI, val); + bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT))); b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); } static inline void __b44_disable_ints(struct b44 *bp) { - bw32(B44_IMASK, 0); + bw32(bp, B44_IMASK, 0); } static void b44_disable_ints(struct b44 *bp) @@ -295,34 +306,34 @@ __b44_disable_ints(bp); /* Flush posted writes. */ - br32(B44_IMASK); + br32(bp, B44_IMASK); } static void b44_enable_ints(struct b44 *bp) { - bw32(B44_IMASK, bp->imask); + bw32(bp, B44_IMASK, bp->imask); } static int b44_readphy(struct b44 *bp, int reg, u32 *val) { int err; - bw32(B44_EMAC_ISTAT, EMAC_INT_MII); - bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START | + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) | (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT))); err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); - *val = br32(B44_MDIO_DATA) & MDIO_DATA_DATA; + *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA; return err; } static int b44_writephy(struct b44 *bp, int reg, u32 val) { - bw32(B44_EMAC_ISTAT, EMAC_INT_MII); - bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START | + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) | (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | @@ -382,20 +393,20 @@ bp->flags &= ~(B44_FLAG_TX_PAUSE | B44_FLAG_RX_PAUSE); bp->flags |= pause_flags; - val = br32(B44_RXCONFIG); + val = br32(bp, B44_RXCONFIG); if (pause_flags & B44_FLAG_RX_PAUSE) val |= RXCONFIG_FLOW; else val &= ~RXCONFIG_FLOW; - bw32(B44_RXCONFIG, val); + bw32(bp, B44_RXCONFIG, val); - val = br32(B44_MAC_FLOW); + val = br32(bp, B44_MAC_FLOW); if (pause_flags & B44_FLAG_TX_PAUSE) val |= (MAC_FLOW_PAUSE_ENAB | (0xc0 & MAC_FLOW_RX_HI_WATER)); else val &= ~MAC_FLOW_PAUSE_ENAB; - bw32(B44_MAC_FLOW, val); + bw32(bp, B44_MAC_FLOW, val); } static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) @@ -491,11 +502,11 @@ val = &bp->hw_stats.tx_good_octets; for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) { - *val++ += br32(reg); + *val++ += br32(bp, reg); } val = &bp->hw_stats.rx_good_octets; for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) { - *val++ += br32(reg); + *val++ += br32(bp, reg); } } @@ -535,14 +546,14 @@ if (!netif_carrier_ok(bp->dev) && (bmsr & BMSR_LSTATUS)) { - u32 val = br32(B44_TX_CTRL); + u32 val = br32(bp, B44_TX_CTRL); u32 local_adv, remote_adv; if (bp->flags & B44_FLAG_FULL_DUPLEX) val |= TX_CTRL_DUPLEX; else val &= ~TX_CTRL_DUPLEX; - bw32(B44_TX_CTRL, val); + bw32(bp, B44_TX_CTRL, val); if (!(bp->flags & B44_FLAG_FORCE_LINK) && !b44_readphy(bp, MII_ADVERTISE, &local_adv) && @@ -587,7 +598,7 @@ { u32 cur, cons; - cur = br32(B44_DMATX_STAT) & DMATX_STAT_CDMASK; + cur = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK; cur /= sizeof(struct dma_desc); /* XXX needs updating when NETIF_F_SG is supported */ @@ -611,7 +622,7 @@ TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH) netif_wake_queue(bp->dev); - bw32(B44_GPTIMER, 0); + bw32(bp, B44_GPTIMER, 0); } /* Works like this. This chip writes a 'struct rx_header" 30 bytes @@ -708,7 +719,7 @@ u32 cons, prod; received = 0; - prod = br32(B44_DMARX_STAT) & DMARX_STAT_CDMASK; + prod = br32(bp, B44_DMARX_STAT) & DMARX_STAT_CDMASK; prod /= sizeof(struct dma_desc); cons = bp->rx_cons; @@ -787,7 +798,7 @@ } bp->rx_cons = cons; - bw32(B44_DMARX_PTR, cons * sizeof(struct dma_desc)); + bw32(bp, B44_DMARX_PTR, cons * sizeof(struct dma_desc)); return received; } @@ -851,8 +862,8 @@ spin_lock_irqsave(&bp->lock, flags); - istat = br32(B44_ISTAT); - imask = br32(B44_IMASK); + istat = br32(bp, B44_ISTAT); + imask = br32(bp, B44_IMASK); /* ??? What the fuck is the purpose of the interrupt mask * ??? register if we have to mask it out by hand anyways? @@ -872,8 +883,8 @@ dev->name); } - bw32(B44_ISTAT, istat); - br32(B44_ISTAT); + bw32(bp, B44_ISTAT, istat); + br32(bp, B44_ISTAT); } spin_unlock_irqrestore(&bp->lock, flags); return IRQ_RETVAL(handled); @@ -937,11 +948,11 @@ wmb(); - bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc)); + bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc)); if (bp->flags & B44_FLAG_BUGGY_TXPTR) - bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc)); + bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc)); if (bp->flags & B44_FLAG_REORDER_BUG) - br32(B44_DMATX_PTR); + br32(bp, B44_DMATX_PTR); if (TX_BUFFS_AVAIL(bp) < 1) netif_stop_queue(dev); @@ -1109,27 +1120,27 @@ { unsigned long reg; - bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); + bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) - br32(reg); + br32(bp, reg); for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) - br32(reg); + br32(bp, reg); } /* bp->lock is held. */ static void b44_chip_reset(struct b44 *bp) { if (ssb_is_core_up(bp)) { - bw32(B44_RCV_LAZY, 0); - bw32(B44_ENET_CTRL, ENET_CTRL_DISABLE); + bw32(bp, B44_RCV_LAZY, 0); + bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1); - bw32(B44_DMATX_CTRL, 0); + bw32(bp, B44_DMATX_CTRL, 0); bp->tx_prod = bp->tx_cons = 0; - if (br32(B44_DMARX_STAT) & DMARX_STAT_EMASK) { + if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) { b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE, 100, 0); } - bw32(B44_DMARX_CTRL, 0); + bw32(bp, B44_DMARX_CTRL, 0); bp->rx_prod = bp->rx_cons = 0; } else { ssb_pci_setup(bp, (bp->core_unit == 0 ? @@ -1142,20 +1153,20 @@ b44_clear_stats(bp); /* Make PHY accessible. */ - bw32(B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | + bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK))); - br32(B44_MDIO_CTRL); + br32(bp, B44_MDIO_CTRL); - if (!(br32(B44_DEVCTRL) & DEVCTRL_IPP)) { - bw32(B44_ENET_CTRL, ENET_CTRL_EPSEL); - br32(B44_ENET_CTRL); + if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { + bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL); + br32(bp, B44_ENET_CTRL); bp->flags &= ~B44_FLAG_INTERNAL_PHY; } else { - u32 val = br32(B44_DEVCTRL); + u32 val = br32(bp, B44_DEVCTRL); if (val & DEVCTRL_EPR) { - bw32(B44_DEVCTRL, (val & ~DEVCTRL_EPR)); - br32(B44_DEVCTRL); + bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR)); + br32(bp, B44_DEVCTRL); udelay(100); } bp->flags |= B44_FLAG_INTERNAL_PHY; @@ -1172,13 +1183,13 @@ /* bp->lock is held. */ static void __b44_set_mac_addr(struct b44 *bp) { - bw32(B44_CAM_CTRL, 0); + bw32(bp, B44_CAM_CTRL, 0); if (!(bp->dev->flags & IFF_PROMISC)) { u32 val; __b44_cam_write(bp, bp->dev->dev_addr, 0); - val = br32(B44_CAM_CTRL); - bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE); + val = br32(bp, B44_CAM_CTRL); + bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); } } @@ -1212,30 +1223,30 @@ b44_setup_phy(bp); /* Enable CRC32, set proper LED modes and power on PHY */ - bw32(B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); - bw32(B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); + bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); + bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); /* This sets the MAC address too. */ __b44_set_rx_mode(bp->dev); /* MTU + eth header + possible VLAN tag + struct rx_header */ - bw32(B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); - bw32(B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); + bw32(bp, B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); + bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); - bw32(B44_TX_WMARK, 56); /* XXX magic */ - bw32(B44_DMATX_CTRL, DMATX_CTRL_ENABLE); - bw32(B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); - bw32(B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | + bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ + bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); + bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); + bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); - bw32(B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); + bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); - bw32(B44_DMARX_PTR, bp->rx_pending); + bw32(bp, B44_DMARX_PTR, bp->rx_pending); bp->rx_prod = bp->rx_pending; - bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); + bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); - val = br32(B44_ENET_CTRL); - bw32(B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); + val = br32(bp, B44_ENET_CTRL); + bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); } static int b44_open(struct net_device *dev) @@ -1372,11 +1383,11 @@ int i=0; unsigned char zero[6] = {0,0,0,0,0,0}; - val = br32(B44_RXCONFIG); + val = br32(bp, B44_RXCONFIG); val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); if (dev->flags & IFF_PROMISC) { val |= RXCONFIG_PROMISC; - bw32(B44_RXCONFIG, val); + bw32(bp, B44_RXCONFIG, val); } else { __b44_set_mac_addr(bp); @@ -1388,9 +1399,9 @@ for(;i<64;i++) { __b44_cam_write(bp, zero, i); } - bw32(B44_RXCONFIG, val); - val = br32(B44_CAM_CTRL); - bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE); + bw32(bp, B44_RXCONFIG, val); + val = br32(bp, B44_CAM_CTRL); + bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); } } @@ -1760,7 +1771,7 @@ spin_lock_init(&bp->lock); - bp->regs = (unsigned long) ioremap(b44reg_base, b44reg_len); + bp->regs = ioremap(b44reg_base, b44reg_len); if (bp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -1826,7 +1837,7 @@ return 0; err_out_iounmap: - iounmap((void *) bp->regs); + iounmap(bp->regs); err_out_free_dev: free_netdev(dev); @@ -1848,7 +1859,7 @@ struct b44 *bp = netdev_priv(dev); unregister_netdev(dev); - iounmap((void *) bp->regs); + iounmap(bp->regs); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); diff -Nru a/drivers/net/b44.h b/drivers/net/b44.h --- a/drivers/net/b44.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/b44.h 2004-10-18 14:56:33 -07:00 @@ -395,9 +395,6 @@ #define SSB_PCI_MASK1 0xfc000000 #define SSB_PCI_MASK2 0xc0000000 -#define br32(REG) readl(bp->regs + (REG)) -#define bw32(REG,VAL) writel((VAL), bp->regs + (REG)) - /* 4400 PHY registers */ #define B44_MII_AUXCTRL 24 /* Auxiliary Control */ #define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */ @@ -530,7 +527,7 @@ struct net_device_stats stats; struct b44_hw_stats hw_stats; - unsigned long regs; + void __iomem *regs; struct pci_dev *pdev; struct net_device *dev; diff -Nru a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c --- a/drivers/net/bonding/bond_alb.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/bonding/bond_alb.c 2004-10-18 14:56:33 -07:00 @@ -1285,7 +1285,7 @@ int res = 1; skb->mac.raw = (unsigned char *)skb->data; - eth_data = (struct ethhdr *)skb->data; + eth_data = eth_hdr(skb); /* make sure that the curr_active_slave and the slaves list do * not change during tx diff -Nru a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c --- a/drivers/net/cs89x0.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/cs89x0.c 2004-10-18 14:56:49 -07:00 @@ -84,6 +84,9 @@ Oskar Schirmer : oskar@scara.com : HiCO.SH4 (superh) support added (irq#1, cs89x0_media=) + Deepak Saxena : dsaxena@plexity.net + : Intel IXDP2x01 (XScale ixp2x00 NPU) platform support + */ /* Always include 'config.h' first in case the user wants to turn on @@ -97,7 +100,11 @@ * Note that even if DMA is turned off we still support the 'dma' and 'use_dma' * module options so we don't break any startup scripts. */ +#ifndef CONFIG_ARCH_IXDP2X01 +#define ALLOW_DMA 0 +#else #define ALLOW_DMA 1 +#endif /* * Set this to zero to remove all the debug statements via @@ -162,6 +169,10 @@ static unsigned int netcard_portlist[] __initdata = { 0x0300, 0}; static unsigned int cs8900_irq_map[] = {1,0,0,0}; +#elif defined(CONFIG_ARCH_IXDP2X01) +#include +static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0}; +static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #else static unsigned int netcard_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; @@ -454,11 +465,12 @@ retval = -ENODEV; goto out2; } - ioaddr &= ~3; - outw(PP_ChipID, ioaddr + ADD_PORT); } printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); + ioaddr &= ~3; + outw(PP_ChipID, ioaddr + ADD_PORT); + if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) { printk(KERN_ERR "%s: incorrect signature 0x%x\n", dev->name, inw(ioaddr + DATA_PORT)); @@ -665,6 +677,9 @@ } else { i = lp->isa_config & INT_NO_MASK; if (lp->chip_type == CS8900) { +#ifdef CONFIG_ARCH_IXDP2X01 + i = cs8900_irq_map[0]; +#else /* Translate the IRQ using the IRQ mapping table. */ if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) printk("\ncs89x0: invalid ISA interrupt number %d\n", i); @@ -681,6 +696,7 @@ if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT) lp->irq_map = (irq_map_buff[0]>>8) | (irq_map_buff[1] << 8); } +#endif } if (!dev->irq) dev->irq = i; @@ -884,8 +900,10 @@ void __init reset_chip(struct net_device *dev) { +#ifndef CONFIG_ARCH_IXDP2X01 struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; +#endif int reset_start_time; writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); @@ -894,6 +912,7 @@ current->state = TASK_INTERRUPTIBLE; schedule_timeout(30*HZ/1000); +#ifndef CONFIG_ARCH_IXDP2X01 if (lp->chip_type != CS8900) { /* Hardware problem requires PNP registers to be reconfigured after a reset */ outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT); @@ -904,6 +923,8 @@ outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT); outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); } +#endif /* IXDP2x01 */ + /* Wait until the chip is reset */ reset_start_time = jiffies; while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) @@ -1155,12 +1176,14 @@ else #endif { +#ifndef CONFIG_ARCH_IXDP2X01 if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); ret = -EAGAIN; goto bad_out; } +#endif /* FIXME: Cirrus' release had this: */ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); /* And 2.3.47 had this: */ @@ -1575,7 +1598,9 @@ static int net_close(struct net_device *dev) { +#if ALLOW_DMA struct net_local *lp = netdev_priv(dev); +#endif netif_stop_queue(dev); diff -Nru a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h --- a/drivers/net/cs89x0.h 2004-10-18 14:56:48 -07:00 +++ b/drivers/net/cs89x0.h 2004-10-18 14:56:48 -07:00 @@ -16,6 +16,13 @@ #include +#ifdef CONFIG_ARCH_IXDP2X01 +/* IXDP2401/IXDP2801 uses dword-aligned register addressing */ +#define CS89x0_PORT(reg) ((reg) * 2) +#else +#define CS89x0_PORT(reg) (reg) +#endif + #define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ /* offset 2h -> Model/Product Number */ /* offset 3h -> Chip Revision Number */ @@ -324,16 +331,16 @@ #define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ #define PKT_START PP_TxFrame /* Start of packet RAM */ -#define RX_FRAME_PORT 0x0000 +#define RX_FRAME_PORT CS89x0_PORT(0x0000) #define TX_FRAME_PORT RX_FRAME_PORT -#define TX_CMD_PORT 0x0004 +#define TX_CMD_PORT CS89x0_PORT(0x0004) #define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ #define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ #define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ -#define TX_LEN_PORT 0x0006 -#define ISQ_PORT 0x0008 -#define ADD_PORT 0x000A -#define DATA_PORT 0x000C +#define TX_LEN_PORT CS89x0_PORT(0x0006) +#define ISQ_PORT CS89x0_PORT(0x0008) +#define ADD_PORT CS89x0_PORT(0x000A) +#define DATA_PORT CS89x0_PORT(0x000C) #define EEPROM_WRITE_EN 0x00F0 #define EEPROM_WRITE_DIS 0x0000 diff -Nru a/drivers/net/defxx.c b/drivers/net/defxx.c --- a/drivers/net/defxx.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/net/defxx.c 2004-10-18 14:55:46 -07:00 @@ -1814,16 +1814,18 @@ /* Fill the bp->stats structure with driver-maintained counters */ - bp->stats.rx_packets = bp->rcv_total_frames; - bp->stats.tx_packets = bp->xmt_total_frames; - bp->stats.rx_bytes = bp->rcv_total_bytes; - bp->stats.tx_bytes = bp->xmt_total_bytes; - bp->stats.rx_errors = (u32)(bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors); - bp->stats.tx_errors = bp->xmt_length_errors; - bp->stats.rx_dropped = bp->rcv_discards; - bp->stats.tx_dropped = bp->xmt_discards; - bp->stats.multicast = bp->rcv_multicast_frames; - bp->stats.transmit_collision = 0; /* always zero (0) for FDDI */ + bp->stats.gen.rx_packets = bp->rcv_total_frames; + bp->stats.gen.tx_packets = bp->xmt_total_frames; + bp->stats.gen.rx_bytes = bp->rcv_total_bytes; + bp->stats.gen.tx_bytes = bp->xmt_total_bytes; + bp->stats.gen.rx_errors = bp->rcv_crc_errors + + bp->rcv_frame_status_errors + + bp->rcv_length_errors; + bp->stats.gen.tx_errors = bp->xmt_length_errors; + bp->stats.gen.rx_dropped = bp->rcv_discards; + bp->stats.gen.tx_dropped = bp->xmt_discards; + bp->stats.gen.multicast = bp->rcv_multicast_frames; + bp->stats.gen.collisions = 0; /* always zero (0) for FDDI */ /* Get FDDI SMT MIB objects */ diff -Nru a/drivers/net/dl2k.h b/drivers/net/dl2k.h --- a/drivers/net/dl2k.h 2004-10-18 14:57:03 -07:00 +++ b/drivers/net/dl2k.h 2004-10-18 14:57:03 -07:00 @@ -92,7 +92,7 @@ EepromCtrl = 0x4a, ExpromAddr = 0x4c, Exprodata = 0x50, - WakeEvent0x51, + WakeEvent = 0x51, CountDown = 0x54, IntStatusAck = 0x5a, IntEnable = 0x5c, diff -Nru a/drivers/net/e100.c b/drivers/net/e100.c --- a/drivers/net/e100.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/e100.c 2004-10-18 14:57:04 -07:00 @@ -87,9 +87,8 @@ * cb_to_use is the next CB to use for queuing a command; cb_to_clean * is the next CB to check for completion; cb_to_send is the first * CB to start on in case of a previous failure to resume. CB clean - * up happens in interrupt context in response to a CU interrupt, or - * in dev->poll in the case where NAPI is enabled. cbs_avail keeps - * track of number of free CB resources available. + * up happens in interrupt context in response to a CU interrupt. + * cbs_avail keeps track of number of free CB resources available. * * Hardware padding of short packets to minimum packet size is * enabled. 82557 pads with 7Eh, while the later controllers pad @@ -112,9 +111,8 @@ * replacement RFDs cannot be allocated, or the RU goes non-active, * the RU must be restarted. Frame arrival generates an interrupt, * and Rx indication and re-allocation happen in the same context, - * therefore no locking is required. If NAPI is enabled, this work - * happens in dev->poll. A software-generated interrupt is gen- - * erated from the watchdog to recover from a failed allocation + * therefore no locking is required. A software-generated interrupt + * is generated from the watchdog to recover from a failed allocation * senario where all Rx resources have been indicated and none re- * placed. * @@ -126,8 +124,6 @@ * supported. Tx Scatter/Gather is not supported. Jumbo Frames is * not supported (hardware limitation). * - * NAPI support is enabled with CONFIG_E100_NAPI. - * * MagicPacket(tm) WoL support is enabled/disabled via ethtool. * * Thanks to JC (jchapman@katalix.com) for helping with @@ -158,7 +154,8 @@ #define DRV_NAME "e100" -#define DRV_VERSION "3.0.18" +#define DRV_EXT "-NAPI" +#define DRV_VERSION "3.0.27-k2"DRV_EXT #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" #define PFX DRV_NAME ": " @@ -201,6 +198,8 @@ INTEL_8255X_ETHERNET_DEVICE(0x1053, 5), INTEL_8255X_ETHERNET_DEVICE(0x1054, 5), INTEL_8255X_ETHERNET_DEVICE(0x1055, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1056, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1057, 5), INTEL_8255X_ETHERNET_DEVICE(0x1064, 6), INTEL_8255X_ETHERNET_DEVICE(0x1065, 6), INTEL_8255X_ETHERNET_DEVICE(0x1066, 6), @@ -242,6 +241,7 @@ phy_nsc_tx = 0x5C002000, phy_82562_et = 0x033002A8, phy_82562_em = 0x032002A8, + phy_82562_ek = 0x031002A8, phy_82562_eh = 0x017002A8, phy_unknown = 0xFFFFFFFF, }; @@ -330,11 +330,16 @@ }; enum eeprom_offsets { + eeprom_cnfg_mdix = 0x03, eeprom_id = 0x0A, eeprom_config_asf = 0x0D, eeprom_smbus_addr = 0x90, }; +enum eeprom_cnfg_mdix { + eeprom_mdix_enabled = 0x0080, +}; + enum eeprom_id { eeprom_id_wol = 0x0020, }; @@ -350,10 +355,12 @@ }; enum cb_command { + cb_nop = 0x0000, cb_iaaddr = 0x0001, cb_config = 0x0002, cb_multi = 0x0003, cb_tx = 0x0004, + cb_ucode = 0x0005, cb_dump = 0x0006, cb_tx_sf = 0x0008, cb_cid = 0x1f00, @@ -428,12 +435,14 @@ }; /* Important: keep total struct u32-aligned */ +#define UCODE_SIZE 134 struct cb { u16 status; u16 command; u32 link; union { u8 iaaddr[ETH_ALEN]; + u32 ucode[UCODE_SIZE]; struct config config; struct multi multi; struct { @@ -548,6 +557,7 @@ u32 rx_fc_pause; u32 rx_fc_unsupported; u32 rx_tco_frames; + u32 rx_over_length_errors; u8 rev_id; u16 leds; @@ -980,6 +990,27 @@ c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); } +static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + int i; + static const u32 ucode[UCODE_SIZE] = { + /* NFS packets are misinterpreted as TCO packets and + * incorrectly routed to the BMC over SMBus. This + * microcode patch checks the fragmented IP bit in the + * NFS/UDP header to distinguish between NFS and TCO. */ + 0x0EF70E36, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, + 0x1FFF1FFF, 0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, + 0x00906EFD, 0x00900EFD, 0x00E00EF8, + }; + + if(nic->mac == mac_82551_F || nic->mac == mac_82551_10) { + for(i = 0; i < UCODE_SIZE; i++) + cb->u.ucode[i] = cpu_to_le32(ucode[i]); + cb->command = cpu_to_le16(cb_ucode); + } else + cb->command = cpu_to_le16(cb_nop); +} + static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, struct sk_buff *skb) { @@ -1045,7 +1076,9 @@ mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); } - if(nic->mac >= mac_82550_D102) + if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && + (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && + (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) /* enable/disable MDI/MDI-X auto-switching */ mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); @@ -1069,6 +1102,8 @@ return err; if((err = e100_exec_cmd(nic, ruc_load_base, 0))) return err; + if((err = e100_exec_cb(nic, NULL, e100_load_ucode))) + return err; if((err = e100_exec_cb(nic, NULL, e100_configure))) return err; if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr))) @@ -1143,9 +1178,11 @@ ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + le32_to_cpu(s->tx_lost_crs); ns->rx_dropped += le32_to_cpu(s->rx_resource_errors); - ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors); + ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) + + nic->rx_over_length_errors; ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); + ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors); ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + le32_to_cpu(s->rx_alignment_errors) + @@ -1456,18 +1493,14 @@ dev_kfree_skb_any(skb); } else if(actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) { /* Don't indicate oversized frames */ - nic->net_stats.rx_over_errors++; + nic->rx_over_length_errors++; nic->net_stats.rx_dropped++; dev_kfree_skb_any(skb); } else { nic->net_stats.rx_packets++; nic->net_stats.rx_bytes += actual_size; nic->netdev->last_rx = jiffies; -#ifdef CONFIG_E100_NAPI netif_receive_skb(skb); -#else - netif_rx(skb); -#endif if(work_done) (*work_done)++; } @@ -1562,20 +1595,12 @@ if(stat_ack & stat_ack_rnr) nic->ru_running = 0; -#ifdef CONFIG_E100_NAPI e100_disable_irq(nic); netif_rx_schedule(netdev); -#else - if(stat_ack & stat_ack_rx) - e100_rx_clean(nic, NULL, 0); - if(stat_ack & stat_ack_tx) - e100_tx_clean(nic); -#endif return IRQ_HANDLED; } -#ifdef CONFIG_E100_NAPI static int e100_poll(struct net_device *netdev, int *budget) { struct nic *nic = netdev_priv(netdev); @@ -1598,7 +1623,6 @@ return 1; } -#endif #ifdef CONFIG_NET_POLL_CONTROLLER static void e100_netpoll(struct net_device *netdev) @@ -1641,7 +1665,7 @@ static int e100_asf(struct nic *nic) { /* ASF can be enabled from eeprom */ - return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) && + return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) && (nic->eeprom[eeprom_config_asf] & eeprom_asf) && !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); @@ -1961,18 +1985,27 @@ static void e100_diag_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) { + struct ethtool_cmd cmd; struct nic *nic = netdev_priv(netdev); - int i; + int i, err; memset(data, 0, E100_TEST_LEN * sizeof(u64)); data[0] = !mii_link_ok(&nic->mii); data[1] = e100_eeprom_load(nic); if(test->flags & ETH_TEST_FL_OFFLINE) { + + /* save speed, duplex & autoneg settings */ + err = mii_ethtool_gset(&nic->mii, &cmd); + if(netif_running(netdev)) e100_down(nic); data[2] = e100_self_test(nic); data[3] = e100_loopback_test(nic, lb_mac); data[4] = e100_loopback_test(nic, lb_phy); + + /* restore speed, duplex & autoneg settings */ + err = mii_ethtool_sset(&nic->mii, &cmd); + if(netif_running(netdev)) e100_up(nic); } @@ -2135,10 +2168,8 @@ SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; -#ifdef CONFIG_E100_NAPI netdev->poll = e100_poll; netdev->weight = E100_NAPI_WEIGHT; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = e100_netpoll; #endif diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h --- a/drivers/net/e1000/e1000.h 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/e1000/e1000.h 2004-10-18 14:55:54 -07:00 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include #include #include +#include #include #ifdef NETIF_F_TSO #include @@ -77,6 +79,8 @@ #define BAR_1 1 #define BAR_5 5 +#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} struct e1000_adapter; @@ -98,11 +102,12 @@ #define E1000_MAX_INTR 10 -/* How many descriptors for TX and RX ? */ +/* TX/RX descriptor defines */ #define E1000_DEFAULT_TXD 256 #define E1000_MAX_TXD 256 #define E1000_MIN_TXD 80 #define E1000_MAX_82544_TXD 4096 + #define E1000_DEFAULT_RXD 256 #define E1000_MAX_RXD 256 #define E1000_MIN_RXD 80 @@ -123,14 +128,11 @@ #define E1000_TX_HEAD_ADDR_SHIFT 7 #define E1000_PBA_TX_MASK 0xFFFF0000 -/* Flow Control High-Watermark: 5688 bytes below Rx FIFO size */ -#define E1000_FC_HIGH_DIFF 0x1638 - -/* Flow Control Low-Watermark: 5696 bytes below Rx FIFO size */ -#define E1000_FC_LOW_DIFF 0x1640 +/* Flow Control Watermarks */ +#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */ +#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */ -/* Flow Control Pause Time: 858 usec */ -#define E1000_FC_PAUSE_TIME 0x0680 +#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ /* How many Tx Descriptors do we need to call netif_wake_queue ? */ #define E1000_TX_QUEUE_WAKE 16 @@ -153,9 +155,9 @@ struct e1000_buffer { struct sk_buff *skb; uint64_t dma; - unsigned long length; unsigned long time_stamp; - unsigned int next_to_watch; + uint16_t length; + uint16_t next_to_watch; }; struct e1000_desc_ring { @@ -202,7 +204,7 @@ spinlock_t stats_lock; atomic_t irq_sem; struct work_struct tx_timeout_task; - uint8_t fc_autoneg; + uint8_t fc_autoneg; struct timer_list blink_timer; unsigned long led_status; diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/e1000/e1000_ethtool.c 2004-10-18 14:56:29 -07:00 @@ -88,9 +88,9 @@ { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, - { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, - { "rx_long_byte_count", E1000_STAT(stats.gorcl) } + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } }; #define E1000_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) @@ -170,7 +170,8 @@ ecmd->duplex = -1; } - ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) || + hw->autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; } @@ -192,6 +193,7 @@ if(netif_running(adapter->netdev)) { e1000_down(adapter); + e1000_reset(adapter); e1000_up(adapter); } else e1000_reset(adapter); @@ -199,12 +201,13 @@ return 0; } -static void +static void e1000_get_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; + pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); @@ -218,9 +221,9 @@ } } -static int +static int e1000_set_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; @@ -271,7 +274,7 @@ e1000_reset(adapter); return 0; } - + static uint32_t e1000_get_tx_csum(struct net_device *netdev) { @@ -337,7 +340,7 @@ static void e1000_get_regs(struct net_device *netdev, - struct ethtool_regs *regs, void *p) + struct ethtool_regs *regs, void *p) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; @@ -418,6 +421,10 @@ e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ + if(hw->mac_type >= e1000_82540 && + hw->media_type == e1000_media_type_copper) { + regs_buff[26] = E1000_READ_REG(hw, MANC); + } } static int @@ -438,7 +445,7 @@ int ret_val = 0; uint16_t i; - if(eeprom->len == 0) + if(eeprom->len == 0) return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); @@ -446,9 +453,9 @@ first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(uint16_t) * + eeprom_buff = kmalloc(sizeof(uint16_t) * (last_word - first_word + 1), GFP_KERNEL); - if (!eeprom_buff) + if(!eeprom_buff) return -ENOMEM; if(hw->eeprom.type == e1000_eeprom_spi) @@ -466,9 +473,8 @@ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); - - memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset%2), - eeprom->len); + memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset & 1), + eeprom->len); kfree(eeprom_buff); return ret_val; @@ -520,6 +526,7 @@ le16_to_cpus(&eeprom_buff[i]); memcpy(ptr, bytes, eeprom->len); + for (i = 0; i < last_word - first_word + 1; i++) eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); @@ -575,17 +582,16 @@ e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - int err; struct e1000_adapter *adapter = netdev->priv; e1000_mac_type mac_type = adapter->hw.mac_type; struct e1000_desc_ring *txdr = &adapter->tx_ring; struct e1000_desc_ring *rxdr = &adapter->rx_ring; - struct e1000_desc_ring tx_old, tx_new; - struct e1000_desc_ring rx_old, rx_new; + struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new; + int err; tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; - + if(netif_running(adapter->netdev)) e1000_down(adapter); @@ -600,15 +606,15 @@ E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); if(netif_running(adapter->netdev)) { - /* try to get new resources before deleting old */ + /* Try to get new resources before deleting old */ if((err = e1000_setup_rx_resources(adapter))) goto err_setup_rx; if((err = e1000_setup_tx_resources(adapter))) goto err_setup_tx; /* save the new, restore the old in order to free it, - * then restore the new back again */ - + * then restore the new back again */ + rx_new = adapter->rx_ring; tx_new = adapter->tx_ring; adapter->rx_ring = rx_old; @@ -620,6 +626,7 @@ if((err = e1000_up(adapter))) return err; } + return 0; err_setup_tx: e1000_free_rx_resources(adapter); @@ -766,13 +773,15 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) { struct net_device *netdev = adapter->netdev; - uint32_t icr, mask, i=0; + uint32_t icr, mask, i=0, shared_int = TRUE; + uint32_t irq = adapter->pdev->irq; *data = 0; /* Hook up test interrupt handler just for this test */ - if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ, - netdev->name, netdev)) { + if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) { + shared_int = FALSE; + } else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)){ *data = 1; return -1; } @@ -802,20 +811,22 @@ /* Interrupt to test */ mask = 1 << i; - /* Disable the interrupt to be reported in - * the cause register and then force the same - * interrupt and see if one gets posted. If - * an interrupt was posted to the bus, the - * test failed. - */ - adapter->test_icr = 0; - E1000_WRITE_REG(&adapter->hw, IMC, mask); - E1000_WRITE_REG(&adapter->hw, ICS, mask); - msec_delay(10); - - if(adapter->test_icr & mask) { - *data = 3; - break; + if(!shared_int) { + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, mask); + E1000_WRITE_REG(&adapter->hw, ICS, mask); + msec_delay(10); + + if(adapter->test_icr & mask) { + *data = 3; + break; + } } /* Enable the interrupt to be reported in @@ -834,20 +845,22 @@ break; } - /* Disable the other interrupts to be reported in - * the cause register and then force the other - * interrupts and see if any get posted. If - * an interrupt was posted to the bus, the - * test failed. - */ - adapter->test_icr = 0; - E1000_WRITE_REG(&adapter->hw, IMC, ~mask); - E1000_WRITE_REG(&adapter->hw, ICS, ~mask); - msec_delay(10); + if(!shared_int) { + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, ~mask); + E1000_WRITE_REG(&adapter->hw, ICS, ~mask); + msec_delay(10); - if(adapter->test_icr) { - *data = 5; - break; + if(adapter->test_icr) { + *data = 5; + break; + } } } @@ -856,7 +869,7 @@ msec_delay(10); /* Unhook test interrupt handler */ - free_irq(adapter->pdev->irq, netdev); + free_irq(irq, netdev); return *data; } @@ -1021,7 +1034,7 @@ return 0; - err_nomem: +err_nomem: e1000_free_desc_rings(adapter); return ret_val; } @@ -1312,15 +1325,15 @@ for(i = 0; i < 64; i++) { e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); - pci_dma_sync_single(pdev, txdr->buffer_info[i].dma, - txdr->buffer_info[i].length, - PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); } E1000_WRITE_REG(&adapter->hw, TDT, i); msec_delay(200); - pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma, + pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[0].dma, rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024); @@ -1357,7 +1370,7 @@ } static void -e1000_diag_test(struct net_device *netdev, +e1000_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, uint64_t *data) { struct e1000_adapter *adapter = netdev->priv; @@ -1368,7 +1381,7 @@ /* save speed, duplex, autoneg settings */ uint16_t autoneg_advertised = adapter->hw.autoneg_advertised; - uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; + uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; uint8_t autoneg = adapter->hw.autoneg; /* Link test performed before hardware reset so autoneg doesn't @@ -1396,10 +1409,11 @@ if(e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; - /* restore Autoneg/speed/duplex settings */ + /* restore speed, duplex, autoneg settings */ adapter->hw.autoneg_advertised = autoneg_advertised; - adapter->hw.forced_speed_duplex = forced_speed_duplex; - adapter->hw.autoneg = autoneg; + adapter->hw.forced_speed_duplex = forced_speed_duplex; + adapter->hw.autoneg = autoneg; + e1000_reset(adapter); if(if_running) e1000_up(adapter); @@ -1427,6 +1441,7 @@ case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: wol->supported = 0; wol->wolopts = 0; return; @@ -1469,6 +1484,7 @@ case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: return wol->wolopts ? -EOPNOTSUPP : 0; case E1000_DEV_ID_82546EB_FIBER: @@ -1571,8 +1587,8 @@ e1000_update_stats(adapter); for(i = 0; i < E1000_STATS_LEN; i++) { char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; - data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) - ? *(uint64_t *)p : *(uint32_t *)p; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; } } diff -Nru a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c --- a/drivers/net/e1000/e1000_hw.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/e1000/e1000_hw.c 2004-10-18 14:57:04 -07:00 @@ -251,6 +251,7 @@ break; case E1000_DEV_ID_82541ER: case E1000_DEV_ID_82541GI: + case E1000_DEV_ID_82541GI_LF: case E1000_DEV_ID_82541GI_MOBILE: hw->mac_type = e1000_82541_rev_2; break; @@ -920,7 +921,8 @@ if(ret_val) return ret_val; - if(hw->mac_type == e1000_82545_rev_3) { + if((hw->mac_type == e1000_82545_rev_3) || + (hw->mac_type == e1000_82546_rev_3)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); phy_data |= 0x00000008; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); @@ -3057,16 +3059,6 @@ } break; default: - eeprom->type = e1000_eeprom_spi; - eeprom->opcode_bits = 8; - eeprom->delay_usec = 1; - if (eecd & E1000_EECD_ADDR_BITS) { - eeprom->page_size = 32; - eeprom->address_bits = 16; - } else { - eeprom->page_size = 8; - eeprom->address_bits = 8; - } break; } @@ -3453,7 +3445,6 @@ uint32_t i = 0; DEBUGFUNC("e1000_read_eeprom"); - /* A check for invalid values: offset too large, too many words, and not * enough words. */ @@ -5224,3 +5215,4 @@ } return FALSE; } + diff -Nru a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h --- a/drivers/net/e1000/e1000_hw.h 2004-10-18 14:56:50 -07:00 +++ b/drivers/net/e1000/e1000_hw.h 2004-10-18 14:56:50 -07:00 @@ -357,11 +357,11 @@ #define E1000_DEV_ID_82547GI 0x1075 #define E1000_DEV_ID_82541GI 0x1076 #define E1000_DEV_ID_82541GI_MOBILE 0x1077 +#define E1000_DEV_ID_82541GI_LF 0x107C #define E1000_DEV_ID_82546GB_COPPER 0x1079 #define E1000_DEV_ID_82546GB_FIBER 0x107A #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82547EI 0x1019 - #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -1043,7 +1043,6 @@ #define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ #define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ - /* Register Bit Masks */ /* Device Control */ #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/e1000/e1000_main.c 2004-10-18 14:56:28 -07:00 @@ -27,73 +27,69 @@ *******************************************************************************/ #include "e1000.h" -#include /* Change Log + * 5.3.12 6/7/04 + * - kcompat NETIF_MSG for older kernels (2.4.9) + * - if_mii support and associated kcompat for older kernels + * - More errlogging support from Jon Mason + * - Fix TSO issues on PPC64 machines -- Jon Mason * - * 5.2.51 5/14/04 - * o set default configuration to 'NAPI disabled'. NAPI enabled driver - * causes kernel panic when the interface is shutdown while data is being - * transferred. - * 5.2.47 5/04/04 - * o fixed ethtool -t implementation - * 5.2.45 4/29/04 - * o fixed ethtool -e implementation - * o Support for ethtool ops [Stephen Hemminger (shemminger@osdl.org)] - * 5.2.42 4/26/04 - * o Added support for the DPRINTK macro for enhanced error logging. Some - * parts of the patch were supplied by Jon Mason. - * o Move the register_netdevice() donw in the probe routine due to a - * loading/unloading test issue. - * o Added a long RX byte count the the extra ethtool data members for BER - * testing purposes. - * 5.2.39 3/12/04 + * 5.3.11 6/4/04 + * - ethtool register dump reads MANC register conditionally. + * + * 5.3.10 6/1/04 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.52-k4"; +#ifndef CONFIG_E1000_NAPI +#define DRIVERNAPI +#else +#define DRIVERNAPI "-NAPI" +#endif +char e1000_driver_version[] = "5.3.19-k2"DRIVERNAPI; char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * - * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, - * Class, Class Mask, private data (not used) } + * Macro expands to... + * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} */ static struct pci_device_id e1000_pci_tbl[] = { - {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + INTEL_E1000_ETHERNET_DEVICE(0x1000), + INTEL_E1000_ETHERNET_DEVICE(0x1001), + INTEL_E1000_ETHERNET_DEVICE(0x1004), + INTEL_E1000_ETHERNET_DEVICE(0x1008), + INTEL_E1000_ETHERNET_DEVICE(0x1009), + INTEL_E1000_ETHERNET_DEVICE(0x100C), + INTEL_E1000_ETHERNET_DEVICE(0x100D), + INTEL_E1000_ETHERNET_DEVICE(0x100E), + INTEL_E1000_ETHERNET_DEVICE(0x100F), + INTEL_E1000_ETHERNET_DEVICE(0x1010), + INTEL_E1000_ETHERNET_DEVICE(0x1011), + INTEL_E1000_ETHERNET_DEVICE(0x1012), + INTEL_E1000_ETHERNET_DEVICE(0x1013), + INTEL_E1000_ETHERNET_DEVICE(0x1015), + INTEL_E1000_ETHERNET_DEVICE(0x1016), + INTEL_E1000_ETHERNET_DEVICE(0x1017), + INTEL_E1000_ETHERNET_DEVICE(0x1018), + INTEL_E1000_ETHERNET_DEVICE(0x1019), + INTEL_E1000_ETHERNET_DEVICE(0x101D), + INTEL_E1000_ETHERNET_DEVICE(0x101E), + INTEL_E1000_ETHERNET_DEVICE(0x1026), + INTEL_E1000_ETHERNET_DEVICE(0x1027), + INTEL_E1000_ETHERNET_DEVICE(0x1028), + INTEL_E1000_ETHERNET_DEVICE(0x1075), + INTEL_E1000_ETHERNET_DEVICE(0x1076), + INTEL_E1000_ETHERNET_DEVICE(0x1077), + INTEL_E1000_ETHERNET_DEVICE(0x1078), + INTEL_E1000_ETHERNET_DEVICE(0x1079), + INTEL_E1000_ETHERNET_DEVICE(0x107A), + INTEL_E1000_ETHERNET_DEVICE(0x107B), + INTEL_E1000_ETHERNET_DEVICE(0x107C), /* required last entry */ {0,} }; @@ -132,8 +128,8 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); -static inline void e1000_irq_disable(struct e1000_adapter *adapter); -static inline void e1000_irq_enable(struct e1000_adapter *adapter); +static void e1000_irq_disable(struct e1000_adapter *adapter); +static void e1000_irq_enable(struct e1000_adapter *adapter); static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); #ifdef CONFIG_E1000_NAPI @@ -150,9 +146,9 @@ void set_ethtool_ops(struct net_device *netdev); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); -static inline void e1000_rx_checksum(struct e1000_adapter *adapter, - struct e1000_rx_desc *rx_desc, - struct sk_buff *skb); +static void e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb); static void e1000_tx_timeout(struct net_device *dev); static void e1000_tx_timeout_task(struct net_device *dev); static void e1000_smartspeed(struct e1000_adapter *adapter); @@ -172,7 +168,7 @@ #ifdef CONFIG_NET_POLL_CONTROLLER /* for netdump / net console */ -static void e1000_netpoll (struct net_device *dev); +static void e1000_netpoll (struct net_device *netdev); #endif struct notifier_block e1000_notifier_reboot = { @@ -185,7 +181,6 @@ extern void e1000_check_options(struct e1000_adapter *adapter); - static struct pci_driver e1000_driver = { .name = e1000_driver_name, .id_table = e1000_pci_tbl, @@ -202,7 +197,7 @@ MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); MODULE_LICENSE("GPL"); -static int debug = 3; +static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); @@ -256,6 +251,14 @@ /* hardware has been reset, we need to reload some things */ + /* Reset the PHY if it was previously powered down */ + if(adapter->hw.media_type == e1000_media_type_copper) { + uint16_t mii_reg; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + if(mii_reg & MII_CR_POWER_DOWN) + e1000_phy_reset(&adapter->hw); + } + e1000_set_multi(netdev); e1000_restore_vlan(adapter); @@ -294,6 +297,15 @@ e1000_reset(adapter); e1000_clean_tx_ring(adapter); e1000_clean_rx_ring(adapter); + + /* If WoL is not enabled + * Power down the PHY so no link is implied when interface is down */ + if(!adapter->wol && adapter->hw.media_type == e1000_media_type_copper) { + uint16_t mii_reg; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); + } } void @@ -323,10 +335,10 @@ E1000_WRITE_REG(&adapter->hw, PBA, pba); /* flow control settings */ - adapter->hw.fc_high_water = - (pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_HIGH_DIFF; - adapter->hw.fc_low_water = - (pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_LOW_DIFF; + adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) - + E1000_FC_HIGH_DIFF; + adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) - + E1000_FC_LOW_DIFF; adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; adapter->hw.fc_send_xon = 1; adapter->hw.fc = adapter->hw.original_fc; @@ -334,7 +346,8 @@ e1000_reset_hw(&adapter->hw); if(adapter->hw.mac_type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, WUC, 0); - e1000_init_hw(&adapter->hw); + if(e1000_init_hw(&adapter->hw)) + DPRINTK(PROBE, ERR, "Hardware Error\n"); /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); @@ -410,8 +423,8 @@ adapter->msg_enable = (1 << debug) - 1; rtnl_lock(); - /* we need to set the name early since the DPRINTK macro needs it set */ - if (dev_alloc_name(netdev, netdev->name) < 0) + /* we need to set the name early for the DPRINTK macro */ + if(dev_alloc_name(netdev, netdev->name) < 0) goto err_free_unlock; mmio_start = pci_resource_start(pdev, BAR_0); @@ -476,7 +489,6 @@ } #ifdef NETIF_F_TSO -#ifdef BROKEN_ON_NON_IA_ARCHS /* Disbaled for now until root-cause is found for * hangs reported against non-IA archs. TSO can be * enabled using ethtool -K eth tso on */ @@ -484,11 +496,12 @@ (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; #endif -#endif - if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; + /* hard_start_xmit is safe against parallel locking */ + netdev->features |= NETIF_F_LLTX; + adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw); /* before reading the EEPROM, reset the controller to @@ -506,10 +519,12 @@ /* copy the MAC address out of the EEPROM */ - e1000_read_mac_addr(&adapter->hw); + if (e1000_read_mac_addr(&adapter->hw)) + DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); if(!is_valid_ether_addr(netdev->dev_addr)) { + DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; } @@ -569,10 +584,9 @@ adapter->wol |= E1000_WUFC_MAG; /* reset the hardware with the new settings */ - e1000_reset(adapter); - /* since we are holding the rtnl lock already, call the no-lock version */ + /* We're already holding the rtnl lock; call the no-lock version */ if((err = register_netdevice(netdev))) goto err_register; @@ -663,7 +677,7 @@ /* identify the MAC */ - if (e1000_set_mac_type(hw)) { + if(e1000_set_mac_type(hw)) { DPRINTK(PROBE, ERR, "Unknown MAC Type\n"); return -EIO; } @@ -672,19 +686,19 @@ e1000_init_eeprom_params(hw); - if((hw->mac_type == e1000_82541) || - (hw->mac_type == e1000_82547) || - (hw->mac_type == e1000_82541_rev_2) || - (hw->mac_type == e1000_82547_rev_2)) + switch(hw->mac_type) { + default: + break; + case e1000_82541: + case e1000_82547: + case e1000_82541_rev_2: + case e1000_82547_rev_2: hw->phy_init_script = 1; + break; + } e1000_set_media_type(hw); - if(hw->mac_type < e1000_82543) - hw->report_tx_early = 0; - else - hw->report_tx_early = 1; - hw->wait_autoneg_complete = FALSE; hw->tbi_compatibility_en = TRUE; hw->adaptive_ifs = TRUE; @@ -736,7 +750,7 @@ if((err = e1000_up(adapter))) goto err_up; - return 0; + return E1000_SUCCESS; err_up: e1000_free_rx_resources(adapter); @@ -788,8 +802,10 @@ int size; size = sizeof(struct e1000_buffer) * txdr->count; - txdr->buffer_info = kmalloc(size, GFP_KERNEL); + txdr->buffer_info = vmalloc(size); if(!txdr->buffer_info) { + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Transmit descriptor ring\n"); return -ENOMEM; } memset(txdr->buffer_info, 0, size); @@ -801,7 +817,9 @@ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); if(!txdr->desc) { - kfree(txdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Transmit descriptor ring\n"); + vfree(txdr->buffer_info); return -ENOMEM; } memset(txdr->desc, 0, txdr->size); @@ -878,10 +896,10 @@ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - if(adapter->hw.report_tx_early == 1) - adapter->txd_cmd |= E1000_TXD_CMD_RS; - else + if(adapter->hw.mac_type < e1000_82543) adapter->txd_cmd |= E1000_TXD_CMD_RPS; + else + adapter->txd_cmd |= E1000_TXD_CMD_RS; /* Cache if we're 82544 running in PCI-X because we'll * need this to apply a workaround later in the send path. */ @@ -905,8 +923,10 @@ int size; size = sizeof(struct e1000_buffer) * rxdr->count; - rxdr->buffer_info = kmalloc(size, GFP_KERNEL); + rxdr->buffer_info = vmalloc(size); if(!rxdr->buffer_info) { + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Recieve descriptor ring\n"); return -ENOMEM; } memset(rxdr->buffer_info, 0, size); @@ -919,7 +939,9 @@ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); if(!rxdr->desc) { - kfree(rxdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Recieve descriptor ring\n"); + vfree(rxdr->buffer_info); return -ENOMEM; } memset(rxdr->desc, 0, rxdr->size); @@ -953,7 +975,9 @@ else rctl &= ~E1000_RCTL_SBP; + /* Setup buffer sizes */ rctl &= ~(E1000_RCTL_SZ_4096); + rctl |= (E1000_RCTL_BSEX | E1000_RCTL_LPE); switch (adapter->rx_buffer_len) { case E1000_RXBUFFER_2048: default: @@ -961,13 +985,13 @@ rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE); break; case E1000_RXBUFFER_4096: - rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_4096; break; case E1000_RXBUFFER_8192: - rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_8192; break; case E1000_RXBUFFER_16384: - rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_16384; break; } @@ -989,13 +1013,11 @@ uint32_t rctl; uint32_t rxcsum; - /* make sure receives are disabled while setting up the descriptors */ - + /* disable receives while setting up the descriptors */ rctl = E1000_READ_REG(&adapter->hw, RCTL); E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); /* set the Receive Delay Timer Register */ - E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay); if(adapter->hw.mac_type >= e1000_82540) { @@ -1006,7 +1028,6 @@ } /* Setup the Base and Length of the Rx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL)); E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); @@ -1025,7 +1046,6 @@ } /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } @@ -1043,7 +1063,7 @@ e1000_clean_tx_ring(adapter); - kfree(adapter->tx_ring.buffer_info); + vfree(adapter->tx_ring.buffer_info); adapter->tx_ring.buffer_info = NULL; pci_free_consistent(pdev, adapter->tx_ring.size, @@ -1073,9 +1093,9 @@ if(buffer_info->skb) { pci_unmap_page(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_TODEVICE); + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); dev_kfree_skb(buffer_info->skb); @@ -1112,7 +1132,7 @@ e1000_clean_rx_ring(adapter); - kfree(rx_ring->buffer_info); + vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); @@ -1141,12 +1161,11 @@ if(buffer_info->skb) { pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_FROMDEVICE); + buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); dev_kfree_skb(buffer_info->skb); - buffer_info->skb = NULL; } } @@ -1259,9 +1278,12 @@ uint32_t rctl; uint32_t hash_value; int i; + unsigned long flags; /* Check for Promiscuous and All Multicast modes */ + spin_lock_irqsave(&adapter->tx_lock, flags); + rctl = E1000_READ_REG(hw, RCTL); if(netdev->flags & IFF_PROMISC) { @@ -1310,9 +1332,12 @@ if(hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); + + spin_unlock_irqrestore(&adapter->tx_lock, flags); } -/* need to wait a few seconds after link up to get diagnostic information from the phy */ +/* Need to wait a few seconds after link up to get diagnostic information from + * the phy */ static void e1000_update_phy_info(unsigned long data) @@ -1420,7 +1445,7 @@ adapter->tpt_old = adapter->stats.tpt; adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old; adapter->colc_old = adapter->stats.colc; - + adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; adapter->gorcl_old = adapter->stats.gorcl; adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; @@ -1477,8 +1502,9 @@ #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; unsigned int i; - uint8_t ipcss, ipcso, tucss, tucso, hdr_len; + uint32_t cmd_length = 0; uint16_t ipcse, tucse, mss; + uint8_t ipcss, ipcso, tucss, tucso, hdr_len; if(skb_shinfo(skb)->tso_size) { hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); @@ -1497,6 +1523,10 @@ tucso = (void *)&(skb->h.th->check) - (void *)skb->data; tucse = 0; + cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | + E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | + (skb->len - (hdr_len))); + i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); @@ -1508,10 +1538,7 @@ context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; - context_desc->cmd_and_length = cpu_to_le32( - E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | - E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | - (skb->len - (hdr_len))); + context_desc->cmd_and_length = cpu_to_le32(cmd_length); if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; @@ -1528,22 +1555,21 @@ { struct e1000_context_desc *context_desc; unsigned int i; - uint8_t css, cso; + uint8_t css; - if(skb->ip_summed == CHECKSUM_HW) { + if(likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; - cso = (skb->h.raw + skb->csum) - skb->data; i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = cso; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); - if(++i == adapter->tx_ring.count) i = 0; + if(unlikely(++i == adapter->tx_ring.count)) i = 0; adapter->tx_ring.next_to_use = i; return TRUE; @@ -1567,7 +1593,6 @@ unsigned int f; len -= skb->data_len; - i = tx_ring->next_to_use; while(len) { @@ -1576,14 +1601,14 @@ #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(mss && !nr_frags && size == len && size > 8) + if(unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4; #endif /* Workaround for potential 82544 hang in PCI-X. Avoid * terminating buffers within evenly-aligned dwords. */ - if(adapter->pcix_82544 && + if(unlikely(adapter->pcix_82544 && !((unsigned long)(skb->data + offset + size - 1) & 4) && - size > 4) + size > 4)) size -= 4; buffer_info->length = size; @@ -1597,7 +1622,7 @@ len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } for(f = 0; f < nr_frags; f++) { @@ -1613,15 +1638,15 @@ #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(mss && f == (nr_frags-1) && size == len && size > 8) + if(unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) size -= 4; #endif /* Workaround for potential 82544 hang in PCI-X. * Avoid terminating buffers within evenly-aligned * dwords. */ - if(adapter->pcix_82544 && + if(unlikely(adapter->pcix_82544 && !((unsigned long)(frag->page+offset+size-1) & 4) && - size > 4) + size > 4)) size -= 4; buffer_info->length = size; @@ -1636,13 +1661,14 @@ len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } } + i = (i == 0) ? tx_ring->count - 1 : i - 1; tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - + return count; } @@ -1655,18 +1681,18 @@ uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; unsigned int i; - if(tx_flags & E1000_TX_FLAGS_TSO) { + if(likely(tx_flags & E1000_TX_FLAGS_TSO)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; txd_upper |= (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; } - if(tx_flags & E1000_TX_FLAGS_CSUM) { + if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; } - if(tx_flags & E1000_TX_FLAGS_VLAN) { + if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) { txd_lower |= E1000_TXD_CMD_VLE; txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); } @@ -1680,7 +1706,7 @@ tx_desc->lower.data = cpu_to_le32(txd_lower | buffer_info->length); tx_desc->upper.data = cpu_to_le32(txd_upper); - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); @@ -1733,7 +1759,7 @@ return 0; } -#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) +#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { @@ -1741,22 +1767,23 @@ unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; - unsigned long flags; unsigned int len = skb->len; - int count = 0; - unsigned int mss = 0; + unsigned long flags; unsigned int nr_frags = 0; + unsigned int mss = 0; + int count = 0; unsigned int f; nr_frags = skb_shinfo(skb)->nr_frags; len -= skb->data_len; - if(skb->len <= 0) { + + if(unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->tso_size; - /* The controller does a simple calculation to + /* The controller does a simple calculation to * make sure there is enough room in the FIFO before * initiating the DMA for each buffer. The calc is: * 4 = ceil(buffer len/mss). To make sure we don't @@ -1766,62 +1793,70 @@ max_per_txd = min(mss << 2, max_per_txd); max_txd_pwr = fls(max_per_txd) - 1; } + if((mss) || (skb->ip_summed == CHECKSUM_HW)) count++; - count++; /*for sentinel desc*/ + count++; /* for sentinel desc */ #else if(skb->ip_summed == CHECKSUM_HW) count++; #endif - count += TXD_USE_COUNT(len, max_txd_pwr); + if(adapter->pcix_82544) count++; nr_frags = skb_shinfo(skb)->nr_frags; for(f = 0; f < nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, - max_txd_pwr); + max_txd_pwr); if(adapter->pcix_82544) count += nr_frags; - - spin_lock_irqsave(&adapter->tx_lock, flags); - /* need: count + 2 desc gap to keep tail from touching + + local_irq_save(flags); + if (!spin_trylock(&adapter->tx_lock)) { + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ - if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2 ) { + if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) { netif_stop_queue(netdev); spin_unlock_irqrestore(&adapter->tx_lock, flags); - return 1; + return NETDEV_TX_BUSY; } - spin_unlock_irqrestore(&adapter->tx_lock, flags); - if(adapter->hw.mac_type == e1000_82547) { - if(e1000_82547_fifo_workaround(adapter, skb)) { + if(unlikely(adapter->hw.mac_type == e1000_82547)) { + if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); - return 1; + spin_unlock_irqrestore(&adapter->tx_lock, flags); + return NETDEV_TX_BUSY; } } - if(adapter->vlgrp && vlan_tx_tag_present(skb)) { + if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) { tx_flags |= E1000_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } first = adapter->tx_ring.next_to_use; - if(e1000_tso(adapter, skb)) + if(likely(e1000_tso(adapter, skb))) tx_flags |= E1000_TX_FLAGS_TSO; - else if(e1000_tx_csum(adapter, skb)) + else if(likely(e1000_tx_csum(adapter, skb))) tx_flags |= E1000_TX_FLAGS_CSUM; - e1000_tx_queue(adapter, - e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), + e1000_tx_queue(adapter, + e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), tx_flags); netdev->trans_start = jiffies; - return 0; + spin_unlock_irqrestore(&adapter->tx_lock, flags); + return NETDEV_TX_OK; } /** @@ -1843,10 +1878,8 @@ { struct e1000_adapter *adapter = netdev->priv; - netif_device_detach(netdev); e1000_down(adapter); e1000_up(adapter); - netif_device_attach(netdev); } /** @@ -1905,7 +1938,6 @@ } if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) { - e1000_down(adapter); e1000_up(adapter); } @@ -1951,8 +1983,6 @@ adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); - /* the rest of the counters are only modified here */ - adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); adapter->stats.mpc += E1000_READ_REG(hw, MPC); adapter->stats.scc += E1000_READ_REG(hw, SCC); @@ -2059,7 +2089,7 @@ * @adapter: board private structure **/ -static inline void +static void e1000_irq_disable(struct e1000_adapter *adapter) { atomic_inc(&adapter->irq_sem); @@ -2073,10 +2103,10 @@ * @adapter: board private structure **/ -static inline void +static void e1000_irq_enable(struct e1000_adapter *adapter) { - if(atomic_dec_and_test(&adapter->irq_sem)) { + if(likely(atomic_dec_and_test(&adapter->irq_sem))) { E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK); E1000_WRITE_FLUSH(&adapter->hw); } @@ -2095,21 +2125,21 @@ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; - uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); + uint32_t icr = E1000_READ_REG(hw, ICR); #ifndef CONFIG_E1000_NAPI unsigned int i; #endif - if(!icr) + if(unlikely(!icr)) return IRQ_NONE; /* Not our interrupt */ - if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + if(unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } #ifdef CONFIG_E1000_NAPI - if(netif_rx_schedule_prep(netdev)) { + if(likely(netif_rx_schedule_prep(netdev))) { /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. @@ -2121,8 +2151,8 @@ } #else for(i = 0; i < E1000_MAX_INTR; i++) - if(!e1000_clean_rx_irq(adapter) & - !e1000_clean_tx_irq(adapter)) + if(unlikely(!e1000_clean_rx_irq(adapter) & + !e1000_clean_tx_irq(adapter))) break; #endif @@ -2140,15 +2170,18 @@ { struct e1000_adapter *adapter = netdev->priv; int work_to_do = min(*budget, netdev->quota); + int tx_cleaned; int work_done = 0; - e1000_clean_tx_irq(adapter); + tx_cleaned = e1000_clean_tx_irq(adapter); e1000_clean_rx_irq(adapter, &work_done, work_to_do); *budget -= work_done; netdev->quota -= work_done; - if(work_done < work_to_do || !netif_running(netdev)) { + /* if no Rx and Tx cleanup work was done, exit the polling mode */ + if(!tx_cleaned || (work_done < work_to_do) || + !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); return 0; @@ -2156,8 +2189,8 @@ return (work_done >= work_to_do); } -#endif +#endif /** * e1000_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure @@ -2174,31 +2207,25 @@ unsigned int i, eop; boolean_t cleaned = FALSE; - i = tx_ring->next_to_clean; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { - for(cleaned = FALSE; !cleaned; ) { tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; - if(buffer_info->dma) { - + if(likely(buffer_info->dma)) { pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_TODEVICE); - buffer_info->dma = 0; } if(buffer_info->skb) { - dev_kfree_skb_any(buffer_info->skb); - buffer_info->skb = NULL; } @@ -2207,7 +2234,7 @@ tx_desc->upper.data = 0; cleaned = (i == eop); - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } eop = tx_ring->buffer_info[i].next_to_watch; @@ -2218,7 +2245,8 @@ spin_lock(&adapter->tx_lock); - if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) + if(unlikely(cleaned && netif_queue_stopped(netdev) && + netif_carrier_ok(netdev))) netif_wake_queue(netdev); spin_unlock(&adapter->tx_lock); @@ -2227,7 +2255,7 @@ } /** - * e1000_clean_rx_irq - Send received data up the network stack, + * e1000_clean_rx_irq - Send received data up the network stack * @adapter: board private structure **/ @@ -2256,14 +2284,11 @@ while(rx_desc->status & E1000_RXD_STAT_DD) { buffer_info = &rx_ring->buffer_info[i]; - #ifdef CONFIG_E1000_NAPI if(*work_done >= work_to_do) break; - (*work_done)++; #endif - cleaned = TRUE; pci_unmap_single(pdev, @@ -2274,49 +2299,28 @@ skb = buffer_info->skb; length = le16_to_cpu(rx_desc->length); - if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { - + if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) { /* All receives must fit into a single buffer */ - - E1000_DBG("%s: Receive packet consumed multiple buffers\n", - netdev->name); - + E1000_DBG("%s: Receive packet consumed multiple" + " buffers\n", netdev->name); dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; + goto next_desc; } - if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { - + if(unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { last_byte = *(skb->data + length - 1); - if(TBI_ACCEPT(&adapter->hw, rx_desc->status, rx_desc->errors, length, last_byte)) { - spin_lock_irqsave(&adapter->stats_lock, flags); - e1000_tbi_adjust_stats(&adapter->hw, &adapter->stats, length, skb->data); - spin_unlock_irqrestore(&adapter->stats_lock, flags); length--; } else { - dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; + goto next_desc; } } @@ -2328,17 +2332,19 @@ skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI - if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + if(unlikely(adapter->vlgrp && + (rx_desc->status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special & - E1000_RXD_SPC_VLAN_MASK)); + le16_to_cpu(rx_desc->special & + E1000_RXD_SPC_VLAN_MASK)); } else { netif_receive_skb(skb); } #else /* CONFIG_E1000_NAPI */ - if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + if(unlikely(adapter->vlgrp && + (rx_desc->status & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special & + le16_to_cpu(rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); } else { netif_rx(skb); @@ -2346,10 +2352,10 @@ #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; +next_desc: rx_desc->status = 0; buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; + if(unlikely(++i == rx_ring->count)) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); } @@ -2381,11 +2387,9 @@ buffer_info = &rx_ring->buffer_info[i]; while(!buffer_info->skb) { - rx_desc = E1000_RX_DESC(*rx_ring, i); skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); - - if(!skb) { + if(unlikely(!skb)) { /* Better luck next round */ break; } @@ -2400,15 +2404,15 @@ buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; - buffer_info->dma = - pci_map_single(pdev, - skb->data, - adapter->rx_buffer_len, - PCI_DMA_FROMDEVICE); + buffer_info->dma = pci_map_single(pdev, + skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); - if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) { + if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) { /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, @@ -2418,7 +2422,7 @@ E1000_WRITE_REG(&adapter->hw, RDT, i); } - if(++i == rx_ring->count) i = 0; + if(unlikely(++i == rx_ring->count)) i = 0; buffer_info = &rx_ring->buffer_info[i]; } @@ -2537,22 +2541,24 @@ return -EFAULT; mii_reg = data->val_in; if (e1000_write_phy_reg(&adapter->hw, data->reg_num, - data->val_in)) + mii_reg)) return -EIO; if (adapter->hw.phy_type == e1000_phy_m88) { switch (data->reg_num) { case PHY_CTRL: - if(data->val_in & MII_CR_AUTO_NEG_EN) { + if(mii_reg & MII_CR_POWER_DOWN) + break; + if(mii_reg & MII_CR_AUTO_NEG_EN) { adapter->hw.autoneg = 1; adapter->hw.autoneg_advertised = 0x2F; } else { - if (data->val_in & 0x40) + if (mii_reg & 0x40) spddplx = SPEED_1000; - else if (data->val_in & 0x2000) + else if (mii_reg & 0x2000) spddplx = SPEED_100; else spddplx = SPEED_10; - spddplx += (data->val_in & 0x100) + spddplx += (mii_reg & 0x100) ? FULL_DUPLEX : HALF_DUPLEX; retval = e1000_set_spd_dplx(adapter, @@ -2572,6 +2578,18 @@ return -EIO; break; } + } else { + switch (data->reg_num) { + case PHY_CTRL: + if(mii_reg & MII_CR_POWER_DOWN) + break; + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else + e1000_reset(adapter); + break; + } } break; default: @@ -2587,17 +2605,17 @@ * @sk_buff: socket buffer with received data **/ -static inline void +static void e1000_rx_checksum(struct e1000_adapter *adapter, struct e1000_rx_desc *rx_desc, struct sk_buff *skb) { /* 82543 or newer only */ - if((adapter->hw.mac_type < e1000_82543) || + if(unlikely((adapter->hw.mac_type < e1000_82543) || /* Ignore Checksum bit is set */ (rx_desc->status & E1000_RXD_STAT_IXSM) || /* TCP Checksum has not been calculated */ - (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { + (!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) { skb->ip_summed = CHECKSUM_NONE; return; } @@ -2609,7 +2627,7 @@ skb->ip_summed = CHECKSUM_NONE; adapter->hw_csum_err++; } else { - /* TCP checksum is good */ + /* TCP checksum is good */ skb->ip_summed = CHECKSUM_UNNECESSARY; adapter->hw_csum_good++; } @@ -2620,7 +2638,8 @@ { struct e1000_adapter *adapter = hw->back; - pci_set_mwi(adapter->pdev); + int ret; + ret = pci_set_mwi(adapter->pdev); } void @@ -2670,26 +2689,22 @@ if(grp) { /* enable VLAN tag insert/strip */ - ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl |= E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); /* enable VLAN receive filtering */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } else { /* disable VLAN tag insert/strip */ - ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl &= ~E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); /* disable VLAN filtering */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~E1000_RCTL_VFE; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); @@ -2705,7 +2720,6 @@ uint32_t vfta, index; /* add VID to filter table */ - index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); vfta |= (1 << (vid & 0x1F)); @@ -2725,8 +2739,7 @@ e1000_irq_enable(adapter); - /* remove VID from filter table*/ - + /* remove VID from filter table */ index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); vfta &= ~(1 << (vid & 0x1F)); @@ -2772,6 +2785,8 @@ break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: + DPRINTK(PROBE, ERR, + "Unsupported Speed/Duplexity configuration\n"); return -EINVAL; } return 0; @@ -2865,6 +2880,8 @@ } } + pci_disable_device(pdev); + state = (state > 0) ? 3 : 0; pci_set_power_state(pdev, state); @@ -2879,6 +2896,7 @@ struct e1000_adapter *adapter = netdev->priv; uint32_t manc; + pci_enable_device(pdev); pci_set_power_state(pdev, 0); pci_restore_state(pdev, adapter->pci_state); @@ -2910,12 +2928,12 @@ * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */ - -static void e1000_netpoll (struct net_device *dev) +static void +e1000_netpoll (struct net_device *netdev) { - struct e1000_adapter *adapter = dev->priv; + struct e1000_adapter *adapter = netdev->priv; disable_irq(adapter->pdev->irq); - e1000_intr (adapter->pdev->irq, dev, NULL); + e1000_intr(adapter->pdev->irq, netdev, NULL); enable_irq(adapter->pdev->irq); } #endif diff -Nru a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c --- a/drivers/net/e1000/e1000_param.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/net/e1000/e1000_param.c 2004-10-18 14:56:48 -07:00 @@ -212,7 +212,7 @@ #define MAX_TXABSDELAY 0xFFFF #define MIN_TXABSDELAY 0 -#define DEFAULT_ITR 1 +#define DEFAULT_ITR 8000 #define MAX_ITR 100000 #define MIN_ITR 100 @@ -235,7 +235,7 @@ static int __devinit e1000_validate_option(int *value, struct e1000_option *opt, - struct e1000_adapter *adapter) + struct e1000_adapter *adapter) { if(*value == OPTION_UNSET) { *value = opt->def; @@ -256,7 +256,7 @@ case range_option: if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { DPRINTK(PROBE, INFO, - "%s set to %i\n", opt->name, *value); + "%s set to %i\n", opt->name, *value); return 0; } break; @@ -449,8 +449,7 @@ DPRINTK(PROBE, INFO, "%s turned off\n", opt.name); break; case 1: - DPRINTK(PROBE, INFO, - "%s set to dynamic mode\n", opt.name); + DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", opt.name); break; default: e1000_validate_option(&adapter->itr, &opt, adapter); @@ -493,8 +492,9 @@ "parameter ignored\n"); } if((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) { - DPRINTK(PROBE, INFO, "AutoNeg other than Full/1000 is " - "not valid for fiber adapters, parameter ignored\n"); + DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is " + "not valid for fiber adapters, " + "parameter ignored\n"); } } @@ -611,24 +611,24 @@ break; case HALF_DUPLEX: DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at Half Duplex only\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "Half Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | ADVERTISE_100_HALF; break; case FULL_DUPLEX: DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at Full Duplex only\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_FULL | ADVERTISE_100_FULL | ADVERTISE_1000_FULL; break; case SPEED_10: - DPRINTK(PROBE, INFO, - "10 Mbps Speed specified without Duplex\n"); + DPRINTK(PROBE, INFO, "10 Mbps Speed specified " + "without Duplex\n"); DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | @@ -647,10 +647,10 @@ adapter->hw.autoneg_advertised = 0; break; case SPEED_100: - DPRINTK(PROBE, INFO, - "100 Mbps Speed specified without Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 100 Mbps only\n"); + DPRINTK(PROBE, INFO, "100 Mbps Speed specified " + "without Duplex\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "100 Mbps only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_100_HALF | ADVERTISE_100_FULL; @@ -668,10 +668,11 @@ adapter->hw.autoneg_advertised = 0; break; case SPEED_1000: + DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without " + "Duplex\n"); DPRINTK(PROBE, INFO, - "1000 Mbps Speed specified without Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + "Using Autonegotiation at 1000 Mbps " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -679,7 +680,8 @@ DPRINTK(PROBE, INFO, "Half Duplex is not supported at 1000 Mbps\n"); DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + "Using Autonegotiation at 1000 Mbps " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -696,8 +698,8 @@ /* Speed, AutoNeg and MDI/MDI-X must all play nice */ if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) { DPRINTK(PROBE, INFO, - "Speed, AutoNeg and MDI-X specifications are " - "incompatible. Setting MDI-X to a compatible value.\n"); + "Speed, AutoNeg and MDI-X specifications are " + "incompatible. Setting MDI-X to a compatible value.\n"); } } diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c --- a/drivers/net/eepro100.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/eepro100.c 2004-10-18 14:56:33 -07:00 @@ -88,7 +88,6 @@ #define PKT_BUF_SZ 1536 #include -#include #include #include @@ -2446,22 +2445,6 @@ .resume = eepro100_resume, #endif /* CONFIG_PM */ }; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48) -static int pci_module_init(struct pci_driver *pdev) -{ - int rc; - - rc = pci_register_driver(pdev); - if (rc <= 0) { - printk(KERN_INFO "%s: No cards found, driver not installed.\n", - pdev->name); - pci_unregister_driver(pdev); - return -ENODEV; - } - return 0; -} -#endif static int __init eepro100_init_module(void) { diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c --- a/drivers/net/epic100.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/epic100.c 2004-10-18 14:56:29 -07:00 @@ -80,8 +80,6 @@ These may be modified when a driver module is loaded.*/ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 32; /* Used to pass the full-duplex flag, etc. */ #define MAX_UNITS 8 /* More are supported, limit only on options */ @@ -99,9 +97,9 @@ Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 256 +#define TX_QUEUE_LEN 240 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 256 #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) @@ -152,12 +150,10 @@ MODULE_LICENSE("GPL"); MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)"); -MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt"); MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex"); MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)"); @@ -289,6 +285,12 @@ StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80, }; +#define EpicRemoved 0xffffffff /* Chip failed or removed (CardBus) */ + +#define EpicNapiEvent (TxEmpty | TxDone | \ + RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull) +#define EpicNormalEvent (0x0000ffff & ~EpicNapiEvent) + static u16 media2miictl[16] = { 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -327,9 +329,12 @@ /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ + spinlock_t napi_lock; + unsigned int reschedule_in_poll; unsigned int cur_tx, dirty_tx; unsigned int cur_rx, dirty_rx; + u32 irq_mask; unsigned int rx_buf_sz; /* Based on MTU+slack. */ struct pci_dev *pci_dev; /* PCI bus location. */ @@ -356,7 +361,8 @@ static void epic_tx_timeout(struct net_device *dev); static void epic_init_ring(struct net_device *dev); static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int epic_rx(struct net_device *dev); +static int epic_rx(struct net_device *dev, int budget); +static int epic_poll(struct net_device *dev, int *budget); static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; @@ -375,7 +381,7 @@ int irq; struct net_device *dev; struct epic_private *ep; - int i, option = 0, duplex = 0; + int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; @@ -389,29 +395,33 @@ card_idx++; - i = pci_enable_device(pdev); - if (i) - return i; + ret = pci_enable_device(pdev); + if (ret) + goto out; irq = pdev->irq; if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) { printk (KERN_ERR "card %d: no PCI region space\n", card_idx); - return -ENODEV; + ret = -ENODEV; + goto err_out_disable; } pci_set_master(pdev); + ret = pci_request_regions(pdev, DRV_NAME); + if (ret < 0) + goto err_out_disable; + + ret = -ENOMEM; + dev = alloc_etherdev(sizeof (*ep)); if (!dev) { printk (KERN_ERR "card %d: no memory for eth device\n", card_idx); - return -ENOMEM; + goto err_out_free_res; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - if (pci_request_regions(pdev, DRV_NAME)) - goto err_out_free_netdev; - #ifdef USE_IO_OPS ioaddr = pci_resource_start (pdev, 0); #else @@ -419,7 +429,7 @@ ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx); - goto err_out_free_res; + goto err_out_free_netdev; } #endif @@ -456,7 +466,9 @@ dev->base_addr = ioaddr; dev->irq = irq; - spin_lock_init (&ep->lock); + spin_lock_init(&ep->lock); + spin_lock_init(&ep->napi_lock); + ep->reschedule_in_poll = 0; /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); @@ -486,6 +498,9 @@ ep->pci_dev = pdev; ep->chip_id = chip_idx; ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; + ep->irq_mask = + (ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) + | CntFull | TxUnderrun | EpicNapiEvent; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but @@ -540,10 +555,12 @@ dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; + dev->poll = epic_poll; + dev->weight = 64; - i = register_netdev(dev); - if (i) - goto err_out_unmap_tx; + ret = register_netdev(dev); + if (ret < 0) + goto err_out_unmap_rx; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); @@ -551,19 +568,24 @@ printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x.\n", dev->dev_addr[i]); - return 0; +out: + return ret; +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); err_out_unmap_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); err_out_iounmap: #ifndef USE_IO_OPS iounmap(ioaddr); -err_out_free_res: -#endif - pci_release_regions(pdev); err_out_free_netdev: +#endif free_netdev(dev); - return -ENODEV; +err_out_free_res: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); + goto out; } /* Serial EEPROM section. */ @@ -589,6 +611,38 @@ #define EE_READ256_CMD (6 << 8) #define EE_ERASE_CMD (7 << 6) +static void epic_disable_int(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(0x00000000, ioaddr + INTMASK); +} + +static inline void __epic_pci_commit(long ioaddr) +{ +#ifndef USE_IO_OPS + inl(ioaddr + INTMASK); +#endif +} + +static inline void epic_napi_irq_off(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK); + __epic_pci_commit(ioaddr); +} + +static inline void epic_napi_irq_on(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + /* No need to commit possible posted write */ + outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK); +} + static int __devinit read_eeprom(long ioaddr, int location) { int i; @@ -749,9 +803,8 @@ /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " @@ -792,7 +845,7 @@ } /* Remove the packets on the Rx queue. */ - epic_rx(dev); + epic_rx(dev, RX_RING_SIZE); } static void epic_restart(struct net_device *dev) @@ -838,9 +891,9 @@ /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); + printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), @@ -926,7 +979,6 @@ int i; ep->tx_full = 0; - ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; ep->dirty_tx = ep->cur_tx = 0; ep->cur_rx = ep->dirty_rx = 0; ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); @@ -1026,6 +1078,76 @@ return 0; } +static void epic_tx_error(struct net_device *dev, struct epic_private *ep, + int status) +{ + struct net_device_stats *stats = &ep->stats; + +#ifndef final_version + /* There was an major error, log it. */ + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + stats->tx_errors++; + if (status & 0x1050) + stats->tx_aborted_errors++; + if (status & 0x0008) + stats->tx_carrier_errors++; + if (status & 0x0040) + stats->tx_window_errors++; + if (status & 0x0010) + stats->tx_fifo_errors++; +} + +static void epic_tx(struct net_device *dev, struct epic_private *ep) +{ + unsigned int dirty_tx, cur_tx; + + /* + * Note: if this lock becomes a problem we can narrow the locked + * region at the cost of occasionally grabbing the lock more times. + */ + cur_tx = ep->cur_tx; + for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) { + struct sk_buff *skb; + int entry = dirty_tx % TX_RING_SIZE; + int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + + if (txstatus & DescOwn) + break; /* It still hasn't been Txed */ + + if (likely(txstatus & 0x0001)) { + ep->stats.collisions += (txstatus >> 8) & 15; + ep->stats.tx_packets++; + ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; + } else + epic_tx_error(dev, ep, txstatus); + + /* Free the original skb. */ + skb = ep->tx_skbuff[entry]; + pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + ep->tx_skbuff[entry] = NULL; + } + +#ifndef final_version + if (cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_WARNING + "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, cur_tx, ep->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + ep->dirty_tx = dirty_tx; + if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, allow new TX entries. */ + ep->tx_full = 0; + netif_wake_queue(dev); + } +} + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) @@ -1033,135 +1155,71 @@ struct net_device *dev = dev_instance; struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; - int status, boguscnt = max_interrupt_work; unsigned int handled = 0; + int status; - do { - status = inl(ioaddr + INTSTAT); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(status & 0x00007fff, ioaddr + INTSTAT); - - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " - "intstat=%#8.8x.\n", - dev->name, status, (int)inl(ioaddr + INTSTAT)); - - if ((status & IntrSummary) == 0) - break; - handled = 1; + status = inl(ioaddr + INTSTAT); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status & EpicNormalEvent, ioaddr + INTSTAT); - if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow)) - epic_rx(dev); + if (debug > 4) { + printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " + "intstat=%#8.8x.\n", dev->name, status, + (int)inl(ioaddr + INTSTAT)); + } - if (status & (TxEmpty | TxDone)) { - unsigned int dirty_tx, cur_tx; + if ((status & IntrSummary) == 0) + goto out; - /* Note: if this lock becomes a problem we can narrow the locked - region at the cost of occasionally grabbing the lock more - times. */ - spin_lock(&ep->lock); - cur_tx = ep->cur_tx; - dirty_tx = ep->dirty_tx; - for (; cur_tx - dirty_tx > 0; dirty_tx++) { - struct sk_buff *skb; - int entry = dirty_tx % TX_RING_SIZE; - int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + handled = 1; - if (txstatus & DescOwn) - break; /* It still hasn't been Txed */ + if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { + spin_lock(&ep->napi_lock); + if (netif_rx_schedule_prep(dev)) { + epic_napi_irq_off(dev, ep); + __netif_rx_schedule(dev); + } else + ep->reschedule_in_poll++; + spin_unlock(&ep->napi_lock); + } + status &= ~EpicNapiEvent; - if ( ! (txstatus & 0x0001)) { - /* There was an major error, log it. */ -#ifndef final_version - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); -#endif - ep->stats.tx_errors++; - if (txstatus & 0x1050) ep->stats.tx_aborted_errors++; - if (txstatus & 0x0008) ep->stats.tx_carrier_errors++; - if (txstatus & 0x0040) ep->stats.tx_window_errors++; - if (txstatus & 0x0010) ep->stats.tx_fifo_errors++; - } else { - ep->stats.collisions += (txstatus >> 8) & 15; - ep->stats.tx_packets++; - ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; - } - - /* Free the original skb. */ - skb = ep->tx_skbuff[entry]; - pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - ep->tx_skbuff[entry] = NULL; - } + /* Check uncommon events all at once. */ + if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) { + if (status == EpicRemoved) + goto out; -#ifndef final_version - if (cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, cur_tx, ep->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - ep->dirty_tx = dirty_tx; - if (ep->tx_full - && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, allow new TX entries. */ - ep->tx_full = 0; - spin_unlock(&ep->lock); - netif_wake_queue(dev); - } else - spin_unlock(&ep->lock); - } + /* Always update the error counts to avoid overhead later. */ + ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); + ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); + ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - /* Check uncommon events all at once. */ - if (status & (CntFull | TxUnderrun | RxOverflow | RxFull | - PCIBusErr170 | PCIBusErr175)) { - if (status == 0xffffffff) /* Chip failed or removed (CardBus). */ - break; - /* Always update the error counts to avoid overhead later. */ - ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); - ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); - ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - - if (status & TxUnderrun) { /* Tx FIFO underflow. */ - ep->stats.tx_fifo_errors++; - outl(ep->tx_threshold += 128, ioaddr + TxThresh); - /* Restart the transmit process. */ - outl(RestartTx, ioaddr + COMMAND); - } - if (status & RxOverflow) { /* Missed a Rx frame. */ - ep->stats.rx_errors++; - } - if (status & (RxOverflow | RxFull)) - outw(RxQueued, ioaddr + COMMAND); - if (status & PCIBusErr170) { - printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n", - dev->name, status); - epic_pause(dev); - epic_restart(dev); - } - /* Clear all error sources. */ - outl(status & 0x7f18, ioaddr + INTSTAT); + if (status & TxUnderrun) { /* Tx FIFO underflow. */ + ep->stats.tx_fifo_errors++; + outl(ep->tx_threshold += 128, ioaddr + TxThresh); + /* Restart the transmit process. */ + outl(RestartTx, ioaddr + COMMAND); } - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, " - "IntrStatus=0x%8.8x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outl(0x0001ffff, ioaddr + INTSTAT); - break; + if (status & PCIBusErr170) { + printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n", + dev->name, status); + epic_pause(dev); + epic_restart(dev); } - } while (1); + /* Clear all error sources. */ + outl(status & 0x7f18, ioaddr + INTSTAT); + } - if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, status); +out: + if (debug > 3) { + printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n", + dev->name, status); + } return IRQ_RETVAL(handled); } -static int epic_rx(struct net_device *dev) +static int epic_rx(struct net_device *dev, int budget) { struct epic_private *ep = dev->priv; int entry = ep->cur_rx % RX_RING_SIZE; @@ -1171,6 +1229,10 @@ if (debug > 4) printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].rxstatus); + + if (rx_work_limit > budget) + rx_work_limit = budget; + /* If we own the next entry, it's a new packet. Send it up. */ while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); @@ -1226,7 +1288,7 @@ ep->rx_skbuff[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + netif_receive_skb(skb); dev->last_rx = jiffies; ep->stats.rx_packets++; ep->stats.rx_bytes += pkt_len; @@ -1254,6 +1316,65 @@ return work_done; } +static void epic_rx_err(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + int status; + + status = inl(ioaddr + INTSTAT); + + if (status == EpicRemoved) + return; + if (status & RxOverflow) /* Missed a Rx frame. */ + ep->stats.rx_errors++; + if (status & (RxOverflow | RxFull)) + outw(RxQueued, ioaddr + COMMAND); +} + +static int epic_poll(struct net_device *dev, int *budget) +{ + struct epic_private *ep = dev->priv; + int work_done, orig_budget; + long ioaddr = dev->base_addr; + + orig_budget = (*budget > dev->quota) ? dev->quota : *budget; + +rx_action: + + epic_tx(dev, ep); + + work_done = epic_rx(dev, *budget); + + epic_rx_err(dev, ep); + + *budget -= work_done; + dev->quota -= work_done; + + if (netif_running(dev) && (work_done < orig_budget)) { + unsigned long flags; + int more; + + /* A bit baroque but it avoids a (space hungry) spin_unlock */ + + spin_lock_irqsave(&ep->napi_lock, flags); + + more = ep->reschedule_in_poll; + if (!more) { + __netif_rx_complete(dev); + outl(EpicNapiEvent, ioaddr + INTSTAT); + epic_napi_irq_on(dev, ep); + } else + ep->reschedule_in_poll--; + + spin_unlock_irqrestore(&ep->napi_lock, flags); + + if (more) + goto rx_action; + } + + return (work_done >= orig_budget); +} + static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1268,9 +1389,13 @@ dev->name, (int)inl(ioaddr + INTSTAT)); del_timer_sync(&ep->timer); - epic_pause(dev); + + epic_disable_int(dev, ep); + free_irq(dev->irq, dev); + epic_pause(dev); + /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { skb = ep->rx_skbuff[i]; @@ -1491,6 +1616,7 @@ #endif pci_release_regions(pdev); free_netdev(dev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); /* pci_power_off(pdev, -1); */ } diff -Nru a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c --- a/drivers/net/forcedeth.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/forcedeth.c 2004-10-18 14:55:54 -07:00 @@ -75,6 +75,7 @@ * added CK804/MCP04 device IDs, code fixes * for registers, link status and other minor fixes. * 0.28: 21 Jun 2004: Big cleanup, making driver mostly endian safe + * 0.29: 31 Aug 2004: Add backup timer for link change notification. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -86,7 +87,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.28" +#define FORCEDETH_VERSION "0.29" #define DRV_NAME "forcedeth" #include @@ -120,10 +121,11 @@ * Hardware access: */ -#define DEV_NEED_LASTPACKET1 0x0001 -#define DEV_IRQMASK_1 0x0002 -#define DEV_IRQMASK_2 0x0004 -#define DEV_NEED_TIMERIRQ 0x0008 +#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */ +#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */ +#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */ +#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */ enum { NvRegIrqStatus = 0x000, @@ -367,6 +369,7 @@ #define OOM_REFILL (1+HZ/20) #define POLL_WAIT (1+HZ/100) +#define LINK_TIMEOUT (3*HZ) #define DESC_VER_1 0x0 #define DESC_VER_2 0x02100 @@ -446,6 +449,11 @@ struct timer_list oom_kick; struct timer_list nic_poll; + /* media detection workaround. + * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); + */ + int need_linktimer; + unsigned long link_timeout; /* * tx specific fields. */ @@ -1384,6 +1392,25 @@ return retval; } +static void nv_linkchange(struct net_device *dev) +{ + if (nv_update_linkspeed(dev)) { + if (netif_carrier_ok(dev)) { + nv_stop_rx(dev); + } else { + netif_carrier_on(dev); + printk(KERN_INFO "%s: link up.\n", dev->name); + } + nv_start_rx(dev); + } else { + if (netif_carrier_ok(dev)) { + netif_carrier_off(dev); + printk(KERN_INFO "%s: link down.\n", dev->name); + nv_stop_rx(dev); + } + } +} + static void nv_link_irq(struct net_device *dev) { u8 *base = get_hwbase(dev); @@ -1391,25 +1418,10 @@ miistat = readl(base + NvRegMIIStatus); writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); - dprintk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat); + dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat); - if (miistat & (NVREG_MIISTAT_LINKCHANGE)) { - if (nv_update_linkspeed(dev)) { - if (netif_carrier_ok(dev)) { - nv_stop_rx(dev); - } else { - netif_carrier_on(dev); - printk(KERN_INFO "%s: link up.\n", dev->name); - } - nv_start_rx(dev); - } else { - if (netif_carrier_ok(dev)) { - netif_carrier_off(dev); - printk(KERN_INFO "%s: link down.\n", dev->name); - nv_stop_rx(dev); - } - } - } + if (miistat & (NVREG_MIISTAT_LINKCHANGE)) + nv_linkchange(dev); dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name); } @@ -1452,6 +1464,12 @@ nv_link_irq(dev); spin_unlock(&np->lock); } + if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { + spin_lock(&np->lock); + nv_linkchange(dev); + spin_unlock(&np->lock); + np->link_timeout = jiffies + LINK_TIMEOUT; + } if (events & (NVREG_IRQ_TX_ERR)) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); @@ -1816,6 +1834,14 @@ np->irqmask = NVREG_IRQMASK_WANTED_2; if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; + if (id->driver_data & DEV_NEED_LINKTIMER) { + dprintk(KERN_INFO "%s: link timer on.\n", pci_name(pci_dev)); + np->need_linktimer = 1; + np->link_timeout = jiffies + LINK_TIMEOUT; + } else { + dprintk(KERN_INFO "%s: link timer off.\n", pci_name(pci_dev)); + np->need_linktimer = 0; + } /* find a suitable phy */ for (i = 1; i < 32; i++) { @@ -1909,21 +1935,21 @@ .device = PCI_DEVICE_ID_NVIDIA_NVENET_1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ, + .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_3, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, diff -Nru a/drivers/net/gianfar.c b/drivers/net/gianfar.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/gianfar.c 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,1864 @@ +/* + * drivers/net/gianfar.c + * + * Gianfar Ethernet Driver + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Gianfar: AKA Lambda Draconis, "Dragon" + * RA 11 31 24.2 + * Dec +69 19 52 + * V 3.84 + * B-V +1.62 + * + * Theory of operation + * This driver is designed for the Triple-speed Ethernet + * controllers on the Freescale 8540/8560 integrated processors, + * as well as the Fast Ethernet Controller on the 8540. + * + * The driver is initialized through OCP. Structures which + * define the configuration needed by the board are defined in a + * board structure in arch/ppc/platforms (though I do not + * discount the possibility that other architectures could one + * day be supported. One assumption the driver currently makes + * is that the PHY is configured in such a way to advertise all + * capabilities. This is a sensible default, and on certain + * PHYs, changing this default encounters substantial errata + * issues. Future versions may remove this requirement, but for + * now, it is best for the firmware to ensure this is the case. + * + * The Gianfar Ethernet Controller uses a ring of buffer + * descriptors. The beginning is indicated by a register + * pointing to the physical address of the start of the ring. + * The end is determined by a "wrap" bit being set in the + * last descriptor of the ring. + * + * When a packet is received, the RXF bit in the + * IEVENT register is set, triggering an interrupt when the + * corresponding bit in the IMASK register is also set (if + * interrupt coalescing is active, then the interrupt may not + * happen immediately, but will wait until either a set number + * of frames or amount of time have passed.). In NAPI, the + * interrupt handler will signal there is work to be done, and + * exit. Without NAPI, the packet(s) will be handled + * immediately. Both methods will start at the last known empty + * descriptor, and process every subsequent descriptor until there + * are none left with data (NAPI will stop after a set number of + * packets to give time to other tasks, but will eventually + * process all the packets). The data arrives inside a + * pre-allocated skb, and so after the skb is passed up to the + * stack, a new skb must be allocated, and the address field in + * the buffer descriptor must be updated to indicate this new + * skb. + * + * When the kernel requests that a packet be transmitted, the + * driver starts where it left off last time, and points the + * descriptor at the buffer which was passed in. The driver + * then informs the DMA engine that there are packets ready to + * be transmitted. Once the controller is finished transmitting + * the packet, an interrupt may be triggered (under the same + * conditions as for reception, but depending on the TXF bit). + * The driver then cleans up the buffer. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gianfar.h" +#include "gianfar_phy.h" + +#define TX_TIMEOUT (1*HZ) +#define SKB_ALLOC_TIMEOUT 1000000 +#undef BRIEF_GFAR_ERRORS +#undef VERBOSE_GFAR_ERRORS + +#ifdef CONFIG_GFAR_NAPI +#define RECEIVE(x) netif_receive_skb(x) +#else +#define RECEIVE(x) netif_rx(x) +#endif + +const char gfar_driver_name[] = "Gianfar Ethernet"; +const char gfar_driver_version[] = "1.1"; + +int startup_gfar(struct net_device *dev); +static int gfar_enet_open(struct net_device *dev); +static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void gfar_timeout(struct net_device *dev); +static int gfar_close(struct net_device *dev); +struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp); +static struct net_device_stats *gfar_get_stats(struct net_device *dev); +static int gfar_set_mac_address(struct net_device *dev); +static int gfar_change_mtu(struct net_device *dev, int new_mtu); +static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void gfar_phy_change(void *data); +static void gfar_phy_timer(unsigned long data); +static void adjust_link(struct net_device *dev); +static void init_registers(struct net_device *dev); +static int init_phy(struct net_device *dev); +static int gfar_probe(struct ocp_device *ocpdev); +static void gfar_remove(struct ocp_device *ocpdev); +void free_skb_resources(struct gfar_private *priv); +static void gfar_set_multi(struct net_device *dev); +static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); +#ifdef CONFIG_GFAR_NAPI +static int gfar_poll(struct net_device *dev, int *budget); +#endif +static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); +static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); +static void gfar_phy_startup_timer(unsigned long data); + +extern struct ethtool_ops gfar_ethtool_ops; + +MODULE_AUTHOR("Freescale Semiconductor, Inc"); +MODULE_DESCRIPTION("Gianfar Ethernet Driver"); +MODULE_LICENSE("GPL"); + +/* Called by the ocp code to initialize device data structures + * required for bringing up the device + * returns 0 on success */ +static int gfar_probe(struct ocp_device *ocpdev) +{ + u32 tempval; + struct ocp_device *mdiodev; + struct net_device *dev = NULL; + struct gfar_private *priv = NULL; + struct ocp_gfar_data *einfo; + int idx; + int err = 0; + int dev_ethtool_ops = 0; + + einfo = (struct ocp_gfar_data *) ocpdev->def->additions; + + if (einfo == NULL) { + printk(KERN_ERR "gfar %d: Missing additional data!\n", + ocpdev->def->index); + + return -ENODEV; + } + + /* get a pointer to the register memory which can + * configure the PHYs. If it's different from this set, + * get the device which has those regs */ + if ((einfo->phyregidx >= 0) && + (einfo->phyregidx != ocpdev->def->index)) { + mdiodev = ocp_find_device(OCP_ANY_ID, + OCP_FUNC_GFAR, einfo->phyregidx); + + /* If the device which holds the MDIO regs isn't + * up, wait for it to come up */ + if (mdiodev == NULL) + return -EAGAIN; + } else { + mdiodev = ocpdev; + } + + /* Create an ethernet device instance */ + dev = alloc_etherdev(sizeof (*priv)); + + if (dev == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + + /* Set the info in the priv to the current info */ + priv->einfo = einfo; + + /* get a pointer to the register memory */ + priv->regs = (struct gfar *) + ioremap(ocpdev->def->paddr, sizeof (struct gfar)); + + if (priv->regs == NULL) { + err = -ENOMEM; + goto regs_fail; + } + + /* Set the PHY base address */ + priv->phyregs = (struct gfar *) + ioremap(mdiodev->def->paddr, sizeof (struct gfar)); + + if (priv->phyregs == NULL) { + err = -ENOMEM; + goto phy_regs_fail; + } + + spin_lock_init(&priv->lock); + + ocp_set_drvdata(ocpdev, dev); + + /* Stop the DMA engine now, in case it was running before */ + /* (The firmware could have used it, and left it running). */ + /* To do this, we write Graceful Receive Stop and Graceful */ + /* Transmit Stop, and then wait until the corresponding bits */ + /* in IEVENT indicate the stops have completed. */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + tempval = gfar_read(&priv->regs->dmactrl); + tempval |= (DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) + cpu_relax(); + + /* Reset MAC layer */ + gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); + + tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); + gfar_write(&priv->regs->maccfg1, tempval); + + /* Initialize MACCFG2. */ + gfar_write(&priv->regs->maccfg2, MACCFG2_INIT_SETTINGS); + + /* Initialize ECNTRL */ + gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS); + + /* Copy the station address into the dev structure, */ + memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN); + + /* Set the dev->base_addr to the gfar reg region */ + dev->base_addr = (unsigned long) (priv->regs); + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &ocpdev->dev); + + /* Fill in the dev structure */ + dev->open = gfar_enet_open; + dev->hard_start_xmit = gfar_start_xmit; + dev->tx_timeout = gfar_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_GFAR_NAPI + dev->poll = gfar_poll; + dev->weight = GFAR_DEV_WEIGHT; +#endif + dev->stop = gfar_close; + dev->get_stats = gfar_get_stats; + dev->change_mtu = gfar_change_mtu; + dev->mtu = 1500; + dev->set_multicast_list = gfar_set_multi; + + /* Index into the array of possible ethtool + * ops to catch all 4 possibilities */ + if((priv->einfo->flags & GFAR_HAS_RMON) == 0) + dev_ethtool_ops += 1; + + if((priv->einfo->flags & GFAR_HAS_COALESCE) == 0) + dev_ethtool_ops += 2; + + dev->ethtool_ops = gfar_op_array[dev_ethtool_ops]; + + priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; +#ifdef CONFIG_GFAR_BUFSTASH + priv->rx_stash_size = STASH_LENGTH; +#endif + priv->tx_ring_size = DEFAULT_TX_RING_SIZE; + priv->rx_ring_size = DEFAULT_RX_RING_SIZE; + + priv->txcoalescing = DEFAULT_TX_COALESCE; + priv->txcount = DEFAULT_TXCOUNT; + priv->txtime = DEFAULT_TXTIME; + priv->rxcoalescing = DEFAULT_RX_COALESCE; + priv->rxcount = DEFAULT_RXCOUNT; + priv->rxtime = DEFAULT_RXTIME; + + err = register_netdev(dev); + + if (err) { + printk(KERN_ERR "%s: Cannot register net device, aborting.\n", + dev->name); + goto register_fail; + } + + /* Print out the device info */ + printk(KERN_INFO DEVICE_NAME, dev->name); + for (idx = 0; idx < 6; idx++) + printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':'); + printk("\n"); + + /* Even more device info helps when determining which kernel */ + /* provided which set of benchmarks. Since this is global for all */ + /* devices, we only print it once */ +#ifdef CONFIG_GFAR_NAPI + printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name); +#else + printk(KERN_INFO "%s: Running with NAPI disabled\n", dev->name); +#endif + printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n", + dev->name, priv->rx_ring_size, priv->tx_ring_size); + + return 0; + +register_fail: + iounmap((void *) priv->phyregs); +phy_regs_fail: + iounmap((void *) priv->regs); +regs_fail: + free_netdev(dev); + return -ENOMEM; +} + +static void gfar_remove(struct ocp_device *ocpdev) +{ + struct net_device *dev = ocp_get_drvdata(ocpdev); + struct gfar_private *priv = netdev_priv(dev); + + ocp_set_drvdata(ocpdev, NULL); + + iounmap((void *) priv->regs); + iounmap((void *) priv->phyregs); + free_netdev(dev); +} + +/* Configure the PHY for dev. + * returns 0 if success. -1 if failure + */ +static int init_phy(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct phy_info *curphy; + unsigned int timeout = PHY_INIT_TIMEOUT; + struct gfar *phyregs = priv->phyregs; + struct gfar_mii_info *mii_info; + int err; + + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + + mii_info = kmalloc(sizeof(struct gfar_mii_info), + GFP_KERNEL); + + if(NULL == mii_info) { + printk(KERN_ERR "%s: Could not allocate mii_info\n", + dev->name); + return -ENOMEM; + } + + mii_info->speed = SPEED_1000; + mii_info->duplex = DUPLEX_FULL; + mii_info->pause = 0; + mii_info->link = 1; + + mii_info->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + mii_info->autoneg = 1; + + mii_info->mii_id = priv->einfo->phyid; + + mii_info->dev = dev; + + mii_info->mdio_read = &read_phy_reg; + mii_info->mdio_write = &write_phy_reg; + + priv->mii_info = mii_info; + + /* Reset the management interface */ + gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); + + /* Setup the MII Mgmt clock speed */ + gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); + + /* Wait until the bus is free */ + while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) && + timeout--) + cpu_relax(); + + if(timeout <= 0) { + printk(KERN_ERR "%s: The MII Bus is stuck!\n", + dev->name); + err = -1; + goto bus_fail; + } + + /* get info for this PHY */ + curphy = get_phy_info(priv->mii_info); + + if (curphy == NULL) { + printk(KERN_ERR "%s: No PHY found\n", dev->name); + err = -1; + goto no_phy; + } + + mii_info->phyinfo = curphy; + + /* Run the commands which initialize the PHY */ + if(curphy->init) { + err = curphy->init(priv->mii_info); + + if (err) + goto phy_init_fail; + } + + return 0; + +phy_init_fail: +no_phy: +bus_fail: + kfree(mii_info); + + return err; +} + +static void init_registers(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, IEVENT_INIT_CLEAR); + + /* Initialize IMASK */ + gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR); + + /* Init hash registers to zero */ + gfar_write(&priv->regs->iaddr0, 0); + gfar_write(&priv->regs->iaddr1, 0); + gfar_write(&priv->regs->iaddr2, 0); + gfar_write(&priv->regs->iaddr3, 0); + gfar_write(&priv->regs->iaddr4, 0); + gfar_write(&priv->regs->iaddr5, 0); + gfar_write(&priv->regs->iaddr6, 0); + gfar_write(&priv->regs->iaddr7, 0); + + gfar_write(&priv->regs->gaddr0, 0); + gfar_write(&priv->regs->gaddr1, 0); + gfar_write(&priv->regs->gaddr2, 0); + gfar_write(&priv->regs->gaddr3, 0); + gfar_write(&priv->regs->gaddr4, 0); + gfar_write(&priv->regs->gaddr5, 0); + gfar_write(&priv->regs->gaddr6, 0); + gfar_write(&priv->regs->gaddr7, 0); + + /* Zero out rctrl */ + gfar_write(&priv->regs->rctrl, 0x00000000); + + /* Zero out the rmon mib registers if it has them */ + if (priv->einfo->flags & GFAR_HAS_RMON) { + memset((void *) &(priv->regs->rmon), 0, + sizeof (struct rmon_mib)); + + /* Mask off the CAM interrupts */ + gfar_write(&priv->regs->rmon.cam1, 0xffffffff); + gfar_write(&priv->regs->rmon.cam2, 0xffffffff); + } + + /* Initialize the max receive buffer length */ + gfar_write(&priv->regs->mrblr, priv->rx_buffer_size); + +#ifdef CONFIG_GFAR_BUFSTASH + /* If we are stashing buffers, we need to set the + * extraction length to the size of the buffer */ + gfar_write(&priv->regs->attreli, priv->rx_stash_size << 16); +#endif + + /* Initialize the Minimum Frame Length Register */ + gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS); + + /* Setup Attributes so that snooping is on for rx */ + gfar_write(&priv->regs->attr, ATTR_INIT_SETTINGS); + gfar_write(&priv->regs->attreli, ATTRELI_INIT_SETTINGS); + + /* Assign the TBI an address which won't conflict with the PHYs */ + gfar_write(&priv->regs->tbipa, TBIPA_VALUE); +} + +void stop_gfar(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + unsigned long flags; + u32 tempval; + + /* Lock it down */ + spin_lock_irqsave(&priv->lock, flags); + + /* Tell the kernel the link is down */ + priv->mii_info->link = 0; + adjust_link(dev); + + /* Mask all interrupts */ + gfar_write(®s->imask, IMASK_INIT_CLEAR); + + /* Clear all interrupts */ + gfar_write(®s->ievent, IEVENT_INIT_CLEAR); + + /* Stop the DMA, and wait for it to stop */ + tempval = gfar_read(&priv->regs->dmactrl); + if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) + != (DMACTRL_GRS | DMACTRL_GTS)) { + tempval |= (DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + while (!(gfar_read(&priv->regs->ievent) & + (IEVENT_GRSC | IEVENT_GTSC))) + cpu_relax(); + } + + /* Disable Rx and Tx */ + tempval = gfar_read(®s->maccfg1); + tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN); + gfar_write(®s->maccfg1, tempval); + + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { + /* Clear any pending interrupts */ + mii_clear_phy_interrupt(priv->mii_info); + + /* Disable PHY Interrupts */ + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_DISABLED); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Free the IRQs */ + if (priv->einfo->flags & GFAR_HAS_MULTI_INTR) { + free_irq(priv->einfo->interruptError, dev); + free_irq(priv->einfo->interruptTransmit, dev); + free_irq(priv->einfo->interruptReceive, dev); + } else { + free_irq(priv->einfo->interruptTransmit, dev); + } + + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { + free_irq(priv->einfo->interruptPHY, dev); + } else { + del_timer_sync(&priv->phy_info_timer); + } + + free_skb_resources(priv); + + dma_free_coherent(NULL, + sizeof(struct txbd8)*priv->tx_ring_size + + sizeof(struct rxbd8)*priv->rx_ring_size, + priv->tx_bd_base, + gfar_read(®s->tbase)); +} + +/* If there are any tx skbs or rx skbs still around, free them. + * Then free tx_skbuff and rx_skbuff */ +void free_skb_resources(struct gfar_private *priv) +{ + struct rxbd8 *rxbdp; + struct txbd8 *txbdp; + int i; + + /* Go through all the buffer descriptors and free their data buffers */ + txbdp = priv->tx_bd_base; + + for (i = 0; i < priv->tx_ring_size; i++) { + + if (priv->tx_skbuff[i]) { + dma_unmap_single(NULL, txbdp->bufPtr, + txbdp->length, + DMA_TO_DEVICE); + dev_kfree_skb_any(priv->tx_skbuff[i]); + priv->tx_skbuff[i] = NULL; + } + } + + kfree(priv->tx_skbuff); + + rxbdp = priv->rx_bd_base; + + /* rx_skbuff is not guaranteed to be allocated, so only + * free it and its contents if it is allocated */ + if(priv->rx_skbuff != NULL) { + for (i = 0; i < priv->rx_ring_size; i++) { + if (priv->rx_skbuff[i]) { + dma_unmap_single(NULL, rxbdp->bufPtr, + priv->rx_buffer_size + + RXBUF_ALIGNMENT, + DMA_FROM_DEVICE); + + dev_kfree_skb_any(priv->rx_skbuff[i]); + priv->rx_skbuff[i] = NULL; + } + + rxbdp->status = 0; + rxbdp->length = 0; + rxbdp->bufPtr = 0; + + rxbdp++; + } + + kfree(priv->rx_skbuff); + } +} + +/* Bring the controller up and running */ +int startup_gfar(struct net_device *dev) +{ + struct txbd8 *txbdp; + struct rxbd8 *rxbdp; + dma_addr_t addr; + unsigned long vaddr; + int i; + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 tempval; + int err = 0; + + gfar_write(®s->imask, IMASK_INIT_CLEAR); + + /* Allocate memory for the buffer descriptors */ + vaddr = (unsigned long) dma_alloc_coherent(NULL, + sizeof (struct txbd8) * priv->tx_ring_size + + sizeof (struct rxbd8) * priv->rx_ring_size, + &addr, GFP_KERNEL); + + if (vaddr == 0) { + printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n", + dev->name); + return -ENOMEM; + } + + priv->tx_bd_base = (struct txbd8 *) vaddr; + + /* enet DMA only understands physical addresses */ + gfar_write(®s->tbase, addr); + + /* Start the rx descriptor ring where the tx ring leaves off */ + addr = addr + sizeof (struct txbd8) * priv->tx_ring_size; + vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size; + priv->rx_bd_base = (struct rxbd8 *) vaddr; + gfar_write(®s->rbase, addr); + + /* Setup the skbuff rings */ + priv->tx_skbuff = + (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * + priv->tx_ring_size, GFP_KERNEL); + + if (priv->tx_skbuff == NULL) { + printk(KERN_ERR "%s: Could not allocate tx_skbuff\n", + dev->name); + err = -ENOMEM; + goto tx_skb_fail; + } + + for (i = 0; i < priv->tx_ring_size; i++) + priv->tx_skbuff[i] = NULL; + + priv->rx_skbuff = + (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * + priv->rx_ring_size, GFP_KERNEL); + + if (priv->rx_skbuff == NULL) { + printk(KERN_ERR "%s: Could not allocate rx_skbuff\n", + dev->name); + err = -ENOMEM; + goto rx_skb_fail; + } + + for (i = 0; i < priv->rx_ring_size; i++) + priv->rx_skbuff[i] = NULL; + + /* Initialize some variables in our dev structure */ + priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; + priv->cur_rx = priv->rx_bd_base; + priv->skb_curtx = priv->skb_dirtytx = 0; + priv->skb_currx = 0; + + /* Initialize Transmit Descriptor Ring */ + txbdp = priv->tx_bd_base; + for (i = 0; i < priv->tx_ring_size; i++) { + txbdp->status = 0; + txbdp->length = 0; + txbdp->bufPtr = 0; + txbdp++; + } + + /* Set the last descriptor in the ring to indicate wrap */ + txbdp--; + txbdp->status |= TXBD_WRAP; + + rxbdp = priv->rx_bd_base; + for (i = 0; i < priv->rx_ring_size; i++) { + struct sk_buff *skb = NULL; + + rxbdp->status = 0; + + skb = gfar_new_skb(dev, rxbdp); + + priv->rx_skbuff[i] = skb; + + rxbdp++; + } + + /* Set the last descriptor in the ring to wrap */ + rxbdp--; + rxbdp->status |= RXBD_WRAP; + + /* If the device has multiple interrupts, register for + * them. Otherwise, only register for the one */ + if (priv->einfo->flags & GFAR_HAS_MULTI_INTR) { + /* Install our interrupt handlers for Error, + * Transmit, and Receive */ + if (request_irq(priv->einfo->interruptError, gfar_error, + 0, "enet_error", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, priv->einfo->interruptError); + + err = -1; + goto err_irq_fail; + } + + if (request_irq(priv->einfo->interruptTransmit, gfar_transmit, + 0, "enet_tx", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, priv->einfo->interruptTransmit); + + err = -1; + + goto tx_irq_fail; + } + + if (request_irq(priv->einfo->interruptReceive, gfar_receive, + 0, "enet_rx", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n", + dev->name, priv->einfo->interruptReceive); + + err = -1; + goto rx_irq_fail; + } + } else { + if (request_irq(priv->einfo->interruptTransmit, gfar_interrupt, + 0, "gfar_interrupt", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, priv->einfo->interruptError); + + err = -1; + goto err_irq_fail; + } + } + + /* Set up the PHY change work queue */ + INIT_WORK(&priv->tq, gfar_phy_change, dev); + + init_timer(&priv->phy_info_timer); + priv->phy_info_timer.function = &gfar_phy_startup_timer; + priv->phy_info_timer.data = (unsigned long) priv->mii_info; + mod_timer(&priv->phy_info_timer, jiffies + HZ); + + /* Configure the coalescing support */ + if (priv->txcoalescing) + gfar_write(®s->txic, + mk_ic_value(priv->txcount, priv->txtime)); + else + gfar_write(®s->txic, 0); + + if (priv->rxcoalescing) + gfar_write(®s->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(®s->rxic, 0); + + init_waitqueue_head(&priv->rxcleanupq); + + /* Enable Rx and Tx in MACCFG1 */ + tempval = gfar_read(®s->maccfg1); + tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + gfar_write(®s->maccfg1, tempval); + + /* Initialize DMACTRL to have WWR and WOP */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval |= DMACTRL_INIT_SETTINGS; + gfar_write(&priv->regs->dmactrl, tempval); + + /* Clear THLT, so that the DMA starts polling now */ + gfar_write(®s->tstat, TSTAT_CLEAR_THALT); + + /* Make sure we aren't stopped */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + /* Unmask the interrupts we look for */ + gfar_write(®s->imask, IMASK_DEFAULT); + + return 0; + +rx_irq_fail: + free_irq(priv->einfo->interruptTransmit, dev); +tx_irq_fail: + free_irq(priv->einfo->interruptError, dev); +err_irq_fail: +rx_skb_fail: + free_skb_resources(priv); +tx_skb_fail: + dma_free_coherent(NULL, + sizeof(struct txbd8)*priv->tx_ring_size + + sizeof(struct rxbd8)*priv->rx_ring_size, + priv->tx_bd_base, + gfar_read(®s->tbase)); + + if (priv->mii_info->phyinfo->close) + priv->mii_info->phyinfo->close(priv->mii_info); + + kfree(priv->mii_info); + + return err; +} + +/* Called when something needs to use the ethernet device */ +/* Returns 0 for success. */ +static int gfar_enet_open(struct net_device *dev) +{ + int err; + + /* Initialize a bunch of registers */ + init_registers(dev); + + gfar_set_mac_address(dev); + + err = init_phy(dev); + + if(err) + return err; + + err = startup_gfar(dev); + + netif_start_queue(dev); + + return err; +} + +/* This is called by the kernel when a frame is ready for transmission. */ +/* It is pointed to by the dev->hard_start_xmit function pointer */ +static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct txbd8 *txbdp; + + /* Update transmit stats */ + priv->stats.tx_bytes += skb->len; + + /* Lock priv now */ + spin_lock_irq(&priv->lock); + + /* Point at the first free tx descriptor */ + txbdp = priv->cur_tx; + + /* Clear all but the WRAP status flags */ + txbdp->status &= TXBD_WRAP; + + /* Set buffer length and pointer */ + txbdp->length = skb->len; + txbdp->bufPtr = dma_map_single(NULL, skb->data, + skb->len, DMA_TO_DEVICE); + + /* Save the skb pointer so we can free it later */ + priv->tx_skbuff[priv->skb_curtx] = skb; + + /* Update the current skb pointer (wrapping if this was the last) */ + priv->skb_curtx = + (priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); + + /* Flag the BD as interrupt-causing */ + txbdp->status |= TXBD_INTERRUPT; + + /* Flag the BD as ready to go, last in frame, and */ + /* in need of CRC */ + txbdp->status |= (TXBD_READY | TXBD_LAST | TXBD_CRC); + + dev->trans_start = jiffies; + + /* If this was the last BD in the ring, the next one */ + /* is at the beginning of the ring */ + if (txbdp->status & TXBD_WRAP) + txbdp = priv->tx_bd_base; + else + txbdp++; + + /* If the next BD still needs to be cleaned up, then the bds + are full. We need to tell the kernel to stop sending us stuff. */ + if (txbdp == priv->dirty_tx) { + netif_stop_queue(dev); + + priv->stats.tx_fifo_errors++; + } + + /* Update the current txbd to the next one */ + priv->cur_tx = txbdp; + + /* Tell the DMA to go go go */ + gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + + /* Unlock priv */ + spin_unlock_irq(&priv->lock); + + return 0; +} + +/* Stops the kernel queue, and halts the controller */ +static int gfar_close(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + stop_gfar(dev); + + /* Shutdown the PHY */ + if (priv->mii_info->phyinfo->close) + priv->mii_info->phyinfo->close(priv->mii_info); + + kfree(priv->mii_info); + + netif_stop_queue(dev); + + return 0; +} + +/* returns a net_device_stats structure pointer */ +static struct net_device_stats * gfar_get_stats(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + + return &(priv->stats); +} + +/* Changes the mac address if the controller is not running. */ +int gfar_set_mac_address(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + int i; + char tmpbuf[MAC_ADDR_LEN]; + u32 tempval; + + /* Now copy it into the mac registers backwards, cuz */ + /* little endian is silly */ + for (i = 0; i < MAC_ADDR_LEN; i++) + tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->dev_addr[i]; + + gfar_write(&priv->regs->macstnaddr1, *((u32 *) (tmpbuf))); + + tempval = *((u32 *) (tmpbuf + 4)); + + gfar_write(&priv->regs->macstnaddr2, tempval); + + return 0; +} + + +static int gfar_change_mtu(struct net_device *dev, int new_mtu) +{ + int tempsize, tempval; + struct gfar_private *priv = netdev_priv(dev); + int oldsize = priv->rx_buffer_size; + int frame_size = new_mtu + 18; + + if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { + printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name); + return -EINVAL; + } + + tempsize = + (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + + INCREMENTAL_BUFFER_SIZE; + + /* Only stop and start the controller if it isn't already + * stopped */ + if ((oldsize != tempsize) && (dev->flags & IFF_UP)) + stop_gfar(dev); + + priv->rx_buffer_size = tempsize; + + dev->mtu = new_mtu; + + gfar_write(&priv->regs->mrblr, priv->rx_buffer_size); + gfar_write(&priv->regs->maxfrm, priv->rx_buffer_size); + + /* If the mtu is larger than the max size for standard + * ethernet frames (ie, a jumbo frame), then set maccfg2 + * to allow huge frames, and to check the length */ + tempval = gfar_read(&priv->regs->maccfg2); + + if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE) + tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); + else + tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); + + gfar_write(&priv->regs->maccfg2, tempval); + + if ((oldsize != tempsize) && (dev->flags & IFF_UP)) + startup_gfar(dev); + + return 0; +} + +/* gfar_timeout gets called when a packet has not been + * transmitted after a set amount of time. + * For now, assume that clearing out all the structures, and + * starting over will fix the problem. */ +static void gfar_timeout(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + + priv->stats.tx_errors++; + + if (dev->flags & IFF_UP) { + stop_gfar(dev); + startup_gfar(dev); + } + + netif_schedule(dev); +} + +/* Interrupt Handler for Transmit complete */ +static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gfar_private *priv = netdev_priv(dev); + struct txbd8 *bdp; + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, IEVENT_TX_MASK); + + /* Lock priv */ + spin_lock(&priv->lock); + bdp = priv->dirty_tx; + while ((bdp->status & TXBD_READY) == 0) { + /* If dirty_tx and cur_tx are the same, then either the */ + /* ring is empty or full now (it could only be full in the beginning, */ + /* obviously). If it is empty, we are done. */ + if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) + break; + + priv->stats.tx_packets++; + + /* Deferred means some collisions occurred during transmit, */ + /* but we eventually sent the packet. */ + if (bdp->status & TXBD_DEF) + priv->stats.collisions++; + + /* Free the sk buffer associated with this TxBD */ + dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); + priv->tx_skbuff[priv->skb_dirtytx] = NULL; + priv->skb_dirtytx = + (priv->skb_dirtytx + + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); + + /* update bdp to point at next bd in the ring (wrapping if necessary) */ + if (bdp->status & TXBD_WRAP) + bdp = priv->tx_bd_base; + else + bdp++; + + /* Move dirty_tx to be the next bd */ + priv->dirty_tx = bdp; + + /* We freed a buffer, so now we can restart transmission */ + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } /* while ((bdp->status & TXBD_READY) == 0) */ + + /* If we are coalescing the interrupts, reset the timer */ + /* Otherwise, clear it */ + if (priv->txcoalescing) + gfar_write(&priv->regs->txic, + mk_ic_value(priv->txcount, priv->txtime)); + else + gfar_write(&priv->regs->txic, 0); + + spin_unlock(&priv->lock); + + return IRQ_HANDLED; +} + +struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) +{ + struct gfar_private *priv = netdev_priv(dev); + struct sk_buff *skb = NULL; + unsigned int timeout = SKB_ALLOC_TIMEOUT; + + /* We have to allocate the skb, so keep trying till we succeed */ + while ((!skb) && timeout--) + skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); + + if (skb == NULL) + return NULL; + + /* We need the data buffer to be aligned properly. We will reserve + * as many bytes as needed to align the data properly + */ + skb_reserve(skb, + RXBUF_ALIGNMENT - + (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1))); + + skb->dev = dev; + + bdp->bufPtr = dma_map_single(NULL, skb->data, + priv->rx_buffer_size + RXBUF_ALIGNMENT, + DMA_FROM_DEVICE); + + bdp->length = 0; + + /* Mark the buffer empty */ + bdp->status |= (RXBD_EMPTY | RXBD_INTERRUPT); + + return skb; +} + +static inline void count_errors(unsigned short status, struct gfar_private *priv) +{ + struct net_device_stats *stats = &priv->stats; + struct gfar_extra_stats *estats = &priv->extra_stats; + + /* If the packet was truncated, none of the other errors + * matter */ + if (status & RXBD_TRUNCATED) { + stats->rx_length_errors++; + + estats->rx_trunc++; + + return; + } + /* Count the errors, if there were any */ + if (status & (RXBD_LARGE | RXBD_SHORT)) { + stats->rx_length_errors++; + + if (status & RXBD_LARGE) + estats->rx_large++; + else + estats->rx_short++; + } + if (status & RXBD_NONOCTET) { + stats->rx_frame_errors++; + estats->rx_nonoctet++; + } + if (status & RXBD_CRCERR) { + estats->rx_crcerr++; + stats->rx_crc_errors++; + } + if (status & RXBD_OVERRUN) { + estats->rx_overrun++; + stats->rx_crc_errors++; + } +} + +irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gfar_private *priv = netdev_priv(dev); + +#ifdef CONFIG_GFAR_NAPI + u32 tempval; +#endif + + /* Clear IEVENT, so rx interrupt isn't called again + * because of this interrupt */ + gfar_write(&priv->regs->ievent, IEVENT_RX_MASK); + + /* support NAPI */ +#ifdef CONFIG_GFAR_NAPI + if (netif_rx_schedule_prep(dev)) { + tempval = gfar_read(&priv->regs->imask); + tempval &= IMASK_RX_DISABLED; + gfar_write(&priv->regs->imask, tempval); + + __netif_rx_schedule(dev); + } else { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n", + dev->name, gfar_read(priv->regs->ievent), + gfar_read(priv->regs->imask)); +#endif + } +#else + + spin_lock(&priv->lock); + gfar_clean_rx_ring(dev, priv->rx_ring_size); + + /* If we are coalescing interrupts, update the timer */ + /* Otherwise, clear it */ + if (priv->rxcoalescing) + gfar_write(&priv->regs->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(&priv->regs->rxic, 0); + + /* Just in case we need to wake the ring param changer */ + priv->rxclean = 1; + + spin_unlock(&priv->lock); +#endif + + return IRQ_HANDLED; +} + + +/* gfar_process_frame() -- handle one incoming packet if skb + * isn't NULL. */ +static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, + int length) +{ + struct gfar_private *priv = netdev_priv(dev); + + if (skb == NULL) { +#ifdef BRIEF_GFAR_ERRORS + printk(KERN_WARNING "%s: Missing skb!!.\n", + dev->name); +#endif + priv->stats.rx_dropped++; + priv->extra_stats.rx_skbmissing++; + } else { + /* Prep the skb for the packet */ + skb_put(skb, length); + + /* Tell the skb what kind of packet this is */ + skb->protocol = eth_type_trans(skb, dev); + + /* Send the packet up the stack */ + if (RECEIVE(skb) == NET_RX_DROP) { + priv->extra_stats.kernel_dropped++; + } + } + + return 0; +} + +/* gfar_clean_rx_ring() -- Processes each frame in the rx ring + * until the budget/quota has been reached. Returns the number + * of frames handled + */ +static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) +{ + struct rxbd8 *bdp; + struct sk_buff *skb; + u16 pkt_len; + int howmany = 0; + struct gfar_private *priv = netdev_priv(dev); + + /* Get the first full descriptor */ + bdp = priv->cur_rx; + + while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { + skb = priv->rx_skbuff[priv->skb_currx]; + + if (!(bdp->status & + (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET + | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) { + /* Increment the number of packets */ + priv->stats.rx_packets++; + howmany++; + + /* Remove the FCS from the packet length */ + pkt_len = bdp->length - 4; + + gfar_process_frame(dev, skb, pkt_len); + + priv->stats.rx_bytes += pkt_len; + } else { + count_errors(bdp->status, priv); + + if (skb) + dev_kfree_skb_any(skb); + + priv->rx_skbuff[priv->skb_currx] = NULL; + } + + dev->last_rx = jiffies; + + /* Clear the status flags for this buffer */ + bdp->status &= ~RXBD_STATS; + + /* Add another skb for the future */ + skb = gfar_new_skb(dev, bdp); + priv->rx_skbuff[priv->skb_currx] = skb; + + /* Update to the next pointer */ + if (bdp->status & RXBD_WRAP) + bdp = priv->rx_bd_base; + else + bdp++; + + /* update to point at the next skb */ + priv->skb_currx = + (priv->skb_currx + + 1) & RX_RING_MOD_MASK(priv->rx_ring_size); + + } + + /* Update the current rxbd pointer to be the next one */ + priv->cur_rx = bdp; + + /* If no packets have arrived since the + * last one we processed, clear the IEVENT RX and + * BSY bits so that another interrupt won't be + * generated when we set IMASK */ + if (bdp->status & RXBD_EMPTY) + gfar_write(&priv->regs->ievent, IEVENT_RX_MASK); + + return howmany; +} + +#ifdef CONFIG_GFAR_NAPI +static int gfar_poll(struct net_device *dev, int *budget) +{ + int howmany; + struct gfar_private *priv = netdev_priv(dev); + int rx_work_limit = *budget; + + if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + + howmany = gfar_clean_rx_ring(dev, rx_work_limit); + + dev->quota -= howmany; + rx_work_limit -= howmany; + *budget -= howmany; + + if (rx_work_limit >= 0) { + netif_rx_complete(dev); + + /* Clear the halt bit in RSTAT */ + gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); + + gfar_write(&priv->regs->imask, IMASK_DEFAULT); + + /* If we are coalescing interrupts, update the timer */ + /* Otherwise, clear it */ + if (priv->rxcoalescing) + gfar_write(&priv->regs->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(&priv->regs->rxic, 0); + + /* Signal to the ring size changer that it's safe to go */ + priv->rxclean = 1; + } + + return (rx_work_limit < 0) ? 1 : 0; +} +#endif + +/* The interrupt handler for devices with one interrupt */ +static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct gfar_private *priv = netdev_priv(dev); + + /* Save ievent for future reference */ + u32 events = gfar_read(&priv->regs->ievent); + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, events); + + /* Check for reception */ + if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0)) + gfar_receive(irq, dev_id, regs); + + /* Check for transmit completion */ + if ((events & IEVENT_TXF) || (events & IEVENT_TXB)) + gfar_transmit(irq, dev_id, regs); + + /* Update error statistics */ + if (events & IEVENT_TXE) { + priv->stats.tx_errors++; + + if (events & IEVENT_LC) + priv->stats.tx_window_errors++; + if (events & IEVENT_CRL) + priv->stats.tx_aborted_errors++; + if (events & IEVENT_XFUN) { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_WARNING "%s: tx underrun. dropped packet\n", + dev->name); +#endif + priv->stats.tx_dropped++; + priv->extra_stats.tx_underrun++; + + /* Reactivate the Tx Queues */ + gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + } + } + if (events & IEVENT_BSY) { + priv->stats.rx_errors++; + priv->extra_stats.rx_bsy++; + + gfar_receive(irq, dev_id, regs); + +#ifndef CONFIG_GFAR_NAPI + /* Clear the halt bit in RSTAT */ + gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); +#endif + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name, + gfar_read(priv->regs->rstat)); +#endif + } + if (events & IEVENT_BABR) { + priv->stats.rx_errors++; + priv->extra_stats.rx_babr++; + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babbling error\n", dev->name); +#endif + } + if (events & IEVENT_EBERR) { + priv->extra_stats.eberr++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: EBERR\n", dev->name); +#endif + } + if (events & IEVENT_RXC) { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: control frame\n", dev->name); +#endif + } + + if (events & IEVENT_BABT) { + priv->extra_stats.tx_babt++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babt error\n", dev->name); +#endif + } + + return IRQ_HANDLED; +} + +static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gfar_private *priv = netdev_priv(dev); + + /* Clear the interrupt */ + mii_clear_phy_interrupt(priv->mii_info); + + /* Disable PHY interrupts */ + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_DISABLED); + + /* Schedule the phy change */ + schedule_work(&priv->tq); + + return IRQ_HANDLED; +} + +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +static void gfar_phy_change(void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct gfar_private *priv = netdev_priv(dev); + int result = 0; + + /* Delay to give the PHY a chance to change the + * register state */ + msleep(1); + + /* Update the link, speed, duplex */ + result = priv->mii_info->phyinfo->read_status(priv->mii_info); + + /* Adjust the known status as long as the link + * isn't still coming up */ + if((0 == result) || (priv->mii_info->link == 0)) + adjust_link(dev); + + /* Reenable interrupts, if needed */ + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_ENABLED); +} + +/* Called every so often on systems that don't interrupt + * the core for PHY changes */ +static void gfar_phy_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct gfar_private *priv = netdev_priv(dev); + + schedule_work(&priv->tq); + + mod_timer(&priv->phy_info_timer, jiffies + + GFAR_PHY_CHANGE_TIME * HZ); +} + +/* Keep trying aneg for some time + * If, after GFAR_AN_TIMEOUT seconds, it has not + * finished, we switch to forced. + * Either way, once the process has completed, we either + * request the interrupt, or switch the timer over to + * using gfar_phy_timer to check status */ +static void gfar_phy_startup_timer(unsigned long data) +{ + int result; + static int secondary = GFAR_AN_TIMEOUT; + struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; + struct gfar_private *priv = netdev_priv(mii_info->dev); + + /* Configure the Auto-negotiation */ + result = mii_info->phyinfo->config_aneg(mii_info); + + /* If autonegotiation failed to start, and + * we haven't timed out, reset the timer, and return */ + if (result && secondary--) { + mod_timer(&priv->phy_info_timer, jiffies + HZ); + return; + } else if (result) { + /* Couldn't start autonegotiation. + * Try switching to forced */ + mii_info->autoneg = 0; + result = mii_info->phyinfo->config_aneg(mii_info); + + /* Forcing failed! Give up */ + if(result) { + printk(KERN_ERR "%s: Forcing failed!\n", + mii_info->dev->name); + return; + } + } + + /* Kill the timer so it can be restarted */ + del_timer_sync(&priv->phy_info_timer); + + /* Grab the PHY interrupt, if necessary/possible */ + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { + if (request_irq(priv->einfo->interruptPHY, + phy_interrupt, + SA_SHIRQ, + "phy_interrupt", + mii_info->dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", + mii_info->dev->name, + priv->einfo->interruptPHY); + } else { + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_ENABLED); + return; + } + } + + /* Start the timer again, this time in order to + * handle a change in status */ + init_timer(&priv->phy_info_timer); + priv->phy_info_timer.function = &gfar_phy_timer; + priv->phy_info_timer.data = (unsigned long) mii_info->dev; + mod_timer(&priv->phy_info_timer, jiffies + + GFAR_PHY_CHANGE_TIME * HZ); +} + +/* Called every time the controller might need to be made + * aware of new link state. The PHY code conveys this + * information through variables in the priv structure, and this + * function converts those variables into the appropriate + * register values, and can bring down the device if needed. + */ +static void adjust_link(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 tempval; + struct gfar_mii_info *mii_info = priv->mii_info; + + if (mii_info->link) { + /* Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. */ + if (mii_info->duplex != priv->oldduplex) { + if (!(mii_info->duplex)) { + tempval = gfar_read(®s->maccfg2); + tempval &= ~(MACCFG2_FULL_DUPLEX); + gfar_write(®s->maccfg2, tempval); + + printk(KERN_INFO "%s: Half Duplex\n", + dev->name); + } else { + tempval = gfar_read(®s->maccfg2); + tempval |= MACCFG2_FULL_DUPLEX; + gfar_write(®s->maccfg2, tempval); + + printk(KERN_INFO "%s: Full Duplex\n", + dev->name); + } + + priv->oldduplex = mii_info->duplex; + } + + if (mii_info->speed != priv->oldspeed) { + switch (mii_info->speed) { + case 1000: + tempval = gfar_read(®s->maccfg2); + tempval = + ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); + gfar_write(®s->maccfg2, tempval); + break; + case 100: + case 10: + tempval = gfar_read(®s->maccfg2); + tempval = + ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); + gfar_write(®s->maccfg2, tempval); + break; + default: + printk(KERN_WARNING + "%s: Ack! Speed (%d) is not 10/100/1000!\n", + dev->name, mii_info->speed); + break; + } + + printk(KERN_INFO "%s: Speed %dBT\n", dev->name, + mii_info->speed); + + priv->oldspeed = mii_info->speed; + } + + if (!priv->oldlink) { + printk(KERN_INFO "%s: Link is up\n", dev->name); + priv->oldlink = 1; + netif_carrier_on(dev); + netif_schedule(dev); + } + } else { + if (priv->oldlink) { + printk(KERN_INFO "%s: Link is down\n", dev->name); + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + netif_carrier_off(dev); + } + } +} + + +/* Update the hash table based on the current list of multicast + * addresses we subscribe to. Also, change the promiscuity of + * the device based on the flags (this function is called + * whenever dev->flags is changed */ +static void gfar_set_multi(struct net_device *dev) +{ + struct dev_mc_list *mc_ptr; + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 tempval; + + if(dev->flags & IFF_PROMISC) { + printk(KERN_INFO "%s: Entering promiscuous mode.\n", + dev->name); + /* Set RCTRL to PROM */ + tempval = gfar_read(®s->rctrl); + tempval |= RCTRL_PROM; + gfar_write(®s->rctrl, tempval); + } else { + /* Set RCTRL to not PROM */ + tempval = gfar_read(®s->rctrl); + tempval &= ~(RCTRL_PROM); + gfar_write(®s->rctrl, tempval); + } + + if(dev->flags & IFF_ALLMULTI) { + /* Set the hash to rx all multicast frames */ + gfar_write(®s->gaddr0, 0xffffffff); + gfar_write(®s->gaddr1, 0xffffffff); + gfar_write(®s->gaddr2, 0xffffffff); + gfar_write(®s->gaddr3, 0xffffffff); + gfar_write(®s->gaddr4, 0xffffffff); + gfar_write(®s->gaddr5, 0xffffffff); + gfar_write(®s->gaddr6, 0xffffffff); + gfar_write(®s->gaddr7, 0xffffffff); + } else { + /* zero out the hash */ + gfar_write(®s->gaddr0, 0x0); + gfar_write(®s->gaddr1, 0x0); + gfar_write(®s->gaddr2, 0x0); + gfar_write(®s->gaddr3, 0x0); + gfar_write(®s->gaddr4, 0x0); + gfar_write(®s->gaddr5, 0x0); + gfar_write(®s->gaddr6, 0x0); + gfar_write(®s->gaddr7, 0x0); + + if(dev->mc_count == 0) + return; + + /* Parse the list, and set the appropriate bits */ + for(mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr); + } + } + + return; +} + +/* Set the appropriate hash bit for the given addr */ +/* The algorithm works like so: + * 1) Take the Destination Address (ie the multicast address), and + * do a CRC on it (little endian), and reverse the bits of the + * result. + * 2) Use the 8 most significant bits as a hash into a 256-entry + * table. The table is controlled through 8 32-bit registers: + * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is + * gaddr7. This means that the 3 most significant bits in the + * hash index which gaddr register to use, and the 5 other bits + * indicate which bit (assuming an IBM numbering scheme, which + * for PowerPC (tm) is usually the case) in the register holds + * the entry. */ +static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr) +{ + u32 tempval; + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 *hash = ®s->gaddr0; + u32 result = ether_crc(MAC_ADDR_LEN, addr); + u8 whichreg = ((result >> 29) & 0x7); + u8 whichbit = ((result >> 24) & 0x1f); + u32 value = (1 << (31-whichbit)); + + tempval = gfar_read(&hash[whichreg]); + tempval |= value; + gfar_write(&hash[whichreg], tempval); + + return; +} + +/* GFAR error interrupt handler */ +static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct gfar_private *priv = netdev_priv(dev); + + /* Save ievent for future reference */ + u32 events = gfar_read(&priv->regs->ievent); + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK); + + /* Hmm... */ +#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS) + printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n", + dev->name, events, gfar_read(priv->regs->imask)); +#endif + + /* Update the error counters */ + if (events & IEVENT_TXE) { + priv->stats.tx_errors++; + + if (events & IEVENT_LC) + priv->stats.tx_window_errors++; + if (events & IEVENT_CRL) + priv->stats.tx_aborted_errors++; + if (events & IEVENT_XFUN) { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: underrun. packet dropped.\n", + dev->name); +#endif + priv->stats.tx_dropped++; + priv->extra_stats.tx_underrun++; + + /* Reactivate the Tx Queues */ + gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + } +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: Transmit Error\n", dev->name); +#endif + } + if (events & IEVENT_BSY) { + priv->stats.rx_errors++; + priv->extra_stats.rx_bsy++; + + gfar_receive(irq, dev_id, regs); + +#ifndef CONFIG_GFAR_NAPI + /* Clear the halt bit in RSTAT */ + gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); +#endif + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name, + gfar_read(priv->regs->rstat)); +#endif + } + if (events & IEVENT_BABR) { + priv->stats.rx_errors++; + priv->extra_stats.rx_babr++; + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babbling error\n", dev->name); +#endif + } + if (events & IEVENT_EBERR) { + priv->extra_stats.eberr++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: EBERR\n", dev->name); +#endif + } + if (events & IEVENT_RXC) +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: control frame\n", dev->name); +#endif + + if (events & IEVENT_BABT) { + priv->extra_stats.tx_babt++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babt error\n", dev->name); +#endif + } + return IRQ_HANDLED; +} + +/* Structure for a device driver */ +static struct ocp_device_id gfar_ids[] = { + {.vendor = OCP_ANY_ID,.function = OCP_FUNC_GFAR}, + {.vendor = OCP_VENDOR_INVALID} +}; + +static struct ocp_driver gfar_driver = { + .name = "gianfar", + .id_table = gfar_ids, + + .probe = gfar_probe, + .remove = gfar_remove, +}; + +static int __init gfar_init(void) +{ + int rc; + + rc = ocp_register_driver(&gfar_driver); + if (rc != 0) { + ocp_unregister_driver(&gfar_driver); + return -ENODEV; + } + + return 0; +} + +static void __exit gfar_exit(void) +{ + ocp_unregister_driver(&gfar_driver); +} + +module_init(gfar_init); +module_exit(gfar_exit); diff -Nru a/drivers/net/gianfar.h b/drivers/net/gianfar.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/gianfar.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,535 @@ +/* + * drivers/net/gianfar.h + * + * Gianfar Ethernet Driver + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Still left to do: + * -Add support for module parameters + * -Add support for ethtool -s + * -Add patch for ethtool phys id + */ +#ifndef __GIANFAR_H +#define __GIANFAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gianfar_phy.h" + +/* The maximum number of packets to be handled in one call of gfar_poll */ +#define GFAR_DEV_WEIGHT 64 + +/* Number of bytes to align the rx bufs to */ +#define RXBUF_ALIGNMENT 64 + +/* The number of bytes which composes a unit for the purpose of + * allocating data buffers. ie-for any given MTU, the data buffer + * will be the next highest multiple of 512 bytes. */ +#define INCREMENTAL_BUFFER_SIZE 512 + + +#define MAC_ADDR_LEN 6 + +#define PHY_INIT_TIMEOUT 100000 +#define GFAR_PHY_CHANGE_TIME 2 + +#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, " +#define DRV_NAME "gfar-enet" +extern const char gfar_driver_name[]; +extern const char gfar_driver_version[]; + +/* These need to be powers of 2 for this driver */ +#ifdef CONFIG_GFAR_NAPI +#define DEFAULT_TX_RING_SIZE 256 +#define DEFAULT_RX_RING_SIZE 256 +#else +#define DEFAULT_TX_RING_SIZE 64 +#define DEFAULT_RX_RING_SIZE 64 +#endif + +#define GFAR_RX_MAX_RING_SIZE 256 +#define GFAR_TX_MAX_RING_SIZE 256 + +#define DEFAULT_RX_BUFFER_SIZE 1536 +#define TX_RING_MOD_MASK(size) (size-1) +#define RX_RING_MOD_MASK(size) (size-1) +#define JUMBO_BUFFER_SIZE 9728 +#define JUMBO_FRAME_SIZE 9600 + +/* Latency of interface clock in nanoseconds */ +/* Interface clock latency , in this case, means the + * time described by a value of 1 in the interrupt + * coalescing registers' time fields. Since those fields + * refer to the time it takes for 64 clocks to pass, the + * latencies are as such: + * GBIT = 125MHz => 8ns/clock => 8*64 ns / tick + * 100 = 25 MHz => 40ns/clock => 40*64 ns / tick + * 10 = 2.5 MHz => 400ns/clock => 400*64 ns / tick + */ +#define GFAR_GBIT_TIME 512 +#define GFAR_100_TIME 2560 +#define GFAR_10_TIME 25600 + +#define DEFAULT_TX_COALESCE 1 +#define DEFAULT_TXCOUNT 16 +#define DEFAULT_TXTIME 400 + +#define DEFAULT_RX_COALESCE 1 +#define DEFAULT_RXCOUNT 16 +#define DEFAULT_RXTIME 400 + +#define TBIPA_VALUE 0x1f +#define MIIMCFG_INIT_VALUE 0x00000007 +#define MIIMCFG_RESET 0x80000000 +#define MIIMIND_BUSY 0x00000001 + +/* MAC register bits */ +#define MACCFG1_SOFT_RESET 0x80000000 +#define MACCFG1_RESET_RX_MC 0x00080000 +#define MACCFG1_RESET_TX_MC 0x00040000 +#define MACCFG1_RESET_RX_FUN 0x00020000 +#define MACCFG1_RESET_TX_FUN 0x00010000 +#define MACCFG1_LOOPBACK 0x00000100 +#define MACCFG1_RX_FLOW 0x00000020 +#define MACCFG1_TX_FLOW 0x00000010 +#define MACCFG1_SYNCD_RX_EN 0x00000008 +#define MACCFG1_RX_EN 0x00000004 +#define MACCFG1_SYNCD_TX_EN 0x00000002 +#define MACCFG1_TX_EN 0x00000001 + +#define MACCFG2_INIT_SETTINGS 0x00007205 +#define MACCFG2_FULL_DUPLEX 0x00000001 +#define MACCFG2_IF 0x00000300 +#define MACCFG2_MII 0x00000100 +#define MACCFG2_GMII 0x00000200 +#define MACCFG2_HUGEFRAME 0x00000020 +#define MACCFG2_LENGTHCHECK 0x00000010 + +#define ECNTRL_INIT_SETTINGS 0x00001000 +#define ECNTRL_TBI_MODE 0x00000020 + +#define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE + +#define MINFLR_INIT_SETTINGS 0x00000040 + +/* Init to do tx snooping for buffers and descriptors */ +#define DMACTRL_INIT_SETTINGS 0x000000c3 +#define DMACTRL_GRS 0x00000010 +#define DMACTRL_GTS 0x00000008 + +#define TSTAT_CLEAR_THALT 0x80000000 + +/* Interrupt coalescing macros */ +#define IC_ICEN 0x80000000 +#define IC_ICFT_MASK 0x1fe00000 +#define IC_ICFT_SHIFT 21 +#define mk_ic_icft(x) \ + (((unsigned int)x << IC_ICFT_SHIFT)&IC_ICFT_MASK) +#define IC_ICTT_MASK 0x0000ffff +#define mk_ic_ictt(x) (x&IC_ICTT_MASK) + +#define mk_ic_value(count, time) (IC_ICEN | \ + mk_ic_icft(count) | \ + mk_ic_ictt(time)) + +#define RCTRL_PROM 0x00000008 +#define RSTAT_CLEAR_RHALT 0x00800000 + +#define IEVENT_INIT_CLEAR 0xffffffff +#define IEVENT_BABR 0x80000000 +#define IEVENT_RXC 0x40000000 +#define IEVENT_BSY 0x20000000 +#define IEVENT_EBERR 0x10000000 +#define IEVENT_MSRO 0x04000000 +#define IEVENT_GTSC 0x02000000 +#define IEVENT_BABT 0x01000000 +#define IEVENT_TXC 0x00800000 +#define IEVENT_TXE 0x00400000 +#define IEVENT_TXB 0x00200000 +#define IEVENT_TXF 0x00100000 +#define IEVENT_LC 0x00040000 +#define IEVENT_CRL 0x00020000 +#define IEVENT_XFUN 0x00010000 +#define IEVENT_RXB0 0x00008000 +#define IEVENT_GRSC 0x00000100 +#define IEVENT_RXF0 0x00000080 +#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0) +#define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF) +#define IEVENT_ERR_MASK \ +(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \ + IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \ + | IEVENT_CRL | IEVENT_XFUN) + +#define IMASK_INIT_CLEAR 0x00000000 +#define IMASK_BABR 0x80000000 +#define IMASK_RXC 0x40000000 +#define IMASK_BSY 0x20000000 +#define IMASK_EBERR 0x10000000 +#define IMASK_MSRO 0x04000000 +#define IMASK_GRSC 0x02000000 +#define IMASK_BABT 0x01000000 +#define IMASK_TXC 0x00800000 +#define IMASK_TXEEN 0x00400000 +#define IMASK_TXBEN 0x00200000 +#define IMASK_TXFEN 0x00100000 +#define IMASK_LC 0x00040000 +#define IMASK_CRL 0x00020000 +#define IMASK_XFUN 0x00010000 +#define IMASK_RXB0 0x00008000 +#define IMASK_GTSC 0x00000100 +#define IMASK_RXFEN0 0x00000080 +#define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY) +#define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \ + IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \ + IMASK_XFUN | IMASK_RXC | IMASK_BABT) + + +/* Attribute fields */ + +/* This enables rx snooping for buffers and descriptors */ +#ifdef CONFIG_GFAR_BDSTASH +#define ATTR_BDSTASH 0x00000800 +#else +#define ATTR_BDSTASH 0x00000000 +#endif + +#ifdef CONFIG_GFAR_BUFSTASH +#define ATTR_BUFSTASH 0x00004000 +#define STASH_LENGTH 64 +#else +#define ATTR_BUFSTASH 0x00000000 +#endif + +#define ATTR_SNOOPING 0x000000c0 +#define ATTR_INIT_SETTINGS (ATTR_SNOOPING \ + | ATTR_BDSTASH | ATTR_BUFSTASH) + +#define ATTRELI_INIT_SETTINGS 0x0 + + +/* TxBD status field bits */ +#define TXBD_READY 0x8000 +#define TXBD_PADCRC 0x4000 +#define TXBD_WRAP 0x2000 +#define TXBD_INTERRUPT 0x1000 +#define TXBD_LAST 0x0800 +#define TXBD_CRC 0x0400 +#define TXBD_DEF 0x0200 +#define TXBD_HUGEFRAME 0x0080 +#define TXBD_LATECOLLISION 0x0080 +#define TXBD_RETRYLIMIT 0x0040 +#define TXBD_RETRYCOUNTMASK 0x003c +#define TXBD_UNDERRUN 0x0002 + +/* RxBD status field bits */ +#define RXBD_EMPTY 0x8000 +#define RXBD_RO1 0x4000 +#define RXBD_WRAP 0x2000 +#define RXBD_INTERRUPT 0x1000 +#define RXBD_LAST 0x0800 +#define RXBD_FIRST 0x0400 +#define RXBD_MISS 0x0100 +#define RXBD_BROADCAST 0x0080 +#define RXBD_MULTICAST 0x0040 +#define RXBD_LARGE 0x0020 +#define RXBD_NONOCTET 0x0010 +#define RXBD_SHORT 0x0008 +#define RXBD_CRCERR 0x0004 +#define RXBD_OVERRUN 0x0002 +#define RXBD_TRUNCATED 0x0001 +#define RXBD_STATS 0x01ff + +struct txbd8 +{ + u16 status; /* Status Fields */ + u16 length; /* Buffer length */ + u32 bufPtr; /* Buffer Pointer */ +}; + +struct rxbd8 +{ + u16 status; /* Status Fields */ + u16 length; /* Buffer Length */ + u32 bufPtr; /* Buffer Pointer */ +}; + +struct rmon_mib +{ + u32 tr64; /* 0x.680 - Transmit and Receive 64-byte Frame Counter */ + u32 tr127; /* 0x.684 - Transmit and Receive 65-127 byte Frame Counter */ + u32 tr255; /* 0x.688 - Transmit and Receive 128-255 byte Frame Counter */ + u32 tr511; /* 0x.68c - Transmit and Receive 256-511 byte Frame Counter */ + u32 tr1k; /* 0x.690 - Transmit and Receive 512-1023 byte Frame Counter */ + u32 trmax; /* 0x.694 - Transmit and Receive 1024-1518 byte Frame Counter */ + u32 trmgv; /* 0x.698 - Transmit and Receive 1519-1522 byte Good VLAN Frame */ + u32 rbyt; /* 0x.69c - Receive Byte Counter */ + u32 rpkt; /* 0x.6a0 - Receive Packet Counter */ + u32 rfcs; /* 0x.6a4 - Receive FCS Error Counter */ + u32 rmca; /* 0x.6a8 - Receive Multicast Packet Counter */ + u32 rbca; /* 0x.6ac - Receive Broadcast Packet Counter */ + u32 rxcf; /* 0x.6b0 - Receive Control Frame Packet Counter */ + u32 rxpf; /* 0x.6b4 - Receive Pause Frame Packet Counter */ + u32 rxuo; /* 0x.6b8 - Receive Unknown OP Code Counter */ + u32 raln; /* 0x.6bc - Receive Alignment Error Counter */ + u32 rflr; /* 0x.6c0 - Receive Frame Length Error Counter */ + u32 rcde; /* 0x.6c4 - Receive Code Error Counter */ + u32 rcse; /* 0x.6c8 - Receive Carrier Sense Error Counter */ + u32 rund; /* 0x.6cc - Receive Undersize Packet Counter */ + u32 rovr; /* 0x.6d0 - Receive Oversize Packet Counter */ + u32 rfrg; /* 0x.6d4 - Receive Fragments Counter */ + u32 rjbr; /* 0x.6d8 - Receive Jabber Counter */ + u32 rdrp; /* 0x.6dc - Receive Drop Counter */ + u32 tbyt; /* 0x.6e0 - Transmit Byte Counter Counter */ + u32 tpkt; /* 0x.6e4 - Transmit Packet Counter */ + u32 tmca; /* 0x.6e8 - Transmit Multicast Packet Counter */ + u32 tbca; /* 0x.6ec - Transmit Broadcast Packet Counter */ + u32 txpf; /* 0x.6f0 - Transmit Pause Control Frame Counter */ + u32 tdfr; /* 0x.6f4 - Transmit Deferral Packet Counter */ + u32 tedf; /* 0x.6f8 - Transmit Excessive Deferral Packet Counter */ + u32 tscl; /* 0x.6fc - Transmit Single Collision Packet Counter */ + u32 tmcl; /* 0x.700 - Transmit Multiple Collision Packet Counter */ + u32 tlcl; /* 0x.704 - Transmit Late Collision Packet Counter */ + u32 txcl; /* 0x.708 - Transmit Excessive Collision Packet Counter */ + u32 tncl; /* 0x.70c - Transmit Total Collision Counter */ + u8 res1[4]; + u32 tdrp; /* 0x.714 - Transmit Drop Frame Counter */ + u32 tjbr; /* 0x.718 - Transmit Jabber Frame Counter */ + u32 tfcs; /* 0x.71c - Transmit FCS Error Counter */ + u32 txcf; /* 0x.720 - Transmit Control Frame Counter */ + u32 tovr; /* 0x.724 - Transmit Oversize Frame Counter */ + u32 tund; /* 0x.728 - Transmit Undersize Frame Counter */ + u32 tfrg; /* 0x.72c - Transmit Fragments Frame Counter */ + u32 car1; /* 0x.730 - Carry Register One */ + u32 car2; /* 0x.734 - Carry Register Two */ + u32 cam1; /* 0x.738 - Carry Mask Register One */ + u32 cam2; /* 0x.73c - Carry Mask Register Two */ +}; + +struct gfar_extra_stats { + u64 kernel_dropped; + u64 rx_large; + u64 rx_short; + u64 rx_nonoctet; + u64 rx_crcerr; + u64 rx_overrun; + u64 rx_bsy; + u64 rx_babr; + u64 rx_trunc; + u64 eberr; + u64 tx_babt; + u64 tx_underrun; + u64 rx_skbmissing; + u64 tx_timeout; +}; + +#define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32)) +#define GFAR_EXTRA_STATS_LEN (sizeof(struct gfar_extra_stats)/sizeof(u64)) + +/* Number of stats in the stats structure (ignore car and cam regs)*/ +#define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN) + +#define GFAR_INFOSTR_LEN 32 + +struct gfar_stats { + u64 extra[GFAR_EXTRA_STATS_LEN]; + u64 rmon[GFAR_RMON_LEN]; +}; + + +struct gfar { + u8 res1[16]; + u32 ievent; /* 0x.010 - Interrupt Event Register */ + u32 imask; /* 0x.014 - Interrupt Mask Register */ + u32 edis; /* 0x.018 - Error Disabled Register */ + u8 res2[4]; + u32 ecntrl; /* 0x.020 - Ethernet Control Register */ + u32 minflr; /* 0x.024 - Minimum Frame Length Register */ + u32 ptv; /* 0x.028 - Pause Time Value Register */ + u32 dmactrl; /* 0x.02c - DMA Control Register */ + u32 tbipa; /* 0x.030 - TBI PHY Address Register */ + u8 res3[88]; + u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */ + u8 res4[8]; + u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */ + u32 fifo_tx_starve_shutoff; /* 0x.09c - FIFO transmit starve shutoff register */ + u8 res5[96]; + u32 tctrl; /* 0x.100 - Transmit Control Register */ + u32 tstat; /* 0x.104 - Transmit Status Register */ + u8 res6[4]; + u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */ + u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */ + u8 res7[16]; + u32 ctbptr; /* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */ + u8 res8[92]; + u32 tbptr; /* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */ + u8 res9[124]; + u32 tbase; /* 0x.204 - Transmit Descriptor Base Address Register */ + u8 res10[168]; + u32 ostbd; /* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */ + u32 ostbdp; /* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */ + u8 res11[72]; + u32 rctrl; /* 0x.300 - Receive Control Register */ + u32 rstat; /* 0x.304 - Receive Status Register */ + u8 res12[4]; + u32 rbdlen; /* 0x.30c - RxBD Data Length Register */ + u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */ + u8 res13[16]; + u32 crbptr; /* 0x.324 - Current Receive Buffer Descriptor Pointer */ + u8 res14[24]; + u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */ + u8 res15[64]; + u32 rbptr; /* 0x.384 - Receive Buffer Descriptor Pointer */ + u8 res16[124]; + u32 rbase; /* 0x.404 - Receive Descriptor Base Address */ + u8 res17[248]; + u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */ + u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */ + u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */ + u32 hafdup; /* 0x.50c - Half Duplex Register */ + u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */ + u8 res18[12]; + u32 miimcfg; /* 0x.520 - MII Management Configuration Register */ + u32 miimcom; /* 0x.524 - MII Management Command Register */ + u32 miimadd; /* 0x.528 - MII Management Address Register */ + u32 miimcon; /* 0x.52c - MII Management Control Register */ + u32 miimstat; /* 0x.530 - MII Management Status Register */ + u32 miimind; /* 0x.534 - MII Management Indicator Register */ + u8 res19[4]; + u32 ifstat; /* 0x.53c - Interface Status Register */ + u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */ + u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */ + u8 res20[312]; + struct rmon_mib rmon; + u8 res21[192]; + u32 iaddr0; /* 0x.800 - Indivdual address register 0 */ + u32 iaddr1; /* 0x.804 - Indivdual address register 1 */ + u32 iaddr2; /* 0x.808 - Indivdual address register 2 */ + u32 iaddr3; /* 0x.80c - Indivdual address register 3 */ + u32 iaddr4; /* 0x.810 - Indivdual address register 4 */ + u32 iaddr5; /* 0x.814 - Indivdual address register 5 */ + u32 iaddr6; /* 0x.818 - Indivdual address register 6 */ + u32 iaddr7; /* 0x.81c - Indivdual address register 7 */ + u8 res22[96]; + u32 gaddr0; /* 0x.880 - Global address register 0 */ + u32 gaddr1; /* 0x.884 - Global address register 1 */ + u32 gaddr2; /* 0x.888 - Global address register 2 */ + u32 gaddr3; /* 0x.88c - Global address register 3 */ + u32 gaddr4; /* 0x.890 - Global address register 4 */ + u32 gaddr5; /* 0x.894 - Global address register 5 */ + u32 gaddr6; /* 0x.898 - Global address register 6 */ + u32 gaddr7; /* 0x.89c - Global address register 7 */ + u8 res23[856]; + u32 attr; /* 0x.bf8 - Attributes Register */ + u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */ + u8 res24[1024]; + +}; + +/* Struct stolen almost completely (and shamelessly) from the FCC enet source + * (Ok, that's not so true anymore, but there is a family resemblence) + * The GFAR buffer descriptors track the ring buffers. The rx_bd_base + * and tx_bd_base always point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct gfar_private { + /* pointers to arrays of skbuffs for tx and rx */ + struct sk_buff ** tx_skbuff; + struct sk_buff ** rx_skbuff; + + /* indices pointing to the next free sbk in skb arrays */ + u16 skb_curtx; + u16 skb_currx; + + /* index of the first skb which hasn't been transmitted + * yet. */ + u16 skb_dirtytx; + + /* Configuration info for the coalescing features */ + unsigned char txcoalescing; + unsigned short txcount; + unsigned short txtime; + unsigned char rxcoalescing; + unsigned short rxcount; + unsigned short rxtime; + + /* GFAR addresses */ + struct rxbd8 *rx_bd_base; /* Base addresses of Rx and Tx Buffers */ + struct txbd8 *tx_bd_base; + struct rxbd8 *cur_rx; /* Next free rx ring entry */ + struct txbd8 *cur_tx; /* Next free ring entry */ + struct txbd8 *dirty_tx; /* The Ring entry to be freed. */ + struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */ + struct gfar *phyregs; + struct work_struct tq; + struct timer_list phy_info_timer; + struct net_device_stats stats; /* linux network statistics */ + struct gfar_extra_stats extra_stats; + spinlock_t lock; + unsigned int rx_buffer_size; + unsigned int rx_stash_size; + unsigned int tx_ring_size; + unsigned int rx_ring_size; + wait_queue_head_t rxcleanupq; + unsigned int rxclean; + + /* Info structure initialized by board setup code */ + struct ocp_gfar_data *einfo; + + struct gfar_mii_info *mii_info; + int oldspeed; + int oldduplex; + int oldlink; +}; + +extern inline u32 gfar_read(volatile unsigned *addr) +{ + u32 val; + val = in_be32(addr); + return val; +} + +extern inline void gfar_write(volatile unsigned *addr, u32 val) +{ + out_be32(addr, val); +} + +extern struct ethtool_ops *gfar_op_array[]; + +#endif /* __GIANFAR_H */ diff -Nru a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/gianfar_ethtool.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,525 @@ +/* + * drivers/net/gianfar_ethtool.c + * + * Gianfar Ethernet Driver + * Ethtool support for Gianfar Enet + * Based on e1000 ethtool support + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2003,2004 Freescale Semiconductor, Inc. + * + * This software may be used and distributed according to + * the terms of the GNU Public License, Version 2, incorporated herein + * by reference. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gianfar.h" + +#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) + +extern int startup_gfar(struct net_device *dev); +extern void stop_gfar(struct net_device *dev); +extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs); + +void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, + u64 * buf); +void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf); +int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals); +int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals); +void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals); +int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals); +void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo); + +static char stat_gstrings[][ETH_GSTRING_LEN] = { + "rx-dropped-by-kernel", + "rx-large-frame-errors", + "rx-short-frame-errors", + "rx-non-octet-errors", + "rx-crc-errors", + "rx-overrun-errors", + "rx-busy-errors", + "rx-babbling-errors", + "rx-truncated-frames", + "ethernet-bus-error", + "tx-babbling-errors", + "tx-underrun-errors", + "rx-skb-missing-errors", + "tx-timeout-errors", + "tx-rx-64-frames", + "tx-rx-65-127-frames", + "tx-rx-128-255-frames", + "tx-rx-256-511-frames", + "tx-rx-512-1023-frames", + "tx-rx-1024-1518-frames", + "tx-rx-1519-1522-good-vlan", + "rx-bytes", + "rx-packets", + "rx-fcs-errors", + "receive-multicast-packet", + "receive-broadcast-packet", + "rx-control-frame-packets", + "rx-pause-frame-packets", + "rx-unknown-op-code", + "rx-alignment-error", + "rx-frame-length-error", + "rx-code-error", + "rx-carrier-sense-error", + "rx-undersize-packets", + "rx-oversize-packets", + "rx-fragmented-frames", + "rx-jabber-frames", + "rx-dropped-frames", + "tx-byte-counter", + "tx-packets", + "tx-multicast-packets", + "tx-broadcast-packets", + "tx-pause-control-frames", + "tx-deferral-packets", + "tx-excessive-deferral-packets", + "tx-single-collision-packets", + "tx-multiple-collision-packets", + "tx-late-collision-packets", + "tx-excessive-collision-packets", + "tx-total-collision", + "reserved", + "tx-dropped-frames", + "tx-jabber-frames", + "tx-fcs-errors", + "tx-control-frames", + "tx-oversize-frames", + "tx-undersize-frames", + "tx-fragmented-frames", +}; + +/* Fill in an array of 64-bit statistics from various sources. + * This array will be appended to the end of the ethtool_stats + * structure, and returned to user space + */ +void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf) +{ + int i; + struct gfar_private *priv = netdev_priv(dev); + u32 *rmon = (u32 *) & priv->regs->rmon; + u64 *extra = (u64 *) & priv->extra_stats; + struct gfar_stats *stats = (struct gfar_stats *) buf; + + for (i = 0; i < GFAR_RMON_LEN; i++) { + stats->rmon[i] = (u64) (rmon[i]); + } + + for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) { + stats->extra[i] = extra[i]; + } +} + +/* Returns the number of stats (and their corresponding strings) */ +int gfar_stats_count(struct net_device *dev) +{ + return GFAR_STATS_LEN; +} + +void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf) +{ + memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN); +} + +void gfar_fill_stats_normon(struct net_device *dev, + struct ethtool_stats *dummy, u64 * buf) +{ + int i; + struct gfar_private *priv = netdev_priv(dev); + u64 *extra = (u64 *) & priv->extra_stats; + + for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) { + buf[i] = extra[i]; + } +} + + +int gfar_stats_count_normon(struct net_device *dev) +{ + return GFAR_EXTRA_STATS_LEN; +} +/* Fills in the drvinfo structure with some basic info */ +void gfar_gdrvinfo(struct net_device *dev, struct + ethtool_drvinfo *drvinfo) +{ + strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN); + strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN); + strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN); + strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN); + drvinfo->n_stats = GFAR_STATS_LEN; + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +/* Return the current settings in the ethtool_cmd structure */ +int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct gfar_private *priv = netdev_priv(dev); + uint gigabit_support = + priv->einfo->flags & GFAR_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0; + uint gigabit_advert = + priv->einfo->flags & GFAR_HAS_GIGABIT ? ADVERTISED_1000baseT_Full: 0; + + cmd->supported = (SUPPORTED_10baseT_Half + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | gigabit_support | SUPPORTED_Autoneg); + + /* For now, we always advertise everything */ + cmd->advertising = (ADVERTISED_10baseT_Half + | ADVERTISED_100baseT_Half + | ADVERTISED_100baseT_Full + | gigabit_advert | ADVERTISED_Autoneg); + + cmd->speed = priv->mii_info->speed; + cmd->duplex = priv->mii_info->duplex; + cmd->port = PORT_MII; + cmd->phy_address = priv->mii_info->mii_id; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = AUTONEG_ENABLE; + cmd->maxtxpkt = priv->txcount; + cmd->maxrxpkt = priv->rxcount; + + return 0; +} + +/* Return the length of the register structure */ +int gfar_reglen(struct net_device *dev) +{ + return sizeof (struct gfar); +} + +/* Return a dump of the GFAR register space */ +void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf) +{ + int i; + struct gfar_private *priv = netdev_priv(dev); + u32 *theregs = (u32 *) priv->regs; + u32 *buf = (u32 *) regbuf; + + for (i = 0; i < sizeof (struct gfar) / sizeof (u32); i++) + buf[i] = theregs[i]; +} + +/* Fill in a buffer with the strings which correspond to the + * stats */ +void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf) +{ + memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN); +} + +/* Convert microseconds to ethernet clock ticks, which changes + * depending on what speed the controller is running at */ +static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs) +{ + unsigned int count; + + /* The timer is different, depending on the interface speed */ + switch (priv->mii_info->speed) { + case 1000: + count = GFAR_GBIT_TIME; + break; + case 100: + count = GFAR_100_TIME; + break; + case 10: + default: + count = GFAR_10_TIME; + break; + } + + /* Make sure we return a number greater than 0 + * if usecs > 0 */ + return ((usecs * 1000 + count - 1) / count); +} + +/* Convert ethernet clock ticks to microseconds */ +static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int ticks) +{ + unsigned int count; + + /* The timer is different, depending on the interface speed */ + switch (priv->mii_info->speed) { + case 1000: + count = GFAR_GBIT_TIME; + break; + case 100: + count = GFAR_100_TIME; + break; + case 10: + default: + count = GFAR_10_TIME; + break; + } + + /* Make sure we return a number greater than 0 */ + /* if ticks is > 0 */ + return ((ticks * count) / 1000); +} + +/* Get the coalescing parameters, and put them in the cvals + * structure. */ +int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) +{ + struct gfar_private *priv = netdev_priv(dev); + + cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); + cvals->rx_max_coalesced_frames = priv->rxcount; + + cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, priv->txtime); + cvals->tx_max_coalesced_frames = priv->txcount; + + cvals->use_adaptive_rx_coalesce = 0; + cvals->use_adaptive_tx_coalesce = 0; + + cvals->pkt_rate_low = 0; + cvals->rx_coalesce_usecs_low = 0; + cvals->rx_max_coalesced_frames_low = 0; + cvals->tx_coalesce_usecs_low = 0; + cvals->tx_max_coalesced_frames_low = 0; + + /* When the packet rate is below pkt_rate_high but above + * pkt_rate_low (both measured in packets per second) the + * normal {rx,tx}_* coalescing parameters are used. + */ + + /* When the packet rate is (measured in packets per second) + * is above pkt_rate_high, the {rx,tx}_*_high parameters are + * used. + */ + cvals->pkt_rate_high = 0; + cvals->rx_coalesce_usecs_high = 0; + cvals->rx_max_coalesced_frames_high = 0; + cvals->tx_coalesce_usecs_high = 0; + cvals->tx_max_coalesced_frames_high = 0; + + /* How often to do adaptive coalescing packet rate sampling, + * measured in seconds. Must not be zero. + */ + cvals->rate_sample_interval = 0; + + return 0; +} + +/* Change the coalescing values. + * Both cvals->*_usecs and cvals->*_frames have to be > 0 + * in order for coalescing to be active + */ +int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) +{ + struct gfar_private *priv = netdev_priv(dev); + + /* Set up rx coalescing */ + if ((cvals->rx_coalesce_usecs == 0) || + (cvals->rx_max_coalesced_frames == 0)) + priv->rxcoalescing = 0; + else + priv->rxcoalescing = 1; + + priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); + priv->rxcount = cvals->rx_max_coalesced_frames; + + /* Set up tx coalescing */ + if ((cvals->tx_coalesce_usecs == 0) || + (cvals->tx_max_coalesced_frames == 0)) + priv->txcoalescing = 0; + else + priv->txcoalescing = 1; + + priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); + priv->txcount = cvals->tx_max_coalesced_frames; + + if (priv->rxcoalescing) + gfar_write(&priv->regs->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(&priv->regs->rxic, 0); + + if (priv->txcoalescing) + gfar_write(&priv->regs->txic, + mk_ic_value(priv->txcount, priv->txtime)); + else + gfar_write(&priv->regs->txic, 0); + + return 0; +} + +/* Fills in rvals with the current ring parameters. Currently, + * rx, rx_mini, and rx_jumbo rings are the same size, as mini and + * jumbo are ignored by the driver */ +void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals) +{ + struct gfar_private *priv = netdev_priv(dev); + + rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE; + rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE; + rvals->rx_jumbo_max_pending = GFAR_RX_MAX_RING_SIZE; + rvals->tx_max_pending = GFAR_TX_MAX_RING_SIZE; + + /* Values changeable by the user. The valid values are + * in the range 1 to the "*_max_pending" counterpart above. + */ + rvals->rx_pending = priv->rx_ring_size; + rvals->rx_mini_pending = priv->rx_ring_size; + rvals->rx_jumbo_pending = priv->rx_ring_size; + rvals->tx_pending = priv->tx_ring_size; +} + +/* Change the current ring parameters, stopping the controller if + * necessary so that we don't mess things up while we're in + * motion. We wait for the ring to be clean before reallocating + * the rings. */ +int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) +{ + u32 tempval; + struct gfar_private *priv = netdev_priv(dev); + int err = 0; + + if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) + return -EINVAL; + + if (!is_power_of_2(rvals->rx_pending)) { + printk("%s: Ring sizes must be a power of 2\n", + dev->name); + return -EINVAL; + } + + if (rvals->tx_pending > GFAR_TX_MAX_RING_SIZE) + return -EINVAL; + + if (!is_power_of_2(rvals->tx_pending)) { + printk("%s: Ring sizes must be a power of 2\n", + dev->name); + return -EINVAL; + } + + /* Stop the controller so we don't rx any more frames */ + /* But first, make sure we clear the bits */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + tempval = gfar_read(&priv->regs->dmactrl); + tempval |= (DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) + cpu_relax(); + + /* Note that rx is not clean right now */ + priv->rxclean = 0; + + if (dev->flags & IFF_UP) { + /* Tell the driver to process the rest of the frames */ + gfar_receive(0, (void *) dev, NULL); + + /* Now wait for it to be done */ + wait_event_interruptible(priv->rxcleanupq, priv->rxclean); + + /* Ok, all packets have been handled. Now we bring it down, + * change the ring size, and bring it up */ + + stop_gfar(dev); + } + + priv->rx_ring_size = rvals->rx_pending; + priv->tx_ring_size = rvals->tx_pending; + + if (dev->flags & IFF_UP) + err = startup_gfar(dev); + + return err; +} + +struct ethtool_ops gfar_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = ethtool_op_get_link, + .get_coalesce = gfar_gcoalesce, + .set_coalesce = gfar_scoalesce, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings, + .get_stats_count = gfar_stats_count, + .get_ethtool_stats = gfar_fill_stats, +}; + +struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = ethtool_op_get_link, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings_normon, + .get_stats_count = gfar_stats_count_normon, + .get_ethtool_stats = gfar_fill_stats_normon, +}; + +struct ethtool_ops gfar_nocoalesce_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = ethtool_op_get_link, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings, + .get_stats_count = gfar_stats_count, + .get_ethtool_stats = gfar_fill_stats, +}; + +struct ethtool_ops gfar_normon_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = ethtool_op_get_link, + .get_coalesce = gfar_gcoalesce, + .set_coalesce = gfar_scoalesce, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings_normon, + .get_stats_count = gfar_stats_count_normon, + .get_ethtool_stats = gfar_fill_stats_normon, +}; + +struct ethtool_ops *gfar_op_array[] = { + &gfar_ethtool_ops, + &gfar_normon_ethtool_ops, + &gfar_nocoalesce_ethtool_ops, + &gfar_normon_nocoalesce_ethtool_ops +}; diff -Nru a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/gianfar_phy.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,661 @@ +/* + * drivers/net/gianfar_phy.c + * + * Gianfar Ethernet Driver -- PHY handling + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gianfar.h" +#include "gianfar_phy.h" + +static void config_genmii_advert(struct gfar_mii_info *mii_info); +static void genmii_setup_forced(struct gfar_mii_info *mii_info); +static void genmii_restart_aneg(struct gfar_mii_info *mii_info); +static int gbit_config_aneg(struct gfar_mii_info *mii_info); +static int genmii_config_aneg(struct gfar_mii_info *mii_info); +static int genmii_update_link(struct gfar_mii_info *mii_info); +static int genmii_read_status(struct gfar_mii_info *mii_info); +u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum); +void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val); + +/* Write value to the PHY for this device to the register at regnum, */ +/* waiting until the write is done before it returns. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) +{ + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regbase = priv->phyregs; + + /* Set the PHY address and the register address we want to write */ + gfar_write(®base->miimadd, (mii_id << 8) | regnum); + + /* Write out the value we want */ + gfar_write(®base->miimcon, value); + + /* Wait for the transaction to finish */ + while (gfar_read(®base->miimind) & MIIMIND_BUSY) + cpu_relax(); +} + +/* Reads from register regnum in the PHY for device dev, */ +/* returning the value. Clears miimcom first. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +int read_phy_reg(struct net_device *dev, int mii_id, int regnum) +{ + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regbase = priv->phyregs; + u16 value; + + /* Set the PHY address and the register address we want to read */ + gfar_write(®base->miimadd, (mii_id << 8) | regnum); + + /* Clear miimcom, and then initiate a read */ + gfar_write(®base->miimcom, 0); + gfar_write(®base->miimcom, MII_READ_COMMAND); + + /* Wait for the transaction to finish */ + while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) + cpu_relax(); + + /* Grab the value of the register from miimstat */ + value = gfar_read(®base->miimstat); + + return value; +} + +void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info) +{ + if(mii_info->phyinfo->ack_interrupt) + mii_info->phyinfo->ack_interrupt(mii_info); +} + + +void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts) +{ + mii_info->interrupts = interrupts; + if(mii_info->phyinfo->config_intr) + mii_info->phyinfo->config_intr(mii_info); +} + + +/* Writes MII_ADVERTISE with the appropriate values, after + * sanitizing advertise to make sure only supported features + * are advertised + */ +static void config_genmii_advert(struct gfar_mii_info *mii_info) +{ + u32 advertise; + u16 adv; + + /* Only allow advertising what this PHY supports */ + mii_info->advertising &= mii_info->phyinfo->features; + advertise = mii_info->advertising; + + /* Setup standard advertisement */ + adv = phy_read(mii_info, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + phy_write(mii_info, MII_ADVERTISE, adv); +} + +static void genmii_setup_forced(struct gfar_mii_info *mii_info) +{ + u16 ctrl; + u32 features = mii_info->phyinfo->features; + + ctrl = phy_read(mii_info, MII_BMCR); + + ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE); + ctrl |= BMCR_RESET; + + switch(mii_info->speed) { + case SPEED_1000: + if(features & (SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full)) { + ctrl |= BMCR_SPEED1000; + break; + } + mii_info->speed = SPEED_100; + case SPEED_100: + if (features & (SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full)) { + ctrl |= BMCR_SPEED100; + break; + } + mii_info->speed = SPEED_10; + case SPEED_10: + if (features & (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full)) + break; + default: /* Unsupported speed! */ + printk(KERN_ERR "%s: Bad speed!\n", + mii_info->dev->name); + break; + } + + phy_write(mii_info, MII_BMCR, ctrl); +} + + +/* Enable and Restart Autonegotiation */ +static void genmii_restart_aneg(struct gfar_mii_info *mii_info) +{ + u16 ctl; + + ctl = phy_read(mii_info, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(mii_info, MII_BMCR, ctl); +} + + +static int gbit_config_aneg(struct gfar_mii_info *mii_info) +{ + u16 adv; + u32 advertise; + + if(mii_info->autoneg) { + /* Configure the ADVERTISE register */ + config_genmii_advert(mii_info); + advertise = mii_info->advertising; + + adv = phy_read(mii_info, MII_1000BASETCONTROL); + adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | + MII_1000BASETCONTROL_HALFDUPLEXCAP); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; + phy_write(mii_info, MII_1000BASETCONTROL, adv); + + /* Start/Restart aneg */ + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); + + return 0; +} + +static int marvell_config_aneg(struct gfar_mii_info *mii_info) +{ + /* The Marvell PHY has an errata which requires + * that certain registers get written in order + * to restart autonegotiation */ + phy_write(mii_info, MII_BMCR, BMCR_RESET); + + phy_write(mii_info, 0x1d, 0x1f); + phy_write(mii_info, 0x1e, 0x200c); + phy_write(mii_info, 0x1d, 0x5); + phy_write(mii_info, 0x1e, 0); + phy_write(mii_info, 0x1e, 0x100); + + gbit_config_aneg(mii_info); + + return 0; +} +static int genmii_config_aneg(struct gfar_mii_info *mii_info) +{ + if (mii_info->autoneg) { + config_genmii_advert(mii_info); + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); + + return 0; +} + + +static int genmii_update_link(struct gfar_mii_info *mii_info) +{ + u16 status; + + /* Do a fake read */ + phy_read(mii_info, MII_BMSR); + + /* Read link and autonegotiation status */ + status = phy_read(mii_info, MII_BMSR); + if ((status & BMSR_LSTATUS) == 0) + mii_info->link = 0; + else + mii_info->link = 1; + + /* If we are autonegotiating, and not done, + * return an error */ + if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) + return -EAGAIN; + + return 0; +} + +static int genmii_read_status(struct gfar_mii_info *mii_info) +{ + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + if (mii_info->autoneg) { + status = phy_read(mii_info, MII_LPA); + + if (status & (LPA_10FULL | LPA_100FULL)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + if (status & (LPA_100FULL | LPA_100HALF)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + mii_info->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} +static int marvell_read_status(struct gfar_mii_info *mii_info) +{ + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); + +#if 0 + /* If speed and duplex aren't resolved, + * return an error. Isn't this handled + * by checking aneg? + */ + if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) + return -EAGAIN; +#endif + + /* Get the duplexity */ + if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + + /* Get the speed */ + speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; + switch(speed) { + case MII_M1011_PHY_SPEC_STATUS_1000: + mii_info->speed = SPEED_1000; + break; + case MII_M1011_PHY_SPEC_STATUS_100: + mii_info->speed = SPEED_100; + break; + default: + mii_info->speed = SPEED_10; + break; + } + mii_info->pause = 0; + } + + return 0; +} + + +static int cis820x_read_status(struct gfar_mii_info *mii_info) +{ + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + + status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); + if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + + speed = status & MII_CIS8201_AUXCONSTAT_SPEED; + + switch (speed) { + case MII_CIS8201_AUXCONSTAT_GBIT: + mii_info->speed = SPEED_1000; + break; + case MII_CIS8201_AUXCONSTAT_100: + mii_info->speed = SPEED_100; + break; + default: + mii_info->speed = SPEED_10; + break; + } + } + + return 0; +} + +static int marvell_ack_interrupt(struct gfar_mii_info *mii_info) +{ + /* Clear the interrupts by reading the reg */ + phy_read(mii_info, MII_M1011_IEVENT); + + return 0; +} + +static int marvell_config_intr(struct gfar_mii_info *mii_info) +{ + if(mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + else + phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + + return 0; +} + +static int cis820x_init(struct gfar_mii_info *mii_info) +{ + phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, + MII_CIS8201_AUXCONSTAT_INIT); + phy_write(mii_info, MII_CIS8201_EXT_CON1, + MII_CIS8201_EXTCON1_INIT); + + return 0; +} + +static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info) +{ + phy_read(mii_info, MII_CIS8201_ISTAT); + + return 0; +} + +static int cis820x_config_intr(struct gfar_mii_info *mii_info) +{ + if(mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); + else + phy_write(mii_info, MII_CIS8201_IMASK, 0); + + return 0; +} + +#define DM9161_DELAY 10 + +static int dm9161_read_status(struct gfar_mii_info *mii_info) +{ + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + status = phy_read(mii_info, MII_DM9161_SCSR); + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + } + + return 0; +} + + +static int dm9161_config_aneg(struct gfar_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + if(0 == priv->resetdone) + return -EAGAIN; + + return 0; +} + +static void dm9161_timer(unsigned long data) +{ + struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; + struct dm9161_private *priv = mii_info->priv; + u16 status = phy_read(mii_info, MII_BMSR); + + if (status & BMSR_ANEGCOMPLETE) { + priv->resetdone = 1; + } else + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); +} + +static int dm9161_init(struct gfar_mii_info *mii_info) +{ + struct dm9161_private *priv; + + /* Allocate the private data structure */ + priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); + + if (NULL == priv) + return -ENOMEM; + + mii_info->priv = priv; + + /* Reset is not done yet */ + priv->resetdone = 0; + + /* Isolate the PHY */ + phy_write(mii_info, MII_BMCR, BMCR_ISOLATE); + + /* Do not bypass the scrambler/descrambler */ + phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); + + /* Clear 10BTCSR to default */ + phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); + + /* Reconnect the PHY, and enable Autonegotiation */ + phy_write(mii_info, MII_BMCR, BMCR_ANENABLE); + + /* Start a timer for DM9161_DELAY seconds to wait + * for the PHY to be ready */ + init_timer(&priv->timer); + priv->timer.function = &dm9161_timer; + priv->timer.data = (unsigned long) mii_info; + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); + + return 0; +} + +static void dm9161_close(struct gfar_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + del_timer_sync(&priv->timer); + kfree(priv); +} + +#if 0 +static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info) +{ + phy_read(mii_info, MII_DM9161_INTR); + + return 0; +} +#endif + +/* Cicada 820x */ +static struct phy_info phy_info_cis820x = { + 0x000fc440, + "Cicada Cis8204", + 0x000fffc0, + .features = MII_GBIT_FEATURES, + .init = &cis820x_init, + .config_aneg = &gbit_config_aneg, + .read_status = &cis820x_read_status, + .ack_interrupt = &cis820x_ack_interrupt, + .config_intr = &cis820x_config_intr, +}; + +static struct phy_info phy_info_dm9161 = { + .phy_id = 0x0181b880, + .name = "Davicom DM9161E", + .phy_id_mask = 0x0ffffff0, + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .close = dm9161_close, +}; + +static struct phy_info phy_info_marvell = { + .phy_id = 0x01410c00, + .phy_id_mask = 0xffffff00, + .name = "Marvell 88E1101", + .features = MII_GBIT_FEATURES, + .config_aneg = &marvell_config_aneg, + .read_status = &marvell_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, +}; + +static struct phy_info phy_info_genmii= { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .features = MII_BASIC_FEATURES, + .config_aneg = genmii_config_aneg, + .read_status = genmii_read_status, +}; + +static struct phy_info *phy_info[] = { + &phy_info_cis820x, + &phy_info_marvell, + &phy_info_dm9161, + &phy_info_genmii, + NULL +}; + +u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum) +{ + u16 retval; + unsigned long flags; + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); + + return retval; +} + +void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val) +{ + unsigned long flags; + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + mii_info->mdio_write(mii_info->dev, + mii_info->mii_id, + regnum, val); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); +} + +/* Use the PHY ID registers to determine what type of PHY is attached + * to device dev. return a struct phy_info structure describing that PHY + */ +struct phy_info * get_phy_info(struct gfar_mii_info *mii_info) +{ + u16 phy_reg; + u32 phy_ID; + int i; + struct phy_info *theInfo = NULL; + struct net_device *dev = mii_info->dev; + + /* Grab the bits from PHYIR1, and put them in the upper half */ + phy_reg = phy_read(mii_info, MII_PHYSID1); + phy_ID = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = phy_read(mii_info, MII_PHYSID2); + phy_ID |= (phy_reg & 0xffff); + + /* loop through all the known PHY types, and find one that */ + /* matches the ID we read from the PHY. */ + for (i = 0; phy_info[i]; i++) + if (phy_info[i]->phy_id == + (phy_ID & phy_info[i]->phy_id_mask)) { + theInfo = phy_info[i]; + break; + } + + /* This shouldn't happen, as we have generic PHY support */ + if (theInfo == NULL) { + printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID); + return NULL; + } else { + printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name, + phy_ID); + } + + return theInfo; +} diff -Nru a/drivers/net/gianfar_phy.h b/drivers/net/gianfar_phy.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/gianfar_phy.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,213 @@ +/* + * drivers/net/gianfar_phy.h + * + * Gianfar Ethernet Driver -- PHY handling + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __GIANFAR_PHY_H +#define __GIANFAR_PHY_H + +#define MII_end ((u32)-2) +#define MII_read ((u32)-1) + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define GFAR_AN_TIMEOUT 2000 + +/* 1000BT control (Marvell & BCM54xx at least) */ +#define MII_1000BASETCONTROL 0x09 +#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 +#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 + +/* Cicada Extended Control Register 1 */ +#define MII_CIS8201_EXT_CON1 0x17 +#define MII_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada Interrupt Mask Register */ +#define MII_CIS8201_IMASK 0x19 +#define MII_CIS8201_IMASK_IEN 0x8000 +#define MII_CIS8201_IMASK_SPEED 0x4000 +#define MII_CIS8201_IMASK_LINK 0x2000 +#define MII_CIS8201_IMASK_DUPLEX 0x1000 +#define MII_CIS8201_IMASK_MASK 0xf000 + +/* Cicada Interrupt Status Register */ +#define MII_CIS8201_ISTAT 0x1a +#define MII_CIS8201_ISTAT_STATUS 0x8000 +#define MII_CIS8201_ISTAT_SPEED 0x4000 +#define MII_CIS8201_ISTAT_LINK 0x2000 +#define MII_CIS8201_ISTAT_DUPLEX 0x1000 + +/* Cicada Auxiliary Control/Status Register */ +#define MII_CIS8201_AUX_CONSTAT 0x1c +#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MII_CIS8201_AUXCONSTAT_100 0x0008 + +/* 88E1011 PHY Status Register */ +#define MII_M1011_PHY_SPEC_STATUS 0x11 +#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 +#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 +#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 +#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 +#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 +#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 + +#define MII_M1011_IEVENT 0x13 +#define MII_M1011_IEVENT_CLEAR 0x0000 + +#define MII_M1011_IMASK 0x12 +#define MII_M1011_IMASK_INIT 0x6400 +#define MII_M1011_IMASK_CLEAR 0x0000 + +#define MII_DM9161_SCR 0x10 +#define MII_DM9161_SCR_INIT 0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MII_DM9161_SCSR 0x11 +#define MII_DM9161_SCSR_100F 0x8000 +#define MII_DM9161_SCSR_100H 0x4000 +#define MII_DM9161_SCSR_10F 0x2000 +#define MII_DM9161_SCSR_10H 0x1000 + +/* DM9161 Interrupt Register */ +#define MII_DM9161_INTR 0x15 +#define MII_DM9161_INTR_PEND 0x8000 +#define MII_DM9161_INTR_DPLX_MASK 0x0800 +#define MII_DM9161_INTR_SPD_MASK 0x0400 +#define MII_DM9161_INTR_LINK_MASK 0x0200 +#define MII_DM9161_INTR_MASK 0x0100 +#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 +#define MII_DM9161_INTR_SPD_CHANGE 0x0008 +#define MII_DM9161_INTR_LINK_CHANGE 0x0004 +#define MII_DM9161_INTR_INIT 0x0000 +#define MII_DM9161_INTR_STOP \ +(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ + | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) + +/* DM9161 10BT Configuration/Status */ +#define MII_DM9161_10BTCSR 0x12 +#define MII_DM9161_10BTCSR_INIT 0x7800 + +#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | \ + SUPPORTED_TP | \ + SUPPORTED_MII) + +#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | \ + SUPPORTED_1000baseT_Full) + +#define MII_READ_COMMAND 0x00000001 + +#define MII_INTERRUPT_DISABLED 0x0 +#define MII_INTERRUPT_ENABLED 0x1 +/* Taken from mii_if_info and sungem_phy.h */ +struct gfar_mii_info { + /* Information about the PHY type */ + /* And management functions */ + struct phy_info *phyinfo; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + + /* The most recently read link state */ + int link; + + /* Enabled Interrupts */ + u32 interrupts; + + u32 advertising; + int autoneg; + int mii_id; + + /* private data pointer */ + /* For use by PHYs to maintain extra state */ + void *priv; + + /* Provided by host chip */ + struct net_device *dev; + + /* A lock to ensure that only one thing can read/write + * the MDIO bus at a time */ + spinlock_t mdio_lock; + + /* Provided by ethernet driver */ + int (*mdio_read) (struct net_device *dev, int mii_id, int reg); + void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); +}; + +/* struct phy_info: a structure which defines attributes for a PHY + * + * id will contain a number which represents the PHY. During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is. The 32-bit result + * gotten from the PHY will be ANDed with phy_id_mask to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + * There are 6 commands which take a gfar_mii_info structure. + * Each PHY must declare config_aneg, and read_status. + */ +struct phy_info { + u32 phy_id; + char *name; + unsigned int phy_id_mask; + u32 features; + + /* Called to initialize the PHY */ + int (*init)(struct gfar_mii_info *mii_info); + + /* Called to suspend the PHY for power */ + int (*suspend)(struct gfar_mii_info *mii_info); + + /* Reconfigures autonegotiation (or disables it) */ + int (*config_aneg)(struct gfar_mii_info *mii_info); + + /* Determines the negotiated speed and duplex */ + int (*read_status)(struct gfar_mii_info *mii_info); + + /* Clears any pending interrupts */ + int (*ack_interrupt)(struct gfar_mii_info *mii_info); + + /* Enables or disables interrupts */ + int (*config_intr)(struct gfar_mii_info *mii_info); + + /* Clears up any memory if needed */ + void (*close)(struct gfar_mii_info *mii_info); +}; + +struct phy_info *get_phy_info(struct gfar_mii_info *mii_info); +int read_phy_reg(struct net_device *dev, int mii_id, int regnum); +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); +void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info); +void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts); + +struct dm9161_private { + struct timer_list timer; + int resetdone; +}; + +#endif /* GIANFAR_PHY_H */ diff -Nru a/drivers/net/gt64240eth.h b/drivers/net/gt64240eth.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/gt64240eth.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,402 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 Patton Electronics Company + * Copyright (C) 2002 Momentum Computer + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or support@mvista.com + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Ethernet driver definitions for the MIPS GT96100 Advanced + * Communication Controller. + * + * Modified for the Marvellous GT64240 Retarded Communication Controller. + */ +#ifndef _GT64240ETH_H +#define _GT64240ETH_H + +#include + +#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400 + +/* Translate those weanie names from Galileo/VxWorks header files: */ + +#define GT64240_MRR MAIN_ROUTING_REGISTER +#define GT64240_CIU_ARBITER_CONFIG COMM_UNIT_ARBITER_CONFIGURATION_REGISTER +#define GT64240_CIU_ARBITER_CONTROL COMM_UNIT_ARBITER_CONTROL +#define GT64240_MAIN_LOW_CAUSE LOW_INTERRUPT_CAUSE_REGISTER +#define GT64240_MAIN_HIGH_CAUSE HIGH_INTERRUPT_CAUSE_REGISTER +#define GT64240_CPU_LOW_MASK CPU_INTERRUPT_MASK_REGISTER_LOW +#define GT64240_CPU_HIGH_MASK CPU_INTERRUPT_MASK_REGISTER_HIGH +#define GT64240_CPU_SELECT_CAUSE CPU_SELECT_CAUSE_REGISTER + +#define GT64240_ETH_PHY_ADDR_REG ETHERNET_PHY_ADDRESS_REGISTER +#define GT64240_ETH_PORT_CONFIG ETHERNET0_PORT_CONFIGURATION_REGISTER +#define GT64240_ETH_PORT_CONFIG_EXT ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER +#define GT64240_ETH_PORT_COMMAND ETHERNET0_PORT_COMMAND_REGISTER +#define GT64240_ETH_PORT_STATUS ETHERNET0_PORT_STATUS_REGISTER +#define GT64240_ETH_IO_SIZE ETHERNET_PORTS_DIFFERENCE_OFFSETS +#define GT64240_ETH_SMI_REG ETHERNET_SMI_REGISTER +#define GT64240_ETH_MIB_COUNT_BASE ETHERNET0_MIB_COUNTER_BASE +#define GT64240_ETH_SDMA_CONFIG ETHERNET0_SDMA_CONFIGURATION_REGISTER +#define GT64240_ETH_SDMA_COMM ETHERNET0_SDMA_COMMAND_REGISTER +#define GT64240_ETH_INT_MASK ETHERNET0_INTERRUPT_MASK_REGISTER +#define GT64240_ETH_INT_CAUSE ETHERNET0_INTERRUPT_CAUSE_REGISTER +#define GT64240_ETH_CURR_TX_DESC_PTR0 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0 +#define GT64240_ETH_CURR_TX_DESC_PTR1 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1 +#define GT64240_ETH_1ST_RX_DESC_PTR0 ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0 +#define GT64240_ETH_CURR_RX_DESC_PTR0 ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0 +#define GT64240_ETH_HASH_TBL_PTR ETHERNET0_HASH_TABLE_POINTER_REGISTER + +/* Turn on NAPI by default */ + +#define GT64240_NAPI 1 + +/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */ +/* (Board-specific to the DSL3224 Rev A board ONLY!) */ +#define D3224_MPP_CTRL0_SETTING 0x66669900 +#define D3224_MPP_CTRL1_SETTING 0x00000000 +#define D3224_MPP_CTRL2_SETTING 0x00887700 +#define D3224_MPP_CTRL3_SETTING 0x00000044 +#define D3224_GPP_IO_CTRL_SETTING 0x0000e800 +#define D3224_GPP_LEVEL_CTRL_SETTING 0xf001f703 +#define D3224_GPP_VALUE_SETTING 0x00000000 + +/* Keep the ring sizes a power of two for efficiency. */ +//-#define TX_RING_SIZE 16 +#define TX_RING_SIZE 64 /* TESTING !!! */ +#define RX_RING_SIZE 32 +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + +#define RX_HASH_TABLE_SIZE 16384 +#define HASH_HOP_NUMBER 12 + +#define NUM_INTERFACES 3 + +#define GT64240ETH_TX_TIMEOUT HZ/4 + +#define MIPS_GT64240_BASE 0xf4000000 +#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG) +#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE) +#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE) + +#if defined(CONFIG_MIPS_DSL3224) +#define GT64240_ETHER0_IRQ 4 +#define GT64240_ETHER1_IRQ 4 +#else +#define GT64240_ETHER0_IRQ -1 +#define GT64240_ETHER1_IRQ -1 +#endif + +#define REV_GT64240 0x1 +#define REV_GT64240A 0x10 + +#define GT64240ETH_READ(gp, offset) \ + GT_READ((gp)->port_offset + (offset)) + +#define GT64240ETH_WRITE(gp, offset, data) \ + GT_WRITE((gp)->port_offset + (offset), (data)) + +#define GT64240ETH_SETBIT(gp, offset, bits) \ + GT64240ETH_WRITE((gp), (offset), \ + GT64240ETH_READ((gp), (offset)) | (bits)) + +#define GT64240ETH_CLRBIT(gp, offset, bits) \ + GT64240ETH_WRITE((gp), (offset), \ + GT64240ETH_READ((gp), (offset)) & ~(bits)) + +#define GT64240_READ(ofs) GT_READ(ofs) +#define GT64240_WRITE(ofs, data) GT_WRITE((ofs), (data)) + +/* Bit definitions of the SMI Reg */ +enum { + smirDataMask = 0xffff, + smirPhyAdMask = 0x1f << 16, + smirPhyAdBit = 16, + smirRegAdMask = 0x1f << 21, + smirRegAdBit = 21, + smirOpCode = 1 << 26, + smirReadValid = 1 << 27, + smirBusy = 1 << 28 +}; + +/* Bit definitions of the Port Config Reg */ +enum pcr_bits { + pcrPM = 1 << 0, + pcrRBM = 1 << 1, + pcrPBF = 1 << 2, + pcrEN = 1 << 7, + pcrLPBKMask = 0x3 << 8, + pcrLPBKBit = 1 << 8, + pcrFC = 1 << 10, + pcrHS = 1 << 12, + pcrHM = 1 << 13, + pcrHDM = 1 << 14, + pcrHD = 1 << 15, + pcrISLMask = 0x7 << 28, + pcrISLBit = 28, + pcrACCS = 1 << 31 +}; + +/* Bit definitions of the Port Config Extend Reg */ +enum pcxr_bits { + pcxrIGMP = 1, + pcxrSPAN = 2, + pcxrPAR = 4, + pcxrPRIOtxMask = 0x7 << 3, + pcxrPRIOtxBit = 3, + pcxrPRIOrxMask = 0x3 << 6, + pcxrPRIOrxBit = 6, + pcxrPRIOrxOverride = 1 << 8, + pcxrDPLXen = 1 << 9, + pcxrFCTLen = 1 << 10, + pcxrFLP = 1 << 11, + pcxrFCTL = 1 << 12, + pcxrMFLMask = 0x3 << 14, + pcxrMFLBit = 14, + pcxrMIBclrMode = 1 << 16, + pcxrSpeed = 1 << 18, + pcxrSpeeden = 1 << 19, + pcxrRMIIen = 1 << 20, + pcxrDSCPen = 1 << 21 +}; + +/* Bit definitions of the Port Command Reg */ +enum pcmr_bits { + pcmrFJ = 1 << 15 +}; + + +/* Bit definitions of the Port Status Reg */ +enum psr_bits { + psrSpeed = 1, + psrDuplex = 2, + psrFctl = 4, + psrLink = 8, + psrPause = 1 << 4, + psrTxLow = 1 << 5, + psrTxHigh = 1 << 6, + psrTxInProg = 1 << 7 +}; + +/* Bit definitions of the SDMA Config Reg */ +enum sdcr_bits { + sdcrRCMask = 0xf << 2, + sdcrRCBit = 2, + sdcrBLMR = 1 << 6, + sdcrBLMT = 1 << 7, + sdcrPOVR = 1 << 8, + sdcrRIFB = 1 << 9, + sdcrBSZMask = 0x3 << 12, + sdcrBSZBit = 12 +}; + +/* Bit definitions of the SDMA Command Reg */ +enum sdcmr_bits { + sdcmrERD = 1 << 7, + sdcmrAR = 1 << 15, + sdcmrSTDH = 1 << 16, + sdcmrSTDL = 1 << 17, + sdcmrTXDH = 1 << 23, + sdcmrTXDL = 1 << 24, + sdcmrAT = 1 << 31 +}; + +/* Bit definitions of the Interrupt Cause Reg */ +enum icr_bits { + icrRxBuffer = 1, + icrTxBufferHigh = 1 << 2, + icrTxBufferLow = 1 << 3, + icrTxEndHigh = 1 << 6, + icrTxEndLow = 1 << 7, + icrRxError = 1 << 8, + icrTxErrorHigh = 1 << 10, + icrTxErrorLow = 1 << 11, + icrRxOVR = 1 << 12, + icrTxUdr = 1 << 13, + icrRxBufferQ0 = 1 << 16, + icrRxBufferQ1 = 1 << 17, + icrRxBufferQ2 = 1 << 18, + icrRxBufferQ3 = 1 << 19, + icrRxErrorQ0 = 1 << 20, + icrRxErrorQ1 = 1 << 21, + icrRxErrorQ2 = 1 << 22, + icrRxErrorQ3 = 1 << 23, + icrMIIPhySTC = 1 << 28, + icrSMIdone = 1 << 29, + icrEtherIntSum = 1 << 31 +}; + + +/* The Rx and Tx descriptor lists. */ +#ifdef __LITTLE_ENDIAN +typedef struct { + u32 cmdstat; + u16 reserved; //-prk21aug01 u32 reserved:16; + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u32 buff_ptr; + u32 next; +} gt64240_td_t; + +typedef struct { + u32 cmdstat; + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u16 buff_sz; //-prk21aug01 u32 buff_sz:16; + u32 buff_ptr; + u32 next; +} gt64240_rd_t; +#elif defined(__BIG_ENDIAN) +typedef struct { + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u16 reserved; //-prk21aug01 u32 reserved:16; + u32 cmdstat; + u32 next; + u32 buff_ptr; +} gt64240_td_t; + +typedef struct { + u16 buff_sz; //-prk21aug01 u32 buff_sz:16; + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u32 cmdstat; + u32 next; + u32 buff_ptr; +} gt64240_rd_t; +#else +#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined! +#endif + + +/* Values for the Tx command-status descriptor entry. */ +enum td_cmdstat { + txOwn = 1 << 31, + txAutoMode = 1 << 30, + txEI = 1 << 23, + txGenCRC = 1 << 22, + txPad = 1 << 18, + txFirst = 1 << 17, + txLast = 1 << 16, + txErrorSummary = 1 << 15, + txReTxCntMask = 0x0f << 10, + txReTxCntBit = 10, + txCollision = 1 << 9, + txReTxLimit = 1 << 8, + txUnderrun = 1 << 6, + txLateCollision = 1 << 5 +}; + + +/* Values for the Rx command-status descriptor entry. */ +enum rd_cmdstat { + rxOwn = 1 << 31, + rxAutoMode = 1 << 30, + rxEI = 1 << 23, + rxFirst = 1 << 17, + rxLast = 1 << 16, + rxErrorSummary = 1 << 15, + rxIGMP = 1 << 14, + rxHashExpired = 1 << 13, + rxMissedFrame = 1 << 12, + rxFrameType = 1 << 11, + rxShortFrame = 1 << 8, + rxMaxFrameLen = 1 << 7, + rxOverrun = 1 << 6, + rxCollision = 1 << 4, + rxCRCError = 1 +}; + +/* Bit fields of a Hash Table Entry */ +enum hash_table_entry { + hteValid = 1, + hteSkip = 2, + hteRD = 4 +}; + +// The MIB counters +typedef struct { + u32 byteReceived; + u32 byteSent; + u32 framesReceived; + u32 framesSent; + u32 totalByteReceived; + u32 totalFramesReceived; + u32 broadcastFramesReceived; + u32 multicastFramesReceived; + u32 cRCError; + u32 oversizeFrames; + u32 fragments; + u32 jabber; + u32 collision; + u32 lateCollision; + u32 frames64; + u32 frames65_127; + u32 frames128_255; + u32 frames256_511; + u32 frames512_1023; + u32 frames1024_MaxSize; + u32 macRxError; + u32 droppedFrames; + u32 outMulticastFrames; + u32 outBroadcastFrames; + u32 undersizeFrames; +} mib_counters_t; + + +struct gt64240_private { + gt64240_rd_t *rx_ring; + gt64240_td_t *tx_ring; + // The Rx and Tx rings must be 16-byte aligned + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + char *hash_table; + // The Hash Table must be 8-byte aligned + dma_addr_t hash_table_dma; + int hash_mode; + + // The Rx buffers must be 8-byte aligned + char *rx_buff; + dma_addr_t rx_buff_dma; + // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes + // of payload must be 8-byte aligned + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + int rx_next_out; /* The next free ring entry to receive */ + int tx_next_in; /* The next free ring entry to send */ + int tx_next_out; /* The last ring entry the ISR processed */ + int tx_count; /* current # of pkts waiting to be sent in Tx ring */ + int intr_work_done; /* number of Rx and Tx pkts processed in the isr */ + int tx_full; /* Tx ring is full */ + + mib_counters_t mib; + struct net_device_stats stats; + + int io_size; + int port_num; // 0 or 1 + u32 port_offset; + + int phy_addr; // PHY address + u32 last_psr; // last value of the port status register + + int options; /* User-settable misc. driver options. */ + int drv_flags; + spinlock_t lock; /* Serialise access to device */ + struct mii_if_info mii_if; + + u32 msg_enable; +}; + +#endif /* _GT64240ETH_H */ diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c --- a/drivers/net/gt96100eth.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/gt96100eth.c 2004-10-18 14:56:49 -07:00 @@ -28,7 +28,6 @@ * gt96100_cleanup_module(), and other general code cleanups * . */ -#include #include #include #include @@ -66,10 +65,6 @@ static void read_mib_counters(struct gt96100_private *gp); static int read_MII(int phy_addr, u32 reg); static int write_MII(int phy_addr, u32 reg, u16 data); -#if 0 -static void dump_tx_ring(struct net_device *dev); -static void dump_rx_ring(struct net_device *dev); -#endif static int gt96100_init_module(void); static void gt96100_cleanup_module(void); static void dump_MII(int dbg_lvl, struct net_device *dev); @@ -84,7 +79,7 @@ static void hard_stop(struct net_device *dev); static void enable_ether_irq(struct net_device *dev); static void disable_ether_irq(struct net_device *dev); -static int gt96100_probe1(int port_num); +static int gt96100_probe1(struct pci_dev *pci, int port_num); static void reset_tx(struct net_device *dev); static void reset_rx(struct net_device *dev); static int gt96100_check_tx_consistent(struct gt96100_private *gp); @@ -164,13 +159,11 @@ /* DMA memory allocation, derived from pci_alloc_consistent. */ -static void * -dmaalloc(size_t size, dma_addr_t *dma_handle) +static void * dmaalloc(size_t size, dma_addr_t *dma_handle) { void *ret; - ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, - get_order(size)); + ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, get_order(size)); if (ret != NULL) { dma_cache_inv((unsigned long)ret, size); @@ -184,17 +177,13 @@ return ret; } -static void -dmafree(size_t size, void *vaddr) +static void dmafree(size_t size, void *vaddr) { vaddr = (void*)KSEG0ADDR(vaddr); free_pages((unsigned long)vaddr, get_order(size)); } - - -static void -gt96100_delay(int ms) +static void gt96100_delay(int ms) { if (in_interrupt()) return; @@ -327,34 +316,6 @@ return 0; } -#if 0 -// These routines work, just disabled to avoid compile warnings -static void -dump_tx_ring(struct net_device *dev) -{ - struct gt96100_private *gp = netdev_priv(dev); - int i; - - dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__, - gp->tx_next_out, gp->tx_next_in, gp->tx_count); - - for (i=0; irx_next_out); - - for (i=0; iirq < 0) { - printk(KERN_ERR "%s: irq unknown - probing not supported\n", __FUNCTION_); + printk(KERN_ERR "%s: irq unknown - probing not supported\n", + __FUNCTION__); return -ENODEV; } - pcibios_read_config_byte(0, 0, PCI_REVISION_ID, &chip_rev); + pci_read_config_byte(pci, PCI_REVISION_ID, &chip_rev); if (chip_rev >= REV_GT96100A_1) { phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); phy_addr = (phyAD >> (5*port_num)) & 0x1f; } else { /* - * not sure what's this about -- probably - * a gt bug + * not sure what's this about -- probably a gt bug */ phy_addr = port_num; phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); @@ -831,6 +784,7 @@ free_netdev (dev); out: release_region(gtif->iobase, GT96100_ETH_IO_SIZE); + err("%s failed. Returns %d\n", __FUNCTION__, retval); return retval; } @@ -1102,6 +1056,7 @@ } free_irq(dev->irq, dev); + return 0; } @@ -1312,10 +1267,11 @@ cmdstat, nextOut); if (cmdstat & (u32)txOwn) { - //dump_tx_ring(dev); - // DMA is not finished writing descriptor??? - // Leave and come back later to pick-up where - // we left off. + /* + * DMA is not finished writing descriptor??? + * Leave and come back later to pick-up where + * we left off. + */ break; } @@ -1342,7 +1298,8 @@ gp->tx_full = 0; if (gp->last_psr & psrLink) { netif_wake_queue(dev); - dbg(2, "%s: Tx Ring was full, queue waked\n", __FUNCTION_); + dbg(2, "%s: Tx Ring was full, queue waked\n", + __FUNCTION__); } } @@ -1425,12 +1382,12 @@ if ((psr & psrLink) && !gp->tx_full && netif_queue_stopped(dev)) { - dbg(0, ": Link up, waking queue.\n", - __FUNCTION_); + dbg(0, "%s: Link up, waking queue.\n", + __FUNCTION__); netif_wake_queue(dev); } else if (!(psr & psrLink) && !netif_queue_stopped(dev)) { - dbg(0, "Link down, stopping queue.\n", + dbg(0, "%s: Link down, stopping queue.\n", __FUNCTION__); netif_stop_queue(dev); } @@ -1569,8 +1526,8 @@ for (i=0; idev != NULL) { - struct gt96100_private *gp = - (struct gt96100_private *)gtif->dev->priv; + struct gt96100_private *gp = (struct gt96100_private *) + netdev_priv(gtif->dev); unregister_netdev(gtif->dev); dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); @@ -1583,9 +1540,6 @@ } } - -#ifndef MODULE - static int __init gt96100_setup(char *options) { char *this_opt; @@ -1609,9 +1563,6 @@ } __setup("gt96100eth=", gt96100_setup); - -#endif /* !MODULE */ - module_init(gt96100_init_module); module_exit(gt96100_cleanup_module); diff -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c --- a/drivers/net/hamachi.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/net/hamachi.c 2004-10-18 14:57:05 -07:00 @@ -559,7 +559,7 @@ static void hamachi_init_ring(struct net_device *dev); static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static inline int hamachi_rx(struct net_device *dev); +static int hamachi_rx(struct net_device *dev); static inline int hamachi_tx(struct net_device *dev); static void hamachi_error(struct net_device *dev, int intr_status); static int hamachi_close(struct net_device *dev); diff -Nru a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c --- a/drivers/net/hamradio/bpqether.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/hamradio/bpqether.c 2004-10-18 14:56:29 -07:00 @@ -193,7 +193,7 @@ bpq = (struct bpqdev *)dev->priv; - eth = (struct ethhdr *)skb->mac.raw; + eth = eth_hdr(skb); if (!(bpq->acpt_addr[0] & 0x01) && memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c --- a/drivers/net/hamradio/dmascc.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/hamradio/dmascc.c 2004-10-18 14:56:29 -07:00 @@ -246,8 +246,14 @@ static struct net_device_stats *scc_get_stats(struct net_device *dev); static int scc_set_mac_address(struct net_device *dev, void *sa); -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs); +static inline void tx_on(struct scc_priv *priv); +static inline void rx_on(struct scc_priv *priv); +static inline void rx_off(struct scc_priv *priv); +static void start_timer(struct scc_priv *priv, int t, int r15); +static inline unsigned char random(void); + static inline void z8530_isr(struct scc_info *info); +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs); static void rx_isr(struct scc_priv *priv); static void special_condition(struct scc_priv *priv, int rc); static void rx_bh(void *arg); @@ -255,12 +261,6 @@ static void es_isr(struct scc_priv *priv); static void tm_isr(struct scc_priv *priv); -static inline void tx_on(struct scc_priv *priv); -static inline void rx_on(struct scc_priv *priv); -static inline void rx_off(struct scc_priv *priv); -static void start_timer(struct scc_priv *priv, int t, int r15); -static inline unsigned char random(void); - /* Initialization variables */ @@ -945,42 +945,115 @@ } -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs) { - struct scc_info *info = dev_id; +static inline void tx_on(struct scc_priv *priv) { + int i, n; + unsigned long flags; - spin_lock(info->priv[0].register_lock); - /* At this point interrupts are enabled, and the interrupt under service - is already acknowledged, but masked off. + if (priv->param.dma >= 0) { + n = (priv->chip == Z85230) ? 3 : 1; + /* Program DMA controller */ + flags = claim_dma_lock(); + set_dma_mode(priv->param.dma, DMA_MODE_WRITE); + set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n); + set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n); + release_dma_lock(flags); + /* Enable TX underrun interrupt */ + write_scc(priv, R15, TxUIE); + /* Configure DREQ */ + if (priv->type == TYPE_TWIN) + outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, + priv->card_base + TWIN_DMA_CFG); + else + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); + /* Write first byte(s) */ + spin_lock_irqsave(priv->register_lock, flags); + for (i = 0; i < n; i++) + write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1); + enable_dma(priv->param.dma); + spin_unlock_irqrestore(priv->register_lock, flags); + } else { + write_scc(priv, R15, TxUIE); + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); + tx_isr(priv); + } + /* Reset EOM latch if we do not have the AUTOEOM feature */ + if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L); +} - Interrupt processing: We loop until we know that the IRQ line is - low. If another positive edge occurs afterwards during the ISR, - another interrupt will be triggered by the interrupt controller - as soon as the IRQ level is enabled again (see asm/irq.h). - Bottom-half handlers will be processed after scc_isr(). This is - important, since we only have small ringbuffers and want new data - to be fetched/delivered immediately. */ +static inline void rx_on(struct scc_priv *priv) { + unsigned long flags; - if (info->priv[0].type == TYPE_TWIN) { - int is, card_base = info->priv[0].card_base; - while ((is = ~inb(card_base + TWIN_INT_REG)) & - TWIN_INT_MSK) { - if (is & TWIN_SCC_MSK) { - z8530_isr(info); - } else if (is & TWIN_TMR1_MSK) { - inb(card_base + TWIN_CLR_TMR1); - tm_isr(&info->priv[0]); - } else { - inb(card_base + TWIN_CLR_TMR2); - tm_isr(&info->priv[1]); - } + /* Clear RX FIFO */ + while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv); + priv->rx_over = 0; + if (priv->param.dma >= 0) { + /* Program DMA controller */ + flags = claim_dma_lock(); + set_dma_mode(priv->param.dma, DMA_MODE_READ); + set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); + set_dma_count(priv->param.dma, BUF_SIZE); + release_dma_lock(flags); + enable_dma(priv->param.dma); + /* Configure PackeTwin DMA */ + if (priv->type == TYPE_TWIN) { + outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, + priv->card_base + TWIN_DMA_CFG); } - } else z8530_isr(info); - spin_unlock(info->priv[0].register_lock); - return IRQ_HANDLED; + /* Sp. cond. intr. only, ext int enable, RX DMA enable */ + write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | + WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); + } else { + /* Reset current frame */ + priv->rx_ptr = 0; + /* Intr. on all Rx characters and Sp. cond., ext int enable */ + write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | + WT_FN_RDYFN); + } + write_scc(priv, R0, ERR_RES); + write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); +} + + +static inline void rx_off(struct scc_priv *priv) { + /* Disable receiver */ + write_scc(priv, R3, Rx8); + /* Disable DREQ / RX interrupt */ + if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) + outb(0, priv->card_base + TWIN_DMA_CFG); + else + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); + /* Disable DMA */ + if (priv->param.dma >= 0) disable_dma(priv->param.dma); +} + + +static void start_timer(struct scc_priv *priv, int t, int r15) { + unsigned long flags; + + outb(priv->tmr_mode, priv->tmr_ctrl); + if (t == 0) { + tm_isr(priv); + } else if (t > 0) { + save_flags(flags); + cli(); + outb(t & 0xFF, priv->tmr_cnt); + outb((t >> 8) & 0xFF, priv->tmr_cnt); + if (priv->type != TYPE_TWIN) { + write_scc(priv, R15, r15 | CTSIE); + priv->rr0 |= CTS; + } + restore_flags(flags); + } } +static inline unsigned char random(void) { + /* See "Numerical Recipes in C", second edition, p. 284 */ + rand = rand * 1664525L + 1013904223L; + return (unsigned char) (rand >> 24); +} + static inline void z8530_isr(struct scc_info *info) { int is, i = 100; @@ -1009,6 +1082,42 @@ } +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs) { + struct scc_info *info = dev_id; + + spin_lock(info->priv[0].register_lock); + /* At this point interrupts are enabled, and the interrupt under service + is already acknowledged, but masked off. + + Interrupt processing: We loop until we know that the IRQ line is + low. If another positive edge occurs afterwards during the ISR, + another interrupt will be triggered by the interrupt controller + as soon as the IRQ level is enabled again (see asm/irq.h). + + Bottom-half handlers will be processed after scc_isr(). This is + important, since we only have small ringbuffers and want new data + to be fetched/delivered immediately. */ + + if (info->priv[0].type == TYPE_TWIN) { + int is, card_base = info->priv[0].card_base; + while ((is = ~inb(card_base + TWIN_INT_REG)) & + TWIN_INT_MSK) { + if (is & TWIN_SCC_MSK) { + z8530_isr(info); + } else if (is & TWIN_TMR1_MSK) { + inb(card_base + TWIN_CLR_TMR1); + tm_isr(&info->priv[0]); + } else { + inb(card_base + TWIN_CLR_TMR2); + tm_isr(&info->priv[1]); + } + } + } else z8530_isr(info); + spin_unlock(info->priv[0].register_lock); + return IRQ_HANDLED; +} + + static void rx_isr(struct scc_priv *priv) { if (priv->param.dma >= 0) { /* Check special condition and perform error reset. See 2.4.7.5. */ @@ -1292,114 +1401,3 @@ break; } } - - -static inline void tx_on(struct scc_priv *priv) { - int i, n; - unsigned long flags; - - if (priv->param.dma >= 0) { - n = (priv->chip == Z85230) ? 3 : 1; - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_WRITE); - set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n); - set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n); - release_dma_lock(flags); - /* Enable TX underrun interrupt */ - write_scc(priv, R15, TxUIE); - /* Configure DREQ */ - if (priv->type == TYPE_TWIN) - outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, - priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); - /* Write first byte(s) */ - spin_lock_irqsave(priv->register_lock, flags); - for (i = 0; i < n; i++) - write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1); - enable_dma(priv->param.dma); - spin_unlock_irqrestore(priv->register_lock, flags); - } else { - write_scc(priv, R15, TxUIE); - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); - tx_isr(priv); - } - /* Reset EOM latch if we do not have the AUTOEOM feature */ - if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L); -} - - -static inline void rx_on(struct scc_priv *priv) { - unsigned long flags; - - /* Clear RX FIFO */ - while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv); - priv->rx_over = 0; - if (priv->param.dma >= 0) { - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_READ); - set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); - set_dma_count(priv->param.dma, BUF_SIZE); - release_dma_lock(flags); - enable_dma(priv->param.dma); - /* Configure PackeTwin DMA */ - if (priv->type == TYPE_TWIN) { - outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, - priv->card_base + TWIN_DMA_CFG); - } - /* Sp. cond. intr. only, ext int enable, RX DMA enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | - WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); - } else { - /* Reset current frame */ - priv->rx_ptr = 0; - /* Intr. on all Rx characters and Sp. cond., ext int enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | - WT_FN_RDYFN); - } - write_scc(priv, R0, ERR_RES); - write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); -} - - -static inline void rx_off(struct scc_priv *priv) { - /* Disable receiver */ - write_scc(priv, R3, Rx8); - /* Disable DREQ / RX interrupt */ - if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) - outb(0, priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - /* Disable DMA */ - if (priv->param.dma >= 0) disable_dma(priv->param.dma); -} - - -static void start_timer(struct scc_priv *priv, int t, int r15) { - unsigned long flags; - - outb(priv->tmr_mode, priv->tmr_ctrl); - if (t == 0) { - tm_isr(priv); - } else if (t > 0) { - save_flags(flags); - cli(); - outb(t & 0xFF, priv->tmr_cnt); - outb((t >> 8) & 0xFF, priv->tmr_cnt); - if (priv->type != TYPE_TWIN) { - write_scc(priv, R15, r15 | CTSIE); - priv->rr0 |= CTS; - } - restore_flags(flags); - } -} - - -static inline unsigned char random(void) { - /* See "Numerical Recipes in C", second edition, p. 284 */ - rand = rand * 1664525L + 1013904223L; - return (unsigned char) (rand >> 24); -} - diff -Nru a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c --- a/drivers/net/hamradio/mkiss.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/hamradio/mkiss.c 2004-10-18 14:57:04 -07:00 @@ -602,8 +602,6 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); /* Restore default settings */ ax->dev->type = ARPHRD_AX25; diff -Nru a/drivers/net/hp100.c b/drivers/net/hp100.c --- a/drivers/net/hp100.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/hp100.c 2004-10-18 14:56:28 -07:00 @@ -2906,13 +2906,19 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); - int ioaddr = pci_resource_start(pdev, 0); + struct net_device *dev; + int ioaddr; u_short pci_command; int err; - - if (!dev) - return -ENOMEM; + + if (pci_enable_device(pdev)) + return -ENODEV; + + dev = alloc_etherdev(sizeof(struct hp100_private)); + if (!dev) { + err = -ENOMEM; + goto out0; + } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -2934,7 +2940,7 @@ pci_write_config_word(pdev, PCI_COMMAND, pci_command); } - + ioaddr = pci_resource_start(pdev, 0); err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev); if (err) goto out1; @@ -2951,6 +2957,8 @@ release_region(dev->base_addr, HP100_REGION_SIZE); out1: free_netdev(dev); + out0: + pci_disable_device(pdev); return err; } @@ -2959,6 +2967,7 @@ struct net_device *dev = pci_get_drvdata(pdev); cleanup_dev(dev); + pci_disable_device(pdev); } diff -Nru a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h --- a/drivers/net/ibm_emac/ibm_emac.h 2004-10-18 14:56:31 -07:00 +++ b/drivers/net/ibm_emac/ibm_emac.h 2004-10-18 14:56:31 -07:00 @@ -228,6 +228,21 @@ (desc & EMAC_BAD_RX_PACKET) #endif +/* SoC implementation specific EMAC register defaults */ +#if defined(CONFIG_440GP) +#define EMAC_RWMR_DEFAULT 0x80009000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0xf8640000 +#elif defined(CONFIG_440GX) +#define EMAC_RWMR_DEFAULT 0x1000a200 +#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 +#define EMAC_TMR1_DEFAULT 0xa00f0000 +#else +#define EMAC_RWMR_DEFAULT 0x0f002000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0x380f0000 +#endif /* CONFIG_440GP */ + /* Revision specific EMAC register defaults */ #ifdef CONFIG_IBM_EMAC4 #define EMAC_M1_DEFAULT (EMAC_M1_BASE | \ @@ -236,7 +251,7 @@ #define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \ EMAC_RMR_RFAF_128_2048) #define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \ - EMAC_TMR0_TFAE_128_2048) + EMAC_TMR0_DEFAULT) #define EMAC_TRTR_DEFAULT EMAC_TRTR_1024 #else /* !CONFIG_IBM_EMAC4 */ #define EMAC_M1_DEFAULT EMAC_M1_BASE @@ -244,20 +259,5 @@ #define EMAC_TMR0_XMIT EMAC_TMR0_GNP0 #define EMAC_TRTR_DEFAULT EMAC_TRTR_1600 #endif /* CONFIG_IBM_EMAC4 */ - -/* SoC implementation specific EMAC register defaults */ -#if defined(CONFIG_440GP) -#define EMAC_RWMR_DEFAULT 0x80009000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0xf8640000 -#elif defined(CONFIG_440GX) -#define EMAC_RWMR_DEFAULT 0x1000a200 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048 -#define EMAC_TMR1_DEFAULT 0x88810000 -#else -#define EMAC_RWMR_DEFAULT 0x0f002000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0x380f0000 -#endif /* CONFIG_440GP */ #endif diff -Nru a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c --- a/drivers/net/ibm_emac/ibm_emac_core.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/ibm_emac/ibm_emac_core.c 2004-10-18 14:55:54 -07:00 @@ -90,23 +90,24 @@ #define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev)) -static unsigned int rgmii_enable[] = - { RGMII_RTBI, RGMII_RGMII, RGMII_TBI, RGMII_GMII }; +static unsigned int rgmii_enable[] = { + RGMII_RTBI, + RGMII_RGMII, + RGMII_TBI, + RGMII_GMII +}; -static unsigned int rgmii_speed_mask[] = { 0, - 0, +static unsigned int rgmii_speed_mask[] = { RGMII_MII2_SPDMASK, RGMII_MII3_SPDMASK }; -static unsigned int rgmii_speed100[] = { 0, - 0, +static unsigned int rgmii_speed100[] = { RGMII_MII2_100MB, RGMII_MII3_100MB }; -static unsigned int rgmii_speed1000[] = { 0, - 0, +static unsigned int rgmii_speed1000[] = { RGMII_MII2_1000MB, RGMII_MII3_1000MB }; @@ -122,11 +123,21 @@ ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI3)}, {ZMII_SMII3, ZMII_RMII3, ZMII_MII3, ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI2)} }; -static unsigned int mdi_enable[] = - { ZMII_MDI0, ZMII_MDI1, ZMII_MDI2, ZMII_MDI3 }; + +static unsigned int mdi_enable[] = { + ZMII_MDI0, + ZMII_MDI1, + ZMII_MDI2, + ZMII_MDI3 +}; static unsigned int zmii_speed = 0x0; -static unsigned int zmii_speed100[] = { ZMII_MII0_100MB, ZMII_MII1_100MB }; +static unsigned int zmii_speed100[] = { + ZMII_MII0_100MB, + ZMII_MII1_100MB, + ZMII_MII2_100MB, + ZMII_MII3_100MB +}; /* Since multiple EMACs share MDIO lines in various ways, we need * to avoid re-using the same PHY ID in cases where the arch didn't @@ -367,6 +378,7 @@ int emac_phy_read(struct net_device *dev, int mii_id, int reg) { + int count; uint32_t stacr; struct ocp_enet_private *fep = dev->priv; emac_t *emacp = fep->emacp; @@ -385,9 +397,13 @@ emacp = fep->emacp; } - udelay(MDIO_DELAY); + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); - if ((in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) { + if ((stacr & EMAC_STACR_OC) == 0) { printk(KERN_WARNING "%s: PHY read timeout #1!\n", dev->name); return -1; } @@ -398,8 +414,11 @@ out_be32(&emacp->em0stacr, stacr); - udelay(MDIO_DELAY); - stacr = in_be32(&emacp->em0stacr); + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); if ((stacr & EMAC_STACR_OC) == 0) { printk(KERN_WARNING "%s: PHY read timeout #2!\n", dev->name); @@ -419,6 +438,7 @@ void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data) { + int count; uint32_t stacr; struct ocp_enet_private *fep = dev->priv; emac_t *emacp = fep->emacp; @@ -437,9 +457,13 @@ emacp = fep->emacp; } - udelay(MDIO_DELAY); + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); - if ((in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) { + if ((stacr & EMAC_STACR_OC) == 0) { printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); return; } @@ -451,9 +475,12 @@ out_be32(&emacp->em0stacr, stacr); - udelay(MDIO_DELAY); + while (((stacr = in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) + && (count++ < 5000)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); - if ((in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) + if ((stacr & EMAC_STACR_OC) == 0) printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); /* Check for a write error */ @@ -1940,8 +1967,6 @@ static int __init emac_init(void) { - int rc; - printk(KERN_INFO DRV_NAME ": " DRV_DESC ", version " DRV_VERSION "\n"); printk(KERN_INFO "Maintained by " DRV_AUTHOR "\n"); @@ -1950,13 +1975,8 @@ skb_res); skb_res = 2; } - rc = ocp_register_driver(&emac_driver); - if (rc < 0) { - ocp_unregister_driver(&emac_driver); - return -ENODEV; - } - return 0; + return ocp_register_driver(&emac_driver); } static void __exit emac_exit(void) diff -Nru a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h --- a/drivers/net/ibm_emac/ibm_emac_core.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/net/ibm_emac/ibm_emac_core.h 2004-10-18 14:56:17 -07:00 @@ -67,7 +67,7 @@ #define TX_TIMEOUT (2*HZ) /* MDIO latency delay */ -#define MDIO_DELAY 50 +#define MDIO_DELAY 250 /* Power managment shift registers */ #define IBM_CPM_EMMII 0 /* Shift value for MII */ diff -Nru a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c --- a/drivers/net/ibm_emac/ibm_emac_mal.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/net/ibm_emac/ibm_emac_mal.c 2004-10-18 14:57:03 -07:00 @@ -55,8 +55,6 @@ write_unlock_irqrestore(&mal_list_lock, flags); - MOD_INC_USE_COUNT; - return 0; } @@ -72,8 +70,6 @@ list_del_init(&commac->list); write_unlock_irqrestore(&mal_list_lock, flags); - - MOD_DEC_USE_COUNT; return 0; } diff -Nru a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c --- a/drivers/net/ibmveth.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/net/ibmveth.c 2004-10-18 14:55:46 -07:00 @@ -2,8 +2,8 @@ /* */ /* IBM eServer i/pSeries Virtual Ethernet Device Driver */ /* Copyright (C) 2003 IBM Corp. */ -/* Dave Larson (larson1@us.ibm.com) */ -/* Santiago Leon (santil@us.ibm.com) */ +/* Originally written by Dave Larson (larson1@us.ibm.com) */ +/* Maintained by Santiago Leon (santil@us.ibm.com) */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ @@ -104,11 +104,12 @@ static const char ibmveth_driver_name[] = "ibmveth"; static const char ibmveth_driver_string[] = "IBM i/pSeries Virtual Ethernet Driver"; -static const char ibmveth_driver_version[] = "1.0"; +#define ibmveth_driver_version "1.02" -MODULE_AUTHOR("Dave Larson "); +MODULE_AUTHOR("Santiago Leon "); MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(ibmveth_driver_version); /* simple methods of getting data from the current rxq entry */ static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter) @@ -213,11 +214,12 @@ free_index = pool->consumer_index++ % pool->size; index = pool->free_map[free_index]; - ibmveth_assert(index != 0xffff); + ibmveth_assert(index != IBM_VETH_INVALID_MAP); ibmveth_assert(pool->skbuff[index] == NULL); dma_addr = vio_map_single(adapter->vdev, skb->data, pool->buff_size, DMA_FROM_DEVICE); + pool->free_map[free_index] = IBM_VETH_INVALID_MAP; pool->dma_addr[index] = dma_addr; pool->skbuff[index] = skb; @@ -232,6 +234,7 @@ lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); if(lpar_rc != H_Success) { + pool->free_map[free_index] = IBM_VETH_INVALID_MAP; pool->skbuff[index] = NULL; pool->consumer_index--; vio_unmap_single(adapter->vdev, pool->dma_addr[index], pool->buff_size, DMA_FROM_DEVICE); @@ -239,7 +242,6 @@ adapter->replenish_add_buff_failure++; break; } else { - pool->free_map[free_index] = 0xffff; buffers_added++; adapter->replenish_add_buff_success++; } @@ -269,7 +271,6 @@ adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); atomic_inc(&adapter->not_replenishing); - ibmveth_assert(atomic_read(&adapter->not_replenishing) == 1); } /* kick the replenish tasklet if we need replenishing and it isn't already running */ @@ -528,7 +529,7 @@ ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); do { rc = h_free_logical_lan(adapter->vdev->unit_address); - } while H_isLongBusy(rc); + } while (H_isLongBusy(rc) || (rc == H_Busy)); ibmveth_cleanup(adapter); return rc; @@ -560,7 +561,7 @@ do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); - } while H_isLongBusy(lpar_rc); + } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); if(lpar_rc != H_Success) { @@ -732,6 +733,8 @@ if(ibmveth_rxq_pending_buffer(adapter)) { struct sk_buff *skb; + rmb(); + if(!ibmveth_rxq_buffer_valid(adapter)) { wmb(); /* suggested by larson1 */ adapter->rx_invalid_buffer++; @@ -882,13 +885,16 @@ mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0); if(!mac_addr_p) { - ibmveth_error_printk("Can't find VETH_MAC_ADDR attribute\n"); + printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR " + "attribute\n", __FILE__, __LINE__); return 0; } mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0); if(!mcastFilterSize_p) { - ibmveth_error_printk("Can't find VETH_MCAST_FILTER_SIZE attribute\n"); + printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find " + "VETH_MCAST_FILTER_SIZE attribute\n", + __FILE__, __LINE__); return 0; } diff -Nru a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h --- a/drivers/net/ibmveth.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/ibmveth.h 2004-10-18 14:56:33 -07:00 @@ -77,6 +77,8 @@ #define IbmVethPool1DftCnt 256 #define IbmVethPool2DftCnt 256 +#define IBM_VETH_INVALID_MAP ((u16)0xffff) + struct ibmveth_buff_pool { u32 size; u32 index; diff -Nru a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c --- a/drivers/net/ioc3-eth.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/ioc3-eth.c 2004-10-18 14:55:54 -07:00 @@ -506,7 +506,7 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) { - struct ethhdr *eh = skb->mac.ethernet; + struct ethhdr *eh = eth_hdr(skb); uint32_t csum, ehsum; unsigned int proto; struct iphdr *ih; @@ -1333,7 +1333,7 @@ uint32_t csum, ehsum; uint16_t *eh; - /* The MAC header. skb->mac.ethernet seem the logic approach + /* The MAC header. skb->mac seem the logic approach to find the MAC header - except it's a NULL pointer ... */ eh = (uint16_t *) skb->data; diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c --- a/drivers/net/irda/irda-usb.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/net/irda/irda-usb.c 2004-10-18 14:56:32 -07:00 @@ -268,7 +268,6 @@ speed_bulk_callback, self); urb->transfer_buffer_length = USB_IRDA_HEADER; urb->transfer_flags = URB_ASYNC_UNLINK; - urb->timeout = msecs_to_jiffies(100); /* Irq disabled -> GFP_ATOMIC */ if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) { @@ -411,8 +410,6 @@ * after each of our packets that is exact multiple of the frame size. * This is how the dongle will detect the end of packet - Jean II */ urb->transfer_flags |= URB_ZERO_PACKET; - /* Timeout need to be shorter than NET watchdog timer */ - urb->timeout = msecs_to_jiffies(200); /* Generate min turn time. FIXME: can we do better than this? */ /* Trying to a turnaround time at this level is trying to measure diff -Nru a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c --- a/drivers/net/irda/irtty-sir.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/net/irda/irtty-sir.c 2004-10-18 14:55:46 -07:00 @@ -509,13 +509,6 @@ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); -/* from old irtty - but what is it good for? - * we _are_ the ldisc and we _don't_ implement flush_buffer! - * - * if (tty->ldisc.flush_buffer) - * tty->ldisc.flush_buffer(tty); - */ - /* apply mtt override */ sir_tty_drv.qos_mtt_bits = qos_mtt_bits; diff -Nru a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c --- a/drivers/net/ixgb/ixgb_main.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/net/ixgb/ixgb_main.c 2004-10-18 14:56:17 -07:00 @@ -55,6 +55,8 @@ /* Local Function Prototypes */ +static inline void ixgb_irq_disable(struct ixgb_adapter *adapter); +static inline void ixgb_irq_enable(struct ixgb_adapter *adapter); int ixgb_up(struct ixgb_adapter *adapter); void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog); void ixgb_reset(struct ixgb_adapter *adapter); @@ -82,10 +84,11 @@ static int ixgb_change_mtu(struct net_device *netdev, int new_mtu); static int ixgb_set_mac(struct net_device *netdev, void *p); static void ixgb_update_stats(struct ixgb_adapter *adapter); -static inline void ixgb_irq_disable(struct ixgb_adapter *adapter); -static inline void ixgb_irq_enable(struct ixgb_adapter *adapter); static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs); static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter); +static inline void ixgb_rx_checksum(struct ixgb_adapter *adapter, + struct ixgb_rx_desc *rx_desc, + struct sk_buff *skb); #ifdef CONFIG_IXGB_NAPI static int ixgb_clean(struct net_device *netdev, int *budget); static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter, @@ -95,9 +98,6 @@ #endif static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter); static int ixgb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); -static inline void ixgb_rx_checksum(struct ixgb_adapter *adapter, - struct ixgb_rx_desc *rx_desc, - struct sk_buff *skb); static void ixgb_tx_timeout(struct net_device *dev); static void ixgb_tx_timeout_task(struct net_device *dev); static void ixgb_vlan_rx_register(struct net_device *netdev, @@ -185,6 +185,34 @@ module_exit(ixgb_exit_module); +/** + * ixgb_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ + +static inline void ixgb_irq_disable(struct ixgb_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + IXGB_WRITE_REG(&adapter->hw, IMC, ~0); + IXGB_WRITE_FLUSH(&adapter->hw); + synchronize_irq(adapter->pdev->irq); +} + +/** + * ixgb_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ + +static inline void ixgb_irq_enable(struct ixgb_adapter *adapter) +{ + if (atomic_dec_and_test(&adapter->irq_sem)) { + IXGB_WRITE_REG(&adapter->hw, IMS, + IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW | + IXGB_INT_RXO | IXGB_INT_LSC); + IXGB_WRITE_FLUSH(&adapter->hw); + } +} + int ixgb_up(struct ixgb_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1550,34 +1578,6 @@ adapter->net_stats.tx_window_errors = 0; } -/** - * ixgb_irq_disable - Mask off interrupt generation on the NIC - * @adapter: board private structure - **/ - -static inline void ixgb_irq_disable(struct ixgb_adapter *adapter) -{ - atomic_inc(&adapter->irq_sem); - IXGB_WRITE_REG(&adapter->hw, IMC, ~0); - IXGB_WRITE_FLUSH(&adapter->hw); - synchronize_irq(adapter->pdev->irq); -} - -/** - * ixgb_irq_enable - Enable default interrupt generation settings - * @adapter: board private structure - **/ - -static inline void ixgb_irq_enable(struct ixgb_adapter *adapter) -{ - if (atomic_dec_and_test(&adapter->irq_sem)) { - IXGB_WRITE_REG(&adapter->hw, IMS, - IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW | - IXGB_INT_RXO | IXGB_INT_LSC); - IXGB_WRITE_FLUSH(&adapter->hw); - } -} - #define IXGB_MAX_INTR 10 /** * ixgb_intr - Interrupt Handler @@ -1730,6 +1730,39 @@ } /** + * ixgb_rx_checksum - Receive Checksum Offload for 82597. + * @adapter: board private structure + * @rx_desc: receive descriptor + * @sk_buff: socket buffer with received data + **/ + +static inline void +ixgb_rx_checksum(struct ixgb_adapter *adapter, + struct ixgb_rx_desc *rx_desc, struct sk_buff *skb) +{ + /* Ignore Checksum bit is set OR + * TCP Checksum has not been calculated + */ + if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) || + (!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) { + skb->ip_summed = CHECKSUM_NONE; + return; + } + + /* At this point we know the hardware did the TCP checksum */ + /* now look at the TCP checksum error bit */ + if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) { + /* let the stack verify checksum errors */ + skb->ip_summed = CHECKSUM_NONE; + adapter->hw_csum_rx_error++; + } else { + /* TCP checksum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_rx_good++; + } +} + +/** * ixgb_clean_rx_irq - Send received data up the network stack, * @adapter: board private structure **/ @@ -1953,39 +1986,6 @@ } return 0; -} - -/** - * ixgb_rx_checksum - Receive Checksum Offload for 82597. - * @adapter: board private structure - * @rx_desc: receive descriptor - * @sk_buff: socket buffer with received data - **/ - -static inline void -ixgb_rx_checksum(struct ixgb_adapter *adapter, - struct ixgb_rx_desc *rx_desc, struct sk_buff *skb) -{ - /* Ignore Checksum bit is set OR - * TCP Checksum has not been calculated - */ - if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) || - (!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) { - skb->ip_summed = CHECKSUM_NONE; - return; - } - - /* At this point we know the hardware did the TCP checksum */ - /* now look at the TCP checksum error bit */ - if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) { - /* let the stack verify checksum errors */ - skb->ip_summed = CHECKSUM_NONE; - adapter->hw_csum_rx_error++; - } else { - /* TCP checksum is good */ - skb->ip_summed = CHECKSUM_UNNECESSARY; - adapter->hw_csum_rx_good++; - } } /** diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c --- a/drivers/net/lasi_82596.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/net/lasi_82596.c 2004-10-18 14:55:55 -07:00 @@ -1426,8 +1426,6 @@ free_irq(dev->irq, dev); remove_rx_bufs(dev); - MOD_DEC_USE_COUNT; - return 0; } diff -Nru a/drivers/net/loopback.c b/drivers/net/loopback.c --- a/drivers/net/loopback.c 2004-10-18 14:56:11 -07:00 +++ b/drivers/net/loopback.c 2004-10-18 14:56:11 -07:00 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include /* For the statistics structure. */ @@ -183,6 +184,17 @@ return stats; } +u32 loopback_get_link(struct net_device *dev) +{ + return 1; +} + +static struct ethtool_ops loopback_ethtool_ops = { + .get_link = loopback_get_link, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, +}; + struct net_device loopback_dev = { .name = "lo", .mtu = (16 * 1024) + 20 + 20 + 12, @@ -199,6 +211,7 @@ .features = NETIF_F_SG|NETIF_F_FRAGLIST |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA |NETIF_F_LLTX, + .ethtool_ops = &loopback_ethtool_ops, }; /* Setup and register the of the LOOPBACK device. */ diff -Nru a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/mv643xx_eth.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,2646 @@ +/* + * drivers/net/mv64340_eth.c - Driver for MV64340X ethernet ports + * Copyright (C) 2002 Matthew Dharm + * + * Based on the 64360 driver from: + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * Copyright (C) 2003 PMC-Sierra, Inc., + * written by Manish Lachwani (lachwani@pmc-sierra.com) + * + * Copyright (C) 2003 Ralf Baechle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "mv643xx_eth.h" + +/* + * The first part is the high level driver of the gigE ethernet ports. + */ + +/* Definition for configuring driver */ +#undef MV64340_RX_QUEUE_FILL_ON_TASK + +/* Constants */ +#define EXTRA_BYTES 32 +#define WRAP ETH_HLEN + 2 + 4 + 16 +#define BUFFER_MTU dev->mtu + WRAP +#define INT_CAUSE_UNMASK_ALL 0x0007ffff +#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff +#ifdef MV64340_RX_FILL_ON_TASK +#define INT_CAUSE_MASK_ALL 0x00000000 +#define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL +#define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT +#endif + +/* Static function declarations */ +static int mv64340_eth_real_open(struct net_device *); +static int mv64340_eth_real_stop(struct net_device *); +static int mv64340_eth_change_mtu(struct net_device *, int); +static struct net_device_stats *mv64340_eth_get_stats(struct net_device *); +static void eth_port_init_mac_tables(unsigned int eth_port_num); +#ifdef MV64340_NAPI +static int mv64340_poll(struct net_device *dev, int *budget); +#endif + +unsigned char prom_mac_addr_base[6]; +unsigned long mv64340_sram_base; + +/* + * Changes MTU (maximum transfer unit) of the gigabit ethenret port + * + * Input : pointer to ethernet interface network device structure + * new mtu size + * Output : 0 upon success, -EINVAL upon failure + */ +static int mv64340_eth_change_mtu(struct net_device *dev, int new_mtu) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&mp->lock, flags); + + if ((new_mtu > 9500) || (new_mtu < 64)) { + spin_unlock_irqrestore(&mp->lock, flags); + return -EINVAL; + } + + dev->mtu = new_mtu; + /* + * Stop then re-open the interface. This will allocate RX skb's with + * the new MTU. + * There is a possible danger that the open will not successed, due + * to memory is full, which might fail the open function. + */ + if (netif_running(dev)) { + if (mv64340_eth_real_stop(dev)) + printk(KERN_ERR + "%s: Fatal error on stopping device\n", + dev->name); + if (mv64340_eth_real_open(dev)) + printk(KERN_ERR + "%s: Fatal error on opening device\n", + dev->name); + } + + spin_unlock_irqrestore(&mp->lock, flags); + return 0; +} + +/* + * mv64340_eth_rx_task + * + * Fills / refills RX queue on a certain gigabit ethernet port + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_rx_task(void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct mv64340_private *mp = netdev_priv(dev); + struct pkt_info pkt_info; + struct sk_buff *skb; + + if (test_and_set_bit(0, &mp->rx_task_busy)) + panic("%s: Error in test_set_bit / clear_bit", dev->name); + + while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) { + /* The +8 for buffer allignment and another 32 byte extra */ + + skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES); + if (!skb) + /* Better luck next time */ + break; + mp->rx_ring_skbs++; + pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; + pkt_info.byte_cnt = dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES; + /* Allign buffer to 8 bytes */ + if (pkt_info.byte_cnt & ~0x7) { + pkt_info.byte_cnt &= ~0x7; + pkt_info.byte_cnt += 8; + } + pkt_info.buf_ptr = + pci_map_single(0, skb->data, + dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES, + PCI_DMA_FROMDEVICE); + pkt_info.return_info = skb; + if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) { + printk(KERN_ERR + "%s: Error allocating RX Ring\n", dev->name); + break; + } + skb_reserve(skb, 2); + } + clear_bit(0, &mp->rx_task_busy); + /* + * If RX ring is empty of SKB, set a timer to try allocating + * again in a later time . + */ + if ((mp->rx_ring_skbs == 0) && (mp->rx_timer_flag == 0)) { + printk(KERN_INFO "%s: Rx ring is empty\n", dev->name); + /* After 100mSec */ + mp->timeout.expires = jiffies + (HZ / 10); + add_timer(&mp->timeout); + mp->rx_timer_flag = 1; + } +#if MV64340_RX_QUEUE_FILL_ON_TASK + else { + /* Return interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(mp->port_num), + INT_CAUSE_UNMASK_ALL); + } +#endif +} + +/* + * mv64340_eth_rx_task_timer_wrapper + * + * Timer routine to wake up RX queue filling task. This function is + * used only in case the RX queue is empty, and all alloc_skb has + * failed (due to out of memory event). + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_rx_task_timer_wrapper(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct mv64340_private *mp = netdev_priv(dev); + + mp->rx_timer_flag = 0; + mv64340_eth_rx_task((void *) data); +} + + +/* + * mv64340_eth_update_mac_address + * + * Update the MAC address of the port in the address table + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_update_mac_address(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + + eth_port_init_mac_tables(port_num); + memcpy(mp->port_mac_addr, dev->dev_addr, 6); + eth_port_uc_addr_set(port_num, mp->port_mac_addr); +} + +/* + * mv64340_eth_set_rx_mode + * + * Change from promiscuos to regular rx mode + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_set_rx_mode(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + if (dev->flags & IFF_PROMISC) { + ethernet_set_config_reg + (mp->port_num, + ethernet_get_config_reg(mp->port_num) | + ETH_UNICAST_PROMISCUOUS_MODE); + } else { + ethernet_set_config_reg + (mp->port_num, + ethernet_get_config_reg(mp->port_num) & + ~(unsigned int) ETH_UNICAST_PROMISCUOUS_MODE); + } +} + + +/* + * mv64340_eth_set_mac_address + * + * Change the interface's mac address. + * No special hardware thing should be done because interface is always + * put in promiscuous mode. + * + * Input : pointer to ethernet interface network device structure and + * a pointer to the designated entry to be added to the cache. + * Output : zero upon success, negative upon failure + */ +static int mv64340_eth_set_mac_address(struct net_device *dev, void *addr) +{ + int i; + + for (i = 0; i < 6; i++) + /* +2 is for the offset of the HW addr type */ + dev->dev_addr[i] = ((unsigned char *) addr)[i + 2]; + mv64340_eth_update_mac_address(dev); + return 0; +} + +/* + * mv64340_eth_tx_timeout + * + * Called upon a timeout on transmitting a packet + * + * Input : pointer to ethernet interface network device structure. + * Output : N/A + */ +static void mv64340_eth_tx_timeout(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + printk(KERN_INFO "%s: TX timeout ", dev->name); + + /* Do the reset outside of interrupt context */ + schedule_work(&mp->tx_timeout_task); +} + +/* + * mv64340_eth_tx_timeout_task + * + * Actual routine to reset the adapter when a timeout on Tx has occurred + */ +static void mv64340_eth_tx_timeout_task(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + netif_device_detach(dev); + eth_port_reset(mp->port_num); + eth_port_start(mp); + netif_device_attach(dev); +} + +/* + * mv64340_eth_free_tx_queue + * + * Input : dev - a pointer to the required interface + * + * Output : 0 if was able to release skb , nonzero otherwise + */ +static int mv64340_eth_free_tx_queue(struct net_device *dev, + unsigned int eth_int_cause_ext) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + struct pkt_info pkt_info; + int released = 1; + + if (!(eth_int_cause_ext & (BIT0 | BIT8))) + return released; + + spin_lock(&mp->lock); + + /* Check only queue 0 */ + while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { + if (pkt_info.cmd_sts & BIT0) { + printk("%s: Error in TX\n", dev->name); + stats->tx_errors++; + } + + /* + * If return_info is different than 0, release the skb. + * The case where return_info is not 0 is only in case + * when transmitted a scatter/gather packet, where only + * last skb releases the whole chain. + */ + if (pkt_info.return_info) { + dev_kfree_skb_irq((struct sk_buff *) + pkt_info.return_info); + released = 0; + if (skb_shinfo(pkt_info.return_info)->nr_frags) + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, PCI_DMA_TODEVICE); + + if (mp->tx_ring_skbs != 1) + mp->tx_ring_skbs--; + } else + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, PCI_DMA_TODEVICE); + + /* + * Decrement the number of outstanding skbs counter on + * the TX queue. + */ + if (mp->tx_ring_skbs == 0) + panic("ERROR - TX outstanding SKBs counter is corrupted"); + + } + + spin_unlock(&mp->lock); + + return released; +} + +/* + * mv64340_eth_receive + * + * This function is forward packets that are received from the port's + * queues toward kernel core or FastRoute them to another interface. + * + * Input : dev - a pointer to the required interface + * max - maximum number to receive (0 means unlimted) + * + * Output : number of served packets + */ +#ifdef MV64340_NAPI +static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max, + int budget) +#else +static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max) +#endif +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + unsigned int received_packets = 0; + struct sk_buff *skb; + struct pkt_info pkt_info; + +#ifdef MV64340_NAPI + while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) { +#else + while ((--max) && eth_port_receive(mp, &pkt_info) == ETH_OK) { +#endif + mp->rx_ring_skbs--; + received_packets++; +#ifdef MV64340_NAPI + budget--; +#endif + /* Update statistics. Note byte count includes 4 byte CRC count */ + stats->rx_packets++; + stats->rx_bytes += pkt_info.byte_cnt; + skb = (struct sk_buff *) pkt_info.return_info; + /* + * In case received a packet without first / last bits on OR + * the error summary bit is on, the packets needs to be dropeed. + */ + if (((pkt_info.cmd_sts + & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) + || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) { + stats->rx_dropped++; + if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC | + ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) { + if (net_ratelimit()) + printk(KERN_ERR + "%s: Received packet spread on multiple" + " descriptors\n", + dev->name); + } + if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY) + stats->rx_errors++; + + dev_kfree_skb_irq(skb); + } else { + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, pkt_info.byte_cnt - 4); + skb->dev = dev; + + if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->csum = htons((pkt_info.cmd_sts + & 0x0007fff8) >> 3); + } + skb->protocol = eth_type_trans(skb, dev); +#ifdef MV64340_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } + } + + return received_packets; +} + +/* + * mv64340_eth_int_handler + * + * Main interrupt handler for the gigbit ethernet ports + * + * Input : irq - irq number (not used) + * dev_id - a pointer to the required interface's data structure + * regs - not used + * Output : N/A + */ + +static irqreturn_t mv64340_eth_int_handler(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct mv64340_private *mp = netdev_priv(dev); + u32 eth_int_cause, eth_int_cause_ext = 0; + unsigned int port_num = mp->port_num; + + /* Read interrupt cause registers */ + eth_int_cause = MV_READ(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num)) & + INT_CAUSE_UNMASK_ALL; + + if (eth_int_cause & BIT1) + eth_int_cause_ext = + MV_READ(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & + INT_CAUSE_UNMASK_ALL_EXT; + +#ifdef MV64340_NAPI + if (!(eth_int_cause & 0x0007fffd)) { + /* Dont ack the Rx interrupt */ +#endif + /* + * Clear specific ethernet port intrerrupt registers by + * acknowleding relevant bits. + */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), + ~eth_int_cause); + if (eth_int_cause_ext != 0x0) + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), + ~eth_int_cause_ext); + + /* UDP change : We may need this */ + if ((eth_int_cause_ext & 0x0000ffff) && + (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && + (MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1)) + netif_wake_queue(dev); +#ifdef MV64340_NAPI + } else { + if (netif_rx_schedule_prep(dev)) { + /* Mask all the interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + __netif_rx_schedule(dev); + } +#else + { + if (eth_int_cause & (BIT2 | BIT11)) + mv64340_eth_receive_queue(dev, 0); + + /* + * After forwarded received packets to upper layer, add a task + * in an interrupts enabled context that refills the RX ring + * with skb's. + */ +#if MV64340_RX_QUEUE_FILL_ON_TASK + /* Unmask all interrupts on ethernet port */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_MASK_ALL); + queue_task(&mp->rx_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + mp->rx_task.func(dev); +#endif +#endif + } + /* PHY status changed */ + if (eth_int_cause_ext & (BIT16 | BIT20)) { + unsigned int phy_reg_data; + + /* Check Link status on ethernet port */ + eth_port_read_smi_reg(port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) { + netif_stop_queue(dev); + } else { + netif_wake_queue(dev); + + /* + * Start all TX queues on ethernet port. This is good in + * case of previous packets where not transmitted, due + * to link down and this command re-enables all TX + * queues. + * Note that it is possible to get a TX resource error + * interrupt after issuing this, since not all TX queues + * are enabled, or has anything to send. + */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1); + } + } + + /* + * If no real interrupt occured, exit. + * This can happen when using gigE interrupt coalescing mechanism. + */ + if ((eth_int_cause == 0x0) && (eth_int_cause_ext == 0x0)) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +#ifdef MV64340_COAL + +/* + * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path + * + * DESCRIPTION: + * This routine sets the RX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the tClk of the MV-643xx chip + * , and the required delay of the interrupt in usec. + * + * INPUT: + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in usec + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + */ +static unsigned int eth_port_set_rx_coal(unsigned int eth_port_num, + unsigned int t_clk, unsigned int delay) +{ + unsigned int coal = ((t_clk / 1000000) * delay) / 64; + + /* Set RX Coalescing mechanism */ + MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), + ((coal & 0x3fff) << 8) | + (MV_READ(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num)) + & 0xffc000ff)); + + return coal; +} +#endif + +/* + * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path + * + * DESCRIPTION: + * This routine sets the TX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the t_cLK frequency of the + * MV-643xx chip and the required delay in the interrupt in uSec + * + * INPUT: + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in uSeconds + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + */ +static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num, + unsigned int t_clk, unsigned int delay) +{ + unsigned int coal; + coal = ((t_clk / 1000000) * delay) / 64; + /* Set TX Coalescing mechanism */ + MV_WRITE(MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num), + coal << 4); + return coal; +} + +/* + * mv64340_eth_open + * + * This function is called when openning the network device. The function + * should initialize all the hardware, initialize cyclic Rx/Tx + * descriptors chain and buffers and allocate an IRQ to the network + * device. + * + * Input : a pointer to the network device structure + * + * Output : zero of success , nonzero if fails. + */ + +static int mv64340_eth_open(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + int err = err; + + spin_lock_irq(&mp->lock); + + err = request_irq(dev->irq, mv64340_eth_int_handler, + SA_INTERRUPT | SA_SAMPLE_RANDOM, dev->name, dev); + + if (err) { + printk(KERN_ERR "Can not assign IRQ number to MV64340_eth%d\n", + port_num); + err = -EAGAIN; + goto out; + } + + if (mv64340_eth_real_open(dev)) { + printk("%s: Error opening interface\n", dev->name); + err = -EBUSY; + goto out_free; + } + + spin_unlock_irq(&mp->lock); + + return 0; + +out_free: + free_irq(dev->irq, dev); + +out: + spin_unlock_irq(&mp->lock); + + return err; +} + +/* + * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Rx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * int rx_desc_num Number of Rx descriptors + * int rx_buff_size Size of Rx buffer + * unsigned int rx_desc_base_addr Rx descriptors memory area base addr. + * unsigned int rx_buff_base_addr Rx buffer memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Rx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + */ +static int ether_init_rx_desc_ring(struct mv64340_private * mp, + unsigned long rx_buff_base_addr) +{ + unsigned long buffer_addr = rx_buff_base_addr; + volatile struct eth_rx_desc *p_rx_desc; + int rx_desc_num = mp->rx_ring_size; + unsigned long rx_desc_base_addr = (unsigned long) mp->p_rx_desc_area; + int rx_buff_size = 1536; /* Dummy, will be replaced later */ + int i; + + p_rx_desc = (struct eth_rx_desc *) rx_desc_base_addr; + + /* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (rx_buff_base_addr & 0xf) + return 0; + + /* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes */ + if ((rx_buff_size < 8) || (rx_buff_size > RX_BUFFER_MAX_SIZE)) + return 0; + + /* Rx buffers must be 64-bit aligned. */ + if ((rx_buff_base_addr + rx_buff_size) & 0x7) + return 0; + + /* initialize the Rx descriptors ring */ + for (i = 0; i < rx_desc_num; i++) { + p_rx_desc[i].buf_size = rx_buff_size; + p_rx_desc[i].byte_cnt = 0x0000; + p_rx_desc[i].cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + p_rx_desc[i].next_desc_ptr = mp->rx_desc_dma + + ((i + 1) % rx_desc_num) * sizeof(struct eth_rx_desc); + p_rx_desc[i].buf_ptr = buffer_addr; + + mp->rx_skb[i] = NULL; + buffer_addr += rx_buff_size; + } + + /* Save Rx desc pointer to driver struct. */ + mp->rx_curr_desc_q = 0; + mp->rx_used_desc_q = 0; + + mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc); + + mp->port_rx_queue_command |= 1; + + return 1; +} + +/* + * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Tx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * int tx_desc_num Number of Tx descriptors + * int tx_buff_size Size of Tx buffer + * unsigned int tx_desc_base_addr Tx descriptors memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Tx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + */ +static int ether_init_tx_desc_ring(struct mv64340_private *mp) +{ + unsigned long tx_desc_base_addr = (unsigned long) mp->p_tx_desc_area; + int tx_desc_num = mp->tx_ring_size; + struct eth_tx_desc *p_tx_desc; + int i; + + /* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (tx_desc_base_addr & 0xf) + return 0; + + /* save the first desc pointer to link with the last descriptor */ + p_tx_desc = (struct eth_tx_desc *) tx_desc_base_addr; + + /* Initialize the Tx descriptors ring */ + for (i = 0; i < tx_desc_num; i++) { + p_tx_desc[i].byte_cnt = 0x0000; + p_tx_desc[i].l4i_chk = 0x0000; + p_tx_desc[i].cmd_sts = 0x00000000; + p_tx_desc[i].next_desc_ptr = mp->tx_desc_dma + + ((i + 1) % tx_desc_num) * sizeof(struct eth_tx_desc); + p_tx_desc[i].buf_ptr = 0x00000000; + mp->tx_skb[i] = NULL; + } + + /* Set Tx desc pointer in driver struct. */ + mp->tx_curr_desc_q = 0; + mp->tx_used_desc_q = 0; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + mp->tx_first_desc_q = 0; +#endif + /* Init Tx ring base and size parameters */ + mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); + + /* Add the queue to the list of Tx queues of this port */ + mp->port_tx_queue_command |= 1; + + return 1; +} + +/* Helper function for mv64340_eth_open */ +static int mv64340_eth_real_open(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + u32 phy_reg_data; + unsigned int size; + + /* Stop RX Queues */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Clear the ethernet port interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + + /* Unmask RX buffer and TX end interrupt */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); + + /* Unmask phy and link status changes interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + + /* Set the MAC Address */ + memcpy(mp->port_mac_addr, dev->dev_addr, 6); + + eth_port_init(mp); + + INIT_WORK(&mp->rx_task, (void (*)(void *)) mv64340_eth_rx_task, dev); + + memset(&mp->timeout, 0, sizeof(struct timer_list)); + mp->timeout.function = mv64340_eth_rx_task_timer_wrapper; + mp->timeout.data = (unsigned long) dev; + + mp->rx_task_busy = 0; + mp->rx_timer_flag = 0; + + /* Allocate TX ring */ + mp->tx_ring_skbs = 0; + mp->tx_ring_size = MV64340_TX_QUEUE_SIZE; + size = mp->tx_ring_size * sizeof(struct eth_tx_desc); + mp->tx_desc_area_size = size; + + /* Assumes allocated ring is 16 bytes alligned */ + mp->p_tx_desc_area = pci_alloc_consistent(NULL, size, &mp->tx_desc_dma); + if (!mp->p_tx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", + dev->name, size); + return -ENOMEM; + } + memset((void *) mp->p_tx_desc_area, 0, mp->tx_desc_area_size); + + /* Dummy will be replaced upon real tx */ + ether_init_tx_desc_ring(mp); + + /* Allocate RX ring */ + /* Meantime RX Ring are fixed - but must be configurable by user */ + mp->rx_ring_size = MV64340_RX_QUEUE_SIZE; + mp->rx_ring_skbs = 0; + size = mp->rx_ring_size * sizeof(struct eth_rx_desc); + mp->rx_desc_area_size = size; + + /* Assumes allocated ring is 16 bytes aligned */ + + mp->p_rx_desc_area = pci_alloc_consistent(NULL, size, &mp->rx_desc_dma); + + if (!mp->p_rx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Rx ring (size %d bytes)\n", + dev->name, size); + printk(KERN_ERR "%s: Freeing previously allocated TX queues...", + dev->name); + pci_free_consistent(0, mp->tx_desc_area_size, + (void *) mp->p_tx_desc_area, + mp->tx_desc_dma); + return -ENOMEM; + } + memset(mp->p_rx_desc_area, 0, size); + + if (!(ether_init_rx_desc_ring(mp, 0))) + panic("%s: Error initializing RX Ring", dev->name); + + mv64340_eth_rx_task(dev); /* Fill RX ring with skb's */ + + eth_port_start(mp); + + /* Interrupt Coalescing */ + +#ifdef MV64340_COAL + mp->rx_int_coal = + eth_port_set_rx_coal(port_num, 133000000, MV64340_RX_COAL); +#endif + + mp->tx_int_coal = + eth_port_set_tx_coal (port_num, 133000000, MV64340_TX_COAL); + + /* Increase the Rx side buffer size */ + + MV_WRITE (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num), (0x5 << 17) | + (MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num)) + & 0xfff1ffff)); + + /* Check Link status on phy */ + eth_port_read_smi_reg(port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) + netif_stop_queue(dev); + else + netif_start_queue(dev); + + return 0; +} + +static void mv64340_eth_free_tx_rings(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + unsigned int curr; + + /* Stop Tx Queues */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Free TX rings */ + /* Free outstanding skb's on TX rings */ + for (curr = 0; + (mp->tx_ring_skbs) && (curr < MV64340_TX_QUEUE_SIZE); + curr++) { + if (mp->tx_skb[curr]) { + dev_kfree_skb(mp->tx_skb[curr]); + mp->tx_ring_skbs--; + } + } + if (mp->tx_ring_skbs != 0) + printk("%s: Error on Tx descriptor free - could not free %d" + " descriptors\n", dev->name, + mp->tx_ring_skbs); + pci_free_consistent(0, mp->tx_desc_area_size, + (void *) mp->p_tx_desc_area, mp->tx_desc_dma); +} + +static void mv64340_eth_free_rx_rings(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + int curr; + + /* Stop RX Queues */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Free RX rings */ + /* Free preallocated skb's on RX rings */ + for (curr = 0; + mp->rx_ring_skbs && (curr < MV64340_RX_QUEUE_SIZE); + curr++) { + if (mp->rx_skb[curr]) { + dev_kfree_skb(mp->rx_skb[curr]); + mp->rx_ring_skbs--; + } + } + + if (mp->rx_ring_skbs != 0) + printk(KERN_ERR + "%s: Error in freeing Rx Ring. %d skb's still" + " stuck in RX Ring - ignoring them\n", dev->name, + mp->rx_ring_skbs); + pci_free_consistent(0, mp->rx_desc_area_size, + (void *) mp->p_rx_desc_area, + mp->rx_desc_dma); +} + +/* + * mv64340_eth_stop + * + * This function is used when closing the network device. + * It updates the hardware, + * release all memory that holds buffers and descriptors and release the IRQ. + * Input : a pointer to the device structure + * Output : zero if success , nonzero if fails + */ + +/* Helper function for mv64340_eth_stop */ + +static int mv64340_eth_real_stop(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + + netif_stop_queue(dev); + + mv64340_eth_free_tx_rings(dev); + mv64340_eth_free_rx_rings(dev); + + eth_port_reset(mp->port_num); + + /* Disable ethernet port interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + + /* Mask RX buffer and TX end interrupt */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 0); + + /* Mask phy and link status changes interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + + return 0; +} + +static int mv64340_eth_stop(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + spin_lock_irq(&mp->lock); + + mv64340_eth_real_stop(dev); + + free_irq(dev->irq, dev); + spin_unlock_irq(&mp->lock); + + return 0; +} + +#ifdef MV64340_NAPI +static void mv64340_tx(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct pkt_info pkt_info; + + while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { + if (pkt_info.return_info) { + dev_kfree_skb_irq((struct sk_buff *) + pkt_info.return_info); + if (skb_shinfo(pkt_info.return_info)->nr_frags) + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + PCI_DMA_TODEVICE); + + if (mp->tx_ring_skbs != 1) + mp->tx_ring_skbs--; + } else + pci_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt, + PCI_DMA_TODEVICE); + } + + if (netif_queue_stopped(dev) && + MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1) + netif_wake_queue(dev); +} + +/* + * mv64340_poll + * + * This function is used in case of NAPI + */ +static int mv64340_poll(struct net_device *dev, int *budget) +{ + struct mv64340_private *mp = netdev_priv(dev); + int done = 1, orig_budget, work_done; + unsigned int port_num = mp->port_num; + unsigned long flags; + +#ifdef MV64340_TX_FAST_REFILL + if (++mp->tx_clean_threshold > 5) { + spin_lock_irqsave(&mp->lock, flags); + mv64340_tx(dev); + mp->tx_clean_threshold = 0; + spin_unlock_irqrestore(&mp->lock, flags); + } +#endif + + if ((u32)(MV_READ(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) != (u32)mp->rx_used_desc_q) { + orig_budget = *budget; + if (orig_budget > dev->quota) + orig_budget = dev->quota; + work_done = mv64340_eth_receive_queue(dev, 0, orig_budget); + mp->rx_task.func(dev); + *budget -= work_done; + dev->quota -= work_done; + if (work_done >= orig_budget) + done = 0; + } + + if (done) { + spin_lock_irqsave(&mp->lock, flags); + __netif_rx_complete(dev); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + spin_unlock_irqrestore(&mp->lock, flags); + } + + return done ? 0 : 1; +} +#endif + +/* + * mv64340_eth_start_xmit + * + * This function is queues a packet in the Tx descriptor for + * required port. + * + * Input : skb - a pointer to socket buffer + * dev - a pointer to the required port + * + * Output : zero upon success + */ +static int mv64340_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + ETH_FUNC_RET_STATUS status; + unsigned long flags; + struct pkt_info pkt_info; + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR + "%s: Tried sending packet when interface is stopped\n", + dev->name); + return 1; + } + + /* This is a hard error, log it. */ + if ((MV64340_TX_QUEUE_SIZE - mp->tx_ring_skbs) <= + (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + printk(KERN_ERR + "%s: Bug in mv64340_eth - Trying to transmit when" + " queue full !\n", dev->name); + return 1; + } + + /* Paranoid check - this shouldn't happen */ + if (skb == NULL) { + stats->tx_dropped++; + return 1; + } + + spin_lock_irqsave(&mp->lock, flags); + + /* Update packet info data structure -- DMA owned, first last */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + if (!skb_shinfo(skb)->nr_frags || (skb_shinfo(skb)->nr_frags > 3)) { +#endif + pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | + ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; + + pkt_info.byte_cnt = skb->len; + pkt_info.buf_ptr = pci_map_single(0, skb->data, skb->len, + PCI_DMA_TODEVICE); + + + pkt_info.return_info = skb; + status = eth_port_send(mp, &pkt_info); + if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) + printk(KERN_ERR "%s: Error on transmitting packet\n", + dev->name); + mp->tx_ring_skbs++; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + } else { + unsigned int frag; + u32 ipheader; + + /* first frag which is skb header */ + pkt_info.byte_cnt = skb_headlen(skb); + pkt_info.buf_ptr = pci_map_single(0, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + pkt_info.return_info = 0; + ipheader = skb->nh.iph->ihl << 11; + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + ipheader; + /* CPU already calculated pseudo header checksum. So, use it */ + pkt_info.l4i_chk = skb->h.th->check; + status = eth_port_send(mp, &pkt_info); + if (status != ETH_OK) { + if ((status == ETH_ERROR)) + printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); + if (status == ETH_QUEUE_FULL) + printk("Error on Queue Full \n"); + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); + } + + /* Check for the remaining frags */ + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; + pkt_info.l4i_chk = 0x0000; + pkt_info.cmd_sts = 0x00000000; + + /* Last Frag enables interrupt and frees the skb */ + if (frag == (skb_shinfo(skb)->nr_frags - 1)) { + pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT | + ETH_TX_LAST_DESC; + pkt_info.return_info = skb; + mp->tx_ring_skbs++; + } + else { + pkt_info.return_info = 0; + } + pkt_info.byte_cnt = this_frag->size; + if (this_frag->size < 8) + printk("%d : \n", skb_shinfo(skb)->nr_frags); + + pkt_info.buf_ptr = pci_map_page(NULL, this_frag->page, + this_frag->page_offset, + this_frag->size, PCI_DMA_TODEVICE); + + status = eth_port_send(mp, &pkt_info); + + if (status != ETH_OK) { + if ((status == ETH_ERROR)) + printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); + + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); + + if (status == ETH_QUEUE_FULL) + printk("Queue is full \n"); + } + } + } +#endif + + /* Check if TX queue can handle another skb. If not, then + * signal higher layers to stop requesting TX + */ + if (MV64340_TX_QUEUE_SIZE <= (mp->tx_ring_skbs + 1)) + /* + * Stop getting skb's from upper layers. + * Getting skb's from upper layers will be enabled again after + * packets are released. + */ + netif_stop_queue(dev); + + /* Update statistics and start of transmittion time */ + stats->tx_bytes += skb->len; + stats->tx_packets++; + dev->trans_start = jiffies; + + spin_unlock_irqrestore(&mp->lock, flags); + + return 0; /* success */ +} + +/* + * mv64340_eth_get_stats + * + * Returns a pointer to the interface statistics. + * + * Input : dev - a pointer to the required interface + * + * Output : a pointer to the interface's statistics + */ + +static struct net_device_stats *mv64340_eth_get_stats(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + return &mp->stats; +} + +/*/ + * mv64340_eth_init + * + * First function called after registering the network device. + * It's purpose is to initialize the device as an ethernet device, + * fill the structure that was given in registration with pointers + * to functions, and setting the MAC address of the interface + * + * Input : number of port to initialize + * Output : -ENONMEM if failed , 0 if success + */ +static struct net_device *mv64340_eth_init(int port_num) +{ + struct mv64340_private *mp; + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct mv64340_private)); + if (!dev) + return NULL; + + mp = netdev_priv(dev); + + dev->irq = ETH_PORT0_IRQ_NUM + port_num; + + dev->open = mv64340_eth_open; + dev->stop = mv64340_eth_stop; + dev->hard_start_xmit = mv64340_eth_start_xmit; + dev->get_stats = mv64340_eth_get_stats; + dev->set_mac_address = mv64340_eth_set_mac_address; + dev->set_multicast_list = mv64340_eth_set_rx_mode; + + /* No need to Tx Timeout */ + dev->tx_timeout = mv64340_eth_tx_timeout; +#ifdef MV64340_NAPI + dev->poll = mv64340_poll; + dev->weight = 64; +#endif + + dev->watchdog_timeo = 2 * HZ; + dev->tx_queue_len = MV64340_TX_QUEUE_SIZE; + dev->base_addr = 0; + dev->change_mtu = mv64340_eth_change_mtu; + +#ifdef MV64340_CHECKSUM_OFFLOAD_TX +#ifdef MAX_SKB_FRAGS +#ifndef CONFIG_JAGUAR_DMALOW + /* + * Zero copy can only work if we use Discovery II memory. Else, we will + * have to map the buffers to ISA memory which is only 16 MB + */ + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM; +#endif +#endif +#endif + + mp->port_num = port_num; + + /* Configure the timeout task */ + INIT_WORK(&mp->tx_timeout_task, + (void (*)(void *))mv64340_eth_tx_timeout_task, dev); + + spin_lock_init(&mp->lock); + + /* set MAC addresses */ + memcpy(dev->dev_addr, prom_mac_addr_base, 6); + dev->dev_addr[5] += port_num; + + err = register_netdev(dev); + if (err) + goto out_free_dev; + + printk(KERN_NOTICE "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, port_num, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + if (dev->features & NETIF_F_SG) + printk("Scatter Gather Enabled "); + + if (dev->features & NETIF_F_IP_CSUM) + printk("TX TCP/IP Checksumming Supported \n"); + + printk("RX TCP/UDP Checksum Offload ON, \n"); + printk("TX and RX Interrupt Coalescing ON \n"); + +#ifdef MV64340_NAPI + printk("RX NAPI Enabled \n"); +#endif + + return dev; + +out_free_dev: + free_netdev(dev); + + return NULL; +} + +static void mv64340_eth_remove(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + unregister_netdev(dev); + flush_scheduled_work(); + free_netdev(dev); +} + +static struct net_device *mv64340_dev0; +static struct net_device *mv64340_dev1; +static struct net_device *mv64340_dev2; + +/* + * mv64340_init_module + * + * Registers the network drivers into the Linux kernel + * + * Input : N/A + * + * Output : N/A + */ +static int __init mv64340_init_module(void) +{ + printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); + +#ifdef CONFIG_MV643XX_ETH_0 + mv64340_dev0 = mv64340_eth_init(0); + if (!mv64340_dev0) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 0\n"); + } +#endif +#ifdef CONFIG_MV643XX_ETH_1 + mv64340_dev1 = mv64340_eth_init(1); + if (!mv64340_dev1) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 1\n"); + } +#endif +#ifdef CONFIG_MV643XX_ETH_2 + mv64340_dev2 = mv64340_eth_init(2); + if (!mv64340_dev2) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 2\n"); + } +#endif + return 0; +} + +/* + * mv64340_cleanup_module + * + * Registers the network drivers into the Linux kernel + * + * Input : N/A + * + * Output : N/A + */ +static void __exit mv64340_cleanup_module(void) +{ + if (mv64340_dev2) + mv64340_eth_remove(mv64340_dev2); + if (mv64340_dev1) + mv64340_eth_remove(mv64340_dev1); + if (mv64340_dev0) + mv64340_eth_remove(mv64340_dev0); +} + +module_init(mv64340_init_module); +module_exit(mv64340_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm and Manish Lachwani"); +MODULE_DESCRIPTION("Ethernet driver for Marvell MV64340"); + +/* + * The second part is the low level driver of the gigE ethernet ports. + */ + +/* + * Marvell's Gigabit Ethernet controller low level driver + * + * DESCRIPTION: + * This file introduce low level API to Marvell's Gigabit Ethernet + * controller. This Gigabit Ethernet Controller driver API controls + * 1) Operations (i.e. port init, start, reset etc'). + * 2) Data flow (i.e. port send, receive etc'). + * Each Gigabit Ethernet port is controlled via + * struct mv64340_private. + * This struct includes user configuration information as well as + * driver internal data needed for its operations. + * + * Supported Features: + * - This low level driver is OS independent. Allocating memory for + * the descriptor rings and buffers are not within the scope of + * this driver. + * - The user is free from Rx/Tx queue managing. + * - This low level driver introduce functionality API that enable + * the to operate Marvell's Gigabit Ethernet Controller in a + * convenient way. + * - Simple Gigabit Ethernet port operation API. + * - Simple Gigabit Ethernet port data flow API. + * - Data flow and operation API support per queue functionality. + * - Support cached descriptors for better performance. + * - Enable access to all four DRAM banks and internal SRAM memory + * spaces. + * - PHY access and control API. + * - Port control register configuration API. + * - Full control over Unicast and Multicast MAC configurations. + * + * Operation flow: + * + * Initialization phase + * This phase complete the initialization of the the mv64340_private + * struct. + * User information regarding port configuration has to be set + * prior to calling the port initialization routine. + * + * In this phase any port Tx/Rx activity is halted, MIB counters + * are cleared, PHY address is set according to user parameter and + * access to DRAM and internal SRAM memory spaces. + * + * Driver ring initialization + * Allocating memory for the descriptor rings and buffers is not + * within the scope of this driver. Thus, the user is required to + * allocate memory for the descriptors ring and buffers. Those + * memory parameters are used by the Rx and Tx ring initialization + * routines in order to curve the descriptor linked list in a form + * of a ring. + * Note: Pay special attention to alignment issues when using + * cached descriptors/buffers. In this phase the driver store + * information in the mv64340_private struct regarding each queue + * ring. + * + * Driver start + * This phase prepares the Ethernet port for Rx and Tx activity. + * It uses the information stored in the mv64340_private struct to + * initialize the various port registers. + * + * Data flow: + * All packet references to/from the driver are done using + * struct pkt_info. + * This struct is a unified struct used with Rx and Tx operations. + * This way the user is not required to be familiar with neither + * Tx nor Rx descriptors structures. + * The driver's descriptors rings are management by indexes. + * Those indexes controls the ring resources and used to indicate + * a SW resource error: + * 'current' + * This index points to the current available resource for use. For + * example in Rx process this index will point to the descriptor + * that will be passed to the user upon calling the receive routine. + * In Tx process, this index will point to the descriptor + * that will be assigned with the user packet info and transmitted. + * 'used' + * This index points to the descriptor that need to restore its + * resources. For example in Rx process, using the Rx buffer return + * API will attach the buffer returned in packet info to the + * descriptor pointed by 'used'. In Tx process, using the Tx + * descriptor return will merely return the user packet info with + * the command status of the transmitted buffer pointed by the + * 'used' index. Nevertheless, it is essential to use this routine + * to update the 'used' index. + * 'first' + * This index supports Tx Scatter-Gather. It points to the first + * descriptor of a packet assembled of multiple buffers. For example + * when in middle of Such packet we have a Tx resource error the + * 'curr' index get the value of 'first' to indicate that the ring + * returned to its state before trying to transmit this packet. + * + * Receive operation: + * The eth_port_receive API set the packet information struct, + * passed by the caller, with received information from the + * 'current' SDMA descriptor. + * It is the user responsibility to return this resource back + * to the Rx descriptor ring to enable the reuse of this source. + * Return Rx resource is done using the eth_rx_return_buff API. + * + * Transmit operation: + * The eth_port_send API supports Scatter-Gather which enables to + * send a packet spanned over multiple buffers. This means that + * for each packet info structure given by the user and put into + * the Tx descriptors ring, will be transmitted only if the 'LAST' + * bit will be set in the packet info command status field. This + * API also consider restriction regarding buffer alignments and + * sizes. + * The user must return a Tx resource after ensuring the buffer + * has been transmitted to enable the Tx ring indexes to update. + * + * BOARD LAYOUT + * This device is on-board. No jumper diagram is necessary. + * + * EXTERNAL INTERFACE + * + * Prior to calling the initialization routine eth_port_init() the user + * must set the following fields under mv64340_private struct: + * port_num User Ethernet port number. + * port_mac_addr[6] User defined port MAC address. + * port_config User port configuration value. + * port_config_extend User port config extend value. + * port_sdma_config User port SDMA config value. + * port_serial_control User port serial control value. + * + * This driver introduce a set of default values: + * PORT_CONFIG_VALUE Default port configuration value + * PORT_CONFIG_EXTEND_VALUE Default port extend configuration value + * PORT_SDMA_CONFIG_VALUE Default sdma control value + * PORT_SERIAL_CONTROL_VALUE Default port serial control value + * + * This driver data flow is done using the struct pkt_info which + * is a unified struct for Rx and Tx operations: + * + * byte_cnt Tx/Rx descriptor buffer byte count. + * l4i_chk CPU provided TCP Checksum. For Tx operation + * only. + * cmd_sts Tx/Rx descriptor command status. + * buf_ptr Tx/Rx descriptor buffer pointer. + * return_info Tx/Rx user resource return information. + */ + +/* defines */ +/* SDMA command macros */ +#define ETH_ENABLE_TX_QUEUE(eth_port) \ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1) + +#define ETH_DISABLE_TX_QUEUE(eth_port) \ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), \ + (1 << 8)) + +#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ + (1 << rx_queue)) + +#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ + (1 << (8 + rx_queue))) + +#define LINK_UP_TIMEOUT 100000 +#define PHY_BUSY_TIMEOUT 10000000 + +/* locals */ + +/* PHY routines */ +static int ethernet_phy_get(unsigned int eth_port_num); + +/* Ethernet Port routines */ +static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, + int option); + +/* + * eth_port_init - Initialize the Ethernet port driver + * + * DESCRIPTION: + * This function prepares the ethernet port to start its activity: + * 1) Completes the ethernet port driver struct initialization toward port + * start routine. + * 2) Resets the device to a quiescent state in case of warm reboot. + * 3) Enable SDMA access to all four DRAM banks as well as internal SRAM. + * 4) Clean MAC tables. The reset status of those tables is unknown. + * 5) Set PHY address. + * Note: Call this routine prior to eth_port_start routine and after + * setting user values in the user fields of Ethernet port control + * struct. + * + * INPUT: + * struct mv64340_private *mp Ethernet port control struct + * + * OUTPUT: + * See description. + * + * RETURN: + * None. + */ +static void eth_port_init(struct mv64340_private * mp) +{ + mp->port_config = PORT_CONFIG_VALUE; + mp->port_config_extend = PORT_CONFIG_EXTEND_VALUE; +#if defined(__BIG_ENDIAN) + mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE; +#elif defined(__LITTLE_ENDIAN) + mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE | + ETH_BLM_RX_NO_SWAP | ETH_BLM_TX_NO_SWAP; +#else +#error One of __LITTLE_ENDIAN or __BIG_ENDIAN must be defined! +#endif + mp->port_serial_control = PORT_SERIAL_CONTROL_VALUE; + + mp->port_rx_queue_command = 0; + mp->port_tx_queue_command = 0; + + mp->rx_resource_err = 0; + mp->tx_resource_err = 0; + + eth_port_reset(mp->port_num); + + eth_port_init_mac_tables(mp->port_num); + + ethernet_phy_reset(mp->port_num); +} + +/* + * eth_port_start - Start the Ethernet port activity. + * + * DESCRIPTION: + * This routine prepares the Ethernet port for Rx and Tx activity: + * 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that + * has been initialized a descriptor's ring (using + * ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx) + * 2. Initialize and enable the Ethernet configuration port by writing to + * the port's configuration and command registers. + * 3. Initialize and enable the SDMA by writing to the SDMA's + * configuration and command registers. After completing these steps, + * the ethernet port SDMA can starts to perform Rx and Tx activities. + * + * Note: Each Rx and Tx queue descriptor's list must be initialized prior + * to calling this function (use ether_init_tx_desc_ring for Tx queues + * and ether_init_rx_desc_ring for Rx queues). + * + * INPUT: + * struct mv64340_private *mp Ethernet port control struct + * + * OUTPUT: + * Ethernet port is ready to receive and transmit. + * + * RETURN: + * false if the port PHY is not up. + * true otherwise. + */ +static int eth_port_start(struct mv64340_private *mp) +{ + unsigned int eth_port_num = mp->port_num; + int tx_curr_desc, rx_curr_desc; + unsigned int phy_reg_data; + + /* Assignment of Tx CTRP of given queue */ + tx_curr_desc = mp->tx_curr_desc_q; + MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), + (struct eth_tx_desc *) mp->tx_desc_dma + tx_curr_desc); + + /* Assignment of Rx CRDP of given queue */ + rx_curr_desc = mp->rx_curr_desc_q; + MV_WRITE(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), + (struct eth_rx_desc *) mp->rx_desc_dma + rx_curr_desc); + + /* Add the assigned Ethernet address to the port's address table */ + eth_port_uc_addr_set(mp->port_num, mp->port_mac_addr); + + /* Assign port configuration and command. */ + MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), + mp->port_config); + + MV_WRITE(MV64340_ETH_PORT_CONFIG_EXTEND_REG(eth_port_num), + mp->port_config_extend); + + MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), + mp->port_serial_control); + + MV_SET_REG_BITS(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), + ETH_SERIAL_PORT_ENABLE); + + /* Assign port SDMA configuration */ + MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), + mp->port_sdma_config); + + /* Enable port Rx. */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port_num), + mp->port_rx_queue_command); + + /* Check if link is up */ + eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); + + if (!(phy_reg_data & 0x20)) + return 0; + + return 1; +} + +/* + * eth_port_uc_addr_set - This function Set the port Unicast address. + * + * DESCRIPTION: + * This function Set the port Ethernet MAC address. + * + * INPUT: + * unsigned int eth_port_num Port number. + * char * p_addr Address to be set + * + * OUTPUT: + * Set MAC address low and high registers. also calls eth_port_uc_addr() + * To set the unicast table with the proper information. + * + * RETURN: + * N/A. + * + */ +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr) +{ + unsigned int mac_h; + unsigned int mac_l; + + mac_l = (p_addr[4] << 8) | (p_addr[5]); + mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | + (p_addr[2] << 8) | (p_addr[3] << 0); + + MV_WRITE(MV64340_ETH_MAC_ADDR_LOW(eth_port_num), mac_l); + MV_WRITE(MV64340_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); + + /* Accept frames of this address */ + eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR); + + return; +} + +/* + * eth_port_uc_addr - This function Set the port unicast address table + * + * DESCRIPTION: + * This function locates the proper entry in the Unicast table for the + * specified MAC nibble and sets its properties according to function + * parameters. + * + * INPUT: + * unsigned int eth_port_num Port number. + * unsigned char uc_nibble Unicast MAC Address last nibble. + * int option 0 = Add, 1 = remove address. + * + * OUTPUT: + * This function add/removes MAC addresses from the port unicast address + * table. + * + * RETURN: + * true is output succeeded. + * false if option parameter is invalid. + * + */ +static int eth_port_uc_addr(unsigned int eth_port_num, + unsigned char uc_nibble, int option) +{ + unsigned int unicast_reg; + unsigned int tbl_offset; + unsigned int reg_offset; + + /* Locate the Unicast table entry */ + uc_nibble = (0xf & uc_nibble); + tbl_offset = (uc_nibble / 4) * 4; /* Register offset from unicast table base */ + reg_offset = uc_nibble % 4; /* Entry offset within the above register */ + + switch (option) { + case REJECT_MAC_ADDR: + /* Clear accepts frame bit at specified unicast DA table entry */ + unicast_reg = MV_READ((MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); + + unicast_reg &= (0x0E << (8 * reg_offset)); + + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); + break; + + case ACCEPT_MAC_ADDR: + /* Set accepts frame bit at unicast DA filter table entry */ + unicast_reg = + MV_READ( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); + + unicast_reg |= (0x01 << (8 * reg_offset)); + + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); + + break; + + default: + return 0; + } + + return 1; +} + +/* + * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables + * + * DESCRIPTION: + * Go through all the DA filter tables (Unicast, Special Multicast & + * Other Multicast) and set each entry to 0. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * Multicast and Unicast packets are rejected. + * + * RETURN: + * None. + */ +static void eth_port_init_mac_tables(unsigned int eth_port_num) +{ + int table_index; + + /* Clear DA filter unicast table (Ex_dFUT) */ + for (table_index = 0; table_index <= 0xC; table_index += 4) + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + + for (table_index = 0; table_index <= 0xFC; table_index += 4) { + /* Clear DA filter special multicast table (Ex_dFSMT) */ + MV_WRITE( + (MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + /* Clear DA filter other multicast table (Ex_dFOMT) */ + MV_WRITE((MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + } +} + +/* + * eth_clear_mib_counters - Clear all MIB counters + * + * DESCRIPTION: + * This function clears all MIB counters of a specific ethernet port. + * A read from the MIB counter will reset the counter. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * After reading all MIB counters, the counters resets. + * + * RETURN: + * MIB counter value. + * + */ +static void eth_clear_mib_counters(unsigned int eth_port_num) +{ + int i; + + /* Perform dummy reads from MIB counters */ + for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; i += 4) + MV_READ(MV64340_ETH_MIB_COUNTERS_BASE(eth_port_num) + i); +} + + +/* + * ethernet_phy_get - Get the ethernet port PHY address. + * + * DESCRIPTION: + * This routine returns the given ethernet port PHY address. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * None. + * + * RETURN: + * PHY address. + * + */ +static int ethernet_phy_get(unsigned int eth_port_num) +{ + unsigned int reg_data; + + reg_data = MV_READ(MV64340_ETH_PHY_ADDR_REG); + + return ((reg_data >> (5 * eth_port_num)) & 0x1f); +} + +/* + * ethernet_phy_reset - Reset Ethernet port PHY. + * + * DESCRIPTION: + * This routine utilize the SMI interface to reset the ethernet port PHY. + * The routine waits until the link is up again or link up is timeout. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * The ethernet port PHY renew its link. + * + * RETURN: + * None. + * + */ +static int ethernet_phy_reset(unsigned int eth_port_num) +{ + unsigned int time_out = 50; + unsigned int phy_reg_data; + + /* Reset the PHY */ + eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); + phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ + eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); + + /* Poll on the PHY LINK */ + do { + eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); + + if (time_out-- == 0) + return 0; + } while (!(phy_reg_data & 0x20)); + + return 1; +} + +/* + * eth_port_reset - Reset Ethernet port + * + * DESCRIPTION: + * This routine resets the chip by aborting any SDMA engine activity and + * clearing the MIB counters. The Receiver and the Transmit unit are in + * idle state after this command is performed and the port is disabled. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * Channel activity is halted. + * + * RETURN: + * None. + * + */ +static void eth_port_reset(unsigned int eth_port_num) +{ + unsigned int reg_data; + + /* Stop Tx port activity. Check port Tx activity. */ + reg_data = + MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Tx activity to terminate. */ + do { + /* Check port cause register that all Tx queues are stopped */ + reg_data = + MV_READ + (MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + /* Stop Rx port activity. Check port Rx activity. */ + reg_data = + MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Rx activity to terminate. */ + do { + /* Check port cause register that all Rx queues are stopped */ + reg_data = + MV_READ + (MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + + /* Clear all MIB counters */ + eth_clear_mib_counters(eth_port_num); + + /* Reset the Enable bit in the Configuration Register */ + reg_data = + MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num)); + reg_data &= ~ETH_SERIAL_PORT_ENABLE; + MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), reg_data); + + return; +} + +/* + * ethernet_set_config_reg - Set specified bits in configuration register. + * + * DESCRIPTION: + * This function sets specified bits in the given ethernet + * configuration register. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int value 32 bit value. + * + * OUTPUT: + * The set bits in the value parameter are set in the configuration + * register. + * + * RETURN: + * None. + * + */ +static void ethernet_set_config_reg(unsigned int eth_port_num, + unsigned int value) +{ + unsigned int eth_config_reg; + + eth_config_reg = + MV_READ(MV64340_ETH_PORT_CONFIG_REG(eth_port_num)); + eth_config_reg |= value; + MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), + eth_config_reg); +} + +/* + * ethernet_get_config_reg - Get the port configuration register + * + * DESCRIPTION: + * This function returns the configuration register value of the given + * ethernet port. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * None. + * + * RETURN: + * Port configuration register value. + */ +static unsigned int ethernet_get_config_reg(unsigned int eth_port_num) +{ + unsigned int eth_config_reg; + + eth_config_reg = MV_READ(MV64340_ETH_PORT_CONFIG_EXTEND_REG + (eth_port_num)); + return eth_config_reg; +} + + +/* + * eth_port_read_smi_reg - Read PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform PHY register read. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int *value Register value buffer. + * + * OUTPUT: + * Write the value of a specified PHY register into given buffer. + * + * RETURN: + * false if the PHY is busy or read data is not in valid state. + * true otherwise. + * + */ +static int eth_port_read_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int *value) +{ + int phy_addr = ethernet_phy_get(eth_port_num); + unsigned int time_out = PHY_BUSY_TIMEOUT; + unsigned int reg_value; + + /* first check that it is not busy */ + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + + MV_WRITE(MV64340_ETH_SMI_REG, + (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ); + + time_out = PHY_BUSY_TIMEOUT; /* initialize the time out var again */ + + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_READ_VALID); + + /* Wait for the data to update in the SMI register */ + for (time_out = 0; time_out < PHY_BUSY_TIMEOUT; time_out++); + + reg_value = MV_READ(MV64340_ETH_SMI_REG); + + *value = reg_value & 0xffff; + + return 1; +} + +/* + * eth_port_write_smi_reg - Write to PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform writes to PHY registers. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int value Register value. + * + * OUTPUT: + * Write the given value to the specified PHY register. + * + * RETURN: + * false if the PHY is busy. + * true otherwise. + * + */ +static int eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int value) +{ + unsigned int time_out = PHY_BUSY_TIMEOUT; + unsigned int reg_value; + int phy_addr; + + phy_addr = ethernet_phy_get(eth_port_num); + + /* first check that it is not busy */ + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + MV_WRITE(MV64340_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) | + ETH_SMI_OPCODE_WRITE | (value & 0xffff)); + + return 1; +} + +/* + * eth_port_send - Send an Ethernet packet + * + * DESCRIPTION: + * This routine send a given packet described by p_pktinfo parameter. It + * supports transmitting of a packet spaned over multiple buffers. The + * routine updates 'curr' and 'first' indexes according to the packet + * segment passed to the routine. In case the packet segment is first, + * the 'first' index is update. In any case, the 'curr' index is updated. + * If the routine get into Tx resource error it assigns 'curr' index as + * 'first'. This way the function can abort Tx process of multiple + * descriptors per packet. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'curr' and 'first' indexes are updated. + * + * RETURN: + * ETH_QUEUE_FULL in case of Tx resource error. + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource. + * ETH_OK otherwise. + * + */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX +/* + * Modified to include the first descriptor pointer in case of SG + */ +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc; + volatile struct eth_tx_desc *current_descriptor; + volatile struct eth_tx_desc *first_descriptor; + u32 command_status, first_chip_ptr; + + /* Do not process Tx ring in case of Tx ring resource error */ + if (mp->tx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; + + current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + if (current_descriptor == NULL) + return ETH_ERROR; + + tx_next_desc = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; + command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + + if (command_status & ETH_TX_FIRST_DESC) { + tx_first_desc = tx_desc_curr; + mp->tx_first_desc_q = tx_first_desc; + + /* fill first descriptor */ + first_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + first_descriptor->l4i_chk = p_pkt_info->l4i_chk; + first_descriptor->cmd_sts = command_status; + first_descriptor->byte_cnt = p_pkt_info->byte_cnt; + first_descriptor->buf_ptr = p_pkt_info->buf_ptr; + first_descriptor->next_desc_ptr = mp->tx_desc_dma + + tx_next_desc * sizeof(struct eth_tx_desc); + wmb(); + } else { + tx_first_desc = mp->tx_first_desc_q; + first_descriptor = &mp->p_tx_desc_area[tx_first_desc]; + if (first_descriptor == NULL) { + printk("First desc is NULL !!\n"); + return ETH_ERROR; + } + if (command_status & ETH_TX_LAST_DESC) + current_descriptor->next_desc_ptr = 0x00000000; + else { + command_status |= ETH_BUFFER_OWNED_BY_DMA; + current_descriptor->next_desc_ptr = mp->tx_desc_dma + + tx_next_desc * sizeof(struct eth_tx_desc); + } + } + + if (p_pkt_info->byte_cnt < 8) { + printk(" < 8 problem \n"); + return ETH_ERROR; + } + + current_descriptor->buf_ptr = p_pkt_info->buf_ptr; + current_descriptor->byte_cnt = p_pkt_info->byte_cnt; + current_descriptor->l4i_chk = p_pkt_info->l4i_chk; + current_descriptor->cmd_sts = command_status; + + mp->tx_skb[tx_desc_curr] = (struct sk_buff*) p_pkt_info->return_info; + + wmb(); + + /* Set last desc with DMA ownership and interrupt enable. */ + if (command_status & ETH_TX_LAST_DESC) { + current_descriptor->cmd_sts = command_status | + ETH_TX_ENABLE_INTERRUPT | + ETH_BUFFER_OWNED_BY_DMA; + + if (!(command_status & ETH_TX_FIRST_DESC)) + first_descriptor->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA; + wmb(); + + first_chip_ptr = MV_READ(MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(mp->port_num)); + + /* Apply send command */ + if (first_chip_ptr == 0x00000000) + MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(mp->port_num), (struct eth_tx_desc *) mp->tx_desc_dma + tx_first_desc); + + ETH_ENABLE_TX_QUEUE(mp->port_num); + + /* + * Finish Tx packet. Update first desc in case of Tx resource + * error */ + tx_first_desc = tx_next_desc; + mp->tx_first_desc_q = tx_first_desc; + } else { + if (! (command_status & ETH_TX_FIRST_DESC) ) { + current_descriptor->cmd_sts = command_status; + wmb(); + } + } + + /* Check for ring index overlap in the Tx desc ring */ + if (tx_next_desc == tx_desc_used) { + mp->tx_resource_err = 1; + mp->tx_curr_desc_q = tx_first_desc; + + return ETH_QUEUE_LAST_RESOURCE; + } + + mp->tx_curr_desc_q = tx_next_desc; + wmb(); + + return ETH_OK; +} +#else +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_curr; + int tx_desc_used; + volatile struct eth_tx_desc* current_descriptor; + unsigned int command_status; + + /* Do not process Tx ring in case of Tx ring resource error */ + if (mp->tx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; + current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + + if (current_descriptor == NULL) + return ETH_ERROR; + + command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + +/* XXX Is this for real ?!?!? */ + /* Buffers with a payload smaller than 8 bytes must be aligned to a + * 64-bit boundary. We use the memory allocated for Tx descriptor. + * This memory is located in TX_BUF_OFFSET_IN_DESC offset within the + * Tx descriptor. */ + if (p_pkt_info->byte_cnt <= 8) { + printk(KERN_ERR + "You have failed in the < 8 bytes errata - fixme\n"); + return ETH_ERROR; + } + current_descriptor->buf_ptr = p_pkt_info->buf_ptr; + current_descriptor->byte_cnt = p_pkt_info->byte_cnt; + mp->tx_skb[tx_desc_curr] = (struct sk_buff *) p_pkt_info->return_info; + + mb(); + + /* Set last desc with DMA ownership and interrupt enable. */ + current_descriptor->cmd_sts = command_status | + ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT; + + /* Apply send command */ + ETH_ENABLE_TX_QUEUE(mp->port_num); + + /* Finish Tx packet. Update first desc in case of Tx resource error */ + tx_desc_curr = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; + + /* Update the current descriptor */ + mp->tx_curr_desc_q = tx_desc_curr; + + /* Check for ring index overlap in the Tx desc ring */ + if (tx_desc_curr == tx_desc_used) { + mp->tx_resource_err = 1; + return ETH_QUEUE_LAST_RESOURCE; + } + + return ETH_OK; +} +#endif + +/* + * eth_tx_return_desc - Free all used Tx descriptors + * + * DESCRIPTION: + * This routine returns the transmitted packet information to the caller. + * It uses the 'first' index to support Tx desc return in case a transmit + * of a packet spanned over multiple buffer still in process. + * In case the Tx queue was in "resource error" condition, where there are + * no available Tx resources, the function resets the resource error flag. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'first' and 'used' indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_RETRY in case there is transmission in process. + * ETH_END_OF_JOB if the routine has nothing to release. + * ETH_OK otherwise. + * + */ +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_used, tx_desc_curr; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + int tx_first_desc; +#endif + volatile struct eth_tx_desc *p_tx_desc_used; + unsigned int command_status; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + tx_first_desc = mp->tx_first_desc_q; +#endif + p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used]; + + /* XXX Sanity check */ + if (p_tx_desc_used == NULL) + return ETH_ERROR; + + command_status = p_tx_desc_used->cmd_sts; + + /* Still transmitting... */ +#ifndef MV64340_CHECKSUM_OFFLOAD_TX + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) + return ETH_RETRY; +#endif + /* Stop release. About to overlap the current available Tx descriptor */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + if (tx_desc_used == tx_first_desc && !mp->tx_resource_err) + return ETH_END_OF_JOB; +#else + if (tx_desc_used == tx_desc_curr && !mp->tx_resource_err) + return ETH_END_OF_JOB; +#endif + + /* Pass the packet information to the caller */ + p_pkt_info->cmd_sts = command_status; + p_pkt_info->return_info = mp->tx_skb[tx_desc_used]; + mp->tx_skb[tx_desc_used] = NULL; + + /* Update the next descriptor to release. */ + mp->tx_used_desc_q = (tx_desc_used + 1) % MV64340_TX_QUEUE_SIZE; + + /* Any Tx return cancels the Tx resource error status */ + mp->tx_resource_err = 0; + + return ETH_OK; +} + +/* + * eth_port_receive - Get received information from Rx ring. + * + * DESCRIPTION: + * This routine returns the received data to the caller. There is no + * data copying during routine operation. All information is returned + * using pointer to packet information struct passed from the caller. + * If the routine exhausts Rx ring resources then the resource error flag + * is set. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Rx ring current and used indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_QUEUE_FULL if Rx ring resources are exhausted. + * ETH_END_OF_JOB if there is no received data. + * ETH_OK otherwise. + */ +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int rx_next_curr_desc, rx_curr_desc, rx_used_desc; + volatile struct eth_rx_desc * p_rx_desc; + unsigned int command_status; + + /* Do not process Rx ring in case of Rx ring resource error */ + if (mp->rx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Rx Desc ring 'curr and 'used' indexes */ + rx_curr_desc = mp->rx_curr_desc_q; + rx_used_desc = mp->rx_used_desc_q; + + p_rx_desc = &mp->p_rx_desc_area[rx_curr_desc]; + + /* The following parameters are used to save readings from memory */ + command_status = p_rx_desc->cmd_sts; + + /* Nothing to receive... */ + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) + return ETH_END_OF_JOB; + + p_pkt_info->byte_cnt = (p_rx_desc->byte_cnt) - RX_BUF_OFFSET; + p_pkt_info->cmd_sts = command_status; + p_pkt_info->buf_ptr = (p_rx_desc->buf_ptr) + RX_BUF_OFFSET; + p_pkt_info->return_info = mp->rx_skb[rx_curr_desc]; + p_pkt_info->l4i_chk = p_rx_desc->buf_size; + + /* Clean the return info field to indicate that the packet has been */ + /* moved to the upper layers */ + mp->rx_skb[rx_curr_desc] = NULL; + + /* Update current index in data structure */ + rx_next_curr_desc = (rx_curr_desc + 1) % MV64340_RX_QUEUE_SIZE; + mp->rx_curr_desc_q = rx_next_curr_desc; + + /* Rx descriptors exhausted. Set the Rx ring resource error flag */ + if (rx_next_curr_desc == rx_used_desc) + mp->rx_resource_err = 1; + + mb(); + return ETH_OK; +} + +/* + * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring. + * + * DESCRIPTION: + * This routine returns a Rx buffer back to the Rx ring. It retrieves the + * next 'used' descriptor and attached the returned buffer to it. + * In case the Rx ring was in "resource error" condition, where there are + * no available Rx resources, the function resets the resource error flag. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info Information on the returned buffer. + * + * OUTPUT: + * New available Rx resource in Rx descriptor ring. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_OK otherwise. + */ +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int used_rx_desc; /* Where to return Rx resource */ + volatile struct eth_rx_desc* p_used_rx_desc; + + /* Get 'used' Rx descriptor */ + used_rx_desc = mp->rx_used_desc_q; + p_used_rx_desc = &mp->p_rx_desc_area[used_rx_desc]; + + p_used_rx_desc->buf_ptr = p_pkt_info->buf_ptr; + p_used_rx_desc->buf_size = p_pkt_info->byte_cnt; + mp->rx_skb[used_rx_desc] = p_pkt_info->return_info; + + /* Flush the write pipe */ + mb(); + + /* Return the descriptor to DMA ownership */ + p_used_rx_desc->cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + + /* Flush descriptor and CPU pipe */ + mb(); + + /* Move the used descriptor pointer to the next descriptor */ + mp->rx_used_desc_q = (used_rx_desc + 1) % MV64340_RX_QUEUE_SIZE; + + /* Any Rx return cancels the Rx resource error status */ + mp->rx_resource_err = 0; + + return ETH_OK; +} diff -Nru a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/mv643xx_eth.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,601 @@ +#ifndef __MV64340_ETH_H__ +#define __MV64340_ETH_H__ + +#include +#include +#include +#include +#include + +#include + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +/* + * The first part is the high level driver of the gigE ethernet ports. + */ + +#define ETH_PORT0_IRQ_NUM 48 /* main high register, bit0 */ +#define ETH_PORT1_IRQ_NUM ETH_PORT0_IRQ_NUM+1 /* main high register, bit1 */ +#define ETH_PORT2_IRQ_NUM ETH_PORT0_IRQ_NUM+2 /* main high register, bit1 */ + +/* Checksum offload for Tx works */ +#define MV64340_CHECKSUM_OFFLOAD_TX +#define MV64340_NAPI +#define MV64340_TX_FAST_REFILL +#undef MV64340_COAL + +/* + * Number of RX / TX descriptors on RX / TX rings. + * Note that allocating RX descriptors is done by allocating the RX + * ring AND a preallocated RX buffers (skb's) for each descriptor. + * The TX descriptors only allocates the TX descriptors ring, + * with no pre allocated TX buffers (skb's are allocated by higher layers. + */ + +/* Default TX ring size is 1000 descriptors */ +#define MV64340_TX_QUEUE_SIZE 1000 + +/* Default RX ring size is 400 descriptors */ +#define MV64340_RX_QUEUE_SIZE 400 + +#define MV64340_TX_COAL 100 +#ifdef MV64340_COAL +#define MV64340_RX_COAL 100 +#endif + + +/* + * The second part is the low level driver of the gigE ethernet ports. * + */ + + +/* + * Header File for : MV-643xx network interface header + * + * DESCRIPTION: + * This header file contains macros typedefs and function declaration for + * the Marvell Gig Bit Ethernet Controller. + * + * DEPENDENCIES: + * None. + * + */ + +/* Default port configuration value */ +#define PORT_CONFIG_VALUE \ + ETH_UNICAST_NORMAL_MODE | \ + ETH_DEFAULT_RX_QUEUE_0 | \ + ETH_DEFAULT_RX_ARP_QUEUE_0 | \ + ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ + ETH_RECEIVE_BC_IF_IP | \ + ETH_RECEIVE_BC_IF_ARP | \ + ETH_CAPTURE_TCP_FRAMES_DIS | \ + ETH_CAPTURE_UDP_FRAMES_DIS | \ + ETH_DEFAULT_RX_TCP_QUEUE_0 | \ + ETH_DEFAULT_RX_UDP_QUEUE_0 | \ + ETH_DEFAULT_RX_BPDU_QUEUE_0 + +/* Default port extend configuration value */ +#define PORT_CONFIG_EXTEND_VALUE \ + ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ + ETH_PARTITION_DISABLE + + +/* Default sdma control value */ +#define PORT_SDMA_CONFIG_VALUE \ + ETH_RX_BURST_SIZE_16_64BIT | \ + GT_ETH_IPG_INT_RX(0) | \ + ETH_TX_BURST_SIZE_16_64BIT; + +#define GT_ETH_IPG_INT_RX(value) \ + ((value & 0x3fff) << 8) + +/* Default port serial control value */ +#define PORT_SERIAL_CONTROL_VALUE \ + ETH_FORCE_LINK_PASS | \ + ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ + ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ + ETH_ADV_SYMMETRIC_FLOW_CTRL | \ + ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + ETH_FORCE_BP_MODE_NO_JAM | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL | \ + ETH_RETRANSMIT_16_ATTEMPTS | \ + ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ + ETH_DTE_ADV_0 | \ + ETH_DISABLE_AUTO_NEG_BYPASS | \ + ETH_AUTO_NEG_NO_CHANGE | \ + ETH_MAX_RX_PACKET_9700BYTE | \ + ETH_CLR_EXT_LOOPBACK | \ + ETH_SET_FULL_DUPLEX_MODE | \ + ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX + +#define RX_BUFFER_MAX_SIZE 0x4000000 +#define TX_BUFFER_MAX_SIZE 0x4000000 + +/* MAC accepet/reject macros */ +#define ACCEPT_MAC_ADDR 0 +#define REJECT_MAC_ADDR 1 + +/* Buffer offset from buffer pointer */ +#define RX_BUF_OFFSET 0x2 + +/* Gigabit Ethernet Unit Global Registers */ + +/* MIB Counters register definitions */ +#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0 +#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4 +#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8 +#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc +#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10 +#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14 +#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18 +#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c +#define ETH_MIB_FRAMES_64_OCTETS 0x20 +#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24 +#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28 +#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c +#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30 +#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34 +#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38 +#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c +#define ETH_MIB_GOOD_FRAMES_SENT 0x40 +#define ETH_MIB_EXCESSIVE_COLLISION 0x44 +#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48 +#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c +#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50 +#define ETH_MIB_FC_SENT 0x54 +#define ETH_MIB_GOOD_FC_RECEIVED 0x58 +#define ETH_MIB_BAD_FC_RECEIVED 0x5c +#define ETH_MIB_UNDERSIZE_RECEIVED 0x60 +#define ETH_MIB_FRAGMENTS_RECEIVED 0x64 +#define ETH_MIB_OVERSIZE_RECEIVED 0x68 +#define ETH_MIB_JABBER_RECEIVED 0x6c +#define ETH_MIB_MAC_RECEIVE_ERROR 0x70 +#define ETH_MIB_BAD_CRC_EVENT 0x74 +#define ETH_MIB_COLLISION 0x78 +#define ETH_MIB_LATE_COLLISION 0x7c + +/* Port serial status reg (PSR) */ +#define ETH_INTERFACE_GMII_MII 0 +#define ETH_INTERFACE_PCM BIT0 +#define ETH_LINK_IS_DOWN 0 +#define ETH_LINK_IS_UP BIT1 +#define ETH_PORT_AT_HALF_DUPLEX 0 +#define ETH_PORT_AT_FULL_DUPLEX BIT2 +#define ETH_RX_FLOW_CTRL_DISABLED 0 +#define ETH_RX_FLOW_CTRL_ENBALED BIT3 +#define ETH_GMII_SPEED_100_10 0 +#define ETH_GMII_SPEED_1000 BIT4 +#define ETH_MII_SPEED_10 0 +#define ETH_MII_SPEED_100 BIT5 +#define ETH_NO_TX 0 +#define ETH_TX_IN_PROGRESS BIT7 +#define ETH_BYPASS_NO_ACTIVE 0 +#define ETH_BYPASS_ACTIVE BIT8 +#define ETH_PORT_NOT_AT_PARTITION_STATE 0 +#define ETH_PORT_AT_PARTITION_STATE BIT9 +#define ETH_PORT_TX_FIFO_NOT_EMPTY 0 +#define ETH_PORT_TX_FIFO_EMPTY BIT10 + + +/* These macros describes the Port configuration reg (Px_cR) bits */ +#define ETH_UNICAST_NORMAL_MODE 0 +#define ETH_UNICAST_PROMISCUOUS_MODE BIT0 +#define ETH_DEFAULT_RX_QUEUE_0 0 +#define ETH_DEFAULT_RX_QUEUE_1 BIT1 +#define ETH_DEFAULT_RX_QUEUE_2 BIT2 +#define ETH_DEFAULT_RX_QUEUE_3 (BIT2 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_4 BIT3 +#define ETH_DEFAULT_RX_QUEUE_5 (BIT3 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_6 (BIT3 | BIT2) +#define ETH_DEFAULT_RX_QUEUE_7 (BIT3 | BIT2 | BIT1) +#define ETH_DEFAULT_RX_ARP_QUEUE_0 0 +#define ETH_DEFAULT_RX_ARP_QUEUE_1 BIT4 +#define ETH_DEFAULT_RX_ARP_QUEUE_2 BIT5 +#define ETH_DEFAULT_RX_ARP_QUEUE_3 (BIT5 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_4 BIT6 +#define ETH_DEFAULT_RX_ARP_QUEUE_5 (BIT6 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_6 (BIT6 | BIT5) +#define ETH_DEFAULT_RX_ARP_QUEUE_7 (BIT6 | BIT5 | BIT4) +#define ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP 0 +#define ETH_REJECT_BC_IF_NOT_IP_OR_ARP BIT7 +#define ETH_RECEIVE_BC_IF_IP 0 +#define ETH_REJECT_BC_IF_IP BIT8 +#define ETH_RECEIVE_BC_IF_ARP 0 +#define ETH_REJECT_BC_IF_ARP BIT9 +#define ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY BIT12 +#define ETH_CAPTURE_TCP_FRAMES_DIS 0 +#define ETH_CAPTURE_TCP_FRAMES_EN BIT14 +#define ETH_CAPTURE_UDP_FRAMES_DIS 0 +#define ETH_CAPTURE_UDP_FRAMES_EN BIT15 +#define ETH_DEFAULT_RX_TCP_QUEUE_0 0 +#define ETH_DEFAULT_RX_TCP_QUEUE_1 BIT16 +#define ETH_DEFAULT_RX_TCP_QUEUE_2 BIT17 +#define ETH_DEFAULT_RX_TCP_QUEUE_3 (BIT17 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_4 BIT18 +#define ETH_DEFAULT_RX_TCP_QUEUE_5 (BIT18 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_6 (BIT18 | BIT17) +#define ETH_DEFAULT_RX_TCP_QUEUE_7 (BIT18 | BIT17 | BIT16) +#define ETH_DEFAULT_RX_UDP_QUEUE_0 0 +#define ETH_DEFAULT_RX_UDP_QUEUE_1 BIT19 +#define ETH_DEFAULT_RX_UDP_QUEUE_2 BIT20 +#define ETH_DEFAULT_RX_UDP_QUEUE_3 (BIT20 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_4 (BIT21 +#define ETH_DEFAULT_RX_UDP_QUEUE_5 (BIT21 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_6 (BIT21 | BIT20) +#define ETH_DEFAULT_RX_UDP_QUEUE_7 (BIT21 | BIT20 | BIT19) +#define ETH_DEFAULT_RX_BPDU_QUEUE_0 0 +#define ETH_DEFAULT_RX_BPDU_QUEUE_1 BIT22 +#define ETH_DEFAULT_RX_BPDU_QUEUE_2 BIT23 +#define ETH_DEFAULT_RX_BPDU_QUEUE_3 (BIT23 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_4 BIT24 +#define ETH_DEFAULT_RX_BPDU_QUEUE_5 (BIT24 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_6 (BIT24 | BIT23) +#define ETH_DEFAULT_RX_BPDU_QUEUE_7 (BIT24 | BIT23 | BIT22) + + +/* These macros describes the Port configuration extend reg (Px_cXR) bits*/ +#define ETH_CLASSIFY_EN BIT0 +#define ETH_SPAN_BPDU_PACKETS_AS_NORMAL 0 +#define ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 BIT1 +#define ETH_PARTITION_DISABLE 0 +#define ETH_PARTITION_ENABLE BIT2 + + +/* Tx/Rx queue command reg (RQCR/TQCR)*/ +#define ETH_QUEUE_0_ENABLE BIT0 +#define ETH_QUEUE_1_ENABLE BIT1 +#define ETH_QUEUE_2_ENABLE BIT2 +#define ETH_QUEUE_3_ENABLE BIT3 +#define ETH_QUEUE_4_ENABLE BIT4 +#define ETH_QUEUE_5_ENABLE BIT5 +#define ETH_QUEUE_6_ENABLE BIT6 +#define ETH_QUEUE_7_ENABLE BIT7 +#define ETH_QUEUE_0_DISABLE BIT8 +#define ETH_QUEUE_1_DISABLE BIT9 +#define ETH_QUEUE_2_DISABLE BIT10 +#define ETH_QUEUE_3_DISABLE BIT11 +#define ETH_QUEUE_4_DISABLE BIT12 +#define ETH_QUEUE_5_DISABLE BIT13 +#define ETH_QUEUE_6_DISABLE BIT14 +#define ETH_QUEUE_7_DISABLE BIT15 + + +/* These macros describes the Port Sdma configuration reg (SDCR) bits */ +#define ETH_RIFB BIT0 +#define ETH_RX_BURST_SIZE_1_64BIT 0 +#define ETH_RX_BURST_SIZE_2_64BIT BIT1 +#define ETH_RX_BURST_SIZE_4_64BIT BIT2 +#define ETH_RX_BURST_SIZE_8_64BIT (BIT2 | BIT1) +#define ETH_RX_BURST_SIZE_16_64BIT BIT3 +#define ETH_BLM_RX_NO_SWAP BIT4 +#define ETH_BLM_RX_BYTE_SWAP 0 +#define ETH_BLM_TX_NO_SWAP BIT5 +#define ETH_BLM_TX_BYTE_SWAP 0 +#define ETH_DESCRIPTORS_BYTE_SWAP BIT6 +#define ETH_DESCRIPTORS_NO_SWAP 0 +#define ETH_TX_BURST_SIZE_1_64BIT 0 +#define ETH_TX_BURST_SIZE_2_64BIT BIT22 +#define ETH_TX_BURST_SIZE_4_64BIT BIT23 +#define ETH_TX_BURST_SIZE_8_64BIT (BIT23 | BIT22) +#define ETH_TX_BURST_SIZE_16_64BIT BIT24 + + + +/* These macros describes the Port serial control reg (PSCR) bits */ +#define ETH_SERIAL_PORT_DISABLE 0 +#define ETH_SERIAL_PORT_ENABLE BIT0 +#define ETH_FORCE_LINK_PASS BIT1 +#define ETH_DO_NOT_FORCE_LINK_PASS 0 +#define ETH_ENABLE_AUTO_NEG_FOR_DUPLX 0 +#define ETH_DISABLE_AUTO_NEG_FOR_DUPLX BIT2 +#define ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL 0 +#define ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL BIT3 +#define ETH_ADV_NO_FLOW_CTRL 0 +#define ETH_ADV_SYMMETRIC_FLOW_CTRL BIT4 +#define ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0 +#define ETH_FORCE_FC_MODE_TX_PAUSE_DIS BIT5 +#define ETH_FORCE_BP_MODE_NO_JAM 0 +#define ETH_FORCE_BP_MODE_JAM_TX BIT7 +#define ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR BIT8 +#define ETH_FORCE_LINK_FAIL 0 +#define ETH_DO_NOT_FORCE_LINK_FAIL BIT10 +#define ETH_RETRANSMIT_16_ATTEMPTS 0 +#define ETH_RETRANSMIT_FOREVER BIT11 +#define ETH_DISABLE_AUTO_NEG_SPEED_GMII BIT13 +#define ETH_ENABLE_AUTO_NEG_SPEED_GMII 0 +#define ETH_DTE_ADV_0 0 +#define ETH_DTE_ADV_1 BIT14 +#define ETH_DISABLE_AUTO_NEG_BYPASS 0 +#define ETH_ENABLE_AUTO_NEG_BYPASS BIT15 +#define ETH_AUTO_NEG_NO_CHANGE 0 +#define ETH_RESTART_AUTO_NEG BIT16 +#define ETH_MAX_RX_PACKET_1518BYTE 0 +#define ETH_MAX_RX_PACKET_1522BYTE BIT17 +#define ETH_MAX_RX_PACKET_1552BYTE BIT18 +#define ETH_MAX_RX_PACKET_9022BYTE (BIT18 | BIT17) +#define ETH_MAX_RX_PACKET_9192BYTE BIT19 +#define ETH_MAX_RX_PACKET_9700BYTE (BIT19 | BIT17) +#define ETH_SET_EXT_LOOPBACK BIT20 +#define ETH_CLR_EXT_LOOPBACK 0 +#define ETH_SET_FULL_DUPLEX_MODE BIT21 +#define ETH_SET_HALF_DUPLEX_MODE 0 +#define ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX BIT22 +#define ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0 +#define ETH_SET_GMII_SPEED_TO_10_100 0 +#define ETH_SET_GMII_SPEED_TO_1000 BIT23 +#define ETH_SET_MII_SPEED_TO_10 0 +#define ETH_SET_MII_SPEED_TO_100 BIT24 + + +/* SMI reg */ +#define ETH_SMI_BUSY BIT28 /* 0 - Write, 1 - Read */ +#define ETH_SMI_READ_VALID BIT27 /* 0 - Write, 1 - Read */ +#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read operation */ +#define ETH_SMI_OPCODE_READ BIT26 /* Operation is in progress */ + +/* SDMA command status fields macros */ + +/* Tx & Rx descriptors status */ +#define ETH_ERROR_SUMMARY (BIT0) + +/* Tx & Rx descriptors command */ +#define ETH_BUFFER_OWNED_BY_DMA (BIT31) + +/* Tx descriptors status */ +#define ETH_LC_ERROR (0 ) +#define ETH_UR_ERROR (BIT1 ) +#define ETH_RL_ERROR (BIT2 ) +#define ETH_LLC_SNAP_FORMAT (BIT9 ) + +/* Rx descriptors status */ +#define ETH_CRC_ERROR (0 ) +#define ETH_OVERRUN_ERROR (BIT1 ) +#define ETH_MAX_FRAME_LENGTH_ERROR (BIT2 ) +#define ETH_RESOURCE_ERROR ((BIT2 | BIT1)) +#define ETH_VLAN_TAGGED (BIT19) +#define ETH_BPDU_FRAME (BIT20) +#define ETH_TCP_FRAME_OVER_IP_V_4 (0 ) +#define ETH_UDP_FRAME_OVER_IP_V_4 (BIT21) +#define ETH_OTHER_FRAME_TYPE (BIT22) +#define ETH_LAYER_2_IS_ETH_V_2 (BIT23) +#define ETH_FRAME_TYPE_IP_V_4 (BIT24) +#define ETH_FRAME_HEADER_OK (BIT25) +#define ETH_RX_LAST_DESC (BIT26) +#define ETH_RX_FIRST_DESC (BIT27) +#define ETH_UNKNOWN_DESTINATION_ADDR (BIT28) +#define ETH_RX_ENABLE_INTERRUPT (BIT29) +#define ETH_LAYER_4_CHECKSUM_OK (BIT30) + +/* Rx descriptors byte count */ +#define ETH_FRAME_FRAGMENTED (BIT2) + +/* Tx descriptors command */ +#define ETH_LAYER_4_CHECKSUM_FIRST_DESC (BIT10) +#define ETH_FRAME_SET_TO_VLAN (BIT15) +#define ETH_TCP_FRAME (0 ) +#define ETH_UDP_FRAME (BIT16) +#define ETH_GEN_TCP_UDP_CHECKSUM (BIT17) +#define ETH_GEN_IP_V_4_CHECKSUM (BIT18) +#define ETH_ZERO_PADDING (BIT19) +#define ETH_TX_LAST_DESC (BIT20) +#define ETH_TX_FIRST_DESC (BIT21) +#define ETH_GEN_CRC (BIT22) +#define ETH_TX_ENABLE_INTERRUPT (BIT23) +#define ETH_AUTO_MODE (BIT30) + +/* typedefs */ + +typedef enum _eth_func_ret_status { + ETH_OK, /* Returned as expected. */ + ETH_ERROR, /* Fundamental error. */ + ETH_RETRY, /* Could not process request. Try later. */ + ETH_END_OF_JOB, /* Ring has nothing to process. */ + ETH_QUEUE_FULL, /* Ring resource error. */ + ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */ +} ETH_FUNC_RET_STATUS; + +typedef enum _eth_target { + ETH_TARGET_DRAM, + ETH_TARGET_DEVICE, + ETH_TARGET_CBS, + ETH_TARGET_PCI0, + ETH_TARGET_PCI1 +} ETH_TARGET; + +/* These are for big-endian machines. Little endian needs different + * definitions. + */ +#if defined(__BIG_ENDIAN) +struct eth_rx_desc { + u16 byte_cnt; /* Descriptor buffer byte count */ + u16 buf_size; /* Buffer size */ + u32 cmd_sts; /* Descriptor command status */ + u32 next_desc_ptr; /* Next descriptor pointer */ + u32 buf_ptr; /* Descriptor buffer pointer */ +}; + +struct eth_tx_desc { + u16 byte_cnt; /* buffer byte count */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u32 cmd_sts; /* Command/status field */ + u32 next_desc_ptr; /* Pointer to next descriptor */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ +}; + +#elif defined(__LITTLE_ENDIAN) +struct eth_rx_desc { + u32 cmd_sts; /* Descriptor command status */ + u16 buf_size; /* Buffer size */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u32 buf_ptr; /* Descriptor buffer pointer */ + u32 next_desc_ptr; /* Next descriptor pointer */ +}; + +struct eth_tx_desc { + u32 cmd_sts; /* Command/status field */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u16 byte_cnt; /* buffer byte count */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ + u32 next_desc_ptr; /* Pointer to next descriptor */ +}; +#else +#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined +#endif + +/* Unified struct for Rx and Tx operations. The user is not required to */ +/* be familier with neither Tx nor Rx descriptors. */ +struct pkt_info { + unsigned short byte_cnt; /* Descriptor buffer byte count */ + unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */ + unsigned int cmd_sts; /* Descriptor command status */ + dma_addr_t buf_ptr; /* Descriptor buffer pointer */ + struct sk_buff * return_info; /* User resource return information */ +}; + + +/* Ethernet port specific infomation */ + +struct mv64340_private { + int port_num; /* User Ethernet port number */ + u8 port_mac_addr[6]; /* User defined port MAC address. */ + u32 port_config; /* User port configuration value */ + u32 port_config_extend; /* User port config extend value */ + u32 port_sdma_config; /* User port SDMA config value */ + u32 port_serial_control; /* User port serial control value */ + u32 port_tx_queue_command; /* Port active Tx queues summary */ + u32 port_rx_queue_command; /* Port active Rx queues summary */ + + int rx_resource_err; /* Rx ring resource error flag */ + int tx_resource_err; /* Tx ring resource error flag */ + + /* Tx/Rx rings managment indexes fields. For driver use */ + + /* Next available and first returning Rx resource */ + int rx_curr_desc_q, rx_used_desc_q; + + /* Next available and first returning Tx resource */ + int tx_curr_desc_q, tx_used_desc_q; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + int tx_first_desc_q; +#endif + +#ifdef MV64340_TX_FAST_REFILL + u32 tx_clean_threshold; +#endif + + volatile struct eth_rx_desc * p_rx_desc_area; + dma_addr_t rx_desc_dma; + unsigned int rx_desc_area_size; + struct sk_buff * rx_skb[MV64340_RX_QUEUE_SIZE]; + + volatile struct eth_tx_desc * p_tx_desc_area; + dma_addr_t tx_desc_dma; + unsigned int tx_desc_area_size; + struct sk_buff * tx_skb[MV64340_TX_QUEUE_SIZE]; + + struct work_struct tx_timeout_task; + + /* + * Former struct mv64340_eth_priv members start here + */ + struct net_device_stats stats; + spinlock_t lock; + /* Size of Tx Ring per queue */ + unsigned int tx_ring_size; + /* Ammont of SKBs outstanding on Tx queue */ + unsigned int tx_ring_skbs; + /* Size of Rx Ring per queue */ + unsigned int rx_ring_size; + /* Ammount of SKBs allocated to Rx Ring per queue */ + unsigned int rx_ring_skbs; + + /* + * rx_task used to fill RX ring out of bottom half context + */ + struct work_struct rx_task; + + /* + * Used in case RX Ring is empty, which can be caused when + * system does not have resources (skb's) + */ + struct timer_list timeout; + long rx_task_busy __attribute__ ((aligned(SMP_CACHE_BYTES))); + unsigned rx_timer_flag; + + u32 rx_int_coal; + u32 tx_int_coal; +}; + +/* ethernet.h API list */ + +/* Port operation control routines */ +static void eth_port_init(struct mv64340_private *mp); +static void eth_port_reset(unsigned int eth_port_num); +static int eth_port_start(struct mv64340_private *mp); + +static void ethernet_set_config_reg(unsigned int eth_port_num, + unsigned int value); +static unsigned int ethernet_get_config_reg(unsigned int eth_port_num); + +/* Port MAC address routines */ +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr); + +/* PHY and MIB routines */ +static int ethernet_phy_reset(unsigned int eth_port_num); + +static int eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, + unsigned int value); + +static int eth_port_read_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, + unsigned int *value); + +static void eth_clear_mib_counters(unsigned int eth_port_num); + +/* Port data flow control routines */ +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); + +#endif /* __MV64340_ETH_H__ */ diff -Nru a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c --- a/drivers/net/myri_sbus.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/myri_sbus.c 2004-10-18 14:55:54 -07:00 @@ -85,7 +85,7 @@ static struct myri_eth *root_myri_dev; #endif -static void myri_reset_off(unsigned long lp, unsigned long cregs) +static void myri_reset_off(void __iomem *lp, void __iomem *cregs) { /* Clear IRQ mask. */ sbus_writel(0, lp + LANAI_EIMASK); @@ -94,7 +94,7 @@ sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL); } -static void myri_reset_on(unsigned long cregs) +static void myri_reset_on(void __iomem *cregs) { /* Enable RESET function. */ sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL); @@ -103,14 +103,14 @@ sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL); } -static void myri_disable_irq(unsigned long lp, unsigned long cregs) +static void myri_disable_irq(void __iomem *lp, void __iomem *cregs) { sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL); sbus_writel(0, lp + LANAI_EIMASK); sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT); } -static void myri_enable_irq(unsigned long lp, unsigned long cregs) +static void myri_enable_irq(void __iomem *lp, void __iomem *cregs) { sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL); sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK); @@ -119,7 +119,7 @@ static inline void bang_the_chip(struct myri_eth *mp) { struct myri_shmem *shmem = mp->shmem; - unsigned long cregs = mp->cregs; + void __iomem *cregs = mp->cregs; sbus_writel(1, &shmem->send); sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL); @@ -128,7 +128,7 @@ static int myri_do_handshake(struct myri_eth *mp) { struct myri_shmem *shmem = mp->shmem; - unsigned long cregs = mp->cregs; + void __iomem *cregs = mp->cregs; struct myri_channel *chan = &shmem->channel; int tick = 0; @@ -176,27 +176,27 @@ static int myri_load_lanai(struct myri_eth *mp) { struct net_device *dev = mp->dev; - struct myri_shmem *shmem = mp->shmem; - unsigned char *rptr; + struct myri_shmem __iomem *shmem = mp->shmem; + void __iomem *rptr; int i; myri_disable_irq(mp->lregs, mp->cregs); myri_reset_on(mp->cregs); - rptr = (unsigned char *) mp->lanai; + rptr = mp->lanai; for (i = 0; i < mp->eeprom.ramsz; i++) - sbus_writeb(0, &rptr[i]); + sbus_writeb(0, rptr + i); if (mp->eeprom.cpuvers >= CPUVERS_3_0) sbus_writel(mp->eeprom.cval, mp->lregs + LANAI_CVAL); /* Load executable code. */ for (i = 0; i < sizeof(lanai4_code); i++) - sbus_writeb(lanai4_code[i], &rptr[(lanai4_code_off * 2) + i]); + sbus_writeb(lanai4_code[i], rptr + (lanai4_code_off * 2) + i); /* Load data segment. */ for (i = 0; i < sizeof(lanai4_data); i++) - sbus_writeb(lanai4_data[i], &rptr[(lanai4_data_off * 2) + i]); + sbus_writeb(lanai4_data[i], rptr + (lanai4_data_off * 2) + i); /* Set device address. */ sbus_writeb(0, &shmem->addr[0]); @@ -237,15 +237,15 @@ static void myri_clean_rings(struct myri_eth *mp) { - struct sendq *sq = mp->sq; - struct recvq *rq = mp->rq; + struct sendq __iomem *sq = mp->sq; + struct recvq __iomem *rq = mp->rq; int i; sbus_writel(0, &rq->tail); sbus_writel(0, &rq->head); for (i = 0; i < (RX_RING_SIZE+1); i++) { if (mp->rx_skbs[i] != NULL) { - struct myri_rxd *rxd = &rq->myri_rxd[i]; + struct myri_rxd __iomem *rxd = &rq->myri_rxd[i]; u32 dma_addr; dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); @@ -261,7 +261,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { if (mp->tx_skbs[i] != NULL) { struct sk_buff *skb = mp->tx_skbs[i]; - struct myri_txd *txd = &sq->myri_txd[i]; + struct myri_txd __iomem *txd = &sq->myri_txd[i]; u32 dma_addr; dma_addr = sbus_readl(&txd->myri_gathers[0].addr); @@ -274,8 +274,8 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq) { - struct recvq *rq = mp->rq; - struct myri_rxd *rxd = &rq->myri_rxd[0]; + struct recvq __iomem *rq = mp->rq; + struct myri_rxd __iomem *rxd = &rq->myri_rxd[0]; struct net_device *dev = mp->dev; int gfp_flags = GFP_KERNEL; int i; @@ -343,7 +343,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) { - struct sendq *sq = mp->sq; + struct sendq __iomem *sq= mp->sq; int entry = mp->tx_old; int limit = sbus_readl(&sq->head); @@ -376,7 +376,7 @@ skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN); skb_pull(skb, dev->hard_header_len); - eth = skb->mac.ethernet; + eth = eth_hdr(skb); #ifdef DEBUG_HEADER DHDR(("myri_type_trans: ")); @@ -411,8 +411,8 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) { - struct recvq *rq = mp->rq; - struct recvq *rqa = mp->rqack; + struct recvq __iomem *rq = mp->rq; + struct recvq __iomem *rqa = mp->rqack; int entry = sbus_readl(&rqa->head); int limit = sbus_readl(&rqa->tail); int drops; @@ -423,11 +423,11 @@ drops = 0; DRX(("\n")); while (entry != limit) { - struct myri_rxd *rxdack = &rqa->myri_rxd[entry]; + struct myri_rxd __iomem *rxdack = &rqa->myri_rxd[entry]; u32 csum = sbus_readl(&rxdack->csum); int len = sbus_readl(&rxdack->myri_scatters[0].len); int index = sbus_readl(&rxdack->ctx); - struct myri_rxd *rxd = &rq->myri_rxd[rq->tail]; + struct myri_rxd __iomem *rxd = &rq->myri_rxd[rq->tail]; struct sk_buff *skb = mp->rx_skbs[index]; /* Ack it. */ @@ -545,7 +545,7 @@ { struct net_device *dev = (struct net_device *) dev_id; struct myri_eth *mp = (struct myri_eth *) dev->priv; - unsigned long lregs = mp->lregs; + void __iomem *lregs = mp->lregs; struct myri_channel *chan = &mp->shmem->channel; unsigned long flags; u32 status; @@ -610,8 +610,8 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct myri_eth *mp = (struct myri_eth *) dev->priv; - struct sendq *sq = mp->sq; - struct myri_txd *txd; + struct sendq __iomem *sq = mp->sq; + struct myri_txd __iomem *txd; unsigned long flags; unsigned int head, tail; int len, entry; @@ -998,22 +998,20 @@ printk("MyriCOM: Cannot map MyriCOM registers.\n"); goto err; } - mp->lanai = (unsigned short *) (mp->regs + (256 * 1024)); - mp->lanai3 = (unsigned int *) mp->lanai; - mp->lregs = (unsigned long) &mp->lanai[0x10000]; + mp->lanai = mp->regs + (256 * 1024); + mp->lregs = mp->lanai + (0x10000 * 2); } else { DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n")); mp->cregs = sbus_ioremap(&sdev->resource[0], 0, PAGE_SIZE, "MyriCOM Control Regs"); mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024), PAGE_SIZE, "MyriCOM LANAI Regs"); - mp->lanai = (unsigned short *) + mp->lanai = sbus_ioremap(&sdev->resource[0], (512 * 1024), mp->eeprom.ramsz, "MyriCOM SRAM"); - mp->lanai3 = (unsigned int *) mp->lanai; } - DET(("Registers mapped: cregs[%lx] lregs[%lx] lanai[%p] lanai3[%p]\n", - mp->cregs, mp->lregs, mp->lanai, mp->lanai3)); + DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n", + mp->cregs, mp->lregs, mp->lanai)); if (mp->eeprom.cpuvers >= CPUVERS_4_0) mp->shmem_base = 0xf000; @@ -1022,7 +1020,8 @@ DET(("Shared memory base is %04x, ", mp->shmem_base)); - mp->shmem = (struct myri_shmem *) &mp->lanai[mp->shmem_base]; + mp->shmem = (struct myri_shmem __iomem *) + (mp->lanai + (mp->shmem_base * 2)); DET(("shmem mapped at %p\n", mp->shmem)); mp->rqack = &mp->shmem->channel.recvqa; diff -Nru a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h --- a/drivers/net/myri_sbus.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/myri_sbus.h 2004-10-18 14:56:49 -07:00 @@ -270,22 +270,21 @@ * to obtain good cache hit rates. */ spinlock_t irq_lock; - struct myri_shmem *shmem; /* Shared data structures. */ - unsigned long cregs; /* Control register space. */ - struct recvq *rqack; /* Where we ack rx's. */ - struct recvq *rq; /* Where we put buffers. */ - struct sendq *sq; /* Where we stuff tx's. */ + struct myri_shmem __iomem *shmem; /* Shared data structures. */ + void __iomem *cregs; /* Control register space. */ + struct recvq __iomem *rqack; /* Where we ack rx's. */ + struct recvq __iomem *rq; /* Where we put buffers. */ + struct sendq __iomem *sq; /* Where we stuff tx's. */ struct net_device *dev; /* Linux/NET dev struct. */ int tx_old; /* To speed up tx cleaning. */ - unsigned long lregs; /* Quick ptr to LANAI regs. */ + void __iomem *lregs; /* Quick ptr to LANAI regs. */ struct sk_buff *rx_skbs[RX_RING_SIZE+1];/* RX skb's */ struct sk_buff *tx_skbs[TX_RING_SIZE]; /* TX skb's */ struct net_device_stats enet_stats; /* Interface stats. */ /* These are less frequently accessed. */ - unsigned long regs; /* MyriCOM register space. */ - unsigned short *lanai; /* View 2 of register space. */ - unsigned int *lanai3; /* View 3 of register space. */ + void __iomem *regs; /* MyriCOM register space. */ + void __iomem *lanai; /* View 2 of register space. */ unsigned int myri_bursts; /* SBUS bursts. */ struct myri_eeprom eeprom; /* Local copy of EEPROM. */ unsigned int reg_size; /* Size of register space. */ diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c --- a/drivers/net/natsemi.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/natsemi.c 2004-10-18 14:55:54 -07:00 @@ -719,7 +719,7 @@ }; static void move_int_phy(struct net_device *dev, int addr); -static int eeprom_read(long ioaddr, int location); +static int eeprom_read(void __iomem *ioaddr, int location); static int mdio_read(struct net_device *dev, int reg); static void mdio_write(struct net_device *dev, int reg, u16 data); static void init_phy_fixup(struct net_device *dev); @@ -750,6 +750,9 @@ static void netdev_rx(struct net_device *dev); static void netdev_tx_done(struct net_device *dev); static int natsemi_change_mtu(struct net_device *dev, int new_mtu); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void natsemi_poll_controller(struct net_device *dev); +#endif static void __set_rx_mode(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void __get_stats(struct net_device *dev); @@ -766,9 +769,15 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf); static int netdev_get_eeprom(struct net_device *dev, u8 *buf); +static inline void __iomem *ns_ioaddr(struct net_device *dev) +{ + return (void __iomem *) dev->base_addr; +} + static void move_int_phy(struct net_device *dev, int addr) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); int target = 31; /* @@ -785,8 +794,8 @@ target--; if (target == np->phy_addr_external) target--; - writew(target, dev->base_addr + PhyCtrl); - readw(dev->base_addr + PhyCtrl); + writew(target, ioaddr + PhyCtrl); + readw(ioaddr + PhyCtrl); udelay(1); } @@ -797,7 +806,8 @@ struct netdev_private *np; int i, option, irq, chip_idx = ent->driver_data; static int find_cnt = -1; - unsigned long ioaddr, iosize; + unsigned long iostart, iosize; + void __iomem *ioaddr; const int pcibar = 1; /* PCI base address register */ int prev_eedata; u32 tmp; @@ -824,7 +834,7 @@ } find_cnt++; - ioaddr = pci_resource_start(pdev, pcibar); + iostart = pci_resource_start(pdev, pcibar); iosize = pci_resource_len(pdev, pcibar); irq = pdev->irq; @@ -841,7 +851,7 @@ if (i) goto err_pci_request_regions; - ioaddr = (unsigned long) ioremap (ioaddr, iosize); + ioaddr = ioremap(iostart, iosize); if (!ioaddr) { i = -ENOMEM; goto err_ioremap; @@ -856,7 +866,7 @@ prev_eedata = eedata; } - dev->base_addr = ioaddr; + dev->base_addr = (unsigned long __force) ioaddr; dev->irq = irq; np = netdev_priv(dev); @@ -876,7 +886,7 @@ * The address would be used to access a phy over the mii bus, but * the internal phy is accessed through mapped registers. */ - if (readl(dev->base_addr + ChipConfig) & CfgExtPhy) + if (readl(ioaddr + ChipConfig) & CfgExtPhy) dev->if_port = PORT_MII; else dev->if_port = PORT_TP; @@ -920,6 +930,9 @@ dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &natsemi_poll_controller; +#endif if (mtu) dev->mtu = mtu; @@ -965,7 +978,7 @@ if (netif_msg_drv(np)) { printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr, + dev->name, natsemi_pci_info[chip_idx].name, iostart, pci_name(np->pci_dev)); for (i = 0; i < ETH_ALEN-1; i++) printk("%02x:", dev->dev_addr[i]); @@ -978,7 +991,7 @@ return 0; err_register_netdev: - iounmap ((void *) dev->base_addr); + iounmap(ioaddr); err_ioremap: pci_release_regions(pdev); @@ -1010,12 +1023,13 @@ EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), }; -static int eeprom_read(long addr, int location) +static int eeprom_read(void __iomem *addr, int location) { int i; int retval = 0; - long ee_addr = addr + EECtrl; + void __iomem *ee_addr = addr + EECtrl; int read_cmd = location | EE_ReadCmd; + writel(EE_Write0, ee_addr); /* Shift the read command bits out. */ @@ -1052,33 +1066,35 @@ /* clock transitions >= 20ns (25MHz) * One readl should be good to PCI @ 100MHz */ -#define mii_delay(dev) readl(dev->base_addr + EECtrl) +#define mii_delay(ioaddr) readl(ioaddr + EECtrl) static int mii_getbit (struct net_device *dev) { int data; + void __iomem *ioaddr = ns_ioaddr(dev); - writel(MII_ShiftClk, dev->base_addr + EECtrl); - data = readl(dev->base_addr + EECtrl); - writel(0, dev->base_addr + EECtrl); - mii_delay(dev); + writel(MII_ShiftClk, ioaddr + EECtrl); + data = readl(ioaddr + EECtrl); + writel(0, ioaddr + EECtrl); + mii_delay(ioaddr); return (data & MII_Data)? 1 : 0; } static void mii_send_bits (struct net_device *dev, u32 data, int len) { u32 i; + void __iomem *ioaddr = ns_ioaddr(dev); for (i = (1 << (len-1)); i; i >>= 1) { u32 mdio_val = MII_Write | ((data & i)? MII_Data : 0); - writel(mdio_val, dev->base_addr + EECtrl); - mii_delay(dev); - writel(mdio_val | MII_ShiftClk, dev->base_addr + EECtrl); - mii_delay(dev); + writel(mdio_val, ioaddr + EECtrl); + mii_delay(ioaddr); + writel(mdio_val | MII_ShiftClk, ioaddr + EECtrl); + mii_delay(ioaddr); } - writel(0, dev->base_addr + EECtrl); - mii_delay(dev); + writel(0, ioaddr + EECtrl); + mii_delay(ioaddr); } static int miiport_read(struct net_device *dev, int phy_id, int reg) @@ -1123,13 +1139,14 @@ static int mdio_read(struct net_device *dev, int reg) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); /* The 83815 series has two ports: * - an internal transceiver * - an external mii bus */ if (dev->if_port == PORT_TP) - return readw(dev->base_addr+BasicControl+(reg<<2)); + return readw(ioaddr+BasicControl+(reg<<2)); else return miiport_read(dev, np->phy_addr_external, reg); } @@ -1137,10 +1154,11 @@ static void mdio_write(struct net_device *dev, int reg, u16 data) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); /* The 83815 series has an internal transceiver; handle separately */ if (dev->if_port == PORT_TP) - writew(data, dev->base_addr+BasicControl+(reg<<2)); + writew(data, ioaddr+BasicControl+(reg<<2)); else miiport_write(dev, np->phy_addr_external, reg, data); } @@ -1148,7 +1166,7 @@ static void init_phy_fixup(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ns_ioaddr(dev); int i; u32 cfg; u16 tmp; @@ -1180,7 +1198,7 @@ */ } mdio_write(dev, MII_BMCR, tmp); - readl(dev->base_addr + ChipConfig); + readl(ioaddr + ChipConfig); udelay(1); /* find out what phy this is */ @@ -1202,7 +1220,7 @@ default: break; } - cfg = readl(dev->base_addr + ChipConfig); + cfg = readl(ioaddr + ChipConfig); if (cfg & CfgExtPhy) return; @@ -1260,9 +1278,10 @@ static int switch_port_external(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); u32 cfg; - cfg = readl(dev->base_addr + ChipConfig); + cfg = readl(ioaddr + ChipConfig); if (cfg & CfgExtPhy) return 0; @@ -1272,8 +1291,8 @@ } /* 1) switch back to external phy */ - writel(cfg | (CfgExtPhy | CfgPhyDis), dev->base_addr + ChipConfig); - readl(dev->base_addr + ChipConfig); + writel(cfg | (CfgExtPhy | CfgPhyDis), ioaddr + ChipConfig); + readl(ioaddr + ChipConfig); udelay(1); /* 2) reset the external phy: */ @@ -1292,11 +1311,12 @@ static int switch_port_internal(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); int i; u32 cfg; u16 bmcr; - cfg = readl(dev->base_addr + ChipConfig); + cfg = readl(ioaddr + ChipConfig); if (!(cfg &CfgExtPhy)) return 0; @@ -1306,17 +1326,17 @@ } /* 1) switch back to internal phy: */ cfg = cfg & ~(CfgExtPhy | CfgPhyDis); - writel(cfg, dev->base_addr + ChipConfig); - readl(dev->base_addr + ChipConfig); + writel(cfg, ioaddr + ChipConfig); + readl(ioaddr + ChipConfig); udelay(1); /* 2) reset the internal phy: */ - bmcr = readw(dev->base_addr+BasicControl+(MII_BMCR<<2)); - writel(bmcr | BMCR_RESET, dev->base_addr+BasicControl+(MII_BMCR<<2)); - readl(dev->base_addr + ChipConfig); + bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2)); + writel(bmcr | BMCR_RESET, ioaddr+BasicControl+(MII_BMCR<<2)); + readl(ioaddr + ChipConfig); udelay(10); for (i=0;ibase_addr+BasicControl+(MII_BMCR<<2)); + bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2)); if (!(bmcr & BMCR_RESET)) break; udelay(10); @@ -1392,6 +1412,7 @@ u16 pmatch[3]; u16 sopass[3]; struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); /* * Resetting the chip causes some registers to be lost. @@ -1402,26 +1423,26 @@ */ /* CFG */ - cfg = readl(dev->base_addr + ChipConfig) & CFG_RESET_SAVE; + cfg = readl(ioaddr + ChipConfig) & CFG_RESET_SAVE; /* WCSR */ - wcsr = readl(dev->base_addr + WOLCmd) & WCSR_RESET_SAVE; + wcsr = readl(ioaddr + WOLCmd) & WCSR_RESET_SAVE; /* RFCR */ - rfcr = readl(dev->base_addr + RxFilterAddr) & RFCR_RESET_SAVE; + rfcr = readl(ioaddr + RxFilterAddr) & RFCR_RESET_SAVE; /* PMATCH */ for (i = 0; i < 3; i++) { - writel(i*2, dev->base_addr + RxFilterAddr); - pmatch[i] = readw(dev->base_addr + RxFilterData); + writel(i*2, ioaddr + RxFilterAddr); + pmatch[i] = readw(ioaddr + RxFilterData); } /* SOPAS */ for (i = 0; i < 3; i++) { - writel(0xa+(i*2), dev->base_addr + RxFilterAddr); - sopass[i] = readw(dev->base_addr + RxFilterData); + writel(0xa+(i*2), ioaddr + RxFilterAddr); + sopass[i] = readw(ioaddr + RxFilterData); } /* now whack the chip */ - writel(ChipReset, dev->base_addr + ChipCmd); + writel(ChipReset, ioaddr + ChipCmd); for (i=0;ibase_addr + ChipCmd) & ChipReset)) + if (!(readl(ioaddr + ChipCmd) & ChipReset)) break; udelay(5); } @@ -1434,40 +1455,41 @@ } /* restore CFG */ - cfg |= readl(dev->base_addr + ChipConfig) & ~CFG_RESET_SAVE; + cfg |= readl(ioaddr + ChipConfig) & ~CFG_RESET_SAVE; /* turn on external phy if it was selected */ if (dev->if_port == PORT_TP) cfg &= ~(CfgExtPhy | CfgPhyDis); else cfg |= (CfgExtPhy | CfgPhyDis); - writel(cfg, dev->base_addr + ChipConfig); + writel(cfg, ioaddr + ChipConfig); /* restore WCSR */ - wcsr |= readl(dev->base_addr + WOLCmd) & ~WCSR_RESET_SAVE; - writel(wcsr, dev->base_addr + WOLCmd); + wcsr |= readl(ioaddr + WOLCmd) & ~WCSR_RESET_SAVE; + writel(wcsr, ioaddr + WOLCmd); /* read RFCR */ - rfcr |= readl(dev->base_addr + RxFilterAddr) & ~RFCR_RESET_SAVE; + rfcr |= readl(ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE; /* restore PMATCH */ for (i = 0; i < 3; i++) { - writel(i*2, dev->base_addr + RxFilterAddr); - writew(pmatch[i], dev->base_addr + RxFilterData); + writel(i*2, ioaddr + RxFilterAddr); + writew(pmatch[i], ioaddr + RxFilterData); } for (i = 0; i < 3; i++) { - writel(0xa+(i*2), dev->base_addr + RxFilterAddr); - writew(sopass[i], dev->base_addr + RxFilterData); + writel(0xa+(i*2), ioaddr + RxFilterAddr); + writew(sopass[i], ioaddr + RxFilterData); } /* restore RFCR */ - writel(rfcr, dev->base_addr + RxFilterAddr); + writel(rfcr, ioaddr + RxFilterAddr); } static void natsemi_reload_eeprom(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); int i; - writel(EepromReload, dev->base_addr + PCIBusCfg); + writel(EepromReload, ioaddr + PCIBusCfg); for (i=0;ibase_addr + PCIBusCfg) & EepromReload)) + if (!(readl(ioaddr + PCIBusCfg) & EepromReload)) break; } if (i==NATSEMI_HW_TIMEOUT) { @@ -1481,7 +1503,7 @@ static void natsemi_stop_rxtx(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); int i; @@ -1503,7 +1525,7 @@ static int netdev_open(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); int i; /* Reset the chip, just in case. */ @@ -1552,6 +1574,7 @@ static void do_cable_magic(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); if (dev->if_port != PORT_TP) return; @@ -1565,15 +1588,15 @@ * activity LED while idle. This process is based on instructions * from engineers at National. */ - if (readl(dev->base_addr + ChipConfig) & CfgSpeed100) { + if (readl(ioaddr + ChipConfig) & CfgSpeed100) { u16 data; - writew(1, dev->base_addr + PGSEL); + writew(1, ioaddr + PGSEL); /* * coefficient visibility should already be enabled via * DSPCFG | 0x1000 */ - data = readw(dev->base_addr + TSTDAT) & 0xff; + data = readw(ioaddr + TSTDAT) & 0xff; /* * the value must be negative, and within certain values * (these values all come from National) @@ -1582,13 +1605,13 @@ struct netdev_private *np = netdev_priv(dev); /* the bug has been triggered - fix the coefficient */ - writew(TSTDAT_FIXED, dev->base_addr + TSTDAT); + writew(TSTDAT_FIXED, ioaddr + TSTDAT); /* lock the value */ - data = readw(dev->base_addr + DSPCFG); + data = readw(ioaddr + DSPCFG); np->dspcfg = data | DSPCFG_LOCK; - writew(np->dspcfg, dev->base_addr + DSPCFG); + writew(np->dspcfg, ioaddr + DSPCFG); } - writew(0, dev->base_addr + PGSEL); + writew(0, ioaddr + PGSEL); } } @@ -1596,6 +1619,7 @@ { u16 data; struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); if (dev->if_port != PORT_TP) return; @@ -1603,18 +1627,18 @@ if (np->srr >= SRR_DP83816_A5) return; - writew(1, dev->base_addr + PGSEL); + writew(1, ioaddr + PGSEL); /* make sure the lock bit is clear */ - data = readw(dev->base_addr + DSPCFG); + data = readw(ioaddr + DSPCFG); np->dspcfg = data & ~DSPCFG_LOCK; - writew(np->dspcfg, dev->base_addr + DSPCFG); - writew(0, dev->base_addr + PGSEL); + writew(np->dspcfg, ioaddr + DSPCFG); + writew(0, ioaddr + PGSEL); } static void check_link(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); int duplex; u16 bmsr; @@ -1675,7 +1699,7 @@ static void init_registers(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); init_phy_fixup(dev); @@ -1754,6 +1778,7 @@ { struct net_device *dev = (struct net_device *)data; struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); int next_tick = 5*HZ; if (netif_msg_timer(np)) { @@ -1765,7 +1790,6 @@ } if (dev->if_port == PORT_TP) { - long ioaddr = dev->base_addr; u16 dspcfg; spin_lock_irq(&np->lock); @@ -1808,7 +1832,7 @@ refill_rx(dev); enable_irq(dev->irq); if (!np->oom) { - writel(RxOn, dev->base_addr + ChipCmd); + writel(RxOn, ioaddr + ChipCmd); } else { next_tick = 1; } @@ -1842,7 +1866,7 @@ static void tx_timeout(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); disable_irq(dev->irq); spin_lock_irq(&np->lock); @@ -2042,6 +2066,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); unsigned entry; /* Note: Ordering is important here, set the field with the @@ -2070,7 +2095,7 @@ netif_stop_queue(dev); } /* Wake the potentially-idle transmit channel. */ - writel(TxOn, dev->base_addr + ChipCmd); + writel(TxOn, ioaddr + ChipCmd); } else { dev_kfree_skb_irq(skb); np->stats.tx_dropped++; @@ -2135,7 +2160,7 @@ { struct net_device *dev = dev_instance; struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); int boguscnt = max_interrupt_work; unsigned int handled = 0; @@ -2197,6 +2222,7 @@ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); unsigned int buflen = np->rx_buf_sz; + void __iomem * ioaddr = ns_ioaddr(dev); /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ @@ -2278,13 +2304,13 @@ if (np->oom) mod_timer(&np->timer, jiffies + 1); else - writel(RxOn, dev->base_addr + ChipCmd); + writel(RxOn, ioaddr + ChipCmd); } static void netdev_error(struct net_device *dev, int intr_status) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); spin_lock(&np->lock); if (intr_status & LinkChange) { @@ -2343,7 +2369,7 @@ static void __get_stats(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); /* The chip only need report frame silently dropped. */ @@ -2364,10 +2390,19 @@ return &np->stats; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void natsemi_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + intr_handler(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + #define HASH_TABLE 0x200 static void __set_rx_mode(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); u8 mc_filter[64]; /* Multicast hash filter */ u32 rx_mode; @@ -2413,7 +2448,7 @@ /* synchronized against open : rtnl_lock() held by caller */ if (netif_running(dev)) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); disable_irq(dev->irq); spin_lock(&np->lock); @@ -2616,7 +2651,8 @@ static int netdev_set_wol(struct net_device *dev, u32 newval) { struct netdev_private *np = netdev_priv(dev); - u32 data = readl(dev->base_addr + WOLCmd) & ~WakeOptsSummary; + void __iomem * ioaddr = ns_ioaddr(dev); + u32 data = readl(ioaddr + WOLCmd) & ~WakeOptsSummary; /* translate to bitmasks this chip understands */ if (newval & WAKE_PHY) @@ -2637,7 +2673,7 @@ } } - writel(data, dev->base_addr + WOLCmd); + writel(data, ioaddr + WOLCmd); return 0; } @@ -2645,7 +2681,8 @@ static int netdev_get_wol(struct net_device *dev, u32 *supported, u32 *cur) { struct netdev_private *np = netdev_priv(dev); - u32 regval = readl(dev->base_addr + WOLCmd); + void __iomem * ioaddr = ns_ioaddr(dev); + u32 regval = readl(ioaddr + WOLCmd); *supported = (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | WAKE_MAGIC); @@ -2680,6 +2717,7 @@ static int netdev_set_sopass(struct net_device *dev, u8 *newval) { struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); u16 *sval = (u16 *)newval; u32 addr; @@ -2688,22 +2726,22 @@ } /* enable writing to these registers by disabling the RX filter */ - addr = readl(dev->base_addr + RxFilterAddr) & ~RFCRAddressMask; + addr = readl(ioaddr + RxFilterAddr) & ~RFCRAddressMask; addr &= ~RxFilterEnable; - writel(addr, dev->base_addr + RxFilterAddr); + writel(addr, ioaddr + RxFilterAddr); /* write the three words to (undocumented) RFCR vals 0xa, 0xc, 0xe */ - writel(addr | 0xa, dev->base_addr + RxFilterAddr); - writew(sval[0], dev->base_addr + RxFilterData); + writel(addr | 0xa, ioaddr + RxFilterAddr); + writew(sval[0], ioaddr + RxFilterData); - writel(addr | 0xc, dev->base_addr + RxFilterAddr); - writew(sval[1], dev->base_addr + RxFilterData); + writel(addr | 0xc, ioaddr + RxFilterAddr); + writew(sval[1], ioaddr + RxFilterData); - writel(addr | 0xe, dev->base_addr + RxFilterAddr); - writew(sval[2], dev->base_addr + RxFilterData); + writel(addr | 0xe, ioaddr + RxFilterAddr); + writew(sval[2], ioaddr + RxFilterData); /* re-enable the RX filter */ - writel(addr | RxFilterEnable, dev->base_addr + RxFilterAddr); + writel(addr | RxFilterEnable, ioaddr + RxFilterAddr); return 0; } @@ -2711,6 +2749,7 @@ static int netdev_get_sopass(struct net_device *dev, u8 *data) { struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); u16 *sval = (u16 *)data; u32 addr; @@ -2720,18 +2759,18 @@ } /* read the three words from (undocumented) RFCR vals 0xa, 0xc, 0xe */ - addr = readl(dev->base_addr + RxFilterAddr) & ~RFCRAddressMask; + addr = readl(ioaddr + RxFilterAddr) & ~RFCRAddressMask; - writel(addr | 0xa, dev->base_addr + RxFilterAddr); - sval[0] = readw(dev->base_addr + RxFilterData); + writel(addr | 0xa, ioaddr + RxFilterAddr); + sval[0] = readw(ioaddr + RxFilterData); - writel(addr | 0xc, dev->base_addr + RxFilterAddr); - sval[1] = readw(dev->base_addr + RxFilterData); + writel(addr | 0xc, ioaddr + RxFilterAddr); + sval[1] = readw(ioaddr + RxFilterData); - writel(addr | 0xe, dev->base_addr + RxFilterAddr); - sval[2] = readw(dev->base_addr + RxFilterData); + writel(addr | 0xe, ioaddr + RxFilterAddr); + sval[2] = readw(ioaddr + RxFilterData); - writel(addr, dev->base_addr + RxFilterAddr); + writel(addr, ioaddr + RxFilterAddr); return 0; } @@ -2894,10 +2933,11 @@ int j; u32 rfcr; u32 *rbuf = (u32 *)buf; + void __iomem * ioaddr = ns_ioaddr(dev); /* read non-mii page 0 of registers */ for (i = 0; i < NATSEMI_PG0_NREGS/2; i++) { - rbuf[i] = readl(dev->base_addr + i*4); + rbuf[i] = readl(ioaddr + i*4); } /* read current mii registers */ @@ -2905,20 +2945,20 @@ rbuf[i] = mdio_read(dev, i & 0x1f); /* read only the 'magic' registers from page 1 */ - writew(1, dev->base_addr + PGSEL); - rbuf[i++] = readw(dev->base_addr + PMDCSR); - rbuf[i++] = readw(dev->base_addr + TSTDAT); - rbuf[i++] = readw(dev->base_addr + DSPCFG); - rbuf[i++] = readw(dev->base_addr + SDCFG); - writew(0, dev->base_addr + PGSEL); + writew(1, ioaddr + PGSEL); + rbuf[i++] = readw(ioaddr + PMDCSR); + rbuf[i++] = readw(ioaddr + TSTDAT); + rbuf[i++] = readw(ioaddr + DSPCFG); + rbuf[i++] = readw(ioaddr + SDCFG); + writew(0, ioaddr + PGSEL); /* read RFCR indexed registers */ - rfcr = readl(dev->base_addr + RxFilterAddr); + rfcr = readl(ioaddr + RxFilterAddr); for (j = 0; j < NATSEMI_RFDR_NREGS; j++) { - writel(j*2, dev->base_addr + RxFilterAddr); - rbuf[i++] = readw(dev->base_addr + RxFilterData); + writel(j*2, ioaddr + RxFilterAddr); + rbuf[i++] = readw(ioaddr + RxFilterData); } - writel(rfcr, dev->base_addr + RxFilterAddr); + writel(rfcr, ioaddr + RxFilterAddr); /* the interrupt status is clear-on-read - see if we missed any */ if (rbuf[4] & rbuf[5]) { @@ -2943,10 +2983,11 @@ { int i; u16 *ebuf = (u16 *)buf; + void __iomem * ioaddr = ns_ioaddr(dev); /* eeprom_read reads 16 bits, and indexes by 16 bits */ for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) { - ebuf[i] = eeprom_read(dev->base_addr, i); + ebuf[i] = eeprom_read(ioaddr, i); /* The EEPROM itself stores data bit-swapped, but eeprom_read * reads it back "sanely". So we swap it back here in order to * present it to userland as it is stored. */ @@ -3016,7 +3057,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); if (netif_msg_wol(np)) @@ -3049,7 +3090,7 @@ static int netdev_close(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); if (netif_msg_ifdown(np)) @@ -3126,10 +3167,11 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + void __iomem * ioaddr = ns_ioaddr(dev); unregister_netdev (dev); pci_release_regions (pdev); - iounmap ((char *) dev->base_addr); + iounmap(ioaddr); free_netdev (dev); pci_set_drvdata(pdev, NULL); } @@ -3163,7 +3205,7 @@ { struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); rtnl_lock(); if (netif_running (dev)) { diff -Nru a/drivers/net/ne.c b/drivers/net/ne.c --- a/drivers/net/ne.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/ne.c 2004-10-18 14:56:29 -07:00 @@ -29,6 +29,7 @@ last in cleanup_modue() Richard Guenther : Added support for ISAPnP cards Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead. + Hayato Fujiwara : Add m32r support. */ @@ -128,6 +129,14 @@ #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ +#ifdef CONFIG_PLAT_MAPPI +# define DCR_VAL 0x4b +#elif CONFIG_PLAT_OAKS32R +# define DCR_VAL 0x48 +#else +# define DCR_VAL 0x49 +#endif + static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_probe_isapnp(struct net_device *dev); @@ -387,7 +396,7 @@ for (i = 0; i < 16; i++) SA_prom[i] = SA_prom[i+i]; /* We must set the 8390 for word mode. */ - outb_p(0x49, ioaddr + EN0_DCFG); + outb_p(DCR_VAL, ioaddr + EN0_DCFG); start_page = NESM_START_PG; stop_page = NESM_STOP_PG; } else { @@ -395,7 +404,12 @@ stop_page = NE1SM_STOP_PG; } +#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) + neX000 = ((SA_prom[14] == 0x57 && SA_prom[15] == 0x57) + || (SA_prom[14] == 0x42 && SA_prom[15] == 0x42)); +#else neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); +#endif ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00); @@ -476,10 +490,20 @@ dev->base_addr = ioaddr; +#ifdef CONFIG_PLAT_MAPPI + outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, + ioaddr + E8390_CMD); /* 0x61 */ + for (i = 0 ; i < ETHER_ADDR_LEN ; i++) { + dev->dev_addr[i] = SA_prom[i] + = inb_p(ioaddr + EN1_PHYS_SHIFT(i)); + printk(" %2.2x", SA_prom[i]); + } +#else for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; } +#endif printk("\n%s: %s found at %#x, using IRQ %d.\n", dev->name, name, ioaddr, dev->irq); @@ -487,7 +511,11 @@ ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; +#ifdef CONFIG_PLAT_OAKS32R + ei_status.word16 = 0; +#else ei_status.word16 = (wordlength == 2); +#endif ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE diff -Nru a/drivers/net/plip.c b/drivers/net/plip.c --- a/drivers/net/plip.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/plip.c 2004-10-18 14:57:04 -07:00 @@ -547,7 +547,7 @@ skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); - eth= skb->mac.ethernet; + eth = eth_hdr(skb); if(*eth->h_dest&1) { diff -Nru a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c --- a/drivers/net/ppp_async.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/ppp_async.c 2004-10-18 14:56:49 -07:00 @@ -122,6 +122,9 @@ * frees the memory that ppp_asynctty_receive is using. The best * way to fix this is to use a rwlock in the tty struct, but for now * we use a single global rwlock for all ttys in ppp line discipline. + * + * FIXME: this is no longer true. The _close path for the ldisc is + * now guaranteed to be sane. */ static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; @@ -144,7 +147,8 @@ } /* - * Called when a tty is put into PPP line discipline. + * Called when a tty is put into PPP line discipline. Called in process + * context. */ static int ppp_asynctty_open(struct tty_struct *tty) @@ -255,6 +259,11 @@ return -EAGAIN; } +/* + * Called in process context only. May be re-entered by multiple + * ioctl calling threads. + */ + static int ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) @@ -716,7 +725,8 @@ /* * Flush output from our internal buffers. - * Called for the TCFLSH ioctl. + * Called for the TCFLSH ioctl. Can be entered in parallel + * but this is covered by the xmit_lock. */ static void ppp_async_flush_output(struct asyncppp *ap) @@ -816,7 +826,9 @@ skb_trim(skb, 0); } -/* called when the tty driver has data for us. */ +/* Called when the tty driver has data for us. Runs parallel with the + other ldisc functions but will not be re-entered */ + static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf, char *flags, int count) diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c --- a/drivers/net/ppp_generic.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/ppp_generic.c 2004-10-18 14:57:04 -07:00 @@ -1595,6 +1595,7 @@ skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb->mac.raw = skb->data; + skb->input_dev = ppp->dev; netif_rx(skb); ppp->dev->last_rx = jiffies; } diff -Nru a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c --- a/drivers/net/ppp_synctty.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/ppp_synctty.c 2004-10-18 14:56:29 -07:00 @@ -175,6 +175,8 @@ * frees the memory that ppp_synctty_receive is using. The best * way to fix this is to use a rwlock in the tty struct, but for now * we use a single global rwlock for all ttys in ppp line discipline. + * + * FIXME: Fixed in tty_io nowdays. */ static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c --- a/drivers/net/pppoe.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/pppoe.c 2004-10-18 14:56:33 -07:00 @@ -391,7 +391,7 @@ ph = (struct pppoe_hdr *) skb->nh.raw; - po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); + po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); if (!po) goto drop; @@ -440,7 +440,7 @@ if (ph->code != PADT_CODE) goto abort; - po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); + po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); if (po) { struct sock *sk = po->sk; diff -Nru a/drivers/net/r8169.c b/drivers/net/r8169.c --- a/drivers/net/r8169.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/net/r8169.c 2004-10-18 14:56:32 -07:00 @@ -7,7 +7,7 @@ Feb 4 2002 - created initially by ShuChen . May 20 2002 - Add link status force-mode and TBI mode support. ========================================================================= - 1. The media can be forced in 5 modes. + 1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes. Command: 'insmod r8169 media = SET_MEDIA' Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex. @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,14 @@ #define dprintk(fmt, args...) do {} while (0) #endif /* RTL8169_DEBUG */ +#ifdef CONFIG_R8169_NAPI +#define rtl8169_rx_skb netif_receive_skb +#define rtl8169_rx_quota(count, quota) min(count, quota) +#else +#define rtl8169_rx_skb netif_rx +#define rtl8169_rx_quota(count, quota) count +#endif + /* media options */ #define MAX_UNITS 8 static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; @@ -90,15 +99,16 @@ #define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ +#define R8169_NAPI_WEIGHT 64 #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ -#define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ +#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ #define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) #define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL_MIN_IO_SIZE 0x80 #define RTL8169_TX_TIMEOUT (6*HZ) -#define RTL8169_PHY_TIMEOUT (HZ) +#define RTL8169_PHY_TIMEOUT (10*HZ) /* write/read MMIO register */ #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) @@ -146,6 +156,7 @@ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); static int rx_copybreak = 200; +static int use_dac; enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ @@ -194,7 +205,7 @@ SWInt = 0x0100, TxDescUnavail = 0x80, RxFIFOOver = 0x40, - RxUnderrun = 0x20, + LinkChg = 0x20, RxOverflow = 0x10, TxErr = 0x08, TxOK = 0x04, @@ -233,6 +244,14 @@ TxInterFrameGapShift = 24, TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + /* TBICSR p.28 */ + TBIReset = 0x80000000, + TBILoopback = 0x40000000, + TBINwEnable = 0x20000000, + TBINwRestart = 0x10000000, + TBILinkOk = 0x02000000, + TBINwComplete = 0x01000000, + /* CPlusCmd p.31 */ RxVlan = (1 << 6), RxChkSum = (1 << 5), @@ -306,10 +325,10 @@ }; struct rtl8169_private { - void *mmio_addr; /* memory map physical address */ + void *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device_stats stats; /* statistics of net device */ - spinlock_t lock; /* spin lock flag */ + spinlock_t lock; /* spin lock flag */ int chipset; int mac_version; int phy_version; @@ -317,21 +336,31 @@ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; u32 dirty_tx; - struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ - struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ + struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */ + struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */ dma_addr_t TxPhyAddr; dma_addr_t RxPhyAddr; struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ - struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ + struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Tx data buffers */ struct timer_list timer; - unsigned long phy_link_down_cnt; u16 cp_cmd; + u16 intr_mask; + int phy_auto_nego_reg; + int phy_1000_ctrl_reg; + + int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex); + void (*get_settings)(struct net_device *, struct ethtool_cmd *); + void (*phy_reset_enable)(void *); + unsigned int (*phy_reset_pending)(void *); + unsigned int (*link_ok)(void *); }; MODULE_AUTHOR("Realtek"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(use_dac, "i"); +MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); MODULE_LICENSE("GPL"); static int rtl8169_open(struct net_device *dev); @@ -344,9 +373,14 @@ static void rtl8169_set_rx_mode(struct net_device *dev); static void rtl8169_tx_timeout(struct net_device *dev); static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev); +#ifdef CONFIG_R8169_NAPI +static int rtl8169_poll(struct net_device *dev, int *budget); +#endif static const u16 rtl8169_intr_mask = - RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; + SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; +static const u16 rtl8169_napi_event = + RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr; static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); @@ -364,11 +398,9 @@ for (i = 2000; i > 0; i--) { // Check if the RTL8169 has completed writing to the specified MII register - if (!(RTL_R32(PHYAR) & 0x80000000)) { + if (!(RTL_R32(PHYAR) & 0x80000000)) break; - } else { - udelay(100); - } + udelay(100); } } @@ -390,18 +422,264 @@ return value; } +static unsigned int rtl8169_tbi_reset_pending(void *ioaddr) +{ + return RTL_R32(TBICSR) & TBIReset; +} + +static unsigned int rtl8169_xmii_reset_pending(void *ioaddr) +{ + return mdio_read(ioaddr, 0) & 0x8000; +} + +static unsigned int rtl8169_tbi_link_ok(void *ioaddr) +{ + return RTL_R32(TBICSR) & TBILinkOk; +} + +static unsigned int rtl8169_xmii_link_ok(void *ioaddr) +{ + return RTL_R8(PHYstatus) & LinkStatus; +} + +static void rtl8169_tbi_reset_enable(void *ioaddr) +{ + RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset); +} + +static void rtl8169_xmii_reset_enable(void *ioaddr) +{ + unsigned int val; + + val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff; + mdio_write(ioaddr, PHY_CTRL_REG, val); +} + +static void rtl8169_check_link_status(struct net_device *dev, + struct rtl8169_private *tp, void *ioaddr) +{ + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + if (tp->link_ok(ioaddr)) { + netif_carrier_on(dev); + printk(KERN_INFO PFX "%s: link up\n", dev->name); + } else + netif_carrier_off(dev); + spin_unlock_irqrestore(&tp->lock, flags); +} + +static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex) +{ + struct { + u16 speed; + u8 duplex; + u8 autoneg; + u8 media; + } link_settings[] = { + { SPEED_10, DUPLEX_HALF, AUTONEG_DISABLE, _10_Half }, + { SPEED_10, DUPLEX_FULL, AUTONEG_DISABLE, _10_Full }, + { SPEED_100, DUPLEX_HALF, AUTONEG_DISABLE, _100_Half }, + { SPEED_100, DUPLEX_FULL, AUTONEG_DISABLE, _100_Full }, + { SPEED_1000, DUPLEX_FULL, AUTONEG_DISABLE, _1000_Full }, + /* Make TBI happy */ + { SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff } + }, *p; + unsigned char option; + + option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff; + + if ((option != 0xff) && !idx) + printk(KERN_WARNING PFX "media option is deprecated.\n"); + + for (p = link_settings; p->media != 0xff; p++) { + if (p->media == option) + break; + } + *autoneg = p->autoneg; + *speed = p->speed; + *duplex = p->duplex; +} + static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); strcpy(info->driver, RTL8169_DRIVER_NAME); strcpy(info->version, RTL8169_VERSION ); strcpy(info->bus_info, pci_name(tp->pci_dev)); } +static int rtl8169_set_speed_tbi(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int ret = 0; + u32 reg; + + reg = RTL_R32(TBICSR); + if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && + (duplex == DUPLEX_FULL)) { + RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); + } else if (autoneg == AUTONEG_ENABLE) + RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); + else { + printk(KERN_WARNING PFX + "%s: incorrect speed setting refused in TBI mode\n", + dev->name); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int rtl8169_set_speed_xmii(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int auto_nego, giga_ctrl; + + auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); + auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG); + giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null); + + if (autoneg == AUTONEG_ENABLE) { + auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl |= PHY_Cap_1000_Full; + } else { + if (speed == SPEED_10) + auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full; + else if (speed == SPEED_100) + auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full; + else if (speed == SPEED_1000) + giga_ctrl |= PHY_Cap_1000_Full; + + if (duplex == DUPLEX_HALF) + auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); + } + + tp->phy_auto_nego_reg = auto_nego; + tp->phy_1000_ctrl_reg = giga_ctrl; + + mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego); + mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl); + mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego | + PHY_Restart_Auto_Nego); + return 0; +} + +static int rtl8169_set_speed(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + + ret = tp->set_speed(dev, autoneg, speed, duplex); + + if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) + mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT); + + return ret; +} + +static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&tp->lock, flags); + ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex); + spin_unlock_irqrestore(&tp->lock, flags); + + return ret; +} + +static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + u32 status; + + cmd->supported = + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + cmd->transceiver = XCVR_INTERNAL; + + status = RTL_R32(TBICSR); + cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0; + cmd->autoneg = !!(status & TBINwEnable); + + cmd->speed = SPEED_1000; + cmd->duplex = DUPLEX_FULL; /* Always set */ +} + +static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + u8 status; + + cmd->supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP; + + cmd->autoneg = 1; + cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; + + if (tp->phy_auto_nego_reg & PHY_Cap_10_Half) + cmd->advertising |= ADVERTISED_10baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_10_Full) + cmd->advertising |= ADVERTISED_10baseT_Full; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Half) + cmd->advertising |= ADVERTISED_100baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Full) + cmd->advertising |= ADVERTISED_100baseT_Full; + if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full) + cmd->advertising |= ADVERTISED_1000baseT_Full; + + status = RTL_R8(PHYstatus); + + if (status & _1000bpsF) + cmd->speed = SPEED_1000; + else if (status & _100bps) + cmd->speed = SPEED_100; + else if (status & _10bps) + cmd->speed = SPEED_10; + + cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? + DUPLEX_FULL : DUPLEX_HALF; +} + +static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + + tp->get_settings(dev, cmd); + + spin_unlock_irqrestore(&tp->lock, flags); + return 0; +} + + static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_settings = rtl8169_get_settings, + .set_settings = rtl8169_set_settings, }; static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum, @@ -500,7 +778,7 @@ static void rtl8169_hw_phy_config(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; struct { u16 regs[5]; /* Beware of bit-sign propagation */ @@ -566,61 +844,47 @@ mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0 } -static void rtl8169_hw_phy_reset(struct net_device *dev) -{ - struct rtl8169_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - int i, val; - - printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name); - - val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff; - mdio_write(ioaddr, 0, val); - - for (i = 50; i >= 0; i--) { - if (!(mdio_read(ioaddr, 0) & 0x8000)) - break; - udelay(100); /* Gross */ - } - - if (i < 0) { - printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n", - dev->name); - } -} - static void rtl8169_phy_timer(unsigned long __opaque) { struct net_device *dev = (struct net_device *)__opaque; - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; void *ioaddr = tp->mmio_addr; + unsigned long timeout = RTL8169_PHY_TIMEOUT; assert(tp->mac_version > RTL_GIGA_MAC_VER_B); assert(tp->phy_version < RTL_GIGA_PHY_VER_G); - if (RTL_R8(PHYstatus) & LinkStatus) - tp->phy_link_down_cnt = 0; - else { - tp->phy_link_down_cnt++; - if (tp->phy_link_down_cnt >= 12) { - int reg; - - // If link on 1000, perform phy reset. - reg = mdio_read(ioaddr, PHY_1000_CTRL_REG); - if (reg & PHY_Cap_1000_Full) - rtl8169_hw_phy_reset(dev); + if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) + return; - tp->phy_link_down_cnt = 0; - } + spin_lock_irq(&tp->lock); + + if (tp->phy_reset_pending(ioaddr)) { + /* + * A busy loop could burn quite a few cycles on nowadays CPU. + * Let's delay the execution of the timer for a few ticks. + */ + timeout = HZ/10; + goto out_mod_timer; } - mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT); + if (tp->link_ok(ioaddr)) + goto out_unlock; + + printk(KERN_WARNING PFX "%s: PHY reset until link up\n", dev->name); + + tp->phy_reset_enable(ioaddr); + +out_mod_timer: + mod_timer(timer, jiffies + timeout); +out_unlock: + spin_unlock_irq(&tp->lock); } static inline void rtl8169_delete_timer(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || @@ -628,21 +892,17 @@ return; del_timer_sync(timer); - - tp->phy_link_down_cnt = 0; } static inline void rtl8169_request_timer(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || (tp->phy_version >= RTL_GIGA_PHY_VER_G)) return; - tp->phy_link_down_cnt = 0; - init_timer(timer); timer->expires = jiffies + RTL8169_PHY_TIMEOUT; timer->data = (unsigned long)(dev); @@ -681,7 +941,7 @@ // enable device (incl. PCI PM wakeup and hotplug setup) rc = pci_enable_device(pdev); if (rc) { - printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name); + printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name); goto err_out; } @@ -693,7 +953,8 @@ pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } else { - printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n"); + printk(KERN_ERR PFX + "Cannot find PowerManagement capability, aborting.\n"); goto err_out_free_res; } @@ -718,14 +979,15 @@ rc = pci_request_regions(pdev, MODULENAME); if (rc) { - printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name); + printk(KERN_ERR PFX "%s: could not request regions.\n", + pdev->slot_name); goto err_out_disable; } tp->cp_cmd = PCIMulRW | RxChkSum; - if ((sizeof(dma_addr_t) > 32) && - !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) + if ((sizeof(dma_addr_t) > 4) && + !pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) tp->cp_cmd |= PCIDAC; else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); @@ -800,8 +1062,9 @@ void *ioaddr = NULL; static int board_idx = -1; static int printed_version = 0; + u8 autoneg, duplex; + u16 speed; int i, rc; - int option = -1, Cap10_100 = 0, Cap1000 = 0; assert(pdev != NULL); assert(ent != NULL); @@ -822,6 +1085,22 @@ assert(dev != NULL); assert(tp != NULL); + if (RTL_R8(PHYstatus) & TBI_Enable) { + tp->set_speed = rtl8169_set_speed_tbi; + tp->get_settings = rtl8169_gset_tbi; + tp->phy_reset_enable = rtl8169_tbi_reset_enable; + tp->phy_reset_pending = rtl8169_tbi_reset_pending; + tp->link_ok = rtl8169_tbi_link_ok; + + tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */ + } else { + tp->set_speed = rtl8169_set_speed_xmii; + tp->get_settings = rtl8169_gset_xmii; + tp->phy_reset_enable = rtl8169_xmii_reset_enable; + tp->phy_reset_pending = rtl8169_xmii_reset_pending; + tp->link_ok = rtl8169_xmii_link_ok; + } + // Get MAC address. FIXME: read EEPROM for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); @@ -836,9 +1115,12 @@ dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; -// dev->do_ioctl = mii_ioctl; - - tp = dev->priv; // private data // +#ifdef CONFIG_R8169_NAPI + dev->poll = rtl8169_poll; + dev->weight = R8169_NAPI_WEIGHT; + printk(KERN_INFO PFX "NAPI enabled\n"); +#endif + tp->intr_mask = 0xffff; tp->pci_dev = pdev; tp->mmio_addr = ioaddr; @@ -885,95 +1167,12 @@ mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 } - // if TBI is not endbled - if (!(RTL_R8(PHYstatus) & TBI_Enable)) { - int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); - - option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; - // Force RTL8169 in 10/100/1000 Full/Half mode. - if (option > 0) { - printk(KERN_INFO "%s: Force-mode Enabled.\n", - dev->name); - Cap10_100 = 0, Cap1000 = 0; - switch (option) { - case _10_Half: - Cap10_100 = PHY_Cap_10_Half_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _10_Full: - Cap10_100 = PHY_Cap_10_Full_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _100_Half: - Cap10_100 = PHY_Cap_100_Half_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _100_Full: - Cap10_100 = PHY_Cap_100_Full_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _1000_Full: - Cap10_100 = PHY_Cap_100_Full_Or_Less; - Cap1000 = PHY_Cap_1000_Full; - break; - default: - break; - } - mdio_write(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged - mdio_write(ioaddr, PHY_1000_CTRL_REG, Cap1000); - } else { - printk(KERN_INFO "%s: Auto-negotiation Enabled.\n", - dev->name); - - // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged - mdio_write(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_100_Full_Or_Less | (val & 0x1f)); - - // enable 1000 Full Mode - mdio_write(ioaddr, PHY_1000_CTRL_REG, - PHY_Cap_1000_Full); + rtl8169_link_option(board_idx, &autoneg, &speed, &duplex); - } - - // Enable auto-negotiation and restart auto-nigotiation - mdio_write(ioaddr, PHY_CTRL_REG, - PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego); - udelay(100); - - // wait for auto-negotiation process - for (i = 10000; i > 0; i--) { - //check if auto-negotiation complete - if (mdio_read(ioaddr, PHY_STAT_REG) & - PHY_Auto_Neco_Comp) { - udelay(100); - option = RTL_R8(PHYstatus); - if (option & _1000bpsF) { - printk(KERN_INFO - "%s: 1000Mbps Full-duplex operation.\n", - dev->name); - } else { - printk(KERN_INFO - "%s: %sMbps %s-duplex operation.\n", - dev->name, - (option & _100bps) ? "100" : - "10", - (option & FullDup) ? "Full" : - "Half"); - } - break; - } else { - udelay(100); - } - } // end for-loop to wait for auto-negotiation process - - } else { - udelay(100); - printk(KERN_INFO - "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n", - dev->name, - (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed"); - - } + rtl8169_set_speed(dev, autoneg, speed, duplex); + + if (RTL_R8(PHYstatus) & TBI_Enable) + printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); return 0; } @@ -982,7 +1181,7 @@ rtl8169_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); assert(dev != NULL); assert(tp != NULL); @@ -1001,7 +1200,7 @@ static int rtl8169_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -1042,7 +1241,7 @@ static int rtl8169_open(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; int retval; @@ -1074,6 +1273,8 @@ rtl8169_hw_start(dev); rtl8169_request_timer(dev); + + rtl8169_check_link_status(dev, tp, tp->mmio_addr); out: return retval; @@ -1091,7 +1292,7 @@ static void rtl8169_hw_start(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u32 i; @@ -1102,8 +1303,7 @@ for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; - else - udelay(10); + udelay(10); } RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -1114,8 +1314,8 @@ RTL_W16(RxMaxSize, RxPacketMaxSize); // Set Rx Config register - i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset]. - RxConfigMask); + i = rtl8169_rx_config | + (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, i); /* Set DMA burst size and Interframe Gap Time */ @@ -1126,7 +1326,8 @@ RTL_W16(CPlusCmd, tp->cp_cmd); if (tp->mac_version == RTL_GIGA_MAC_VER_D) { - dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n"); + dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. " + "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14) | PCIMulRW; RTL_W16(CPlusCmd, tp->cp_cmd); } @@ -1151,7 +1352,6 @@ RTL_W16(IntrMask, rtl8169_intr_mask); netif_start_queue(dev); - } static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) @@ -1248,7 +1448,7 @@ static int rtl8169_init_ring(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); tp->cur_rx = tp->dirty_rx = 0; tp->cur_tx = tp->dirty_tx = 0; @@ -1302,10 +1502,11 @@ static void rtl8169_tx_timeout(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u8 tmp8; + printk(KERN_INFO "%s: TX Timeout\n", dev->name); /* disable Tx, if not already */ tmp8 = RTL_R8(ChipCmd); if (tmp8 & CmdTxEnb) @@ -1328,9 +1529,9 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; - int entry = tp->cur_tx % NUM_TX_DESC; + unsigned int entry = tp->cur_tx % NUM_TX_DESC; u32 len = skb->len; if (unlikely(skb->len < ETH_ZLEN)) { @@ -1340,10 +1541,9 @@ len = ETH_ZLEN; } - spin_lock_irq(&tp->lock); - if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { dma_addr_t mapping; + u32 status; mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE); @@ -1351,24 +1551,30 @@ tp->Tx_skbuff[entry] = skb; tp->TxDescArray[entry].addr = cpu_to_le64(mapping); - tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit | - LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC))); + /* anti gcc 2.95.3 bugware */ + status = OWNbit | FSbit | LSbit | len | + (EORbit * !((entry + 1) % NUM_TX_DESC)); + tp->TxDescArray[entry].status = cpu_to_le32(status); RTL_W8(TxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->cur_tx++; + smp_wmb(); } else goto err_drop; - if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) { + u32 dirty = tp->dirty_tx; + netif_stop_queue(dev); + smp_rmb(); + if (dirty != tp->dirty_tx) + netif_wake_queue(dev); } -out: - spin_unlock_irq(&tp->lock); +out: return 0; err_drop: @@ -1382,17 +1588,18 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - unsigned long dirty_tx, tx_left; + unsigned int dirty_tx, tx_left; assert(dev != NULL); assert(tp != NULL); assert(ioaddr != NULL); dirty_tx = tp->dirty_tx; + smp_rmb(); tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { - int entry = dirty_tx % NUM_TX_DESC; + unsigned int entry = dirty_tx % NUM_TX_DESC; struct sk_buff *skb = tp->Tx_skbuff[entry]; u32 status; @@ -1415,6 +1622,7 @@ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; + smp_wmb(); if (netif_queue_stopped(dev)) netif_wake_queue(dev); } @@ -1442,11 +1650,11 @@ return ret; } -static void +static int rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - unsigned long cur_rx, rx_left; + unsigned int cur_rx, rx_left, count; int delta; assert(dev != NULL); @@ -1455,9 +1663,10 @@ cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; + rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota); while (rx_left > 0) { - int entry = cur_rx % NUM_RX_DESC; + unsigned int entry = cur_rx % NUM_RX_DESC; u32 status; rmb(); @@ -1494,7 +1703,7 @@ skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + rtl8169_rx_skb(skb); dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; @@ -1505,13 +1714,15 @@ rx_left--; } + count = cur_rx - tp->cur_rx; tp->cur_rx = cur_rx; delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); - if (delta > 0) - tp->dirty_rx += delta; - else if (delta < 0) + if (delta < 0) { printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + delta = 0; + } + tp->dirty_rx += delta; /* * FIXME: until there is periodic timer to try and refill the ring, @@ -1522,6 +1733,8 @@ */ if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); + + return count; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -1529,7 +1742,7 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; int status = 0; @@ -1543,26 +1756,46 @@ break; handled = 1; -/* - if (status & RxUnderrun) - link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; -*/ + + status &= tp->intr_mask; RTL_W16(IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); if (!(status & rtl8169_intr_mask)) break; + if (unlikely(status & SYSErr)) { + printk(KERN_ERR PFX "%s: PCI error (status: 0x%04x)." + " Device disabled.\n", dev->name, status); + RTL_W8(ChipCmd, 0x00); + RTL_W16(IntrMask, 0x0000); + RTL_R16(IntrMask); + break; + } + + if (status & LinkChg) + rtl8169_check_link_status(dev, tp, ioaddr); + +#ifdef CONFIG_R8169_NAPI + RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event); + tp->intr_mask = ~rtl8169_napi_event; + + if (likely(netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + else { + printk(KERN_INFO "%s: interrupt %x taken in poll\n", + dev->name, status); + } + break; +#else // Rx interrupt - if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) { + if (status & (RxOK | RxOverflow | RxFIFOOver)) { rtl8169_rx_interrupt(dev, tp, ioaddr); } // Tx interrupt - if (status & (TxOK | TxErr)) { - spin_lock(&tp->lock); + if (status & (TxOK | TxErr)) rtl8169_tx_interrupt(dev, tp, ioaddr); - spin_unlock(&tp->lock); - } +#endif boguscnt--; } while (boguscnt > 0); @@ -1576,10 +1809,40 @@ return IRQ_RETVAL(handled); } +#ifdef CONFIG_R8169_NAPI +static int rtl8169_poll(struct net_device *dev, int *budget) +{ + unsigned int work_done, work_to_do = min(*budget, dev->quota); + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + + work_done = rtl8169_rx_interrupt(dev, tp, ioaddr); + rtl8169_tx_interrupt(dev, tp, ioaddr); + + *budget -= work_done; + dev->quota -= work_done; + + if ((work_done < work_to_do) || !netif_running(dev)) { + netif_rx_complete(dev); + tp->intr_mask = 0xffff; + /* + * 20040426: the barrier is not strictly required but the + * behavior of the irq handler could be less predictable + * without it. Btw, the lack of flush for the posted pci + * write is safe - FR + */ + smp_wmb(); + RTL_W16(IntrMask, rtl8169_intr_mask); + } + + return (work_done >= work_to_do); +} +#endif + static int rtl8169_close(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; @@ -1621,7 +1884,7 @@ static void rtl8169_set_rx_mode(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ @@ -1655,10 +1918,8 @@ spin_lock_irqsave(&tp->lock, flags); - tmp = - rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) & - rtl_chip_info[tp->chipset]. - RxConfigMask); + tmp = rtl8169_rx_config | rx_mode | + (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, tmp); RTL_W32(MAR0 + 0, mc_filter[0]); @@ -1675,7 +1936,7 @@ */ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; diff -Nru a/drivers/net/rrunner.c b/drivers/net/rrunner.c --- a/drivers/net/rrunner.c 2004-10-18 14:56:20 -07:00 +++ b/drivers/net/rrunner.c 2004-10-18 14:56:20 -07:00 @@ -1139,6 +1139,49 @@ return IRQ_HANDLED; } +static inline void rr_raz_tx(struct rr_private *rrpriv, + struct net_device *dev) +{ + int i; + + for (i = 0; i < TX_RING_ENTRIES; i++) { + struct sk_buff *skb = rrpriv->tx_skbuff[i]; + + if (skb) { + struct tx_desc *desc = &(rrpriv->tx_ring[i]); + + pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, + skb->len, PCI_DMA_TODEVICE); + desc->size = 0; + set_rraddr(&desc->addr, 0); + dev_kfree_skb(skb); + rrpriv->tx_skbuff[i] = NULL; + } + } +} + + +static inline void rr_raz_rx(struct rr_private *rrpriv, + struct net_device *dev) +{ + int i; + + for (i = 0; i < RX_RING_ENTRIES; i++) { + struct sk_buff *skb = rrpriv->rx_skbuff[i]; + + if (skb) { + struct rx_desc *desc = &(rrpriv->rx_ring[i]); + + pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, + dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); + desc->size = 0; + set_rraddr(&desc->addr, 0); + dev_kfree_skb(skb); + rrpriv->rx_skbuff[i] = NULL; + } + } +} + static void rr_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; @@ -1253,49 +1296,6 @@ return ecode; } - -static inline void rr_raz_tx(struct rr_private *rrpriv, - struct net_device *dev) -{ - int i; - - for (i = 0; i < TX_RING_ENTRIES; i++) { - struct sk_buff *skb = rrpriv->tx_skbuff[i]; - - if (skb) { - struct tx_desc *desc = &(rrpriv->tx_ring[i]); - - pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, - skb->len, PCI_DMA_TODEVICE); - desc->size = 0; - set_rraddr(&desc->addr, 0); - dev_kfree_skb(skb); - rrpriv->tx_skbuff[i] = NULL; - } - } -} - - -static inline void rr_raz_rx(struct rr_private *rrpriv, - struct net_device *dev) -{ - int i; - - for (i = 0; i < RX_RING_ENTRIES; i++) { - struct sk_buff *skb = rrpriv->rx_skbuff[i]; - - if (skb) { - struct rx_desc *desc = &(rrpriv->rx_ring[i]); - - pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, - dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); - desc->size = 0; - set_rraddr(&desc->addr, 0); - dev_kfree_skb(skb); - rrpriv->rx_skbuff[i] = NULL; - } - } -} static void rr_dump(struct net_device *dev) { diff -Nru a/drivers/net/s2io.c b/drivers/net/s2io.c --- a/drivers/net/s2io.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/s2io.c 2004-10-18 14:56:33 -07:00 @@ -235,10 +235,10 @@ MODULE_DEVICE_TABLE(pci, s2io_tbl); static struct pci_driver s2io_driver = { - name:"S2IO", - id_table:s2io_tbl, - probe:s2io_init_nic, - remove:__devexit_p(s2io_rem_nic), + .name = "S2IO", + .id_table = s2io_tbl, + .probe = s2io_init_nic, + .remove = __devexit_p(s2io_rem_nic), }; /* diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c --- a/drivers/net/sis900.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/sis900.c 2004-10-18 14:56:29 -07:00 @@ -124,6 +124,7 @@ { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME}, { "ICS LAN PHY", 0x0015, 0xF440, LAN }, { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, + { "NS 83847 PHY", 0x2000, 0x5C30, MIX }, { "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN }, { "VIA 6103 PHY", 0x0101, 0x8f20, LAN }, {NULL,}, diff -Nru a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h --- a/drivers/net/sk98lin/h/skdrv2nd.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/sk98lin/h/skdrv2nd.h 2004-10-18 14:57:04 -07:00 @@ -53,60 +53,6 @@ #include "h/skrlmt.h" #include "h/skgedrv.h" -#define SK_PCI_ISCOMPLIANT(result, pdev) { \ - result = SK_FALSE; /* default */ \ - /* 3Com (0x10b7) */ \ - if (pdev->vendor == 0x10b7) { \ - /* Gigabit Ethernet Adapter (0x1700) */ \ - if ((pdev->device == 0x1700) || \ - (pdev->device == 0x80eb)) { \ - result = SK_TRUE; \ - } \ - /* SysKonnect (0x1148) */ \ - } else if (pdev->vendor == 0x1148) { \ - /* SK-98xx Gigabit Ethernet Server Adapter (0x4300) */ \ - /* SK-98xx V2.0 Gigabit Ethernet Adapter (0x4320) */ \ - if ((pdev->device == 0x4300) || \ - (pdev->device == 0x4320)) { \ - result = SK_TRUE; \ - } \ - /* D-Link (0x1186) */ \ - } else if (pdev->vendor == 0x1186) { \ - /* Gigabit Ethernet Adapter (0x4c00) */ \ - if ((pdev->device == 0x4c00)) { \ - result = SK_TRUE; \ - } \ - /* Marvell (0x11ab) */ \ - } else if (pdev->vendor == 0x11ab) { \ - /* Gigabit Ethernet Adapter (0x4320) */ \ - /* Gigabit Ethernet Adapter (0x4360) */ \ - /* Gigabit Ethernet Adapter (0x4361) */ \ - /* Belkin (0x5005) */ \ - if ((pdev->device == 0x4320) || \ - (pdev->device == 0x4360) || \ - (pdev->device == 0x4361) || \ - (pdev->device == 0x5005)) { \ - result = SK_TRUE; \ - } \ - /* CNet (0x1371) */ \ - } else if (pdev->vendor == 0x1371) { \ - /* GigaCard Network Adapter (0x434e) */ \ - if ((pdev->device == 0x434e)) { \ - result = SK_TRUE; \ - } \ - /* Linksys (0x1737) */ \ - } else if (pdev->vendor == 0x1737) { \ - /* Gigabit Network Adapter (0x1032) */ \ - /* Gigabit Network Adapter (0x1064) */ \ - if ((pdev->device == 0x1032) || \ - (pdev->device == 0x1064)) { \ - result = SK_TRUE; \ - } \ - } else { \ - result = SK_FALSE; \ - } \ -} - extern SK_MBUF *SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned); extern void SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*); diff -Nru a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c --- a/drivers/net/sk98lin/skaddr.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/sk98lin/skaddr.c 2004-10-18 14:56:33 -07:00 @@ -892,7 +892,7 @@ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ { - int ReturnCode; + int ReturnCode = 0; #if (!defined(SK_SLIM) || defined(DEBUG)) if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); @@ -1424,7 +1424,7 @@ SK_U32 PortNumber, /* port whose promiscuous mode changes */ int NewPromMode) /* new promiscuous mode */ { - int ReturnCode; + int ReturnCode = 0; #if (!defined(SK_SLIM) || defined(DEBUG)) if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); diff -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c --- a/drivers/net/sk98lin/skge.c 2004-10-18 14:56:11 -07:00 +++ b/drivers/net/sk98lin/skge.c 2004-10-18 14:56:11 -07:00 @@ -110,10 +110,7 @@ #include #include - -#ifdef CONFIG_PROC_FS #include -#endif #include "h/skdrv1st.h" #include "h/skdrv2nd.h" @@ -239,7 +236,7 @@ #ifdef CONFIG_PROC_FS static const char SK_Root_Dir_entry[] = "sk98lin"; -static struct proc_dir_entry *pSkRootDir = NULL; +static struct proc_dir_entry *pSkRootDir; extern struct file_operations sk_proc_fops; #endif @@ -255,303 +252,13 @@ #endif /* global variables *********************************************************/ -static const char *BootString = BOOT_STRING; struct SK_NET_DEVICE *SkGeRootDev = NULL; -static int probed __initdata = 0; static SK_BOOL DoPrintInterfaceChange = SK_TRUE; /* local variables **********************************************************/ static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *pSkRootDir; -#endif - - - -/***************************************************************************** - * - * skge_probe - find all SK-98xx adapters - * - * Description: - * This function scans the PCI bus for SK-98xx adapters. Resources for - * each adapter are allocated and the adapter is brought into Init 1 - * state. - * - * Returns: - * 0, if everything is ok - * !=0, on error - */ -static int __init skge_probe (void) -{ - int boards_found = 0; - int vendor_flag = SK_FALSE; - SK_AC *pAC; - DEV_NET *pNet = NULL; - struct pci_dev *pdev = NULL; - struct SK_NET_DEVICE *dev = NULL; - SK_BOOL DeviceFound = SK_FALSE; - SK_BOOL BootStringCount = SK_FALSE; - int retval; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *pProcFile; -#endif - - if (probed) - return -ENODEV; - probed++; - - - while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { - - if (pci_enable_device(pdev)) { - continue; - } - dev = NULL; - pNet = NULL; - - /* Don't handle Yukon2 cards at the moment */ - /* 12-feb-2004 ---- mlindner@syskonnect.de */ - if (pdev->vendor == 0x11ab) { - if ( (pdev->device == 0x4360) || (pdev->device == 0x4361) ) - continue; - } - - SK_PCI_ISCOMPLIANT(vendor_flag, pdev); - if (!vendor_flag) - continue; - - /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && - pci_set_dma_mask(pdev, (u64) 0xffffffff)) - continue; - - - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { - printk(KERN_ERR "Unable to allocate etherdev " - "structure!\n"); - break; - } - - pNet = dev->priv; - pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); - if (pNet->pAC == NULL){ - free_netdev(dev); - printk(KERN_ERR "Unable to allocate adapter " - "structure!\n"); - break; - } - - /* Print message */ - if (!BootStringCount) { - /* set display flag to TRUE so that */ - /* we only display this string ONCE */ - BootStringCount = SK_TRUE; - printk("%s\n", BootString); - } - - memset(pNet->pAC, 0, sizeof(SK_AC)); - pAC = pNet->pAC; - pAC->PciDev = pdev; - pAC->PciDevId = pdev->device; - pAC->dev[0] = dev; - pAC->dev[1] = dev; - sprintf(pAC->Name, "SysKonnect SK-98xx"); - pAC->CheckQueue = SK_FALSE; - - pNet->Mtu = 1500; - pNet->Up = 0; - dev->irq = pdev->irq; - retval = SkGeInitPCI(pAC); - if (retval) { - printk("SKGE: PCI setup failed: %i\n", retval); - free_netdev(dev); - continue; - } - - SET_MODULE_OWNER(dev); - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; - dev->last_stats = &SkGeStats; - dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; - SET_NETDEV_DEV(dev, &pdev->dev); - -#ifdef SK_ZEROCOPY -#ifdef USE_SK_TX_CHECKSUM - - if (pAC->ChipsetType) { - /* Use only if yukon hardware */ - /* SK and ZEROCOPY - fly baby... */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } -#endif -#endif - - pAC->Index = boards_found; - - if (SkGeBoardInit(dev, pAC)) { - free_netdev(dev); - continue; - } - - /* Register net device */ - if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); - FreeResources(dev); - free_netdev(dev); - continue; - } - - /* Print adapter specific string from vpd */ - ProductStr(pAC); - printk("%s: %s\n", dev->name, pAC->DeviceStr); - - /* Print configuration settings */ - printk(" PrefPort:%c RlmtMode:%s\n", - 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, - (pAC->RlmtMode==0) ? "Check Link State" : - ((pAC->RlmtMode==1) ? "Check Link State" : - ((pAC->RlmtMode==3) ? "Check Local Port" : - ((pAC->RlmtMode==7) ? "Check Segmentation" : - ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); - - SkGeYellowLED(pAC, pAC->IoBase, 1); - - - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); - - /* First adapter... Create proc and print message */ -#ifdef CONFIG_PROC_FS - if (!DeviceFound) { - DeviceFound = SK_TRUE; - SK_MEMCPY(&SK_Root_Dir_entry, BootString, - sizeof(SK_Root_Dir_entry) - 1); - - /*Create proc (directory)*/ - if(!pSkRootDir) { - pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); - if (!pSkRootDir) { - printk(KERN_WARNING "%s: Unable to create /proc/net/%s", - dev->name, SK_Root_Dir_entry); - } else { - pSkRootDir->owner = THIS_MODULE; - } - } - } - - /* Create proc file */ - if (pSkRootDir && - (pProcFile = create_proc_entry(dev->name, S_IRUGO, - pSkRootDir))) { - pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; - } - -#endif - - pNet->PortNr = 0; - pNet->NetNr = 0; - - boards_found++; - - /* More then one port found */ - if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { - printk(KERN_ERR "Unable to allocate etherdev " - "structure!\n"); - break; - } - - pAC->dev[1] = dev; - pNet = dev->priv; - pNet->PortNr = 1; - pNet->NetNr = 1; - pNet->pAC = pAC; - pNet->Mtu = 1500; - pNet->Up = 0; - - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; - dev->last_stats = &SkGeStats; - dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; - -#ifdef SK_ZEROCOPY -#ifdef USE_SK_TX_CHECKSUM - if (pAC->ChipsetType) { - /* SG and ZEROCOPY - fly baby... */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } -#endif -#endif - - if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); - free_netdev(dev); - pAC->dev[1] = pAC->dev[0]; - } else { -#ifdef CONFIG_PROC_FS - if (pSkRootDir - && (pProcFile = create_proc_entry(dev->name, - S_IRUGO, pSkRootDir))) { - pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; - } -#endif - - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); - - printk("%s: %s\n", dev->name, pAC->DeviceStr); - printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); - } - } - - /* Save the hardware revision */ - pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + - (pAC->GIni.GIPciHwRev & 0x0F); - - /* Set driver globals */ - pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; - pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; - - SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); - SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), - sizeof(SK_PNMI_STRUCT_DATA)); - - /* - * This is bollocks, but we need to tell the net-init - * code that it shall go for the next device. - */ -#ifndef MODULE - dev->base_addr = 0; -#endif - } - - /* - * If we're at this point we're going through skge_probe() for - * the first time. Return success (0) if we've initialized 1 - * or more boards. Otherwise, return failure (-ENODEV). - */ - - return boards_found; -} /* skge_probe */ - - /***************************************************************************** * * SkGeInitPCI - Init the PCI resources @@ -666,9 +373,6 @@ MODULE_PARM(ConType, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); MODULE_PARM(PrefPort, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); MODULE_PARM(RlmtMode, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); -/* not used, just there because every driver should have them: */ -MODULE_PARM(options, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); -MODULE_PARM(debug, "i"); /* used for interrupt moderation */ MODULE_PARM(IntsPerSec, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); MODULE_PARM(Moderation, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); @@ -755,123 +459,12 @@ static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", }; #endif -static int debug = 0; /* not used */ -static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */ - static int IntsPerSec[SK_MAX_CARD_PARAM]; static char *Moderation[SK_MAX_CARD_PARAM]; static char *ModerationMask[SK_MAX_CARD_PARAM]; static char *AutoSizing[SK_MAX_CARD_PARAM]; static char *Stats[SK_MAX_CARD_PARAM]; - -/***************************************************************************** - * - * skge_init_module - module initialization function - * - * Description: - * Very simple, only call skge_probe and return approriate result. - * - * Returns: - * 0, if everything is ok - * !=0, on error - */ -static int __init skge_init_module(void) -{ - int cards; - SkGeRootDev = NULL; - - /* just to avoid warnings ... */ - debug = 0; - options[0] = 0; - - cards = skge_probe(); - if (cards == 0) { - printk("sk98lin: No adapter found.\n"); - } - return cards ? 0 : -ENODEV; -} /* skge_init_module */ - - -/***************************************************************************** - * - * skge_cleanup_module - module unload function - * - * Description: - * Disable adapter if it is still running, free resources, - * free device struct. - * - * Returns: N/A - */ -static void __exit skge_cleanup_module(void) -{ -DEV_NET *pNet; -SK_AC *pAC; -struct SK_NET_DEVICE *next; -unsigned long Flags; -SK_EVPARA EvPara; - - while (SkGeRootDev) { - pNet = (DEV_NET*) SkGeRootDev->priv; - pAC = pNet->pAC; - next = pAC->Next; - - netif_stop_queue(SkGeRootDev); - SkGeYellowLED(pAC, pAC->IoBase, 0); - - if(pAC->BoardLevel == SK_INIT_RUN) { - /* board is still alive */ - spin_lock_irqsave(&pAC->SlowPathLock, Flags); - EvPara.Para32[0] = 0; - EvPara.Para32[1] = -1; - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); - EvPara.Para32[0] = 1; - EvPara.Para32[1] = -1; - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); - SkEventDispatcher(pAC, pAC->IoBase); - /* disable interrupts */ - SK_OUT32(pAC->IoBase, B0_IMSK, 0); - SkGeDeInit(pAC, pAC->IoBase); - spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - pAC->BoardLevel = SK_INIT_DATA; - /* We do NOT check here, if IRQ was pending, of course*/ - } - - if(pAC->BoardLevel == SK_INIT_IO) { - /* board is still alive */ - SkGeDeInit(pAC, pAC->IoBase); - pAC->BoardLevel = SK_INIT_DATA; - } - - if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ - unregister_netdev(pAC->dev[1]); - free_netdev(pAC->dev[1]); - } - - FreeResources(SkGeRootDev); - - SkGeRootDev->get_stats = NULL; - /* - * otherwise unregister_netdev calls get_stats with - * invalid IO ... :-( - */ - unregister_netdev(SkGeRootDev); - free_netdev(SkGeRootDev); - kfree(pAC); - SkGeRootDev = next; - } - -#ifdef CONFIG_PROC_FS - /* clear proc-dir */ - remove_proc_entry(pSkRootDir->name, proc_net); -#endif - -} /* skge_cleanup_module */ - -module_init(skge_init_module); -module_exit(skge_cleanup_module); - - /***************************************************************************** * * SkGeBoardInit - do level 0 and 1 initialization @@ -3094,8 +2687,7 @@ SkEventDispatcher(pAC, pAC->IoBase); for (i=0; iGIni.GIMacsFound; i++) { - spin_lock_irqsave( - &pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); netif_stop_queue(pAC->dev[i]); } @@ -4774,12 +4366,10 @@ spin_lock_irqsave( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); - spin_lock_irqsave( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST); SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST); - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -4792,8 +4382,7 @@ spin_lock_irqsave( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); - spin_lock_irqsave( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); pAC->ActivePort = ToPort; #if 0 SetQueueSizes(pAC); @@ -4808,8 +4397,7 @@ pAC, pAC->ActivePort, DualNet)) { - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -4835,8 +4423,7 @@ SkGePollTxD(pAC, IoC, ToPort, SK_TRUE); ClearAndStartRx(pAC, FromPort); ClearAndStartRx(pAC, ToPort); - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -5311,8 +4898,317 @@ #endif -/******************************************************************************* - * - * End of file - * - ******************************************************************************/ +static int __devinit skge_probe_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + SK_AC *pAC; + DEV_NET *pNet = NULL; + struct net_device *dev = NULL; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pProcFile; +#endif + static int boards_found = 0; + int error = -ENODEV; + + if (pci_enable_device(pdev)) + goto out; + + /* Configure DMA attributes. */ + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && + pci_set_dma_mask(pdev, (u64) 0xffffffff)) + goto out_disable_device; + + + if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { + printk(KERN_ERR "Unable to allocate etherdev " + "structure!\n"); + goto out_disable_device; + } + + pNet = dev->priv; + pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); + if (!pNet->pAC) { + printk(KERN_ERR "Unable to allocate adapter " + "structure!\n"); + goto out_free_netdev; + } + + memset(pNet->pAC, 0, sizeof(SK_AC)); + pAC = pNet->pAC; + pAC->PciDev = pdev; + pAC->PciDevId = pdev->device; + pAC->dev[0] = dev; + pAC->dev[1] = dev; + sprintf(pAC->Name, "SysKonnect SK-98xx"); + pAC->CheckQueue = SK_FALSE; + + pNet->Mtu = 1500; + pNet->Up = 0; + dev->irq = pdev->irq; + error = SkGeInitPCI(pAC); + if (error) { + printk("SKGE: PCI setup failed: %i\n", error); + goto out_free_netdev; + } + + SET_MODULE_OWNER(dev); + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; + SET_NETDEV_DEV(dev, &pdev->dev); + +#ifdef SK_ZEROCOPY +#ifdef USE_SK_TX_CHECKSUM + if (pAC->ChipsetType) { + /* Use only if yukon hardware */ + /* SK and ZEROCOPY - fly baby... */ + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + } +#endif +#endif + + pAC->Index = boards_found++; + + if (SkGeBoardInit(dev, pAC)) + goto out_free_netdev; + + /* Register net device */ + if (register_netdev(dev)) { + printk(KERN_ERR "SKGE: Could not register device.\n"); + goto out_free_resources; + } + + /* Print adapter specific string from vpd */ + ProductStr(pAC); + printk("%s: %s\n", dev->name, pAC->DeviceStr); + + /* Print configuration settings */ + printk(" PrefPort:%c RlmtMode:%s\n", + 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, + (pAC->RlmtMode==0) ? "Check Link State" : + ((pAC->RlmtMode==1) ? "Check Link State" : + ((pAC->RlmtMode==3) ? "Check Local Port" : + ((pAC->RlmtMode==7) ? "Check Segmentation" : + ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); + + SkGeYellowLED(pAC, pAC->IoBase, 1); + + + memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6); + +#ifdef CONFIG_PROC_FS + pProcFile = create_proc_entry(dev->name, S_IRUGO, pSkRootDir); + if (pProcFile) { + pProcFile->proc_fops = &sk_proc_fops; + pProcFile->data = dev; + pProcFile->owner = THIS_MODULE; + } +#endif + + pNet->PortNr = 0; + pNet->NetNr = 0; + + boards_found++; + + /* More then one port found */ + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { + printk(KERN_ERR "Unable to allocate etherdev " + "structure!\n"); + goto out; + } + + pAC->dev[1] = dev; + pNet = dev->priv; + pNet->PortNr = 1; + pNet->NetNr = 1; + pNet->pAC = pAC; + pNet->Mtu = 1500; + pNet->Up = 0; + + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; + +#ifdef SK_ZEROCOPY +#ifdef USE_SK_TX_CHECKSUM + if (pAC->ChipsetType) { + /* SG and ZEROCOPY - fly baby... */ + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + } +#endif +#endif + + if (register_netdev(dev)) { + printk(KERN_ERR "SKGE: Could not register device.\n"); + free_netdev(dev); + pAC->dev[1] = pAC->dev[0]; + } else { +#ifdef CONFIG_PROC_FS + pProcFile = create_proc_entry(dev->name, S_IRUGO, + pSkRootDir); + if (pProcFile) { + pProcFile->proc_fops = &sk_proc_fops; + pProcFile->data = dev; + pProcFile->owner = THIS_MODULE; + } +#endif + + memcpy(&dev->dev_addr, + &pAC->Addr.Net[1].CurrentMacAddress, 6); + + printk("%s: %s\n", dev->name, pAC->DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + } + } + + /* Save the hardware revision */ + pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + + (pAC->GIni.GIPciHwRev & 0x0F); + + /* Set driver globals */ + pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; + pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; + + memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA)); + memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA)); + + pci_set_drvdata(pdev, dev); + return 0; + + out_free_resources: + FreeResources(dev); + out_free_netdev: + free_netdev(dev); + out_disable_device: + pci_disable_device(pdev); + out: + return error; +} + +static void __devexit skge_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + DEV_NET *pNet = (DEV_NET *) dev->priv; + SK_AC *pAC = pNet->pAC; + int have_second_mac = 0; + + if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2) + have_second_mac = 1; + + remove_proc_entry(dev->name, pSkRootDir); + unregister_netdev(dev); + if (have_second_mac) { + remove_proc_entry(pAC->dev[1]->name, pSkRootDir); + unregister_netdev(pAC->dev[1]); + } + + SkGeYellowLED(pAC, pAC->IoBase, 0); + + if (pAC->BoardLevel == SK_INIT_RUN) { + SK_EVPARA EvPara; + unsigned long Flags; + + /* board is still alive */ + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + EvPara.Para32[0] = 0; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + EvPara.Para32[0] = 1; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + /* disable interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + SkGeDeInit(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + pAC->BoardLevel = SK_INIT_DATA; + /* We do NOT check here, if IRQ was pending, of course*/ + } + + if (pAC->BoardLevel == SK_INIT_IO) { + /* board is still alive */ + SkGeDeInit(pAC, pAC->IoBase); + pAC->BoardLevel = SK_INIT_DATA; + } + + FreeResources(dev); + free_netdev(dev); + if (have_second_mac) + free_netdev(pAC->dev[1]); + kfree(pAC); +} + +static struct pci_device_id skge_pci_tbl[] = { + { PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#if 0 /* don't handle Yukon2 cards at the moment -- mlindner@syskonnect.de */ + { PCI_VENDOR_ID_MARVELL, 0x4360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MARVELL, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +static struct pci_driver skge_driver = { + .name = "skge", + .id_table = skge_pci_tbl, + .probe = skge_probe_one, + .remove = __devexit_p(skge_remove_one), +}; + +static int __init skge_init(void) +{ + int error; + +#ifdef CONFIG_PROC_FS + memcpy(&SK_Root_Dir_entry, BOOT_STRING, sizeof(SK_Root_Dir_entry) - 1); + + pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); + if (!pSkRootDir) { + printk(KERN_WARNING "Unable to create /proc/net/%s", + SK_Root_Dir_entry); + return -ENOMEM; + } + pSkRootDir->owner = THIS_MODULE; +#endif + + error = pci_module_init(&skge_driver); + if (error) { +#ifdef CONFIG_PROC_FS + remove_proc_entry(pSkRootDir->name, proc_net); +#endif + } + + return error; +} + +static void __exit skge_exit(void) +{ + pci_unregister_driver(&skge_driver); +#ifdef CONFIG_PROC_FS + remove_proc_entry(pSkRootDir->name, proc_net); +#endif +} + +module_init(skge_init); +module_exit(skge_exit); diff -Nru a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c --- a/drivers/net/skfp/skfddi.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/skfp/skfddi.c 2004-10-18 14:55:54 -07:00 @@ -1095,7 +1095,7 @@ */ if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) { - bp->MacStat.tx_errors++; /* bump error counter */ + bp->MacStat.gen.tx_errors++; /* bump error counter */ // dequeue packets from xmt queue and send them netif_start_queue(dev); dev_kfree_skb(skb); @@ -1546,8 +1546,8 @@ skb->len, PCI_DMA_TODEVICE); txd->txd_os.dma_addr = 0; - smc->os.MacStat.tx_packets++; // Count transmitted packets. - smc->os.MacStat.tx_bytes+=skb->len; // Count bytes + smc->os.MacStat.gen.tx_packets++; // Count transmitted packets. + smc->os.MacStat.gen.tx_bytes+=skb->len; // Count bytes // free the skb dev_kfree_skb_irq(skb); @@ -1629,7 +1629,7 @@ skb = rxd->rxd_os.skb; if (!skb) { PRINTK(KERN_INFO "No skb in rxd\n"); - smc->os.MacStat.rx_errors++; + smc->os.MacStat.gen.rx_errors++; goto RequeueRxd; } virt = skb->data; @@ -1682,13 +1682,14 @@ } // Count statistics. - smc->os.MacStat.rx_packets++; // Count indicated receive packets. - smc->os.MacStat.rx_bytes+=len; // Count bytes + smc->os.MacStat.gen.rx_packets++; // Count indicated receive + // packets. + smc->os.MacStat.gen.rx_bytes+=len; // Count bytes. // virt points to header again if (virt[1] & 0x01) { // Check group (multicast) bit. - smc->os.MacStat.multicast++; + smc->os.MacStat.gen.multicast++; } // deliver frame to system @@ -1706,7 +1707,8 @@ RequeueRxd: PRINTK(KERN_INFO "Rx: re-queue RXD.\n"); mac_drv_requeue_rxd(smc, rxd, frag_count); - smc->os.MacStat.rx_errors++; // Count receive packets not indicated. + smc->os.MacStat.gen.rx_errors++; // Count receive packets + // not indicated. } // mac_drv_rx_complete @@ -2081,7 +2083,7 @@ break; case 1: PRINTK(KERN_INFO "Receive fifo overflow.\n"); - smc->os.MacStat.rx_errors++; + smc->os.MacStat.gen.rx_errors++; break; default: PRINTK(KERN_INFO "Unknown status (%d).\n", stat); diff -Nru a/drivers/net/slip.c b/drivers/net/slip.c --- a/drivers/net/slip.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/net/slip.c 2004-10-18 14:57:05 -07:00 @@ -672,7 +672,9 @@ * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when * a block of SLIP data has been received, which can now be decapsulated - * and sent on to some IP layer for further processing. + * and sent on to some IP layer for further processing. This will not + * be re-entered while running but other ldisc functions may be called + * in parallel */ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) @@ -841,9 +843,11 @@ * SLIP line discipline is called for. Because we are * sure the tty line exists, we only have to link it to * a free SLIP channel... + * + * Called in process context serialized from other ldisc calls. */ -static int -slip_open(struct tty_struct *tty) + +static int slip_open(struct tty_struct *tty) { struct slip *sl; int err; @@ -876,11 +880,11 @@ tty->disc_data = sl; sl->line = tty_devnum(tty); sl->pid = current->pid; + + /* FIXME: already done before we were called - seems this can go */ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + if (!test_bit(SLF_INUSE, &sl->flags)) { /* Perform the low-level SLIP initialization. */ if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0) @@ -923,6 +927,9 @@ } /* + + FIXME: 1,2 are fixed 3 was never true anyway. + Let me to blame a bit. 1. TTY module calls this funstion on soft interrupt. 2. TTY module calls this function WITH MASKED INTERRUPTS! @@ -941,9 +948,8 @@ /* * Close down a SLIP channel. - * This means flushing out any pending queues, and then restoring the - * TTY line discipline to what it was before it got hooked to SLIP - * (which usually is TTY again). + * This means flushing out any pending queues, and then returning. This + * call is serialized against other ldisc functions. */ static void slip_close(struct tty_struct *tty) diff -Nru a/drivers/net/smc9194.c b/drivers/net/smc9194.c --- a/drivers/net/smc9194.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/smc9194.c 2004-10-18 14:56:49 -07:00 @@ -1191,133 +1191,6 @@ netif_wake_queue(dev); } -/*-------------------------------------------------------------------- - . - . This is the main routine of the driver, to handle the device when - . it needs some attention. - . - . So: - . first, save state of the chipset - . branch off into routines to handle each case, and acknowledge - . each to the interrupt register - . and finally restore state. - . - ---------------------------------------------------------------------*/ - -static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) -{ - struct net_device *dev = dev_id; - int ioaddr = dev->base_addr; - struct smc_local *lp = netdev_priv(dev); - - byte status; - word card_stats; - byte mask; - int timeout; - /* state registers */ - word saved_bank; - word saved_pointer; - int handled = 0; - - - PRINTK3((CARDNAME": SMC interrupt started \n")); - - saved_bank = inw( ioaddr + BANK_SELECT ); - - SMC_SELECT_BANK(2); - saved_pointer = inw( ioaddr + POINTER ); - - mask = inb( ioaddr + INT_MASK ); - /* clear all interrupts */ - outb( 0, ioaddr + INT_MASK ); - - - /* set a timeout value, so I don't stay here forever */ - timeout = 4; - - PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask )); - do { - /* read the status flag, and mask it */ - status = inb( ioaddr + INTERRUPT ) & mask; - if (!status ) - break; - - handled = 1; - - PRINTK3((KERN_WARNING CARDNAME - ": Handling interrupt status %x \n", status )); - - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - PRINTK2((KERN_WARNING CARDNAME - ": Receive Interrupt\n")); - smc_rcv(dev); - } else if (status & IM_TX_INT ) { - PRINTK2((KERN_WARNING CARDNAME - ": TX ERROR handled\n")); - smc_tx(dev); - outb(IM_TX_INT, ioaddr + INTERRUPT ); - } else if (status & IM_TX_EMPTY_INT ) { - /* update stats */ - SMC_SELECT_BANK( 0 ); - card_stats = inw( ioaddr + COUNTER ); - /* single collisions */ - lp->stats.collisions += card_stats & 0xF; - card_stats >>= 4; - /* multiple collisions */ - lp->stats.collisions += card_stats & 0xF; - - /* these are for when linux supports these statistics */ - - SMC_SELECT_BANK( 2 ); - PRINTK2((KERN_WARNING CARDNAME - ": TX_BUFFER_EMPTY handled\n")); - outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); - mask &= ~IM_TX_EMPTY_INT; - lp->stats.tx_packets += lp->packets_waiting; - lp->packets_waiting = 0; - - } else if (status & IM_ALLOC_INT ) { - PRINTK2((KERN_DEBUG CARDNAME - ": Allocation interrupt \n")); - /* clear this interrupt so it doesn't happen again */ - mask &= ~IM_ALLOC_INT; - - smc_hardware_send_packet( dev ); - - /* enable xmit interrupts based on this */ - mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - - PRINTK2((CARDNAME": Handoff done successfully.\n")); - } else if (status & IM_RX_OVRN_INT ) { - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; - outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); - } else if (status & IM_EPH_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); - } else if (status & IM_ERCV_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n")); - outb( IM_ERCV_INT, ioaddr + INTERRUPT ); - } - } while ( timeout -- ); - - - /* restore state register */ - SMC_SELECT_BANK( 2 ); - outb( mask, ioaddr + INT_MASK ); - - PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask )); - outw( saved_pointer, ioaddr + POINTER ); - - SMC_SELECT_BANK( saved_bank ); - - PRINTK3((CARDNAME ": Interrupt done\n")); - return IRQ_RETVAL(handled); -} - /*------------------------------------------------------------- . . smc_rcv - receive a packet from the card @@ -1508,6 +1381,134 @@ outb( saved_packet, ioaddr + PNR_ARR ); return; } + +/*-------------------------------------------------------------------- + . + . This is the main routine of the driver, to handle the device when + . it needs some attention. + . + . So: + . first, save state of the chipset + . branch off into routines to handle each case, and acknowledge + . each to the interrupt register + . and finally restore state. + . + ---------------------------------------------------------------------*/ + +static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + int ioaddr = dev->base_addr; + struct smc_local *lp = netdev_priv(dev); + + byte status; + word card_stats; + byte mask; + int timeout; + /* state registers */ + word saved_bank; + word saved_pointer; + int handled = 0; + + + PRINTK3((CARDNAME": SMC interrupt started \n")); + + saved_bank = inw( ioaddr + BANK_SELECT ); + + SMC_SELECT_BANK(2); + saved_pointer = inw( ioaddr + POINTER ); + + mask = inb( ioaddr + INT_MASK ); + /* clear all interrupts */ + outb( 0, ioaddr + INT_MASK ); + + + /* set a timeout value, so I don't stay here forever */ + timeout = 4; + + PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask )); + do { + /* read the status flag, and mask it */ + status = inb( ioaddr + INTERRUPT ) & mask; + if (!status ) + break; + + handled = 1; + + PRINTK3((KERN_WARNING CARDNAME + ": Handling interrupt status %x \n", status )); + + if (status & IM_RCV_INT) { + /* Got a packet(s). */ + PRINTK2((KERN_WARNING CARDNAME + ": Receive Interrupt\n")); + smc_rcv(dev); + } else if (status & IM_TX_INT ) { + PRINTK2((KERN_WARNING CARDNAME + ": TX ERROR handled\n")); + smc_tx(dev); + outb(IM_TX_INT, ioaddr + INTERRUPT ); + } else if (status & IM_TX_EMPTY_INT ) { + /* update stats */ + SMC_SELECT_BANK( 0 ); + card_stats = inw( ioaddr + COUNTER ); + /* single collisions */ + lp->stats.collisions += card_stats & 0xF; + card_stats >>= 4; + /* multiple collisions */ + lp->stats.collisions += card_stats & 0xF; + + /* these are for when linux supports these statistics */ + + SMC_SELECT_BANK( 2 ); + PRINTK2((KERN_WARNING CARDNAME + ": TX_BUFFER_EMPTY handled\n")); + outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); + mask &= ~IM_TX_EMPTY_INT; + lp->stats.tx_packets += lp->packets_waiting; + lp->packets_waiting = 0; + + } else if (status & IM_ALLOC_INT ) { + PRINTK2((KERN_DEBUG CARDNAME + ": Allocation interrupt \n")); + /* clear this interrupt so it doesn't happen again */ + mask &= ~IM_ALLOC_INT; + + smc_hardware_send_packet( dev ); + + /* enable xmit interrupts based on this */ + mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); + + /* and let the card send more packets to me */ + netif_wake_queue(dev); + + PRINTK2((CARDNAME": Handoff done successfully.\n")); + } else if (status & IM_RX_OVRN_INT ) { + lp->stats.rx_errors++; + lp->stats.rx_fifo_errors++; + outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); + } else if (status & IM_EPH_INT ) { + PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); + } else if (status & IM_ERCV_INT ) { + PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n")); + outb( IM_ERCV_INT, ioaddr + INTERRUPT ); + } + } while ( timeout -- ); + + + /* restore state register */ + SMC_SELECT_BANK( 2 ); + outb( mask, ioaddr + INT_MASK ); + + PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask )); + outw( saved_pointer, ioaddr + POINTER ); + + SMC_SELECT_BANK( saved_bank ); + + PRINTK3((CARDNAME ": Interrupt done\n")); + return IRQ_RETVAL(handled); +} + /*---------------------------------------------------- . smc_close diff -Nru a/drivers/net/smc91x.c b/drivers/net/smc91x.c --- a/drivers/net/smc91x.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/smc91x.c 2004-10-18 14:57:04 -07:00 @@ -55,6 +55,9 @@ * smc_phy_configure * - clean up (and fix stack overrun) in PHY * MII read/write functions + * 09/15/04 Hayato Fujiwara - Add m32r support. + * - Modify for SMP kernel; Change spin-locked + * regions. */ static const char version[] = "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre \n"; @@ -256,24 +259,18 @@ /* this enables an interrupt in the interrupt mask register */ #define SMC_ENABLE_INT(x) do { \ - unsigned long flags; \ unsigned char mask; \ - spin_lock_irqsave(&lp->lock, flags); \ mask = SMC_GET_INT_MASK(); \ mask |= (x); \ SMC_SET_INT_MASK(mask); \ - spin_unlock_irqrestore(&lp->lock, flags); \ } while (0) /* this disables an interrupt from the interrupt mask register */ #define SMC_DISABLE_INT(x) do { \ - unsigned long flags; \ unsigned char mask; \ - spin_lock_irqsave(&lp->lock, flags); \ mask = SMC_GET_INT_MASK(); \ mask &= ~(x); \ SMC_SET_INT_MASK(mask); \ - spin_unlock_irqrestore(&lp->lock, flags); \ } while (0) /* @@ -580,9 +577,12 @@ struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned int numPages, poll_count, status, saved_bank; + unsigned long flags; DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + spin_lock_irqsave(&lp->lock, flags); + BUG_ON(lp->saved_skb != NULL); lp->saved_skb = skb; @@ -604,6 +604,7 @@ lp->stats.tx_errors++; lp->stats.tx_dropped++; dev_kfree_skb(skb); + spin_unlock_irqrestore(&lp->lock, flags); return 0; } @@ -652,6 +653,7 @@ } SMC_SELECT_BANK(saved_bank); + spin_unlock_irqrestore(&lp->lock, flags); return 0; } @@ -1166,6 +1168,8 @@ DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + spin_lock(&lp->lock); + saved_bank = SMC_CURRENT_BANK(); SMC_SELECT_BANK(2); saved_pointer = SMC_GET_PTR(); @@ -1189,8 +1193,6 @@ if (!status) break; - spin_lock(&lp->lock); - if (status & IM_RCV_INT) { DBG(3, "%s: RX irq\n", dev->name); smc_rcv(dev); @@ -1239,7 +1241,6 @@ PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); } - spin_unlock(&lp->lock); } while (--timeout); /* restore register states */ @@ -1249,6 +1250,7 @@ DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout); + spin_unlock(&lp->lock); /* * We return IRQ_HANDLED unconditionally here even if there was * nothing to do. There is a possibility that a packet might @@ -1264,7 +1266,9 @@ static void smc_timeout(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); + unsigned long flags; + spin_lock_irqsave(&lp->lock, flags); DBG(2, "%s: %s\n", dev->name, __FUNCTION__); smc_reset(dev); @@ -1298,6 +1302,9 @@ } /* We can accept TX packets again */ dev->trans_start = jiffies; + + spin_unlock_irqrestore(&lp->lock, flags); + netif_wake_queue(dev); } @@ -1438,7 +1445,7 @@ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) { - DBG(2, (KERN_DEBUG "smc_open: no valid ethernet hw addr\n")); + DBG(2, "smc_open: no valid ethernet hw addr\n"); return -EINVAL; } @@ -1878,7 +1885,9 @@ if (retval) goto err_out; +#if !defined(__m32r__) set_irq_type(dev->irq, IRQT_RISING); +#endif #ifdef SMC_USE_PXA_DMA { int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, @@ -2154,10 +2163,12 @@ static int __init smc_init(void) { #ifdef MODULE +#ifdef CONFIG_ISA if (io == -1) printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n", CARDNAME); +#endif #endif return driver_register(&smc_driver); diff -Nru a/drivers/net/smc91x.h b/drivers/net/smc91x.h --- a/drivers/net/smc91x.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/smc91x.h 2004-10-18 14:56:49 -07:00 @@ -160,6 +160,19 @@ #define SMC_insw(a, r, p, l) insw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) +#elif defined(CONFIG_M32R) + +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 + +#define SMC_inb(a, r) inb((a) + (r) - 0xa0000000) +#define SMC_inw(a, r) inw((a) + (r) - 0xa0000000) +#define SMC_outb(v, a, r) outb(v, (a) + (r) - 0xa0000000) +#define SMC_outw(v, a, r) outw(v, (a) + (r) - 0xa0000000) +#define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) +#define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) + #else #define SMC_CAN_USE_8BIT 1 @@ -809,9 +822,10 @@ do { \ char *__ptr = (p); \ int __len = (l); \ - if (__len >= 2 && (long)__ptr & 2) { \ + if (__len >= 2 && (unsigned long)__ptr & 2) { \ __len -= 2; \ - SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\ + SMC_outw( *(u16 *)__ptr, ioaddr, DATA_REG ); \ + __ptr += 2; \ } \ SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2); \ if (__len & 2) { \ @@ -823,7 +837,7 @@ do { \ char *__ptr = (p); \ int __len = (l); \ - if ((long)__ptr & 2) { \ + if ((unsigned long)__ptr & 2) { \ /* \ * We want 32bit alignment here. \ * Since some buses perform a full 32bit \ @@ -831,7 +845,7 @@ * SMC_inw() here. Back both source (on chip \ * and destination) pointers of 2 bytes. \ */ \ - (long)__ptr &= ~2; \ + __ptr -= 2; \ __len += 2; \ SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ } \ diff -Nru a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c --- a/drivers/net/sunbmac.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/net/sunbmac.c 2004-10-18 14:56:32 -07:00 @@ -68,7 +68,7 @@ #define QEC_RESET_TRIES 200 -static int qec_global_reset(unsigned long gregs) +static int qec_global_reset(void __iomem *gregs) { int tries = QEC_RESET_TRIES; @@ -88,7 +88,7 @@ static void qec_init(struct bigmac *bp) { - unsigned long gregs = bp->gregs; + void __iomem *gregs = bp->gregs; struct sbus_dev *qec_sdev = bp->qec_sdev; u8 bsizes = bp->bigmac_bursts; u32 regval; @@ -117,7 +117,7 @@ #define TX_RESET_TRIES 32 #define RX_RESET_TRIES 32 -static void bigmac_tx_reset(unsigned long bregs) +static void bigmac_tx_reset(void __iomem *bregs) { int tries = TX_RESET_TRIES; @@ -137,7 +137,7 @@ } } -static void bigmac_rx_reset(unsigned long bregs) +static void bigmac_rx_reset(void __iomem *bregs) { int tries = RX_RESET_TRIES; @@ -159,7 +159,7 @@ bigmac_rx_reset(bp->bregs); } -static void bigmac_get_counters(struct bigmac *bp, unsigned long bregs) +static void bigmac_get_counters(struct bigmac *bp, void __iomem *bregs) { struct net_device_stats *stats = &bp->enet_stats; @@ -244,7 +244,7 @@ #define MGMT_CLKON (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB|MGMT_PAL_DCLOCK) #define MGMT_CLKOFF (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB) -static void idle_transceiver(unsigned long tregs) +static void idle_transceiver(void __iomem *tregs) { int i = 20; @@ -256,7 +256,7 @@ } } -static void write_tcvr_bit(struct bigmac *bp, unsigned long tregs, int bit) +static void write_tcvr_bit(struct bigmac *bp, void __iomem *tregs, int bit) { if (bp->tcvr_type == internal) { bit = (bit & 1) << 3; @@ -279,7 +279,7 @@ } } -static int read_tcvr_bit(struct bigmac *bp, unsigned long tregs) +static int read_tcvr_bit(struct bigmac *bp, void __iomem *tregs) { int retval = 0; @@ -302,7 +302,7 @@ return retval; } -static int read_tcvr_bit2(struct bigmac *bp, unsigned long tregs) +static int read_tcvr_bit2(struct bigmac *bp, void __iomem *tregs) { int retval = 0; @@ -325,7 +325,7 @@ } static void put_tcvr_byte(struct bigmac *bp, - unsigned long tregs, + void __iomem *tregs, unsigned int byte) { int shift = 4; @@ -336,7 +336,7 @@ } while (shift >= 0); } -static void bigmac_tcvr_write(struct bigmac *bp, unsigned long tregs, +static void bigmac_tcvr_write(struct bigmac *bp, void __iomem *tregs, int reg, unsigned short val) { int shift; @@ -376,7 +376,7 @@ } static unsigned short bigmac_tcvr_read(struct bigmac *bp, - unsigned long tregs, + void __iomem *tregs, int reg) { unsigned short retval = 0; @@ -444,7 +444,7 @@ static void bigmac_tcvr_init(struct bigmac *bp) { - unsigned long tregs = bp->tregs; + void __iomem *tregs = bp->tregs; u32 mpal; idle_transceiver(tregs); @@ -482,7 +482,7 @@ static int bigmac_init(struct bigmac *, int); -static int try_next_permutation(struct bigmac *bp, unsigned long tregs) +static int try_next_permutation(struct bigmac *bp, void __iomem *tregs) { if (bp->sw_bmcr & BMCR_SPEED100) { int timeout; @@ -518,7 +518,7 @@ static void bigmac_timer(unsigned long data) { struct bigmac *bp = (struct bigmac *) data; - unsigned long tregs = bp->tregs; + void __iomem *tregs = bp->tregs; int restart_timer = 0; bp->timer_ticks++; @@ -573,7 +573,7 @@ */ static void bigmac_begin_auto_negotiation(struct bigmac *bp) { - unsigned long tregs = bp->tregs; + void __iomem *tregs = bp->tregs; int timeout; /* Grab new software copies of PHY registers. */ @@ -612,9 +612,9 @@ static int bigmac_init(struct bigmac *bp, int from_irq) { - unsigned long gregs = bp->gregs; - unsigned long cregs = bp->creg; - unsigned long bregs = bp->bregs; + void __iomem *gregs = bp->gregs; + void __iomem *cregs = bp->creg; + void __iomem *bregs = bp->bregs; unsigned char *e = &bp->dev->dev_addr[0]; /* Latch current counters into statistics. */ @@ -987,7 +987,7 @@ static void bigmac_set_multicast(struct net_device *dev) { struct bigmac *bp = (struct bigmac *) dev->priv; - unsigned long bregs = bp->bregs; + void __iomem *bregs = bp->bregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i; diff -Nru a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h --- a/drivers/net/sunbmac.h 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/sunbmac.h 2004-10-18 14:55:54 -07:00 @@ -303,10 +303,10 @@ }; struct bigmac { - unsigned long gregs; /* QEC Global Registers */ - unsigned long creg; /* QEC BigMAC Channel Registers */ - unsigned long bregs; /* BigMAC Registers */ - unsigned long tregs; /* BigMAC Transceiver */ + void __iomem *gregs; /* QEC Global Registers */ + void __iomem *creg; /* QEC BigMAC Channel Registers */ + void __iomem *bregs; /* BigMAC Registers */ + void __iomem *tregs; /* BigMAC Transceiver */ struct bmac_init_block *bmac_block; /* RX and TX descriptors */ __u32 bblock_dvma; /* RX and TX descriptors */ diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c --- a/drivers/net/sundance.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/sundance.c 2004-10-18 14:56:33 -07:00 @@ -879,7 +879,7 @@ if (dev->if_port == 0) dev->if_port = np->default_port; - np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED; + np->mcastlock = SPIN_LOCK_UNLOCKED; set_rx_mode(dev); writew(0, ioaddr + IntrEnable); diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c --- a/drivers/net/sungem.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/sungem.c 2004-10-18 14:57:04 -07:00 @@ -5,6 +5,9 @@ * * Support for Apple GMAC and assorted PHYs by * Benjamin Herrenscmidt (benh@kernel.crashing.org) + * + * NAPI and NETPOLL support + * (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com) * * TODO: * - Get rid of all those nasty mdelay's and replace them @@ -181,6 +184,18 @@ __phy_write(gp, gp->mii_phy_addr, reg, val); } +static inline void gem_enable_ints(struct gem *gp) +{ + /* Enable all interrupts but TXDONE */ + writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); +} + +static inline void gem_disable_ints(struct gem *gp) +{ + /* Disable all interrupts, including TXDONE */ + writel(GREG_STAT_NAPI | GREG_STAT_TXDONE, gp->regs + GREG_IMASK); +} + static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) { if (netif_msg_intr(gp)) @@ -678,12 +693,12 @@ } } -static void gem_rx(struct gem *gp) +static int gem_rx(struct gem *gp, int work_to_do) { - int entry, drops; + int entry, drops, work_done = 0; u32 done; - if (netif_msg_intr(gp)) + if (netif_msg_rx_status(gp)) printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", gp->dev->name, readl(gp->regs + RXDMA_DONE), gp->rx_new); @@ -700,6 +715,9 @@ if ((status & RXDCTRL_OWN) != 0) break; + if (work_done >= RX_RING_SIZE || work_done >= work_to_do) + break; + /* When writing back RX descriptor, GEM writes status * then buffer address, possibly in seperate transactions. * If we don't wait for the chip to write both, we could @@ -713,6 +731,9 @@ break; } + /* We can now account for the work we're about to do */ + work_done++; + skb = gp->rx_skbs[entry]; len = (status & RXDCTRL_BUFSZ) >> 16; @@ -775,7 +796,8 @@ skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff); skb->ip_summed = CHECKSUM_HW; skb->protocol = eth_type_trans(skb, gp->dev); - netif_rx(skb); + + netif_receive_skb(skb); gp->net_stats.rx_packets++; gp->net_stats.rx_bytes += len; @@ -792,35 +814,103 @@ if (drops) printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", gp->dev->name); + + return work_done; +} + +static int gem_poll(struct net_device *dev, int *budget) +{ + struct gem *gp = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&gp->lock, flags); + + do { + int work_to_do, work_done; + + /* Handle anomalies */ + if (gp->status & GREG_STAT_ABNORMAL) { + if (gem_abnormal_irq(dev, gp, gp->status)) + break; + } + + /* Run TX completion thread */ + spin_lock(&gp->tx_lock); + gem_tx(dev, gp, gp->status); + spin_unlock(&gp->tx_lock); + + spin_unlock_irqrestore(&gp->lock, flags); + + /* Run RX thread. We don't use any locking here, + * code willing to do bad things - like cleaning the + * rx ring - must call netif_poll_disable(), which + * schedule_timeout()'s if polling is already disabled. + */ + work_to_do = min(*budget, dev->quota); + + work_done = gem_rx(gp, work_to_do); + + *budget -= work_done; + dev->quota -= work_done; + + if (work_done >= work_to_do) + return 1; + + spin_lock_irqsave(&gp->lock, flags); + + gp->status = readl(gp->regs + GREG_STAT); + } while (gp->status & GREG_STAT_NAPI); + + __netif_rx_complete(dev); + gem_enable_ints(gp); + + spin_unlock_irqrestore(&gp->lock, flags); + return 0; } static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct gem *gp = dev->priv; - u32 gem_status = readl(gp->regs + GREG_STAT); + unsigned long flags; /* Swallow interrupts when shutting the chip down */ - if (gp->hw_running == 0) - goto out; - - spin_lock(&gp->lock); + if (!gp->hw_running) + return IRQ_HANDLED; - if (gem_status & GREG_STAT_ABNORMAL) { - if (gem_abnormal_irq(dev, gp, gem_status)) - goto out; - } - if (gem_status & (GREG_STAT_TXALL | GREG_STAT_TXINTME)) - gem_tx(dev, gp, gem_status); - if (gem_status & GREG_STAT_RXDONE) - gem_rx(gp); + spin_lock_irqsave(&gp->lock, flags); + + if (netif_rx_schedule_prep(dev)) { + u32 gem_status = readl(gp->regs + GREG_STAT); -out: - spin_unlock(&gp->lock); + if (gem_status == 0) { + spin_unlock_irqrestore(&gp->lock, flags); + return IRQ_NONE; + } + gp->status = gem_status; + gem_disable_ints(gp); + __netif_rx_schedule(dev); + } + spin_unlock_irqrestore(&gp->lock, flags); + + /* If polling was disabled at the time we received that + * interrupt, we may return IRQ_HANDLED here while we + * should return IRQ_NONE. No big deal... + */ return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void gem_poll_controller(struct net_device *dev) +{ + /* gem_interrupt is safe to reentrance so no need + * to disable_irq here. + */ + gem_interrupt(dev->irq, dev, NULL); +} +#endif + static void gem_tx_timeout(struct net_device *dev) { struct gem *gp = dev->priv; @@ -842,10 +932,12 @@ readl(gp->regs + MAC_RXCFG)); spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gp->reset_task_pending = 2; schedule_work(&gp->reset_task); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } @@ -863,6 +955,7 @@ struct gem *gp = dev->priv; int entry; u64 ctrl; + unsigned long flags; ctrl = 0; if (skb->ip_summed == CHECKSUM_HW) { @@ -876,15 +969,20 @@ (csum_stuff_off << 21)); } - spin_lock_irq(&gp->lock); + local_irq_save(flags); + if (!spin_trylock(&gp->tx_lock)) { + /* Tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); - spin_unlock_irq(&gp->lock); + spin_unlock_irqrestore(&gp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } entry = gp->tx_new; @@ -968,11 +1066,11 @@ dev->name, entry, skb->len); mb(); writel(gp->tx_new, gp->regs + TXDMA_KICK); - spin_unlock_irq(&gp->lock); + spin_unlock_irqrestore(&gp->tx_lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Jumbo-grams don't seem to work :-( */ @@ -999,9 +1097,11 @@ } spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); dev->mtu = new_mtu; gp->reset_task_pending = 1; schedule_work(&gp->reset_task); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); flush_scheduled_work(); @@ -1011,7 +1111,7 @@ #define STOP_TRIES 32 -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_stop(struct gem *gp) { int limit; @@ -1037,7 +1137,7 @@ printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_start_dma(struct gem *gp) { unsigned long val; @@ -1062,7 +1162,7 @@ } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ // XXX dbl check what that function should do when called on PCS PHY static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) { @@ -1149,7 +1249,7 @@ /* A link-up condition has occurred, initialize and enable the * rest of the chip. * - * Must be invoked under gp->lock. + * Must be invoked under gp->lock and gp->tx_lock. */ static int gem_set_link_modes(struct gem *gp) { @@ -1256,7 +1356,7 @@ return 0; } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static int gem_mdio_link_not_up(struct gem *gp) { switch (gp->lstate) { @@ -1312,19 +1412,13 @@ { struct gem *gp = (struct gem *) data; - /* The link went down, we reset the ring, but keep - * DMA stopped. Todo: Use this function for reset - * on error as well. - */ - + netif_poll_disable(gp->dev); spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); if (gp->hw_running && gp->opened) { - /* Make sure we don't get interrupts or tx packets */ netif_stop_queue(gp->dev); - writel(0xffffffff, gp->regs + GREG_IMASK); - /* Reset the chip & rings */ gem_stop(gp); gem_init_rings(gp); @@ -1336,7 +1430,9 @@ } gp->reset_task_pending = 0; + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); + netif_poll_enable(gp->dev); } static void gem_link_timer(unsigned long data) @@ -1348,6 +1444,7 @@ return; spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); /* If the link of task is still pending, we just * reschedule the link timer @@ -1417,10 +1514,11 @@ restart: mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); out_unlock: + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_clean_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1471,7 +1569,7 @@ } } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1521,7 +1619,7 @@ wmb(); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_phy(struct gem *gp) { u32 mifcfg; @@ -1659,7 +1757,7 @@ } } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_dma(struct gem *gp) { u64 desc_dma = (u64) gp->gblock_dvma; @@ -1697,7 +1795,7 @@ gp->regs + RXDMA_BLANK); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static u32 gem_setup_multicast(struct gem *gp) { @@ -1740,7 +1838,7 @@ return rxcfg; } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_mac(struct gem *gp) { unsigned char *e = &gp->dev->dev_addr[0]; @@ -1818,7 +1916,7 @@ writel(0xffffffff, gp->regs + MAC_MCMASK); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_pause_thresholds(struct gem *gp) { u32 cfg; @@ -1954,7 +2052,7 @@ return 0; } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_hw(struct gem *gp, int restart_link) { /* On Apple's gmac, I initialize the PHY only after @@ -2052,9 +2150,11 @@ if (!gp->wake_on_lan) { spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); gem_stop(gp); writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); + spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); } @@ -2102,8 +2202,10 @@ unsigned long flags; spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); gem_stop(gp); - spin_unlock_irqrestore(&gp->lock, flags); + spin_unlock(&gp->tx_lock); + spin_unlock_irqrestore(&gp->lock, flags); } } @@ -2163,7 +2265,9 @@ /* Reset the chip */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_stop(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); gp->hw_running = 1; @@ -2177,6 +2281,7 @@ printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); #ifdef CONFIG_PPC_PMAC if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerdown(gp); @@ -2185,12 +2290,14 @@ gp->pm_timer.expires = jiffies + 10*HZ; add_timer(&gp->pm_timer); up(&gp->pm_sem); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return -EAGAIN; } spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); /* Allocate & setup ring buffers */ gem_init_rings(gp); @@ -2200,6 +2307,7 @@ gp->opened = 1; + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); up(&gp->pm_sem); @@ -2214,11 +2322,16 @@ /* Make sure we don't get distracted by suspend/resume */ down(&gp->pm_sem); + /* Note: we don't need to call netif_poll_disable() here because + * our caller (dev_close) already did it for us + */ + /* Stop traffic, mark us closed */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gp->opened = 0; - writel(0xffffffff, gp->regs + GREG_IMASK); + netif_stop_queue(dev); /* Stop chip */ @@ -2230,6 +2343,7 @@ /* Bye, the pm timer will finish the job */ free_irq(gp->pdev->irq, (void *) dev); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); /* Fire the PM timer that will shut us down in about 10 seconds */ @@ -2247,6 +2361,8 @@ struct net_device *dev = pci_get_drvdata(pdev); struct gem *gp = dev->priv; + netif_poll_disable(dev); + /* We hold the PM semaphore during entire driver * sleep time */ @@ -2258,18 +2374,18 @@ /* If the driver is opened, we stop the DMA */ if (gp->opened) { spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); /* Stop traffic, mark us closed */ netif_device_detach(dev); - writel(0xffffffff, gp->regs + GREG_IMASK); - /* Stop chip */ gem_stop(gp); /* Get rid of ring buffers */ gem_clean_rings(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) @@ -2303,12 +2419,14 @@ } #endif /* CONFIG_PPC_PMAC */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_stop(gp); gp->hw_running = 1; gem_init_rings(gp); gem_init_hw(gp, 1); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); netif_device_attach(dev); @@ -2317,6 +2435,8 @@ } up(&gp->pm_sem); + netif_poll_enable(dev); + return 0; } #endif /* CONFIG_PM */ @@ -2327,6 +2447,7 @@ struct net_device_stats *stats = &gp->net_stats; spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); if (gp->hw_running) { stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); @@ -2346,6 +2467,7 @@ writel(0, gp->regs + MAC_LCOLL); } + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return &gp->net_stats; @@ -2361,6 +2483,7 @@ return; spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); netif_stop_queue(dev); @@ -2385,6 +2508,7 @@ netif_wake_queue(dev); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } @@ -2416,6 +2540,7 @@ /* Return current PHY settings */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); cmd->autoneg = gp->want_autoneg; cmd->speed = gp->phy_mii.speed; cmd->duplex = gp->phy_mii.duplex; @@ -2427,6 +2552,7 @@ */ if (cmd->advertising == 0) cmd->advertising = cmd->supported; + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } else { // XXX PCS ? cmd->supported = @@ -2466,7 +2592,9 @@ /* Apply settings and restart link process. */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, cmd); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2481,7 +2609,9 @@ /* Restart link process. */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, NULL); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2581,7 +2711,7 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) { u32 rom_reg_orig; - void *p; + void __iomem *p; if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) { if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0) @@ -2733,6 +2863,7 @@ gp->msg_enable = DEFAULT_MSG; spin_lock_init(&gp->lock); + spin_lock_init(&gp->tx_lock); init_MUTEX(&gp->pm_sem); init_timer(&gp->link_timer); @@ -2750,7 +2881,7 @@ gp->timer_ticks = 0; netif_carrier_off(dev); - gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len); + gp->regs = ioremap(gemreg_base, gemreg_len); if (gp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -2768,7 +2899,9 @@ gem_apple_powerup(gp); #endif spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_stop(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); /* Fill up the mii_phy structure (even if we won't use it) */ @@ -2806,12 +2939,17 @@ dev->get_stats = gem_get_stats; dev->set_multicast_list = gem_set_multicast; dev->do_ioctl = gem_ioctl; + dev->poll = gem_poll; + dev->weight = 64; dev->ethtool_ops = &gem_ethtool_ops; dev->tx_timeout = gem_tx_timeout; dev->watchdog_timeo = 5 * HZ; dev->change_mtu = gem_change_mtu; dev->irq = pdev->irq; dev->dma = 0; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = gem_poll_controller; +#endif if (register_netdev(dev)) { printk(KERN_ERR PFX "Cannot register net device, " @@ -2829,9 +2967,11 @@ /* Detect & init PHY, start autoneg */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gp->hw_running = 1; gem_init_phy(gp); gem_begin_auto_negotiation(gp, NULL); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); if (gp->phy_type == phy_mii_mdio0 || @@ -2842,7 +2982,7 @@ pci_set_drvdata(pdev, dev); /* GEM can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; @@ -2867,7 +3007,7 @@ gem_shutdown(gp); up(&gp->pm_sem); - iounmap((void *) gp->regs); + iounmap(gp->regs); err_out_free_res: pci_release_regions(pdev); @@ -2901,7 +3041,7 @@ sizeof(struct gem_init_block), gp->init_block, gp->gblock_dvma); - iounmap((void *) gp->regs); + iounmap(gp->regs); pci_release_regions(pdev); free_netdev(dev); diff -Nru a/drivers/net/sungem.h b/drivers/net/sungem.h --- a/drivers/net/sungem.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/net/sungem.h 2004-10-18 14:56:32 -07:00 @@ -60,6 +60,9 @@ GREG_STAT_PCS | GREG_STAT_TXMAC | GREG_STAT_RXMAC | \ GREG_STAT_MAC | GREG_STAT_MIF | GREG_STAT_PCIERR) +#define GREG_STAT_NAPI (GREG_STAT_TXALL | GREG_STAT_TXINTME | \ + GREG_STAT_RXDONE | GREG_STAT_ABNORMAL) + /* The layout of GREG_IMASK and GREG_IACK is identical to GREG_STAT. * Bits set in GREG_IMASK will prevent that interrupt type from being * signalled to the cpu. GREG_IACK can be used to clear specific top-level @@ -950,7 +953,8 @@ struct gem { spinlock_t lock; - unsigned long regs; + spinlock_t tx_lock; + void __iomem *regs; int rx_new, rx_old; int tx_new, tx_old; @@ -969,6 +973,7 @@ struct sk_buff *tx_skbs[RX_RING_SIZE]; u32 msg_enable; + u32 status; struct net_device_stats net_stats; diff -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c --- a/drivers/net/sunhme.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/sunhme.c 2004-10-18 14:56:28 -07:00 @@ -203,12 +203,12 @@ */ #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) -static void sbus_hme_write32(unsigned long reg, u32 val) +static void sbus_hme_write32(void __iomem *reg, u32 val) { sbus_writel(val, reg); } -static u32 sbus_hme_read32(unsigned long reg) +static u32 sbus_hme_read32(void __iomem *reg) { return sbus_readl(reg); } @@ -232,12 +232,12 @@ return *p; } -static void pci_hme_write32(unsigned long reg, u32 val) +static void pci_hme_write32(void __iomem *reg, u32 val) { writel(val, reg); } -static u32 pci_hme_read32(unsigned long reg) +static u32 pci_hme_read32(void __iomem *reg) { return readl(reg); } @@ -354,7 +354,7 @@ /* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ -static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit) +static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit) { hme_write32(hp, tregs + TCVR_BBDATA, bit); hme_write32(hp, tregs + TCVR_BBCLOCK, 0); @@ -362,7 +362,7 @@ } #if 0 -static u32 BB_GET_BIT(struct happy_meal *hp, unsigned long tregs, int internal) +static u32 BB_GET_BIT(struct happy_meal *hp, void __iomem *tregs, int internal) { u32 ret; @@ -378,7 +378,7 @@ } #endif -static u32 BB_GET_BIT2(struct happy_meal *hp, unsigned long tregs, int internal) +static u32 BB_GET_BIT2(struct happy_meal *hp, void __iomem *tregs, int internal) { u32 retval; @@ -397,7 +397,7 @@ #define TCVR_FAILURE 0x80000000 /* Impossible MIF read value */ static int happy_meal_bb_read(struct happy_meal *hp, - unsigned long tregs, int reg) + void __iomem *tregs, int reg) { u32 tmp; int retval = 0; @@ -443,7 +443,7 @@ } static void happy_meal_bb_write(struct happy_meal *hp, - unsigned long tregs, int reg, + void __iomem *tregs, int reg, unsigned short value) { u32 tmp; @@ -488,7 +488,7 @@ #define TCVR_READ_TRIES 16 static int happy_meal_tcvr_read(struct happy_meal *hp, - unsigned long tregs, int reg) + void __iomem *tregs, int reg) { int tries = TCVR_READ_TRIES; int retval; @@ -520,7 +520,7 @@ #define TCVR_WRITE_TRIES 16 static void happy_meal_tcvr_write(struct happy_meal *hp, - unsigned long tregs, int reg, + void __iomem *tregs, int reg, unsigned short value) { int tries = TCVR_WRITE_TRIES; @@ -579,7 +579,7 @@ * service routine, and the chip is reset, or the link is ifconfig'd down * and then back up, this entire process repeats itself all over again. */ -static int try_next_permutation(struct happy_meal *hp, unsigned long tregs) +static int try_next_permutation(struct happy_meal *hp, void __iomem *tregs) { hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); @@ -603,7 +603,7 @@ return -1; } -static void display_link_mode(struct happy_meal *hp, unsigned long tregs) +static void display_link_mode(struct happy_meal *hp, void __iomem *tregs) { printk(KERN_INFO "%s: Link is up using ", hp->dev->name); if (hp->tcvr_type == external) @@ -625,7 +625,7 @@ } } -static void display_forced_link_mode(struct happy_meal *hp, unsigned long tregs) +static void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs) { printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name); if (hp->tcvr_type == external) @@ -644,7 +644,7 @@ printk("Half Duplex.\n"); } -static int set_happy_link_modes(struct happy_meal *hp, unsigned long tregs) +static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs) { int full; @@ -708,7 +708,7 @@ static int is_lucent_phy(struct happy_meal *hp) { - unsigned long tregs = hp->tcvregs; + void __iomem *tregs = hp->tcvregs; unsigned short mr2, mr3; int ret = 0; @@ -724,7 +724,7 @@ static void happy_meal_timer(unsigned long data) { struct happy_meal *hp = (struct happy_meal *) data; - unsigned long tregs = hp->tcvregs; + void __iomem *tregs = hp->tcvregs; int restart_timer = 0; spin_lock_irq(&hp->happy_lock); @@ -905,7 +905,7 @@ #define RX_RESET_TRIES 32 /* hp->happy_lock must be held */ -static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs) +static void happy_meal_tx_reset(struct happy_meal *hp, void __iomem *bregs) { int tries = TX_RESET_TRIES; @@ -925,7 +925,7 @@ } /* hp->happy_lock must be held */ -static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs) +static void happy_meal_rx_reset(struct happy_meal *hp, void __iomem *bregs) { int tries = RX_RESET_TRIES; @@ -947,7 +947,7 @@ #define STOP_TRIES 16 /* hp->happy_lock must be held */ -static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs) +static void happy_meal_stop(struct happy_meal *hp, void __iomem *gregs) { int tries = STOP_TRIES; @@ -967,7 +967,7 @@ } /* hp->happy_lock must be held */ -static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs) +static void happy_meal_get_counters(struct happy_meal *hp, void __iomem *bregs) { struct net_device_stats *stats = &hp->net_stats; @@ -990,7 +990,7 @@ } /* hp->happy_lock must be held */ -static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs) +static void happy_meal_poll_stop(struct happy_meal *hp, void __iomem *tregs) { ASD(("happy_meal_poll_stop: ")); @@ -1025,7 +1025,7 @@ #define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */ /* hp->happy_lock must be held */ -static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs) +static int happy_meal_tcvr_reset(struct happy_meal *hp, void __iomem *tregs) { u32 tconfig; int result, tries = TCVR_RESET_TRIES; @@ -1123,7 +1123,7 @@ * * hp->happy_lock must be held */ -static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs) +static void happy_meal_transceiver_check(struct happy_meal *hp, void __iomem *tregs) { unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG); @@ -1318,7 +1318,7 @@ /* hp->happy_lock must be held */ static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, - unsigned long tregs, + void __iomem *tregs, struct ethtool_cmd *ep) { int timeout; @@ -1443,11 +1443,11 @@ /* hp->happy_lock must be held */ static int happy_meal_init(struct happy_meal *hp) { - unsigned long gregs = hp->gregs; - unsigned long etxregs = hp->etxregs; - unsigned long erxregs = hp->erxregs; - unsigned long bregs = hp->bigmacregs; - unsigned long tregs = hp->tcvregs; + void __iomem *gregs = hp->gregs; + void __iomem *etxregs = hp->etxregs; + void __iomem *erxregs = hp->erxregs; + void __iomem *bregs = hp->bigmacregs; + void __iomem *tregs = hp->tcvregs; u32 regtmp, rxcfg; unsigned char *e = &hp->dev->dev_addr[0]; @@ -1736,9 +1736,9 @@ /* hp->happy_lock must be held */ static void happy_meal_set_initial_advertisement(struct happy_meal *hp) { - unsigned long tregs = hp->tcvregs; - unsigned long bregs = hp->bigmacregs; - unsigned long gregs = hp->gregs; + void __iomem *tregs = hp->tcvregs; + void __iomem *bregs = hp->bigmacregs; + void __iomem *gregs = hp->gregs; happy_meal_stop(hp, gregs); hme_write32(hp, tregs + TCVR_IMASK, 0xffff); @@ -1910,7 +1910,7 @@ /* hp->happy_lock must be held */ static void happy_meal_mif_interrupt(struct happy_meal *hp) { - unsigned long tregs = hp->tcvregs; + void __iomem *tregs = hp->tcvregs; printk(KERN_INFO "%s: Link status change.\n", hp->dev->name); hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); @@ -2390,7 +2390,7 @@ static void happy_meal_set_multicast(struct net_device *dev) { struct happy_meal *hp = dev->priv; - unsigned long bregs = hp->bigmacregs; + void __iomem *bregs = hp->bigmacregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i; @@ -3025,7 +3025,8 @@ #endif struct happy_meal *hp; struct net_device *dev; - unsigned long hpreg_base; + void __iomem *hpreg_base; + unsigned long hpreg_res; int i, qfe_slot = -1; char prom_name[64]; int err; @@ -3084,7 +3085,7 @@ qp->happy_meals[qfe_slot] = dev; } - hpreg_base = pci_resource_start(pdev, 0); + hpreg_res = pci_resource_start(pdev, 0); err = -ENODEV; if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n"); @@ -3096,7 +3097,7 @@ goto err_out_clear_quattro; } - if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) { + if ((hpreg_base = ioremap(hpreg_res, 0x8000)) == 0) { printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n"); goto err_out_free_res; } diff -Nru a/drivers/net/sunhme.h b/drivers/net/sunhme.h --- a/drivers/net/sunhme.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/sunhme.h 2004-10-18 14:56:29 -07:00 @@ -397,7 +397,7 @@ /* Happy happy, joy joy! */ struct happy_meal { - unsigned long gregs; /* Happy meal global registers */ + void __iomem *gregs; /* Happy meal global registers */ struct hmeal_init_block *happy_block; /* RX and TX descriptors (CPU addr) */ #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) @@ -423,14 +423,14 @@ struct net_device_stats net_stats; /* Statistical counters */ #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - u32 (*read32)(unsigned long); - void (*write32)(unsigned long, u32); + u32 (*read32)(void __iomem *); + void (*write32)(void __iomem *, u32); #endif - unsigned long etxregs; /* External transmitter regs */ - unsigned long erxregs; /* External receiver regs */ - unsigned long bigmacregs; /* BIGMAC core regs */ - unsigned long tcvregs; /* MIF transceiver regs */ + void __iomem *etxregs; /* External transmitter regs */ + void __iomem *erxregs; /* External receiver regs */ + void __iomem *bigmacregs; /* BIGMAC core regs */ + void __iomem *tcvregs; /* MIF transceiver regs */ dma_addr_t hblock_dvma; /* DVMA visible address happy block */ unsigned int happy_flags; /* Driver state flags */ diff -Nru a/drivers/net/sunlance.c b/drivers/net/sunlance.c --- a/drivers/net/sunlance.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/net/sunlance.c 2004-10-18 14:56:27 -07:00 @@ -230,9 +230,9 @@ ((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem][0]))))) struct lance_private { - unsigned long lregs; /* Lance RAP/RDP regs. */ - unsigned long dregs; /* DMA controller regs. */ - volatile struct lance_init_block *init_block; + void __iomem *lregs; /* Lance RAP/RDP regs. */ + void __iomem *dregs; /* DMA controller regs. */ + struct lance_init_block *init_block; spinlock_t lock; @@ -270,7 +270,7 @@ #define LANCE_REG_SIZE 0x04UL #define STOP_LANCE(__lp) \ -do { unsigned long __base = (__lp)->lregs; \ +do { void __iomem *__base = (__lp)->lregs; \ sbus_writew(LE_CSR0, __base + RAP); \ sbus_writew(LE_C0_STOP, __base + RDP); \ } while (0) @@ -314,7 +314,7 @@ static void lance_init_ring_dvma(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; dma_addr_t aib = lp->init_block_dvma; __u32 leptr; int i; @@ -371,7 +371,7 @@ static void lance_init_ring_pio(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; u32 leptr; int i; @@ -501,8 +501,8 @@ static void lance_rx_dvma(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_rx_desc *rd; + struct lance_init_block *ib = lp->init_block; + struct lance_rx_desc *rd; u8 bits; int len, entry = lp->rx_new; struct sk_buff *skb; @@ -564,14 +564,14 @@ static void lance_tx_dvma(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int i, j; spin_lock(&lp->lock); j = lp->tx_old; for (i = j; i != lp->tx_new; i = j) { - volatile struct lance_tx_desc *td = &ib->btx_ring [i]; + struct lance_tx_desc *td = &ib->btx_ring [i]; u8 bits = td->tmd1_bits; /* If we hit a packet not owned by us, stop */ @@ -641,12 +641,12 @@ spin_unlock(&lp->lock); } -static void lance_piocopy_to_skb(struct sk_buff *skb, volatile void *piobuf, int len) +static void lance_piocopy_to_skb(struct sk_buff *skb, void __iomem *piobuf, int len) { u16 *p16 = (u16 *) skb->data; u32 *p32; u8 *p8; - unsigned long pbuf = (unsigned long) piobuf; + void __iomem *pbuf = piobuf; /* We know here that both src and dest are on a 16bit boundary. */ *p16++ = sbus_readw(pbuf); @@ -674,8 +674,8 @@ static void lance_rx_pio(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_rx_desc *rd; + struct lance_init_block *ib = lp->init_block; + struct lance_rx_desc *rd; unsigned char bits; int len, entry; struct sk_buff *skb; @@ -736,14 +736,14 @@ static void lance_tx_pio(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int i, j; spin_lock(&lp->lock); j = lp->tx_old; for (i = j; i != lp->tx_new; i = j) { - volatile struct lance_tx_desc *td = &ib->btx_ring [i]; + struct lance_tx_desc *td = &ib->btx_ring [i]; u8 bits = sbus_readb(&td->tmd1_bits); /* If we hit a packet not owned by us, stop */ @@ -880,7 +880,7 @@ static void build_fake_packet(struct lance_private *lp) { struct net_device *dev = lp->dev; - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; u16 *packet; struct ethhdr *eth; int i, entry; @@ -916,7 +916,7 @@ static int lance_open(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int status = 0; last_dev = dev; @@ -1006,9 +1006,9 @@ return status; } -static void lance_piocopy_from_skb(volatile void *dest, unsigned char *src, int len) +static void lance_piocopy_from_skb(void __iomem *dest, unsigned char *src, int len) { - unsigned long piobuf = (unsigned long) dest; + void __iomem *piobuf = dest; u32 *p32; u16 *p16; u8 *p8; @@ -1064,11 +1064,11 @@ sbus_writeb(src[0], piobuf); } -static void lance_piozero(volatile void *dest, int len) +static void lance_piozero(void __iomem *dest, int len) { - unsigned long piobuf = (unsigned long) dest; + void __iomem *piobuf = dest; - if (piobuf & 1) { + if ((unsigned long)piobuf & 1) { sbus_writeb(0, piobuf); piobuf += 1; len -= 1; @@ -1079,7 +1079,7 @@ sbus_writeb(0, piobuf); return; } - if (piobuf & 2) { + if ((unsigned long)piobuf & 2) { sbus_writew(0, piobuf); piobuf += 2; len -= 2; @@ -1113,7 +1113,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int entry, skblen, len; skblen = skb->len; @@ -1174,8 +1174,8 @@ static void lance_load_multicast(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; - volatile u16 *mcast_table = (u16 *) &ib->filter; + struct lance_init_block *ib = lp->init_block; + u16 *mcast_table = (u16 *) &ib->filter; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i; @@ -1224,7 +1224,7 @@ static void lance_set_multicast(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; u16 mode; if (!netif_running(dev)) @@ -1277,12 +1277,12 @@ sbus_iounmap(lp->lregs, LANCE_REG_SIZE); if (lp->init_block != NULL) { if (lp->pio_buffer) { - sbus_iounmap((unsigned long)lp->init_block, + sbus_iounmap(lp->init_block, sizeof(struct lance_init_block)); } else { sbus_free_consistent(lp->sdev, sizeof(struct lance_init_block), - (void *)lp->init_block, + lp->init_block, lp->init_block_dvma); } } @@ -1349,7 +1349,7 @@ lp->sdev = sdev; if (lebuffer) { - lp->init_block = (volatile struct lance_init_block *) + lp->init_block = sbus_ioremap(&lebuffer->resource[0], 0, sizeof(struct lance_init_block), "lebuffer"); if (lp->init_block == NULL) { @@ -1362,7 +1362,7 @@ lp->rx = lance_rx_pio; lp->tx = lance_tx_pio; } else { - lp->init_block = (volatile struct lance_init_block *) + lp->init_block = sbus_alloc_consistent(sdev, sizeof(struct lance_init_block), &lp->init_block_dvma); if (lp->init_block == NULL || diff -Nru a/drivers/net/sunqe.c b/drivers/net/sunqe.c --- a/drivers/net/sunqe.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/sunqe.c 2004-10-18 14:56:28 -07:00 @@ -49,7 +49,7 @@ #define QEC_RESET_TRIES 200 -static inline int qec_global_reset(unsigned long gregs) +static inline int qec_global_reset(void __iomem *gregs) { int tries = QEC_RESET_TRIES; @@ -73,8 +73,8 @@ static inline int qe_stop(struct sunqe *qep) { - unsigned long cregs = qep->qcregs; - unsigned long mregs = qep->mregs; + void __iomem *cregs = qep->qcregs; + void __iomem *mregs = qep->mregs; int tries; /* Reset the MACE, then the QEC channel. */ @@ -130,9 +130,9 @@ static int qe_init(struct sunqe *qep, int from_irq) { struct sunqec *qecp = qep->parent; - unsigned long cregs = qep->qcregs; - unsigned long mregs = qep->mregs; - unsigned long gregs = qecp->gregs; + void __iomem *cregs = qep->qcregs; + void __iomem *mregs = qep->mregs; + void __iomem *gregs = qecp->gregs; unsigned char *e = &qep->dev->dev_addr[0]; u32 tmp; int i; @@ -699,7 +699,7 @@ static u32 qe_get_link(struct net_device *dev) { struct sunqe *qep = dev->priv; - unsigned long mregs = qep->mregs; + void __iomem *mregs = qep->mregs; u8 phyconfig; spin_lock_irq(&qep->lock); diff -Nru a/drivers/net/sunqe.h b/drivers/net/sunqe.h --- a/drivers/net/sunqe.h 2004-10-18 14:55:46 -07:00 +++ b/drivers/net/sunqe.h 2004-10-18 14:55:46 -07:00 @@ -311,7 +311,7 @@ struct sunqe; struct sunqec { - unsigned long gregs; /* QEC Global Registers */ + void __iomem *gregs; /* QEC Global Registers */ struct sunqe *qes[4]; /* Each child MACE */ unsigned int qec_bursts; /* Support burst sizes */ struct sbus_dev *qec_sdev; /* QEC's SBUS device */ @@ -331,8 +331,8 @@ ((__u32)((unsigned long)(&(((struct sunqe_buffers *)0)->mem[elem][0])))) struct sunqe { - unsigned long qcregs; /* QEC per-channel Registers */ - unsigned long mregs; /* Per-channel MACE Registers */ + void __iomem *qcregs; /* QEC per-channel Registers */ + void __iomem *mregs; /* Per-channel MACE Registers */ struct qe_init_block *qe_block; /* RX and TX descriptors */ __u32 qblock_dvma; /* RX and TX descriptors */ spinlock_t lock; /* Protects txfull state */ diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/net/tg3.c 2004-10-18 14:56:32 -07:00 @@ -4,6 +4,9 @@ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. + * + * Firmware is: + * Copyright (C) 2000-2003 Broadcom Corporation. */ #include @@ -57,8 +60,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.8" -#define DRV_MODULE_RELDATE "July 14, 2004" +#define DRV_MODULE_VERSION "3.10" +#define DRV_MODULE_RELDATE "September 14, 2004" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -328,7 +331,7 @@ pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); spin_unlock_irqrestore(&tp->indirect_lock, flags); } else { - unsigned long dest = tp->regs + off; + void __iomem *dest = tp->regs + off; writel(val, dest); readl(dest); /* always flush PCI write */ } @@ -336,7 +339,7 @@ static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val) { - unsigned long mbox = tp->regs + off; + void __iomem *mbox = tp->regs + off; writel(val, mbox); if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) readl(mbox); @@ -344,7 +347,7 @@ static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val) { - unsigned long mbox = tp->regs + off; + void __iomem *mbox = tp->regs + off; writel(val, mbox); if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) writel(val, mbox); @@ -442,9 +445,14 @@ 0x1f); tp->pci_clock_ctrl = clock_ctrl; - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) { + tw32_f(TG3PCI_CLOCK_CTRL, + clock_ctrl | CLOCK_CTRL_625_CORE); + udelay(40); + } + } else if ((orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK)); @@ -980,7 +988,7 @@ tp->link_config.orig_autoneg = tp->link_config.autoneg; } - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tp->link_config.speed = SPEED_10; tp->link_config.duplex = DUPLEX_HALF; tp->link_config.autoneg = AUTONEG_ENABLE; @@ -992,7 +1000,7 @@ if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { u32 mac_mode; - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); udelay(40); @@ -1114,29 +1122,33 @@ u32 old_rx_mode = tp->rx_mode; u32 old_tx_mode = tp->tx_mode; - if (local_adv & ADVERTISE_PAUSE_CAP) { - if (local_adv & ADVERTISE_PAUSE_ASYM) { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); - else if (remote_adv & LPA_PAUSE_ASYM) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE); - } else { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); + if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) { + if (local_adv & ADVERTISE_PAUSE_CAP) { + if (local_adv & ADVERTISE_PAUSE_ASYM) { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + else if (remote_adv & LPA_PAUSE_ASYM) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE); + } else { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + } + } else if (local_adv & ADVERTISE_PAUSE_ASYM) { + if ((remote_adv & LPA_PAUSE_CAP) && + (remote_adv & LPA_PAUSE_ASYM)) + new_tg3_flags |= TG3_FLAG_TX_PAUSE; } - } else if (local_adv & ADVERTISE_PAUSE_ASYM) { - if ((remote_adv & LPA_PAUSE_CAP) && - (remote_adv & LPA_PAUSE_ASYM)) - new_tg3_flags |= TG3_FLAG_TX_PAUSE; - } - tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); - tp->tg3_flags |= new_tg3_flags; + tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); + tp->tg3_flags |= new_tg3_flags; + } else { + new_tg3_flags = tp->tg3_flags; + } if (new_tg3_flags & TG3_FLAG_RX_PAUSE) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; @@ -1487,6 +1499,18 @@ current_speed = SPEED_INVALID; current_duplex = DUPLEX_INVALID; + if (tp->tg3_flags2 & TG3_FLG2_CAPACITIVE_COUPLING) { + u32 val; + + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007); + tg3_readphy(tp, MII_TG3_AUX_CTRL, &val); + if (!(val & (1 << 10))) { + val |= (1 << 10); + tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + goto relink; + } + } + bmsr = 0; for (i = 0; i < 100; i++) { tg3_readphy(tp, MII_BMSR, &bmsr); @@ -1566,7 +1590,7 @@ tg3_setup_flow_control(tp, local_adv, remote_adv); } } - +relink: if (current_link_up == 0) { u32 tmp; @@ -1616,7 +1640,7 @@ tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - if (tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES)) { + if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { /* Polled via timer. */ tw32_f(MAC_EVENT, 0); } else { @@ -1965,62 +1989,264 @@ static int fiber_autoneg(struct tg3 *tp, u32 *flags) { int res = 0; + struct tg3_fiber_aneginfo aninfo; + int status = ANEG_FAILED; + unsigned int tick; + u32 tmp; - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) { - u32 dig_status; + tw32_f(MAC_TX_AUTO_NEG, 0); - dig_status = tr32(SG_DIG_STATUS); - *flags = 0; - if (dig_status & SG_DIG_PARTNER_ASYM_PAUSE) - *flags |= MR_LP_ADV_ASYM_PAUSE; - if (dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE) - *flags |= MR_LP_ADV_SYM_PAUSE; - - if ((dig_status & SG_DIG_AUTONEG_COMPLETE) && - !(dig_status & (SG_DIG_AUTONEG_ERROR | - SG_DIG_PARTNER_FAULT_MASK))) - res = 1; - } else { - struct tg3_fiber_aneginfo aninfo; - int status = ANEG_FAILED; - unsigned int tick; - u32 tmp; + tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; + tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); + udelay(40); - tw32_f(MAC_TX_AUTO_NEG, 0); + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); + udelay(40); - tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; - tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); - udelay(40); + memset(&aninfo, 0, sizeof(aninfo)); + aninfo.flags |= MR_AN_ENABLE; + aninfo.state = ANEG_STATE_UNKNOWN; + aninfo.cur_time = 0; + tick = 0; + while (++tick < 195000) { + status = tg3_fiber_aneg_smachine(tp, &aninfo); + if (status == ANEG_DONE || status == ANEG_FAILED) + break; - tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); - udelay(40); + udelay(1); + } - memset(&aninfo, 0, sizeof(aninfo)); - aninfo.flags |= MR_AN_ENABLE; - aninfo.state = ANEG_STATE_UNKNOWN; - aninfo.cur_time = 0; - tick = 0; - while (++tick < 195000) { - status = tg3_fiber_aneg_smachine(tp, &aninfo); - if (status == ANEG_DONE || status == ANEG_FAILED) - break; + tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); - udelay(1); + *flags = aninfo.flags; + + if (status == ANEG_DONE && + (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | + MR_LP_ADV_FULL_DUPLEX))) + res = 1; + + return res; +} + +static void tg3_init_bcm8002(struct tg3 *tp) +{ + u32 mac_status = tr32(MAC_STATUS); + int i; + + /* Reset when initting first time or we have a link. */ + if ((tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) && + !(mac_status & MAC_STATUS_PCS_SYNCED)) + return; + + /* Set PLL lock range. */ + tg3_writephy(tp, 0x16, 0x8007); + + /* SW reset */ + tg3_writephy(tp, MII_BMCR, BMCR_RESET); + + /* Wait for reset to complete. */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 500; i++) + udelay(10); + + /* Config mode; select PMA/Ch 1 regs. */ + tg3_writephy(tp, 0x10, 0x8411); + + /* Enable auto-lock and comdet, select txclk for tx. */ + tg3_writephy(tp, 0x11, 0x0a10); + + tg3_writephy(tp, 0x18, 0x00a0); + tg3_writephy(tp, 0x16, 0x41ff); + + /* Assert and deassert POR. */ + tg3_writephy(tp, 0x13, 0x0400); + udelay(40); + tg3_writephy(tp, 0x13, 0x0000); + + tg3_writephy(tp, 0x11, 0x0a50); + udelay(40); + tg3_writephy(tp, 0x11, 0x0a10); + + /* Wait for signal to stabilize */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 15000; i++) + udelay(10); + + /* Deselect the channel register so we can read the PHYID + * later. + */ + tg3_writephy(tp, 0x10, 0x8011); +} + +static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) +{ + u32 sg_dig_ctrl, sg_dig_status; + u32 serdes_cfg, expected_sg_dig_ctrl; + int workaround, port_a; + int current_link_up; + + serdes_cfg = 0; + expected_sg_dig_ctrl = 0; + workaround = 0; + port_a = 1; + current_link_up = 0; + + if (tp->pci_chip_rev_id != CHIPREV_ID_5704_A0 && + tp->pci_chip_rev_id != CHIPREV_ID_5704_A1) { + workaround = 1; + if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) + port_a = 0; + + serdes_cfg = tr32(MAC_SERDES_CFG) & + ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20)); + } + + sg_dig_ctrl = tr32(SG_DIG_CTRL); + + if (tp->link_config.autoneg != AUTONEG_ENABLE) { + if (sg_dig_ctrl & (1 << 31)) { + if (workaround) { + u32 val = serdes_cfg; + + if (port_a) + val |= 0xc010880; + else + val |= 0x4010880; + tw32_f(MAC_SERDES_CFG, val); + } + tw32_f(SG_DIG_CTRL, 0x01388400); } + if (mac_status & MAC_STATUS_PCS_SYNCED) { + tg3_setup_flow_control(tp, 0, 0); + current_link_up = 1; + } + goto out; + } - tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); + /* Want auto-negotiation. */ + expected_sg_dig_ctrl = 0x81388400; + + /* Pause capability */ + expected_sg_dig_ctrl |= (1 << 11); + + /* Asymettric pause */ + expected_sg_dig_ctrl |= (1 << 12); + + if (sg_dig_ctrl != expected_sg_dig_ctrl) { + if (workaround) + tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011880); + tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30)); + udelay(5); + tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl); + + tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED; + } else if (mac_status & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET)) { + sg_dig_status = tr32(SG_DIG_STATUS); + + if ((sg_dig_status & (1 << 1)) && + (mac_status & MAC_STATUS_PCS_SYNCED)) { + u32 local_adv, remote_adv; + + local_adv = ADVERTISE_PAUSE_CAP; + remote_adv = 0; + if (sg_dig_status & (1 << 19)) + remote_adv |= LPA_PAUSE_CAP; + if (sg_dig_status & (1 << 20)) + remote_adv |= LPA_PAUSE_ASYM; + + tg3_setup_flow_control(tp, local_adv, remote_adv); + current_link_up = 1; + tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; + } else if (!(sg_dig_status & (1 << 1))) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) + tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; + else { + if (workaround) { + u32 val = serdes_cfg; + + if (port_a) + val |= 0xc010880; + else + val |= 0x4010880; - *flags = aninfo.flags; + tw32_f(MAC_SERDES_CFG, val); + } - if (status == ANEG_DONE && - (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | - MR_LP_ADV_FULL_DUPLEX))) - res = 1; + tw32_f(SG_DIG_CTRL, 0x01388400); + udelay(40); + + mac_status = tr32(MAC_STATUS); + if (mac_status & MAC_STATUS_PCS_SYNCED) { + tg3_setup_flow_control(tp, 0, 0); + current_link_up = 1; + } + } + } } - return res; +out: + return current_link_up; +} + +static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) +{ + int current_link_up = 0; + + if (!(mac_status & MAC_STATUS_PCS_SYNCED)) { + tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL; + goto out; + } + + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + u32 flags; + int i; + + if (fiber_autoneg(tp, &flags)) { + u32 local_adv, remote_adv; + + local_adv = ADVERTISE_PAUSE_CAP; + remote_adv = 0; + if (flags & MR_LP_ADV_SYM_PAUSE) + remote_adv |= LPA_PAUSE_CAP; + if (flags & MR_LP_ADV_ASYM_PAUSE) + remote_adv |= LPA_PAUSE_ASYM; + + tg3_setup_flow_control(tp, local_adv, remote_adv); + + tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; + current_link_up = 1; + } + for (i = 0; i < 30; i++) { + udelay(20); + tw32_f(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + udelay(40); + if ((tr32(MAC_STATUS) & + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + + mac_status = tr32(MAC_STATUS); + if (current_link_up == 0 && + (mac_status & MAC_STATUS_PCS_SYNCED) && + !(mac_status & MAC_STATUS_RCVD_CFG)) + current_link_up = 1; + } else { + /* Forcing 1000FD link up. */ + current_link_up = 1; + tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; + + tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS)); + udelay(40); + } + +out: + return current_link_up; } static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) @@ -2028,6 +2254,7 @@ u32 orig_pause_cfg; u16 orig_active_speed; u8 orig_active_duplex; + u32 mac_status; int current_link_up; int i; @@ -2037,118 +2264,43 @@ orig_active_speed = tp->link_config.active_speed; orig_active_duplex = tp->link_config.active_duplex; - tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); - tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); - - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) { - /* Allow time for the hardware to auto-negotiate (195ms) */ - unsigned int tick = 0; - - while (++tick < 195000) { - if (tr32(SG_DIG_STATUS) & SG_DIG_AUTONEG_COMPLETE) - break; - udelay(1); + if (!(tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) && + netif_carrier_ok(tp->dev) && + (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) { + mac_status = tr32(MAC_STATUS); + mac_status &= (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET | + MAC_STATUS_CFG_CHANGED | + MAC_STATUS_RCVD_CFG); + if (mac_status == (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET)) { + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + return 0; } - if (tick >= 195000) - printk(KERN_INFO PFX "%s: HW autoneg failed !\n", - tp->dev->name); } - /* Reset when initting first time or we have a link. */ - if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || - (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { - /* Set PLL lock range. */ - tg3_writephy(tp, 0x16, 0x8007); - - /* SW reset */ - tg3_writephy(tp, MII_BMCR, BMCR_RESET); - - /* Wait for reset to complete. */ - /* XXX schedule_timeout() ... */ - for (i = 0; i < 500; i++) - udelay(10); - - /* Config mode; select PMA/Ch 1 regs. */ - tg3_writephy(tp, 0x10, 0x8411); - - /* Enable auto-lock and comdet, select txclk for tx. */ - tg3_writephy(tp, 0x11, 0x0a10); - - tg3_writephy(tp, 0x18, 0x00a0); - tg3_writephy(tp, 0x16, 0x41ff); - - /* Assert and deassert POR. */ - tg3_writephy(tp, 0x13, 0x0400); - udelay(40); - tg3_writephy(tp, 0x13, 0x0000); - - tg3_writephy(tp, 0x11, 0x0a50); - udelay(40); - tg3_writephy(tp, 0x11, 0x0a10); + tw32_f(MAC_TX_AUTO_NEG, 0); - /* Wait for signal to stabilize */ - /* XXX schedule_timeout() ... */ - for (i = 0; i < 15000; i++) - udelay(10); + tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); + tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); - /* Deselect the channel register so we can read the PHYID - * later. - */ - tg3_writephy(tp, 0x10, 0x8011); - } + if (tp->phy_id == PHY_ID_BCM8002) + tg3_init_bcm8002(tp); - /* Enable link change interrupt unless serdes polling. */ - if (!(tp->tg3_flags & TG3_FLAG_POLL_SERDES)) - tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); - else - tw32_f(MAC_EVENT, 0); + /* Enable link change event even when serdes polling. */ + tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); udelay(40); current_link_up = 0; - if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) { - if (tp->link_config.autoneg == AUTONEG_ENABLE) { - u32 flags; - - if (fiber_autoneg(tp, &flags)) { - u32 local_adv, remote_adv; - - local_adv = ADVERTISE_PAUSE_CAP; - remote_adv = 0; - if (flags & MR_LP_ADV_SYM_PAUSE) - remote_adv |= LPA_PAUSE_CAP; - if (flags & MR_LP_ADV_ASYM_PAUSE) - remote_adv |= LPA_PAUSE_ASYM; + mac_status = tr32(MAC_STATUS); - tg3_setup_flow_control(tp, local_adv, remote_adv); - - tp->tg3_flags |= - TG3_FLAG_GOT_SERDES_FLOWCTL; - current_link_up = 1; - } - for (i = 0; i < 60; i++) { - udelay(20); - tw32_f(MAC_STATUS, - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)); - udelay(40); - if ((tr32(MAC_STATUS) & - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)) == 0) - break; - } - if (current_link_up == 0 && - (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { - current_link_up = 1; - } - } else { - /* Forcing 1000FD link up. */ - current_link_up = 1; - tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; - } - } else - tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL; + if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) + current_link_up = tg3_setup_fiber_hw_autoneg(tp, mac_status); + else + current_link_up = tg3_setup_fiber_by_hand(tp, mac_status); tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; tw32_f(MAC_MODE, tp->mac_mode); @@ -2159,19 +2311,24 @@ (tp->hw_status->status & ~SD_STATUS_LINK_CHG)); for (i = 0; i < 100; i++) { - udelay(20); - tw32_f(MAC_STATUS, - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)); - udelay(40); - if ((tr32(MAC_STATUS) & - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)) == 0) + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + udelay(5); + if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) break; } - if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) + mac_status = tr32(MAC_STATUS); + if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) { current_link_up = 0; + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + tw32_f(MAC_MODE, (tp->mac_mode | + MAC_MODE_SEND_CONFIGS)); + udelay(1); + tw32_f(MAC_MODE, tp->mac_mode); + } + } if (current_link_up == 1) { tp->link_config.active_speed = SPEED_1000; @@ -2203,15 +2360,6 @@ tg3_link_report(tp); } - if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { - tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); - udelay(40); - if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); - } - } - return 0; } @@ -2219,7 +2367,7 @@ { int err; - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { err = tg3_setup_fiber_phy(tp, force_reset); } else { err = tg3_setup_copper_phy(tp, force_reset); @@ -2738,11 +2886,11 @@ tg3_halt(tp); tg3_init_hw(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); - if (restart_timer) mod_timer(&tp->timer, jiffies + 1); } @@ -2812,6 +2960,7 @@ dma_addr_t mapping, int len, u32 flags, u32 mss_and_is_end) { + struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; int is_end = (mss_and_is_end & 0x1); u32 mss = (mss_and_is_end >> 1); u32 vlan_tag = 0; @@ -2823,35 +2972,11 @@ flags &= 0xffff; } vlan_tag |= (mss << TXD_MSS_SHIFT); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; - - txd->addr_hi = ((u64) mapping >> 32); - txd->addr_lo = ((u64) mapping & 0xffffffff); - txd->len_flags = (len << TXD_LEN_SHIFT) | flags; - txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; - } else { - struct tx_ring_info *txr = &tp->tx_buffers[entry]; - unsigned long txd; - - txd = (tp->regs + - NIC_SRAM_WIN_BASE + - NIC_SRAM_TX_BUFFER_DESC); - txd += (entry * TXD_SIZE); - /* Save some PIOs */ - if (sizeof(dma_addr_t) != sizeof(u32)) - writel(((u64) mapping >> 32), - txd + TXD_ADDR + TG3_64BIT_REG_HIGH); - - writel(((u64) mapping & 0xffffffff), - txd + TXD_ADDR + TG3_64BIT_REG_LOW); - writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS); - if (txr->prev_vlan_tag != vlan_tag) { - writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG); - txr->prev_vlan_tag = vlan_tag; - } - } + txd->addr_hi = ((u64) mapping >> 32); + txd->addr_lo = ((u64) mapping & 0xffffffff); + txd->len_flags = (len << TXD_LEN_SHIFT) | flags; + txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) @@ -2892,7 +3017,11 @@ * So we really do need to disable interrupts when taking * tx_lock here. */ - spin_lock_irqsave(&tp->tx_lock, flags); + local_irq_save(flags); + if (!spin_trylock(&tp->tx_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } /* This is a hard error, log it. */ if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { @@ -2900,7 +3029,7 @@ spin_unlock_irqrestore(&tp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } entry = tp->tx_prod; @@ -3040,19 +3169,7 @@ } /* Packets are ready, update Tx producer idx local and on card. */ - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - } else { - /* First, make sure tg3 sees last descriptor fully - * in SRAM. - */ - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW); - - tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - } + tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); tp->tx_prod = entry; if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) @@ -3063,7 +3180,7 @@ dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, @@ -3102,9 +3219,10 @@ tg3_init_hw(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -3190,7 +3308,6 @@ */ static void tg3_init_rings(struct tg3 *tp) { - unsigned long start, end; u32 i; /* Free up all the SKBs. */ @@ -3200,21 +3317,7 @@ memset(tp->rx_std, 0, TG3_RX_RING_BYTES); memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); - } else { - start = (tp->regs + - NIC_SRAM_WIN_BASE + - NIC_SRAM_TX_BUFFER_DESC); - end = start + TG3_TX_RING_BYTES; - while (start < end) { - writel(0, start); - start += 4; - } - for (i = 0; i < TG3_TX_RING_SIZE; i++) - tp->tx_buffers[i].prev_vlan_tag = 0; - } + memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); /* Initialize invariants of the rings, we only set this * stuff once. This works because the card does not @@ -3345,15 +3448,10 @@ if (!tp->rx_rcb) goto err_out; - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, - &tp->tx_desc_mapping); - if (!tp->tx_ring) - goto err_out; - } else { - tp->tx_ring = NULL; - tp->tx_desc_mapping = 0; - } + tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, + &tp->tx_desc_mapping); + if (!tp->tx_ring) + goto err_out; tp->hw_status = pci_alloc_consistent(tp->pdev, TG3_HW_STATUS_SIZE, @@ -3595,6 +3693,8 @@ } } +static void tg3_stop_fw(struct tg3 *); + /* tp->lock is held. */ static int tg3_chip_reset(struct tg3 *tp) { @@ -3602,7 +3702,7 @@ u32 flags_save; int i; - if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) + if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) tg3_nvram_lock(tp); /* @@ -3697,6 +3797,11 @@ tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) { + tg3_stop_fw(tp); + tw32(0x5000, 0x400); + } + tw32(GRC_MODE, tp->grc_mode); if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { @@ -3713,7 +3818,7 @@ tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); } - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tp->mac_mode = MAC_MODE_PORT_MODE_TBI; tw32_f(MAC_MODE, tp->mac_mode); } else @@ -3728,7 +3833,7 @@ udelay(10); } if (i >= 100000 && - !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) { + !(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) { printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, " "firmware will not restart magic=%08x\n", tp->dev->name, val); @@ -4810,10 +4915,7 @@ GRC_MODE_4X_NIC_SEND_RINGS | GRC_MODE_NO_TX_PHDR_CSUM | GRC_MODE_NO_RX_PHDR_CSUM); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) - tp->grc_mode |= GRC_MODE_HOST_SENDBDS; - else - tp->grc_mode |= GRC_MODE_4X_NIC_SEND_RINGS; + tp->grc_mode |= GRC_MODE_HOST_SENDBDS; if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM) tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM) @@ -4966,18 +5068,11 @@ tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - tp->tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); - } else { - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - 0, - BDINFO_FLAGS_DISABLED, - NIC_SRAM_TX_BUFFER_DESC); - } + tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, + tp->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); /* There is only one receive return ring on 5705/5750, no need * to explicitly disable the others. @@ -5243,14 +5338,14 @@ tw32(MAC_LED_CTRL, tp->led_ctrl); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tw32_f(MAC_RX_MODE, RX_MODE_RESET); udelay(10); } tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { /* Set drive transmission level to 1.2V */ val = tr32(MAC_SERDES_CFG); @@ -5268,22 +5363,8 @@ tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && - tp->phy_id == PHY_ID_SERDES) { - /* Enable hardware link auto-negotiation */ - u32 digctrl, txctrl; - - digctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_CRC16_CLEAR_N | - SG_DIG_LOCAL_DUPLEX_STATUS | SG_DIG_LOCAL_LINK_STATUS | - (2 << SG_DIG_SPEED_STATUS_SHIFT) | SG_DIG_FIBER_MODE | - SG_DIG_GBIC_ENABLE; - - txctrl = tr32(MAC_SERDES_CFG); - tw32_f(MAC_SERDES_CFG, txctrl | MAC_SERDES_CFG_EDGE_SELECT); - tw32_f(SG_DIG_CTRL, digctrl | SG_DIG_SOFT_RESET); - tr32(SG_DIG_CTRL); - udelay(5); - tw32_f(SG_DIG_CTRL, digctrl); - + (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { + /* Use hardware link auto-negotiation */ tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG; } @@ -5291,7 +5372,7 @@ if (err) return err; - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { u32 tmp; /* Clear CRC stats. */ @@ -5483,7 +5564,8 @@ need_setup = 1; } if (! netif_carrier_ok(tp->dev) && - (mac_stat & MAC_STATUS_PCS_SYNCED)) { + (mac_stat & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET))) { need_setup = 1; } if (need_setup) { @@ -5536,8 +5618,8 @@ spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - /* If you move this call, make sure TG3_FLAG_HOST_TXDS in - * tp->tg3_flags is accurate at that new place. + /* The placement of this call is tied + * to the setup and use of Host TX descriptors. */ err = tg3_alloc_consistent(tp); if (err) @@ -5879,7 +5961,7 @@ { struct tg3_hw_stats *hw_stats = tp->hw_stats; - if (tp->phy_id != PHY_ID_SERDES && + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { unsigned long flags; @@ -6152,7 +6234,9 @@ struct tg3 *tp = netdev_priv(dev); spin_lock_irq(&tp->lock); + spin_lock(&tp->tx_lock); __tg3_set_rx_mode(dev); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } @@ -6310,7 +6394,7 @@ cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (tp->phy_id != PHY_ID_SERDES) + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | @@ -6339,7 +6423,7 @@ tp->link_config.phy_is_low_power) return -EAGAIN; - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && (cmd->advertising & ~(ADVERTISED_1000baseT_Half | @@ -6397,7 +6481,7 @@ if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; if ((wol->wolopts & WAKE_MAGIC) && - tp->phy_id == PHY_ID_SERDES && + tp->tg3_flags2 & TG3_FLG2_PHY_SERDES && !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP)) return -EINVAL; @@ -6493,10 +6577,9 @@ tg3_halt(tp); tg3_init_hw(tp); - netif_wake_queue(tp->dev); + tg3_netif_start(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -6506,8 +6589,8 @@ struct tg3 *tp = netdev_priv(dev); epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; - epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0; - epause->tx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0; + epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0; + epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0; } static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) @@ -6522,18 +6605,18 @@ else tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; if (epause->rx_pause) - tp->tg3_flags |= TG3_FLAG_PAUSE_RX; + tp->tg3_flags |= TG3_FLAG_RX_PAUSE; else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX; + tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE; if (epause->tx_pause) - tp->tg3_flags |= TG3_FLAG_PAUSE_TX; + tp->tg3_flags |= TG3_FLAG_TX_PAUSE; else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX; + tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE; tg3_halt(tp); tg3_init_hw(tp); + tg3_netif_start(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -6620,7 +6703,7 @@ case SIOCGMIIREG: { u32 mii_regval; - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ spin_lock_irq(&tp->lock); @@ -6633,7 +6716,7 @@ } case SIOCSMIIREG: - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ if (!capable(CAP_NET_ADMIN)) @@ -6720,7 +6803,7 @@ { int j; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) return; tw32_f(GRC_EEPROM_ADDR, @@ -6807,8 +6890,8 @@ { int i; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) { - printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 5704\n"); + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { + printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n"); return -EINVAL; } @@ -6870,10 +6953,10 @@ { PCI_VENDOR_ID_BROADCOM, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */ { PCI_VENDOR_ID_BROADCOM, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */ { PCI_VENDOR_ID_BROADCOM, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */ - { PCI_VENDOR_ID_BROADCOM, 0x0003, PHY_ID_SERDES }, /* BCM95700A9 */ + { PCI_VENDOR_ID_BROADCOM, 0x0003, 0 }, /* BCM95700A9 */ { PCI_VENDOR_ID_BROADCOM, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */ { PCI_VENDOR_ID_BROADCOM, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */ - { PCI_VENDOR_ID_BROADCOM, 0x0007, PHY_ID_SERDES }, /* BCM95701A7 */ + { PCI_VENDOR_ID_BROADCOM, 0x0007, 0 }, /* BCM95701A7 */ { PCI_VENDOR_ID_BROADCOM, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */ { PCI_VENDOR_ID_BROADCOM, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */ { PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5703 }, /* BCM95703Ax1 */ @@ -6882,7 +6965,7 @@ /* 3com boards. */ { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */ { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */ - { PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES }, /* 3C996SX */ + { PCI_VENDOR_ID_3COM, 0x1004, 0 }, /* 3C996SX */ { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */ { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */ @@ -6895,37 +6978,43 @@ /* Compaq boards. */ { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */ { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */ - { PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES }, /* CHANGELING */ + { PCI_VENDOR_ID_COMPAQ, 0x007d, 0 }, /* CHANGELING */ { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */ { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */ /* IBM boards. */ - { PCI_VENDOR_ID_IBM, 0x0281, PHY_ID_SERDES } /* IBM??? */ + { PCI_VENDOR_ID_IBM, 0x0281, 0 } /* IBM??? */ }; -static int __devinit tg3_phy_probe(struct tg3 *tp) +static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp) { - u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; - u32 hw_phy_id, hw_phy_id_masked; - u32 val; - int i, eeprom_signature_found, err; + int i; - tp->phy_id = PHY_ID_INVALID; for (i = 0; i < ARRAY_SIZE(subsys_id_to_phy_id); i++) { if ((subsys_id_to_phy_id[i].subsys_vendor == tp->pdev->subsystem_vendor) && (subsys_id_to_phy_id[i].subsys_devid == - tp->pdev->subsystem_device)) { - tp->phy_id = subsys_id_to_phy_id[i].phy_id; - break; - } + tp->pdev->subsystem_device)) + return &subsys_id_to_phy_id[i]; } + return NULL; +} +static int __devinit tg3_phy_probe(struct tg3 *tp) +{ + u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; + u32 hw_phy_id, hw_phy_id_masked; + u32 val; + int eeprom_signature_found, eeprom_phy_serdes, err; + + tp->phy_id = PHY_ID_INVALID; eeprom_phy_id = PHY_ID_INVALID; + eeprom_phy_serdes = 0; eeprom_signature_found = 0; tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; + u32 nic_phy_id, cfg2; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); tp->nic_sram_data_cfg = nic_cfg; @@ -6933,21 +7022,19 @@ eeprom_signature_found = 1; if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == - NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) { - eeprom_phy_id = PHY_ID_SERDES; - } else { - u32 nic_phy_id; + NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) + eeprom_phy_serdes = 1; - tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id); - if (nic_phy_id != 0) { - u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK; - u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK; - - eeprom_phy_id = (id1 >> 16) << 10; - eeprom_phy_id |= (id2 & 0xfc00) << 16; - eeprom_phy_id |= (id2 & 0x03ff) << 0; - } - } + tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id); + if (nic_phy_id != 0) { + u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK; + u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK; + + eeprom_phy_id = (id1 >> 16) << 10; + eeprom_phy_id |= (id2 & 0xfc00) << 16; + eeprom_phy_id |= (id2 & 0x03ff) << 0; + } else + eeprom_phy_id = 0; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &led_cfg); @@ -7009,6 +7096,10 @@ } if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL) tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP; + + tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &cfg2); + if (cfg2 & (1 << 17)) + tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING; } /* Reading the PHY ID register can conflict with ASF @@ -7035,20 +7126,31 @@ if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) { tp->phy_id = hw_phy_id; + if (hw_phy_id_masked == PHY_ID_BCM8002) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; } else { - /* phy_id currently holds the value found in the - * subsys_id_to_phy_id[] table or PHY_ID_INVALID - * if a match was not found there. - */ - if (tp->phy_id == PHY_ID_INVALID) { - if (!eeprom_signature_found || - !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK)) - return -ENODEV; + if (eeprom_signature_found) { tp->phy_id = eeprom_phy_id; + if (eeprom_phy_serdes) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; + } else { + struct subsys_tbl_ent *p; + + /* No eeprom signature? Try the hardcoded + * subsys device table. + */ + p = lookup_by_subsys(tp); + if (!p) + return -ENODEV; + + tp->phy_id = p->phy_id; + if (!tp->phy_id || + tp->phy_id == PHY_ID_BCM8002) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; } } - if (tp->phy_id != PHY_ID_SERDES && + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { u32 bmsr, adv_reg, tg3_ctrl; @@ -7105,7 +7207,7 @@ if (!eeprom_signature_found) tp->led_ctrl = LED_CTRL_MODE_PHY_1; - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) tp->link_config.advertising = (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | @@ -7124,11 +7226,11 @@ unsigned char vpd_data[256]; int i; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) { + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { /* Sun decided not to put the necessary bits in the * NVRAM of their onboard tg3 parts :( */ - strcpy(tp->board_part_number, "Sun 5704"); + strcpy(tp->board_part_number, "Sun 570X"); return; } @@ -7189,27 +7291,21 @@ } #ifdef CONFIG_SPARC64 -static int __devinit tg3_is_sun_5704(struct tg3 *tp) +static int __devinit tg3_is_sun_570X(struct tg3 *tp) { struct pci_dev *pdev = tp->pdev; struct pcidev_cookie *pcp = pdev->sysdata; if (pcp != NULL) { int node = pcp->prom_node; - u32 venid, devid; + u32 venid; int err; err = prom_getproperty(node, "subsystem-vendor-id", (char *) &venid, sizeof(venid)); if (err == 0 || err == -1) return 0; - err = prom_getproperty(node, "subsystem-id", - (char *) &devid, sizeof(devid)); - if (err == 0 || err == -1) - return 0; - - if (venid == PCI_VENDOR_ID_SUN && - devid == PCI_DEVICE_ID_TIGON3_5704) + if (venid == PCI_VENDOR_ID_SUN) return 1; } return 0; @@ -7226,8 +7322,8 @@ int err; #ifdef CONFIG_SPARC64 - if (tg3_is_sun_5704(tp)) - tp->tg3_flags2 |= TG3_FLG2_SUN_5704; + if (tg3_is_sun_570X(tp)) + tp->tg3_flags2 |= TG3_FLG2_SUN_570X; #endif /* If we have an AMD 762 or Intel ICH/ICH0/ICH2 chipset, write @@ -7453,7 +7549,7 @@ chiprevid == CHIPREV_ID_5701_B0 || chiprevid == CHIPREV_ID_5701_B2 || chiprevid == CHIPREV_ID_5701_B5) { - unsigned long sram_base; + void __iomem *sram_base; /* Write some dummy words into the SRAM status block * area, see if it reads back correctly. If the return @@ -7472,32 +7568,17 @@ udelay(50); tg3_nvram_init(tp); - /* Always use host TXDs, it performs better in particular - * with multi-frag packets. The tests below are kept here - * as documentation should we change this decision again - * in the future. - */ - tp->tg3_flags |= TG3_FLAG_HOST_TXDS; - -#if 0 - /* Determine if TX descriptors will reside in - * main memory or in the chip SRAM. - */ - if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) - tp->tg3_flags |= TG3_FLAG_HOST_TXDS; -#endif - grc_misc_cfg = tr32(GRC_MISC_CFG); grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK; + /* Broadcom's driver says that CIOBE multisplit has a bug */ +#if 0 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) { tp->tg3_flags |= TG3_FLAG_SPLIT_MODE; tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ; } - +#endif if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 || grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M)) @@ -7524,7 +7605,7 @@ tg3_read_partno(tp); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT; } else { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) @@ -7547,13 +7628,13 @@ * upon subsystem IDs. */ if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && - tp->phy_id != PHY_ID_SERDES) { + !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT | TG3_FLAG_USE_LINKCHG_REG); } /* For all SERDES we poll the MAC status register. */ - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) tp->tg3_flags |= TG3_FLAG_POLL_SERDES; else tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; @@ -7624,7 +7705,7 @@ mac_offset = 0x7c; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && - !(tp->tg3_flags & TG3_FLG2_SUN_5704)) { + !(tp->tg3_flags & TG3_FLG2_SUN_570X)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) @@ -7646,7 +7727,7 @@ dev->dev_addr[5] = (lo >> 0) & 0xff; } /* Next, try NVRAM. */ - else if (!(tp->tg3_flags & TG3_FLG2_SUN_5704) && + else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && !tg3_nvram_read(tp, mac_offset + 0, &hi) && !tg3_nvram_read(tp, mac_offset + 4, &lo)) { dev->dev_addr[0] = ((hi >> 16) & 0xff); @@ -7988,8 +8069,8 @@ case PHY_ID_BCM5704: return "5704"; case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; - case PHY_ID_BCM8002: return "8002"; - case PHY_ID_SERDES: return "serdes"; + case PHY_ID_BCM8002: return "8002/serdes"; + case 0: return "serdes"; default: return "unknown"; }; } @@ -8096,6 +8177,7 @@ if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; + dev->features |= NETIF_F_LLTX; #if TG3_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->vlan_rx_register = tg3_vlan_rx_register; @@ -8141,7 +8223,7 @@ spin_lock_init(&tp->indirect_lock); INIT_WORK(&tp->reset_task, tg3_reset_task, tp); - tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len); + tp->regs = ioremap(tg3reg_base, tg3reg_len); if (tp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -8257,6 +8339,9 @@ if (tp->tg3_flags2 & TG3_FLG2_IS_5788) dev->features &= ~NETIF_F_HIGHDMA; + /* flow control autonegotiation is default behavior */ + tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register net device, " @@ -8288,11 +8373,10 @@ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - printk(KERN_INFO "%s: HostTXDS[%d] RXcsums[%d] LinkChgREG[%d] " + printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] " "MIirq[%d] ASF[%d] Split[%d] WireSpeed[%d] " "TSOcap[%d] \n", dev->name, - (tp->tg3_flags & TG3_FLAG_HOST_TXDS) != 0, (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0, @@ -8304,7 +8388,7 @@ return 0; err_out_iounmap: - iounmap((void *) tp->regs); + iounmap(tp->regs); err_out_free_dev: free_netdev(dev); @@ -8326,7 +8410,7 @@ struct tg3 *tp = netdev_priv(dev); unregister_netdev(dev); - iounmap((void *)tp->regs); + iounmap(tp->regs); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -8371,11 +8455,11 @@ tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); - netif_device_attach(dev); tg3_netif_start(tp); + + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); } return err; @@ -8408,10 +8492,10 @@ tg3_enable_ints(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - - tg3_netif_start(tp); return 0; } diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h --- a/drivers/net/tg3.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/net/tg3.h 2004-10-18 14:56:17 -07:00 @@ -124,6 +124,7 @@ #define CHIPREV_ID_5705_A3 0x3003 #define CHIPREV_ID_5750_A0 0x4000 #define CHIPREV_ID_5750_A1 0x4001 +#define CHIPREV_ID_5750_A3 0x4003 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -1548,7 +1549,7 @@ * exist only in the cards on-chip SRAM. All 16 send bds are under * the same mode, they may not be configured individually. * - * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags. + * This driver always uses host memory TX descriptors. * * To use host memory TX descriptors: * 1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register. @@ -1988,7 +1989,7 @@ spinlock_t lock; spinlock_t indirect_lock; - unsigned long regs; + void __iomem *regs; struct net_device *dev; struct pci_dev *pdev; @@ -2004,7 +2005,6 @@ spinlock_t tx_lock; - /* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */ struct tg3_tx_buffer_desc *tx_ring; struct tx_ring_info *tx_buffers; dma_addr_t tx_desc_mapping; @@ -2040,7 +2040,6 @@ u32 rx_offset; u32 tg3_flags; -#define TG3_FLAG_HOST_TXDS 0x00000001 #define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 #define TG3_FLAG_RX_CHECKSUMS 0x00000004 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 @@ -2070,15 +2069,13 @@ #define TG3_FLAG_JUMBO_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 -#define TG3_FLAG_PAUSE_RX 0x04000000 -#define TG3_FLAG_PAUSE_TX 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_SPLIT_MODE 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; #define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_SUN_5704 0x00000002 +#define TG3_FLG2_SUN_570X 0x00000002 #define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004 #define TG3_FLG2_IS_5788 0x00000008 #define TG3_FLG2_MAX_RXPEND_64 0x00000010 @@ -2089,6 +2086,9 @@ #define TG3_FLG2_PCI_EXPRESS 0x00000200 #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 #define TG3_FLG2_HW_AUTONEG 0x00000800 +#define TG3_FLG2_PHY_JUST_INITTED 0x00001000 +#define TG3_FLG2_PHY_SERDES 0x00002000 +#define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2136,7 +2136,6 @@ #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 #define PHY_ID_BCM8002 0x60010140 -#define PHY_ID_SERDES 0xfeedbee0 #define PHY_ID_INVALID 0xffffffff #define PHY_ID_REV_MASK 0x0000000f #define PHY_REV_BCM5401_B0 0x1 @@ -2159,7 +2158,7 @@ (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ - (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES) + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff -Nru a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig --- a/drivers/net/tokenring/Kconfig 2004-10-18 14:56:27 -07:00 +++ b/drivers/net/tokenring/Kconfig 2004-10-18 14:56:27 -07:00 @@ -84,7 +84,8 @@ config TMS380TR tristate "Generic TMS380 Token Ring ISA/PCI adapter support" - depends on TR && (PCI || ISA) + depends on TR && (PCI || ISA) && HOTPLUG + select FW_LOADER ---help--- This driver provides generic support for token ring adapters based on the Texas Instruments TMS380 series chipsets. This diff -Nru a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c --- a/drivers/net/tokenring/ibmtr.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/tokenring/ibmtr.c 2004-10-18 14:56:33 -07:00 @@ -895,7 +895,7 @@ ti->sram_virt &= ~1; /* to reverse what we do in tok_close */ /* init the spinlock */ - ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + ti->lock = SPIN_LOCK_UNLOCKED; init_timer(&ti->tr_timer); i = tok_init_card(dev); diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c --- a/drivers/net/tokenring/olympic.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/tokenring/olympic.c 2004-10-18 14:56:49 -07:00 @@ -221,6 +221,8 @@ olympic_priv = dev->priv ; + spin_lock_init(&olympic_priv->olympic_lock) ; + init_waitqueue_head(&olympic_priv->srb_wait); init_waitqueue_head(&olympic_priv->trb_wait); #if OLYMPIC_DEBUG @@ -291,7 +293,7 @@ static int __devinit olympic_init(struct net_device *dev) { struct olympic_private *olympic_priv; - u8 *olympic_mmio, *init_srb,*adapter_addr; + u8 __iomem *olympic_mmio, *init_srb,*adapter_addr; unsigned long t; unsigned int uaa_addr; @@ -311,7 +313,6 @@ } } - spin_lock_init(&olympic_priv->olympic_lock) ; /* Needed for cardbus */ if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { @@ -435,13 +436,15 @@ static int olympic_open(struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; unsigned long flags, t; char open_error[255] ; int i, open_finished = 1 ; DECLARE_WAITQUEUE(wait,current) ; + olympic_init(dev); + if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) { return -EAGAIN; } @@ -706,10 +709,10 @@ #endif if (olympic_priv->olympic_network_monitor) { - u8 *oat ; - u8 *opt ; - oat = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; - opt = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + u8 __iomem *oat ; + u8 __iomem *opt ; + oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), @@ -755,7 +758,7 @@ static void olympic_rx(struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; struct olympic_rx_status *rx_status; struct olympic_rx_desc *rx_desc ; int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len; @@ -898,7 +901,10 @@ int i; for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); + if (olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received] != NULL) { + dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]); + olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received] = NULL; + } if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { pci_unmap_single(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), @@ -925,9 +931,9 @@ { struct net_device *dev= (struct net_device *)dev_id; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; u32 sisr; - u8 *adapter_check_area ; + u8 __iomem *adapter_check_area ; /* * Read sisr but don't reset it yet. @@ -944,9 +950,6 @@ /* Hotswap gives us this on removal */ if (sisr == 0xffffffff) { printk(KERN_WARNING "%s: Hotswap adapter removal.\n",dev->name) ; - olympic_freemem(dev) ; - free_irq(dev->irq, dev) ; - dev->stop = NULL ; spin_unlock(&olympic_priv->olympic_lock) ; return IRQ_NONE; } @@ -961,9 +964,7 @@ printk(KERN_ERR "The adapter must be reset to clear this condition.\n") ; printk(KERN_ERR "Please report this error to the driver maintainer and/\n") ; printk(KERN_ERR "or the linux-tr mailing list.\n") ; - olympic_freemem(dev) ; - free_irq(dev->irq, dev) ; - dev->stop = NULL ; + wake_up_interruptible(&olympic_priv->srb_wait); spin_unlock(&olympic_priv->olympic_lock) ; return IRQ_HANDLED; } /* SISR_ERR */ @@ -1006,9 +1007,6 @@ writel(readl(olympic_mmio+LAPWWC),olympic_mmio+LAPA); adapter_check_area = olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWC)) & (~0xf800)) ; printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; - olympic_freemem(dev) ; - free_irq(dev->irq, dev) ; - dev->stop = NULL ; spin_unlock(&olympic_priv->olympic_lock) ; return IRQ_HANDLED; } /* SISR_ADAPTER_CHECK */ @@ -1049,7 +1047,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; unsigned long flags ; spin_lock_irqsave(&olympic_priv->olympic_lock, flags); @@ -1080,7 +1078,7 @@ static int olympic_close(struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb; unsigned long t,flags; DECLARE_WAITQUEUE(wait,current) ; @@ -1094,34 +1092,32 @@ writeb(0,srb+1); writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + add_wait_queue(&olympic_priv->srb_wait,&wait) ; + set_current_state(TASK_INTERRUPTIBLE) ; + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - - t = jiffies ; - - add_wait_queue(&olympic_priv->srb_wait,&wait) ; - set_current_state(TASK_INTERRUPTIBLE) ; while(olympic_priv->srb_queued) { - schedule() ; + + t = schedule_timeout(60*HZ); + if(signal_pending(current)) { printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR)); olympic_priv->srb_queued=0; break; } - if ((jiffies-t) > 60*HZ) { + + if (t == 0) { printk(KERN_WARNING "%s: SRB timed out. May not be fatal. \n",dev->name) ; - olympic_priv->srb_queued=0; - break ; } - set_current_state(TASK_INTERRUPTIBLE) ; + olympic_priv->srb_queued=0; } remove_wait_queue(&olympic_priv->srb_wait,&wait) ; - set_current_state(TASK_RUNNING) ; olympic_priv->rx_status_last_received++; olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; @@ -1152,9 +1148,9 @@ static void olympic_set_rx_mode(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; - u8 *olympic_mmio = olympic_priv->olympic_mmio ; + u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; u8 options = 0; - u8 *srb; + u8 __iomem *srb; struct dev_mc_list *dmi ; unsigned char dev_mc_address[4] ; int i ; @@ -1220,8 +1216,8 @@ static void olympic_srb_bh(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; - u8 *olympic_mmio = olympic_priv->olympic_mmio ; - u8 *srb; + u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; + u8 __iomem *srb; writel(olympic_priv->srb,olympic_mmio+LAPA); srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); @@ -1394,22 +1390,22 @@ static void olympic_arb_cmd(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; - u8 *arb_block, *asb_block, *srb ; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *arb_block, *asb_block, *srb ; u8 header_len ; u16 frame_len, buffer_len ; struct sk_buff *mac_frame ; - u8 *buf_ptr ; - u8 *frame_data ; + u8 __iomem *buf_ptr ; + u8 __iomem *frame_data ; u16 buff_off ; u16 lan_status = 0, lan_status_diff ; /* Initialize to stop compiler warning */ u8 fdx_prot_error ; u16 next_ptr; int i ; - arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; - asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; - srb = (u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; + arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (olympic_priv->olympic_lap + olympic_priv->asb) ; + srb = (olympic_priv->olympic_lap + olympic_priv->srb) ; if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ @@ -1513,29 +1509,6 @@ writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); netif_stop_queue(dev); olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; - for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); - if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { - pci_unmap_single(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), - olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); - } - olympic_priv->rx_status_last_received++; - olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; - } - /* unmap rings */ - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, - sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr, - sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); - - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, - sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, - sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE); - - free_irq(dev->irq,dev); - dev->stop=NULL; printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; } /* If serious error */ @@ -1604,10 +1577,10 @@ static void olympic_asb_bh(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; - u8 *arb_block, *asb_block ; + u8 __iomem *arb_block, *asb_block ; - arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; - asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; + arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (olympic_priv->olympic_lap + olympic_priv->asb) ; if (olympic_priv->asb_queued == 1) { /* Dropped through the first time */ @@ -1666,8 +1639,8 @@ { struct net_device *dev = (struct net_device *)data ; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *oat = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; - u8 *opt = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; int size = 0 ; int len=0; off_t begin=0; diff -Nru a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h --- a/drivers/net/tokenring/olympic.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/tokenring/olympic.h 2004-10-18 14:57:04 -07:00 @@ -251,8 +251,8 @@ u16 arb; /* be16 */ u16 asb; /* be16 */ - u8 *olympic_mmio; - u8 *olympic_lap; + u8 __iomem *olympic_mmio; + u8 __iomem *olympic_lap; struct pci_dev *pdev ; char *olympic_card_name ; diff -Nru a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig --- a/drivers/net/tulip/Kconfig 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/tulip/Kconfig 2004-10-18 14:56:49 -07:00 @@ -40,9 +40,7 @@ (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type will say Y here.) Do read the Ethernet-HOWTO, available from - . More specific - information is contained in - . + . To compile this driver as a module, choose M here and read . The module will diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/tulip/de4x5.c 2004-10-18 14:55:54 -07:00 @@ -1141,7 +1141,7 @@ lp->asBitValid = TRUE; lp->timeout = -1; lp->gendev = gendev; - lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + lp->lock = SPIN_LOCK_UNLOCKED; init_timer(&lp->timer); de4x5_parse_params(dev); @@ -1316,7 +1316,7 @@ ** Re-initialize the DE4X5... */ status = de4x5_init(dev); - lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + lp->lock = SPIN_LOCK_UNLOCKED; lp->state = OPEN; de4x5_dbg_open(dev); @@ -2242,8 +2242,13 @@ return -ENODEV; /* Ok, the device seems to be for us. */ - if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) - return -ENOMEM; + if (pci_enable_device (pdev)) + return -ENODEV; + + if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) { + error = -ENOMEM; + goto disable_dev; + } lp = netdev_priv(dev); lp->bus = PCI; @@ -2327,6 +2332,8 @@ release_region (iobase, DE4X5_PCI_TOTAL_SIZE); free_dev: free_netdev (dev); + disable_dev: + pci_disable_device (pdev); return error; } @@ -2341,6 +2348,7 @@ unregister_netdev (dev); free_netdev (dev); release_region (iobase, DE4X5_PCI_TOTAL_SIZE); + pci_disable_device (pdev); } static struct pci_device_id de4x5_pci_tbl[] = { diff -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c --- a/drivers/net/tulip/dmfe.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/net/tulip/dmfe.c 2004-10-18 14:57:03 -07:00 @@ -314,13 +314,13 @@ static u8 dmfe_sense_speed(struct dmfe_board_info *); static void dmfe_process_mode(struct dmfe_board_info *); static void dmfe_timer(unsigned long); +static inline u32 cal_CRC(unsigned char *, unsigned int, u8); static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *); static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *); static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *); static void dmfe_dynamic_reset(struct DEVICE *); static void dmfe_free_rxbuffer(struct dmfe_board_info *); static void dmfe_init_dm910x(struct DEVICE *); -static inline u32 cal_CRC(unsigned char *, unsigned int, u8); static void dmfe_parse_srom(struct dmfe_board_info *); static void dmfe_program_DM9801(struct dmfe_board_info *, int); static void dmfe_program_DM9802(struct dmfe_board_info *); @@ -885,6 +885,20 @@ /* + * Calculate the CRC valude of the Rx packet + * flag = 1 : return the reverse CRC (for the received packet CRC) + * 0 : return the normal CRC (for Hash Table index) + */ + +static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) +{ + u32 crc = crc32(~0, Data, Len); + if (flag) crc = ~crc; + return crc; +} + + +/* * Receive the come packet and pass to upper layer */ @@ -1770,20 +1784,6 @@ udelay(1); return phy_data; -} - - -/* - * Calculate the CRC valude of the Rx packet - * flag = 1 : return the reverse CRC (for the received packet CRC) - * 0 : return the normal CRC (for Hash Table index) - */ - -static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) -{ - u32 crc = crc32(~0, Data, Len); - if (flag) crc = ~crc; - return crc; } diff -Nru a/drivers/net/typhoon.c b/drivers/net/typhoon.c --- a/drivers/net/typhoon.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/net/typhoon.c 2004-10-18 14:56:33 -07:00 @@ -248,11 +248,11 @@ /* Tx cache line section */ struct transmit_ring txLoRing ____cacheline_aligned; struct pci_dev * tx_pdev; - unsigned long tx_ioaddr; + void __iomem *tx_ioaddr; u32 txlo_dma_addr; /* Irq/Rx cache line section */ - unsigned long ioaddr ____cacheline_aligned; + void __iomem *ioaddr ____cacheline_aligned; struct typhoon_indexes *indexes; u8 awaiting_resp; u8 duplex; @@ -373,7 +373,7 @@ } static int -typhoon_reset(unsigned long ioaddr, int wait_type) +typhoon_reset(void __iomem *ioaddr, int wait_type) { int i, err = 0; int timeout; @@ -428,7 +428,7 @@ } static int -typhoon_wait_status(unsigned long ioaddr, u32 wait_value) +typhoon_wait_status(void __iomem *ioaddr, u32 wait_value) { int i, err = 0; @@ -1240,7 +1240,7 @@ } static int -typhoon_wait_interrupt(unsigned long ioaddr) +typhoon_wait_interrupt(void __iomem *ioaddr) { int i, err = 0; @@ -1348,7 +1348,7 @@ static int typhoon_download_firmware(struct typhoon *tp) { - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct pci_dev *pdev = tp->pdev; struct typhoon_file_header *fHdr; struct typhoon_section_header *sHdr; @@ -1497,7 +1497,7 @@ static int typhoon_boot_3XP(struct typhoon *tp, u32 initial_status) { - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; if(typhoon_wait_status(ioaddr, initial_status) < 0) { printk(KERN_ERR "%s: boot ready timeout\n", tp->name); @@ -1812,7 +1812,8 @@ typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *) dev_instance; - unsigned long ioaddr = dev->base_addr; + struct typhoon *tp = dev->priv; + void __iomem *ioaddr = tp->ioaddr; u32 intr_status; intr_status = readl(ioaddr + TYPHOON_REG_INTR_STATUS); @@ -1852,7 +1853,7 @@ typhoon_sleep(struct typhoon *tp, int state, u16 events) { struct pci_dev *pdev = tp->pdev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int err; @@ -1890,7 +1891,7 @@ typhoon_wakeup(struct typhoon *tp, int wait_type) { struct pci_dev *pdev = tp->pdev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; pci_set_power_state(pdev, 0); pci_restore_state(pdev, tp->pci_state); @@ -1911,7 +1912,7 @@ typhoon_start_runtime(struct typhoon *tp) { struct net_device *dev = tp->dev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int err; @@ -2006,7 +2007,7 @@ { struct typhoon_indexes *indexes = tp->indexes; struct transmit_ring *txLo = &tp->txLoRing; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int i; @@ -2070,7 +2071,7 @@ { struct typhoon *tp = (struct typhoon *) dev->priv; - if(typhoon_reset(dev->base_addr, WaitNoSleep) < 0) { + if(typhoon_reset(tp->ioaddr, WaitNoSleep) < 0) { printk(KERN_WARNING "%s: could not reset in tx timeout\n", dev->name); goto truely_dead; @@ -2091,7 +2092,7 @@ truely_dead: /* Reset the hardware, and turn off carrier to avoid more timeouts */ - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); netif_carrier_off(dev); } @@ -2126,7 +2127,7 @@ if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) { printk(KERN_ERR "%s: unable to reboot into sleep img\n", dev->name); - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); goto out; } @@ -2192,7 +2193,7 @@ return 0; reset: - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); return -EBUSY; } @@ -2276,6 +2277,7 @@ struct typhoon *tp; int card_id = (int) ent->driver_data; unsigned long ioaddr; + void __iomem *ioaddr_mapped; void *shared; dma_addr_t shared_dma; struct cmd_desc xp_cmd; @@ -2345,14 +2347,13 @@ /* map our MMIO region */ ioaddr = pci_resource_start(pdev, 1); - ioaddr = (unsigned long) ioremap(ioaddr, 128); - if(!ioaddr) { + ioaddr_mapped = ioremap(ioaddr, 128); + if (!ioaddr_mapped) { printk(ERR_PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev)); err = -EIO; goto error_out_regions; } - dev->base_addr = ioaddr; /* allocate pci dma space for rx and tx descriptor rings */ @@ -2371,8 +2372,8 @@ tp->shared_dma = shared_dma; tp->pdev = pdev; tp->tx_pdev = pdev; - tp->ioaddr = dev->base_addr; - tp->tx_ioaddr = dev->base_addr; + tp->ioaddr = ioaddr_mapped; + tp->tx_ioaddr = ioaddr_mapped; tp->dev = dev; /* need to be able to restore PCI state after a suspend */ @@ -2385,7 +2386,7 @@ * 4) Get the hardware address. * 5) Put the card to sleep. */ - if(typhoon_reset(ioaddr, WaitSleep) < 0) { + if (typhoon_reset(ioaddr_mapped, WaitSleep) < 0) { printk(ERR_PFX "%s: could not reset 3XP\n", pci_name(pdev)); err = -EIO; goto error_out_dma; @@ -2518,13 +2519,13 @@ return 0; error_out_reset: - typhoon_reset(ioaddr, NoWait); + typhoon_reset(ioaddr_mapped, NoWait); error_out_dma: pci_free_consistent(pdev, sizeof(struct typhoon_shared), shared, shared_dma); error_out_remap: - iounmap((void *) ioaddr); + iounmap(ioaddr_mapped); error_out_regions: pci_release_regions(pdev); error_out_dev: @@ -2542,8 +2543,8 @@ unregister_netdev(dev); pci_set_power_state(pdev, 0); pci_restore_state(pdev, tp->pci_state); - typhoon_reset(dev->base_addr, NoWait); - iounmap((char *) (dev->base_addr)); + typhoon_reset(tp->ioaddr, NoWait); + iounmap(tp->ioaddr); pci_free_consistent(pdev, sizeof(struct typhoon_shared), tp->shared, tp->shared_dma); pci_release_regions(pdev); diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/via-rhine.c 2004-10-18 14:57:04 -07:00 @@ -125,11 +125,16 @@ LK1.1.19 (Roger Luethi) - Increase Tx threshold for unspecified errors + LK1.2.0-2.6 (Roger Luethi) + - Massive clean-up + - Rewrite PHY, media handling (remove options, full_duplex, backoff) + - Fix Tx engine race for good + */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.1.20-2.6" -#define DRV_RELDATE "May-23-2004" +#define DRV_VERSION "1.2.0-2.6" +#define DRV_RELDATE "June-10-2004" /* A few user-configurable values. @@ -142,22 +147,10 @@ Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; -/* Select a backoff algorithm (Ethernet capture effect) */ -static int backoff; - -/* Used to pass the media type, etc. - Both 'options[]' and 'full_duplex[]' should exist for driver - interoperability. - The media type is usually passed in 'options[]'. - The default is autonegotiation for speed and duplex. - This should rarely be overridden. - Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps. - Use option values 0x10 and 0x100 for forcing half duplex fixed speed. - Use option values 0x20 and 0x200 for forcing full duplex operation. -*/ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* + * In case you are looking for 'options[]' or 'full_duplex[]', they + * are gone. Use ethtool(8) instead. + */ /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Rhine has a 64 element 8390-like hash table. */ @@ -210,9 +203,6 @@ static char version[] __devinitdata = KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"; -static char shortname[] = DRV_NAME; - - /* This driver was written to use PCI memory space. Some early versions of the Rhine may only work correctly with I/O space accesses. */ #ifdef CONFIG_VIA_RHINE_MMIO @@ -239,15 +229,9 @@ MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(backoff, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm"); -MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex"); -MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)"); /* Theory of Operation @@ -350,24 +334,24 @@ enum rhine_revs { VT86C100A = 0x00, + VTunknown0 = 0x20, VT6102 = 0x40, VT8231 = 0x50, /* Integrated MAC */ VT8233 = 0x60, /* Integrated MAC */ VT8235 = 0x74, /* Integrated MAC */ VT8237 = 0x78, /* Integrated MAC */ - VTunknown0 = 0x7C, + VTunknown1 = 0x7C, VT6105 = 0x80, VT6105_B0 = 0x83, VT6105L = 0x8A, VT6107 = 0x8C, - VTunknown1 = 0x8E, - VT6105M = 0x90, + VTunknown2 = 0x8E, + VT6105M = 0x90, /* Management adapter */ }; enum rhine_quirks { rqWOL = 0x0001, /* Wake-On-LAN support */ rqForceReset = 0x0002, - rqDavicomPhy = 0x0020, rq6patterns = 0x0040, /* 6 instead of 4 patterns for WOL */ rqStatusWBRace = 0x0080, /* Tx Status Writeback Error possible */ rqRhineI = 0x0100, /* See comment below */ @@ -395,6 +379,7 @@ /* Offsets to the device registers. */ enum register_offsets { StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, + ChipCmd1=0x09, IntrStatus=0x0C, IntrEnable=0x0E, MulticastFilter0=0x10, MulticastFilter1=0x14, RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, @@ -403,8 +388,8 @@ ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81, StickyHW=0x83, IntrStatus2=0x84, - WOLcrSet=0xA0, WOLcrClr=0xA4, WOLcrClr1=0xA6, - WOLcgClr=0xA7, + WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4, + WOLcrClr1=0xA6, WOLcgClr=0xA7, PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD, }; @@ -436,6 +421,15 @@ IntrTxErrSummary=0x082218, }; +/* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */ +enum wol_bits { + WOLucast = 0x10, + WOLmagic = 0x20, + WOLbmcast = 0x30, + WOLlnkon = 0x40, + WOLlnkoff = 0x80, +}; + /* The Rx and Tx buffer descriptors. */ struct rx_desc { s32 rx_status; @@ -464,13 +458,12 @@ /* Bits in ChipCmd. */ enum chip_cmd_bits { - CmdInit=0x0001, CmdStart=0x0002, CmdStop=0x0004, CmdRxOn=0x0008, - CmdTxOn=0x0010, CmdTxDemand=0x0020, CmdRxDemand=0x0040, - CmdEarlyRx=0x0100, CmdEarlyTx=0x0200, CmdFDuplex=0x0400, - CmdNoTxPoll=0x0800, CmdReset=0x8000, + CmdInit=0x01, CmdStart=0x02, CmdStop=0x04, CmdRxOn=0x08, + CmdTxOn=0x10, Cmd1TxDemand=0x20, CmdRxDemand=0x40, + Cmd1EarlyRx=0x01, Cmd1EarlyTx=0x02, Cmd1FDuplex=0x04, + Cmd1NoTxPoll=0x08, Cmd1Reset=0x80, }; -#define MAX_MII_CNT 4 struct rhine_private { /* Descriptor rings */ struct rx_desc *rx_ring; @@ -492,8 +485,8 @@ dma_addr_t tx_bufs_dma; struct pci_dev *pdev; + long pioaddr; struct net_device_stats stats; - struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ @@ -502,23 +495,16 @@ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ - u16 chip_cmd; /* Current setting for ChipCmd */ + u8 wolopts; - /* These values are keep track of the transceiver/media in use. */ u8 tx_thresh, rx_thresh; - /* MII transceiver section. */ - unsigned char phys[MAX_MII_CNT]; /* MII device addresses. */ - unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ - u16 mii_status; /* last read MII status */ struct mii_if_info mii_if; }; static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); -static void rhine_check_duplex(struct net_device *dev); -static void rhine_timer(unsigned long data); static void rhine_tx_timeout(struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); @@ -530,6 +516,16 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; static int rhine_close(struct net_device *dev); +static void rhine_shutdown (struct device *gdev); + +#define RHINE_WAIT_FOR(condition) do { \ + int i=1024; \ + while (!(condition) && --i) \ + ; \ + if (debug > 1 && i < 512) \ + printk(KERN_INFO "%s: %4d cycles used @ %s:%d\n", \ + DRV_NAME, 1024-i, __func__, __LINE__); \ +} while(0) static inline u32 get_intr_status(struct net_device *dev) { @@ -546,12 +542,13 @@ /* * Get power related registers into sane state. - * Returns content of power-event (WOL) registers. + * Notify user about past WOL event. */ static void rhine_power_init(struct net_device *dev) { long ioaddr = dev->base_addr; struct rhine_private *rp = netdev_priv(dev); + u16 wolstat; if (rp->quirks & rqWOL) { /* Make sure chip is in power state D0 */ @@ -566,63 +563,109 @@ if (rp->quirks & rq6patterns) writeb(0x03, ioaddr + WOLcrClr1); + /* Save power-event status bits */ + wolstat = readb(ioaddr + PwrcsrSet); + if (rp->quirks & rq6patterns) + wolstat |= (readb(ioaddr + PwrcsrSet1) & 0x03) << 8; + /* Clear power-event status bits */ writeb(0xFF, ioaddr + PwrcsrClr); if (rp->quirks & rq6patterns) writeb(0x03, ioaddr + PwrcsrClr1); + + if (wolstat) { + char *reason; + switch (wolstat) { + case WOLmagic: + reason = "Magic packet"; + break; + case WOLlnkon: + reason = "Link went up"; + break; + case WOLlnkoff: + reason = "Link went down"; + break; + case WOLucast: + reason = "Unicast packet"; + break; + case WOLbmcast: + reason = "Multicast/broadcast packet"; + break; + default: + reason = "Unknown"; + } + printk(KERN_INFO "%s: Woke system up. Reason: %s.\n", + DRV_NAME, reason); + } } } -static void wait_for_reset(struct net_device *dev, u32 quirks, char *name) +static void rhine_chip_reset(struct net_device *dev) { long ioaddr = dev->base_addr; - int boguscnt = 20; + struct rhine_private *rp = netdev_priv(dev); + writeb(Cmd1Reset, ioaddr + ChipCmd1); IOSYNC; - if (readw(ioaddr + ChipCmd) & CmdReset) { + if (readb(ioaddr + ChipCmd1) & Cmd1Reset) { printk(KERN_INFO "%s: Reset not complete yet. " - "Trying harder.\n", name); + "Trying harder.\n", DRV_NAME); - /* Rhine-II needs to be forced sometimes */ - if (quirks & rqForceReset) + /* Force reset */ + if (rp->quirks & rqForceReset) writeb(0x40, ioaddr + MiscCmd); - /* VT86C100A may need long delay after reset (dlink) */ - /* Seen on Rhine-II as well (rl) */ - while ((readw(ioaddr + ChipCmd) & CmdReset) && --boguscnt) - udelay(5); - + /* Reset can take somewhat longer (rare) */ + RHINE_WAIT_FOR(!(readb(ioaddr + ChipCmd1) & Cmd1Reset)); } if (debug > 1) - printk(KERN_INFO "%s: Reset %s.\n", name, - boguscnt ? "succeeded" : "failed"); + printk(KERN_INFO "%s: Reset %s.\n", dev->name, + (readb(ioaddr + ChipCmd1) & Cmd1Reset) ? + "failed" : "succeeded"); } #ifdef USE_MMIO -static void __devinit enable_mmio(long ioaddr, u32 quirks) +static void __devinit enable_mmio(long pioaddr, u32 quirks) { int n; if (quirks & rqRhineI) { /* More recent docs say that this bit is reserved ... */ - n = inb(ioaddr + ConfigA) | 0x20; - outb(n, ioaddr + ConfigA); + n = inb(pioaddr + ConfigA) | 0x20; + outb(n, pioaddr + ConfigA); } else { - n = inb(ioaddr + ConfigD) | 0x80; - outb(n, ioaddr + ConfigD); + n = inb(pioaddr + ConfigD) | 0x80; + outb(n, pioaddr + ConfigD); } } #endif -static void __devinit reload_eeprom(long ioaddr) +/* + * Loads bytes 0x00-0x05, 0x6E-0x6F, 0x78-0x7B from EEPROM + * (plus 0x6C for Rhine-I/II) + */ +static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev) { - int i; - outb(0x20, ioaddr + MACRegEEcsr); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (inb(ioaddr + MACRegEEcsr) & 0x20)) - break; + long ioaddr = dev->base_addr; + struct rhine_private *rp = netdev_priv(dev); + + outb(0x20, pioaddr + MACRegEEcsr); + RHINE_WAIT_FOR(!(inb(pioaddr + MACRegEEcsr) & 0x20)); + +#ifdef USE_MMIO + /* + * Reloading from EEPROM overwrites ConfigA-D, so we must re-enable + * MMIO. If reloading EEPROM was done first this could be avoided, but + * it is not known if that still works with the "win98-reboot" problem. + */ + enable_mmio(pioaddr, rp->quirks); +#endif + + /* Turn off EEPROM-controlled wake-up (magic packet) */ + if (rp->quirks & rqWOL) + writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); + } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -634,22 +677,33 @@ } #endif +static void rhine_hw_init(struct net_device *dev, long pioaddr) +{ + struct rhine_private *rp = netdev_priv(dev); + + /* Reset the chip to erase previous misconfiguration. */ + rhine_chip_reset(dev); + + /* Rhine-I needs extra time to recuperate before EEPROM reload */ + if (rp->quirks & rqRhineI) + msleep(5); + + /* Reload EEPROM controlled bytes cleared by soft reset */ + rhine_reload_eeprom(pioaddr, dev); +} + static int __devinit rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; struct rhine_private *rp; - int i, option, rc; + int i, rc; u8 pci_rev; u32 quirks; - static int card_idx = -1; - long ioaddr; + long pioaddr; long memaddr; - int io_size; - int phy, phy_idx = 0; -#ifdef USE_MMIO - long ioaddr0; -#endif + long ioaddr; + int io_size, phy_id; const char *name; /* when built into the kernel, we only print version if device is found */ @@ -659,26 +713,30 @@ printk(version); #endif - card_idx++; - option = card_idx < MAX_UNITS ? options[card_idx] : 0; pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); io_size = 256; - if (pci_rev < VT6102) { - quirks = rqRhineI | rqDavicomPhy; + phy_id = 0; + quirks = 0; + name = "Rhine"; + if (pci_rev < VTunknown0) { + quirks = rqRhineI; io_size = 128; - name = "VT86C100A Rhine"; } - else { + else if (pci_rev >= VT6102) { quirks = rqWOL | rqForceReset; if (pci_rev < VT6105) { name = "Rhine II"; quirks |= rqStatusWBRace; /* Rhine-II exclusive */ } else { - name = "Rhine III"; + phy_id = 1; /* Integrated PHY, phy_id fixed to 1 */ if (pci_rev >= VT6105_B0) quirks |= rq6patterns; + if (pci_rev < VT6105M) + name = "Rhine III"; + else + name = "Rhine III (Management Adapter)"; } } @@ -702,28 +760,31 @@ goto err_out; } - ioaddr = pci_resource_start(pdev, 0); + pioaddr = pci_resource_start(pdev, 0); memaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); - dev = alloc_etherdev(sizeof(*rp)); - if (dev == NULL) { + dev = alloc_etherdev(sizeof(struct rhine_private)); + if (!dev) { rc = -ENOMEM; - printk(KERN_ERR "init_ethernet failed for card #%d\n", - card_idx); + printk(KERN_ERR "alloc_etherdev failed\n"); goto err_out; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - rc = pci_request_regions(pdev, shortname); + rp = netdev_priv(dev); + rp->quirks = quirks; + rp->pioaddr = pioaddr; + rp->pdev = pdev; + + rc = pci_request_regions(pdev, DRV_NAME); if (rc) goto err_out_free_netdev; #ifdef USE_MMIO - ioaddr0 = ioaddr; - enable_mmio(ioaddr0, quirks); + enable_mmio(pioaddr, quirks); ioaddr = (long) ioremap(memaddr, io_size); if (!ioaddr) { @@ -737,7 +798,7 @@ i = 0; while (mmio_verify_registers[i]) { int reg = mmio_verify_registers[i++]; - unsigned char a = inb(ioaddr0+reg); + unsigned char a = inb(pioaddr+reg); unsigned char b = readb(ioaddr+reg); if (a != b) { rc = -EIO; @@ -746,65 +807,38 @@ goto err_out_unmap; } } +#else + ioaddr = pioaddr; #endif /* USE_MMIO */ + dev->base_addr = ioaddr; - rp = netdev_priv(dev); - rp->quirks = quirks; + /* Get chip registers into a sane state */ rhine_power_init(dev); - - /* Reset the chip to erase previous misconfiguration. */ - writew(CmdReset, ioaddr + ChipCmd); - - wait_for_reset(dev, quirks, shortname); - - /* Reload the station address from the EEPROM. */ -#ifdef USE_MMIO - reload_eeprom(ioaddr0); - /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO. - If reload_eeprom() was done first this could be avoided, but it is - not known if that still works with the "win98-reboot" problem. */ - enable_mmio(ioaddr0, quirks); -#else - reload_eeprom(ioaddr); -#endif + rhine_hw_init(dev, pioaddr); for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); if (!is_valid_ether_addr(dev->dev_addr)) { rc = -EIO; - printk(KERN_ERR "Invalid MAC address for card #%d\n", card_idx); + printk(KERN_ERR "Invalid MAC address\n"); goto err_out_unmap; } - if (quirks & rqWOL) { - /* - * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA - * turned on. it makes MAC receive magic packet - * automatically. So, we turn it off. (D-Link) - */ - writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); - } - - /* Select backoff algorithm */ - if (backoff) - writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff), - ioaddr + ConfigD); + /* For Rhine-I/II, phy_id is loaded from EEPROM */ + if (!phy_id) + phy_id = readb(ioaddr + 0x6C); dev->irq = pdev->irq; spin_lock_init(&rp->lock); - rp->pdev = pdev; rp->mii_if.dev = dev; rp->mii_if.mdio_read = mdio_read; rp->mii_if.mdio_write = mdio_write; rp->mii_if.phy_id_mask = 0x1f; rp->mii_if.reg_num_mask = 0x1f; - if (dev->mem_start) - option = dev->mem_start; - /* The chip-specific entries in the device structure. */ dev->open = rhine_open; dev->hard_start_xmit = rhine_start_tx; @@ -826,20 +860,6 @@ if (rc) goto err_out_unmap; - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x220) - rp->mii_if.full_duplex = 1; - } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - rp->mii_if.full_duplex = 1; - - if (rp->mii_if.full_duplex) { - printk(KERN_INFO "%s: Set to forced full duplex, " - "autonegotiation disabled.\n", dev->name); - rp->mii_if.force_media = 1; - } - printk(KERN_INFO "%s: VIA %s at 0x%lx, ", dev->name, name, #ifdef USE_MMIO @@ -855,17 +875,18 @@ pci_set_drvdata(pdev, dev); - rp->phys[0] = 1; /* Standard for this chip. */ - for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, 1); + { + u16 mii_cmd; + int mii_status = mdio_read(dev, phy_id, 1); + mii_cmd = mdio_read(dev, phy_id, MII_BMCR) & ~BMCR_ISOLATE; + mdio_write(dev, phy_id, MII_BMCR, mii_cmd); if (mii_status != 0xffff && mii_status != 0x0000) { - rp->phys[phy_idx++] = phy; - rp->mii_if.advertising = mdio_read(dev, phy, 4); + rp->mii_if.advertising = mdio_read(dev, phy_id, 4); printk(KERN_INFO "%s: MII PHY found at address " "%d, status 0x%4.4x advertising %4.4x " - "Link %4.4x.\n", dev->name, phy, + "Link %4.4x.\n", dev->name, phy_id, mii_status, rp->mii_if.advertising, - mdio_read(dev, phy, 5)); + mdio_read(dev, phy_id, 5)); /* set IFF_RUNNING */ if (mii_status & BMSR_LSTATUS) @@ -873,27 +894,9 @@ else netif_carrier_off(dev); - break; - } - } - rp->mii_cnt = phy_idx; - rp->mii_if.phy_id = rp->phys[0]; - - /* Allow forcing the media type. */ - if (option > 0) { - if (option & 0x220) - rp->mii_if.full_duplex = 1; - if (option & 0x330) { - printk(KERN_INFO " Forcing %dMbs %s-duplex " - "operation.\n", - (option & 0x300 ? 100 : 10), - (option & 0x220 ? "full" : "half")); - if (rp->mii_cnt) - mdio_write(dev, rp->phys[0], MII_BMCR, - ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ - ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */ } } + rp->mii_if.phy_id = phy_id; return 0; @@ -1065,6 +1068,21 @@ } } +static void rhine_check_media(struct net_device *dev, unsigned int init_media) +{ + struct rhine_private *rp = netdev_priv(dev); + long ioaddr = dev->base_addr; + + mii_check_media(&rp->mii_if, debug, init_media); + + if (rp->mii_if.full_duplex) + writeb(readb(ioaddr + ChipCmd1) | Cmd1FDuplex, + ioaddr + ChipCmd1); + else + writeb(readb(ioaddr + ChipCmd1) & ~Cmd1FDuplex, + ioaddr + ChipCmd1); +} + static void init_registers(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1080,7 +1098,6 @@ writeb(0x20, ioaddr + TxConfig); rp->tx_thresh = 0x20; rp->rx_thresh = 0x60; /* Written in rhine_set_rx_mode(). */ - rp->mii_if.full_duplex = 0; writel(rp->rx_ring_dma, ioaddr + RxRingPtr); writel(rp->tx_ring_dma, ioaddr + TxRingPtr); @@ -1094,17 +1111,44 @@ IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - rp->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; - if (rp->mii_if.force_media) - rp->chip_cmd |= CmdFDuplex; - writew(rp->chip_cmd, ioaddr + ChipCmd); - - rhine_check_duplex(dev); - - /* The LED outputs of various MII xcvrs should be configured. */ - /* For NS or Mison phys, turn on bit 1 in register 0x17 */ - mdio_write(dev, rp->phys[0], 0x17, mdio_read(dev, rp->phys[0], 0x17) | - 0x0001); + writew(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8), + ioaddr + ChipCmd); + rhine_check_media(dev, 1); +} + +/* Enable MII link status auto-polling (required for IntrLinkChange) */ +static void rhine_enable_linkmon(long ioaddr) +{ + writeb(0, ioaddr + MIICmd); + writeb(MII_BMSR, ioaddr + MIIRegAddr); + writeb(0x80, ioaddr + MIICmd); + + RHINE_WAIT_FOR((readb(ioaddr + MIIRegAddr) & 0x20)); + + writeb(MII_BMSR | 0x40, ioaddr + MIIRegAddr); +} + +/* Disable MII link status auto-polling (required for MDIO access) */ +static void rhine_disable_linkmon(long ioaddr, u32 quirks) +{ + writeb(0, ioaddr + MIICmd); + + if (quirks & rqRhineI) { + writeb(0x01, ioaddr + MIIRegAddr); // MII_BMSR + + /* Can be called from ISR. Evil. */ + mdelay(1); + + /* 0x80 must be set immediately before turning it off */ + writeb(0x80, ioaddr + MIICmd); + + RHINE_WAIT_FOR(readb(ioaddr + MIIRegAddr) & 0x20); + + /* Heh. Now clear 0x80 again. */ + writeb(0, ioaddr + MIICmd); + } + else + RHINE_WAIT_FOR(readb(ioaddr + MIIRegAddr) & 0x80); } /* Read and write over the MII Management Data I/O (MDIO) interface. */ @@ -1112,156 +1156,72 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum) { long ioaddr = dev->base_addr; - int boguscnt = 1024; + struct rhine_private *rp = netdev_priv(dev); + int result; + + rhine_disable_linkmon(ioaddr, rp->quirks); - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); + /* rhine_disable_linkmon already cleared MIICmd */ writeb(phy_id, ioaddr + MIIPhyAddr); writeb(regnum, ioaddr + MIIRegAddr); writeb(0x40, ioaddr + MIICmd); /* Trigger read */ - boguscnt = 1024; - while ((readb(ioaddr + MIICmd) & 0x40) && --boguscnt > 0) - ; - return readw(ioaddr + MIIData); + RHINE_WAIT_FOR(!(readb(ioaddr + MIICmd) & 0x40)); + result = readw(ioaddr + MIIData); + + rhine_enable_linkmon(ioaddr); + return result; } static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) { struct rhine_private *rp = netdev_priv(dev); long ioaddr = dev->base_addr; - int boguscnt = 1024; - if (phy_id == rp->phys[0]) { - switch (regnum) { - case MII_BMCR: /* Is user forcing speed/duplex? */ - if (value & 0x9000) /* Autonegotiation. */ - rp->mii_if.force_media = 0; - else - rp->mii_if.full_duplex = (value & 0x0100) ? 1 : 0; - break; - case MII_ADVERTISE: - rp->mii_if.advertising = value; - break; - } - } + rhine_disable_linkmon(ioaddr, rp->quirks); - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); + /* rhine_disable_linkmon already cleared MIICmd */ writeb(phy_id, ioaddr + MIIPhyAddr); writeb(regnum, ioaddr + MIIRegAddr); writew(value, ioaddr + MIIData); - writeb(0x20, ioaddr + MIICmd); /* Trigger write. */ -} + writeb(0x20, ioaddr + MIICmd); /* Trigger write */ + RHINE_WAIT_FOR(!(readb(ioaddr + MIICmd) & 0x20)); + rhine_enable_linkmon(ioaddr); +} static int rhine_open(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); long ioaddr = dev->base_addr; - int i; - - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); + int rc; - i = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name, + rc = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name, dev); - if (i) - return i; + if (rc) + return rc; if (debug > 1) printk(KERN_DEBUG "%s: rhine_open() irq %d.\n", dev->name, rp->pdev->irq); - i = alloc_ring(dev); - if (i) - return i; + rc = alloc_ring(dev); + if (rc) + return rc; alloc_rbufs(dev); alloc_tbufs(dev); - wait_for_reset(dev, rp->quirks, dev->name); + rhine_chip_reset(dev); init_registers(dev); if (debug > 2) printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x " "MII status: %4.4x.\n", dev->name, readw(ioaddr + ChipCmd), - mdio_read(dev, rp->phys[0], MII_BMSR)); + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); netif_start_queue(dev); - /* Set the timer to check for link beat. */ - init_timer(&rp->timer); - rp->timer.expires = jiffies + 2 * HZ/100; - rp->timer.data = (unsigned long)dev; - rp->timer.function = &rhine_timer; /* timer handler */ - add_timer(&rp->timer); - return 0; } -static void rhine_check_duplex(struct net_device *dev) -{ - struct rhine_private *rp = netdev_priv(dev); - long ioaddr = dev->base_addr; - int mii_lpa = mdio_read(dev, rp->phys[0], MII_LPA); - int negotiated = mii_lpa & rp->mii_if.advertising; - int duplex; - - if (rp->mii_if.force_media || mii_lpa == 0xffff) - return; - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (rp->mii_if.full_duplex != duplex) { - rp->mii_if.full_duplex = duplex; - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on " - "MII #%d link partner capability of %4.4x.\n", - dev->name, duplex ? "full" : "half", - rp->phys[0], mii_lpa); - if (duplex) - rp->chip_cmd |= CmdFDuplex; - else - rp->chip_cmd &= ~CmdFDuplex; - writew(rp->chip_cmd, ioaddr + ChipCmd); - } -} - - -static void rhine_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct rhine_private *rp = netdev_priv(dev); - long ioaddr = dev->base_addr; - int next_tick = 10*HZ; - int mii_status; - - if (debug > 3) { - printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", - dev->name, readw(ioaddr + IntrStatus)); - } - - spin_lock_irq (&rp->lock); - - rhine_check_duplex(dev); - - /* make IFF_RUNNING follow the MII status bit "Link established" */ - mii_status = mdio_read(dev, rp->phys[0], MII_BMSR); - if ((mii_status & BMSR_LSTATUS) != (rp->mii_status & BMSR_LSTATUS)) { - if (mii_status & BMSR_LSTATUS) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - } - rp->mii_status = mii_status; - - spin_unlock_irq(&rp->lock); - - rp->timer.expires = jiffies + next_tick; - add_timer(&rp->timer); -} - - static void rhine_tx_timeout(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1270,16 +1230,13 @@ printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " "%4.4x, resetting...\n", dev->name, readw(ioaddr + IntrStatus), - mdio_read(dev, rp->phys[0], MII_BMSR)); + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); /* protect against concurrent rx interrupts */ disable_irq(rp->pdev->irq); spin_lock(&rp->lock); - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); - /* clear all descriptors */ free_tbufs(dev); free_rbufs(dev); @@ -1287,7 +1244,7 @@ alloc_rbufs(dev); /* Reinitialize the hardware. */ - wait_for_reset(dev, rp->quirks, dev->name); + rhine_chip_reset(dev); init_registers(dev); spin_unlock(&rp->lock); @@ -1301,8 +1258,8 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + long ioaddr = dev->base_addr; unsigned entry; - u32 intr_status; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -1353,14 +1310,9 @@ /* Non-x86 Todo: explicitly flush cache lines here. */ - /* - * Wake the potentially-idle transmit channel unless errors are - * pending (the ISR must sort them out first). - */ - intr_status = get_intr_status(dev); - if ((intr_status & IntrTxErrSummary) == 0) { - writew(CmdTxDemand | rp->chip_cmd, dev->base_addr + ChipCmd); - } + /* Wake the potentially-idle transmit channel */ + writeb(readb(ioaddr + ChipCmd1) | Cmd1TxDemand, + ioaddr + ChipCmd1); IOSYNC; if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN) @@ -1408,11 +1360,10 @@ if (intr_status & (IntrTxErrSummary | IntrTxDone)) { if (intr_status & IntrTxErrSummary) { - int cnt = 20; /* Avoid scavenging before Tx engine turned off */ - while ((readw(ioaddr+ChipCmd) & CmdTxOn) && --cnt) - udelay(5); - if (debug > 2 && !cnt) + RHINE_WAIT_FOR(!(readb(ioaddr+ChipCmd) & CmdTxOn)); + if (debug > 2 && + readb(ioaddr+ChipCmd) & CmdTxOn) printk(KERN_WARNING "%s: " "rhine_interrupt() Tx engine" "still on.\n", dev->name); @@ -1572,10 +1523,6 @@ rp->rx_buf_sz, PCI_DMA_FROMDEVICE); - /* *_IP_COPYSUM isn't defined anywhere and - eth_copy_and_sum is memcpy for all archs so - this is kind of pointless right now - ... or? */ eth_copy_and_sum(skb, rp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -1627,10 +1574,6 @@ } rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } - - /* Pre-emptively restart Rx engine. */ - writew(readw(dev->base_addr + ChipCmd) | CmdRxOn | CmdRxDemand, - dev->base_addr + ChipCmd); } /* @@ -1664,7 +1607,10 @@ writel(rp->tx_ring_dma + entry * sizeof(struct tx_desc), ioaddr + TxRingPtr); - writew(CmdTxDemand | rp->chip_cmd, ioaddr + ChipCmd); + writeb(readb(ioaddr + ChipCmd) | CmdTxOn, + ioaddr + ChipCmd); + writeb(readb(ioaddr + ChipCmd1) | Cmd1TxDemand, + ioaddr + ChipCmd1); IOSYNC; } else { @@ -1684,20 +1630,8 @@ spin_lock(&rp->lock); - if (intr_status & (IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) { - /* Link failed, restart autonegotiation. */ - if (rp->quirks & rqRhineI) - mdio_write(dev, rp->phys[0], MII_BMCR, 0x3300); - } else - rhine_check_duplex(dev); - if (debug) - printk(KERN_ERR "%s: MII status changed: " - "Autonegotiation advertising %4.4x partner " - "%4.4x.\n", dev->name, - mdio_read(dev, rp->phys[0], MII_ADVERTISE), - mdio_read(dev, rp->phys[0], MII_LPA)); - } + if (intr_status & IntrLinkChange) + rhine_check_media(dev, 0); if (intr_status & IntrStatsMax) { rp->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); rp->stats.rx_missed_errors += readw(ioaddr + RxMissed); @@ -1790,7 +1724,7 @@ i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); @@ -1856,6 +1790,39 @@ debug = value; } +static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rhine_private *rp = netdev_priv(dev); + + if (!(rp->quirks & rqWOL)) + return; + + spin_lock_irq(&rp->lock); + wol->supported = WAKE_PHY | WAKE_MAGIC | + WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ + wol->wolopts = rp->wolopts; + spin_unlock_irq(&rp->lock); +} + +static int rhine_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rhine_private *rp = netdev_priv(dev); + u32 support = WAKE_PHY | WAKE_MAGIC | + WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ + + if (!(rp->quirks & rqWOL)) + return -EINVAL; + + if (wol->wolopts & ~support) + return -EINVAL; + + spin_lock_irq(&rp->lock); + rp->wolopts = wol->wolopts; + spin_unlock_irq(&rp->lock); + + return 0; +} + static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, @@ -1864,6 +1831,8 @@ .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, + .get_wol = rhine_get_wol, + .set_wol = rhine_set_wol, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, }; @@ -1888,8 +1857,6 @@ long ioaddr = dev->base_addr; struct rhine_private *rp = netdev_priv(dev); - del_timer_sync(&rp->timer); - spin_lock_irq(&rp->lock); netif_stop_queue(dev); @@ -1936,12 +1903,110 @@ pci_set_drvdata(pdev, NULL); } +static void rhine_shutdown (struct device *gendev) +{ + struct pci_dev *pdev = to_pci_dev(gendev); + struct net_device *dev = pci_get_drvdata(pdev); + struct rhine_private *rp = netdev_priv(dev); + + long ioaddr = dev->base_addr; + + rhine_power_init(dev); + + /* Make sure we use pattern 0, 1 and not 4, 5 */ + if (rp->quirks & rq6patterns) + writeb(0x04, ioaddr + 0xA7); + + if (rp->wolopts & WAKE_MAGIC) + writeb(WOLmagic, ioaddr + WOLcrSet); + + if (rp->wolopts & (WAKE_BCAST|WAKE_MCAST)) + writeb(WOLbmcast, ioaddr + WOLcgSet); + + if (rp->wolopts & WAKE_PHY) + writeb(WOLlnkon | WOLlnkoff, ioaddr + WOLcrSet); + + if (rp->wolopts & WAKE_UCAST) + writeb(WOLucast, ioaddr + WOLcrSet); + + /* Enable legacy WOL (for old motherboards) */ + writeb(0x01, ioaddr + PwcfgSet); + writeb(readb(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW); + + /* Hit power state D3 (sleep) */ + writeb(readb(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); + + /* TODO: Check use of pci_enable_wake() */ + +} + +#ifdef CONFIG_PM +static int rhine_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rhine_private *rp = netdev_priv(dev); + unsigned long flags; + + if (!netif_running(dev)) + return 0; + + netif_device_detach(dev); + pci_save_state(pdev, pdev->saved_config_space); + + spin_lock_irqsave(&rp->lock, flags); + rhine_shutdown(&pdev->dev); + spin_unlock_irqrestore(&rp->lock, flags); + + return 0; +} + +static int rhine_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rhine_private *rp = netdev_priv(dev); + unsigned long flags; + int ret; + + if (!netif_running(dev)) + return 0; + + ret = pci_set_power_state(pdev, 0); + if (debug > 1) + printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n", + dev->name, ret ? "failed" : "succeeded", ret); + + pci_restore_state(pdev, pdev->saved_config_space); + + spin_lock_irqsave(&rp->lock, flags); +#ifdef USE_MMIO + enable_mmio(rp->pioaddr, rp->quirks); +#endif + rhine_power_init(dev); + free_tbufs(dev); + free_rbufs(dev); + alloc_tbufs(dev); + alloc_rbufs(dev); + init_registers(dev); + spin_unlock_irqrestore(&rp->lock, flags); + + netif_device_attach(dev); + + return 0; +} +#endif /* CONFIG_PM */ static struct pci_driver rhine_driver = { - .name = "via-rhine", + .name = DRV_NAME, .id_table = rhine_pci_tbl, .probe = rhine_init_one, .remove = __devexit_p(rhine_remove_one), +#ifdef CONFIG_PM + .suspend = rhine_suspend, + .resume = rhine_resume, +#endif /* CONFIG_PM */ + .driver = { + .shutdown = rhine_shutdown, + } }; diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c --- a/drivers/net/via-velocity.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/via-velocity.c 2004-10-18 14:56:49 -07:00 @@ -78,6 +78,8 @@ #include #include #include +#include +#include #include "via-velocity.h" @@ -226,7 +228,10 @@ VELOCITY_PARAM(int_works, "Number of packets per interrupt services"); -static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent); +static int rx_copybreak = 200; +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); + static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info); static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev); static void velocity_print_info(struct velocity_info *vptr); @@ -238,10 +243,8 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev); static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int velocity_close(struct net_device *dev); -static int velocity_rx_srv(struct velocity_info *vptr, int status); static int velocity_receive_frame(struct velocity_info *, int idx); static int velocity_alloc_rx_buf(struct velocity_info *, int idx); -static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type); static void velocity_free_rd_ring(struct velocity_info *vptr); static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); static int velocity_soft_reset(struct velocity_info *vptr); @@ -254,25 +257,40 @@ static void enable_mii_autopoll(struct mac_regs * regs); static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata); static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data); -static int velocity_set_wol(struct velocity_info *vptr); -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context); -static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context); static u32 mii_check_media_mode(struct mac_regs * regs); static u32 check_connection_type(struct mac_regs * regs); -static void velocity_init_cam_filter(struct velocity_info *vptr); static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); #ifdef CONFIG_PM + static int velocity_suspend(struct pci_dev *pdev, u32 state); static int velocity_resume(struct pci_dev *pdev); static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); static struct notifier_block velocity_inetaddr_notifier = { - notifier_call:velocity_netdev_event, + .notifier_call = velocity_netdev_event, }; -#endif /* CONFIG_PM */ +static spinlock_t velocity_dev_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(velocity_dev_list); + +static void velocity_register_notifier(void) +{ + register_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +static void velocity_unregister_notifier(void) +{ + unregister_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +#else /* CONFIG_PM */ + +#define velocity_register_notifier() do {} while (0) +#define velocity_unregister_notifier() do {} while (0) + +#endif /* !CONFIG_PM */ /* * Internal board variants. At the moment we have only one @@ -289,8 +307,9 @@ */ static struct pci_device_id velocity_id_table[] __devinitdata = { - {0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]}, - {0,} + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table}, + {0, } }; MODULE_DEVICE_TABLE(pci, velocity_id_table); @@ -326,12 +345,22 @@ struct net_device *dev = pci_get_drvdata(pdev); struct velocity_info *vptr = dev->priv; +#ifdef CONFIG_PM + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + if (!list_empty(&velocity_dev_list)) + list_del(&vptr->list); + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); +#endif unregister_netdev(dev); iounmap(vptr->mac_regs); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_netdev(dev); + + velocity_nics--; } /** @@ -435,7 +464,7 @@ { struct mac_regs * regs = vptr->mac_regs; - /* T urn on MCFG_PQEN, turn off MCFG_RTGOPT */ + /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); WORD_REG_BITS_ON(MCFG_VIDFR, ®s->MCFG); @@ -477,13 +506,13 @@ struct mac_regs * regs = vptr->mac_regs; int i; - vptr->rd_used = vptr->rd_curr = 0; + vptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0; /* * Init state, all RD entries belong to the NIC */ for (i = 0; i < vptr->options.numrx; ++i) - vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC); + vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC; writew(vptr->options.numrx, ®s->RBRDU); writel(vptr->rd_pool_dma, ®s->RDBaseLo); @@ -558,11 +587,16 @@ writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); /* - * Bback off algorithm use original IEEE standard + * Back off algorithm use original IEEE standard */ BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); /* + * Init CAM filter + */ + velocity_init_cam_filter(vptr); + + /* * Set packet filter: Receive directed and broadcast address */ velocity_set_multi(vptr->dev); @@ -586,8 +620,6 @@ mac_tx_queue_run(regs, i); } - velocity_init_cam_filter(vptr); - init_flow_control_register(vptr); writel(CR0_STOP, ®s->CR0Clr); @@ -595,7 +627,6 @@ mii_status = velocity_get_opt_media_mode(vptr); netif_stop_queue(vptr->dev); - mac_clear_isr(regs); mii_init(vptr, mii_status); @@ -662,7 +693,7 @@ struct mac_regs * regs; int ret = -ENOMEM; - if (velocity_nics++ >= MAX_UNITS) { + if (velocity_nics >= MAX_UNITS) { printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n", velocity_nics); return -ENODEV; @@ -694,7 +725,6 @@ vptr->dev = dev; - dev->priv = vptr; dev->irq = pdev->irq; ret = pci_enable_device(pdev); @@ -729,7 +759,7 @@ dev->dev_addr[i] = readb(®s->PAR[i]); - velocity_get_options(&vptr->options, velocity_nics - 1, dev->name); + velocity_get_options(&vptr->options, velocity_nics, dev->name); /* * Mask out the options cannot be set to the chip @@ -775,6 +805,16 @@ /* and leave the chip powered down */ pci_set_power_state(pdev, 3); +#ifdef CONFIG_PM + { + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + list_add(&vptr->list, &velocity_dev_list); + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + } +#endif + velocity_nics++; out: return ret; @@ -827,9 +867,8 @@ vptr->io_size = info->io_size; vptr->num_txq = info->txqueue; vptr->multicast_limit = MCAM_SIZE; - spin_lock_init(&vptr->lock); - spin_lock_init(&vptr->xmit_lock); + INIT_LIST_HEAD(&vptr->list); } /** @@ -966,6 +1005,60 @@ pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma); } +static inline void velocity_give_many_rx_descs(struct velocity_info *vptr) +{ + struct mac_regs *regs = vptr->mac_regs; + int avail, dirty, unusable; + + /* + * RD number must be equal to 4X per hardware spec + * (programming guide rev 1.20, p.13) + */ + if (vptr->rd_filled < 4) + return; + + wmb(); + + unusable = vptr->rd_filled & 0x0003; + dirty = vptr->rd_dirty - unusable; + for (avail = vptr->rd_filled & 0xfffc; avail; avail--) { + dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; + vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC; + } + + writew(vptr->rd_filled & 0xfffc, ®s->RBRDU); + vptr->rd_filled = unusable; +} + +static int velocity_rx_refill(struct velocity_info *vptr) +{ + int dirty = vptr->rd_dirty, done = 0, ret = 0; + + do { + struct rx_desc *rd = vptr->rd_ring + dirty; + + /* Fine for an all zero Rx desc at init time as well */ + if (rd->rdesc0.owner == OWNED_BY_NIC) + break; + + if (!vptr->rd_info[dirty].skb) { + ret = velocity_alloc_rx_buf(vptr, dirty); + if (ret < 0) + break; + } + done++; + dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; + } while (dirty != vptr->rd_curr); + + if (done) { + vptr->rd_dirty = dirty; + vptr->rd_filled += done; + velocity_give_many_rx_descs(vptr); + } + + return ret; +} + /** * velocity_init_rd_ring - set up receive ring * @vptr: velocity to configure @@ -976,9 +1069,7 @@ static int velocity_init_rd_ring(struct velocity_info *vptr) { - int i, ret = -ENOMEM; - struct rx_desc *rd; - struct velocity_rd_info *rd_info; + int ret = -ENOMEM; unsigned int rsize = sizeof(struct velocity_rd_info) * vptr->options.numrx; @@ -987,28 +1078,20 @@ goto out; memset(vptr->rd_info, 0, rsize); - /* Init the RD ring entries */ - for (i = 0; i < vptr->options.numrx; i++) { - rd = &(vptr->rd_ring[i]); - rd_info = &(vptr->rd_info[i]); + vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0; - ret = velocity_alloc_rx_buf(vptr, i); - if (ret < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR - "%s: failed to allocate RX buffer.\n", - vptr->dev->name); - velocity_free_rd_ring(vptr); - goto out; - } - rd->rdesc0.owner = OWNED_BY_NIC; + ret = velocity_rx_refill(vptr); + if (ret < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: failed to allocate RX buffer.\n", vptr->dev->name); + velocity_free_rd_ring(vptr); } - vptr->rd_used = vptr->rd_curr = 0; out: return ret; } /** - * velocity_free_rd_ring - set up receive ring + * velocity_free_rd_ring - free receive ring * @vptr: velocity to clean up * * Free the receive buffers for each ring slot and any @@ -1025,7 +1108,7 @@ for (i = 0; i < vptr->options.numrx; i++) { struct velocity_rd_info *rd_info = &(vptr->rd_info[i]); - if (!rd_info->skb_dma) + if (!rd_info->skb) continue; pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); @@ -1073,8 +1156,10 @@ for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) { td = &(vptr->td_rings[j][i]); td_info = &(vptr->td_infos[j][i]); - td_info->buf = vptr->tx_bufs + (i + j) * PKT_BUF_SZ; - td_info->buf_dma = vptr->tx_bufs_dma + (i + j) * PKT_BUF_SZ; + td_info->buf = vptr->tx_bufs + + (j * vptr->options.numtx + i) * PKT_BUF_SZ; + td_info->buf_dma = vptr->tx_bufs_dma + + (j * vptr->options.numtx + i) * PKT_BUF_SZ; } vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0; } @@ -1146,40 +1231,27 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) { - struct rx_desc *rd; struct net_device_stats *stats = &vptr->stats; - struct mac_regs * regs = vptr->mac_regs; int rd_curr = vptr->rd_curr; int works = 0; - while (1) { - - rd = &(vptr->rd_ring[rd_curr]); + do { + struct rx_desc *rd = vptr->rd_ring + rd_curr; - if ((vptr->rd_info[rd_curr]).skb == NULL) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) - break; - } - - if (works++ > 15) + if (!vptr->rd_info[rd_curr].skb) break; if (rd->rdesc0.owner == OWNED_BY_NIC) break; + rmb(); + /* * Don't drop CE or RL error frame although RXOK is off - * FIXME: need to handle copybreak */ if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) { - if (velocity_receive_frame(vptr, rd_curr) == 0) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name); - break; - } - } else { + if (velocity_receive_frame(vptr, rd_curr) < 0) stats->rx_dropped++; - } } else { if (rd->rdesc0.RSR & RSR_CRC) stats->rx_crc_errors++; @@ -1191,26 +1263,20 @@ rd->inten = 1; - if (++vptr->rd_used >= 4) { - int i, rd_prev = rd_curr; - for (i = 0; i < 4; i++) { - if (--rd_prev < 0) - rd_prev = vptr->options.numrx - 1; - - rd = &(vptr->rd_ring[rd_prev]); - rd->rdesc0.owner = OWNED_BY_NIC; - } - writew(4, &(regs->RBRDU)); - vptr->rd_used -= 4; - } - vptr->dev->last_rx = jiffies; rd_curr++; if (rd_curr >= vptr->options.numrx) rd_curr = 0; - } + } while (++works <= 15); + vptr->rd_curr = rd_curr; + + if (works > 0 && velocity_rx_refill(vptr) < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: rx buf allocation failure\n", vptr->dev->name); + } + VAR_USED(stats); return works; } @@ -1242,6 +1308,65 @@ } /** + * velocity_rx_copy - in place Rx copy for small packets + * @rx_skb: network layer packet buffer candidate + * @pkt_size: received data size + * @rd: receive packet descriptor + * @dev: network device + * + * Replace the current skb that is scheduled for Rx processing by a + * shorter, immediatly allocated skb, if the received packet is small + * enough. This function returns a negative value if the received + * packet is too big or if memory is exhausted. + */ +static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *new_skb; + + new_skb = dev_alloc_skb(pkt_size + 2); + if (new_skb) { + new_skb->dev = vptr->dev; + new_skb->ip_summed = rx_skb[0]->ip_summed; + + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) + skb_reserve(new_skb, 2); + + memcpy(new_skb->data, rx_skb[0]->tail, pkt_size); + *rx_skb = new_skb; + ret = 0; + } + + } + return ret; +} + +/** + * velocity_iph_realign - IP header alignment + * @vptr: velocity we are handling + * @skb: network layer packet buffer + * @pkt_size: received data size + * + * Align IP header on a 2 bytes boundary. This behavior can be + * configured by the user. + */ +static inline void velocity_iph_realign(struct velocity_info *vptr, + struct sk_buff *skb, int pkt_size) +{ + /* FIXME - memmove ? */ + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { + int i; + + for (i = pkt_size; i >= 0; i--) + *(skb->data + i + 2) = *(skb->data + i); + skb_reserve(skb, 2); + } +} + +/** * velocity_receive_frame - received packet processor * @vptr: velocity we are handling * @idx: ring index @@ -1252,9 +1377,11 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) { + void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); struct net_device_stats *stats = &vptr->stats; struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); struct rx_desc *rd = &(vptr->rd_ring[idx]); + int pkt_len = rd->rdesc0.len; struct sk_buff *skb; if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { @@ -1269,22 +1396,8 @@ skb = rd_info->skb; skb->dev = vptr->dev; - pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, - PCI_DMA_FROMDEVICE); - rd_info->skb_dma = (dma_addr_t) NULL; - rd_info->skb = NULL; - - /* FIXME - memmove ? */ - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - int i; - for (i = rd->rdesc0.len + 4; i >= 0; i--) - *(skb->data + i + 2) = *(skb->data + i); - skb->data += 2; - skb->tail += 2; - } - - skb_put(skb, (rd->rdesc0.len - 4)); - skb->protocol = eth_type_trans(skb, skb->dev); + pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, + vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* * Drop frame not meeting IEEE 802.3 @@ -1297,13 +1410,23 @@ } } + pci_action = pci_dma_sync_single_for_device; + velocity_rx_csum(rd, skb); - - /* - * FIXME: need rx_copybreak handling - */ - stats->rx_bytes += skb->len; + if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { + velocity_iph_realign(vptr, skb, pkt_len); + pci_action = pci_unmap_single; + rd_info->skb = NULL; + } + + pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + skb_put(skb, pkt_len - 4); + skb->protocol = eth_type_trans(skb, skb->dev); + + stats->rx_bytes += pkt_len; netif_rx(skb); return 0; @@ -1963,32 +2086,6 @@ /** - * ether_crc - ethernet CRC function - * - * Compute an ethernet CRC hash of the data block provided. This - * is not performance optimised but is not needed in performance - * critical code paths. - * - * FIXME: could we use shared code here ? - */ - -static inline u32 ether_crc(int length, unsigned char *data) -{ - static unsigned const ethernet_polynomial = 0x04c11db7U; - - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - return crc; -} - -/** * velocity_set_multi - filter list change callback * @dev: network device * @@ -2123,13 +2220,13 @@ */ static struct pci_driver velocity_driver = { - name:VELOCITY_NAME, - id_table:velocity_id_table, - probe:velocity_found1, - remove:velocity_remove1, + .name = VELOCITY_NAME, + .id_table = velocity_id_table, + .probe = velocity_found1, + .remove = __devexit_p(velocity_remove1), #ifdef CONFIG_PM - suspend:velocity_suspend, - resume:velocity_resume, + .suspend = velocity_suspend, + .resume = velocity_resume, #endif }; @@ -2145,11 +2242,11 @@ static int __init velocity_init_module(void) { int ret; - ret = pci_module_init(&velocity_driver); -#ifdef CONFIG_PM - register_inetaddr_notifier(&velocity_inetaddr_notifier); -#endif + velocity_register_notifier(); + ret = pci_module_init(&velocity_driver); + if (ret < 0) + velocity_unregister_notifier(); return ret; } @@ -2164,9 +2261,7 @@ static void __exit velocity_cleanup_module(void) { -#ifdef CONFIG_PM - unregister_inetaddr_notifier(&velocity_inetaddr_notifier); -#endif + velocity_unregister_notifier(); pci_unregister_driver(&velocity_driver); } @@ -2992,172 +3087,6 @@ } -static int velocity_suspend(struct pci_dev *pdev, u32 state) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - - if(!netif_running(vptr->dev)) - return 0; - - netif_device_detach(vptr->dev); - - spin_lock_irqsave(&vptr->lock, flags); - pci_save_state(pdev, vptr->pci_state); -#ifdef ETHTOOL_GWOL - if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { - velocity_get_ip(vptr); - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - velocity_set_wol(vptr); - pci_enable_wake(pdev, 3, 1); - pci_set_power_state(pdev, 3); - } else { - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - pci_disable_device(pdev); - pci_set_power_state(pdev, state); - } -#else - pci_set_power_state(pdev, state); -#endif - spin_unlock_irqrestore(&vptr->lock, flags); - return 0; -} - -static int velocity_resume(struct pci_dev *pdev) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - int i; - - if(!netif_running(vptr->dev)) - return 0; - - pci_set_power_state(pdev, 0); - pci_enable_wake(pdev, 0, 0); - pci_restore_state(pdev, vptr->pci_state); - - mac_wol_reset(vptr->mac_regs); - - spin_lock_irqsave(&vptr->lock, flags); - velocity_restore_context(vptr, &vptr->context); - velocity_init_registers(vptr, VELOCITY_INIT_WOL); - mac_disable_int(vptr->mac_regs); - - velocity_tx_srv(vptr, 0); - - for (i = 0; i < vptr->num_txq; i++) { - if (vptr->td_used[i]) { - mac_tx_queue_wake(vptr->mac_regs, i); - } - } - - mac_enable_int(vptr->mac_regs); - spin_unlock_irqrestore(&vptr->lock, flags); - netif_device_attach(vptr->dev); - - return 0; -} - -static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; - struct net_device *dev; - struct velocity_info *vptr; - - if (ifa) { - dev = ifa->ifa_dev->dev; - vptr = dev->priv; - velocity_get_ip(vptr); - } - return NOTIFY_DONE; -} -#endif - -/* - * Purpose: Functions to set WOL. - */ - -const static unsigned short crc16_tab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - - -static u32 mask_pattern[2][4] = { - {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ - {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ -}; - -/** - * ether_crc16 - compute ethernet CRC - * @len: buffer length - * @cp: buffer - * @crc16: initial CRC - * - * Compute a CRC value for a block of data. - * FIXME: can we use generic functions ? - */ - -static u16 ether_crc16(int len, u8 * cp, u16 crc16) -{ - while (len--) - crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff]; - return (crc16); -} - -/** - * bit_reverse - 16bit reverse - * @data: 16bit data t reverse - * - * Reverse the order of a 16bit value and return the reversed bits - */ - -static u16 bit_reverse(u16 data) -{ - u32 new = 0x00000000; - int ii; - - - for (ii = 0; ii < 16; ii++) { - new |= ((u32) (data & 1) << (31 - ii)); - data >>= 1; - } - - return (u16) (new >> 16); -} - /** * wol_calc_crc - WOL CRC * @pattern: data pattern @@ -3166,7 +3095,7 @@ * Compute the wake on lan crc hashes for the packet header * we are interested in. */ - + u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; @@ -3186,12 +3115,12 @@ continue; } mask >>= 1; - crc = ether_crc16(1, &(pattern[i * 8 + j]), crc); + crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1); } } /* Finally, invert the result once to get the correct data */ crc = ~crc; - return bit_reverse(crc); + return bitreverse(crc) >> 16; } /** @@ -3203,13 +3132,18 @@ * * FIXME: check static buffer is safe here */ - + static int velocity_set_wol(struct velocity_info *vptr) { struct mac_regs * regs = vptr->mac_regs; static u8 buf[256]; int i; + static u32 mask_pattern[2][4] = { + {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ + {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ + }; + writew(0xFFFF, ®s->WOLCRClr); writeb(WOLCFG_SAB | WOLCFG_SAM, ®s->WOLCFGSet); writew(WOLCR_MAGIC_EN, ®s->WOLCRSet); @@ -3236,7 +3170,8 @@ memcpy(arp->ar_tip, vptr->ip_addr, 4); - crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]); + crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, + (u8 *) & mask_pattern[0][0]); writew(crc, ®s->PatternCRC[0]); writew(WOLCR_ARP_EN, ®s->WOLCRSet); @@ -3275,3 +3210,92 @@ return 0; } +static int velocity_suspend(struct pci_dev *pdev, u32 state) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + + if(!netif_running(vptr->dev)) + return 0; + + netif_device_detach(vptr->dev); + + spin_lock_irqsave(&vptr->lock, flags); + pci_save_state(pdev, vptr->pci_state); +#ifdef ETHTOOL_GWOL + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { + velocity_get_ip(vptr); + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + velocity_set_wol(vptr); + pci_enable_wake(pdev, 3, 1); + pci_set_power_state(pdev, 3); + } else { + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + pci_disable_device(pdev); + pci_set_power_state(pdev, state); + } +#else + pci_set_power_state(pdev, state); +#endif + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +static int velocity_resume(struct pci_dev *pdev) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + int i; + + if(!netif_running(vptr->dev)) + return 0; + + pci_set_power_state(pdev, 0); + pci_enable_wake(pdev, 0, 0); + pci_restore_state(pdev, vptr->pci_state); + + mac_wol_reset(vptr->mac_regs); + + spin_lock_irqsave(&vptr->lock, flags); + velocity_restore_context(vptr, &vptr->context); + velocity_init_registers(vptr, VELOCITY_INIT_WOL); + mac_disable_int(vptr->mac_regs); + + velocity_tx_srv(vptr, 0); + + for (i = 0; i < vptr->num_txq; i++) { + if (vptr->td_used[i]) { + mac_tx_queue_wake(vptr->mac_regs, i); + } + } + + mac_enable_int(vptr->mac_regs); + spin_unlock_irqrestore(&vptr->lock, flags); + netif_device_attach(vptr->dev); + + return 0; +} + +static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; + + if (ifa) { + struct net_device *dev = ifa->ifa_dev->dev; + struct velocity_info *vptr; + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + list_for_each_entry(vptr, &velocity_dev_list, list) { + if (vptr->dev == dev) { + velocity_get_ip(vptr); + break; + } + } + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + } + return NOTIFY_DONE; +} +#endif diff -Nru a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h --- a/drivers/net/via-velocity.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/via-velocity.h 2004-10-18 14:57:04 -07:00 @@ -37,7 +37,6 @@ #define OPTION_DEFAULT { [0 ... MAX_UNITS-1] = -1} #define REV_ID_VT6110 (0) -#define DEVICE_ID (0x3119) #define BYTE_REG_BITS_ON(x,p) do { writeb(readb((p))|(x),(p));} while (0) #define WORD_REG_BITS_ON(x,p) do { writew(readw((p))|(x),(p));} while (0) @@ -1320,7 +1319,7 @@ /* disable CAMEN */ writeb(0, ®s->CAMADDR); - /* Select CAM mask */ + /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } @@ -1361,7 +1360,7 @@ writeb(0, ®s->CAMADDR); - /* Select CAM mask */ + /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } @@ -1402,7 +1401,7 @@ writeb(0, ®s->CAMADDR); - /* Select CAM mask */ + /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } @@ -1734,14 +1733,13 @@ }; struct velocity_info { - struct velocity_info *next; - struct velocity_info *prev; + struct list_head list; struct pci_dev *pdev; struct net_device *dev; struct net_device_stats stats; -#if CONFIG_PM +#ifdef CONFIG_PM u32 pci_state[16]; #endif @@ -1772,7 +1770,8 @@ struct velocity_td_info *td_infos[TX_QUEUE_NO]; int rd_curr; - int rd_used; + int rd_dirty; + u32 rd_filled; struct rx_desc *rd_ring; struct velocity_rd_info *rd_info; /* It's an array */ @@ -1793,7 +1792,6 @@ u8 mCAMmask[(MCAM_SIZE / 8)]; spinlock_t lock; - spinlock_t xmit_lock; int wol_opts; u8 wol_passwd[6]; diff -Nru a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c --- a/drivers/net/wan/cycx_x25.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/net/wan/cycx_x25.c 2004-10-18 14:56:17 -07:00 @@ -186,7 +186,7 @@ reset_timer(struct net_device *dev); static u8 bps_to_speed_code(u32 bps); -static u8 log2(u32 n); +static u8 cycx_log2(u32 n); static unsigned dec_to_uint(u8 *str, int len); @@ -263,7 +263,7 @@ else card->wandev.mtu = 64; - cfg.pktlen = log2(card->wandev.mtu); + cfg.pktlen = cycx_log2(card->wandev.mtu); if (conf->station == WANOPT_DTE) { cfg.locaddr = 3; /* DTE */ @@ -1513,7 +1513,7 @@ } /* log base 2 */ -static u8 log2(u32 n) +static u8 cycx_log2(u32 n) { u8 log = 0; diff -Nru a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c --- a/drivers/net/wan/dscc4.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/net/wan/dscc4.c 2004-10-18 14:57:19 -07:00 @@ -351,8 +351,8 @@ #endif /* Functions prototypes */ -static inline void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); -static inline void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); +static void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); +static void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); static int dscc4_found1(struct pci_dev *, unsigned long ioaddr); static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent); static int dscc4_open(struct net_device *); @@ -366,7 +366,6 @@ static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs); static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short); static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *); -static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int); #ifdef DSCC4_POLLING static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *); #endif @@ -866,6 +865,18 @@ //scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2); } +static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz) +{ + int ret = 0; + + if ((hz < 0) || (hz > DSCC4_HZ_MAX)) + ret = -EOPNOTSUPP; + else + dpriv->pci_priv->xtal_hz = hz; + + return ret; +} + static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr) { struct dscc4_pci_priv *ppriv; @@ -1340,18 +1351,6 @@ return ret; } -static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz) -{ - int ret = 0; - - if ((hz < 0) || (hz > DSCC4_HZ_MAX)) - ret = -EOPNOTSUPP; - else - dpriv->pci_priv->xtal_hz = hz; - - return ret; -} - static int dscc4_match(struct thingie *p, int value) { int i; @@ -1531,7 +1530,7 @@ return IRQ_RETVAL(handled); } -static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, +static void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, struct dscc4_dev_priv *dpriv) { struct net_device *dev = dscc4_to_dev(dpriv); @@ -1700,7 +1699,7 @@ goto try; } -static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, +static void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct dscc4_dev_priv *dpriv) { struct net_device *dev = dscc4_to_dev(dpriv); diff -Nru a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c --- a/drivers/net/wan/hd6457x.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/net/wan/hd6457x.c 2004-10-18 14:56:17 -07:00 @@ -463,8 +463,8 @@ brv >>= 1; /* brv = 2^9 = 512 max in specs */ /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ - tmc = CLOCK_BASE / (brv * port->settings.clock_rate); - }while(br > 1 && tmc <= 128); + tmc = CLOCK_BASE / brv / port->settings.clock_rate; + }while (br > 1 && tmc <= 128); if (tmc < 1) { tmc = 1; @@ -473,7 +473,7 @@ } else if (tmc > 255) tmc = 256; /* tmc=0 means 256 - low baud rates */ - port->settings.clock_rate = CLOCK_BASE / (brv * tmc); + port->settings.clock_rate = CLOCK_BASE / brv / tmc; } else { br = 9; /* Minimum clock rate */ tmc = 256; /* 8bit = 0 */ diff -Nru a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c --- a/drivers/net/wan/lmc/lmc_debug.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/wan/lmc/lmc_debug.c 2004-10-18 14:56:28 -07:00 @@ -64,7 +64,7 @@ #endif } -inline void lmc_trace(struct net_device *dev, char *msg){ +void lmc_trace(struct net_device *dev, char *msg){ #ifdef LMC_TRACE unsigned long j = jiffies + 3; /* Wait for 50 ms */ diff -Nru a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h --- a/drivers/net/wan/pc300.h 2004-10-18 14:56:27 -07:00 +++ b/drivers/net/wan/pc300.h 2004-10-18 14:56:27 -07:00 @@ -164,9 +164,9 @@ * (required to support Alpha systems) * ***************************************/ #ifdef __KERNEL__ -#define cpc_writeb(port,val) {writeb((ucchar)(val),(ulong)(port)); mb();} -#define cpc_writew(port,val) {writew((ushort)(val),(ulong)(port)); mb();} -#define cpc_writel(port,val) {writel((uclong)(val),(ulong)(port)); mb();} +#define cpc_writeb(port,val) {writeb((ucchar)(val),(port)); mb();} +#define cpc_writew(port,val) {writew((ushort)(val),(port)); mb();} +#define cpc_writel(port,val) {writel((uclong)(val),(port)); mb();} #define cpc_readb(port) readb(port) #define cpc_readw(port) readw(port) @@ -358,17 +358,17 @@ uclong iophys; /* PLX registers I/O base */ uclong iosize; /* PLX registers I/O size */ uclong plxphys; /* PLX registers MMIO base (physical) */ - uclong plxbase; /* PLX registers MMIO base (virtual) */ + void __iomem * plxbase; /* PLX registers MMIO base (virtual) */ uclong plxsize; /* PLX registers MMIO size */ uclong scaphys; /* SCA registers MMIO base (physical) */ - uclong scabase; /* SCA registers MMIO base (virtual) */ + void __iomem * scabase; /* SCA registers MMIO base (virtual) */ uclong scasize; /* SCA registers MMIO size */ uclong ramphys; /* On-board RAM MMIO base (physical) */ - uclong rambase; /* On-board RAM MMIO base (virtual) */ + void __iomem * rambase; /* On-board RAM MMIO base (virtual) */ uclong alloc_ramsize; /* RAM MMIO size allocated by the PCI bridge */ uclong ramsize; /* On-board RAM MMIO size */ uclong falcphys; /* FALC registers MMIO base (physical) */ - uclong falcbase; /* FALC registers MMIO base (virtual) */ + void __iomem * falcbase;/* FALC registers MMIO base (virtual) */ uclong falcsize; /* FALC registers MMIO size */ } pc300hw_t; diff -Nru a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c --- a/drivers/net/wan/pc300_drv.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/wan/pc300_drv.c 2004-10-18 14:57:04 -07:00 @@ -307,7 +307,7 @@ { int i; int ch_factor = ch * N_DMA_TX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { @@ -322,7 +322,7 @@ { int i; int ch_factor = ch * N_DMA_TX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { @@ -337,7 +337,7 @@ { int i; int ch_factor = ch * N_DMA_RX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { @@ -352,7 +352,7 @@ { int i; int ch_factor = ch * N_DMA_RX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { @@ -365,7 +365,7 @@ static void tx_dma_buf_check(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int i; ucshort first_bd = card->chan[ch].tx_first_bd; ucshort next_bd = card->chan[ch].tx_next_bd; @@ -374,10 +374,10 @@ first_bd, TX_BD_ADDR(ch, first_bd), next_bd, TX_BD_ADDR(ch, next_bd)); for (i = first_bd, - ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, first_bd)); + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, first_bd)); i != ((next_bd + 1) & (N_DMA_TX_BUF - 1)); i = (i + 1) & (N_DMA_TX_BUF - 1), - ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i))) { + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i))) { printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d", ch, i, (uclong) cpc_readl(&ptdescr->next), (uclong) cpc_readl(&ptdescr->ptbuf), @@ -390,7 +390,7 @@ /* Show all TX buffer descriptors */ static void tx1_dma_buf_check(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int i; ucshort first_bd = card->chan[ch].tx_first_bd; ucshort next_bd = card->chan[ch].tx_next_bd; @@ -404,7 +404,7 @@ (uclong) cpc_readl(scabase + DTX_REG(CDAL, ch)), (uclong) cpc_readl(scabase + DTX_REG(EDAL, ch))); for (i = 0; i < N_DMA_TX_BUF; i++) { - ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i)); + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i)); printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d", ch, i, (uclong) cpc_readl(&ptdescr->next), (uclong) cpc_readl(&ptdescr->ptbuf), @@ -416,7 +416,7 @@ static void rx_dma_buf_check(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int i; ucshort first_bd = card->chan[ch].rx_first_bd; ucshort last_bd = card->chan[ch].rx_last_bd; @@ -424,7 +424,7 @@ ch_factor = ch * N_DMA_RX_BUF; printk("#CH%d: f_bd = %d, l_bd = %d\n", ch, first_bd, last_bd); - for (i = 0, ptdescr = (pcsca_bd_t *) (card->hw.rambase + + for (i = 0, ptdescr = (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); i < N_DMA_RX_BUF; i++, ptdescr++) { if (cpc_readb(&ptdescr->status) & DST_OSB) @@ -439,12 +439,12 @@ int dma_get_rx_frame_size(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; ucshort first_bd = card->chan[ch].rx_first_bd; int rcvd = 0; volatile ucchar status; - ptdescr = (pcsca_bd_t *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd)); + ptdescr = (card->hw.rambase + RX_BD_ADDR(ch, first_bd)); while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { rcvd += cpc_readw(&ptdescr->len); first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1); @@ -453,7 +453,7 @@ * (dma_buf_read will clean the buffer descriptors in this case). */ return (rcvd); } - ptdescr = (pcsca_bd_t *)(card->hw.rambase + cpc_readl(&ptdescr->next)); + ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); } return (-1); } @@ -465,7 +465,7 @@ int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) { int i, nchar; - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int tosend = len; ucchar nbuf = ((len - 1) / BD_DEF_LEN) + 1; @@ -474,11 +474,11 @@ } for (i = 0; i < nbuf; i++) { - ptdescr = (pcsca_bd_t *) (card->hw.rambase + + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, card->chan[ch].tx_next_bd)); nchar = cpc_min(BD_DEF_LEN, tosend); if (cpc_readb(&ptdescr->status) & DST_OSB) { - memcpy_toio((void *)(card->hw.rambase + cpc_readl(&ptdescr->ptbuf)), + memcpy_toio((card->hw.rambase + cpc_readl(&ptdescr->ptbuf)), &ptdata[len - tosend], nchar); cpc_writew(&ptdescr->len, nchar); card->chan[ch].nfree_tx_bd--; @@ -507,11 +507,11 @@ { int nchar; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int rcvd = 0; volatile ucchar status; - ptdescr = (pcsca_bd_t *) (card->hw.rambase + + ptdescr = (card->hw.rambase + RX_BD_ADDR(ch, chan->rx_first_bd)); while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { nchar = cpc_readw(&ptdescr->len); @@ -527,7 +527,7 @@ chan->rx_first_bd = (chan->rx_first_bd+1) & (N_DMA_RX_BUF-1); if (status & DST_EOM) break; - ptdescr = (pcsca_bd_t *) (card->hw.rambase + + ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); status = cpc_readb(&ptdescr->status); } @@ -536,7 +536,7 @@ if (nchar != 0) { if (skb) { memcpy_fromio(skb_put(skb, nchar), - (void *)(card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar); + (card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar); } rcvd += nchar; } @@ -547,7 +547,7 @@ if (status & DST_EOM) break; - ptdescr = (pcsca_bd_t *) (card->hw.rambase + cpc_readl(&ptdescr->next)); + ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); } if (rcvd != 0) { @@ -562,7 +562,7 @@ void tx_dma_stop(pc300_t * card, int ch) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (5 + 2 * ch); ucchar drr_rst_bit = 1 << (1 + 2 * ch); @@ -573,7 +573,7 @@ void rx_dma_stop(pc300_t * card, int ch) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (4 + 2 * ch); ucchar drr_rst_bit = 1 << (2 * ch); @@ -584,7 +584,7 @@ void rx_dma_start(pc300_t * card, int ch) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; /* Start DMA */ @@ -609,7 +609,7 @@ /*************************/ void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; unsigned long i = 0; while (cpc_readb(falcbase + F_REG(SIS, ch)) & SIS_CEC) { @@ -627,7 +627,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; /* Interrupt pins are open-drain */ cpc_writeb(falcbase + F_REG(IPC, ch), @@ -674,7 +674,7 @@ void falc_open_timeslot(pc300_t * card, int ch, int timeslot) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch), @@ -690,7 +690,7 @@ void falc_close_timeslot(pc300_t * card, int ch, int timeslot) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch), @@ -708,7 +708,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; cpc_writeb(falcbase + F_REG(ICB1, ch), 0xff); cpc_writeb(falcbase + F_REG(TTR1, ch), 0); @@ -730,7 +730,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; cpc_writeb(falcbase + F_REG(ICB1, ch), 0); if (conf->fr_mode == PC300_FR_UNFRAMED) { @@ -811,7 +811,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0); /* Switch to T1 mode (PCM 24) */ @@ -980,7 +980,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0); /* Switch to E1 mode (PCM 30) */ @@ -1157,7 +1157,7 @@ void falc_init_hdlc(pc300_t * card, int ch) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1186,7 +1186,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar dummy; unsigned long flags; @@ -1246,7 +1246,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; /* Verify LOS */ if (frs0 & FRS0_LOS) { @@ -1402,7 +1402,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucshort counter; counter = cpc_readb(falcbase + F_REG(FECL, ch)); @@ -1455,7 +1455,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (loop_on) { // EVENT_FALC_ABNORMAL @@ -1499,7 +1499,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (loop_on) { cpc_writeb(falcbase + F_REG(LIM0, ch), @@ -1527,7 +1527,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (loop_on) { // EVENT_FALC_ABNORMAL @@ -1580,7 +1580,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1601,7 +1601,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1624,7 +1624,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1657,7 +1657,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1687,7 +1687,7 @@ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (activate) { pfalc->prbs = 1; @@ -1973,11 +1973,11 @@ pc300ch_t *chan = (pc300ch_t *)dev->chan; pc300_t *card = (pc300_t *)chan->card; int ch = chan->channel; - volatile pcsca_bd_t * ptdescr; + volatile pcsca_bd_t __iomem * ptdescr; struct net_device_stats *stats = hdlc_stats(dev->dev); /* Clean up descriptors from previous transmission */ - ptdescr = (pcsca_bd_t *)(card->hw.rambase + + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd)); while ((cpc_readl(card->hw.scabase + DTX_REG(CDAL,ch)) != TX_BD_ADDR(ch,chan->tx_first_bd)) && @@ -1988,8 +1988,7 @@ cpc_writew(&ptdescr->len, 0); chan->nfree_tx_bd++; chan->tx_first_bd = (chan->tx_first_bd + 1) & (N_DMA_TX_BUF - 1); - ptdescr = (pcsca_bd_t *)(card->hw.rambase + - TX_BD_ADDR(ch,chan->tx_first_bd)); + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd)); } #ifdef CONFIG_PC300_MLPPP @@ -2006,7 +2005,7 @@ static void sca_intr(pc300_t * card) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; volatile uclong status; int ch; int intr_count = 0; @@ -2187,7 +2186,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) && !pfalc->loop_gen) { @@ -2212,7 +2211,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) && !pfalc->loop_gen) { @@ -2237,7 +2236,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar isr0, isr3, gis; ucchar dummy; @@ -2284,7 +2283,7 @@ { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar isr1, isr2, isr3, gis, rsp; ucchar dummy; @@ -2408,7 +2407,7 @@ void cpc_sca_status(pc300_t * card, int ch) { ucchar ilar; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; uclong flags; tx_dma_buf_check(card, ch); @@ -2544,7 +2543,7 @@ int ch = chan->channel; void __user *arg = ifr->ifr_data; struct if_settings *settings = &ifr->ifr_settings; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -2863,8 +2862,8 @@ pc300ch_t *chan = (pc300ch_t *) d->chan; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; pc300_t *card = (pc300_t *) chan->card; - uclong scabase = card->hw.scabase; - uclong plxbase = card->hw.plxbase; + void __iomem *scabase = card->hw.scabase; + void __iomem *plxbase = card->hw.plxbase; int ch = chan->channel; uclong clkrate = chan->conf.phys_settings.clock_rate; uclong clktype = chan->conf.phys_settings.clock_type; @@ -3010,7 +3009,7 @@ { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; int ch = chan->channel; cpc_writeb(scabase + DSR_RX(ch), 0); @@ -3041,7 +3040,7 @@ { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; int ch = chan->channel; cpc_writeb(scabase + DSR_TX(ch), 0); @@ -3105,7 +3104,7 @@ pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; ch_config(d); @@ -3211,7 +3210,7 @@ { uclong i; ucchar data; - uclong rambase = card->hw.rambase; + void __iomem *rambase = card->hw.rambase; card->hw.ramsize = PC300_RAMSIZE; /* Let's find out how much RAM is present on this board */ @@ -3227,7 +3226,7 @@ static void plx_init(pc300_t * card) { - struct RUNTIME_9050 *plx_ctl = (struct RUNTIME_9050 *) card->hw.plxbase; + struct RUNTIME_9050 __iomem *plx_ctl = card->hw.plxbase; /* Reset PLX */ cpc_writel(&plx_ctl->init_ctrl, @@ -3532,10 +3531,9 @@ if ((err = pci_enable_device(pdev)) != 0) goto err_release_sca; - card->hw.plxbase = (uclong) ioremap(card->hw.plxphys, card->hw.plxsize); - card->hw.rambase = (uclong) ioremap(card->hw.ramphys, - card->hw.alloc_ramsize); - card->hw.scabase = (uclong) ioremap(card->hw.scaphys, card->hw.scasize); + card->hw.plxbase = ioremap(card->hw.plxphys, card->hw.plxsize); + card->hw.rambase = ioremap(card->hw.ramphys, card->hw.alloc_ramsize); + card->hw.scabase = ioremap(card->hw.scaphys, card->hw.scasize); switch (device_id) { case PCI_DEVICE_ID_PC300_TE_1: case PCI_DEVICE_ID_PC300_TE_2: @@ -3543,14 +3541,13 @@ case PCI_DEVICE_ID_PC300_TE_M_2: request_mem_region(card->hw.falcphys, card->hw.falcsize, "FALC Registers"); - card->hw.falcbase = (uclong) ioremap(card->hw.falcphys, - card->hw.falcsize); + card->hw.falcbase = ioremap(card->hw.falcphys, card->hw.falcsize); break; case PCI_DEVICE_ID_PC300_RX_1: case PCI_DEVICE_ID_PC300_RX_2: default: - card->hw.falcbase = 0; + card->hw.falcbase = NULL; break; } @@ -3616,11 +3613,11 @@ return 0; err_io_unmap: - iounmap((void *) card->hw.plxbase); - iounmap((void *) card->hw.scabase); - iounmap((void *) card->hw.rambase); + iounmap(card->hw.plxbase); + iounmap(card->hw.scabase); + iounmap(card->hw.rambase); if (card->hw.type == PC300_TE) { - iounmap((void *) card->hw.falcbase); + iounmap(card->hw.falcbase); release_mem_region(card->hw.falcphys, card->hw.falcsize); } err_release_sca: @@ -3649,15 +3646,15 @@ for (i = 0; i < card->hw.nchan; i++) { unregister_hdlc_device(card->chan[i].d.dev); } - iounmap((void *) card->hw.plxbase); - iounmap((void *) card->hw.scabase); - iounmap((void *) card->hw.rambase); + iounmap(card->hw.plxbase); + iounmap(card->hw.scabase); + iounmap(card->hw.rambase); release_mem_region(card->hw.plxphys, card->hw.plxsize); release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize); release_mem_region(card->hw.scaphys, card->hw.scasize); release_region(card->hw.iophys, card->hw.iosize); if (card->hw.type == PC300_TE) { - iounmap((void *) card->hw.falcbase); + iounmap(card->hw.falcbase); release_mem_region(card->hw.falcphys, card->hw.falcsize); } for (i = 0; i < card->hw.nchan; i++) diff -Nru a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c --- a/drivers/net/wan/pc300_tty.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/wan/pc300_tty.c 2004-10-18 14:56:29 -07:00 @@ -192,13 +192,14 @@ */ void cpc_tty_init(pc300dev_t *pc300dev) { - int port, aux; + unsigned long port; + int aux; st_cpc_tty_area * cpc_tty; /* hdlcX - X=interface number */ port = pc300dev->dev->name[4] - '0'; if (port >= CPC_TTY_NPORTS) { - printk("%s-tty: invalid interface selected (0-%i): %i", + printk("%s-tty: invalid interface selected (0-%i): %li", pc300dev->dev->name, CPC_TTY_NPORTS-1,port); return; @@ -634,14 +635,8 @@ } CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name); - - wake_up_interruptible(&tty->write_wait); - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){ - CPC_TTY_DBG("%s: call line disc. wake up\n",cpc_tty->name); - tty->ldisc.write_wakeup(tty); - } + tty_wakeup(tty); return; } @@ -688,25 +683,32 @@ */ static void cpc_tty_rx_work(void * data) { - int port, i, j; + unsigned long port; + int i, j; st_cpc_tty_area *cpc_tty; volatile st_cpc_rx_buf * buf; char flags=0,flg_rx=1; + struct tty_ldisc *ld; if (cpc_tty_cnt == 0) return; + for (i=0; (i < 4) && flg_rx ; i++) { flg_rx = 0; - port = (int) data; + port = (unsigned long)data; for (j=0; j < CPC_TTY_NPORTS; j++) { cpc_tty = &cpc_tty_area[port]; if ((buf=cpc_tty->buf_rx.first) != 0) { - - if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { - CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); - cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (char *)(buf->data), - &flags, buf->size); + if(cpc_tty->tty) { + ld = tty_ldisc_ref(cpc_tty->tty); + if(ld) { + if (ld->receive_buf) { + CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); + ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); + } + tty_ldisc_deref(ld); + } } cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; kfree((unsigned char *)buf); @@ -760,7 +762,7 @@ int rx_len, rx_aux; volatile unsigned char status; unsigned short first_bd = pc300chan->rx_first_bd; - st_cpc_rx_buf *new; + st_cpc_rx_buf *new=NULL; unsigned char dsr_rx; if (pc300dev->cpc_tty == NULL) { @@ -789,6 +791,10 @@ cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), RX_BD_ADDR(ch, pc300chan->rx_last_bd)); } + if (new) { + kfree(new); + new = NULL; + } return; } @@ -834,7 +840,8 @@ cpc_tty->name); cpc_tty_rx_disc_frame(pc300chan); rx_len = 0; - kfree((unsigned char *)new); + kfree(new); + new = NULL; break; /* read next frame - while(1) */ } @@ -843,7 +850,8 @@ cpc_tty_rx_disc_frame(pc300chan); stats->rx_dropped++; rx_len = 0; - kfree((unsigned char *)new); + kfree(new); + new = NULL; break; /* read next frame - while(1) */ } @@ -910,13 +918,7 @@ CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name); return; } - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){ - CPC_TTY_DBG("%s:call line disc. wakeup\n",cpc_tty->name); - tty->ldisc.write_wakeup (tty); - } - - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } /* diff -Nru a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c --- a/drivers/net/wan/sdla_chdlc.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/net/wan/sdla_chdlc.c 2004-10-18 14:56:31 -07:00 @@ -3628,11 +3628,7 @@ if ((tty=card->tty)==NULL) return; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); #if defined(SERIAL_HAVE_POLL_WAIT) wake_up_interruptible(&tty->poll_wait); #endif @@ -3857,6 +3853,7 @@ char fp=0; struct tty_struct *tty; int i; + struct tty_ldisc *ld; if (!card->tty_open){ dbg_printk(KERN_INFO "%s: TTY not open during receive\n", @@ -3944,8 +3941,11 @@ len -= offset; } sdla_peek(&card->hw, addr, card->tty_rx+offset, len); - if (tty->ldisc.receive_buf){ - tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen); + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty,card->tty_rx,&fp,olen); + tty_ldisc_deref(ld); }else{ if (net_ratelimit()){ printk(KERN_INFO @@ -4252,14 +4252,10 @@ if (!tty) return; - wake_up_interruptible(&tty->write_wait); #if defined(SERIAL_HAVE_POLL_WAIT) wake_up_interruptible(&tty->poll_wait); #endif - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - + tty_wakeup(tty); return; } diff -Nru a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c --- a/drivers/net/wan/sdla_fr.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/wan/sdla_fr.c 2004-10-18 14:57:04 -07:00 @@ -3678,7 +3678,7 @@ break; } - (void *)ptr_trc_el = card->u.f.curr_trc_el; + ptr_trc_el = (void *)card->u.f.curr_trc_el; buffer_length = 0; fr_udp_pkt->data[0x00] = 0x00; @@ -3729,7 +3729,7 @@ ptr_trc_el ++; if((void *)ptr_trc_el > card->u.f.trc_el_last) - (void*)ptr_trc_el = card->u.f.trc_el_base; + ptr_trc_el = (void*)card->u.f.trc_el_base; buffer_length += sizeof(fpipemon_trc_hdr_t); if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { diff -Nru a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c --- a/drivers/net/wan/sdladrv.c 2004-10-18 14:56:20 -07:00 +++ b/drivers/net/wan/sdladrv.c 2004-10-18 14:56:20 -07:00 @@ -937,7 +937,7 @@ peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, curlen); addr += curlen; - (char*)buf += curlen; + buf = (char*)buf + curlen; len -= curlen; } @@ -1019,7 +1019,7 @@ poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, curlen); addr += curlen; - (char*)buf += curlen; + buf = (char*)buf + curlen; len -= curlen; } @@ -2001,7 +2001,7 @@ (void *)hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, (unsigned long)MAX_SIZEOF_S514_MEMORY); /* map the physical control register memory to virtual memory */ - (void *)hw->vector = ioremap( + hw->vector = (unsigned long)ioremap( (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), (unsigned long)16); diff -Nru a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c --- a/drivers/net/wan/sdlamain.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/net/wan/sdlamain.c 2004-10-18 14:56:49 -07:00 @@ -976,7 +976,7 @@ dump.length -= len; dump.offset += len; - (char*)dump.ptr += len; + dump.ptr = (char*)dump.ptr + len; } sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c --- a/drivers/net/wan/syncppp.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/net/wan/syncppp.c 2004-10-18 14:56:27 -07:00 @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -767,9 +768,9 @@ struct in_ifaddr *ifa; u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ #ifdef CONFIG_INET - if ((in_dev=in_dev_get(dev)) != NULL) + rcu_read_lock(); + if ((in_dev = __in_dev_get(dev)) != NULL) { - read_lock(&in_dev->lock); for (ifa=in_dev->ifa_list; ifa != NULL; ifa=ifa->ifa_next) { if (strcmp(dev->name, ifa->ifa_label) == 0) @@ -779,9 +780,8 @@ break; } } - read_unlock(&in_dev->lock); - in_dev_put(in_dev); } + rcu_read_unlock(); #endif /* I hope both addr and mask are in the net order */ sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/net/wireless/airo.c 2004-10-18 14:55:55 -07:00 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -1815,7 +1816,8 @@ if (!test_bit (FLAG_COMMIT, &ai->flags)) return SUCCESS; - clear_bit (FLAG_COMMIT | FLAG_RESET, &ai->flags); + clear_bit (FLAG_COMMIT, &ai->flags); + clear_bit (FLAG_RESET, &ai->flags); checkThrottle(ai); cfgr = ai->config; @@ -1979,9 +1981,6 @@ ai->txfids[0].tx_desc.eoc = 1; ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); - memcpy((char *)ai->txfids[0].card_ram_off, - (char *)&ai->txfids[0].tx_desc, sizeof(TxFid)); - /* * Magic, the cards firmware needs a length count (2 bytes) in the host buffer * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen @@ -2011,6 +2010,7 @@ return ERROR; *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); + ai->txfids[0].tx_desc.len += sizeof(pMic); /* copy data into airo dma buffer */ memcpy (sendbuf, buffer, sizeof(etherHead)); buffer += sizeof(etherHead); @@ -2029,6 +2029,9 @@ memcpy(sendbuf, buffer, len); } + memcpy((char *)ai->txfids[0].card_ram_off, + (char *)&ai->txfids[0].tx_desc, sizeof(TxFid)); + OUT4500(ai, EVACK, 8); dev_kfree_skb_any(skb); @@ -2183,6 +2186,12 @@ struct airo_info *priv = dev->priv; u32 *fids = priv->fids; + if (test_bit(FLAG_MPI, &priv->flags)) { + /* Not implemented yet for MPI350 */ + netif_stop_queue(dev); + return -ENETDOWN; + } + if ( skb == NULL ) { printk( KERN_ERR "airo: skb == NULL!!!\n" ); return 0; @@ -2248,12 +2257,14 @@ { struct airo_info *local = dev->priv; - /* Get stats out of the card if available */ - if (down_trylock(&local->sem) != 0) { - set_bit(JOB_STATS, &local->flags); - wake_up_interruptible(&local->thr_wait); - } else - airo_read_stats(local); + if (!test_bit(JOB_STATS, &local->flags)) { + /* Get stats out of the card if available */ + if (down_trylock(&local->sem) != 0) { + set_bit(JOB_STATS, &local->flags); + wake_up_interruptible(&local->thr_wait); + } else + airo_read_stats(local); + } return &local->stats; } @@ -2339,6 +2350,9 @@ void stop_airo_card( struct net_device *dev, int freeres ) { struct airo_info *ai = dev->priv; + + set_bit(FLAG_RADIO_DOWN, &ai->flags); + disable_MAC(ai, 1); disable_interrupts(ai); free_irq( dev->irq, dev ); takedown_proc_entry( dev, ai ); @@ -3405,13 +3419,8 @@ } static void enable_interrupts( struct airo_info *ai ) { - /* Reset the status register */ - u16 status = IN4500( ai, EVSTAT ); - OUT4500( ai, EVACK, status ); /* Enable the interrupts */ OUT4500( ai, EVINTEN, STATUS_INTS ); - /* Note there is a race condition between the last two lines that - I don't know how to get rid of right now... */ } static void disable_interrupts( struct airo_info *ai ) { @@ -3459,7 +3468,7 @@ memcpy(buffer + ETH_ALEN * 2, ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, len - ETH_ALEN * 2 - off); - if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off)) { + if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { badmic: dev_kfree_skb_irq (skb); goto badrx; @@ -3669,18 +3678,6 @@ status = readCapabilityRid(ai, &cap_rid, lock); if ( status != SUCCESS ) return ERROR; - /* - * This driver supports MPI350 firmwares up to, and - * including 5.30.17 - */ - if (test_bit(FLAG_MPI, &ai->flags) && - strncmp (cap_rid.prodVer, "5.00.", 5) && - strncmp (cap_rid.prodVer, "5b00.", 5) && - strncmp (cap_rid.prodVer, "5.02.", 5) && - strncmp (cap_rid.prodVer, "5.20.", 5) && - strncmp (cap_rid.prodVer, "5.30.", 5)) - printk(KERN_ERR "airo: Firmware version %s is not supported. Use it at your own risk!\n", cap_rid.prodVer); - status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock); if ( status == SUCCESS ) { if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) @@ -3715,9 +3712,9 @@ /* Check to see if there are any insmod configured rates to add */ - if ( rates ) { + if ( rates[0] ) { int i = 0; - if ( rates[0] ) memset(ai->config.rates,0,sizeof(ai->config.rates)); + memset(ai->config.rates,0,sizeof(ai->config.rates)); for( i = 0; i < 8 && rates[i]; i++ ) { ai->config.rates[i] = rates[i]; } @@ -3784,7 +3781,6 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { // Im really paranoid about letting it run forever! int max_tries = 600000; - u16 cmd; if (IN4500(ai, EVSTAT) & EV_CMD) OUT4500(ai, EVACK, EV_CMD); @@ -3793,26 +3789,23 @@ OUT4500(ai, PARAM1, pCmd->parm1); OUT4500(ai, PARAM2, pCmd->parm2); OUT4500(ai, COMMAND, pCmd->cmd); - while ( max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0 && - (cmd = IN4500(ai, COMMAND)) != 0 ) - if (cmd == pCmd->cmd) - // PC4500 didn't notice command, try again - OUT4500(ai, COMMAND, pCmd->cmd); - if ( max_tries == -1 ) { - printk( KERN_ERR - "airo: Max tries exceeded when issueing command\n" ); - return ERROR; - } while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { + if ((IN4500(ai, COMMAND)) == pCmd->cmd) + // PC4500 didn't notice command, try again + OUT4500(ai, COMMAND, pCmd->cmd); if (!in_atomic() && (max_tries & 255) == 0) schedule(); } + if ( max_tries == -1 ) { printk( KERN_ERR - "airo: Max tries exceeded waiting for command\n" ); - return ERROR; + "airo: Max tries exceeded when issueing command\n" ); + if (IN4500(ai, COMMAND) & COMMAND_BUSY) + OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); + return ERROR; } + // command completed pRsp->status = IN4500(ai, STATUS); pRsp->rsp0 = IN4500(ai, RESP0); @@ -4508,8 +4501,6 @@ len = priv->readlen - pos; if (copy_to_user(buffer, priv->rbuffer + pos, len)) return -EFAULT; - if (pos + len > priv->writelen) - priv->writelen = pos + len; *offset = pos + len; return len; } @@ -5520,7 +5511,6 @@ mpi_init_descriptors(ai); setup_card(ai, dev->dev_addr, 0); clear_bit(FLAG_RADIO_OFF, &ai->flags); - clear_bit(FLAG_RADIO_DOWN, &ai->flags); clear_bit(FLAG_PENDING_XMIT, &ai->flags); } else { OUT4500(ai, EVACK, EV_AWAKEN); @@ -5605,6 +5595,30 @@ * would not work at all... - Jean II */ +static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) +{ + int quality = 0; + + if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) { + if (memcmp(cap_rid->prodName, "350", 3)) + if (status_rid->signalQuality > 0x20) + quality = 0; + else + quality = 0x20 - status_rid->signalQuality; + else + if (status_rid->signalQuality > 0xb0) + quality = 0; + else if (status_rid->signalQuality < 0x10) + quality = 0xa0; + else + quality = 0xb0 - status_rid->signalQuality; + } + return quality; +} + +#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0) +#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50); + /*------------------------------------------------------------------*/ /* * Wireless Handler : get protocol name @@ -6292,7 +6306,8 @@ readCapabilityRid(local, &cap_rid, 1); if (vwrq->disabled) { - set_bit (FLAG_RADIO_OFF | FLAG_COMMIT, &local->flags); + set_bit (FLAG_RADIO_OFF, &local->flags); + set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ } if (vwrq->flags != IW_TXPOW_MWATT) { @@ -6431,7 +6446,7 @@ range->num_frequency = k; /* Hum... Should put the right values there */ - range->max_qual.qual = 10; + range->max_qual.qual = airo_get_max_quality(&cap_rid); range->max_qual.level = 0x100 - 120; /* -120 dBm */ range->max_qual.noise = 0; range->sensitivity = 65535; @@ -6498,7 +6513,7 @@ /* Experimental measurements - boundary 11/5.5 Mb/s */ /* Note : with or without the (local->rssi), results * are somewhat different. - Jean II */ - range->avg_qual.qual = 6; + range->avg_qual.qual = airo_get_avg_quality(&cap_rid); if (local->rssi) range->avg_qual.level = 186; /* -70 dBm */ else @@ -7112,6 +7127,7 @@ { StatusRid status_rid; StatsRid stats_rid; + CapabilityRid cap_rid; u32 *vals = stats_rid.vals; /* Get stats out of the card */ @@ -7120,6 +7136,7 @@ up(&local->sem); return; } + readCapabilityRid(local, &cap_rid, 0); readStatusRid(local, &status_rid, 0); readStatsRid(local, &stats_rid, RID_STATS, 0); up(&local->sem); @@ -7128,7 +7145,7 @@ local->wstats.status = status_rid.mode; /* Signal quality and co. But where is the noise level ??? */ - local->wstats.qual.qual = status_rid.signalQuality; + local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); if (local->rssi) local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm; else @@ -7155,12 +7172,14 @@ { struct airo_info *local = dev->priv; - /* Get stats out of the card if available */ - if (down_trylock(&local->sem) != 0) { - set_bit(JOB_WSTATS, &local->flags); - wake_up_interruptible(&local->thr_wait); - } else - airo_read_wireless_stats(local); + if (!test_bit(JOB_WSTATS, &local->flags)) { + /* Get stats out of the card if available */ + if (down_trylock(&local->sem) != 0) { + set_bit(JOB_WSTATS, &local->flags); + wake_up_interruptible(&local->thr_wait); + } else + airo_read_wireless_stats(local); + } return &local->wstats; } @@ -7187,9 +7206,11 @@ { case AIROGCAP: ridcode = RID_CAPABILITIES; break; case AIROGCFG: ridcode = RID_CONFIG; - disable_MAC (ai, 1); - writeConfigRid (ai, 1); - enable_MAC (ai, &rsp, 1); + if (test_bit(FLAG_COMMIT, &ai->flags)) { + disable_MAC (ai, 1); + writeConfigRid (ai, 1); + enable_MAC (ai, &rsp, 1); + } break; case AIROGSLIST: ridcode = RID_SSID; break; case AIROGVLIST: ridcode = RID_APLIST; break; @@ -7269,6 +7290,7 @@ case AIROPCAP: ridcode = RID_CAPABILITIES; break; case AIROPAPLIST: ridcode = RID_APLIST; break; case AIROPCFG: ai->config.len = 0; + clear_bit(FLAG_COMMIT, &ai->flags); ridcode = RID_CONFIG; break; case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break; case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break; diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c --- a/drivers/net/wireless/airport.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/wireless/airport.c 2004-10-18 14:57:04 -07:00 @@ -1,4 +1,4 @@ -/* airport.c 0.13e +/* airport.c * * A driver for "Hermes" chipset based Apple Airport wireless * card. @@ -11,6 +11,9 @@ * 0.06 : fix possible hang on powerup, add sleep support */ +#define DRIVER_NAME "airport" +#define PFX DRIVER_NAME ": " + #include #include @@ -25,6 +28,7 @@ #include #include #include +#include #include #include @@ -50,7 +54,7 @@ airport_suspend(struct macio_dev *mdev, u32 state) { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -84,15 +88,14 @@ airport_resume(struct macio_dev *mdev) { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/5); + msleep(200); enable_irq(dev->irq); @@ -126,7 +129,7 @@ airport_detach(struct macio_dev *mdev) { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct airport *card = priv->card; if (card->ndev_registered) @@ -144,8 +147,7 @@ macio_release_resource(mdev, 0); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); macio_set_drvdata(mdev, NULL); free_netdev(dev); @@ -171,14 +173,12 @@ disable_irq(dev->irq); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); enable_irq(dev->irq); - schedule_timeout(HZ); + ssleep(1); #endif return 0; @@ -194,24 +194,24 @@ hermes_t *hw; if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { - printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); + printk(KERN_ERR PFX "wrong interrupt/addresses in OF tree\n"); return -ENODEV; } /* Allocate space for private device-specific data */ dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); if (! dev) { - printk(KERN_ERR "airport: can't allocate device datas\n"); + printk(KERN_ERR PFX "can't allocate device datas\n"); return -ENODEV; } - priv = dev->priv; + priv = netdev_priv(dev); card = priv->card; hw = &priv->hw; card->mdev = mdev; if (macio_request_resource(mdev, 0, "airport")) { - printk(KERN_ERR "airport: can't request IO resource !\n"); + printk(KERN_ERR PFX "can't request IO resource !\n"); free_netdev(dev); return -EBUSY; } @@ -224,11 +224,11 @@ /* Setup interrupts & base address */ dev->irq = macio_irq(mdev, 0); phys_addr = macio_resource_start(mdev, 0); /* Physical address */ - printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr); + printk(KERN_DEBUG PFX "Airport at physical address %lx\n", phys_addr); dev->base_addr = phys_addr; card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); if (!card->vaddr) { - printk("airport: ioremap() failed\n"); + printk(PFX "ioremap() failed\n"); goto failed; } @@ -237,24 +237,23 @@ /* Power up card */ pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); /* Reset it before we get the interrupt */ hermes_init(hw); if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) { - printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq); + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); goto failed; } card->irq_requested = 1; /* Tell the stack we exist */ if (register_netdev(dev) != 0) { - printk(KERN_ERR "airport: register_netdev() failed\n"); + printk(KERN_ERR PFX "register_netdev() failed\n"); goto failed; } - printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name); + printk(KERN_DEBUG PFX "card registered for interface %s\n", dev->name); card->ndev_registered = 1; return 0; failed: @@ -263,7 +262,8 @@ } /* airport_attach */ -static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt )"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Benjamin Herrenschmidt )"; MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); @@ -280,7 +280,7 @@ static struct macio_driver airport_driver = { - .name = "airport", + .name = DRIVER_NAME, .match_table = airport_match, .probe = airport_attach, .remove = airport_detach, diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c --- a/drivers/net/wireless/atmel.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/net/wireless/atmel.c 2004-10-18 14:56:27 -07:00 @@ -2430,12 +2430,13 @@ rc = -ENOMEM; break; } - + if (copy_from_user(new_firmware, com.data, com.len)) { + kfree(new_firmware); rc = -EFAULT; break; } - + if (priv->firmware) kfree(priv->firmware); diff -Nru a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c --- a/drivers/net/wireless/hermes.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/net/wireless/hermes.c 2004-10-18 14:56:17 -07:00 @@ -13,8 +13,8 @@ * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no * particular order). * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * Copyright (C) 2001, David Gibson, IBM + * Copyright (C) 2000, David Gibson, Linuxcare Australia. + * (C) Copyright David Gibson, IBM Corp. 2001-2003. * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -53,10 +53,9 @@ #include "hermes.h" MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); -MODULE_AUTHOR("David Gibson "); -#ifdef MODULE_LICENSE +MODULE_AUTHOR("Pavel Roskin " + " & David Gibson "); MODULE_LICENSE("Dual MPL/GPL"); -#endif /* These are maximum timeouts. Most often, card wil react much faster */ #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ @@ -226,7 +225,7 @@ * * Callable from any context, but locking is your problem. */ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, - hermes_response_t *resp) + struct hermes_response *resp) { int err; int k; @@ -391,7 +390,6 @@ if (reg & HERMES_OFFSET_ERR) { return -EIO; } - return 0; } diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h --- a/drivers/net/wireless/hermes.h 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/wireless/hermes.h 2004-10-18 14:55:54 -07:00 @@ -12,7 +12,8 @@ * project, the Linux wvlan_cs driver, Lucent's HCF-Light * (wvlan_hcf.c) library, and the NetBSD wireless driver. * - * Copyright (C) 2000, David Gibson, Linuxcare Australia + * Copyright (C) 2000, David Gibson, Linuxcare Australia. + * (C) Copyright David Gibson, IBM Corp. 2001-2003. * * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. * @@ -124,29 +125,52 @@ /* * Command codes */ -/*--- Controller Commands --------------------------*/ +/*--- Controller Commands ----------------------------*/ #define HERMES_CMD_INIT (0x0000) #define HERMES_CMD_ENABLE (0x0001) #define HERMES_CMD_DISABLE (0x0002) #define HERMES_CMD_DIAG (0x0003) -/*--- Buffer Mgmt Commands --------------------------*/ +/*--- Buffer Mgmt Commands ---------------------------*/ #define HERMES_CMD_ALLOC (0x000A) #define HERMES_CMD_TX (0x000B) -#define HERMES_CMD_CLRPRST (0x0012) -/*--- Regulate Commands --------------------------*/ +/*--- Regulate Commands ------------------------------*/ #define HERMES_CMD_NOTIFY (0x0010) #define HERMES_CMD_INQUIRE (0x0011) -/*--- Configure Commands --------------------------*/ +/*--- Configure Commands -----------------------------*/ #define HERMES_CMD_ACCESS (0x0021) #define HERMES_CMD_DOWNLD (0x0022) +/*--- Serial I/O Commands ----------------------------*/ +#define HERMES_CMD_READMIF (0x0030) +#define HERMES_CMD_WRITEMIF (0x0031) + /*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_MONITOR (0x0038) -#define HERMES_MONITOR_ENABLE (0x000b) -#define HERMES_MONITOR_DISABLE (0x000f) +#define HERMES_CMD_TEST (0x0038) + + +/* Test command arguments */ +#define HERMES_TEST_SET_CHANNEL 0x0800 +#define HERMES_TEST_MONITOR 0x0b00 +#define HERMES_TEST_STOP 0x0f00 + +/* Authentication algorithms */ +#define HERMES_AUTH_OPEN 1 +#define HERMES_AUTH_SHARED_KEY 2 + +/* WEP settings */ +#define HERMES_WEP_PRIVACY_INVOKED 0x0001 +#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 +#define HERMES_WEP_HOST_ENCRYPT 0x0010 +#define HERMES_WEP_HOST_DECRYPT 0x0080 + +/* Symbol hostscan options */ +#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 +#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 +#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 +#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 /* * Frame structures and constants @@ -157,16 +181,6 @@ #define HERMES_802_3_OFFSET (14+32) #define HERMES_802_2_OFFSET (14+32+14) -struct hermes_rx_descriptor { - u16 status; - u32 time; - u8 silence; - u8 signal; - u8 rate; - u8 rxflow; - u32 reserved; -} __attribute__ ((packed)); - #define HERMES_RXSTAT_ERR (0x0003) #define HERMES_RXSTAT_BADCRC (0x0001) #define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) @@ -201,7 +215,11 @@ #define HERMES_INQ_TALLIES (0xF100) #define HERMES_INQ_SCAN (0xF101) +#define HERMES_INQ_CHANNELINFO (0xF102) +#define HERMES_INQ_HOSTSCAN (0xF103) +#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) #define HERMES_INQ_LINKSTATUS (0xF200) +#define HERMES_INQ_SEC_STAT_AGERE (0xF202) struct hermes_tallies_frame { u16 TxUnicastFrames; @@ -233,23 +251,58 @@ /* Grabbed from wlan-ng - Thanks Mark... - Jean II * This is the result of a scan inquiry command */ /* Structure describing info about an Access Point */ -struct hermes_scan_apinfo { +struct prism2_scan_apinfo { u16 channel; /* Channel where the AP sits */ u16 noise; /* Noise level */ u16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval ? */ - u16 capabilities; /* Capabilities ? */ + u16 beacon_interv; /* Beacon interval */ + u16 capabilities; /* Capabilities */ + u16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ u8 rates[10]; /* Bit rate supported */ - u16 proberesp_rate; /* ???? */ + u16 proberesp_rate; /* Data rate of the response frame */ + u16 atim; /* ATIM window time, Kus (hostscan only) */ } __attribute__ ((packed)); -/* Container */ -struct hermes_scan_frame { - u16 rsvd; /* ??? */ - u16 scanreason; /* ??? */ - struct hermes_scan_apinfo aps[35]; /* Scan result */ + +/* Same stuff for the Lucent/Agere card. + * Thanks to h1kari - Jean II */ +struct agere_scan_apinfo { + u16 channel; /* Channel where the AP sits */ + u16 noise; /* Noise level */ + u16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + u16 beacon_interv; /* Beacon interval */ + u16 capabilities; /* Capabilities */ + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ + u16 essid_len; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ +} __attribute__ ((packed)); + +/* Moustafa: Scan structure for Symbol cards */ +struct symbol_scan_apinfo { + u8 channel; /* Channel where the AP sits */ + u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ + u16 noise; /* Noise level */ + u16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + u16 beacon_interv; /* Beacon interval */ + u16 capabilities; /* Capabilities */ + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ + u16 essid_len; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ + u16 rates[5]; /* Bit rate supported */ + u16 basic_rates; /* Basic rates bitmask */ + u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ + u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ } __attribute__ ((packed)); + +union hermes_scan_info { + struct agere_scan_apinfo a; + struct prism2_scan_apinfo p; + struct symbol_scan_apinfo s; +}; + #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) #define HERMES_LINKSTATUS_CONNECTED (0x0001) #define HERMES_LINKSTATUS_DISCONNECTED (0x0002) @@ -262,6 +315,20 @@ u16 linkstatus; /* Link status */ } __attribute__ ((packed)); +struct hermes_response { + u16 status, resp0, resp1, resp2; +}; + +/* "ID" structure - used for ESSID and station nickname */ +struct hermes_idstring { + u16 len; + u16 val[16]; +} __attribute__ ((packed)); + +struct hermes_multicast { + u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)); + // #define HERMES_DEBUG_BUFFER 1 #define HERMES_DEBUG_BUFSIZE 4096 struct hermes_debug_entry { @@ -294,10 +361,6 @@ #endif } hermes_t; -typedef struct hermes_response { - u16 status, resp0, resp1, resp2; -} hermes_response_t; - /* Register access convenience macros */ #define hermes_read_reg(hw, off) ((hw)->io_space ? \ inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \ @@ -312,9 +375,11 @@ #define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val)) /* Function prototypes */ -void hermes_struct_init(hermes_t *hw, ulong address, int io_space, int reg_spacing); +void hermes_struct_init(hermes_t *hw, ulong address, int io_space, + int reg_spacing); int hermes_init(hermes_t *hw); -int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp); +int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, + struct hermes_response *resp); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, diff -Nru a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h --- a/drivers/net/wireless/hermes_rid.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/net/wireless/hermes_rid.h 2004-10-18 14:56:29 -07:00 @@ -4,21 +4,21 @@ /* * Configuration RIDs */ -#define HERMES_RID_CNFPORTTYPE 0xFC00 /* used */ -#define HERMES_RID_CNFOWNMACADDR 0xFC01 /* used */ -#define HERMES_RID_CNFDESIREDSSID 0xFC02 /* used */ -#define HERMES_RID_CNFOWNCHANNEL 0xFC03 /* used */ -#define HERMES_RID_CNFOWNSSID 0xFC04 /* used */ +#define HERMES_RID_CNFPORTTYPE 0xFC00 +#define HERMES_RID_CNFOWNMACADDR 0xFC01 +#define HERMES_RID_CNFDESIREDSSID 0xFC02 +#define HERMES_RID_CNFOWNCHANNEL 0xFC03 +#define HERMES_RID_CNFOWNSSID 0xFC04 #define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 -#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 /* used */ +#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 #define HERMES_RID_CNFMAXDATALEN 0xFC07 #define HERMES_RID_CNFWDSADDRESS 0xFC08 -#define HERMES_RID_CNFPMENABLED 0xFC09 /* used */ +#define HERMES_RID_CNFPMENABLED 0xFC09 #define HERMES_RID_CNFPMEPS 0xFC0A -#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B /* used */ -#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C /* used */ -#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D /* used */ -#define HERMES_RID_CNFOWNNAME 0xFC0E /* used */ +#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B +#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C +#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D +#define HERMES_RID_CNFOWNNAME 0xFC0E #define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 #define HERMES_RID_CNFWDSADDRESS1 0xFC11 #define HERMES_RID_CNFWDSADDRESS2 0xFC12 @@ -27,17 +27,18 @@ #define HERMES_RID_CNFWDSADDRESS5 0xFC15 #define HERMES_RID_CNFWDSADDRESS6 0xFC16 #define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 -#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 /* used */ +#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 +#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 #define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 -#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 /* used */ -#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 /* used */ -#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 /* used */ -#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 /* used */ -#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 /* used */ -#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 /* used */ -#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 /* used */ +#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 +#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 +#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 +#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 +#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 +#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 +#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 #define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HERMES_RID_CNFAUTHENTICATION 0xFC2A /* used */ +#define HERMES_RID_CNFAUTHENTICATION 0xFC2A #define HERMES_RID_CNFMAXASSOCSTA 0xFC2B #define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B #define HERMES_RID_CNFTXCONTROL 0xFC2C @@ -53,14 +54,14 @@ #define HERMES_RID_CNFTIMCTRL 0xFC40 #define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 #define HERMES_RID_CNFENHSECURITY 0xFC43 -#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 /* used */ -#define HERMES_RID_CNFCREATEIBSS 0xFC81 /* used */ -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 /* used */ -#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 /* used */ -#define HERMES_RID_CNFTXRATECONTROL 0xFC84 /* used */ -#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 /* used */ +#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 +#define HERMES_RID_CNFCREATEIBSS 0xFC81 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 +#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 +#define HERMES_RID_CNFTXRATECONTROL 0xFC84 +#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 #define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A -#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C /* used */ +#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 @@ -75,18 +76,21 @@ #define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B #define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C #define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D +#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB #define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 /* used */ +#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 #define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 /* used */ +#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 #define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 +#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 #define HERMES_RID_CNFBASICRATES 0xFCB3 #define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HERMES_RID_CNFTICKTIME 0xFCE0 /* used */ +#define HERMES_RID_CNFTICKTIME 0xFCE0 #define HERMES_RID_CNFSCANREQUEST 0xFCE1 #define HERMES_RID_CNFJOINREQUEST 0xFCE2 #define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 #define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 +#define HERMES_RID_CNFHOSTSCAN 0xFCE5 /* * Information RIDs @@ -100,30 +104,31 @@ #define HERMES_RID_NICID 0xFD0B #define HERMES_RID_MFISUPRANGE 0xFD0C #define HERMES_RID_CFISUPRANGE 0xFD0D -#define HERMES_RID_CHANNELLIST 0xFD10 /* used */ +#define HERMES_RID_CHANNELLIST 0xFD10 #define HERMES_RID_REGULATORYDOMAINS 0xFD11 #define HERMES_RID_TEMPTYPE 0xFD12 #define HERMES_RID_CIS 0xFD13 -#define HERMES_RID_STAID 0xFD20 /* used */ +#define HERMES_RID_STAID 0xFD20 #define HERMES_RID_STASUPRANGE 0xFD21 #define HERMES_RID_MFIACTRANGES 0xFD22 #define HERMES_RID_CFIACTRANGES2 0xFD23 -#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 /* used */ +#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 #define HERMES_RID_PORTSTATUS 0xFD40 -#define HERMES_RID_CURRENTSSID 0xFD41 /* used */ -#define HERMES_RID_CURRENTBSSID 0xFD42 /* used */ -#define HERMES_RID_COMMSQUALITY 0xFD43 /* used */ -#define HERMES_RID_CURRENTTXRATE 0xFD44 /* used */ +#define HERMES_RID_CURRENTSSID 0xFD41 +#define HERMES_RID_CURRENTBSSID 0xFD42 +#define HERMES_RID_COMMSQUALITY 0xFD43 +#define HERMES_RID_CURRENTTXRATE 0xFD44 #define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 #define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 #define HERMES_RID_PROTOCOLRSPTIME 0xFD47 -#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 /* used */ -#define HERMES_RID_LONGRETRYLIMIT 0xFD49 /* used */ -#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A /* used */ +#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 +#define HERMES_RID_LONGRETRYLIMIT 0xFD49 +#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A #define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B #define HERMES_RID_CFPOLLABLE 0xFD4C #define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D #define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F +#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 #define HERMES_RID_CURRENTTXRATE1 0xFD80 #define HERMES_RID_CURRENTTXRATE2 0xFD81 #define HERMES_RID_CURRENTTXRATE3 0xFD82 @@ -133,21 +138,11 @@ #define HERMES_RID_OWNMACADDR 0xFD86 #define HERMES_RID_SCANRESULTSTABLE 0xFD88 #define HERMES_RID_PHYTYPE 0xFDC0 -#define HERMES_RID_CURRENTCHANNEL 0xFDC1 /* used */ +#define HERMES_RID_CURRENTCHANNEL 0xFDC1 #define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 #define HERMES_RID_CCAMODE 0xFDC3 -#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 /* used */ +#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 #define HERMES_RID_BUILDSEQ 0xFFFE #define HERMES_RID_FWID 0xFFFF - -/* "ID" structure - used for ESSID and station nickname */ -struct hermes_idstring { - u16 len; - u16 val[16]; -} __attribute__ ((packed)); - -typedef struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __attribute__ ((packed)) hermes_multicast_t; #endif diff -Nru a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h --- a/drivers/net/wireless/ieee802_11.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/net/wireless/ieee802_11.h 2004-10-18 14:56:32 -07:00 @@ -76,4 +76,3 @@ #define IEEE802_11_SCTL_SEQ 0xFFF0 #endif /* _IEEE802_11_H */ - diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c --- a/drivers/net/wireless/orinoco.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/net/wireless/orinoco.c 2004-10-18 14:57:05 -07:00 @@ -1,17 +1,23 @@ -/* orinoco.c 0.13e - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for Hermes or Prism 2 chipset based PCMCIA wireless * adaptors, with Lucent/Agere, Intersil or Symbol firmware. * - * Copyright (C) 2000 David Gibson, Linuxcare Australia + * Current maintainers (as of 29 September 2003) are: + * Pavel Roskin + * and David Gibson + * + * (C) Copyright David Gibson, IBM Corporation 2001-2003. + * Copyright (C) 2000 David Gibson, Linuxcare Australia. * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * Copyright (C) 2001 Benjamin Herrenschmidt + * Copyright (C) 2001 Jean Tourrilhes, HP Labs + * Copyright (C) 2001 Benjamin Herrenschmidt * * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus + * http://www.stud.fh-dortmund.de/~andy/wvlan/ * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -24,7 +30,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David + * . Portions created by David * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights * Reserved. * @@ -58,7 +64,7 @@ * o Add PM timeout (holdover duration) * o Enable "iwconfig eth0 key off" and friends (toggle flags) * o Enable "iwconfig eth0 power unicast/all" (toggle flags) - * o Try with an intel card. It report firmware 1.01, behave like + * o Try with an Intel card. It report firmware 1.01, behave like * an antiquated firmware, however on windows it says 2.00. Yuck ! * o Workaround firmware bug in allocate buffer (Intel 1.01) * o Finish external renaming to orinoco... @@ -68,8 +74,8 @@ * o Update to Wireless 11 -> add retry limit/lifetime support * o Tested with a D-Link DWL 650 card, fill in firmware support * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) - * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( - * It work on D-Link *only* after a tcpdump. Weird... + * o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-( + * It works on D-Link *only* after a tcpdump. Weird... * And still doesn't work on Intel card. Grrrr... * o Update the mode after a setport3 * o Add preamble setting for Symbol cards (not yet enabled) @@ -82,7 +88,7 @@ * o Clean up RID definitions in hermes.h, other cleanups * * v0.04b -> v0.04c - 24/4/2001 - Jean II - * o Tim Hurley reported a D-Link card + * o Tim Hurley reported a D-Link card * with vendor 02 and firmware 0.08. Added in the capabilities... * o Tested Lucent firmware 7.28, everything works... * @@ -105,15 +111,15 @@ * o Remove deferred power enabling code * * v0.05c -> v0.05d - 5/5/2001 - Jean II - * o Workaround to SNAP decapsulate frame from LinkSys AP - * original patch from : Dong Liu + * o Workaround to SNAP decapsulate frame from Linksys AP + * original patch from : Dong Liu * (note : the memcmp bug was mine - fixed) * o Remove set_retry stuff, no firmware support it (bloat--). * * v0.05d -> v0.06 - 25/5/2001 - Jean II - * Original patch from "Hong Lin" , - * "Ian Kinner" - * and "David Smith" + * Original patch from "Hong Lin" , + * "Ian Kinner" + * and "David Smith" * o Init of priv->tx_rate_ctrl in firmware specific section. * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh ! * o Spectrum card always need cor_reset (for every reset) @@ -134,15 +140,15 @@ * * v0.06c -> v0.06d - 6/7/2001 - David Gibson * o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus' - * wishes to reduce the number of unecessary messages. + * wishes to reduce the number of unnecessary messages. * o Removed bogus message on CRC error. - * o Merged fixeds for v0.08 Prism 2 firmware from William Waghorn - * + * o Merged fixes for v0.08 Prism 2 firmware from William Waghorn + * * o Slight cleanup/re-arrangement of firmware detection code. * * v0.06d -> v0.06e - 1/8/2001 - David Gibson * o Removed some redundant global initializers (orinoco_cs.c). - * o Added some module metadataa + * o Added some module metadata * * v0.06e -> v0.06f - 14/8/2001 - David Gibson * o Wording fix to license @@ -159,7 +165,7 @@ * v0.07 -> v0.07a - 1/10/3001 - Jean II * o Add code to read Symbol firmware revision, inspired by latest code * in Spectrum24 by Lee John Keyser-Allen - Thanks Lee ! - * o Thanks to Jared Valentine for "providing" me + * o Thanks to Jared Valentine for "providing" me * a 3Com card with a recent firmware, fill out Symbol firmware * capabilities of latest rev (2.20), as well as older Symbol cards. * o Disable Power Management in newer Symbol firmware, the API @@ -172,7 +178,7 @@ * o Turned has_big_wep on for Intersil cards. That's not true for all of * them but we should at least let the capable ones try. * o Wait for BUSY to clear at the beginning of hermes_bap_seek(). I - * realised that my assumption that the driver's serialization + * realized that my assumption that the driver's serialization * would prevent the BAP being busy on entry was possibly false, because * things other than seeks may make the BAP busy. * o Use "alternate" (oui 00:00:00) encapsulation by default. @@ -181,12 +187,12 @@ * o Don't try to make __initdata const (the version string). This can't * work because of the way the __initdata sectioning works. * o Added MODULE_LICENSE tags. - * o Support for PLX (transparent PCMCIA->PCI brdge) cards. - * o Changed to using the new type-facist min/max. + * o Support for PLX (transparent PCMCIA->PCI bridge) cards. + * o Changed to using the new type-fascist min/max. * * v0.08 -> v0.08a - 9/10/2001 - David Gibson * o Inserted some missing acknowledgements/info into the Changelog. - * o Fixed some bugs in the normalisation of signel level reporting. + * o Fixed some bugs in the normalization of signal level reporting. * o Fixed bad bug in WEP key handling on Intersil and Symbol firmware, * which led to an instant crash on big-endian machines. * @@ -342,7 +348,7 @@ * o Bugfix in orinoco_stop() - it used to fail if hw_unavailable * was set, which was usually true on PCMCIA hot removes. * o Track LINKSTATUS messages, silently drop Tx packets before - * we are connected (avoids cofusing the firmware), and only + * we are connected (avoids confusing the firmware), and only * give LINKSTATUS printk()s if the status has changed. * * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson @@ -397,7 +403,8 @@ * o Disconnect wireless extensions from fundamental configuration. * o (maybe) Software WEP support (patch from Stano Meduna). * o (maybe) Use multiple Tx buffers - driver handling queue - * rather than firmware. */ + * rather than firmware. + */ /* Locking and synchronization: * @@ -414,7 +421,10 @@ * flag after taking the lock, and if it is set, give up on whatever * they are doing and drop the lock again. The orinoco_lock() * function handles this (it unlocks and returns -EBUSY if - * hw_unavailable is non-zero). */ + * hw_unavailable is non-zero). + */ + +#define DRIVER_NAME "orinoco" #include @@ -444,11 +454,9 @@ /* Module information */ /********************************************************************/ -MODULE_AUTHOR("David Gibson "); +MODULE_AUTHOR("Pavel Roskin & David Gibson "); MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif /* Level of debugging. Used in the macros in orinoco.h */ #ifdef ORINOCO_DEBUG @@ -464,11 +472,6 @@ /* Compile time configuration and compatibility stuff */ /********************************************************************/ -/* Wireless extensions backwards compatibility */ -#ifndef SIOCIWFIRSTPRIV -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ - /* We do this this way to avoid ifdefs in the actual code */ #ifdef WIRELESS_SPY #define SPY_NUMBER(priv) (priv->spy_number) @@ -497,25 +500,29 @@ #define DUMMY_FID 0xFFFF -#define RUP_EVEN(a) (((a) + 1) & (~1)) - /*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ HERMES_MAX_MULTICAST : 0)*/ #define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) +#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ + | HERMES_EV_TX | HERMES_EV_TXEXC \ + | HERMES_EV_WTERR | HERMES_EV_INFO \ + | HERMES_EV_INFDROP ) + /********************************************************************/ /* Data tables */ /********************************************************************/ /* The frequency of each channel in MHz */ -const long channel_frequency[] = { +static const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; -#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) +#define NUM_CHANNELS ARRAY_SIZE(channel_frequency) -/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */ -struct { +/* This tables gives the actual meanings of the bitrate IDs returned + * by the firmware. */ +static struct { int bitrate; /* in 100s of kilobits */ int automatic; u16 agere_txratectrl; @@ -530,7 +537,7 @@ {55, 1, 7, 7}, {110, 0, 5, 8}, }; -#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) +#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) /********************************************************************/ /* Data types */ @@ -555,46 +562,758 @@ #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) +struct hermes_rx_descriptor { + u16 status; + u32 time; + u8 silence; + u8 signal; + u8 rate; + u8 rxflow; + u32 reserved; +} __attribute__ ((packed)); + /********************************************************************/ /* Function prototypes */ /********************************************************************/ +static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int __orinoco_program_rids(struct net_device *dev); +static void __orinoco_set_multicast_list(struct net_device *dev); +static int orinoco_debug_dump_recs(struct net_device *dev); + +/********************************************************************/ +/* Internal helper functions */ +/********************************************************************/ + +static inline void set_port_type(struct orinoco_private *priv) +{ + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->createibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->createibss = 0; + } else { + priv->port_type = priv->ibss_port; + priv->createibss = 1; + } + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev->name); + } +} + +/********************************************************************/ +/* Device methods */ +/********************************************************************/ + +static int orinoco_open(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_lock(priv, &flags); + if (err) + return err; + + err = __orinoco_up(dev); + + if (! err) + priv->open = 1; + + orinoco_unlock(priv, &flags); + + return err; +} + +int orinoco_stop(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = 0; + + /* We mustn't use orinoco_lock() here, because we need to be + able to close the interface even if hw_unavailable is set + (e.g. as we're released after a PC Card removal) */ + spin_lock_irq(&priv->lock); + + priv->open = 0; + + err = __orinoco_down(dev); + + spin_unlock_irq(&priv->lock); + + return err; +} + +static struct net_device_stats *orinoco_get_stats(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + + return &priv->stats; +} + +static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + unsigned long flags; + + if (! netif_device_present(dev)) { + printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", + dev->name); + return NULL; /* FIXME: Can we do better than this? */ + } + + err = orinoco_lock(priv, &flags); + if (err) + return NULL; /* FIXME: Erg, we've been signalled, how + * do we propagate this back up? */ + + if (priv->iw_mode == IW_MODE_ADHOC) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (SPY_NUMBER(priv)) { + wstats->qual.qual = priv->spy_stat[0].qual; + wstats->qual.level = priv->spy_stat[0].level; + wstats->qual.noise = priv->spy_stat[0].noise; + wstats->qual.updated = priv->spy_stat[0].updated; + } + } else { + struct { + u16 qual, signal, noise; + } __attribute__ ((packed)) cq; + + err = HERMES_READ_RECORD(hw, USER_BAP, + HERMES_RID_COMMSQUALITY, &cq); + + wstats->qual.qual = (int)le16_to_cpu(cq.qual); + wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; + wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; + wstats->qual.updated = 7; + } + + /* We can't really wait for the tallies inquiry command to + * complete, so we just use the previous results and trigger + * a new tallies inquiry command for next time - Jean II */ + /* FIXME: We're in user context (I think?), so we should just + wait for the tallies to come through */ + err = hermes_inquire(hw, HERMES_INQ_TALLIES); + + orinoco_unlock(priv, &flags); + + if (err) + return NULL; + + return wstats; +} + +static void orinoco_set_multicast_list(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) { + printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " + "called when hw_unavailable\n", dev->name); + return; + } + + __orinoco_set_multicast_list(dev); + orinoco_unlock(priv, &flags); +} + +static int orinoco_change_mtu(struct net_device *dev, int new_mtu) +{ + struct orinoco_private *priv = netdev_priv(dev); + + if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) + return -EINVAL; + + if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > + (priv->nicbuf_size - ETH_HLEN) ) + return -EINVAL; + + dev->mtu = new_mtu; + + return 0; +} + +/********************************************************************/ +/* Tx path */ +/********************************************************************/ + +static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + int err = 0; + u16 txfid = priv->txfid; + char *p; + struct ethhdr *eh; + int len, data_len, data_off; + struct hermes_tx_descriptor desc; + unsigned long flags; + + TRACE_ENTER(dev->name); + + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", + dev->name); + TRACE_EXIT(dev->name); + return 1; + } + + if (netif_queue_stopped(dev)) { + printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", + dev->name); + TRACE_EXIT(dev->name); + return 1; + } + + if (orinoco_lock(priv, &flags) != 0) { + printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", + dev->name); + TRACE_EXIT(dev->name); + return 1; + } + + if (! priv->connected) { + /* Oops, the firmware hasn't established a connection, + silently drop the packet (this seems to be the + safest approach). */ + stats->tx_errors++; + orinoco_unlock(priv, &flags); + dev_kfree_skb(skb); + TRACE_EXIT(dev->name); + return 0; + } + + /* Length of the packet body */ + /* FIXME: what if the skb is smaller than this? */ + len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); + + eh = (struct ethhdr *)skb->data; + + memset(&desc, 0, sizeof(desc)); + desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); + if (err) { + printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + /* Clear the 802.11 header and data length fields - some + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused + * if this isn't done. */ + hermes_clear_words(hw, HERMES_DATA0, + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ + struct header_struct hdr; + data_len = len; + data_off = HERMES_802_3_OFFSET + sizeof(hdr); + p = skb->data + ETH_HLEN; + + /* 802.3 header */ + memcpy(hdr.dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.src, eh->h_source, ETH_ALEN); + hdr.len = htons(data_len + ENCAPS_OVERHEAD); + + /* 802.2 header */ + memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); + + hdr.ethertype = eh->h_proto; + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), + txfid, HERMES_802_3_OFFSET); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } else { /* IEEE 802.3 frame */ + data_len = len + ETH_HLEN; + data_off = HERMES_802_3_OFFSET; + p = skb->data; + } + + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), + txfid, data_off); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + /* Finally, we actually initiate the send */ + netif_stop_queue(dev); + + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, + txfid, NULL); + if (err) { + netif_start_queue(dev); + printk(KERN_ERR "%s: Error %d transmitting packet\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + dev->trans_start = jiffies; + stats->tx_bytes += data_off + data_len; + + orinoco_unlock(priv, &flags); + + dev_kfree_skb(skb); + + TRACE_EXIT(dev->name); + + return 0; + fail: + TRACE_EXIT(dev->name); + + orinoco_unlock(priv, &flags); + return err; +} + +static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + u16 fid = hermes_read_regn(hw, ALLOCFID); + + if (fid != priv->txfid) { + if (fid != DUMMY_FID) + printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", + dev->name, fid); + return; + } else { + netif_wake_queue(dev); + } + + hermes_write_regn(hw, ALLOCFID, DUMMY_FID); +} + +static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + + stats->tx_packets++; + + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); +} + +static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + u16 fid = hermes_read_regn(hw, TXCOMPLFID); + struct hermes_tx_descriptor desc; + int err = 0; + + if (fid == DUMMY_FID) + return; /* Nothing's really happened */ + + err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " + "(FID=%04X error %d)\n", + dev->name, fid, err); + } else { + DEBUG(1, "%s: Tx error, status %d\n", + dev->name, le16_to_cpu(desc.status)); + } + + stats->tx_errors++; + + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); +} + +static void orinoco_tx_timeout(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + struct hermes *hw = &priv->hw; + + printk(KERN_WARNING "%s: Tx timeout! " + "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", + dev->name, hermes_read_regn(hw, ALLOCFID), + hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); + + stats->tx_errors++; + + schedule_work(&priv->reset_work); +} + +/********************************************************************/ +/* Rx path (data frames) */ +/********************************************************************/ + +/* Does the frame have a SNAP header indicating it should be + * de-encapsulated to Ethernet-II? */ +static inline int is_ethersnap(struct header_struct *hdr) +{ + /* We de-encapsulate all packets which, a) have SNAP headers + * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header + * and where b) the OUI of the SNAP header is 00:00:00 or + * 00:00:f8 - we need both because different APs appear to use + * different OUIs for some reason */ + return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) + && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); +} + +static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, + int level, int noise) +{ + struct orinoco_private *priv = netdev_priv(dev); + int i; + + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + for (i = 0; i < priv->spy_number; i++) + if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { + priv->spy_stat[i].level = level - 0x95; + priv->spy_stat[i].noise = noise - 0x95; + priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; + priv->spy_stat[i].updated = 7; + } +} + static void orinoco_stat_gather(struct net_device *dev, struct sk_buff *skb, - struct hermes_rx_descriptor *desc); + struct hermes_rx_descriptor *desc) +{ + struct orinoco_private *priv = netdev_priv(dev); -static struct net_device_stats *orinoco_get_stats(struct net_device *dev); -static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev); + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if (SPY_NUMBER(priv)) { + orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, + desc->signal, desc->silence); + } +} -/* Hardware control routines */ +static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + struct iw_statistics *wstats = &priv->wstats; + struct sk_buff *skb = NULL; + u16 rxfid, status; + int length, data_len, data_off; + char *p; + struct hermes_rx_descriptor desc; + struct header_struct hdr; + struct ethhdr *eh; + int err; -static int __orinoco_program_rids(struct net_device *dev); + rxfid = hermes_read_regn(hw, RXFID); -static int __orinoco_hw_set_bitrate(struct orinoco_private *priv); -static int __orinoco_hw_setup_wep(struct orinoco_private *priv); -static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]); -static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]); -static long orinoco_hw_get_freq(struct orinoco_private *priv); -static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, - s32 *rates, int max); -static void __orinoco_set_multicast_list(struct net_device *dev); + err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), + rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading Rx descriptor. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } -/* Interrupt handling routines */ -static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw); + status = le16_to_cpu(desc.status); -/* ioctl() routines */ -static int orinoco_debug_dump_recs(struct net_device *dev); + if (status & HERMES_RXSTAT_ERR) { + if (status & HERMES_RXSTAT_UNDECRYPTABLE) { + wstats->discard.code++; + DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + } else { + stats->rx_crc_errors++; + DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); + } + stats->rx_errors++; + goto drop; + } + + /* For now we ignore the 802.11 header completely, assuming + that the card's firmware has handled anything vital */ + + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), + rxfid, HERMES_802_3_OFFSET); + if (err) { + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } + + length = ntohs(hdr.len); + + /* Sanity checks */ + if (length < 3) { /* No for even an 802.2 LLC header */ + /* At least on Symbol firmware with PCF we get quite a + lot of these legitimately - Poll frames with no + data. */ + stats->rx_dropped++; + goto drop; + } + if (length > IEEE802_11_DATA_LEN) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + stats->rx_errors++; + goto drop; + } + + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + goto drop; + } + + skb_reserve(skb, 2); /* This way the IP header is aligned */ + + /* Handle decapsulation + * In most cases, the firmware tell us about SNAP frames. + * For some reason, the SNAP frames sent by LinkSys APs + * are not properly recognised by most firmwares. + * So, check ourselves */ + if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || + ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || + is_ethersnap(&hdr)) { + /* These indicate a SNAP within 802.2 LLC within + 802.11 frame which we'll need to de-encapsulate to + the original EthernetII frame. */ + + if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ + stats->rx_length_errors++; + goto drop; + } + + /* Remove SNAP header, reconstruct EthernetII frame */ + data_len = length - ENCAPS_OVERHEAD; + data_off = HERMES_802_3_OFFSET + sizeof(hdr); + + eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); + + memcpy(eh, &hdr, 2 * ETH_ALEN); + eh->h_proto = hdr.ethertype; + } else { + /* All other cases indicate a genuine 802.3 frame. No + decapsulation needed. We just throw the whole + thing in, and hope the protocol layer can deal with + it as 802.3 */ + data_len = length; + data_off = HERMES_802_3_OFFSET; + /* FIXME: we re-read from the card data we already read here */ + } + + p = skb_put(skb, data_len); + err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2), + rxfid, data_off); + if (err) { + printk(KERN_ERR "%s: error %d reading frame. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } + + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* Process the wireless stats if needed */ + orinoco_stat_gather(dev, skb, &desc); + + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; + + drop: + stats->rx_dropped++; + + if (skb) + dev_kfree_skb_irq(skb); + return; +} /********************************************************************/ -/* Function prototypes */ +/* Rx path (info frames) */ +/********************************************************************/ + +static void print_linkstatus(struct net_device *dev, u16 status) +{ + char * s; + + if (suppress_linkstatus) + return; + + switch (status) { + case HERMES_LINKSTATUS_NOT_CONNECTED: + s = "Not Connected"; + break; + case HERMES_LINKSTATUS_CONNECTED: + s = "Connected"; + break; + case HERMES_LINKSTATUS_DISCONNECTED: + s = "Disconnected"; + break; + case HERMES_LINKSTATUS_AP_CHANGE: + s = "AP Changed"; + break; + case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: + s = "AP Out of Range"; + break; + case HERMES_LINKSTATUS_AP_IN_RANGE: + s = "AP In Range"; + break; + case HERMES_LINKSTATUS_ASSOC_FAILED: + s = "Association Failed"; + break; + default: + s = "UNKNOWN"; + } + + printk(KERN_INFO "%s: New link status: %s (%04x)\n", + dev->name, s, status); +} + +static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + u16 infofid; + struct { + u16 len; + u16 type; + } __attribute__ ((packed)) info; + int len, type; + int err; + + /* This is an answer to an INQUIRE command that we did earlier, + * or an information "event" generated by the card + * The controller return to us a pseudo frame containing + * the information in question - Jean II */ + infofid = hermes_read_regn(hw, INFOFID); + + /* Read the info frame header - don't try too hard */ + err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), + infofid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading info frame. " + "Frame dropped.\n", dev->name, err); + return; + } + + len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); + type = le16_to_cpu(info.type); + + switch (type) { + case HERMES_INQ_TALLIES: { + struct hermes_tallies_frame tallies; + struct iw_statistics *wstats = &priv->wstats; + + if (len > sizeof(tallies)) { + printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", + dev->name, len); + len = sizeof(tallies); + } + + /* Read directly the data (no seek) */ + hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, + len / 2); /* FIXME: blech! */ + + /* Increment our various counters */ + /* wstats->discard.nwid - no wrong BSSID stuff */ + wstats->discard.code += + le16_to_cpu(tallies.RxWEPUndecryptable); + if (len == sizeof(tallies)) + wstats->discard.code += + le16_to_cpu(tallies.RxDiscards_WEPICVError) + + le16_to_cpu(tallies.RxDiscards_WEPExcluded); + wstats->discard.misc += + le16_to_cpu(tallies.TxDiscardsWrongSA); + wstats->discard.fragment += + le16_to_cpu(tallies.RxMsgInBadMsgFragments); + wstats->discard.retries += + le16_to_cpu(tallies.TxRetryLimitExceeded); + /* wstats->miss.beacon - no match */ + } + break; + case HERMES_INQ_LINKSTATUS: { + struct hermes_linkstatus linkstatus; + u16 newstatus; + + if (len != sizeof(linkstatus)) { + printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", + dev->name, len); + break; + } + + hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus, + len / 2); + newstatus = le16_to_cpu(linkstatus.linkstatus); + + if ( (newstatus == HERMES_LINKSTATUS_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) + || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) ) + priv->connected = 1; + else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_DISCONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) + || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) ) + priv->connected = 0; + + if (newstatus != priv->last_linkstatus) + print_linkstatus(dev, newstatus); + + priv->last_linkstatus = newstatus; + } + break; + default: + printk(KERN_DEBUG "%s: Unknown information frame received " + "(type %04x).\n", dev->name, type); + /* We don't actually do anything about it */ + break; + } +} + +static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) +{ + if (net_ratelimit()) + printk(KERN_WARNING "%s: Information frame lost.\n", dev->name); +} + +/********************************************************************/ +/* Internal hardware control routines */ /********************************************************************/ int __orinoco_up(struct net_device *dev) @@ -683,43 +1402,139 @@ return err; } -static int orinoco_open(struct net_device *dev) +static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - err = orinoco_lock(priv, &flags); - if (err) - return err; - - err = __orinoco_up(dev); + hermes_t *hw = &priv->hw; + int err = 0; - if (! err) - priv->open = 1; + if (priv->bitratemode >= BITRATE_TABLE_SIZE) { + printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", + priv->ndev->name, priv->bitratemode); + return -EINVAL; + } - orinoco_unlock(priv, &flags); + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].agere_txratectrl); + break; + case FIRMWARE_TYPE_INTERSIL: + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].intersil_txratectrl); + break; + default: + BUG(); + } return err; } -int orinoco_stop(struct net_device *dev) +static int __orinoco_hw_setup_wep(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; int err = 0; + int master_wep_flag; + int auth_flag; - /* We mustn't use orinoco_lock() here, because we need to be - able to close the interface even if hw_unavailable is set - (e.g. as we're released after a PC Card removal) */ - spin_lock_irq(&priv->lock); + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ + if (priv->wep_on) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXKEY_AGERE, + priv->tx_key); + if (err) + return err; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFWEPKEYS_AGERE, + &priv->keys); + if (err) + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPENABLED_AGERE, + priv->wep_on); + if (err) + return err; + break; - priv->open = 0; + case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + master_wep_flag = 0; /* Off */ + if (priv->wep_on) { + int keylen; + int i; - err = __orinoco_down(dev); + /* Fudge around firmware weirdness */ + keylen = le16_to_cpu(priv->keys[priv->tx_key].len); + + /* Write all 4 keys */ + for(i = 0; i < ORINOCO_MAX_KEYS; i++) { +/* int keylen = le16_to_cpu(priv->keys[i].len); */ + + if (keylen > LARGE_KEY_SIZE) { + printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", + priv->ndev->name, i, keylen); + return -E2BIG; + } - spin_unlock_irq(&priv->lock); + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFDEFAULTKEY0 + i, + HERMES_BYTES_TO_RECLEN(keylen), + priv->keys[i].data); + if (err) + return err; + } - return err; + /* Write the index of the key used in transmission */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPDEFAULTKEYID, + priv->tx_key); + if (err) + return err; + + if (priv->wep_restrict) { + auth_flag = 2; + master_wep_flag = 3; + } else { + /* Authentication is where Intersil and Symbol + * firmware differ... */ + auth_flag = 1; + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) + master_wep_flag = 3; /* Symbol */ + else + master_wep_flag = 1; /* Intersil */ + } + + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFAUTHENTICATION, + auth_flag); + if (err) + return err; + } + + /* Master WEP setting : on/off */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPFLAGS_INTERSIL, + master_wep_flag); + if (err) + return err; + + break; + + default: + if (priv->wep_on) { + printk(KERN_ERR "%s: WEP enabled, although not supported!\n", + priv->ndev->name); + return -EINVAL; + } + } + + return 0; } static int __orinoco_program_rids(struct net_device *dev) @@ -733,14 +1548,17 @@ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting MAC address\n", + dev->name, err); return err; } /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, + priv->port_type); if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting port type\n", + dev->name, err); return err; } /* Set the channel/frequency */ @@ -749,14 +1567,17 @@ if (priv->createibss) priv->channel = 10; } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, + priv->channel); if (err) { - printk(KERN_ERR "%s: Error %d setting channel\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting channel\n", + dev->name, err); return err; } if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFCREATEIBSS, priv->createibss); if (err) { printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err); @@ -765,8 +1586,8 @@ if ((strlen(priv->desired_essid) == 0) && (priv->createibss) && (!priv->has_ibss_any)) { - printk(KERN_WARNING "%s: This firmware requires an \ -ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + printk(KERN_WARNING "%s: This firmware requires an " + "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); /* With wvlan_cs, in this case, we would crash. * hopefully, this driver will behave better... * Jean II */ @@ -781,14 +1602,16 @@ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), &idbuf); if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting OWNSSID\n", + dev->name, err); return err; } err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), &idbuf); if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", + dev->name, err); return err; } @@ -799,26 +1622,31 @@ HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), &idbuf); if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting nickname\n", + dev->name, err); return err; } /* Set AP density */ if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, priv->ap_density); if (err) { printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", dev->name, err); + "Disabling sensitivity control\n", + dev->name, err); priv->has_sensitivity = 0; } } /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + priv->rts_thresh); if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting RTS threshold\n", + dev->name, err); return err; } @@ -832,20 +1660,23 @@ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, priv->frag_thresh); if (err) { - printk(KERN_ERR "%s: Error %d setting framentation\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting fragmentation\n", + dev->name, err); return err; } /* Set bitrate */ err = __orinoco_hw_set_bitrate(priv); if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", dev->name, err); + printk(KERN_ERR "%s: Error %d setting bitrate\n", + dev->name, err); return err; } /* Set power management */ if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMENABLED, priv->pm_on); if (err) { printk(KERN_ERR "%s: Error %d setting up PM\n", @@ -909,7 +1740,73 @@ return 0; } -/* xyzzy */ +/* FIXME: return int? */ +static void +__orinoco_set_multicast_list(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, mc_count; + + /* The Hermes doesn't seem to have an allmulti mode, so we go + * into promiscuous mode and let the upper levels deal. */ + if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > MAX_MULTICAST(priv)) ) { + promisc = 1; + mc_count = 0; + } else { + promisc = 0; + mc_count = dev->mc_count; + } + + if (promisc != priv->promiscuous) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPROMISCUOUSMODE, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", + dev->name, err); + } else + priv->promiscuous = promisc; + } + + if (! promisc && (mc_count || priv->mc_count) ) { + struct dev_mc_list *p = dev->mc_list; + struct hermes_multicast mclist; + int i; + + for (i = 0; i < mc_count; i++) { + /* paranoia: is list shorter than mc_count? */ + BUG_ON(! p); + /* paranoia: bad address size in list? */ + BUG_ON(p->dmi_addrlen != ETH_ALEN); + + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); + p = p->next; + } + + if (p) + printk(KERN_WARNING "Multicast list is longer than mc_count\n"); + + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, + HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), + &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->mc_count = mc_count; + } + + /* Since we can set the promiscuous flag when it wasn't asked + for, make sure the net_device knows about it. */ + if (priv->promiscuous) + dev->flags |= IFF_PROMISC; + else + dev->flags &= ~IFF_PROMISC; +} + static int orinoco_reconfigure(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); @@ -974,7 +1871,7 @@ if (err) /* When the hardware becomes available again, whatever * detects that is responsible for re-initializing - * it. So no need for anything further*/ + * it. So no need for anything further */ return; netif_stop_queue(dev); @@ -993,8 +1890,8 @@ if (priv->hard_reset) err = (*priv->hard_reset)(priv); if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d performing hard reset\n", - dev->name, err); + printk(KERN_ERR "%s: orinoco_reset: Error %d " + "performing hard reset\n", dev->name, err); /* FIXME: shutdown of some sort */ return; } @@ -1027,409 +1924,22 @@ } /********************************************************************/ -/* Internal helper functions */ +/* Interrupt handler */ /********************************************************************/ -static inline void -set_port_type(struct orinoco_private *priv) -{ - switch (priv->iw_mode) { - case IW_MODE_INFRA: - priv->port_type = 1; - priv->createibss = 0; - break; - case IW_MODE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->createibss = 0; - } else { - priv->port_type = priv->ibss_port; - priv->createibss = 1; - } - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev->name); - } -} - -/* Does the frame have a SNAP header indicating it should be - * de-encapsulated to Ethernet-II? */ -static inline int -is_ethersnap(struct header_struct *hdr) -{ - /* We de-encapsulate all packets which, a) have SNAP headers - * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header - * and where b) the OUI of the SNAP header is 00:00:00 or - * 00:00:f8 - we need both because different APs appear to use - * different OUIs for some reason */ - return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) - && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); -} - -static void -orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " - "called when hw_unavailable\n", dev->name); - return; - } - - __orinoco_set_multicast_list(dev); - orinoco_unlock(priv, &flags); -} - -/********************************************************************/ -/* Hardware control functions */ -/********************************************************************/ - - -static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - - if (priv->bitratemode >= BITRATE_TABLE_SIZE) { - printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", - priv->ndev->name, priv->bitratemode); - return -EINVAL; - } - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[priv->bitratemode].agere_txratectrl); - break; - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[priv->bitratemode].intersil_txratectrl); - break; - default: - BUG(); - } - - return err; -} - - -static int __orinoco_hw_setup_wep(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - int master_wep_flag; - int auth_flag; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXKEY_AGERE, - priv->tx_key); - if (err) - return err; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFWEPKEYS_AGERE, - &priv->keys); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPENABLED_AGERE, - priv->wep_on); - if (err) - return err; - break; - - case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - master_wep_flag = 0; /* Off */ - if (priv->wep_on) { - int keylen; - int i; - - /* Fudge around firmware weirdness */ - keylen = le16_to_cpu(priv->keys[priv->tx_key].len); - - /* Write all 4 keys */ - for(i = 0; i < ORINOCO_MAX_KEYS; i++) { -/* int keylen = le16_to_cpu(priv->keys[i].len); */ - - if (keylen > LARGE_KEY_SIZE) { - printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", - priv->ndev->name, i, keylen); - return -E2BIG; - } - - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNFDEFAULTKEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen), - priv->keys[i].data); - if (err) - return err; - } - - /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID, - priv->tx_key); - if (err) - return err; - - if (priv->wep_restrict) { - auth_flag = 2; - master_wep_flag = 3; - } else { - /* Authentication is where Intersil and Symbol - * firmware differ... */ - auth_flag = 1; - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) - master_wep_flag = 3; /* Symbol */ - else - master_wep_flag = 1; /* Intersil */ - } - - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION, auth_flag); - if (err) - return err; - } - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPFLAGS_INTERSIL, - master_wep_flag); - if (err) - return err; - - break; - - default: - if (priv->wep_on) { - printk(KERN_ERR "%s: WEP enabled, although not supported!\n", - priv->ndev->name); - return -EINVAL; - } - } - - return 0; -} - -static int orinoco_hw_get_bssid(struct orinoco_private *priv, - char buf[ETH_ALEN]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - unsigned long flags; - - err = orinoco_lock(priv, &flags); - if (err) - return err; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, buf); - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - struct hermes_idstring essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - unsigned long flags; - - err = orinoco_lock(priv, &flags); - if (err) - return err; - - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWNSSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - u16 rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : - HERMES_RID_CNFDESIREDSSID; - - err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - - memset(buf, 0, IW_ESSID_MAX_SIZE+1); - memcpy(buf, p, len); - buf[len] = '\0'; - - fail_unlock: - orinoco_unlock(priv, &flags); - - return err; -} - -static long orinoco_hw_get_freq(struct orinoco_private *priv) -{ - - hermes_t *hw = &priv->hw; - int err = 0; - u16 channel; - long freq = 0; - unsigned long flags; - - err = orinoco_lock(priv, &flags); - if (err) - return err; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); - if (err) - goto out; - - /* Intersil firmware 1.3.5 returns 0 when the interface is down */ - if (channel == 0) { - err = -EBUSY; - goto out; - } - - if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", - priv->ndev->name, channel); - err = -EBUSY; - goto out; - - } - freq = channel_frequency[channel-1] * 100000; - - out: - orinoco_unlock(priv, &flags); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max) +static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) { - hermes_t *hw = &priv->hw; - struct hermes_idstring list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - unsigned long flags; - - err = orinoco_lock(priv, &flags); - if (err) - return err; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, - sizeof(list), NULL, &list); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = min(num, max); - - for (i = 0; i < num; i++) { - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - } - - return 0; + printk(KERN_DEBUG "%s: TICK\n", dev->name); } -#if 0 -static void show_rx_frame(struct orinoco_rxframe_hdr *frame) +static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) { - printk(KERN_DEBUG "RX descriptor:\n"); - printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); - printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); - printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); - printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); - printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); - printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); - printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); - - printk(KERN_DEBUG "IEEE 802.11 header:\n"); - printk(KERN_DEBUG " frame_ctl = 0x%04x\n", - frame->p80211.frame_ctl); - printk(KERN_DEBUG " duration_id = 0x%04x\n", - frame->p80211.duration_id); - printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr1[0], frame->p80211.addr1[1], - frame->p80211.addr1[2], frame->p80211.addr1[3], - frame->p80211.addr1[4], frame->p80211.addr1[5]); - printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr2[0], frame->p80211.addr2[1], - frame->p80211.addr2[2], frame->p80211.addr2[3], - frame->p80211.addr2[4], frame->p80211.addr2[5]); - printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr3[0], frame->p80211.addr3[1], - frame->p80211.addr3[2], frame->p80211.addr3[3], - frame->p80211.addr3[4], frame->p80211.addr3[5]); - printk(KERN_DEBUG " seq_ctl = 0x%04x\n", - frame->p80211.seq_ctl); - printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr4[0], frame->p80211.addr4[1], - frame->p80211.addr4[2], frame->p80211.addr4[3], - frame->p80211.addr4[4], frame->p80211.addr4[5]); - printk(KERN_DEBUG " data_len = 0x%04x\n", - frame->p80211.data_len); - - printk(KERN_DEBUG "IEEE 802.3 header:\n"); - printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_dest[0], frame->p8023.h_dest[1], - frame->p8023.h_dest[2], frame->p8023.h_dest[3], - frame->p8023.h_dest[4], frame->p8023.h_dest[5]); - printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_source[0], frame->p8023.h_source[1], - frame->p8023.h_source[2], frame->p8023.h_source[3], - frame->p8023.h_source[4], frame->p8023.h_source[5]); - printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); - - printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); - printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); - printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); - printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); - printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", - frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); - printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", + dev->name); } -#endif /* 0 */ -/* - * Interrupt handler - */ irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; @@ -1440,7 +1950,8 @@ /* These are used to detect a runaway interrupt situation */ /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, * we panic and shut down the hardware */ - static int last_irq_jiffy = 0; /* jiffies value the last time we were called */ + static int last_irq_jiffy = 0; /* jiffies value the last time + * we were called */ static int loops_this_jiffy = 0; unsigned long flags; @@ -1504,368 +2015,9 @@ return IRQ_HANDLED; } -static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", dev->name); -} - -static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - dev->name); -} - -static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) -{ - if (net_ratelimit()) - printk(KERN_WARNING "%s: Information frame lost.\n", dev->name); -} - -static void print_linkstatus(struct net_device *dev, u16 status) -{ - char * s; - - if (suppress_linkstatus) - return; - - switch (status) { - case HERMES_LINKSTATUS_NOT_CONNECTED: - s = "Not Connected"; - break; - case HERMES_LINKSTATUS_CONNECTED: - s = "Connected"; - break; - case HERMES_LINKSTATUS_DISCONNECTED: - s = "Disconnected"; - break; - case HERMES_LINKSTATUS_AP_CHANGE: - s = "AP Changed"; - break; - case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: - s = "AP Out of Range"; - break; - case HERMES_LINKSTATUS_AP_IN_RANGE: - s = "AP In Range"; - break; - case HERMES_LINKSTATUS_ASSOC_FAILED: - s = "Association Failed"; - break; - default: - s = "UNKNOWN"; - } - - printk(KERN_INFO "%s: New link status: %s (%04x)\n", - dev->name, s, status); -} - -static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - u16 infofid; - struct { - u16 len; - u16 type; - } __attribute__ ((packed)) info; - int len, type; - int err; - - /* This is an answer to an INQUIRE command that we did earlier, - * or an information "event" generated by the card - * The controller return to us a pseudo frame containing - * the information in question - Jean II */ - infofid = hermes_read_regn(hw, INFOFID); - - /* Read the info frame header - don't try too hard */ - err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), - infofid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading info frame. " - "Frame dropped.\n", dev->name, err); - return; - } - - len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); - type = le16_to_cpu(info.type); - - switch (type) { - case HERMES_INQ_TALLIES: { - struct hermes_tallies_frame tallies; - struct iw_statistics *wstats = &priv->wstats; - - if (len > sizeof(tallies)) { - printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", - dev->name, len); - len = sizeof(tallies); - } - - /* Read directly the data (no seek) */ - hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, - len / 2); /* FIXME: blech! */ - - /* Increment our various counters */ - /* wstats->discard.nwid - no wrong BSSID stuff */ - wstats->discard.code += - le16_to_cpu(tallies.RxWEPUndecryptable); - if (len == sizeof(tallies)) - wstats->discard.code += - le16_to_cpu(tallies.RxDiscards_WEPICVError) + - le16_to_cpu(tallies.RxDiscards_WEPExcluded); - wstats->discard.misc += - le16_to_cpu(tallies.TxDiscardsWrongSA); -#if WIRELESS_EXT > 11 - wstats->discard.fragment += - le16_to_cpu(tallies.RxMsgInBadMsgFragments); - wstats->discard.retries += - le16_to_cpu(tallies.TxRetryLimitExceeded); - /* wstats->miss.beacon - no match */ -#endif /* WIRELESS_EXT > 11 */ - } - break; - case HERMES_INQ_LINKSTATUS: { - struct hermes_linkstatus linkstatus; - u16 newstatus; - - if (len != sizeof(linkstatus)) { - printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", - dev->name, len); - break; - } - - hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus, - len / 2); - newstatus = le16_to_cpu(linkstatus.linkstatus); - - if ( (newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) ) - priv->connected = 1; - else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_DISCONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) - || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) ) - priv->connected = 0; - - if (newstatus != priv->last_linkstatus) - print_linkstatus(dev, newstatus); - - priv->last_linkstatus = newstatus; - } - break; - default: - printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n", - dev->name, type); - /* We don't actually do anything about it */ - break; - } -} - -static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - u16 rxfid, status; - int length, data_len, data_off; - char *p; - struct hermes_rx_descriptor desc; - struct header_struct hdr; - struct ethhdr *eh; - int err; - - rxfid = hermes_read_regn(hw, RXFID); - - err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), - rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading Rx descriptor. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; - } - - status = le16_to_cpu(desc.status); - - if (status & HERMES_RXSTAT_ERR) { - if (status & HERMES_RXSTAT_UNDECRYPTABLE) { - wstats->discard.code++; - DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - } else { - stats->rx_crc_errors++; - DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); - } - stats->rx_errors++; - goto drop; - } - - /* For now we ignore the 802.11 header completely, assuming - that the card's firmware has handled anything vital */ - - err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), - rxfid, HERMES_802_3_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading frame header. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; - } - - length = ntohs(hdr.len); - - /* Sanity checks */ - if (length < 3) { /* No for even an 802.2 LLC header */ - /* At least on Symbol firmware with PCF we get quite a - lot of these legitimately - Poll frames with no - data. */ - stats->rx_dropped++; - goto drop; - } - if (length > IEEE802_11_DATA_LEN) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - stats->rx_errors++; - goto drop; - } - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length+ETH_HLEN+2+1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - goto drop; - } - - skb_reserve(skb, 2); /* This way the IP header is aligned */ - - /* Handle decapsulation - * In most cases, the firmware tell us about SNAP frames. - * For some reason, the SNAP frames sent by LinkSys APs - * are not properly recognised by most firmwares. - * So, check ourselves */ - if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || - ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_ethersnap(&hdr)) { - /* These indicate a SNAP within 802.2 LLC within - 802.11 frame which we'll need to de-encapsulate to - the original EthernetII frame. */ - - if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ - stats->rx_length_errors++; - goto drop; - } - - /* Remove SNAP header, reconstruct EthernetII frame */ - data_len = length - ENCAPS_OVERHEAD; - data_off = HERMES_802_3_OFFSET + sizeof(hdr); - - eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); - - memcpy(eh, &hdr, 2 * ETH_ALEN); - eh->h_proto = hdr.ethertype; - } else { - /* All other cases indicate a genuine 802.3 frame. No - decapsulation needed. We just throw the whole - thing in, and hope the protocol layer can deal with - it as 802.3 */ - data_len = length; - data_off = HERMES_802_3_OFFSET; - /* FIXME: we re-read from the card data we already read here */ - } - - p = skb_put(skb, data_len); - err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), - rxfid, data_off); - if (err) { - printk(KERN_ERR "%s: error %d reading frame. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; - } - - dev->last_rx = jiffies; - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - - /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, &desc); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - stats->rx_dropped++; - - if (skb) - dev_kfree_skb_irq(skb); - return; -} - -static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - u16 fid = hermes_read_regn(hw, TXCOMPLFID); - struct hermes_tx_descriptor desc; - int err = 0; - - if (fid == DUMMY_FID) - return; /* Nothing's really happened */ - - err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " - "(FID=%04X error %d)\n", - dev->name, fid, err); - } else { - DEBUG(1, "%s: Tx error, status %d\n", - dev->name, le16_to_cpu(desc.status)); - } - - stats->tx_errors++; - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); -} - -static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - - stats->tx_packets++; - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); -} - -static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - - u16 fid = hermes_read_regn(hw, ALLOCFID); - - if (fid != priv->txfid) { - if (fid != DUMMY_FID) - printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", - dev->name, fid); - return; - } else { - netif_wake_queue(dev); - } - - hermes_write_regn(hw, ALLOCFID, DUMMY_FID); -} +/********************************************************************/ +/* Initialization */ +/********************************************************************/ struct sta_id { u16 id, variant, major, minor; @@ -1901,11 +2053,11 @@ dev->name, err); memset(&sta_id, 0, sizeof(sta_id)); } + le16_to_cpus(&sta_id.id); le16_to_cpus(&sta_id.variant); le16_to_cpus(&sta_id.major); le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", dev->name, sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); @@ -2018,12 +2170,7 @@ } } -/* - * struct net_device methods - */ - -static int -orinoco_init(struct net_device *dev) +static int orinoco_init(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; @@ -2112,7 +2259,8 @@ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, &priv->rts_thresh); if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); + printk(KERN_ERR "%s: failed to read RTS threshold!\n", + dev->name); goto out; } @@ -2125,7 +2273,8 @@ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", + dev->name); goto out; } @@ -2153,7 +2302,8 @@ /* Preamble setup */ if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, &priv->preamble); if (err) goto out; @@ -2202,357 +2352,204 @@ return err; } -struct net_device_stats * -orinoco_get_stats(struct net_device *dev) +struct net_device *alloc_orinocodev(int sizeof_card, + int (*hard_reset)(struct orinoco_private *)) { - struct orinoco_private *priv = netdev_priv(dev); - - return &priv->stats; -} + struct net_device *dev; + struct orinoco_private *priv; -struct iw_statistics * -orinoco_get_wireless_stats(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err = 0; - unsigned long flags; + dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); + if (! dev) + return NULL; + priv = netdev_priv(dev); + priv->ndev = dev; + if (sizeof_card) + priv->card = (void *)((unsigned long)netdev_priv(dev) + + sizeof(struct orinoco_private)); + else + priv->card = NULL; - if (! netif_device_present(dev)) { - printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", - dev->name); - return NULL; /* FIXME: Can we do better than this? */ - } + /* Setup / override net_device fields */ + dev->init = orinoco_init; + dev->hard_start_xmit = orinoco_xmit; + dev->tx_timeout = orinoco_tx_timeout; + dev->watchdog_timeo = HZ; /* 1 second timeout */ + dev->get_stats = orinoco_get_stats; + dev->get_wireless_stats = orinoco_get_wireless_stats; + dev->do_ioctl = orinoco_ioctl; + dev->change_mtu = orinoco_change_mtu; + dev->set_multicast_list = orinoco_set_multicast_list; + /* we use the default eth_mac_addr for setting the MAC addr */ - err = orinoco_lock(priv, &flags); - if (err) - return NULL; /* FIXME: Erg, we've been signalled, how - * do we propagate this back up? */ + /* Set up default callbacks */ + dev->open = orinoco_open; + dev->stop = orinoco_stop; + priv->hard_reset = hard_reset; - if (priv->iw_mode == IW_MODE_ADHOC) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_stat[0].qual; - wstats->qual.level = priv->spy_stat[0].level; - wstats->qual.noise = priv->spy_stat[0].noise; - wstats->qual.updated = priv->spy_stat[0].updated; - } - } else { - struct { - u16 qual, signal, noise; - } __attribute__ ((packed)) cq; + spin_lock_init(&priv->lock); + priv->open = 0; + priv->hw_unavailable = 1; /* orinoco_init() must clear this + * before anything else touches the + * hardware */ + INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_COMMSQUALITY, &cq); - - wstats->qual.qual = (int)le16_to_cpu(cq.qual); - wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; - wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = 7; - } + priv->last_linkstatus = 0xffff; + priv->connected = 0; - /* We can't really wait for the tallies inquiry command to - * complete, so we just use the previous results and trigger - * a new tallies inquiry command for next time - Jean II */ - /* FIXME: We're in user context (I think?), so we should just - wait for the tallies to come through */ - err = hermes_inquire(hw, HERMES_INQ_TALLIES); - - orinoco_unlock(priv, &flags); + return dev; - if (err) - return NULL; - - return wstats; } -static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, - int level, int noise) -{ - struct orinoco_private *priv = netdev_priv(dev); - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].level = level - 0x95; - priv->spy_stat[i].noise = noise - 0x95; - priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; - priv->spy_stat[i].updated = 7; - } -} - -void -orinoco_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct hermes_rx_descriptor *desc) -{ - struct orinoco_private *priv = netdev_priv(dev); - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if (SPY_NUMBER(priv)) { - orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, - desc->signal, desc->silence); - } -} +/********************************************************************/ +/* Wireless extensions */ +/********************************************************************/ -static int -orinoco_xmit(struct sk_buff *skb, struct net_device *dev) +static int orinoco_hw_get_bssid(struct orinoco_private *priv, + char buf[ETH_ALEN]) { - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; - u16 txfid = priv->txfid; - char *p; - struct ethhdr *eh; - int len, data_len, data_off; - struct hermes_tx_descriptor desc; unsigned long flags; - TRACE_ENTER(dev->name); + err = orinoco_lock(priv, &flags); + if (err) + return err; - if (! netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - TRACE_EXIT(dev->name); - return 1; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - TRACE_EXIT(dev->name); - return 1; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", - dev->name); - TRACE_EXIT(dev->name); -/* BUG(); */ - return 1; - } + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, + ETH_ALEN, NULL, buf); - if (! priv->connected) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - stats->tx_errors++; - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - TRACE_EXIT(dev->name); - return 0; - } + orinoco_unlock(priv, &flags); - /* Length of the packet body */ - /* FIXME: what if the skb is smaller than this? */ - len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); + return err; +} - eh = (struct ethhdr *)skb->data; +static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + struct hermes_idstring essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + unsigned long flags; - memset(&desc, 0, sizeof(desc)); - desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); - err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); - if (err) { - printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } + err = orinoco_lock(priv, &flags); + if (err) + return err; - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + if (strlen(priv->desired_essid) > 0) { + /* We read the desired SSID from the hardware rather + than from priv->desired_essid, just in case the + firmware is allowed to change it on us. I'm not + sure about this */ + /* My guess is that the OWNSSID should always be whatever + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + u16 rid; - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ - struct header_struct hdr; - data_len = len; - data_off = HERMES_802_3_OFFSET + sizeof(hdr); - p = skb->data + ETH_HLEN; + *active = 1; - /* 802.3 header */ - memcpy(hdr.dest, eh->h_dest, ETH_ALEN); - memcpy(hdr.src, eh->h_source, ETH_ALEN); - hdr.len = htons(data_len + ENCAPS_OVERHEAD); + rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : + HERMES_RID_CNFDESIREDSSID; - /* 802.2 header */ - memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); - - hdr.ethertype = eh->h_proto; - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), - txfid, HERMES_802_3_OFFSET); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } else { /* IEEE 802.3 frame */ - data_len = len + ETH_HLEN; - data_off = HERMES_802_3_OFFSET; - p = skb->data; - } + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; - /* Round up for odd length packets */ - err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; } - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, NULL); - if (err) { - netif_start_queue(dev); - printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); - stats->tx_errors++; - goto fail; - } + len = le16_to_cpu(essidbuf.len); - dev->trans_start = jiffies; - stats->tx_bytes += data_off + data_len; + memset(buf, 0, IW_ESSID_MAX_SIZE+1); + memcpy(buf, p, len); + buf[len] = '\0'; + fail_unlock: orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - - TRACE_EXIT(dev->name); - - return 0; - fail: - TRACE_EXIT(dev->name); - - orinoco_unlock(priv, &flags); - return err; + return err; } -static void -orinoco_tx_timeout(struct net_device *dev) +static long orinoco_hw_get_freq(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - struct hermes *hw = &priv->hw; - - printk(KERN_WARNING "%s: Tx timeout! " - "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", - dev->name, hermes_read_regn(hw, ALLOCFID), - hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); - - stats->tx_errors++; + + hermes_t *hw = &priv->hw; + int err = 0; + u16 channel; + long freq = 0; + unsigned long flags; - schedule_work(&priv->reset_work); -} + err = orinoco_lock(priv, &flags); + if (err) + return err; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); + if (err) + goto out; -static int -orinoco_change_mtu(struct net_device *dev, int new_mtu) -{ - struct orinoco_private *priv = netdev_priv(dev); + /* Intersil firmware 1.3.5 returns 0 when the interface is down */ + if (channel == 0) { + err = -EBUSY; + goto out; + } - if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) - return -EINVAL; + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", + priv->ndev->name, channel); + err = -EBUSY; + goto out; - if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > - (priv->nicbuf_size - ETH_HLEN) ) - return -EINVAL; + } + freq = channel_frequency[channel-1] * 100000; - dev->mtu = new_mtu; + out: + orinoco_unlock(priv, &flags); - return 0; + if (err > 0) + err = -EBUSY; + return err ? err : freq; } -/* FIXME: return int? */ -static void -__orinoco_set_multicast_list(struct net_device *dev) +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, + int *numrates, s32 *rates, int max) { - struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; + struct hermes_idstring list; + unsigned char *p = (unsigned char *)&list.val; int err = 0; - int promisc, mc_count; - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST(priv)) ) { - promisc = 1; - mc_count = 0; - } else { - promisc = 0; - mc_count = dev->mc_count; - } + int num; + int i; + unsigned long flags; - if (promisc != priv->promiscuous) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPROMISCUOUSMODE, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", - dev->name, err); - } else - priv->promiscuous = promisc; - } + err = orinoco_lock(priv, &flags); + if (err) + return err; - if (! promisc && (mc_count || priv->mc_count) ) { - struct dev_mc_list *p = dev->mc_list; - hermes_multicast_t mclist; - int i; + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, + sizeof(list), NULL, &list); + orinoco_unlock(priv, &flags); - for (i = 0; i < mc_count; i++) { - /* Paranoia: */ - if (! p) - BUG(); /* Multicast list shorter than mc_count */ - if (p->dmi_addrlen != ETH_ALEN) - BUG(); /* Bad address size in multicast list */ - - memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); - p = p->next; - } - - if (p) - printk(KERN_WARNING "Multicast list is longer than mc_count\n"); + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = min(num, max); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->mc_count = mc_count; + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ } - /* Since we can set the promiscuous flag when it wasn't asked - for, make sure the net_device knows about it. */ - if (priv->promiscuous) - dev->flags |= IFF_PROMISC; - else - dev->flags &= ~IFF_PROMISC; + return 0; } -/********************************************************************/ -/* Wireless extensions support */ -/********************************************************************/ - static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) { struct orinoco_private *priv = netdev_priv(dev); @@ -2582,10 +2579,8 @@ /* Much of this shamelessly taken from wvlan_cs.c. No idea * what it all means -dgibson */ -#if WIRELESS_EXT > 10 range.we_version_compiled = WIRELESS_EXT; range.we_version_source = 11; -#endif /* WIRELESS_EXT > 10 */ range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ @@ -2612,22 +2607,17 @@ range.max_qual.qual = 0; range.max_qual.level = 0; range.max_qual.noise = 0; -#if WIRELESS_EXT > 11 range.avg_qual.qual = 0; range.avg_qual.level = 0; range.avg_qual.noise = 0; -#endif /* WIRELESS_EXT > 11 */ - } else { range.max_qual.qual = 0x8b - 0x2f; range.max_qual.level = 0x2f - 0x95 - 1; range.max_qual.noise = 0x2f - 0x95 - 1; -#if WIRELESS_EXT > 11 /* Need to get better values */ range.avg_qual.qual = 0x24; range.avg_qual.level = 0xC2; range.avg_qual.noise = 0x9E; -#endif /* WIRELESS_EXT > 11 */ } err = orinoco_hw_get_bitratelist(priv, &numrates, @@ -2680,7 +2670,6 @@ range.txpower[0] = 15; /* 15dBm */ range.txpower_capa = IW_TXPOW_DBM; -#if WIRELESS_EXT > 10 range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; range.retry_flags = IW_RETRY_LIMIT; range.r_time_flags = IW_RETRY_LIFETIME; @@ -2688,7 +2677,6 @@ range.max_retry = 65535; /* ??? */ range.min_r_time = 0; range.max_r_time = 65535 * 1000; /* ??? */ -#endif /* WIRELESS_EXT > 10 */ if (copy_to_user(rrq->pointer, &range, sizeof(range))) return -EFAULT; @@ -2737,7 +2725,8 @@ if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; - + + /* Adjust key length to a supported value */ if (erq->length > SMALL_KEY_SIZE) { xlen = LARGE_KEY_SIZE; } else if (erq->length > 0) { @@ -2779,14 +2768,14 @@ if (erq->pointer) { priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); + memset(priv->keys[index].data, 0, + sizeof(priv->keys[index].data)); memcpy(priv->keys[index].data, keybuf, erq->length); } priv->tx_key = setindex; priv->wep_on = enable; priv->wep_restrict = restricted; - out: orinoco_unlock(priv, &flags); @@ -3012,7 +3001,8 @@ err = orinoco_lock(priv, &flags); if (err) return err; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &val); + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, &val); orinoco_unlock(priv, &flags); if (err) @@ -3201,8 +3191,7 @@ ratemode = priv->bitratemode; - if ( (ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE) ) - BUG(); + BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); rrq->value = bitrate_table[ratemode].bitrate * 100000; rrq->fixed = ! bitrate_table[ratemode].automatic; @@ -3354,7 +3343,6 @@ return err; } -#if WIRELESS_EXT > 10 static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) { struct orinoco_private *priv = netdev_priv(dev); @@ -3406,7 +3394,6 @@ return err; } -#endif /* WIRELESS_EXT > 10 */ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) { @@ -3500,7 +3487,6 @@ *val = priv->prefer_port3; orinoco_unlock(priv, &flags); - return 0; } @@ -3790,7 +3776,6 @@ wrq->u.txpower.flags = IW_TXPOW_DBM; break; -#if WIRELESS_EXT > 10 case SIOCSIWRETRY: err = -EOPNOTSUPP; break; @@ -3798,7 +3783,6 @@ case SIOCGIWRETRY: err = orinoco_ioctl_getretry(dev, &wrq->u.retry); break; -#endif /* WIRELESS_EXT > 10 */ case SIOCSIWSPY: err = orinoco_ioctl_setspy(dev, &wrq->u.data); @@ -4124,51 +4108,68 @@ return 0; } -struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *)) -{ - struct net_device *dev; - struct orinoco_private *priv; - - dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); - if (!dev) - return NULL; - priv = netdev_priv(dev); - priv->ndev = dev; - if (sizeof_card) - priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private)); - else - priv->card = NULL; - - /* Setup / override net_device fields */ - dev->init = orinoco_init; - dev->hard_start_xmit = orinoco_xmit; - dev->tx_timeout = orinoco_tx_timeout; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->get_stats = orinoco_get_stats; - dev->get_wireless_stats = orinoco_get_wireless_stats; - dev->do_ioctl = orinoco_ioctl; - dev->change_mtu = orinoco_change_mtu; - dev->set_multicast_list = orinoco_set_multicast_list; - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Set up default callbacks */ - dev->open = orinoco_open; - dev->stop = orinoco_stop; - priv->hard_reset = hard_reset; +/********************************************************************/ +/* Debugging */ +/********************************************************************/ - spin_lock_init(&priv->lock); - priv->open = 0; - priv->hw_unavailable = 1; /* orinoco_init() must clear this - * before anything else touches the - * hardware */ - INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); +#if 0 +static void show_rx_frame(struct orinoco_rxframe_hdr *frame) +{ + printk(KERN_DEBUG "RX descriptor:\n"); + printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); + printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); + printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); + printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); + printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); + printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); + printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); - priv->last_linkstatus = 0xffff; - priv->connected = 0; + printk(KERN_DEBUG "IEEE 802.11 header:\n"); + printk(KERN_DEBUG " frame_ctl = 0x%04x\n", + frame->p80211.frame_ctl); + printk(KERN_DEBUG " duration_id = 0x%04x\n", + frame->p80211.duration_id); + printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr1[0], frame->p80211.addr1[1], + frame->p80211.addr1[2], frame->p80211.addr1[3], + frame->p80211.addr1[4], frame->p80211.addr1[5]); + printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr2[0], frame->p80211.addr2[1], + frame->p80211.addr2[2], frame->p80211.addr2[3], + frame->p80211.addr2[4], frame->p80211.addr2[5]); + printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr3[0], frame->p80211.addr3[1], + frame->p80211.addr3[2], frame->p80211.addr3[3], + frame->p80211.addr3[4], frame->p80211.addr3[5]); + printk(KERN_DEBUG " seq_ctl = 0x%04x\n", + frame->p80211.seq_ctl); + printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr4[0], frame->p80211.addr4[1], + frame->p80211.addr4[2], frame->p80211.addr4[3], + frame->p80211.addr4[4], frame->p80211.addr4[5]); + printk(KERN_DEBUG " data_len = 0x%04x\n", + frame->p80211.data_len); - return dev; + printk(KERN_DEBUG "IEEE 802.3 header:\n"); + printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_dest[0], frame->p8023.h_dest[1], + frame->p8023.h_dest[2], frame->p8023.h_dest[3], + frame->p8023.h_dest[4], frame->p8023.h_dest[5]); + printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_source[0], frame->p8023.h_source[1], + frame->p8023.h_source[2], frame->p8023.h_source[3], + frame->p8023.h_source[4], frame->p8023.h_source[5]); + printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); + printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); + printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); + printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); + printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); + printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", + frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); + printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); } +#endif /* 0 */ /********************************************************************/ /* Module initialization */ @@ -4185,7 +4186,9 @@ /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco.c 0.13e (David Gibson and others)"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (David Gibson , " + "Pavel Roskin , et al)"; static int __init init_orinoco(void) { diff -Nru a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h --- a/drivers/net/wireless/orinoco.h 2004-10-18 14:56:27 -07:00 +++ b/drivers/net/wireless/orinoco.h 2004-10-18 14:56:27 -07:00 @@ -7,39 +7,19 @@ #ifndef _ORINOCO_H #define _ORINOCO_H +#define DRIVER_VERSION "0.13e" + #include #include #include #include #include -#include "hermes.h" - -/* Workqueue / task queue backwards compatibility stuff */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) -#include -#else -#include -#define work_struct tq_struct -#define INIT_WORK INIT_TQUEUE -#define schedule_work schedule_task -#endif - -/* Interrupt handler backwards compatibility stuff */ -#ifndef IRQ_NONE -#define IRQ_NONE -#define IRQ_HANDLED -typedef void irqreturn_t; - -#endif +#include "hermes.h" /* To enable debug messages */ //#define ORINOCO_DEBUG 3 -#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) -#error "orinoco driver requires Wireless extensions v10 or later." -#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ #define WIRELESS_SPY // enable iwspy support #define ORINOCO_MAX_KEY_SIZE 14 @@ -50,11 +30,6 @@ char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); -#define ORINOCO_INTEN ( HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | \ - HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \ - HERMES_EV_INFDROP ) - - struct orinoco_private { void *card; /* Pointer to card dependent structure */ int (*hard_reset)(struct orinoco_private *); @@ -78,7 +53,6 @@ hermes_t hw; u16 txfid; - /* Capabilities of the hardware/firmware */ int firmware_type; #define FIRMWARE_TYPE_AGERE 1 @@ -127,6 +101,10 @@ #define TRACE_ENTER(devname) DEBUG(2, "%s: -> %s()\n", devname, __FUNCTION__); #define TRACE_EXIT(devname) DEBUG(2, "%s: <- %s()\n", devname, __FUNCTION__); + +/********************************************************************/ +/* Exported prototypes */ +/********************************************************************/ extern struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *)); diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c --- a/drivers/net/wireless/orinoco_cs.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/net/wireless/orinoco_cs.c 2004-10-18 14:57:03 -07:00 @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c) +/* orinoco_cs.c (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -10,6 +10,9 @@ * Copyright notice & release notes in file orinoco.c */ +#define DRIVER_NAME "orinoco_cs" +#define PFX DRIVER_NAME ": " + #include #ifdef __IN_PCMCIA_PACKAGE__ #include @@ -47,9 +50,7 @@ MODULE_AUTHOR("David Gibson "); MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif /* Module parameters */ @@ -76,7 +77,7 @@ * device driver with appropriate cards, through the card * configuration database. */ -static dev_info_t dev_info = "orinoco_cs"; +static dev_info_t dev_info = DRIVER_NAME; /********************************************************************/ /* Data structures */ @@ -144,15 +145,6 @@ /* PCMCIA stuff */ /********************************************************************/ -/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which - * does this, but it's not in 2.4 so we do our own for now. */ -static void -orinoco_cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - pcmcia_report_error(handle, &err); -} - /* * This creates an "instance" of the driver, allocating local data * structures for one device. The device is registered with Card @@ -174,7 +166,7 @@ dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); if (! dev) return NULL; - priv = dev->priv; + priv = netdev_priv(dev); card = priv->card; /* Link both structures together */ @@ -216,7 +208,7 @@ ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { - orinoco_cs_error(link->handle, RegisterClient, ret); + cs_error(link->handle, RegisterClient, ret); orinoco_cs_detach(link); return NULL; } @@ -230,8 +222,7 @@ * are freed. Otherwise, the structures will be freed when the device * is released. */ -static void -orinoco_cs_detach(dev_link_t * link) +static void orinoco_cs_detach(dev_link_t *link) { dev_link_t **linkp; struct net_device *dev = link->priv; @@ -240,10 +231,8 @@ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; - if (*linkp == NULL) { - BUG(); - return; - } + + BUG_ON(*linkp == NULL); if (link->state & DEV_CONFIG) orinoco_cs_release(link); @@ -254,9 +243,9 @@ /* Unlink device structure, and free it */ *linkp = link->next; - DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); + DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); if (link->dev) { - DEBUG(0, "orinoco_cs: About to unregister net device %p\n", + DEBUG(0, PFX "About to unregister net device %p\n", dev); unregister_netdev(dev); } @@ -269,15 +258,16 @@ * device available to the system. */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) +#define CS_CHECK(fn, ret) do { \ + last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ + } while (0) static void orinoco_cs_config(dev_link_t *link) { struct net_device *dev = link->priv; client_handle_t handle = link->handle; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; int last_fn, last_ret; @@ -308,7 +298,8 @@ link->state |= DEV_CONFIG; /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); + CS_CHECK(GetConfigurationInfo, + pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* @@ -412,8 +403,9 @@ pcmcia_release_io(link->handle, &link->io); last_ret = pcmcia_get_next_tuple(handle, &tuple); if (last_ret == CS_NO_MORE_ITEMS) { - printk(KERN_ERR "GetNextTuple(). No matching CIS configuration, " - "maybe you need the ignore_cis_vcc=1 parameter.\n"); + printk(KERN_ERR PFX "GetNextTuple(): No matching " + "CIS configuration, maybe you need the " + "ignore_cis_vcc=1 parameter.\n"); goto cs_failed; } } @@ -451,7 +443,8 @@ * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, + pcmcia_request_configuration(link->handle, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; @@ -463,7 +456,7 @@ dev->name[0] = '\0'; /* Tell the stack we exist */ if (register_netdev(dev) != 0) { - printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); + printk(KERN_ERR PFX "register_netdev() failed\n"); goto failed; } @@ -495,7 +488,7 @@ return; cs_failed: - orinoco_cs_error(link->handle, last_fn, last_ret); + cs_error(link->handle, last_fn, last_ret); failed: orinoco_cs_release(link); @@ -510,7 +503,7 @@ orinoco_cs_release(dev_link_t *link) { struct net_device *dev = link->priv; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; /* We're committed to taking the device away now, so mark the @@ -538,7 +531,7 @@ { dev_link_t *link = args->client_data; struct net_device *dev = link->priv; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; int err = 0; unsigned long flags; @@ -635,12 +628,14 @@ /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson and others)"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (David Gibson , " + "Pavel Roskin , et al)"; static struct pcmcia_driver orinoco_driver = { .owner = THIS_MODULE, .drv = { - .name = "orinoco_cs", + .name = DRIVER_NAME, }, .attach = orinoco_cs_attach, .detach = orinoco_cs_detach, @@ -660,7 +655,7 @@ pcmcia_unregister_driver(&orinoco_driver); if (dev_list) - DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); + DEBUG(0, PFX "Removing leftover devices.\n"); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) orinoco_cs_release(dev_list); @@ -670,4 +665,3 @@ module_init(init_orinoco_cs); module_exit(exit_orinoco_cs); - diff -Nru a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c --- a/drivers/net/wireless/orinoco_pci.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/net/wireless/orinoco_pci.c 2004-10-18 14:56:48 -07:00 @@ -1,19 +1,23 @@ -/* orinoco_pci.c 0.13e +/* orinoco_pci.c * * Driver for Prism II devices that have a direct PCI interface * (i.e., not in a Pcmcia or PLX bridge) * * Specifically here we're talking about the Linksys WMP11 * + * Current maintainers (as of 29 September 2003) are: + * Pavel Roskin + * and David Gibson + * * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow + * Copyright (C) 2001 Daniel Barlow * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing * has been copied from it. linux-wlan-ng-0.1.10 is originally : * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. * This file originally written by: - * Copyright (C) 2001 Jean Tourrilhes + * Copyright (C) 2001 Jean Tourrilhes * And is now maintained by: - * Copyright (C) 2002 David Gibson, IBM Corporation + * (C) Copyright David Gibson, IBM Corp. 2002-2003. * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -85,6 +89,9 @@ * Jean II */ +#define DRIVER_NAME "orinoco_pci" +#define PFX DRIVER_NAME ": " + #include #include @@ -99,7 +106,6 @@ #include #include #include -#include #include #include #include @@ -174,7 +180,7 @@ } /* Did we timeout ? */ if(time_after_eq(jiffies, timeout)) { - printk(KERN_ERR "orinoco_pci: Busy timeout\n"); + printk(KERN_ERR PFX "Busy timeout\n"); return -ETIMEDOUT; } printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies); @@ -206,22 +212,21 @@ if (! pci_iorange) goto fail; - /* Usual setup of structures */ + /* Allocate network device */ dev = alloc_orinocodev(0, NULL); if (! dev) { err = -ENOMEM; goto fail; } - priv = dev->priv; + priv = netdev_priv(dev); dev->base_addr = (unsigned long) pci_ioaddr; dev->mem_start = pci_iorange; dev->mem_end = pci_iorange + pci_iolen - 1; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n", pci_name(pdev), dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); @@ -232,12 +237,13 @@ err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); if (err) { - printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", + printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq); err = -EBUSY; goto fail; } dev->irq = pdev->irq; + /* Perform a COR reset to start the card */ if(orinoco_pci_cor_reset(priv) != 0) { printk(KERN_ERR "%s: Failed to start the card\n", dev->name); @@ -255,7 +261,8 @@ goto fail; } - return 0; /* succeeded */ + return 0; + fail: if (dev) { if (dev->irq) @@ -275,11 +282,11 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unregister_netdev(dev); - if (dev->irq) + if (dev->irq) free_irq(dev->irq, dev); if (priv->hw.iobase) @@ -294,7 +301,7 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -325,7 +332,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -357,7 +364,9 @@ } static struct pci_device_id orinoco_pci_pci_id_table[] = { + /* Intersil Prism 3 */ {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, + /* Intersil Prism 2.5 */ {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; @@ -365,7 +374,7 @@ MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table); static struct pci_driver orinoco_pci_driver = { - .name = "orinoco_pci", + .name = DRIVER_NAME, .id_table = orinoco_pci_pci_id_table, .probe = orinoco_pci_init_one, .remove = __devexit_p(orinoco_pci_remove_one), @@ -373,8 +382,11 @@ .resume = orinoco_pci_resume, }; -static char version[] __initdata = "orinoco_pci.c 0.13e (David Gibson & Jean Tourrilhes )"; -MODULE_AUTHOR("David Gibson "); +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Pavel Roskin ," + " David Gibson &" + " Jean Tourrilhes )"; +MODULE_AUTHOR("Pavel Roskin & David Gibson "); MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); MODULE_LICENSE("Dual MPL/GPL"); @@ -384,7 +396,7 @@ return pci_module_init(&orinoco_pci_driver); } -void __exit orinoco_pci_exit(void) +static void __exit orinoco_pci_exit(void) { pci_unregister_driver(&orinoco_pci_driver); } diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c --- a/drivers/net/wireless/orinoco_plx.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/net/wireless/orinoco_plx.c 2004-10-18 14:57:04 -07:00 @@ -1,9 +1,14 @@ -/* orinoco_plx.c 0.13e - * +/* orinoco_plx.c + * * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PLX9052. + * but are connected to the PCI bus by a PLX9052. + * + * Current maintainers (as of 29 September 2003) are: + * Pavel Roskin + * and David Gibson * - * Copyright (C) 2001 Daniel Barlow + * (C) Copyright David Gibson, IBM Corp. 2001-2003. + * Copyright (C) 2001 Daniel Barlow * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -33,77 +38,83 @@ * drop me mail with the id and "it works"/"it doesn't work". * * Note: if everything gets detected fine but it doesn't actually send - * or receive packets, your first port of call should probably be to + * or receive packets, your first port of call should probably be to * try newer firmware in the card. Especially if you're doing Ad-Hoc - * modes + * modes. * * The actual driving is done by orinoco.c, this is just resource * allocation stuff. The explanation below is courtesy of Ryan Niemi * on the linux-wlan-ng list at * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html + * + * The PLX9052-based cards (WL11000 and several others) are a + * different beast than the usual PCMCIA-based PRISM2 configuration + * expected by wlan-ng. Here's the general details on how the WL11000 + * PCI adapter works: + * + * - Two PCI I/O address spaces, one 0x80 long which contains the + * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA + * slot I/O address space. + * + * - One PCI memory address space, mapped to the PCMCIA memory space + * (containing the CIS). + * + * After identifying the I/O and memory space, you can read through + * the memory space to confirm the CIS's device ID or manufacturer ID + * to make sure it's the expected card. qKeep in mind that the PCMCIA + * spec specifies the CIS as the lower 8 bits of each word read from + * the CIS, so to read the bytes of the CIS, read every other byte + * (0,2,4,...). Passing that test, you need to enable the I/O address + * space on the PCMCIA card via the PCMCIA COR register. This is the + * first byte following the CIS. In my case (which may not have any + * relation to what's on the PRISM2 cards), COR was at offset 0x800 + * within the PCI memory space. Write 0x41 to the COR register to + * enable I/O mode and to select level triggered interrupts. To + * confirm you actually succeeded, read the COR register back and make + * sure it actually got set to 0x41, incase you have an unexpected + * card inserted. + * + * Following that, you can treat the second PCI I/O address space (the + * one that's not 0x80 in length) as the PCMCIA I/O space. + * + * Note that in the Eumitcom's source for their drivers, they register + * the interrupt as edge triggered when registering it with the + * Windows kernel. I don't recall how to register edge triggered on + * Linux (if it can be done at all). But in some experimentation, I + * don't see much operational difference between using either + * interrupt mode. Don't mess with the interrupt mode in the COR + * register though, as the PLX9052 wants level triggers with the way + * the serial EEPROM configures it on the WL11000. + * + * There's some other little quirks related to timing that I bumped + * into, but I don't recall right now. Also, there's two variants of + * the WL11000 I've seen, revision A1 and T2. These seem to differ + * slightly in the timings configured in the wait-state generator in + * the PLX9052. There have also been some comments from Eumitcom that + * cards shouldn't be hot swapped, apparently due to risk of cooking + * the PLX9052. I'm unsure why they believe this, as I can't see + * anything in the design that would really cause a problem, except + * for crashing drivers not written to expect it. And having developed + * drivers for the WL11000, I'd say it's quite tricky to write code + * that will successfully deal with a hot unplug. Very odd things + * happen on the I/O side of things. But anyway, be warned. Despite + * that, I've hot-swapped a number of times during debugging and + * driver development for various reasons (stuck WAIT# line after the + * radio card's firmware locks up). + * + * Hope this is enough info for someone to add PLX9052 support to the + * wlan-ng card. In the case of the WL11000, the PCI ID's are + * 0x1639/0x0200, with matching subsystem ID's. Other PLX9052-based + * manufacturers other than Eumitcom (or on cards other than the + * WL11000) may have different PCI ID's. + * + * If anyone needs any more specific info, let me know. I haven't had + * time to implement support myself yet, and with the way things are + * going, might not have time for a while.. + */ -The PLX9052-based cards (WL11000 and several others) are a different -beast than the usual PCMCIA-based PRISM2 configuration expected by -wlan-ng. Here's the general details on how the WL11000 PCI adapter -works: - - - Two PCI I/O address spaces, one 0x80 long which contains the PLX9052 - registers, and one that's 0x40 long mapped to the PCMCIA slot I/O - address space. - - - One PCI memory address space, mapped to the PCMCIA memory space - (containing the CIS). - -After identifying the I/O and memory space, you can read through the -memory space to confirm the CIS's device ID or manufacturer ID to make -sure it's the expected card. Keep in mind that the PCMCIA spec specifies -the CIS as the lower 8 bits of each word read from the CIS, so to read the -bytes of the CIS, read every other byte (0,2,4,...). Passing that test, -you need to enable the I/O address space on the PCMCIA card via the PCMCIA -COR register. This is the first byte following the CIS. In my case -(which may not have any relation to what's on the PRISM2 cards), COR was -at offset 0x800 within the PCI memory space. Write 0x41 to the COR -register to enable I/O mode and to select level triggered interrupts. To -confirm you actually succeeded, read the COR register back and make sure -it actually got set to 0x41, incase you have an unexpected card inserted. - -Following that, you can treat the second PCI I/O address space (the one -that's not 0x80 in length) as the PCMCIA I/O space. - -Note that in the Eumitcom's source for their drivers, they register the -interrupt as edge triggered when registering it with the Windows kernel. I -don't recall how to register edge triggered on Linux (if it can be done at -all). But in some experimentation, I don't see much operational -difference between using either interrupt mode. Don't mess with the -interrupt mode in the COR register though, as the PLX9052 wants level -triggers with the way the serial EEPROM configures it on the WL11000. - -There's some other little quirks related to timing that I bumped into, but -I don't recall right now. Also, there's two variants of the WL11000 I've -seen, revision A1 and T2. These seem to differ slightly in the timings -configured in the wait-state generator in the PLX9052. There have also -been some comments from Eumitcom that cards shouldn't be hot swapped, -apparently due to risk of cooking the PLX9052. I'm unsure why they -believe this, as I can't see anything in the design that would really -cause a problem, except for crashing drivers not written to expect it. And -having developed drivers for the WL11000, I'd say it's quite tricky to -write code that will successfully deal with a hot unplug. Very odd things -happen on the I/O side of things. But anyway, be warned. Despite that, -I've hot-swapped a number of times during debugging and driver development -for various reasons (stuck WAIT# line after the radio card's firmware -locks up). - -Hope this is enough info for someone to add PLX9052 support to the wlan-ng -card. In the case of the WL11000, the PCI ID's are 0x1639/0x0200, with -matching subsystem ID's. Other PLX9052-based manufacturers other than -Eumitcom (or on cards other than the WL11000) may have different PCI ID's. - -If anyone needs any more specific info, let me know. I haven't had time -to implement support myself yet, and with the way things are going, might -not have time for a while.. - ----end of mail--- -*/ +#define DRIVER_NAME "orinoco_plx" +#define PFX DRIVER_NAME ": " #include @@ -122,7 +133,6 @@ #include #include #include -#include #include #include #include @@ -132,13 +142,11 @@ #include "hermes.h" #include "orinoco.h" -static char dev_info[] = "orinoco_plx"; - -#define COR_OFFSET (0x3e0 / 2) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ +#define COR_OFFSET (0x3e0/2) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define PLX_INTCSR 0x4c /* Interrupt Control and Status Register */ -#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ +#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ +#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ static const u16 cis_magic[] = { 0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067 @@ -215,7 +223,7 @@ /* and 3 to the PCMCIA slot I/O address space */ pccard_ioaddr = pci_resource_start(pdev, 3); pccard_iolen = pci_resource_len(pdev, 3); - if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { + if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) { printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n", pccard_iolen, pccard_ioaddr); pccard_ioaddr = 0; @@ -223,28 +231,30 @@ goto fail; } + /* Allocate network device */ dev = alloc_orinocodev(0, NULL); if (! dev) { err = -ENOMEM; goto fail; } - priv = dev->priv; + priv = netdev_priv(dev); dev->base_addr = pccard_ioaddr; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG - "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n", - pci_name(pdev), pdev->irq, pccard_ioaddr); + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device " + "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, + pccard_ioaddr); - hermes_struct_init(&(priv->hw), dev->base_addr, - HERMES_IO, HERMES_16BIT_REGSPACING); + hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, + HERMES_16BIT_REGSPACING); pci_set_drvdata(pdev, dev); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); if (err) { - printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq); + printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq); err = -EBUSY; goto fail; } @@ -254,10 +264,10 @@ if (err) goto fail; - return 0; /* succeeded */ + return 0; - fail: - printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n"); + fail: + printk(KERN_DEBUG PFX "init_one(), FAIL!\n"); if (dev) { if (dev->irq) @@ -281,8 +291,7 @@ { struct net_device *dev = pci_get_drvdata(pdev); - if (! dev) - BUG(); + BUG_ON(! dev); unregister_netdev(dev); @@ -305,33 +314,34 @@ {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, Eumitcom PCI WL11000, - Addtron AWA-100*/ + Addtron AWA-100 */ {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by - Brendan W. McAdams */ + Brendan W. McAdams */ {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by - Damien Persohn */ + Damien Persohn */ {0,}, }; MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table); static struct pci_driver orinoco_plx_driver = { - .name = "orinoco_plx", + .name = DRIVER_NAME, .id_table = orinoco_plx_pci_id_table, .probe = orinoco_plx_init_one, .remove = __devexit_p(orinoco_plx_remove_one), }; -static char version[] __initdata = "orinoco_plx.c 0.13e (Daniel Barlow , David Gibson )"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Pavel Roskin ," + " David Gibson ," + " Daniel Barlow )"; MODULE_AUTHOR("Daniel Barlow "); MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif static int __init orinoco_plx_init(void) { @@ -339,7 +349,7 @@ return pci_module_init(&orinoco_plx_driver); } -void __exit orinoco_plx_exit(void) +static void __exit orinoco_plx_exit(void) { pci_unregister_driver(&orinoco_plx_driver); current->state = TASK_UNINTERRUPTIBLE; diff -Nru a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c --- a/drivers/net/wireless/orinoco_tmd.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/net/wireless/orinoco_tmd.c 2004-10-18 14:55:55 -07:00 @@ -1,10 +1,10 @@ -/* orinoco_tmd.c 0.01 +/* orinoco_tmd.c * * Driver for Prism II devices which would usually be driven by orinoco_cs, * but are connected to the PCI bus by a TMD7160. * - * Copyright (C) 2003 Joerg Dorchain - * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow + * Copyright (C) 2003 Joerg Dorchain + * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -49,6 +49,9 @@ * Pheecom sells cards with the TMD chip as "ASIC version" */ +#define DRIVER_NAME "orinoco_tmd" +#define PFX DRIVER_NAME ": " + #include #include @@ -66,7 +69,6 @@ #include #include #include -#include #include #include #include @@ -76,10 +78,7 @@ #include "hermes.h" #include "orinoco.h" -static char dev_info[] = "orinoco_tmd"; - -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA | COR_FUNC_ENA) /* Enable PC card with level triggered irqs and irq requests */ - +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ static int orinoco_tmd_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -95,11 +94,11 @@ if (err) return -EIO; - printk(KERN_DEBUG "TMD setup\n"); + printk(KERN_DEBUG PFX "TMD setup\n"); pccard_ioaddr = pci_resource_start(pdev, 2); pccard_iolen = pci_resource_len(pdev, 2); - if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { - printk(KERN_ERR "orinoco_tmd: I/O resource at 0x%lx len 0x%lx busy\n", + if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) { + printk(KERN_ERR PFX "I/O resource at 0x%lx len 0x%lx busy\n", pccard_ioaddr, pccard_iolen); pccard_ioaddr = 0; err = -EBUSY; @@ -110,34 +109,35 @@ mdelay(1); reg = inb(addr); if (reg != COR_VALUE) { - printk(KERN_ERR "orinoco_tmd: Error setting TMD COR values %x should be %x\n", reg, COR_VALUE); + printk(KERN_ERR PFX "Error setting TMD COR values %x should be %x\n", reg, COR_VALUE); err = -EIO; goto fail; } + /* Allocate network device */ dev = alloc_orinocodev(0, NULL); if (! dev) { err = -ENOMEM; goto fail; } - priv = dev->priv; + priv = netdev_priv(dev); dev->base_addr = pccard_ioaddr; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG - "Detected Orinoco/Prism2 TMD device at %s irq:%d, io addr:0x%lx\n", - pci_name(pdev), pdev->irq, pccard_ioaddr); + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device " + "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, + pccard_ioaddr); hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, HERMES_16BIT_REGSPACING); pci_set_drvdata(pdev, dev); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, - dev); + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); if (err) { - printk(KERN_ERR "orinoco_tmd: Error allocating IRQ %d.\n", + printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq); err = -EBUSY; goto fail; @@ -148,10 +148,10 @@ if (err) goto fail; - return 0; /* succeeded */ + return 0; - fail: - printk(KERN_DEBUG "orinoco_tmd: init_one(), FAIL!\n"); + fail: + printk(KERN_DEBUG PFX "init_one(), FAIL!\n"); if (dev) { if (dev->irq) @@ -172,8 +172,7 @@ { struct net_device *dev = pci_get_drvdata(pdev); - if (! dev) - BUG(); + BUG_ON(! dev); unregister_netdev(dev); @@ -198,18 +197,17 @@ MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table); static struct pci_driver orinoco_tmd_driver = { - .name = "orinoco_tmd", + .name = DRIVER_NAME, .id_table = orinoco_tmd_pci_id_table, .probe = orinoco_tmd_init_one, .remove = __devexit_p(orinoco_tmd_remove_one), }; -static char version[] __initdata = "orinoco_tmd.c 0.01 (Joerg Dorchain )"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Joerg Dorchain )"; MODULE_AUTHOR("Joerg Dorchain "); MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif static int __init orinoco_tmd_init(void) { @@ -217,7 +215,7 @@ return pci_module_init(&orinoco_tmd_driver); } -void __exit orinoco_tmd_exit(void) +static void __exit orinoco_tmd_exit(void) { pci_unregister_driver(&orinoco_tmd_driver); current->state = TASK_UNINTERRUPTIBLE; diff -Nru a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c --- a/drivers/net/wireless/prism54/isl_38xx.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/net/wireless/prism54/isl_38xx.c 2004-10-18 14:56:31 -07:00 @@ -44,7 +44,7 @@ * register located at offset %ISL38XX_INT_IDENT_REG. */ void -isl38xx_disable_interrupts(void *device) +isl38xx_disable_interrupts(void __iomem *device) { isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); udelay(ISL38XX_WRITEIO_DELAY); @@ -52,7 +52,7 @@ void isl38xx_handle_sleep_request(isl38xx_control_block *control_block, - int *powerstate, void *device_base) + int *powerstate, void __iomem *device_base) { /* device requests to go into sleep mode * check whether the transmit queues for data and management are empty */ @@ -88,7 +88,7 @@ void isl38xx_handle_wakeup(isl38xx_control_block *control_block, - int *powerstate, void *device_base) + int *powerstate, void __iomem *device_base) { /* device is in active state, update the powerstate flag */ *powerstate = ISL38XX_PSM_ACTIVE_STATE; @@ -110,7 +110,7 @@ } void -isl38xx_trigger_device(int asleep, void *device_base) +isl38xx_trigger_device(int asleep, void __iomem *device_base) { struct timeval current_time; u32 reg, counter = 0; @@ -190,7 +190,7 @@ } void -isl38xx_interface_reset(void *device_base, dma_addr_t host_address) +isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) { u32 reg; @@ -219,7 +219,7 @@ } void -isl38xx_enable_common_interrupts(void *device_base) { +isl38xx_enable_common_interrupts(void __iomem *device_base) { u32 reg; reg = ( ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); diff -Nru a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h --- a/drivers/net/wireless/prism54/isl_38xx.h 2004-10-18 14:57:19 -07:00 +++ b/drivers/net/wireless/prism54/isl_38xx.h 2004-10-18 14:57:19 -07:00 @@ -75,7 +75,7 @@ * from the %ISL38XX_PCI_POSTING_FLUSH offset. */ static inline void -isl38xx_w32_flush(void *base, u32 val, unsigned long offset) +isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset) { writel(val, base + offset); (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); @@ -157,13 +157,13 @@ /* determine number of entries currently in queue */ int isl38xx_in_queue(isl38xx_control_block *cb, int queue); -void isl38xx_disable_interrupts(void *); -void isl38xx_enable_common_interrupts(void *); +void isl38xx_disable_interrupts(void __iomem *); +void isl38xx_enable_common_interrupts(void __iomem *); void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, - void *); -void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *); -void isl38xx_trigger_device(int, void *); -void isl38xx_interface_reset(void *, dma_addr_t); + void __iomem *); +void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void __iomem *); +void isl38xx_trigger_device(int, void __iomem *); +void isl38xx_interface_reset(void __iomem *, dma_addr_t); #endif /* _ISL_38XX_H */ diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c --- a/drivers/net/wireless/prism54/isl_ioctl.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/wireless/prism54/isl_ioctl.c 2004-10-18 14:56:28 -07:00 @@ -334,9 +334,10 @@ int rvalue; rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); - + fwrq->i = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r); fwrq->m = r.u; - fwrq->e = 0; + fwrq->e = 3; return rvalue; } diff -Nru a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c --- a/drivers/net/wireless/prism54/islpci_dev.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/net/wireless/prism54/islpci_dev.c 2004-10-18 14:55:54 -07:00 @@ -58,7 +58,7 @@ isl_upload_firmware(islpci_private *priv) { u32 reg, rc; - void *device_base = priv->device_base; + void __iomem *device_base = priv->device_base; /* clear the RAMBoot and the Reset bit */ reg = readl(device_base + ISL38XX_CTRL_STAT_REG); @@ -113,7 +113,7 @@ (fw_len > ISL38XX_MEMORY_WINDOW_SIZE) ? ISL38XX_MEMORY_WINDOW_SIZE : fw_len; - u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; + u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; /* set the cards base address for writting the data */ isl38xx_w32_flush(device_base, reg, @@ -183,7 +183,7 @@ u32 reg; islpci_private *priv = config; struct net_device *ndev = priv->ndev; - void *device = priv->device_base; + void __iomem *device = priv->device_base; int powerstate = ISL38XX_PSM_POWERSAVE_STATE; /* lock the interrupt handler */ @@ -405,7 +405,7 @@ static int prism54_bring_down(islpci_private *priv) { - void *device_base = priv->device_base; + void __iomem *device_base = priv->device_base; u32 reg; /* we are going to shutdown the device */ islpci_set_state(priv, PRV_STATE_PREBOOT); diff -Nru a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h --- a/drivers/net/wireless/prism54/islpci_dev.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/wireless/prism54/islpci_dev.h 2004-10-18 14:56:28 -07:00 @@ -109,7 +109,7 @@ u32 pci_state[16]; /* used for suspend/resume */ char firmware[33]; - void *device_base; /* ioremapped device base address */ + void __iomem *device_base; /* ioremapped device base address */ /* consistent DMA region */ void *driver_mem_address; /* base DMA address */ diff -Nru a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c --- a/drivers/net/wireless/ray_cs.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/net/wireless/ray_cs.c 2004-10-18 14:56:28 -07:00 @@ -54,7 +54,6 @@ #include #include -#ifdef CONFIG_NET_PCMCIA_RADIO #include #include @@ -68,7 +67,6 @@ typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ -#endif /* CONFIG_NET_PCMCIA_RADIO */ #include "rayctl.h" #include "ray_cs.h" @@ -112,9 +110,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void ray_update_multi_list(struct net_device *dev, int all); -static int translate_frame(ray_dev_t *local, struct tx_msg *ptx, +static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, int len); -static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type, +static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, unsigned char *data); static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ @@ -140,14 +138,14 @@ /* Prototypes for interrpt time functions **********************************/ static irqreturn_t ray_interrupt (int reg, void *dev_id, struct pt_regs *regs); static void clear_interrupt(ray_dev_t *local); -static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, +static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len); static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); -static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs); -static void release_frag_chain(ray_dev_t *local, struct rcs *prcs); -static void rx_authenticate(ray_dev_t *local, struct rcs *prcs, +static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs); +static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs); +static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len); -static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, +static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len); static void associate(ray_dev_t *local); @@ -540,7 +538,7 @@ CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); - local->sram = (UCHAR *)(ioremap(req.Base,req.Size)); + local->sram = ioremap(req.Base,req.Size); /*** Set up 16k window for shared memory (receive buffer) ***************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; @@ -550,7 +548,7 @@ CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->rmem_handle)); mem.CardOffset = 0x8000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); - local->rmem = (UCHAR *)(ioremap(req.Base,req.Size)); + local->rmem = ioremap(req.Base,req.Size); /*** Set up window for attribute memory ***********************************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; @@ -560,7 +558,7 @@ CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->amem_handle)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); - local->amem = (UCHAR *)(ioremap(req.Base,req.Size)); + local->amem = ioremap(req.Base,req.Size); DEBUG(3,"ray_config sram=%p\n",local->sram); DEBUG(3,"ray_config rmem=%p\n",local->rmem); @@ -593,12 +591,30 @@ ray_release(link); } /* ray_config */ + +static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) +{ + return dev->sram + CCS_BASE; +} + +static inline struct rcs __iomem *rcs_base(ray_dev_t *dev) +{ + /* + * This looks nonsensical, since there is a separate + * RCS_BASE. But the difference between a "struct rcs" + * and a "struct ccs" ends up being in the _index_ off + * the base, so the base pointer is the same for both + * ccs/rcs. + */ + return dev->sram + CCS_BASE; +} + /*===========================================================================*/ static int ray_init(struct net_device *dev) { int i; UCHAR *p; - struct ccs *pccs; + struct ccs __iomem *pccs; ray_dev_t *local = (ray_dev_t *)dev->priv; dev_link_t *link = local->finder; DEBUG(1, "ray_init(0x%p)\n", dev); @@ -632,7 +648,7 @@ local->tib_length = local->startup_res.tib_length; DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length); /* Initialize CCS's to buffer free state */ - pccs = (struct ccs *)(local->sram + CCS_BASE); + pccs = ccs_base(local); for (i=0; ibuffer_status); } @@ -661,7 +677,7 @@ { int ccsindex; ray_dev_t *local = (ray_dev_t *)dev->priv; - struct ccs *pccs; + struct ccs __iomem *pccs; dev_link_t *link = local->finder; DEBUG(1,"dl_startup_params entered\n"); @@ -682,7 +698,7 @@ /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return -1; local->dl_param_ccs = ccsindex; - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); /* Interrupt the firmware to process the command */ @@ -767,7 +783,7 @@ static void verify_dl_startup(u_long data) { ray_dev_t *local = (ray_dev_t *)data; - struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs; + struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; UCHAR status; dev_link_t *link = local->finder; @@ -807,7 +823,7 @@ static void start_net(u_long data) { ray_dev_t *local = (ray_dev_t *)data; - struct ccs *pccs; + struct ccs __iomem *pccs; int ccsindex; dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { @@ -816,7 +832,7 @@ } /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return; - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_START_NETWORK, &pccs->cmd); writeb(0, &pccs->var.start_network.update_param); /* Interrupt the firmware to process the command */ @@ -834,7 +850,7 @@ { ray_dev_t *local = (ray_dev_t *)data; - struct ccs *pccs; + struct ccs __iomem *pccs; int ccsindex; dev_link_t *link = local->finder; @@ -844,7 +860,7 @@ } /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return; - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_JOIN_NETWORK, &pccs->cmd); writeb(0, &pccs->var.join_network.update_param); writeb(0, &pccs->var.join_network.net_initiated); @@ -1049,10 +1065,10 @@ UCHAR msg_type) { ray_dev_t *local = (ray_dev_t *)dev->priv; - struct ccs *pccs; + struct ccs __iomem *pccs; int ccsindex; int offset; - struct tx_msg *ptx; /* Address of xmit buffer in PC space */ + struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ short int addr; /* Address of xmit buffer in card space */ DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev); @@ -1079,7 +1095,7 @@ local->stats.tx_packets++; } - ptx = (struct tx_msg *)(local->sram + addr); + ptx = local->sram + addr; ray_build_header(local, ptx, msg_type, data); if (translate) { @@ -1092,7 +1108,7 @@ } /* fill in the CCS */ - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; len += TX_HEADER_LENGTH + offset; writeb(CCS_TX_REQUEST, &pccs->cmd); writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); @@ -1119,21 +1135,21 @@ return XMIT_OK; } /* end ray_hw_xmit */ /*===========================================================================*/ -static int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char *data, +static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, int len) { unsigned short int proto = ((struct ethhdr *)data)->h_proto; if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ DEBUG(3,"ray_cs translate_frame DIX II\n"); /* Copy LLC header to card buffer */ - memcpy_toio((UCHAR *)&ptx->var, eth2_llc, sizeof(eth2_llc)); - memcpy_toio( ((UCHAR *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); + memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); + memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); if ((proto == 0xf380) || (proto == 0x3781)) { /* This is the selective translation table, only 2 entries */ - writeb(0xf8, (UCHAR *) &((struct snaphdr_t *)ptx->var)->org[3]); + writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); } /* Copy body of ethernet packet without ethernet header */ - memcpy_toio((UCHAR *)&ptx->var + sizeof(struct snaphdr_t), \ + memcpy_toio((void __iomem *)&ptx->var + sizeof(struct snaphdr_t), \ data + ETH_HLEN, len - ETH_HLEN); return (int) sizeof(struct snaphdr_t) - ETH_HLEN; } @@ -1141,16 +1157,16 @@ DEBUG(3,"ray_cs translate_frame 802\n"); if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ DEBUG(3,"ray_cs translate_frame evil IPX\n"); - memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN, len - ETH_HLEN); + memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); return 0 - ETH_HLEN; } - memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN, len - ETH_HLEN); + memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); return 0 - ETH_HLEN; } /* TBD do other frame types */ } /* end translate_frame */ /*===========================================================================*/ -static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type, +static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, unsigned char *data) { writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); @@ -1633,7 +1649,7 @@ { ray_dev_t * local = (ray_dev_t *) dev->priv; dev_link_t *link = local->finder; - struct status *p = (struct status *)(local->sram + STATUS_BASE); + struct status __iomem *p = local->sram + STATUS_BASE; if(local == (ray_dev_t *) NULL) return (iw_stats *) NULL; @@ -1755,7 +1771,7 @@ static int get_free_tx_ccs(ray_dev_t *local) { int i; - struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE); + struct ccs __iomem *pccs = ccs_base(local); dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { @@ -1786,7 +1802,7 @@ static int get_free_ccs(ray_dev_t *local) { int i; - struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE); + struct ccs __iomem *pccs = ccs_base(local); dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { @@ -1863,7 +1879,7 @@ { ray_dev_t *local = (ray_dev_t *)dev->priv; dev_link_t *link = local->finder; - struct status *p = (struct status *)(local->sram + STATUS_BASE); + struct status __iomem *p = local->sram + STATUS_BASE; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_cs net_device_stats - device not present\n"); return &local->stats; @@ -1895,7 +1911,7 @@ dev_link_t *link = local->finder; int ccsindex; int i; - struct ccs *pccs; + struct ccs __iomem *pccs; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_update_parm - device not present\n"); @@ -1907,7 +1923,7 @@ DEBUG(0,"ray_update_parm - No free ccs\n"); return; } - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_UPDATE_PARAMS, &pccs->cmd); writeb(objid, &pccs->var.update_param.object_id); writeb(1, &pccs->var.update_param.number_objects); @@ -1926,11 +1942,11 @@ { struct dev_mc_list *dmi, **dmip; int ccsindex; - struct ccs *pccs; + struct ccs __iomem *pccs; int i = 0; ray_dev_t *local = (ray_dev_t *)dev->priv; dev_link_t *link = local->finder; - UCHAR *p = local->sram + HOST_TO_ECF_BASE; + void __iomem *p = local->sram + HOST_TO_ECF_BASE; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_update_multi_list - device not present\n"); @@ -1943,7 +1959,7 @@ DEBUG(1,"ray_update_multi - No free ccs\n"); return; } - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); if (all) { @@ -2011,8 +2027,8 @@ struct net_device *dev = (struct net_device *)dev_id; dev_link_t *link; ray_dev_t *local; - struct ccs *pccs; - struct rcs *prcs; + struct ccs __iomem *pccs; + struct rcs __iomem *prcs; UCHAR rcsindex; UCHAR tmp; UCHAR cmd; @@ -2029,7 +2045,7 @@ DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); return IRQ_NONE; } - rcsindex = readb(&((struct scb *)(local->sram))->rcs_index); + rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { @@ -2039,7 +2055,7 @@ } if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */ { - pccs = ((struct ccs *) (local->sram + CCS_BASE)) + rcsindex; + pccs = ccs_base(local) + rcsindex; cmd = readb(&pccs->cmd); status = readb(&pccs->buffer_status); switch (cmd) @@ -2153,7 +2169,7 @@ } else /* It's an RCS */ { - prcs = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex; + prcs = rcs_base(local) + rcsindex; switch (readb(&prcs->interrupt_id)) { @@ -2194,11 +2210,11 @@ return IRQ_HANDLED; } /* ray_interrupt */ /*===========================================================================*/ -static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs) +static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs) { int rx_len; unsigned int pkt_addr; - UCHAR *pmsg; + void __iomem *pmsg; DEBUG(4,"ray_rx process rx packet\n"); /* Calculate address of packet within Rx buffer */ @@ -2248,11 +2264,11 @@ } /* end ray_rx */ /*===========================================================================*/ -static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, +static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len) { struct sk_buff *skb = NULL; - struct rcs *prcslink = prcs; + struct rcs __iomem *prcslink = prcs; ray_dev_t *local = dev->priv; UCHAR *rx_ptr; int total_len; @@ -2294,7 +2310,7 @@ + readb(&prcslink->var.rx_packet.rx_data_length[1]); if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF || tmp < 0) break; - prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + prcslink = rcs_base(local) + readb(&prcslink->link_field); } while (1); @@ -2355,7 +2371,7 @@ prcslink = prcs; DEBUG(1,"ray_cs rx_data in fragment loop\n"); do { - prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + prcslink = rcs_base(local) + readb(&prcslink->var.rx_packet.next_frag_rcs_index); rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) + readb(&prcslink->var.rx_packet.rx_data_length[1])) @@ -2529,9 +2545,9 @@ return length; } /*===========================================================================*/ -static void release_frag_chain(ray_dev_t *local, struct rcs* prcs) +static void release_frag_chain(ray_dev_t *local, struct rcs __iomem * prcs) { - struct rcs *prcslink = prcs; + struct rcs __iomem *prcslink = prcs; int tmp = 17; unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); @@ -2541,7 +2557,7 @@ DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); break; } - prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex; + prcslink = rcs_base(local) + rcsindex; rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); } writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); @@ -2569,7 +2585,7 @@ local->authentication_state = AWAITING_RESPONSE; } /* end authenticate */ /*===========================================================================*/ -static void rx_authenticate(ray_dev_t *local, struct rcs *prcs, +static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len) { UCHAR buff[256]; @@ -2614,7 +2630,7 @@ /*===========================================================================*/ static void associate(ray_dev_t *local) { - struct ccs *pccs; + struct ccs __iomem *pccs; dev_link_t *link = local->finder; struct net_device *dev = link->priv; int ccsindex; @@ -2630,7 +2646,7 @@ return; } DEBUG(1,"ray_cs Starting association with access point\n"); - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; /* fill in the CCS */ writeb(CCS_START_ASSOCIATION, &pccs->cmd); /* Interrupt the firmware to process the command */ @@ -2650,7 +2666,7 @@ } /* end associate */ /*===========================================================================*/ -static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, +static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len) { /* UCHAR buff[256]; @@ -2798,8 +2814,8 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) { int addr; - struct ccs *pccs; - struct tx_msg *ptx; + struct ccs __iomem *pccs; + struct tx_msg __iomem *ptx; int ccsindex; /* If no tx buffers available, return */ @@ -2809,7 +2825,7 @@ return -1; } - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; /* Address in card space */ addr = TX_BUF_BASE + (ccsindex << 11); @@ -2821,7 +2837,7 @@ writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1); writeb(0, &pccs->var.tx_request.pow_sav_mode); - ptx = (struct tx_msg *)(local->sram + addr); + ptx = local->sram + addr; /* fill in the mac header */ writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); writeb(0, &ptx->mac.frame_ctl_2); @@ -2931,15 +2947,6 @@ { DEBUG(0, "ray_cs: cleanup_module\n"); - -#ifdef CONFIG_PROC_FS - remove_proc_entry("ray_cs", proc_root_driver); -#endif - - pcmcia_unregister_driver(&ray_driver); - while (dev_list != NULL) - ray_detach(dev_list); - #ifdef CONFIG_PROC_FS remove_proc_entry("driver/ray_cs/ray_cs", NULL); remove_proc_entry("driver/ray_cs/essid", NULL); @@ -2947,6 +2954,10 @@ remove_proc_entry("driver/ray_cs/translate", NULL); remove_proc_entry("driver/ray_cs", NULL); #endif + + pcmcia_unregister_driver(&ray_driver); + while (dev_list != NULL) + ray_detach(dev_list); } /* exit_ray_cs */ module_init(init_ray_cs); diff -Nru a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h --- a/drivers/net/wireless/ray_cs.h 2004-10-18 14:56:50 -07:00 +++ b/drivers/net/wireless/ray_cs.h 2004-10-18 14:56:50 -07:00 @@ -28,9 +28,9 @@ dev_node_t node; window_handle_t amem_handle; /* handle to window for attribute memory */ window_handle_t rmem_handle; /* handle to window for rx buffer on card */ - UCHAR *sram; /* pointer to beginning of shared RAM */ - UCHAR *amem; /* pointer to attribute mem window */ - UCHAR *rmem; /* pointer to receive buffer window */ + void __iomem *sram; /* pointer to beginning of shared RAM */ + void __iomem *amem; /* pointer to attribute mem window */ + void __iomem *rmem; /* pointer to receive buffer window */ dev_link_t *finder; /* pointer back to dev_link_t for card */ struct timer_list timer; long tx_ccs_lock; diff -Nru a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c --- a/drivers/net/wireless/strip.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/net/wireless/strip.c 2004-10-18 14:56:48 -07:00 @@ -106,6 +106,7 @@ #include #include #include +#include #include #include @@ -1348,14 +1349,17 @@ */ if (haddr.c[0] == 0xFF) { u32 brd = 0; - struct in_device *in_dev = in_dev_get(strip_info->dev); - if (in_dev == NULL) + struct in_device *in_dev; + + rcu_read_lock(); + in_dev = __in_dev_get(strip_info->dev); + if (in_dev == NULL) { + rcu_read_unlock(); return NULL; - read_lock(&in_dev->lock); + } if (in_dev->ifa_list) brd = in_dev->ifa_list->ifa_broadcast; - read_unlock(&in_dev->lock); - in_dev_put(in_dev); + rcu_read_unlock(); /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ if (!arp_query(haddr.c, brd, strip_info->dev)) { @@ -1500,17 +1504,18 @@ } if (1) { - struct in_device *in_dev = in_dev_get(strip_info->dev); + struct in_device *in_dev; + brd = addr = 0; + rcu_read_lock(); + in_dev = __in_dev_get(strip_info->dev); if (in_dev) { - read_lock(&in_dev->lock); if (in_dev->ifa_list) { brd = in_dev->ifa_list->ifa_broadcast; addr = in_dev->ifa_list->ifa_local; } - read_unlock(&in_dev->lock); - in_dev_put(in_dev); } + rcu_read_unlock(); } @@ -2661,8 +2666,6 @@ tty->disc_data = strip_info; if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); /* * Restore default settings diff -Nru a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c --- a/drivers/net/wireless/wavelan.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/net/wireless/wavelan.c 2004-10-18 14:57:03 -07:00 @@ -3822,17 +3822,18 @@ if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) { u8 dce_status; -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", - dev->name, dce_status); -#endif /* * Interrupt from the modem management controller. * This will clear it -- ignored for now. */ mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status)); + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", + dev->name, dce_status); +#endif } /* Check if not controller interrupt */ diff -Nru a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c --- a/drivers/oprofile/buffer_sync.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/oprofile/buffer_sync.c 2004-10-18 14:56:27 -07:00 @@ -32,61 +32,65 @@ #include "cpu_buffer.h" #include "buffer_sync.h" -#define DEFAULT_EXPIRE (HZ / 4) - -static void wq_sync_buffers(void *); -static DECLARE_WORK(sync_wq, wq_sync_buffers, NULL); - -static struct timer_list sync_timer; -static void timer_ping(unsigned long data); -static void sync_cpu_buffers(void); +static LIST_HEAD(dying_tasks); +static LIST_HEAD(dead_tasks); +cpumask_t marked_cpus = CPU_MASK_NONE; +static spinlock_t task_mortuary = SPIN_LOCK_UNLOCKED; +void process_task_mortuary(void); - -/* We must make sure to process every entry in the CPU buffers - * before a task got the PF_EXITING flag, otherwise we will hold - * references to a possibly freed task_struct. We are safe with - * samples past the PF_EXITING point in do_exit(), because we - * explicitly check for that in cpu_buffer.c + +/* Take ownership of the task struct and place it on the + * list for processing. Only after two full buffer syncs + * does the task eventually get freed, because by then + * we are sure we will not reference it again. */ -static int exit_task_notify(struct notifier_block * self, unsigned long val, void * data) +static int task_free_notify(struct notifier_block * self, unsigned long val, void * data) { - sync_cpu_buffers(); - return 0; + struct task_struct * task = (struct task_struct *)data; + spin_lock(&task_mortuary); + list_add(&task->tasks, &dying_tasks); + spin_unlock(&task_mortuary); + return NOTIFY_OK; } - -/* There are two cases of tasks modifying task->mm->mmap list we - * must concern ourselves with. First, when a task is about to - * exit (exit_mmap()), we should process the buffer to deal with - * any samples in the CPU buffer, before we lose the ->mmap information - * we need. It is vital to get this case correct, otherwise we can - * end up trying to access a freed task_struct. + + +/* The task is on its way out. A sync of the buffer means we can catch + * any remaining samples for this task. */ -static int mm_notify(struct notifier_block * self, unsigned long val, void * data) +static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data) { - sync_cpu_buffers(); - return 0; + /* To avoid latency problems, we only process the current CPU, + * hoping that most samples for the task are on this CPU + */ + sync_buffer(smp_processor_id()); + return 0; } -/* Second, a task may unmap (part of) an executable mmap, - * so we want to process samples before that happens too. This is merely - * a QOI issue not a correctness one. +/* The task is about to try a do_munmap(). We peek at what it's going to + * do, and if it's an executable region, process the samples first, so + * we don't lose any. This does not have to be exact, it's a QoI issue + * only. */ static int munmap_notify(struct notifier_block * self, unsigned long val, void * data) { - /* Note that we cannot sync the buffers directly, because we might end up - * taking the the mmap_sem that we hold now inside of event_buffer_read() - * on a page fault, whilst holding buffer_sem - deadlock. - * - * This would mean a threaded reader of the event buffer, but we should - * prevent it anyway. - * - * Delaying the work in a context that doesn't hold the mmap_sem means - * that we won't lose samples from other mappings that current() may - * have. Note that either way, we lose any pending samples for what is - * being unmapped. - */ - schedule_work(&sync_wq); + unsigned long addr = (unsigned long)data; + struct mm_struct * mm = current->mm; + struct vm_area_struct * mpnt; + + down_read(&mm->mmap_sem); + + mpnt = find_vma(mm, addr); + if (mpnt && mpnt->vm_file && (mpnt->vm_flags & VM_EXEC)) { + up_read(&mm->mmap_sem); + /* To avoid latency problems, we only process the current CPU, + * hoping that most samples for the task are on this CPU + */ + sync_buffer(smp_processor_id()); + return 0; + } + + up_read(&mm->mmap_sem); return 0; } @@ -100,7 +104,7 @@ if (val != MODULE_STATE_COMING) return 0; - sync_cpu_buffers(); + /* FIXME: should we process all CPU buffers ? */ down(&buffer_sem); add_event_entry(ESCAPE_CODE); add_event_entry(MODULE_LOADED_CODE); @@ -110,16 +114,16 @@ } -static struct notifier_block exit_task_nb = { - .notifier_call = exit_task_notify, +static struct notifier_block task_free_nb = { + .notifier_call = task_free_notify, }; -static struct notifier_block exec_unmap_nb = { - .notifier_call = munmap_notify, +static struct notifier_block task_exit_nb = { + .notifier_call = task_exit_notify, }; -static struct notifier_block exit_mmap_nb = { - .notifier_call = mm_notify, +static struct notifier_block munmap_nb = { + .notifier_call = munmap_notify, }; static struct notifier_block module_load_nb = { @@ -127,11 +131,12 @@ }; -static void end_sync_timer(void) +static void end_sync(void) { - del_timer_sync(&sync_timer); - /* timer might have queued work, make sure it's completed. */ - flush_scheduled_work(); + end_cpu_work(); + /* make sure we don't leak task structs */ + process_task_mortuary(); + process_task_mortuary(); } @@ -139,18 +144,15 @@ { int err; - init_timer(&sync_timer); - sync_timer.function = timer_ping; - sync_timer.expires = jiffies + DEFAULT_EXPIRE; - add_timer(&sync_timer); + start_cpu_work(); - err = profile_event_register(EXIT_TASK, &exit_task_nb); + err = task_handoff_register(&task_free_nb); if (err) goto out1; - err = profile_event_register(EXIT_MMAP, &exit_mmap_nb); + err = profile_event_register(PROFILE_TASK_EXIT, &task_exit_nb); if (err) goto out2; - err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb); + err = profile_event_register(PROFILE_MUNMAP, &munmap_nb); if (err) goto out3; err = register_module_notifier(&module_load_nb); @@ -160,13 +162,13 @@ out: return err; out4: - profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb); + profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); out3: - profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); + profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); out2: - profile_event_unregister(EXIT_TASK, &exit_task_nb); + task_handoff_unregister(&task_free_nb); out1: - end_sync_timer(); + end_sync(); goto out; } @@ -174,10 +176,10 @@ void sync_stop(void) { unregister_module_notifier(&module_load_nb); - profile_event_unregister(EXIT_TASK, &exit_task_nb); - profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); - profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb); - end_sync_timer(); + profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); + profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); + task_handoff_unregister(&task_free_nb); + end_sync(); } @@ -337,40 +339,25 @@ } } - + static void release_mm(struct mm_struct * mm) { - if (mm) - up_read(&mm->mmap_sem); + if (!mm) + return; + up_read(&mm->mmap_sem); + mmput(mm); } -/* Take the task's mmap_sem to protect ourselves from - * races when we do lookup_dcookie(). - */ static struct mm_struct * take_tasks_mm(struct task_struct * task) { - struct mm_struct * mm; - - /* Subtle. We don't need to keep a reference to this task's mm, - * because, for the mm to be freed on another CPU, that would have - * to go through the task exit notifier, which ends up sleeping - * on the buffer_sem we hold, so we end up with mutual exclusion - * anyway. - */ - task_lock(task); - mm = task->mm; - task_unlock(task); - - if (mm) { - /* needed to walk the task's VMAs */ + struct mm_struct * mm = get_task_mm(task); + if (mm) down_read(&mm->mmap_sem); - } - return mm; } - - + + static inline int is_ctx_switch(unsigned long val) { return val == ~0UL; @@ -417,24 +404,80 @@ } +/* Move tasks along towards death. Any tasks on dead_tasks + * will definitely have no remaining references in any + * CPU buffers at this point, because we use two lists, + * and to have reached the list, it must have gone through + * one full sync already. + */ +void process_task_mortuary(void) +{ + struct list_head * pos; + struct list_head * pos2; + struct task_struct * task; + + spin_lock(&task_mortuary); + + list_for_each_safe(pos, pos2, &dead_tasks) { + task = list_entry(pos, struct task_struct, tasks); + list_del(&task->tasks); + free_task(task); + } + + list_for_each_safe(pos, pos2, &dying_tasks) { + task = list_entry(pos, struct task_struct, tasks); + list_del(&task->tasks); + list_add_tail(&task->tasks, &dead_tasks); + } + + spin_unlock(&task_mortuary); +} + + +static void mark_done(int cpu) +{ + int i; + + cpu_set(cpu, marked_cpus); + + for_each_online_cpu(i) { + if (!cpu_isset(i, marked_cpus)) + return; + } + + /* All CPUs have been processed at least once, + * we can process the mortuary once + */ + process_task_mortuary(); + + cpus_clear(marked_cpus); +} + + /* Sync one of the CPU's buffers into the global event buffer. * Here we need to go through each batch of samples punctuated * by context switch notes, taking the task's mmap_sem and doing * lookup in task->mm->mmap to convert EIP into dcookie/offset * value. */ -static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf) +void sync_buffer(int cpu) { + struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu]; struct mm_struct *mm = NULL; struct task_struct * new; unsigned long cookie = 0; int in_kernel = 1; unsigned int i; + unsigned long available; + + down(&buffer_sem); + add_cpu_switch(cpu); + /* Remember, only we can modify tail_pos */ - unsigned long const available = get_slots(cpu_buf); - + available = get_slots(cpu_buf); + for (i=0; i < available; ++i) { struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos]; @@ -462,50 +505,8 @@ increment_tail(cpu_buf); } release_mm(mm); -} - - -/* Process each CPU's local buffer into the global - * event buffer. - */ -static void sync_cpu_buffers(void) -{ - int i; - down(&buffer_sem); - - for (i = 0; i < NR_CPUS; ++i) { - struct oprofile_cpu_buffer * cpu_buf; - - if (!cpu_possible(i)) - continue; - - cpu_buf = &cpu_buffer[i]; - - add_cpu_switch(i); - sync_buffer(cpu_buf); - } + mark_done(cpu); up(&buffer_sem); - - mod_timer(&sync_timer, jiffies + DEFAULT_EXPIRE); -} - - -static void wq_sync_buffers(void * data) -{ - sync_cpu_buffers(); -} - - -/* It is possible that we could have no munmap() or - * other events for a period of time. This will lead - * the CPU buffers to overflow and lose samples and - * context switches. We try to reduce the problem - * by timing out when nothing happens for a while. - */ -static void timer_ping(unsigned long data) -{ - schedule_work(&sync_wq); - /* timer is re-added by the scheduled task */ } diff -Nru a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h --- a/drivers/oprofile/buffer_sync.h 2004-10-18 14:55:54 -07:00 +++ b/drivers/oprofile/buffer_sync.h 2004-10-18 14:55:54 -07:00 @@ -16,4 +16,7 @@ /* remove the hooks */ void sync_stop(void); +/* sync the given CPU's buffer */ +void sync_buffer(int cpu); + #endif /* OPROFILE_BUFFER_SYNC_H */ diff -Nru a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c --- a/drivers/oprofile/cpu_buffer.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/oprofile/cpu_buffer.c 2004-10-18 14:55:54 -07:00 @@ -9,7 +9,7 @@ * Each CPU has a local buffer that stores PC value/event * pairs. We also log context switches when we notice them. * Eventually each CPU's buffer is processed into the global - * event buffer by sync_cpu_buffers(). + * event buffer by sync_buffer(). * * We use a local buffer for two reasons: an NMI or similar * interrupt cannot synchronise, and high sampling rates @@ -22,21 +22,23 @@ #include #include "cpu_buffer.h" +#include "buffer_sync.h" #include "oprof.h" struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned; +static void wq_sync_buffer(void *); + +#define DEFAULT_TIMER_EXPIRE (HZ / 10) +int work_enabled; + static void __free_cpu_buffers(int num) { int i; - for (i=0; i < num; ++i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; - - if (!cpu_possible(i)) - continue; - - vfree(b->buffer); + for_each_online_cpu(i) { + if (cpu_buffer[i].buffer) + vfree(cpu_buffer[i].buffer); } } @@ -47,12 +49,9 @@ unsigned long buffer_size = fs_cpu_buffer_size; - for (i=0; i < NR_CPUS; ++i) { + for_each_online_cpu(i) { struct oprofile_cpu_buffer * b = &cpu_buffer[i]; - if (!cpu_possible(i)) - continue; - b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size); if (!b->buffer) goto fail; @@ -64,9 +63,11 @@ b->head_pos = 0; b->sample_received = 0; b->sample_lost_overflow = 0; - b->sample_lost_task_exit = 0; + b->cpu = i; + INIT_WORK(&b->work, wq_sync_buffer, b); } return 0; + fail: __free_cpu_buffers(i); return -ENOMEM; @@ -79,6 +80,40 @@ } +void start_cpu_work(void) +{ + int i; + + work_enabled = 1; + + for_each_online_cpu(i) { + struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + + /* + * Spread the work by 1 jiffy per cpu so they dont all + * fire at once. + */ + schedule_delayed_work_on(i, &b->work, DEFAULT_TIMER_EXPIRE + i); + } +} + + +void end_cpu_work(void) +{ + int i; + + work_enabled = 0; + + for_each_online_cpu(i) { + struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + + cancel_delayed_work(&b->work); + } + + flush_scheduled_work(); +} + + /* compute number of available slots in cpu_buffer queue */ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b) { @@ -145,21 +180,9 @@ /* notice a task switch */ if (cpu_buf->last_task != task) { cpu_buf->last_task = task; - if (!(task->flags & PF_EXITING)) { - cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL; - cpu_buf->buffer[cpu_buf->head_pos].event = (unsigned long)task; - increment_head(cpu_buf); - } - } - - /* If the task is exiting it's not safe to take a sample - * as the task_struct is about to be freed. We can't just - * notify at release_task() time because of CLONE_DETACHED - * tasks that release_task() themselves. - */ - if (task->flags & PF_EXITING) { - cpu_buf->sample_lost_task_exit++; - return; + cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL; + cpu_buf->buffer[cpu_buf->head_pos].event = (unsigned long)task; + increment_head(cpu_buf); } cpu_buf->buffer[cpu_buf->head_pos].eip = eip; @@ -177,4 +200,26 @@ */ cpu_buf->last_is_kernel = -1; cpu_buf->last_task = NULL; +} + + +/* + * This serves to avoid cpu buffer overflow, and makes sure + * the task mortuary progresses + * + * By using schedule_delayed_work_on and then schedule_delayed_work + * we guarantee this will stay on the correct cpu + */ +static void wq_sync_buffer(void * data) +{ + struct oprofile_cpu_buffer * b = (struct oprofile_cpu_buffer *)data; + if (b->cpu != smp_processor_id()) { + printk("WQ on CPU%d, prefer CPU%d\n", + smp_processor_id(), b->cpu); + } + sync_buffer(b->cpu); + + /* don't re-add the work if we're shutting down */ + if (work_enabled) + schedule_delayed_work(&b->work, DEFAULT_TIMER_EXPIRE); } diff -Nru a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h --- a/drivers/oprofile/cpu_buffer.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/oprofile/cpu_buffer.h 2004-10-18 14:57:04 -07:00 @@ -12,15 +12,17 @@ #include #include +#include #include struct task_struct; -/* allocate a sample buffer for each CPU */ int alloc_cpu_buffers(void); - void free_cpu_buffers(void); +void start_cpu_work(void); +void end_cpu_work(void); + /* CPU buffer is composed of such entries (which are * also used for context switch notes) */ @@ -38,11 +40,12 @@ struct op_sample * buffer; unsigned long sample_received; unsigned long sample_lost_overflow; - unsigned long sample_lost_task_exit; + int cpu; + struct work_struct work; } ____cacheline_aligned; extern struct oprofile_cpu_buffer cpu_buffer[]; -void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf); +void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); #endif /* OPROFILE_CPU_BUFFER_H */ diff -Nru a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c --- a/drivers/oprofile/oprofile_stats.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/oprofile/oprofile_stats.c 2004-10-18 14:56:48 -07:00 @@ -22,14 +22,10 @@ struct oprofile_cpu_buffer * cpu_buf; int i; - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_possible(i)) - continue; - + for_each_cpu(i) { cpu_buf = &cpu_buffer[i]; cpu_buf->sample_received = 0; cpu_buf->sample_lost_overflow = 0; - cpu_buf->sample_lost_task_exit = 0; } atomic_set(&oprofile_stats.sample_lost_no_mm, 0); @@ -50,10 +46,7 @@ if (!dir) return; - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_possible(i)) - continue; - + for_each_cpu(i) { cpu_buf = &cpu_buffer[i]; snprintf(buf, 10, "cpu%d", i); cpudir = oprofilefs_mkdir(sb, dir, buf); @@ -66,8 +59,6 @@ &cpu_buf->sample_received); oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_overflow", &cpu_buf->sample_lost_overflow); - oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_task_exit", - &cpu_buf->sample_lost_task_exit); } oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm", diff -Nru a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c --- a/drivers/oprofile/timer_int.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/oprofile/timer_int.c 2004-10-18 14:56:28 -07:00 @@ -19,7 +19,7 @@ { struct pt_regs * regs = (struct pt_regs *)data; int cpu = smp_processor_id(); - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); oprofile_add_sample(eip, !user_mode(regs), 0, cpu); return 0; diff -Nru a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c --- a/drivers/parisc/lasi.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/parisc/lasi.c 2004-10-18 14:56:48 -07:00 @@ -11,7 +11,7 @@ * (at your option) any later version. * * by Alan Cox and - * Alex deVries + * Alex deVries */ #include diff -Nru a/drivers/parisc/superio.c b/drivers/parisc/superio.c --- a/drivers/parisc/superio.c 2004-10-18 14:56:34 -07:00 +++ b/drivers/parisc/superio.c 2004-10-18 14:56:34 -07:00 @@ -8,7 +8,7 @@ * (C) Copyright 2000 Linuxcare, Inc. * (C) Copyright 2000 Linuxcare Canada, Inc. * (C) Copyright 2000 Martin K. Petersen - * (C) Copyright 2000 Alex deVries + * (C) Copyright 2000 Alex deVries * (C) Copyright 2001 John Marvin * (C) Copyright 2003 Grant Grundler * @@ -484,6 +484,7 @@ pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci); /* Because of a defect in Super I/O, all reads of the PCI DMA status * registers, IDE status register and the IDE select register need to be diff -Nru a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c --- a/drivers/parport/parport_pc.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/parport/parport_pc.c 2004-10-18 14:57:04 -07:00 @@ -1194,7 +1194,7 @@ #ifdef CONFIG_PARPORT_PC_SUPERIO /* Super-IO chipset detection, Winbond, SMSC */ -static void __devinit show_parconfig_smsc37c669(int io, int key) +static int __devinit show_parconfig_smsc37c669(int io, int key) { int cr1,cr4,cra,cr23,cr26,cr27,i=0; static const char *modes[]={ "SPP and Bidirectional (PS/2)", @@ -1261,17 +1261,26 @@ superios[i].io = 0x278; superios[i].irq = 5; } + if (io != superios[i].io) { + /* how many bytes? */ + if (!request_region(superios[i].io, 3, "smsc parport")) { + superios[i].io = 0; + return 0; + } + } d=(cr26 &0x0f); if((d==1) || (d==3)) superios[i].dma= d; else superios[i].dma= PARPORT_DMA_NONE; + return 1; } } + return 0; } -static void __devinit show_parconfig_winbond(int io, int key) +static int __devinit show_parconfig_winbond(int io, int key) { int cr30,cr60,cr61,cr70,cr74,crf0,i=0; static const char *modes[] = { @@ -1327,14 +1336,23 @@ printk(KERN_INFO "Super-IO: too many chips!\n"); else { superios[i].io = (cr60<<8)|cr61; + if (io != superios[i].io) { + /* how many bytes? */ + if (!request_region(superios[i].io, 3, "winbond parport")) { + superios[i].io = 0; + return 0; + } + } superios[i].irq = cr70&0x0f; superios[i].dma = (((cr74 & 0x07) > 3) ? PARPORT_DMA_NONE : (cr74 & 0x07)); + return 1; } } + return 0; } -static void __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid) +static int __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid) { const char *type = "unknown"; int id,progif=2; @@ -1342,7 +1360,7 @@ if (devid == devrev) /* simple heuristics, we happened to read some non-winbond register */ - return; + return 0; id=(devid<<8) | devrev; @@ -1367,19 +1385,20 @@ efer, key, devid, devrev, oldid, type); if (progif == 2) - show_parconfig_winbond(efer,key); + return show_parconfig_winbond(efer,key); + return 0; } -static void __devinit decode_smsc(int efer, int key, int devid, int devrev) +static int __devinit decode_smsc(int efer, int key, int devid, int devrev) { const char *type = "unknown"; - void (*func)(int io, int key); + int (*func)(int io, int key); int id; if (devid == devrev) /* simple heuristics, we happened to read some non-smsc register */ - return; + return 0; func=NULL; id=(devid<<8) | devrev; @@ -1395,7 +1414,8 @@ efer, key, devid, devrev, type); if (func) - func(efer,key); + return func(efer,key); + return 0; } @@ -1403,6 +1423,9 @@ { int devid,devrev,oldid,x_devid,x_devrev,x_oldid; + if (!request_region(io, 3, __FUNCTION__)) + return; + /* First probe without key */ outb(0x20,io); x_devid=inb(io+1); @@ -1423,15 +1446,21 @@ outb(0xaa,io); /* Magic Seal */ if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) - return; /* protection against false positives */ + goto out; /* protection against false positives */ - decode_winbond(io,key,devid,devrev,oldid); + if (decode_winbond(io,key,devid,devrev,oldid)); + return; +out: + release_region(io, 3); } static void __devinit winbond_check2(int io,int key) { int devid,devrev,oldid,x_devid,x_devrev,x_oldid; + if (!request_region(io, 3, __FUNCTION__)) + return; + /* First probe without the key */ outb(0x20,io+2); x_devid=inb(io+2); @@ -1451,15 +1480,21 @@ outb(0xaa,io); /* Magic Seal */ if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) - return; /* protection against false positives */ + goto out; /* protection against false positives */ - decode_winbond(io,key,devid,devrev,oldid); + if (decode_winbond(io,key,devid,devrev,oldid)) + return; +out: + release_region(io, 3); } static void __devinit smsc_check(int io, int key) { int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev; + if (!request_region(io, 3, __FUNCTION__)) + return; + /* First probe without the key */ outb(0x0d,io); x_oldid=inb(io+1); @@ -1485,9 +1520,12 @@ if ((x_id == id) && (x_oldrev == oldrev) && (x_oldid == oldid) && (x_rev == rev)) - return; /* protection against false positives */ + goto out; /* protection against false positives */ - decode_smsc(io,key,oldid,oldrev); + if (decode_smsc(io,key,oldid,oldrev)) + return; +out: + release_region(io, 3); } @@ -2636,6 +2674,10 @@ netmos_9805, netmos_9815, netmos_9855, + netmos_9735, + netmos_9835, + netmos_9755, + netmos_9715 }; @@ -2709,6 +2751,10 @@ /* netmos_9805 */ { 1, { { 0, -1 }, } }, /* untested */ /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */ /* netmos_9855 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */ + /* netmos_9735 */ { 1, { { 2, 3 }, } }, /* untested */ + /* netmos_9835 */ { 1, { { 2, 3 }, } }, /* untested */ + /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */ + /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */ }; static struct pci_device_id parport_pc_pci_tbl[] = { @@ -2786,6 +2832,14 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl); diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile --- a/drivers/pci/Makefile 2004-10-18 14:57:03 -07:00 +++ b/drivers/pci/Makefile 2004-10-18 14:57:03 -07:00 @@ -35,7 +35,7 @@ obj-y += syscall.o endif -host-progs := gen-devlist +hostprogs-y := gen-devlist # Dependencies on generated files need to be listed explicitly $(obj)/names.o: $(obj)/devlist.h $(obj)/classlist.h diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig --- a/drivers/pci/hotplug/Kconfig 2004-10-18 14:57:20 -07:00 +++ b/drivers/pci/hotplug/Kconfig 2004-10-18 14:57:20 -07:00 @@ -88,6 +88,18 @@ When in doubt, say N. +config HOTPLUG_PCI_ACPI_IBM + tristate "ACPI PCI Hotplug driver IBM extensions" + depends on HOTPLUG_PCI_ACPI + help + Say Y here if you have an IBM system that supports PCI Hotplug using + ACPI. + + To compile this driver as a module, choose M here: the + module will be called acpiphp_ibm. + + When in doubt, say N. + config HOTPLUG_PCI_CPCI bool "CompactPCI Hotplug driver" depends on HOTPLUG_PCI diff -Nru a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile --- a/drivers/pci/hotplug/Makefile 2004-10-18 14:56:48 -07:00 +++ b/drivers/pci/hotplug/Makefile 2004-10-18 14:56:48 -07:00 @@ -7,6 +7,7 @@ obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o diff -Nru a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h --- a/drivers/pci/hotplug/acpiphp.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/pci/hotplug/acpiphp.h 2004-10-18 14:57:04 -07:00 @@ -171,6 +171,18 @@ struct pci_resource *bus_head; }; +/** + * struct acpiphp_attention_info - device specific attention registration + * + * ACPI has no generic method of setting/getting attention status + * this allows for device specific driver registration + */ +struct acpiphp_attention_info +{ + int (*set_attn)(struct hotplug_slot *slot, u8 status); + int (*get_attn)(struct hotplug_slot *slot, u8 *status); + struct module *owner; +}; /* PCI bus bridge HID */ #define ACPI_PCI_HOST_HID "PNP0A03" @@ -211,6 +223,10 @@ #define FUNC_HAS_PS3 (0x00000080) /* function prototypes */ + +/* acpiphp_core.c */ +extern int acpiphp_register_attention(struct acpiphp_attention_info*info); +extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info); /* acpiphp_glue.c */ extern int acpiphp_glue_init (void); diff -Nru a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c --- a/drivers/pci/hotplug/acpiphp_core.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/pci/hotplug/acpiphp_core.c 2004-10-18 14:56:33 -07:00 @@ -51,6 +51,7 @@ /* local variables */ static int num_slots; +static struct acpiphp_attention_info *attention_info; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " @@ -60,12 +61,17 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -module_param(debug, bool, 644); +module_param(debug, bool, 0644); + +/* export the attention callback registration methods */ +EXPORT_SYMBOL_GPL(acpiphp_register_attention); +EXPORT_SYMBOL_GPL(acpiphp_unregister_attention); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); static int set_attention_status (struct hotplug_slot *slot, u8 value); static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_address (struct hotplug_slot *slot, u32 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); @@ -76,11 +82,54 @@ .disable_slot = disable_slot, .set_attention_status = set_attention_status, .get_power_status = get_power_status, + .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_status, .get_address = get_address, }; + +/** + * acpiphp_register_attention - set attention LED callback + * @info: must be completely filled with LED callbacks + * + * Description: this is used to register a hardware specific ACPI + * driver that manipulates the attention LED. All the fields in + * info must be set. + **/ +int acpiphp_register_attention(struct acpiphp_attention_info *info) +{ + int retval = -EINVAL; + + if (info && info->owner && info->set_attn && + info->get_attn && !attention_info) { + retval = 0; + attention_info = info; + } + return retval; +} + + +/** + * acpiphp_unregister_attention - unset attention LED callback + * @info: must match the pointer used to register + * + * Description: this is used to un-register a hardware specific acpi + * driver that manipulates the attention LED. The pointer to the + * info struct must be the same as the one used to set it. + **/ +int acpiphp_unregister_attention(struct acpiphp_attention_info *info) +{ + int retval = -EINVAL; + + if (info && attention_info == info) { + attention_info = NULL; + retval = 0; + } + return retval; +} + + /** * enable_slot - power on and enable a slot * @hotplug_slot: slot to enable @@ -117,33 +166,29 @@ } -/** - * set_attention_status - set attention LED - * - * TBD: - * ACPI doesn't have known method to manipulate - * attention status LED. - * - */ -static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) -{ - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - switch (status) { - case 0: - /* FIXME turn light off */ - hotplug_slot->info->attention_status = 0; - break; - - case 1: - default: - /* FIXME turn light on */ - hotplug_slot->info->attention_status = 1; - break; - } - - return 0; -} + /** + * set_attention_status - set attention LED + * @hotplug_slot: slot to set attention LED on + * @status: value to set attention LED to (0 or 1) + * + * attention status LED, so we use a callback that + * was registered with us. This allows hardware specific + * ACPI implementations to blink the light for us. + **/ + static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) + { + int retval = -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + if (attention_info && try_module_get(attention_info->owner)) { + retval = attention_info->set_attn(hotplug_slot, status); + module_put(attention_info->owner); + } else + attention_info = NULL; + return retval; + } + /** * get_power_status - get power status of a slot @@ -165,6 +210,32 @@ return 0; } + + /** + * get_attention_status - get attention LED status + * @hotplug_slot: slot to get status from + * @value: returns with value of attention LED + * + * ACPI doesn't have known method to determine the state + * of the attention status LED, so we use a callback that + * was registered with us. This allows hardware specific + * ACPI implementations to determine its state + **/ +static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) +{ + int retval = -EINVAL; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + if (attention_info && try_module_get(attention_info->owner)) { + retval = attention_info->get_attn(hotplug_slot, value); + module_put(attention_info->owner); + } else + attention_info = NULL; + return retval; +} + + /** * get_latch_status - get latch status of a slot * @hotplug_slot: slot to get status @@ -307,7 +378,7 @@ slot->acpi_slot = get_slot_from_id(i); slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); - slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot); + slot->hotplug_slot->info->attention_status = 0; slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; diff -Nru a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c --- a/drivers/pci/hotplug/acpiphp_glue.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/pci/hotplug/acpiphp_glue.c 2004-10-18 14:56:28 -07:00 @@ -1302,20 +1302,6 @@ /* - * attention LED ON: 1 - * OFF: 0 - * - * TBD - * no direct attention led status information via ACPI - * - */ -u8 acpiphp_get_attention_status(struct acpiphp_slot *slot) -{ - return 0; -} - - -/* * latch closed: 1 * latch open: 0 */ diff -Nru a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pci/hotplug/acpiphp_ibm.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,474 @@ +/* + * ACPI PCI Hot Plug IBM Extension + * + * Copyright (C) 2004 Vernon Mauery + * Copyright (C) 2004 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acpiphp.h" +#include "pci_hotplug.h" + +#define DRIVER_VERSION "1.0.1" +#define DRIVER_AUTHOR "Irene Zubarev , Vernon Mauery " +#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver IBM extension" + +static int debug; + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); +module_param(debug, bool, 644); +MODULE_PARM_DESC(debug, " Debugging mode enabled or not"); +#define MY_NAME "acpiphp_ibm" + +#undef dbg +#define dbg(format, arg...) \ +do { \ + if (debug) \ + printk(KERN_DEBUG "%s: " format, \ + MY_NAME , ## arg); \ +} while (0) + +#define FOUND_APCI 0x61504349 +/* these are the names for the IBM ACPI pseudo-device */ +#define IBM_HARDWARE_ID1 "IBM37D0" +#define IBM_HARDWARE_ID2 "IBM37D4" + +/* union apci_descriptor - allows access to the + * various device descriptors that are embedded in the + * aPCI table + */ +union apci_descriptor { + struct { + char sig[4]; + u8 len; + } header; + struct { + u8 type; + u8 len; + u16 slot_id; + u8 bus_id; + u8 dev_num; + u8 slot_num; + u8 slot_attr[2]; + u8 attn; + u8 status[2]; + u8 sun; + } slot; + struct { + u8 type; + u8 len; + } generic; +}; + +/* struct notification - keeps info about the device + * that cause the ACPI notification event + */ +struct notification { + struct acpi_device *device; + u8 event; +}; + +static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status); +static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status); +static void ibm_handle_events(acpi_handle handle, u32 event, void *context); +static int ibm_get_table_from_acpi(char **bufp); +static ssize_t ibm_read_apci_table(struct kobject *kobj, + char *buffer, loff_t pos, size_t size); +static acpi_status __init ibm_find_acpi_device(acpi_handle handle, + u32 lvl, void *context, void **rv); +static int __init ibm_acpiphp_init(void); +static void __exit ibm_acpiphp_exit(void); + +static acpi_handle ibm_acpi_handle; +static struct notification ibm_note; +static struct bin_attribute ibm_apci_table_attr = { + .attr = { + .name = "apci_table", + .owner = THIS_MODULE, + .mode = S_IRUGO, + }, + .read = ibm_read_apci_table, + .write = NULL, +}; +static struct acpiphp_attention_info ibm_attention_info = +{ + .set_attn = ibm_set_attention_status, + .get_attn = ibm_get_attention_status, + .owner = THIS_MODULE, +}; + + +/** + * ibm_set_attention_status - callback method to set the attention LED + * @slot: the hotplug_slot to work with + * @status: what to set the LED to (0 or 1) + * + * Description: this method is registered with the acpiphp module as a + * callback to do the device specific task of setting the LED status + **/ +static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status) +{ + int retval = 0; + union acpi_object args[2]; + struct acpi_object_list params = { .pointer = args, .count = 2 }; + acpi_status stat; + unsigned long rc = 0; + struct acpiphp_slot *acpi_slot; + + acpi_slot = ((struct slot *)(slot->private))->acpi_slot; + + dbg("%s: set slot %d attention status to %d\n", __FUNCTION__, + acpi_slot->sun, (status ? 1 : 0)); + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = acpi_slot->sun; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = (status) ? 1 : 0; + + stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", ¶ms, &rc); + if (ACPI_FAILURE(stat)) { + retval = -ENODEV; + err("APLS evaluation failed: 0x%08x\n", stat); + } else if (!rc) { + retval = -ERANGE; + err("APLS method failed: 0x%08lx\n", rc); + } + return retval; +} + +/** + * ibm_get_attention_status - callback method to get attention LED status + * @slot: the hotplug_slot to work with + * @status: returns what the LED is set to (0 or 1) + * + * Description: this method is registered with the acpiphp module as a + * callback to do the device specific task of getting the LED status + * + * Because there is no direct method of getting the LED status directly + * from an ACPI call, we read the aPCI table and parse out our + * slot descriptor to read the status from that. + **/ +static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status) +{ + int retval = -EINVAL, ind = 0, size; + char *table = NULL; + struct acpiphp_slot *acpi_slot; + union apci_descriptor *des; + + acpi_slot = ((struct slot *)(slot->private))->acpi_slot; + + size = ibm_get_table_from_acpi(&table); + if (size <= 0 || !table) + goto get_attn_done; + // read the header + des = (union apci_descriptor *)&table[ind]; + if (memcmp(des->header.sig, "aPCI", 4) != 0) + goto get_attn_done; + des = (union apci_descriptor *)&table[ind += des->header.len]; + while (ind < size && (des->generic.type != 0x82 || + des->slot.slot_id != acpi_slot->sun)) + des = (union apci_descriptor *)&table[ind += des->generic.len]; + if (ind < size && des->slot.slot_id == acpi_slot->sun) { + retval = 0; + if (des->slot.attn & 0xa0 || des->slot.status[1] & 0x08) + *status = 1; + else + *status = 0; + } + + dbg("%s: get slot %d attention status is %d retval=%x\n", + __FUNCTION__, acpi_slot->sun, *status, retval); + +get_attn_done: + kfree(table); + return retval; +} + +/** + * ibm_handle_events - listens for ACPI events for the IBM37D0 device + * @handle: an ACPI handle to the device that caused the event + * @event: the event info (device specific) + * @context: passed context (our notification struct) + * + * Description: this method is registered as a callback with the ACPI + * subsystem it is called when this device has an event to notify the OS of + * + * The events actually come from the device as two events that get + * synthesized into one event with data by this function. The event + * ID comes first and then the slot number that caused it. We report + * this as one event to the OS. + * + * From section 5.6.2.2 of the ACPI 2.0 spec, I understand that the OSPM will + * only re-enable the interrupt that causes this event AFTER this method + * has returned, thereby enforcing serial access for the notification struct. + **/ +static void ibm_handle_events(acpi_handle handle, u32 event, void *context) +{ + u8 detail = event & 0x0f; + u8 subevent = event & 0xf0; + struct notification *note = context; + + dbg("%s: Received notification %02x\n", __FUNCTION__, event); + + if (subevent == 0x80) { + dbg("%s: generationg bus event\n", __FUNCTION__); + acpi_bus_generate_event(note->device, note->event, detail); + } else + note->event = event; +} + +/** + * ibm_get_table_from_acpi - reads the APLS buffer from ACPI + * @bufp: address to pointer to allocate for the table + * + * Description: this method reads the APLS buffer in from ACPI and + * stores the "stripped" table into a single buffer + * it allocates and passes the address back in bufp + * + * If NULL is passed in as buffer, this method only calculates + * the size of the table and returns that without filling + * in the buffer + * + * returns < 0 on error or the size of the table on success + **/ +static int ibm_get_table_from_acpi(char **bufp) +{ + union acpi_object *package; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + char *lbuf = NULL; + int i, size = -EIO; + + status = acpi_evaluate_object(ibm_acpi_handle, "APCI", NULL, &buffer); + if (ACPI_FAILURE(status)) { + err("%s: APCI evaluation failed\n", __FUNCTION__); + return -ENODEV; + } + + package = (union acpi_object *) buffer.pointer; + if(!(package) || + (package->type != ACPI_TYPE_PACKAGE) || + !(package->package.elements)) { + err("%s: Invalid APCI object\n", __FUNCTION__); + goto read_table_done; + } + + for(size = 0, i = 0; i < package->package.count; i++) { + if (package->package.elements[i].type != ACPI_TYPE_BUFFER) { + err("%s: Invalid APCI element %d\n", __FUNCTION__, i); + goto read_table_done; + } + size += package->package.elements[i].buffer.length; + } + + if (bufp == NULL) + goto read_table_done; + + lbuf = kmalloc(size, GFP_KERNEL); + dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n", + __FUNCTION__, package->package.count, size, lbuf); + + if (lbuf) { + *bufp = lbuf; + memset(lbuf, 0, size); + } else { + size = -ENOMEM; + goto read_table_done; + } + + size = 0; + for (i=0; ipackage.count; i++) { + memcpy(&lbuf[size], + package->package.elements[i].buffer.pointer, + package->package.elements[i].buffer.length); + size += package->package.elements[i].buffer.length; + } + +read_table_done: + kfree(buffer.pointer); + return size; +} + +/** + * ibm_read_apci_table - callback for the sysfs apci_table file + * @kobj: the kobject this binary attribute is a part of + * @buffer: the kernel space buffer to fill + * @pos: the offset into the file + * @size: the number of bytes requested + * + * Description: gets registered with sysfs as the reader callback + * to be executed when /sys/bus/pci/slots/apci_table gets read + * + * Since we don't get notified on open and close for this file, + * things get really tricky here... + * our solution is to only allow reading the table in all at once + **/ +static ssize_t ibm_read_apci_table(struct kobject *kobj, + char *buffer, loff_t pos, size_t size) +{ + int bytes_read = -EINVAL; + char *table = NULL; + + dbg("%s: pos = %d, size = %zd\n", __FUNCTION__, (int)pos, size); + + if (pos == 0) { + bytes_read = ibm_get_table_from_acpi(&table); + if (bytes_read > 0 && bytes_read <= size) + memcpy(buffer, table, bytes_read); + kfree(table); + } + return bytes_read; +} + +/** + * ibm_find_acpi_device - callback to find our ACPI device + * @handle: the ACPI handle of the device we are inspecting + * @lvl: depth into the namespace tree + * @context: a pointer to our handle to fill when we find the device + * @rv: a return value to fill if desired + * + * Description: used as a callback when calling acpi_walk_namespace + * to find our device. When this method returns non-zero + * acpi_walk_namespace quits its search and returns our value + **/ +static acpi_status __init ibm_find_acpi_device(acpi_handle handle, + u32 lvl, void *context, void **rv) +{ + acpi_handle *phandle = (acpi_handle *)context; + acpi_status status; + struct acpi_device_info info; + struct acpi_buffer info_buffer = { + .length = sizeof(struct acpi_device_info), + .pointer = &info, + }; + + status = acpi_get_object_info(handle, &info_buffer); + if (ACPI_FAILURE(status)) { + err("%s: Failed to get device information", __FUNCTION__); + return 0; + } + info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0'; + + if(info.current_status && (info.valid & ACPI_VALID_HID) && + (!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) || + !strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) { + dbg("found hardware: %s, handle: %p\n", info.hardware_id.value, + handle); + *phandle = handle; + /* returning non-zero causes the search to stop + * and returns this value to the caller of + * acpi_walk_namespace, but it also causes some warnings + * in the acpi debug code to print... + */ + return FOUND_APCI; + } + return 0; +} + +static int __init ibm_acpiphp_init(void) +{ + int retval = 0; + acpi_status status; + struct acpi_device *device; + struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; + + dbg("%s\n", __FUNCTION__); + + if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, ibm_find_acpi_device, + &ibm_acpi_handle, NULL) != FOUND_APCI) { + err("%s: acpi_walk_namespace failed\n", __FUNCTION__); + retval = -ENODEV; + goto init_return; + } + dbg("%s: found IBM aPCI device\n", __FUNCTION__); + if (acpi_bus_get_device(ibm_acpi_handle, &device)) { + err("%s: acpi_bus_get_device failed\n", __FUNCTION__); + retval = -ENODEV; + goto init_return; + } + if (acpiphp_register_attention(&ibm_attention_info)) { + retval = -ENODEV; + goto init_return; + } + + ibm_note.device = device; + status = acpi_install_notify_handler( + ibm_acpi_handle, + ACPI_DEVICE_NOTIFY, + ibm_handle_events, + &ibm_note); + if (ACPI_FAILURE(status)) { + err("%s: Failed to register notification handler\n", + __FUNCTION__); + retval = -EBUSY; + goto init_cleanup; + } + + ibm_apci_table_attr.size = ibm_get_table_from_acpi(NULL); + retval = sysfs_create_bin_file(sysdir, &ibm_apci_table_attr); + + return retval; + +init_cleanup: + acpiphp_unregister_attention(&ibm_attention_info); +init_return: + return retval; +} + +static void __exit ibm_acpiphp_exit(void) +{ + acpi_status status; + struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; + + dbg("%s\n", __FUNCTION__); + + if (acpiphp_unregister_attention(&ibm_attention_info)) + err("%s: attention info deregistration failed", __FUNCTION__); + + status = acpi_remove_notify_handler( + ibm_acpi_handle, + ACPI_DEVICE_NOTIFY, + ibm_handle_events); + if (ACPI_FAILURE(status)) + err("%s: Notification handler removal failed\n", + __FUNCTION__); + // remove the /sys entries + if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr)) + err("%s: removal of sysfs file apci_table failed\n", + __FUNCTION__); +} + +module_init(ibm_acpiphp_init); +module_exit(ibm_acpiphp_exit); diff -Nru a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c --- a/drivers/pci/hotplug/cpci_hotplug_core.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/pci/hotplug/cpci_hotplug_core.c 2004-10-18 14:56:29 -07:00 @@ -33,6 +33,7 @@ #include #include #include +#include #include "pci_hotplug.h" #include "cpci_hotplug.h" @@ -513,11 +514,10 @@ break; while(controller->ops->query_enum()) { rc = check_slots(); - if(rc > 0) { + if (rc > 0) /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { + msleep(500); + else if (rc < 0) { dbg("%s - error checking slots", __FUNCTION__); thread_finished = 1; break; @@ -568,11 +568,10 @@ while(controller->ops->query_enum()) { rc = check_slots(); - if(rc > 0) { + if(rc > 0) /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { + msleep(500); + else if (rc < 0) { dbg("%s - error checking slots", __FUNCTION__); thread_finished = 1; break; @@ -595,8 +594,7 @@ } } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + msleep(100); } dbg("poll thread signals exit"); up(&thread_exit); diff -Nru a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c --- a/drivers/pci/hotplug/cpcihp_zt5550.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/pci/hotplug/cpcihp_zt5550.c 2004-10-18 14:56:33 -07:00 @@ -298,7 +298,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, 644); +module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -module_param(poll, bool, 644); +module_param(poll, bool, 0644); MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); diff -Nru a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c --- a/drivers/pci/hotplug/cpqphp_core.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/pci/hotplug/cpqphp_core.c 2004-10-18 14:55:46 -07:00 @@ -69,10 +69,10 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(power_mode, bool, 644); +module_param(power_mode, bool, 0644); MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); -module_param(debug, bool, 644); +module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); #define CPQHPC_MODULE_MINOR 208 diff -Nru a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h --- a/drivers/pci/hotplug/ibmphp.h 2004-10-18 14:55:55 -07:00 +++ b/drivers/pci/hotplug/ibmphp.h 2004-10-18 14:55:55 -07:00 @@ -759,11 +759,5 @@ extern int ibmphp_unconfigure_card (struct slot **, int); extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; -static inline void long_delay (int delay) -{ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (delay); -} - #endif //__IBMPHP_H diff -Nru a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c --- a/drivers/pci/hotplug/ibmphp_core.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/pci/hotplug/ibmphp_core.c 2004-10-18 14:57:05 -07:00 @@ -190,7 +190,7 @@ err ("command not completed successfully in power_on\n"); return -EIO; } - long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ + msleep(3000); /* For ServeRAID cards, and some 66 PCI */ return 0; } @@ -913,7 +913,7 @@ } /* This is for x440, once Brandon fixes the firmware, will not need this delay */ - long_delay (1 * HZ); + msleep(1000); debug ("%s -Exit\n", __FUNCTION__); return 0; } diff -Nru a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c --- a/drivers/pci/hotplug/ibmphp_hpc.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/pci/hotplug/ibmphp_hpc.c 2004-10-18 14:56:27 -07:00 @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -205,7 +206,7 @@ // READ - step 4 : wait until start operation bit clears i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -221,7 +222,7 @@ // READ - step 5 : read I2C status register i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -316,7 +317,7 @@ // WRITE - step 4 : wait until start operation bit clears i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -333,7 +334,7 @@ // WRITE - step 5 : read I2C status register i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -748,7 +749,7 @@ done = TRUE; } if (!done) { - long_delay (1 * HZ); + msleep(1000); if (timeout < 1) { done = TRUE; err ("%s - Error command complete timeout\n", __FUNCTION__); @@ -891,7 +892,7 @@ case POLL_SLEEP: /* don't sleep with a lock on the hardware */ up (&semOperations); - long_delay (POLL_INTERVAL_SEC * HZ); + msleep(POLL_INTERVAL_SEC * 1000); if (ibmphp_shutdown) break; @@ -908,8 +909,7 @@ /* give up the harware semaphore */ up (&semOperations); /* sleep for a short time just for good measure */ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (HZ/10); + msleep(100); } up (&sem_exit); debug ("%s - Exit\n", __FUNCTION__); @@ -974,7 +974,7 @@ if (SLOT_PWRGD (pslot->status)) { // power goes on and off after closing latch // check again to make sure power is still ON - long_delay (1 * HZ); + msleep(1000); rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); if (SLOT_PWRGD (status)) update = TRUE; @@ -1147,7 +1147,7 @@ if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) done = TRUE; if (!done) { - long_delay (1 * HZ); + msleep(1000); if (timeout < 1) { done = TRUE; err ("HPCreadslot - Error ctlr timeout\n"); diff -Nru a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c --- a/drivers/pci/hotplug/pci_hotplug_core.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/pci/hotplug/pci_hotplug_core.c 2004-10-18 14:56:49 -07:00 @@ -701,7 +701,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, 644); +module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys); diff -Nru a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c --- a/drivers/pci/hotplug/pciehp_core.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/pci/hotplug/pciehp_core.c 2004-10-18 14:55:53 -07:00 @@ -57,9 +57,9 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(pciehp_debug, bool, 644); -module_param(pciehp_poll_mode, bool, 644); -module_param(pciehp_poll_time, int, 644); +module_param(pciehp_debug, bool, 0644); +module_param(pciehp_poll_mode, bool, 0644); +module_param(pciehp_poll_time, int, 0644); MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); diff -Nru a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c --- a/drivers/pci/hotplug/pciehp_hpc.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/pci/hotplug/pciehp_hpc.c 2004-10-18 14:56:33 -07:00 @@ -1017,7 +1017,7 @@ return IRQ_HANDLED; } -static int hpc_get_max_lnk_speed (struct slot *slot, enum pcie_link_speed *value) +static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pcie_link_speed lnk_speed; @@ -1120,7 +1120,7 @@ return retval; } -static int hpc_get_cur_lnk_speed (struct slot *slot, enum pcie_link_speed *value) +static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; diff -Nru a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c --- a/drivers/pci/hotplug/pcihp_skeleton.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/pci/hotplug/pcihp_skeleton.c 2004-10-18 14:56:32 -07:00 @@ -70,7 +70,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, 644); +module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); static int enable_slot (struct hotplug_slot *slot); diff -Nru a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c --- a/drivers/pci/hotplug/rpaphp_core.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/pci/hotplug/rpaphp_core.c 2004-10-18 14:57:04 -07:00 @@ -54,8 +54,6 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -void eeh_register_disable_func(int (*)(struct pci_dev *)); - module_param(debug, bool, 0644); static int enable_slot(struct hotplug_slot *slot); @@ -407,18 +405,12 @@ { info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - /* let EEH know they can use hotplug */ - eeh_register_disable_func(&rpaphp_disable_slot); - /* read all the PRA info from the system */ return init_rpa(); } static void __exit rpaphp_exit(void) { - /* let EEH know we are going away */ - eeh_register_disable_func(NULL); - cleanup_slots(); } @@ -457,7 +449,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) { - int retval; + int retval = -EINVAL; struct slot *slot = (struct slot *)hotplug_slot->private; dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name); diff -Nru a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c --- a/drivers/pci/hotplug/rpaphp_pci.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/pci/hotplug/rpaphp_pci.c 2004-10-18 14:55:46 -07:00 @@ -186,7 +186,7 @@ rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus) { struct device_node *eads_first_child = dn->child; - struct pci_dev *dev; + struct pci_dev *dev = NULL; int num; dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); @@ -341,7 +341,6 @@ return rc; } - static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) { eeh_remove_device(dev); @@ -363,7 +362,7 @@ int rpaphp_unconfig_pci_adapter(struct slot *slot) { int retval = 0; - struct list_head *ln; + struct list_head *ln, *tmp; dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); if (list_empty(&slot->dev.pci_funcs)) { @@ -374,7 +373,7 @@ goto exit; } /* remove the devices from the pci core */ - list_for_each (ln, &slot->dev.pci_funcs) { + list_for_each_safe (ln, tmp, &slot->dev.pci_funcs) { struct rpaphp_pci_func *func; func = list_entry(ln, struct rpaphp_pci_func, sibling); @@ -430,10 +429,26 @@ __FUNCTION__, slot->name); goto exit_rc; } - if (init_slot_pci_funcs(slot)) { - err("%s: init_slot_pci_funcs failed\n", __FUNCTION__); + + if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { + dbg("%s CONFIGURING pci adapter in slot[%s]\n", + __FUNCTION__, slot->name); + if (rpaphp_config_pci_adapter(slot)) { + err("%s: CONFIG pci adapter failed\n", __FUNCTION__); + goto exit_rc; + } + } else if (slot->hotplug_slot->info->adapter_status == CONFIGURED) { + if (init_slot_pci_funcs(slot)) { + err("%s: init_slot_pci_funcs failed\n", __FUNCTION__); + goto exit_rc; + } + + } else { + err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", + __FUNCTION__, slot->name); goto exit_rc; } + print_slot_pci_funcs(slot); if (!list_empty(&slot->dev.pci_funcs)) { slot->state = CONFIGURED; diff -Nru a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c --- a/drivers/pci/hotplug/rpaphp_slot.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/pci/hotplug/rpaphp_slot.c 2004-10-18 14:56:32 -07:00 @@ -244,7 +244,7 @@ int rpaphp_get_power_status(struct slot *slot, u8 * value) { - int rc = 0; + int rc = 0, level; if (slot->type == EMBEDDED) { dbg("%s set to POWER_ON for EMBEDDED slot %s\n", @@ -252,10 +252,14 @@ *value = POWER_ON; } else { - rc = rtas_get_power_level(slot->power_domain, (int *) value); - if (rc) + rc = rtas_get_power_level(slot->power_domain, &level); + if (!rc) { + dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n", + __FUNCTION__, slot->name, slot->power_domain, level); + *value = level; + } else err("failed to get power-level for slot(%s), rc=0x%x\n", - slot->location, rc); + slot->location, rc); } return rc; diff -Nru a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c --- a/drivers/pci/hotplug/shpchp_core.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/pci/hotplug/shpchp_core.c 2004-10-18 14:55:53 -07:00 @@ -57,9 +57,9 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(shpchp_debug, bool, 644); -module_param(shpchp_poll_mode, bool, 644); -module_param(shpchp_poll_time, int, 644); +module_param(shpchp_debug, bool, 0644); +module_param(shpchp_poll_mode, bool, 0644); +module_param(shpchp_poll_time, int, 0644); MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds"); diff -Nru a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c --- a/drivers/pci/hotplug/shpchp_ctrl.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/pci/hotplug/shpchp_ctrl.c 2004-10-18 14:57:04 -07:00 @@ -2163,11 +2163,13 @@ u32 rc = 0; int ret = 0; unsigned int devfn; - struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate; + struct pci_bus *pci_bus; struct pci_func *func; if (!p_slot->ctrl) return 1; + + pci_bus = p_slot->ctrl->pci_dev->subordinate; /* Check to see if (latch closed, card present, power on) */ down(&p_slot->ctrl->crit_sect); diff -Nru a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c --- a/drivers/pci/hotplug/shpchp_hpc.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/pci/hotplug/shpchp_hpc.c 2004-10-18 14:56:27 -07:00 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "shpchp.h" @@ -300,8 +301,7 @@ if (!(cmd_status & 0x1)) break; /* Check every 0.1 sec for a total of 1 sec*/ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); } cmd_status = readw(php_ctlr->creg + CMD_STATUS); diff -Nru a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c --- a/drivers/pci/pci-driver.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/pci/pci-driver.c 2004-10-18 14:56:48 -07:00 @@ -299,10 +299,23 @@ { struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; + u32 dev_state; int i = 0; + /* Translate PM_SUSPEND_xx states to PCI device states */ + static u32 state_conversion[] = { + [PM_SUSPEND_ON] = 0, + [PM_SUSPEND_STANDBY] = 1, + [PM_SUSPEND_MEM] = 3, + [PM_SUSPEND_DISK] = 3, + }; + + if (state >= sizeof(state_conversion) / sizeof(state_conversion[1])) + return -EINVAL; + + dev_state = state_conversion[state]; if (drv && drv->suspend) - i = drv->suspend(pci_dev,state); + i = drv->suspend(pci_dev, dev_state); pci_save_state(pci_dev, pci_dev->saved_config_space); return i; @@ -390,10 +403,9 @@ * pci_register_driver - register a new pci driver * @drv: the driver structure to register * - * Adds the driver structure to the list of registered drivers - * Returns the number of pci devices which were claimed by the driver - * during registration. The driver remains registered even if the - * return value is zero. + * Adds the driver structure to the list of registered drivers. + * Returns a negative value on error. The driver remains registered + * even if no device was claimed during registration. */ int pci_register_driver(struct pci_driver *drv) diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/pci/pci.c 2004-10-18 14:56:27 -07:00 @@ -291,10 +291,7 @@ /* Mandatory power management transition delays */ /* see PCI PM 1.1 5.6.1 table 18 */ if(state == 3 || dev->current_state == 3) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); - } + msleep(10); else if(state == 2 || dev->current_state == 2) udelay(200); dev->current_state = state; @@ -748,7 +745,7 @@ struct pci_dev *dev = NULL; while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - pci_fixup_device(PCI_FIXUP_FINAL, dev); + pci_fixup_device(pci_fixup_final, dev); } return 0; } diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids --- a/drivers/pci/pci.ids 2004-10-18 14:56:32 -07:00 +++ b/drivers/pci/pci.ids 2004-10-18 14:56:32 -07:00 @@ -7,7 +7,7 @@ # so if you have anything to contribute, please visit the home page or # send a diff -u against the most recent pci.ids to pci-ids@ucw.cz. # -# Daily snapshot on Thu 2004-04-15 10:00:04 +# Daily snapshot on Mon 2004-07-12 10:00:27 # # Vendors, devices and subsystems. Please keep sorted. @@ -150,37 +150,58 @@ 0e11 4082 Smart Array 532 0e11 4083 Smart Array 5312 b1a4 NC7131 Gigabit Server Adapter + b203 Integrated Lights Out Controller + b204 Integrated Lights Out Processor f130 NetFlex-3/P ThunderLAN 1.0 f150 NetFlex-3/P ThunderLAN 2.3 0e55 HaSoTec GmbH # Formerly NCR 1000 LSI Logic / Symbios Logic 0001 53c810 - 1000 1000 8100S + 1000 1000 LSI53C810AE PCI to SCSI I/O Processor 0002 53c820 0003 53c825 + 1000 1000 LSI53C825AE PCI to SCSI I/O Processor (Ultra Wide) 0004 53c815 0005 53c810AP 0006 53c860 + 1000 1000 LSI53C860E PCI to Ultra SCSI I/O Processor 000a 53c1510 - 000b 53c896 + 1000 1000 LSI53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Nonintelligent mode) + 000b 53C896/897 + 1000 1000 LSI53C896/7 PCI to Dual Channel Ultra2 SCSI Multifunction Controller + 1000 1010 LSI22910 PCI to Dual Channel Ultra2 SCSI host adapter + 1000 1020 LSI21002 PCI to Dual Channel Ultra2 SCSI host adapter +# multifunction PCI card: Dual U2W SCSI, dual 10/100TX, graphics + 13e9 1000 6221L-4U 000c 53c895 + 1000 1010 LSI8951U PCI to Ultra2 SCSI host adapter + 1000 1020 LSI8952U PCI to Ultra2 SCSI host adapter + 1de1 3906 DC-390U2B SCSI adapter 1de1 3907 DC-390U2W 000d 53c885 000f 53c875 0e11 7004 Embedded Ultra Wide SCSI Controller + 1000 1000 LSI53C876/E PCI to Dual Channel SCSI Controller + 1000 1010 LSI22801 PCI to Dual Channel Ultra SCSI host adapter + 1000 1020 LSI22802 PCI to Dual Channel Ultra SCSI host adapter 1092 8760 FirePort 40 Dual SCSI Controller - 1de1 3904 DC390F Ultra Wide SCSI Controller + 1de1 3904 DC390F/U Ultra Wide SCSI Adapter 4c53 1000 CC7/CR7/CP7/VC7/VP7/VR7 mainboard 4c53 1050 CT7 mainboard - 0010 53c895 + 0010 53C1510 0e11 4040 Integrated Array Controller 0e11 4048 Integrated Array Controller + 1000 1000 53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Intelligent mode) 0012 53c895a + 1000 1000 LSI53C895A PCI to Ultra2 SCSI Controller 0013 53c875a + 1000 1000 LSI53C875A PCI to Ultra SCSI Controller 0020 53c1010 Ultra3 SCSI Adapter + 1000 1000 LSI53C1010-33 PCI to Dual Channel Ultra160 SCSI Controller 1de1 1020 DC-390U3W 0021 53c1010 66MHz Ultra3 SCSI Adapter + 1000 1000 LSI53C1000/1000R/1010R/1010-66 PCI to Ultra160 SCSI Controller 124b 1070 PMC-USCSI3 4c53 1080 CT8 mainboard 4c53 1300 P017 mezzanine (32-bit PMC) @@ -191,6 +212,7 @@ 1028 1010 LSI U320 SCSI Controller 0031 53c1030ZC PCI-X Fusion-MPT Dual Ultra320 SCSI 0032 53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI + 1000 1000 LSI53C1020/1030 PCI-X to Ultra320 SCSI Controller 0033 1030ZC_53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI 0040 53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI 1000 0033 MegaRAID SCSI 320-2XR @@ -203,8 +225,22 @@ 1000 0530 MegaRAID 530 SCSI 320-0X RAID Controller 1000 0531 MegaRAID 531 SCSI 320-4X RAID Controller 1000 0532 MegaRAID 532 SCSI 320-2X RAID Controller - 1028 0533 PowerEgde Expandable RAID Controller 4/QC - 8086 0532 Storage RAID Controller SRCU42X + 1028 0531 PowerEdge Expandable RAID Controller 4/QC + 8086 0530 MegaRAID Intel RAID Controller SRCZCRX + 8086 0532 MegaRAID Intel RAID Controller SRCU42X + 0408 MegaRAID + 1000 0001 MegaRAID SCSI 320-1E RAID Controller + 1000 0002 MegaRAID SCSI 320-2E RAID Controller + 1028 0001 Dell PowerEdge RAID Controller PERC4e/SC + 1028 0002 Dell PowerEdge RAID Controller PERC4e/DC + 1734 1065 FSC MegaRAID PCI Express ROMB + 8086 0002 MegaRAID Intel RAID Controller SRCU42E + 0409 MegaRAID + 1000 3004 MegaRAID SATA 300-4X RAID Controller + 1000 3008 MegaRAID SATA 300-8X RAID Controller + 8086 3008 MegaRAID Intel RAID Controller SRCS28X + 8086 3431 MegaRAID Intel RAID Controller Alief SROMBU42E + 8086 3499 MegaRAID Intel RAID Controller Harwich SROMBU42E 0621 FC909 Fibre Channel Adapter 0622 FC929 Fibre Channel Adapter 1000 1020 44929 O Dual Fibre Channel card @@ -228,13 +264,16 @@ 1960 MegaRAID 1000 0518 MegaRAID 518 SCSI 320-2 Controller 1000 0520 MegaRAID 520 SCSI 320-1 Controller - 1000 0522 MegaRAID 522 i4133 RAID Controller + 1000 0522 MegaRAID 522 i4 133 RAID Controller 1000 0523 MegaRAID SATA 150-6 RAID Controller 1000 4523 MegaRAID SATA 150-4 RAID Controller 1000 a520 MegaRAID ZCR SCSI 320-0 Controller 1028 0518 MegaRAID 518 DELL PERC 4/DC RAID Controller 1028 0520 MegaRAID 520 DELL PERC 4/SC RAID Controller 1028 0531 PowerEdge Expandable RAID Controller 4/QC + 1028 0533 PowerEdge Expandable RAID Controller 4/QC + 8086 0520 MegaRAID Intel RAID Controller SRCU41L + 8086 0523 MegaRAID Intel RAID Controller SRCS16 1001 Kolter Electronic 0010 PCI 1616 Measurement card with 32 digital I/O lines 0011 OPTO-PCI Opto-Isolated digital I/O board @@ -350,6 +389,8 @@ 1002 8008 Rage XL 1028 00ce PowerEdge 1400 1028 00d1 PowerEdge 2550 + 8086 3411 SDS2 Mainboard + 8086 3427 S875WP1-E mainboard 4753 Rage XC 1002 4753 Rage XC 4754 3D Rage I/II 215GT [Mach64 GT] @@ -435,10 +476,12 @@ 4e44 Radeon R300 ND [Radeon 9700 Pro] 4e45 Radeon R300 NE [Radeon 9500 Pro] 1002 0002 Radeon R300 NE [Radeon 9500 Pro] + 1681 0002 Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] # New PCI ID provided by ATI developer relations (correction to above) 4e46 RV350 NF [Radeon 9600] 4e47 Radeon R300 NG [FireGL X1] - 4e48 Radeon R350 [Radeon 9800] +# (added pro) + 4e48 Radeon R350 [Radeon 9800 Pro] # New PCI ID provided by ATI developer relations 4e49 Radeon R350 [Radeon 9800] 4e4a RV350 NJ [Radeon 9800 XT] @@ -451,10 +494,12 @@ 4e64 Radeon R300 [Radeon 9700 Pro] (Secondary) 4e65 Radeon R300 [Radeon 9500 Pro] (Secondary) 1002 0003 Radeon R300 NE [Radeon 9500 Pro] + 1681 0003 Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] (Secondary) # New PCI ID provided by ATI developer relations (correction to above) 4e66 RV350 NF [Radeon 9600] (Secondary) 4e67 Radeon R300 [FireGL X1] (Secondary) - 4e68 Radeon R350 [Radeon 9800] (Secondary) +# (added pro) + 4e68 Radeon R350 [Radeon 9800 Pro] (Secondary) # New PCI ID provided by ATI developer relations 4e69 Radeon R350 [Radeon 9800] (Secondary) 4e6a RV350 NJ [Radeon 9800 XT] (Secondary) @@ -535,6 +580,7 @@ 148c 2024 RV200 QW [Radeon 7500LE Dual Display] 148c 2025 RV200 QW [Radeon 7500 Evil Master Multi Display Edition] 148c 2036 RV200 QW [Radeon 7500 PCI Dual Display] + 174b 7146 RV200 QW [Radeon 7500 LE] 174b 7147 RV200 QW [Sapphire Radeon 7500LE] 174b 7161 Radeon RV200 QW [Radeon 7500 LE] 17af 0202 RV200 QW [Excalibur Radeon 7500LE] @@ -624,6 +670,7 @@ 5d44 RV280 [Radeon 9200 SE] (Secondary) 700f PCI Bridge [IGP 320M] 7010 PCI Bridge [IGP 340M] + 7c37 RV350 AQ [Radeon 9600 SE] cab0 AGP Bridge [IGP 320M] cab2 RS200/RS200M AGP Bridge [IGP 340M] 1003 ULSI Systems @@ -865,6 +912,8 @@ 1014 002e ServeRAID-3x 1014 022e ServeRAID-4H 0031 2 Port Serial Adapter +# AS400 iSeries PCI sync serial card + 1014 0031 2721 WAN IOA - 2 Port Sync Serial Adapter 0036 Miami 003a CPU to PCI Bridge 003c GXT250P/GXT255P Graphics Adapter @@ -924,6 +973,7 @@ 0180 Snipe chipset SCSI controller 1014 0241 iSeries 2757 DASD IOA 1014 0264 Quad Channel PCI-X U320 SCSI RAID Adapter (2780) + 1014 02BD Quad Channel PCI-X U320 DDR SCSI RAID Adapter (570F) 01a7 PCI-X to PCI-X Bridge 01bd ServeRAID Controller 1014 01be ServeRAID-4M @@ -946,7 +996,9 @@ 0266 PCI-X Dual Channel SCSI 0268 Gigabit Ethernet-SX Adapter (PCI-X) 0269 10/100/1000 Base-TX Ethernet Adapter (PCI-X) - 0302 XA-32 chipset [Summit] + 028C Citrine chipset SCSI controller + 1014 02BE Dual Channel PCI-X U320 DDR SCSI RAID Adapter (571B) + 0302 X-Architecture Bridge [Summit] ffff MPIC-2 interrupt controller 1015 LSI Logic Corp of Canada 1016 ICL Personal Systems @@ -1059,20 +1111,27 @@ 7454 AMD-8151 System Controller 7455 AMD-8151 AGP Bridge 7460 AMD-8111 PCI + 161f 3017 HDAMB 7461 AMD-8111 USB 7462 AMD-8111 Ethernet 7464 AMD-8111 USB + 161f 3017 HDAMB 7468 AMD-8111 LPC + 161f 3017 HDAMB 7469 AMD-8111 IDE + 161f 3017 HDAMB 746a AMD-8111 SMBus 2.0 746b AMD-8111 ACPI + 161f 3017 HDAMB 746d AMD-8111 AC97 Audio + 161f 3017 HDAMB 746e AMD-8111 MC97 Modem 756b AMD-8111 ACPI 1023 Trident Microsystems 0194 82C194 2000 4DWave DX 2001 4DWave NX + 122d 1400 Trident PCI288-Q3DII (NX) 2100 CyberBlade XP4m32 8400 CyberBlade/i7 1023 8400 CyberBlade i7 AGP @@ -1083,7 +1142,7 @@ 0e11 b16e CyberBlade i1 AGP 1023 8520 CyberBlade i1 AGP 8620 CyberBlade/i1 - 1014 0502 ThinkPad T30 + 1014 0502 ThinkPad R30/T30 8820 CyberBlade XPAi1 9320 TGUI 9320 9350 GUI Accelerator @@ -1179,34 +1238,32 @@ 5453 M5453 PCI AC-Link Controller Modem Device 7101 M7101 PCI PMU Power Management Controller 10b9 7101 M7101 PCI PMU Power Management Controller -1028 Dell Computer Corporation +1028 Dell 0001 PowerEdge Expandable RAID Controller 2/Si - 1028 0001 PowerEdge Expandable RAID Controller 2/Si - 0002 PowerEdge Expandable RAID Controller 3 - 1028 0002 PowerEdge Expandable RAID Controller 3/Di - 1028 00d1 PowerEdge Expandable RAID Controller 3/Di - 1028 00d9 PowerEdge Expandable RAID Controller 3/Di + 1028 0001 PowerEdge 2400 + 0002 PowerEdge Expandable RAID Controller 3/Di + 1028 0002 PowerEdge 4400 0003 PowerEdge Expandable RAID Controller 3/Si - 1028 0003 PowerEdge Expandable RAID Controller 3/Si - 0004 PowerEdge Expandable RAID Controller 3/Si - 1028 00d0 PowerEdge Expandable RAID Controller 3/Si + 1028 0003 PowerEdge 2450 0006 PowerEdge Expandable RAID Controller 3/Di - 0007 Remote Access Controller:DRAC III - 0008 Remote Access Controller - 0009 BMC/SMIC device not present - 000a PowerEdge Expandable RAID Controller 3 - 1028 0106 PowerEdge Expandable RAID Controller 3/Di - 1028 011b PowerEdge Expandable RAID Controller 3/Di - 1028 0121 PowerEdge Expandable RAID Controller 3/Di - 000c Remote Access Controller:ERA or ERA/O - 000d BMC/SMIC device - 000e PowerEdge Expandable RAID controller 4 - 1028 0123 PowerEdge Expandable RAID Controller 4/Di - 000f PowerEdge Expandable RAID controller 4 - 1028 013b MegaRAID DELL PERC 4/Di RAID On Motherboard - 1028 014a PowerEdge Expandable RAID Controller 4/Di - 1028 014c MegaRAID DELL PERC 4/Di RAID On Motherboard - 1028 014d MegaRAID DELL PERC 4/Di RAID On Motherboard + 0007 Remote Access Card III + 0008 Remote Access Card III + 0009 Remote Access Card III: BMC/SMIC device not present + 000a PowerEdge Expandable RAID Controller 3/Di + 000c Embedded Remote Access or ERA/O + 000d Embedded Remote Access: BMC/SMIC device + 000e PowerEdge Expandable RAID controller 4/Di + 000f PowerEdge Expandable RAID controller 4/Di + 0010 Remote Access Card 4 + 0011 Remote Access Card 4 Daughter Card + 0012 Remote Access Card 4 Daughter Card Virtual UART + 0013 PowerEdge Expandable RAID controller 4 + 1028 016c PowerEdge Expandable RAID Controller 4e/Si + 1028 016d PowerEdge Expandable RAID Controller 4e/Di + 1028 016e PowerEdge Expandable RAID Controller 4e/Di + 1028 016f PowerEdge Expandable RAID Controller 4e/Di + 1028 0170 PowerEdge Expandable RAID Controller 4e/Di + 0014 Remote Access Card 4 Daughter Card SMIC interface 1029 Siemens Nixdorf IS 102a LSI Logic 0000 HYDRA @@ -1518,6 +1575,7 @@ 1039 5513 SiS5513 EIDE Controller (A,B step) 1043 8035 CUSI-FX motherboard 5517 5517 + 5518 5518 [IDE] 5571 5571 5581 5581 Pentium Chipset 5582 5582 @@ -1542,6 +1600,7 @@ 1092 4920 SpeedStar A70 1569 6326 SiS6326 GUI Accelerator 6330 661FX/M661FX/M661MX/741/M741/760/M760 PCI/AGP + 1039 6330 [M]661FX/M661MX/[M]741/[M]760 PCI/AGP VGA Display Adapter 7001 USB 1.0 Controller 1039 7000 Onboard USB Controller 7002 USB 2.0 Controller @@ -1604,7 +1663,7 @@ 103c 1049 Tosca Console 103c 104a Tosca Secondary 103c 104b Maestro SP2 - 103c 1223 Halfdome Console + 103c 1223 Superdome Console 103c 1226 Keystone SP2 103c 1227 Powerbar SP2 103c 1282 Everest SP2 @@ -1642,7 +1701,7 @@ 4057 v8200 GeForce 3 8043 v8240 PAL 128M [P4T] Motherboard 807b v9280/TD [Geforce4 TI4200 8X With TV-Out and DVI] -1044 Distributed Processing Technology +1044 Adaptec (formerly DPT) 1012 Domino RAID Engine a400 SmartCache/Raid I-IV Controller a500 PCI Bridge @@ -1683,6 +1742,7 @@ 1044 c065 3010S Ultra3 Four Channel 1044 c066 3010S Fibre Channel a511 SmartRAID V Controller + 1044 c032 ASR-2005S I2O Zero Channel 1045 OPTi Inc. a0f8 82C750 [Vendetta] USB Controller c101 92C264 @@ -1786,6 +1846,7 @@ 1028 00e6 PCI4451 IEEE-1394 Controller (Dell Inspiron 8100) 8029 PCI4510 IEEE-1394 Controller 1071 8160 MIM2900 + 802e PCI7x20 1394a-2000 OHCI Two-Port PHY/Link-Layer Controller 8400 ACX 100 22Mbps Wireless Interface 00fc 16ec U.S. Robotics 22 Mbps Wireless PC Card (model 2210) 00fd 16ec U.S. Robotics 22Mbps Wireless PCI Adapter (model 2216) @@ -1894,6 +1955,8 @@ 0003 MPC8240 [Kahlua] 0004 MPC107 0006 MPC8245 [Unity] + 0008 MPC8540 + 0009 MPC8560 0100 MC145575 [HFC-PCI] 0431 KTI829c 100VG 1801 DSP56301 Digital Signal Processor @@ -1939,44 +2002,49 @@ 1058 Electronics & Telecommunications RSH 1059 Teknor Industrial Computers Inc 105a Promise Technology, Inc. - 0d30 20265 +# more correct description from promise linux sources + 0d30 PDC20265 (FastTrak100 Lite/Ultra100) 105a 4d33 Ultra100 0d38 20263 105a 4d39 Fasttrak66 1275 20275 3318 PDC20318 (SATA150 TX4) - 3319 PDC20319 (SATA150 TX4) - 3373 PDC20378 (SATA150 TX) + 3319 PDC20319 (FastTrak S150 TX4) + 8086 3427 S875WP1-E mainboard + 3371 PDC20371 (FastTrak S150 TX2plus) + 3373 PDC20378 (FastTrak 378/SATA 378) + 1043 80f5 PC-DL Deluxe motherboard 1462 702e K8T NEO FIS2R motherboard 3375 PDC20375 (SATA150 TX2plus) - 3376 PDC20376 + 3376 PDC20376 (FastTrak 376) 1043 809e A7V8X motherboard - 4d30 20267 + 4d30 PDC20267 (FastTrak100/Ultra100) 105a 4d33 Ultra100 - 105a 4d39 Fasttrak100 + 105a 4d39 FastTrak100 4d33 20246 105a 4d33 20246 IDE Controller - 4d38 20262 + 4d38 PDC20262 (FastTrak66/Ultra66) 105a 4d30 Ultra Device on SuperTrak 105a 4d33 Ultra66 - 105a 4d39 Fasttrak66 - 4d68 20268 + 105a 4d39 FastTrak66 + 4d68 PDC20268 (Ultra100 TX2) 105a 4d68 Ultra100TX2 4d69 20269 105a 4d68 Ultra133TX2 - 5275 PDC20276 IDE + 5275 PDC20276 (MBFastTrak133 Lite) 105a 0275 SuperTrak SX6000 IDE 105a 1275 MBFastTrak133 Lite (tm) Controller (RAID mode) 1458 b001 MBUltra 133 5300 DC5300 - 6268 20268R - 6269 PDC20271 + 6268 PDC20270 (FastTrak100 LP/TX2/TX4) + 105a 4d68 FastTrak100 TX2 + 6269 PDC20271 (FastTrak TX2000) 105a 6269 FastTrak TX2/TX2000 - 6621 PDC20621 [SX4000] 4 Channel IDE RAID Controller + 6621 PDC20621 (FastTrak S150 SX4/FastTrak SX4000 lite) 6622 PDC20621 [SATA150 SX4] 4 Channel IDE RAID Controller - 6626 PDC20618 Ultra 618 - 6629 PDC20619 FastTrak TX4000 RAID - 7275 PDC20277 + 6626 PDC20618 (Ultra 618) + 6629 PDC20619 (FastTrak TX4000) + 7275 PDC20277 (SBFastTrak133 Lite) 105b Foxconn International, Inc. 105c Wipro Infotech Limited 105d Number 9 Computer Company @@ -2070,6 +2138,8 @@ 1014 0242 iSeries 2872 DASD IOA 1014 0266 Dual Channel PCI-X U320 SCSI Adapter 1014 0278 Dual Channel PCI-X U320 SCSI RAID Adapter + 1014 02D3 Dual Channel PCI-X U320 SCSI Adapter + 1014 02D4 Dual Channel PCI-X U320 SCSI RAID Adapter ba55 eXtremeRAID 1100 support Device ba56 eXtremeRAID 2000/3000 support Device 106a Aten Research Inc @@ -2199,6 +2269,7 @@ 107c LG Electronics [Lucky Goldstar Co. Ltd] 107d LeadTek Research Inc. 0000 P86C850 + 2134 WinFast 3D S320 II 107e Interphase Corporation 0001 5515 ATM Adapter [Flipper] 0002 100 VG AnyLan Controller @@ -2348,10 +2419,10 @@ 0673 USB0673 0680 PCI0680 Ultra ATA-133 Host Controller 1095 3680 Winic W-680 (Silicon Image 680 based) - 3112 Silicon Image Serial ATARaid Controller [ CMD/Sil 3112/3112A ] + 3112 SiI 3112 [SATALink/SATARaid] Serial ATA Controller 1095 6112 Asus A7N8X - 3114 Silicon Image SiI 3114 SATARaid - 3512 Silicon Image Serial ATARaid Controller [ CMD/Sil 3512 ] + 3114 SiI 3114 [SATALink/SATARaid] Serial ATA Controller + 3512 SiI 3512 [SATALink/SATARaid] Serial ATA Controller 1096 Alacron 1097 Appian Technology 1098 Quantum Designs (H.K.) Ltd @@ -2742,6 +2813,7 @@ 10b7 7000 10/100 Mini PCI Ethernet Adapter 10f1 2466 Tiger MPX S2466 (3C920 Integrated Fast Ethernet Controller) 9201 3C920B-EMB Integrated Fast Ethernet Controller [Tornado] + 1043 80ab A7N8X Deluxe onboard 3C920B-EMB Integrated Fast Ethernet Controller 9202 3Com 3C920B-EMB-WNM Integrated Fast Ethernet Controller 9210 3C920B-EMB-WNM Integrated Fast Ethernet Controller 9300 3CSOHO100B-TX 910-A01 [tulip] @@ -2837,6 +2909,7 @@ 5219 M5219 5225 M5225 5229 M5229 IDE + 1014 050f ThinkPad R30 1043 8053 A7A266 Motherboard IDE 5235 M5225 5237 USB 1.1 Controller @@ -2859,8 +2932,8 @@ 545a SmartLink SmartPCI563 56K Modem 5471 M5471 Memory Stick Controller 5473 M5473 SD-MMC Controller - 7101 M7101 PMU - 10b9 7101 ALI M7101 Power Management Controller + 7101 M7101 Power Management Controller [PMU] + 1014 0510 ThinkPad R30 10ba Mitsubishi Electric Corp. 0301 AccelGraphics AccelECLIPSE 0304 AccelGALAXY A2100 [OEM Evans & Sutherland] @@ -3001,6 +3074,7 @@ 1043 0205 PCI-V3800 1043 4000 AGP-V3800PRO 1048 0c21 Synergy II + 107d 2134 WinFast 3D S320 II + TV-Out 1092 4804 Viper V770 1092 4a00 Viper V770 1092 4a02 Viper V770 Ultra @@ -3041,11 +3115,13 @@ 1554 1041 Pixelview RIVA TNT2 M64 002e NV6 [Vanta] 002f NV6 [Vanta] + 0041 NV40 OS1RT00B30 0060 nForce2 ISA Bridge 1043 80ad A7N8X Mainboard 0064 nForce2 SMBus (MCP) 0065 nForce2 IDE 0066 nForce2 Ethernet Controller + 1043 80a7 A7N8X Mainboard onboard nForce2 Ethernet 0067 nForce2 USB Controller 1043 0c11 A7N8X Mainboard 0068 nForce2 USB Controller @@ -3292,6 +3368,7 @@ 1071 8160 MIM2000 10bd 0320 EP-320X-R 10ec 8139 RT8139 + 1113 ec01 FNC-0107TX 1186 1300 DFE-538TX 1186 1320 SN5200 1186 8139 DRN-32TX @@ -3342,7 +3419,7 @@ 10f9 PC Direct 10fa Truevision 000c TARGA 1000 -10fb Thesys Gesellschaft fĂĽr Mikroelektronik mbH +10fb Thesys Gesellschaft für Mikroelektronik mbH 186f TH 6255 10fc I-O Data Device, Inc. # What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives @@ -3358,6 +3435,7 @@ 9400 INI-940 9401 INI-950 9500 360P + 9502 Initio INI-9100UW Ultra Wide SCSI Controller INIC-950P chip 1102 Creative Labs 0002 SB Live! EMU10k1 1102 0020 CT4850 SBLive! Value @@ -3507,13 +3585,16 @@ 0e11 0097 SoundMax Digital Integrated Audio 0e11 b194 Soundmax integrated digital audio 1019 0985 P6VXA Motherboard + 1043 1106 A7V133/A7V133-C Mainboard 1106 4511 Onboard Audio on EP7KXA 1458 7600 Onboard Audio 1462 3091 MS-6309 Onboard Audio + 1462 3300 MS-6330 Onboard Audio 15dd 7609 Onboard Audio 3059 VT8233/A/8235/8237 AC97 Audio Controller 1019 0a81 L7VTA v1.0 Motherboard (KT400-8235) 1043 8095 A7V8X Motherboard (Realtek ALC650 codec) + 1043 80a1 A7V8X-X Motherboard 1043 80b0 A7V600 motherboard (ADI AD1980 codec [SoundMAX]) 1106 3059 L7VMM2 Motherboard 1297 c160 FX41 motherboard (Realtek ALC650 codec) @@ -3526,6 +3607,7 @@ 1186 1401 DFE-530TX rev B 13b9 1421 LD-10/100AL PCI Fast Ethernet Adapter (rev.B) 3068 Intel 537 [AC97 Modem] + 1462 309e MS-6309 Saturn Motherboard 3074 VT8233 PCI to ISA Bridge 1043 8052 VT8233A 3091 VT8633 [Apollo Pro266] @@ -3906,7 +3988,15 @@ 1133 1c0b Diva Server V-PRI/T1-24 Cornet NQ 3 1133 1c0c Diva Server V-PRI/E1-30 Cornet NQ 3 e01e Diva Server 2PRI + 1133 1e00 Diva Server V-2PRI/E1-60 + 1133 1e01 Diva Server V-2PRI/T1-48 + 1133 1e02 Diva Server 2PRI/E1-60 + 1133 1e03 Diva Server 2PRI/T1-48 e020 Diva Server 4PRI + 1133 2000 Diva Server V-4PRI/E1-120 + 1133 2001 Diva Server V-4PRI/T1-96 + 1133 2002 Diva Server 4PRI/E1-120 + 1133 2003 Diva Server 4PRI/T1-96 e024 Diva Server Analog-4P e028 Diva Server Analog-8P 1134 Mercury Computer Systems @@ -4145,6 +4235,7 @@ 1165 Imagraph Corporation 0001 Motion TPEG Recorder/Player with audio 1166 ServerWorks + 0000 CMIC-LE 0005 CNB20-LE Host Bridge 0006 CNB20HE Host Bridge 0007 CNB20-LE Host Bridge @@ -4152,13 +4243,13 @@ 0009 CNB20LE Host Bridge 0010 CIOB30 0011 CMIC-HE - 0012 CMIC-LE + 0012 CMIC-WS Host Bridge (GC-LE chipset) 0013 CNB20-HE Host Bridge - 0014 CNB20-HE Host Bridge + 0014 CMIC-LE Host Bridge (GC-LE chipset) 0015 CMIC-GC Host Bridge 0016 CMIC-GC Host Bridge 0017 GCNB-LE Host Bridge - 0101 CIOB-X2 + 0101 CIOB-X2 PCI-X I/O Bridge 0110 CIOB-E I/O Bridge with Gigabit Ethernet 0200 OSB4 South Bridge 0201 CSB5 South Bridge @@ -4255,6 +4346,7 @@ 1186 1300 DFE-538TX 10/100 Ethernet Adapter 1186 1301 DFE-530TX+ 10/100 Ethernet Adapter 1340 DFE-690TXD CardBus PC Card + 1541 DFE-680TXD CardBus PC Card 1561 DRP-32TXD Cardbus PC Card 3300 DWL-510 2.4GHz Wireless PCI Adapter 3b05 DWL-G650+ CardBus PC Card @@ -4337,9 +4429,10 @@ 11a9 InnoSys Inc. 4240 AMCC S933Q Intelligent Serial Card 11aa Actel -# (formerly Galileo technologies) -11ab Marvell +# Formerly Galileo Technology, Inc. +11ab Marvell Technology Group Ltd. 0146 GT-64010/64010A System Controller + 1fa6 Marvell W8300 802.11 Adapter 4320 Yukon Gigabit Ethernet 10/100/1000Base-T Adapter 4611 GT-64115 System Controller 4620 GT-64120/64120A/64121A System Controller @@ -4677,6 +4770,7 @@ 6933 OZ6933 Cardbus Controller 1025 1016 Travelmate 612 TX 6972 OZ6912 Cardbus Controller + 1014 020c ThinkPad R30 1179 0001 Magnia Z310 7110 OZ711Mx MultiMediaBay Accelerator 7112 OZ711EC1/M1 SmartCardBus MultiMediaBay Controller @@ -4762,6 +4856,7 @@ 122c Sican GmbH 122d Aztech System Ltd 1206 368DSP + 1400 Trident PCI288-Q3DII (NX) 50dc 3328 Audio 122d 0001 3328 Audio 80da 3328 Audio @@ -4905,11 +5000,15 @@ 3873 Prism 2.5 Wavelan chipset 1186 3501 DWL-520 Wireless PCI Adapter 1186 3700 DWL-520 Wireless PCI Adapter, Rev E1 + 1385 4105 MA311 802.11b wireless adapter 1668 0414 HWP01170-01 802.11b PCI Wireless Adapter 16a5 1601 AIR.mate PC-400 PCI Wireless LAN Adapter 1737 3874 WMP11 Wireless 802.11b PCI Adapter 8086 2513 Wireless 802.11b MiniPCI Adapter + 3886 ISL3886 [Prism Javelin/Prism Xbow] 3890 Intersil ISL3890 [Prism GT/Prism Duette] + 10b8 a835 SMC2835W V2 Wireless Cardbus Adapter + 16a5 1605 ALLNET ALL0271 Wireless PCI Adapter 17cf 0014 Ovislink WL-5400PCM, Prism GT 8130 HMP8130 NTSC/PAL Video Decoder 8131 HMP8131 NTSC/PAL Video Decoder @@ -5155,7 +5254,7 @@ 9132 Ethernet 100/10 MBit 1283 Integrated Technology Express, Inc. 673a IT8330G - 8212 IT/ITE8212 Dual channel ATA RAID + 8212 IT/ITE8212 Dual channel ATA RAID controller 8330 IT8330G 8872 IT8874F PCI Dual Serial Port Controller 8888 IT8888F PCI to ISA Bridge with SMB @@ -5466,7 +5565,8 @@ 0985 NC100 Network Everywhere Fast Ethernet 10/100 1985 21x4x DEC-Tulip compatible 10/100 Ethernet 2850 HSP MicroModem 56 - 8201 [ADMtek] SP906B_V2 Wireless LAN adapter + 8201 ADMtek ADM8211 802.11b Wireless Interface + 10b8 2635 SMC2635W 802.11b (11Mbps) wireless lan pcmcia (cardbus) card 1317 8201 SMC2635W 802.11b (11mbps) wireless lan pcmcia (cardbus) card 9511 21x4x DEC-Tulip compatible 10/100 Ethernet 1318 Packet Engines Inc. @@ -5535,7 +5635,6 @@ 132d Integrated Silicon Solution, Inc. 1330 MMC Networks 1331 Radisys Corp. - 0030 ENP-2611 8200 82600 Host Bridge 8201 82600 IDE 8202 82600 USB @@ -5659,9 +5758,11 @@ 1385 Netgear 4100 802.11b Wireless Adapter (MA301) 4105 MA311 802.11b wireless adapter + 4a00 WAG311 802.11abg Wireless Adapter 620a GA620 Gigabit Ethernet 622a GA622 630a GA630 Gigabit Ethernet + f004 FA310TX 1386 Video Domain Technologies 1387 Systran Corp 1388 Hitachi Information Technology Co Ltd @@ -5720,6 +5821,7 @@ 13a6 Videonics Inc 13a7 Teles AG 13a8 Exar Corp. + 0154 XR17C154 Quad UART 0158 XR17C158 Octal UART 13a9 Siemens Medical Systems, Ultrasound Group 13aa Broadband Networks Inc @@ -5752,6 +5854,7 @@ 13c1 3ware Inc 1000 3ware ATA-RAID 1001 3ware 7000-series ATA-RAID + 13c1 1001 3ware Inc 3ware 7xxx/8xxx-series PATA/SATA-RAID 1002 3ware ATA-RAID 13c2 Technotrend Systemtechnik GmbH 13c3 Janz Computer AG @@ -5884,10 +5987,11 @@ 140f Salient Systems Corp 1410 Midas lab Inc 1411 Ikos Systems Inc -1412 IC Ensemble Inc - 1712 ICE1712 [Envy24] +# formerly IC Ensemble Inc. +1412 VIA Technologies Inc. + 1712 ICE1712 [Envy24] PCI Multi-Channel I/O Controller 1412 d638 M-Audio Delta 410 - 1724 ICE1724 [Envy24HT] + 1724 VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller 1413 Addonics 1414 Microsoft Corporation 1415 Oxford Semiconductor Ltd @@ -5990,6 +6094,7 @@ 1460 DYNARC INC 1461 Avermedia Technologies Inc 1462 Micro-Star International Co., Ltd. + 6825 PCI Card wireless 11g [PC54G] 8725 NVIDIA NV25 [GeForce4 Ti 4600] VGA Adapter # MSI G4Ti4800, 128MB DDR SDRAM, TV-Out, DVI-I 9000 NVIDIA NV28 [GeForce4 Ti 4800] VGA Adapter @@ -6150,8 +6255,9 @@ 14d6 Accusys Inc 14d7 Hirakawa Hewtech Corp 14d8 HOPF Elektronik GmBH -14d9 Alpha Processor Inc - 0010 AP1011 HyperTransport-PCI Bridge [Sturgeon] +# Formerly SiPackets, Inc., formerly API NetWorks, Inc., formerly Alpha Processor, Inc. +14d9 Alliance Semiconductor Corporation + 0010 AP1011/SP1011 HyperTransport-PCI Bridge [Sturgeon] 14da National Aerospace Laboratories 14db AFAVLAB Technology Inc 2120 TK9902 @@ -6175,6 +6281,14 @@ 14e2 INFOLIBRIA 14e3 AMTELCO 14e4 Broadcom Corporation + 0800 Sentry5 Chipcommon I/O Controller + 0804 Sentry5 PCI Bridge + 0805 Sentry5 MIPS32 CPU + 0806 Sentry5 Ethernet Controller + 080b Sentry5 Crypto Accelerator + 080f Sentry5 DDR/SDR RAM Controller + 0811 Sentry5 External Interface Core + 0816 BCM3302 Sentry5 MIPS32 CPU 1644 NetXtreme BCM5700 Gigabit Ethernet 1014 0277 Broadcom Vigil B5700 1000Base-T 1028 00d1 Broadcom BCM5700 @@ -6241,21 +6355,14 @@ 164d NetXtreme BCM5702FE Gigabit Ethernet 1653 NetXtreme BCM5705 Gigabit Ethernet 1654 NetXtreme BCM5705_2 Gigabit Ethernet - 1658 NetXtreme BCM5720 Gigabit Ethernet - 1659 NetXtreme BCM5721 Gigabit Ethernet + 1659 NetXtreme BCM5721 Gigabit Ethernet PCI Express 165d NetXtreme BCM5705M Gigabit Ethernet 165e NetXtreme BCM5705M_2 Gigabit Ethernet - 166e NetXtreme BCM5705F Gigabit Ethernet - 1676 NetXtreme BCM5750 Gigabit Ethernet - 1677 NetXtreme BCM5751 Gigabit Ethernet - 167c NetXtreme BCM5750M Gigabit Ethernet - 167d NetXtreme BCM5751M Gigabit Ethernet - 167e NetXtreme BCM5751F Gigabit Ethernet + 1677 NetXtreme BCM5751 Gigabit Ethernet PCI Express 1696 NetXtreme BCM5782 Gigabit Ethernet 103c 12bc HP d530 CMT (DG746A) 14e4 000d NetXtreme BCM5782 1000Base-T 169c NetXtreme BCM5788 Gigabit Ethernet - 169d NetXtreme BCM5789 Gigabit Ethernet 16a6 NetXtreme BCM5702X Gigabit Ethernet 0e11 00bb NC7760 Gigabit Server Adapter (PCI-X, 10/100/1000-T) 1028 0126 BCM5702 1000Base-T @@ -6279,13 +6386,17 @@ 103c 12ca HP Combo FC/GigE-T [A9784A] 14e4 0009 NetXtreme BCM5703 1000Base-T 14e4 000a NetXtreme BCM5703 1000Base-SX - 170d NetXtreme BCM5901 Gigabit Ethernet - 170e NetXtreme BCM5901_2 Gigabit Ethernet + 170c BCM4401-B0 100Base-TX + 170d NetXtreme BCM5901 100Base-TX + 170e NetXtreme BCM5901 100Base-TX + 3352 BCM3352 + 3360 BCM3360 4210 BCM4210 iLine10 HomePNA 2.0 4211 BCM4211 iLine10 HomePNA 2.0 + V.90 56k modem 4212 BCM4212 v.90 56k modem 4301 BCM4301 802.11b - 4320 BCM94306 802.11g + 4307 BCM4307 802.11b Wireless LAN Controller + 4320 BCM4306 802.11b/g Wireless LAN Controller 1028 0001 TrueMobile 1300 WLAN Mini-PCI Card 1737 4320 WPC54G 4324 BCM4309 802.11a/b/g @@ -6293,12 +6404,47 @@ 4401 BCM4401 100Base-T 1043 80a8 A7V8X motherboard 4402 BCM4402 Integrated 10/100BaseT + 4403 BCM4402 V.90 56k Modem 4410 BCM4413 iLine32 HomePNA 2.0 4411 BCM4413 V.90 56k modem 4412 BCM4413 10/100BaseT + 4430 BCM44xx CardBus iLine32 HomePNA 2.0 + 4432 BCM44xx CardBus 10/100BaseT + 4610 BCM4610 Sentry5 PCI to SB Bridge + 4611 BCM4610 Sentry5 iLine32 HomePNA 1.0 + 4612 BCM4610 Sentry5 V.90 56k Modem + 4613 BCM4610 Sentry5 Ethernet Controller + 4614 BCM4610 Sentry5 External Interface + 4615 BCM4610 Sentry5 USB Controller + 4704 BCM4704 PCI to SB Bridge + 4708 BCM4708 Sentry5 PCI to SB Bridge + 4710 BCM4710 Sentry5 PCI to SB Bridge + 4711 BCM47xx Sentry5 iLine32 HomePNA 2.0 + 4712 Sentry5 UART + 4713 Sentry5 Ethernet Controller + 4714 BCM47xx Sentry5 External Interface + 4715 Sentry5 USB Controller + 4716 BCM47xx Sentry5 USB Host Controller + 4717 BCM47xx Sentry5 USB Device Controller + 4718 Sentry5 Crypto Accelerator + 5365 BCM5365P Sentry5 Host Bridge + 5600 BCM5600 StrataSwitch 24+2 Ethernet Switch Controller + 5605 BCM5605 StrataSwitch 24+2 Ethernet Switch Controller + 5615 BCM5615 StrataSwitch 24+2 Ethernet Switch Controller + 5625 BCM5625 StrataSwitch 24+2 Ethernet Switch Controller + 5645 BCM5645 StrataSwitch 24+2 Ethernet Switch Controller + 5670 BCM5670 8-Port 10GE Ethernet Switch Fabric + 5680 BCM5680 G-Switch 8 Port Gigabit Ethernet Switch Controller 5690 BCM5690 12-port Multi-Layer Gigabit Ethernet Switch + 5691 BCM5691 GE/10GE 8+2 Gigabit Ethernet Switch Controller 5820 BCM5820 Crypto Accelerator 5821 BCM5821 Crypto Accelerator + 5822 BCM5822 Crypto Accelerator + 5823 BCM5823 Crypto Accelerator + 5824 BCM5824 Crypto Accelerator + 5840 BCM5840 Crypto Accelerator + 5841 BCM5841 Crypto Accelerator + 5850 BCM5850 Crypto Accelerator 14e5 Pixelfusion Ltd 14e6 SHINING Technology Inc 14e7 3CX @@ -6823,11 +6969,16 @@ 1619 FarSite Communications Ltd 0400 FarSync T2P (2 port X.21/V.35/V.24) 0440 FarSync T4P (4 port X.21/V.35/V.24) +# www.rioworks.com +161f Rioworks 1626 TDK Semiconductor Corp. 8410 RTL81xx Fast Ethernet 1629 Kongsberg Spacetec AS 1003 Format synchronizer v3.0 2002 Fast Universal Data Output +# This seems to occur on their 802.11b Wireless card WMP-11 +1637 Linksys + 3874 Linksys 802.11b WMP11 PCI Wireless card 1638 Standard Microsystems Corp [SMC] 1100 SMC2602W EZConnect/Addtron AWA-100/Eumitcom WL11000 163c Smart Link Ltd. @@ -6862,6 +7013,7 @@ 168c 0013 WG511T Wireless CardBus Adapter 168c 1025 DWL-G650B2 Wireless CardBus Adapter 1014 AR5212 802.11abg NIC +16a5 Tekram Technology Co.,Ltd. 16ab Global Sun Technology Inc 1100 GL24110P 1101 PLX9052 PCMCIA-to-PCI Wireless LAN @@ -6874,9 +7026,13 @@ 16cd Densitron Technologies # www.pikatechnologies.com 16df PIKA Technologies Inc. +16e3 European Space Agency + 1e0f LEON2FT Processor 16ec U.S. Robotics 00ff USR997900 10/100 Mbps PCI Network Card 3685 Wireless Access PCI Adapter Model 022415 +16f4 Vweb Corp + 8000 VW2010 16f6 VideoTele.com, Inc. # www.internetmachines.com 1702 Internet Machines Corporation (IMC) @@ -6884,8 +7040,12 @@ 170b NetOctave 0100 NSP2000-SSL crypto accelerator 170c YottaYotta Inc. +# Seems to be a 2nd ID for Vitesse Semiconductor +1725 Vitesse Semiconductor + 7174 VSC7174 PCI/PCI-X Serial ATA Host Bus Controller 172a Accelerated Encryption 1737 Linksys + 0013 WMP54G Wireless Pci Card 1032 Gigabit Network Adapter 1737 0015 EG1032 v2 Instant Gigabit Network Adapter 1064 Gigabit Network Adapter @@ -6914,10 +7074,12 @@ 0004 CAMAC Controller 0005 PROFIBUS 0006 AMCC HOTlink +1797 JumpTec h, GMBH 1799 Belkin 6001 Wireless PCI Card - F5D6001 6020 Wireless PCMCIA Card - F5D6020 6060 Wireless PDA Card - F5D6060 + 7000 Wireless PCI Card - F5D7000 17af Hightech Information System Ltd. 17b3 Hawking Technologies ab08 PN672TX 10/100 Ethernet @@ -6929,6 +7091,9 @@ 2280 USB 2.0 # S2io ships 10Gb PCI-X Ethernet adapters www.s2io.com 17d5 S2io Inc. +# Supplying full name for a currently green entry +17fe Linksys, A Division of Cisco Systems + 2220 [AirConn] INPROCOMM IPN 2220 WLAN Adapter (rev 01) 1813 Ambient Technologies Inc 4000 HaM controllerless modem 16be 0001 V9x HAM Data Fax Modem @@ -6937,6 +7102,8 @@ 1814 RaLink 0101 Wireless PCI Adpator RT2400 / RT2460 0201 Ralink RT2500 802.11 Cardbus Reference Card +1820 InfiniCon Systems Inc. +1822 Twinhan Technology Co. Ltd 1830 Credence Systems Corporation 1851 Microtune, Inc. 1852 Anritsu Corp. @@ -6952,6 +7119,8 @@ # found e.g. on KNC DVB-S card 1894 KNC One 18a1 Astute Networks Inc. +18bc Info-Tek Corp. +18c9 ARVOO Engineering BV 18ca XGI - Xabre Graphics Inc 0040 Volari V8 18e6 MPL AG @@ -7018,6 +7187,7 @@ 0008 GLINT Gamma G1 0009 Permedia II 2D+3D 1040 0011 AccelStar II + 13e9 1000 6221L-4U 3d3d 0100 AccelStar II 3D Accelerator 3d3d 0111 Permedia 3:16 3d3d 0114 Santa Ana @@ -7269,10 +7439,11 @@ 5555 Genroco, Inc 0003 TURBOstor HFP-832 [HiPPI NIC] 5654 VoiceTronix Pty Ltd + 3132 OpenSwitch12 5700 Netpower 5851 Exacq Technologies 6356 UltraStor -6374 c't Magazin fĂĽr Computertechnik +6374 c't Magazin für Computertechnik 6773 GPPCI 6409 Logitec Corp. 6666 Decision Computer International Co. @@ -7292,6 +7463,8 @@ 0008 1000 WorldMark 4300 INCA ASIC 0039 21145 Fast Ethernet 0122 82437FX + 0309 80303 I/O Processor PCI-to-PCI Bridge + 030d 80312 I/O Companion Chip PCI-to-PCI Bridge 0326 PCI Bridge Hub I/OxAPIC Interrupt Controller A 0327 PCI Bridge Hub I/OxAPIC Interrupt Controller B 0329 PCI Bridge Hub A @@ -7315,13 +7488,38 @@ 0340 41210 [Lanai] Serial to Parallel PCI Bridge # B-segment bridge 0341 41210 [Lanai] Serial to Parallel PCI Bridge - 0482 82375EB - 0483 82424ZX [Saturn] - 0484 82378IB [SIO ISA Bridge] - 0486 82430ZX [Aries] - 04a3 82434LX [Mercury/Neptune] + 0482 82375EB/SB PCI to EISA Bridge + 0483 82424TX/ZX [Saturn] CPU to PCI bridge + 0484 82378ZB/IB, 82379AB (SIO, SIO.A) PCI to ISA Bridge + 0486 82425EX/ZX [Aries] PCIset with ISA bridge + 04a3 82434LX/NX [Mercury/Neptune] Processor to PCI bridge 04d0 82437FX [Triton FX] + 0500 E8870 Processor bus control + 0501 E8870 Memory controller +# and registers common to both SPs + 0502 E8870 Scalability Port 0 +# and global performance monitoring + 0503 E8870 Scalability Port 1 + 0510 E8870IO Hub Interface Port 0 registers (8-bit compatibility port) + 0511 E8870IO Hub Interface Port 1 registers + 0512 E8870IO Hub Interface Port 2 registers + 0513 E8870IO Hub Interface Port 3 registers + 0514 E8870IO Hub Interface Port 4 registers + 0515 E8870IO General SIOH registers + 0516 E8870IO RAS registers + 0530 E8870SP Scalability Port 0 registers + 0531 E8870SP Scalability Port 1 registers + 0532 E8870SP Scalability Port 2 registers + 0533 E8870SP Scalability Port 3 registers + 0534 E8870SP Scalability Port 4 registers + 0535 E8870SP Scalability Port 5 registers +# (bi-interleave 0) and global registers that are neither per-port nor per-interleave + 0536 E8870SP Interleave registers 0 and 1 +# (bi-interleave 1) + 0537 E8870SP Interleave registers 2 and 3 0600 RAID Controller + 8086 01c1 ICP Vortex GDT8546RZ + 8086 01f7 SCRU32 0960 80960RP [i960 RP Microprocessor/Bridge] 0962 80960RM [i960RM Bridge] 0964 80960RP [i960 RP Microprocessor/Bridge] @@ -7406,6 +7604,7 @@ 1019 82547EI Gigabit Ethernet Controller (LOM) 1458 1019 GA-8IPE1000 Pro2 motherboard (865PE) 8086 1019 PRO/1000 CT Desktop Connection + 8086 3427 S875WP1-E mainboard 101d 82546EB Gigabit Ethernet Controller 8086 1000 PRO/1000 MT Quad Port Server Adapter 101e 82540EP Gigabit Ethernet Controller (Mobile) @@ -7453,13 +7652,16 @@ 16be 1040 V.9X DSP Data Fax Modem 1043 PRO/Wireless LAN 2100 3B Mini PCI Adapter 8086 2527 MIM2000/Centrino - 1048 Intel(R) PRO/10GbE LR Server Adapter + 1048 PRO/10GbE LR Server Adapter 8086 a01f PRO/10GbE LR Server Adapter 8086 a11f PRO/10GbE LR Server Adapter 1050 82562EZ 10/100 Ethernet Controller 1462 728c 865PE Neo2 (MS-6728) + 1462 758c MS-6758 (875P Neo) + 8086 3427 S875WP1-E mainboard 1051 82801EB/ER (ICH5/ICH5R) integrated LAN Controller 1059 82551QM Ethernet Controller + 1065 82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller # Updated controller name from 82547EI to 82547GI 1075 82547GI Gigabit Ethernet Controller 8086 0075 PRO/1000 CT Network Connection @@ -7516,8 +7718,8 @@ 4c53 1050 CT7 mainboard 4c53 1051 CE7 mainboard 4c53 1070 PC6 mainboard - 1221 82092AA_0 - 1222 82092AA_1 + 1221 82092AA PCI to PCMCIA Bridge + 1222 82092AA IDE Controller 1223 SAA7116 1225 82452KX/GX [Orion] 1226 82596 PRO/10 PCI @@ -7587,6 +7789,7 @@ 1259 2560 AT-2560 100 1259 2561 AT-2560 100 FX Ethernet Adapter 1266 0001 NE10/100 Adapter + 13e9 1000 6221L-4U 144d 2501 SEM-2000 MiniPCI LAN Adapter 144d 2502 SEM-2100IL MiniPCI LAN Adapter 1668 1100 EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem) @@ -7675,6 +7878,7 @@ 8086 3010 EtherExpress PRO/100 S Network Connection 8086 3011 EtherExpress PRO/100 S Network Connection 8086 3012 EtherExpress PRO/100 Network Connection + 8086 3411 SDS2 Mainboard 122d 430FX - 82437FX TSC [Triton I] 122e 82371FB PIIX ISA [Triton I] 1230 82371FB PIIX IDE [Triton I] @@ -7682,13 +7886,15 @@ 1234 430MX - 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX) 1235 430MX - 82437MX Mob. System Ctrlr (MTSC) & 82438MX Data Path (MTDP) 1237 440FX - 82441FX PMC [Natoma] - 1239 82371FB - 123b 82380PB - 123c 82380AB + 1239 82371FB PIIX IDE Interface + 123b 82380PB PCI to PCI Docking Bridge + 123c 82380AB (MISA) Mobile PCI-to-ISA Bridge 123d 683053 Programmable Interrupt Device +# in" hidden" mode + 123e 82466GX (IHPC) Integrated Hot-Plug Controller 123f 82466GX Integrated Hot-Plug Controller (IHPC) - 1240 752 AGP - 124b 82380FB + 1240 82752 (752) AGP Graphics Accelerator + 124b 82380FB (MPCI2) Mobile Docking Controller 1250 430HX - 82439HX TXC [Triton II] 1360 82806AA PCI64 Hub PCI Bridge 1361 82806AA PCI64 Hub Controller (HRes) @@ -7782,7 +7988,7 @@ 2446 Intel 537 [82801BA/BAM AC'97 Modem] 1025 1016 Travelmate 612 TX 104d 80df Vaio PCG-FX403 - 2448 82801BAM/CAM PCI Bridge + 2448 82801 PCI Bridge 2449 82801BA/BAM/CA/CAM Ethernet Controller 0e11 0012 EtherExpress PRO/100 VM 0e11 0091 EtherExpress PRO/100 VE @@ -7824,7 +8030,7 @@ 8086 4532 D815EEA2 mainboard 8086 4557 D815EGEW Mainboard 244c 82801BAM ISA Bridge (LPC) - 244e 82801BA/CA/DB/EB/ER Hub interface to PCI Bridge + 244e 82801 PCI Bridge 1014 0267 NetVista A30p 2450 82801E ISA Bridge (LPC) 2452 82801E USB @@ -7879,45 +8085,45 @@ 248b 82801CA Ultra ATA Storage Controller 15d9 3480 P4DP6 248c 82801CAM ISA Bridge (LPC) - 24c0 82801DB (ICH4) LPC Bridge + 24c0 82801DB/DBL (ICH4/ICH4-L) LPC Bridge 1014 0267 NetVista A30p 1462 5800 845PE Max (MS-6580) - 24c2 82801DB (ICH4) USB UHCI #1 + 24c2 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 5800 845PE Max (MS-6580) - 24c3 82801DB/DBM (ICH4) SMBus Controller + 24c3 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller 1014 0267 NetVista A30p 1071 8160 MIM2000 1458 24c2 GA-8PE667 Ultra 1462 5800 845PE Max (MS-6580) 4c53 1090 Cx9 / Vx9 mainboard - 24c4 82801DB (ICH4) USB UHCI #2 + 24c4 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 5800 845PE Max (MS-6580) 4c53 1090 Cx9 / Vx9 mainboard - 24c5 82801DB (ICH4) AC'97 Audio Controller + 24c5 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller 0e11 00b8 Analog Devices Inc. codec [SoundMAX] 1014 0267 NetVista A30p 1071 8160 MIM2000 1458 a002 GA-8PE667 Ultra 1462 5800 845PE Max (MS-6580) - 24c6 82801DB (ICH4) AC'97 Modem Controller + 24c6 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller 1071 8160 MIM2000 - 24c7 82801DB (ICH4) USB UHCI #3 + 24c7 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 5800 845PE Max (MS-6580) 24ca 82801DBM (ICH4) Ultra ATA Storage Controller 1071 8160 MIM2000 - 24cb 82801DB (ICH4) Ultra ATA 100 Storage Controller + 24cb 82801DB/DBL (ICH4/ICH4-L) UltraATA-100 IDE Controller 1014 0267 NetVista A30p 1458 24c2 GA-8PE667 Ultra 1462 5800 845PE Max (MS-6580) 4c53 1090 Cx9 / Vx9 mainboard 24cc 82801DBM LPC Interface Controller - 24cd 82801DB (ICH4) USB2 EHCI Controller + 24cd 82801DB/DBM (ICH4/ICH4-M) USB 2.0 EHCI Controller 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 3981 845PE Max (MS-6580) @@ -7927,19 +8133,23 @@ 103c 12bc d530 CMT (DG746A) 1458 24d1 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d2 82801EB/ER (ICH5/ICH5R) USB UHCI #1 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d3 82801EB/ER (ICH5/ICH5R) SMBus Controller 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d4 82801EB/ER (ICH5/ICH5R) USB UHCI #2 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d5 82801EB/ER (ICH5/ICH5R) AC'97 Audio Controller 103c 12bc Analog Devices codec [SoundMAX Integrated Digital Audio] 1043 80f3 P4P800 Mainboard @@ -7950,22 +8160,26 @@ 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24db 82801EB/ER (ICH5/ICH5R) Ultra ATA 100 Storage Controller 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) 1462 7580 MSI 875P + 8086 3427 S875WP1-E mainboard 24dc 82801EB LPC Interface Controller 24dd 82801EB/ER (ICH5/ICH5R) USB2 EHCI Controller 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1458 5006 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24de 82801EB/ER (ICH5/ICH5R) USB UHCI #4 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24df 82801EB (ICH5R) SATA (cc=RAID) 2500 82820 820 (Camino) Chipset Host Bridge (MCH) 1028 0095 Precision Workstation 220 Chipset @@ -7984,23 +8198,23 @@ 2534 82860 860 (Wombat) Chipset PCI Bridge 2540 E7500 Memory Controller Hub 15d9 3480 P4DP6 - 2541 E7000 Series Host RASUM Controller + 2541 E7500/E7501 Host RASUM Controller 15d9 3480 P4DP6 4c53 1090 Cx9 / Vx9 mainboard - 2543 E7000 Series Hub Interface B PCI-to-PCI Bridge - 2544 E7000 Series Hub Interface B RASUM Controller + 2543 E7500/E7501 Hub Interface B PCI-to-PCI Bridge + 2544 E7500/E7501 Hub Interface B RASUM Controller 4c53 1090 Cx9 / Vx9 mainboard - 2545 E7000 Series Hub Interface C PCI-to-PCI Bridge - 2546 E7000 Series Hub Interface C RASUM Controller - 2547 E7000 Series Hub Interface D PCI-to-PCI Bridge - 2548 E7000 Series Hub Interface D RASUM Controller + 2545 E7500/E7501 Hub Interface C PCI-to-PCI Bridge + 2546 E7500/E7501 Hub Interface C RASUM Controller + 2547 E7500/E7501 Hub Interface D PCI-to-PCI Bridge + 2548 E7500/E7501 Hub Interface D RASUM Controller 254c E7501 Memory Controller Hub 4c53 1090 Cx9 / Vx9 mainboard 2550 E7505 Memory Controller Hub - 2551 E7000 Series RAS Controller - 2552 E7000 Series Processor to AGP Controller - 2553 E7000 Series Hub Interface B PCI-to-PCI Bridge - 2554 E7000 Series Hub Interface B PCI-to-PCI Bridge RAS Controller + 2551 E7505/E7205 Series RAS Controller + 2552 E7505/E7205 PCI-to-AGP Bridge + 2553 E7505 Hub Interface B PCI-to-PCI Bridge + 2554 E7505 Hub Interface B PCI-to-PCI Bridge RAS Controller 255d E7205 Memory Controller Hub 2560 82845G/GL[Brookdale-G]/GE/PE DRAM Controller/Host-Hub Interface 1458 2560 GA-8PE667 Ultra @@ -8022,14 +8236,17 @@ 2579 82875P Processor to AGP Controller 257b 82875P Processor to PCI to CSA Bridge 257e 82875P Processor to I/O Memory Interface - 2580 Memory Controller Hub - 2581 Memory Controller Hub PCI Express Port - 2582 Graphics Controller - 2584 Workstation Memory Controller Hub - 2585 Workstation Memory Controller Hub PCI Express Port + 2580 915G/P/GV Processor to I/O Controller + 2581 915G/P/GV PCI Express Root Port + 2582 82915G Express Chipset Family Graphics Controller + 2584 925X Memory Controller Hub + 2585 925X PCI Express Root Port 2588 Server Memory Controller Hub 2589 Server Memory Controller Hub PCI Express Port 258a Graphics Controller + 2590 Mobile Memory Controller Hub + 2591 Mobile Memory Controller Hub PCI Express Port + 2592 Mobile Graphics Controller 25a1 6300ESB LPC Interface Controller 25a2 6300ESB PATA Storage Controller 25a3 6300ESB SATA Storage Controller @@ -8043,26 +8260,63 @@ 25ad 6300ESB USB2 Enhanced Host Controller 25ae 6300ESB 64-bit PCI-X Bridge 25b0 6300ESB SATA RAID Controller - 2640 I/O Controller Hub LPC - 2641 I/O Controller Hub LPC - 2642 I/O Controller Hub LPC - 2651 I/O Controller Hub SATA cc=ide - 2652 I/O Controller Hub SATA cc=raid - 2658 I/O Controller Hub USB - 2659 I/O Controller Hub USB - 265a I/O Controller Hub USB - 265b I/O Controller Hub USB - 265c I/O Controller Hub USB2 - 2660 I/O Controller Hub PCI Express Port 0 - 2662 I/O Controller Hub PCI Express Port 1 - 2664 I/O Controller Hub PCI Express Port 2 - 2666 I/O Controller Hub PCI Express Port 3 - 2668 I/O Controller Hub Audio - 266a I/O Controller Hub SMBus - 266d I/O Controller Hub Modem - 266e I/O Controller Hub Audio - 266f I/O Controller Hub PATA - 2782 Graphics Controller + 2600 Server Hub Interface + 2601 Server Hub PCI Express x4 Port D + 2602 Server Hub PCI Express x4 Port C0 + 2603 Server Hub PCI Express x4 Port C1 + 2604 Server Hub PCI Express x4 Port B0 + 2605 Server Hub PCI Express x4 Port B1 + 2606 Server Hub PCI Express x4 Port A0 + 2607 Server Hub PCI Express x4 Port A1 + 2608 Server Hub PCI Express x8 Port C + 2609 Server Hub PCI Express x8 Port B + 260a Server Hub PCI Express x8 Port A + 260c Server Hub IMI Registers + 2610 Server Hub System Bus, Boot, and Interrupt Registers + 2611 Server Hub Address Mapping Registers + 2612 Server Hub RAS Registers + 2613 Server Hub Performance Monitoring Registers + 2614 Server Hub Performance Monitoring Registers + 2615 Server Hub Performance Monitoring Registers + 2617 Server Hub Debug Registers + 2618 Server Hub Debug Registers + 2619 Server Hub Debug Registers + 261a Server Hub Debug Registers + 261b Server Hub Debug Registers + 261c Server Hub Debug Registers + 261d Server Hub Debug Registers + 261e Server Hub Debug Registers + 2620 External Memory Bridge + 2621 External Memory Bridge Control Registers + 2622 External Memory Bridge Memory Interleaving Registers + 2623 External Memory Bridge DDR Initialization and Calibration + 2624 External Memory Bridge Reserved Registers + 2625 External Memory Bridge Reserved Registers + 2626 External Memory Bridge Reserved Registers + 2627 External Memory Bridge Reserved Registers + 2640 82801FB/FR (ICH6/ICH6R) LPC Interface Bridge + 2641 82801FBM (ICH6M) LPC Interface Bridge + 2642 82801FW/FRW (ICH6W/ICH6RW) LPC Interface Bridge + 2651 82801FB/FW (ICH6/ICH6W) SATA Controller + 2652 82801FR/FRW (ICH6R/ICH6RW) SATA Controller + 2653 82801FBM (ICH6M) SATA Controller + 2658 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1 + 2659 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #2 + 265a 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #3 + 265b 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #4 + 265c 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller + 2660 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 1 + 2662 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 2 + 2664 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 3 + 2666 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 4 + 2668 82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller + 266a 82801FB/FBM/FR/FW/FRW (ICH6 Family) SMBus Controller + 266c 82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller + 266d 82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Modem Controller + 266e 82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Audio Controller + 266f 82801FB/FBM/FR/FW/FRW (ICH6 Family) IDE Controller + 2782 82915G Express Chipset Family Graphics Controller + 2792 Mobile Graphics Controller 3092 Integrated RAID 3200 GD31244 PCI-X SATA HBA 3340 82855PM Processor to I/O Controller @@ -8092,7 +8346,7 @@ 359a Memory Controller Hub PCI Express Port C1 359b Memory Controller Hub Extended Configuration Registers 359e Workstation Memory Controller Hub - 4220 Intel(R) PRO/Wireless 2200BG + 4220 PRO/Wireless 2200BG 5200 EtherExpress PRO/100 Intelligent Server 5201 EtherExpress PRO/100 Intelligent Server 8086 0001 EtherExpress PRO/100 Server Ethernet Adapter @@ -8155,7 +8409,7 @@ 7601 82372FB PIIX5 IDE 7602 82372FB PIIX5 USB 7603 82372FB PIIX5 SMBus - 7800 i740 + 7800 82740 (i740) AGP Graphics Accelerator 003d 0008 Starfighter AGP 003d 000b Starfighter AGP 1092 0100 Stealth II G460 @@ -8175,7 +8429,9 @@ 84e6 460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB) 84ea 460GX - 84460GX AGP Bridge (GXB function 1) 8500 IXP4xx Family Network Processor (IXP420, 421, 422, 425 and IXC1100) - 9000 Intel IXP2000 Familly Network Processor + 9000 Intel IXP2000 Family Network Processor + 9001 Intel IXP2400 Network Processor + 9004 Intel IXP2800 Network Processor 9621 Integrated RAID 9622 Integrated RAID 9641 Integrated RAID @@ -8184,10 +8440,12 @@ # observed, and documented in Intel revision note; new mask of 1011:0026 b154 21154 PCI-to-PCI Bridge b555 21555 Non transparent PCI-to-PCI Bridge + 1331 0030 Radisys ENP-2611 4c53 1050 CT7 mainboard 4c53 1051 CE7 mainboard e4bf 1000 CC8-1-BLUES ffff 450NX/GX [Orion] - 82453KX/GX Memory controller [BUG] +8401 TRENDware International Inc. 8800 Trigem Computer Inc. 2008 Video assistent component 8866 T-Square Design Inc. @@ -8352,15 +8610,18 @@ 00c1 AIC-7899B U160/m 00c3 AIC-7899D U160/m 00c5 RAID subsystem HBA - 1028 00c5 PowerEdge 2550 + 1028 00c5 PowerEdge 2400,2500,2550,4400 00cf AIC-7899P U160/m 1028 00ce PowerEdge 1400 1028 00d1 PowerEdge 2550 10f1 2462 Thunder K7 S2462 15d9 9005 Onboard SCSI Host Adapter + 8086 3411 SDS2 Mainboard 0250 ServeRAID Controller 1014 0279 ServeRAID-xx 1014 028c ServeRAID-xx +# from kernel sources + 0279 ServeRAID 6M 0283 AAC-RAID 9005 0283 Catapult 0284 AAC-RAID @@ -8429,7 +8690,7 @@ 1000 0012 1P2S 9845 PCI 9845 Multi-I/O Controller 1000 0006 0P6S (6 port 16550a serial card) - 9855 PCI 9855 Multi-I/O Controller 4 Serial 1 Parallel + 9855 PCI 9855 Multi-I/O Controller 1000 0014 1P4S 9902 Stargen Inc. 0001 SG2010 PCI over Starfabric Bridge @@ -8444,6 +8705,7 @@ a727 3Com Corporation aa42 Scitex Digital Video ac1e Digital Receiver Technology Inc +aecb Adrienne Electronics Corporation b1b3 Shiva Europe Limited # Pinnacle should be 11bd, but they got it wrong several times --mj bd11 Pinnacle Systems, Inc. (Wrong ID) @@ -8464,9 +8726,9 @@ dead Indigita Corporation e000 Winbond e000 W89C940 -# see : http://www.schoenfeld.de/inside/Inside_CWMK3.txt -e159 Individual Computers - Jens Schoenfeld - 0001 Intel 537 +# see also : http://www.schoenfeld.de/inside/Inside_CWMK3.txt maybe a misuse of TJN id or it use the TJN 3XX chip for other applic +e159 Tiger Jet Network Inc. + 0001 Tiger3XX Modem/ISDN interface 0059 0001 128k ISDN-S/T Adapter 0059 0003 128k ISDN-U Adapter 0002 Tiger100APC ISDN chipset diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c --- a/drivers/pci/probe.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/pci/probe.c 2004-10-18 14:56:48 -07:00 @@ -373,7 +373,10 @@ child->bridge_ctl = bctl; cmax = pci_scan_child_bus(child); - if (cmax > max) max = cmax; + if (cmax > max) + max = cmax; + if (child->subordinate > max) + max = child->subordinate; } else { /* * We need to assign a number to this bus which we always @@ -571,6 +574,11 @@ return PCI_CFG_SPACE_SIZE; } +static void pci_release_bus_bridge_dev(struct device *dev) +{ + kfree(dev); +} + /* * Read the config data for a PCI device, sanity-check it * and fill in the dev structure... @@ -640,7 +648,7 @@ return NULL; /* Fix up broken headers */ - pci_fixup_device(PCI_FIXUP_HEADER, dev); + pci_fixup_device(pci_fixup_header, dev); /* * Add the device to our list of discovered devices @@ -772,6 +780,7 @@ memset(dev, 0, sizeof(*dev)); dev->parent = parent; + dev->release = pci_release_bus_bridge_dev; sprintf(dev->bus_id, "pci%04x:%02x", pci_domain_nr(b), bus); device_register(dev); b->bridge = get_device(dev); diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c --- a/drivers/pci/quirks.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/pci/quirks.c 2004-10-18 14:55:54 -07:00 @@ -1,10 +1,10 @@ /* - * $Id: quirks.c,v 1.5 1998/05/02 19:24:14 mj Exp $ - * * This file contains work-arounds for many known PCI hardware * bugs. Devices present only on certain architectures (host * bridges et cetera) should be handled in arch-specific code. * + * Note: any quirks for hotpluggable devices must _NOT_ be declared __init. + * * Copyright (c) 1999 Martin Mares * * The bridge optimization stuff has been removed. If you really @@ -39,6 +39,7 @@ } } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); /* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround but VIA don't answer queries. If you happen to have good contacts at VIA @@ -46,8 +47,6 @@ This appears to be BIOS not version dependent. So presumably there is a chipset level fix */ - - int isa_dma_bridge_buggy; /* Exported */ static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) @@ -57,34 +56,47 @@ printk(KERN_INFO "Activating ISA DMA hang workarounds.\n"); } } + /* + * Its not totally clear which chipsets are the problematic ones + * We know 82C586 and 82C596 variants are affected. + */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs ); int pci_pci_problems; /* * Chipsets where PCI->PCI transfers vanish or hang */ - static void __devinit quirk_nopcipci(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_FAIL)==0) - { + if ((pci_pci_problems & PCIPCI_FAIL)==0) { printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_FAIL; + pci_pci_problems |= PCIPCI_FAIL; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); /* * Triton requires workarounds to be used by the drivers */ - static void __devinit quirk_triton(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_TRITON)==0) - { + if ((pci_pci_problems&PCIPCI_TRITON)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_TRITON; + pci_pci_problems |= PCIPCI_TRITON; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton ); /* * VIA Apollo KT133 needs PCI latency patch @@ -104,19 +116,16 @@ /* Ok we have a potential problem chipset here. Now see if we have a buggy southbridge */ - p=pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); - if(p!=NULL) - { + p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); + if (p!=NULL) { pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ /* Check for buggy part revisions */ if (rev < 0x40 || rev > 0x42) return; - } - else - { + } else { p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); - if(p==NULL) /* No problem parts */ + if (p==NULL) /* No problem parts */ return; pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* Check for buggy part revisions */ @@ -145,27 +154,30 @@ pci_write_config_byte(dev, 0x76, busarb); printk(KERN_INFO "Applying VIA southbridge workaround.\n"); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); /* * VIA Apollo VP3 needs ETBF on BT848/878 */ - static void __devinit quirk_viaetbf(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_VIAETBF)==0) - { + if ((pci_pci_problems&PCIPCI_VIAETBF)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_VIAETBF; + pci_pci_problems |= PCIPCI_VIAETBF; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf ); + static void __devinit quirk_vsfx(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_VSFX)==0) - { + if ((pci_pci_problems&PCIPCI_VSFX)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_VSFX; + pci_pci_problems |= PCIPCI_VSFX; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx ); /* * Ali Magik requires workarounds to be used by the drivers @@ -173,36 +185,38 @@ * workaround applied too * [Info kindly provided by ALi] */ - static void __init quirk_alimagik(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_ALIMAGIK)==0) - { + if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_ALIMAGIK|PCIPCI_TRITON; + pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON; } } - +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik ); /* * Natoma has some interesting boundary conditions with Zoran stuff * at least */ - static void __devinit quirk_natoma(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_NATOMA)==0) - { + if ((pci_pci_problems&PCIPCI_NATOMA)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_NATOMA; + pci_pci_problems |= PCIPCI_NATOMA; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma ); /* * S3 868 and 968 chips report region size equal to 32M, but they decode 64M. * If it's needed, re-allocate the region. */ - static void __devinit quirk_s3_64M(struct pci_dev *dev) { struct resource *r = &dev->resource[0]; @@ -212,6 +226,8 @@ r->end = 0x3ffffff; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M ); static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr) { @@ -231,7 +247,6 @@ * ATI Northbridge setups MCE the processor if you even * read somewhere between 0x3b0->0x3bb or read 0x3d3 */ - static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev) { printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n"); @@ -239,6 +254,7 @@ request_region(0x3b0, 0x0C, "RadeonIGP"); request_region(0x3d3, 0x01, "RadeonIGP"); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce ); /* * Let's make the southbridge information explicit instead @@ -260,6 +276,7 @@ pci_read_config_word(dev, 0xE2, ®ion); quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi ); /* * PIIX4 ACPI: Two IO regions pointed to by longwords at @@ -275,6 +292,7 @@ pci_read_config_dword(dev, 0x90, ®ion); quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi ); /* * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at @@ -291,6 +309,15 @@ pci_read_config_dword(dev, 0x58, ®ion); quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi ); /* * VIA ACPI: One IO region pointed to by longword at @@ -308,6 +335,7 @@ quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi ); /* * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at @@ -330,6 +358,7 @@ smb &= PCI_BASE_ADDRESS_IO_MASK; quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi ); #ifdef CONFIG_X86_IO_APIC @@ -358,6 +387,7 @@ /* Offset 0x58: External APIC IRQ output control */ pci_write_config_byte (dev, 0x58, tmp); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); /* * The AMD io apic can hang the box when an apic irq is masked. @@ -368,30 +398,29 @@ * noapic specified. For the moment we assume its the errata. We may be wrong * of course. However the advice is demonstrably good even if so.. */ - static void __devinit quirk_amd_ioapic(struct pci_dev *dev) { u8 rev; pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - if(rev >= 0x02) - { + if (rev >= 0x02) { printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n"); printk(KERN_WARNING " : booting with the \"noapic\" option.\n"); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic ); static void __init quirk_ioapic_rmw(struct pci_dev *dev) { if (dev->devfn == 0 && dev->bus->number == 0) sis_apic_bug = 1; } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw ); #define AMD8131_revA0 0x01 #define AMD8131_revB0 0x11 #define AMD8131_MISC 0x40 #define AMD8131_NIOAMODE_BIT 0 - static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) { unsigned char revid, tmp; @@ -407,6 +436,7 @@ pci_write_config_byte( dev, AMD8131_MISC, tmp); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, quirk_amd_8131_ioapic ); #endif /* CONFIG_X86_IO_APIC */ @@ -444,6 +474,8 @@ if (irq && (irq != 2)) d->irq = irq; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); static void __devinit quirk_via_irqpic(struct pci_dev *dev) { @@ -459,6 +491,9 @@ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic ); /* @@ -480,6 +515,8 @@ legsup &= 0x50ef; pci_write_config_word(dev, 0xc0, legsup); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb ); /* * VIA VT82C598 has its device ID settable and many BIOSes @@ -492,6 +529,7 @@ pci_write_config_byte(dev, 0xfc, 0); pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id ); /* * CardBus controllers have a legacy base address that enables them @@ -505,6 +543,7 @@ return; pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0); } +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy ); /* * Following the PCI ordering rules is optional on the AMD762. I'm not @@ -513,13 +552,11 @@ * To be fair to AMD, it follows the spec by default, its BIOS people * who turn it off! */ - static void __devinit quirk_amd_ordering(struct pci_dev *dev) { u32 pcic; pci_read_config_dword(dev, 0x4C, &pcic); - if((pcic&6)!=6) - { + if ((pcic&6)!=6) { pcic |= 6; printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n"); pci_write_config_dword(dev, 0x4C, pcic); @@ -528,6 +565,7 @@ pci_write_config_dword(dev, 0x84, pcic); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); /* * DreamWorks provided workaround for Dunord I-3000 problem @@ -536,18 +574,26 @@ * assigned to it. We force a larger allocation to ensure that * nothing gets put too close to it. */ - static void __devinit quirk_dunord ( struct pci_dev * dev ) { - struct resource * r = & dev -> resource [ 1 ]; - r -> start = 0; - r -> end = 0xffffff; + struct resource *r = &dev->resource [1]; + r->start = 0; + r->end = 0xffffff; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord ); +/* + * i82380FB mobile docking controller: its PCI-to-PCI bridge + * is subtractive decoding (transparent), and does indicate this + * in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80 + * instead of 0x01. + */ static void __devinit quirk_transparent_bridge(struct pci_dev *dev) { dev->transparent = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge ); /* * Common misconfiguration of the MediaGX/Geode PCI master that will @@ -555,7 +601,6 @@ * datasheets found at http://www.national.com/ds/GX for info on what * these bits do. */ - static void __init quirk_mediagx_master(struct pci_dev *dev) { u8 reg; @@ -566,6 +611,7 @@ pci_write_config_byte(dev, 0x41, reg); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); /* * As per PCI spec, ignore base address registers 0-3 of the IDE controllers @@ -584,7 +630,6 @@ * we do now ? We don't want is pci_enable_device to come along * and assign new resources. Both approaches work for that. */ - static void __devinit quirk_ide_bases(struct pci_dev *dev) { struct resource *res; @@ -616,34 +661,33 @@ printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n", first_bar, last_bar, pci_name(dev)); } +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases ); /* * Ensure C0 rev restreaming is off. This is normally done by * the BIOS but in the odd case it is not the results are corruption * hence the presence of a Linux check */ - static void __init quirk_disable_pxb(struct pci_dev *pdev) { u16 config; u8 rev; pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - if(rev != 0x04) /* Only C0 requires this */ + if (rev != 0x04) /* Only C0 requires this */ return; pci_read_config_word(pdev, 0x40, &config); - if(config & (1<<6)) - { + if (config & (1<<6)) { config &= ~(1<<6); pci_write_config_word(pdev, 0x40, config); printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n"); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); /* * VIA northbridges care about PCI_INTERRUPT_LINE */ - int interrupt_line_quirk; static void __devinit quirk_via_bridge(struct pci_dev *pdev) @@ -651,6 +695,7 @@ if(pdev->devfn == 0) interrupt_line_quirk = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge ); /* * Serverworks CSB5 IDE does not fully support native mode @@ -667,15 +712,16 @@ quirk_ide_bases(pdev); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide ); /* This was originally an Alpha specific thing, but it really fits here. * The i82375 PCI/EISA bridge appears as non-classified. Fix that. */ - static void __init quirk_eisa_bridge(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_EISA << 8; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge ); /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge @@ -689,7 +735,6 @@ * becomes necessary to do this tweak in two steps -- I've chosen the Host * bridge as trigger. */ - static int __initdata asus_hides_smbus = 0; static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) @@ -699,6 +744,7 @@ switch(dev->subsystem_device) { case 0x8070: /* P4B */ case 0x8088: /* P4B533 */ + case 0x1626: /* L3C notebook */ asus_hides_smbus = 1; } if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) @@ -730,8 +776,20 @@ case 0x0890: /* HP Compaq nc6000 */ asus_hides_smbus = 1; } + if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) + switch (dev->subsystem_device) { + case 0x12bc: /* HP D330L */ + asus_hides_smbus = 1; + } } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); static void __init asus_hides_smbus_lpc(struct pci_dev *dev) { @@ -744,12 +802,17 @@ if (val & 0x8) { pci_write_config_word(dev, 0xF2, val & (~0x8)); pci_read_config_word(dev, 0xF2, &val); - if(val & 0x8) + if (val & 0x8) printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); else printk(KERN_INFO "PCI: Enabled i801 SMBus device\n"); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); /* * SiS 96x south bridge: BIOS typically hides SMBus device... @@ -803,6 +866,19 @@ { sis_96x_compatible = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible ); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); #ifdef CONFIG_X86_IO_APIC static void __init quirk_alder_ioapic(struct pci_dev *pdev) @@ -815,16 +891,17 @@ /* the first BAR is the location of the IO APIC...we must * not touch this (and it's already covered by the fixmap), so * forcibly insert it into the resource tree */ - if(pci_resource_start(pdev, 0) && pci_resource_len(pdev, 0)) + if (pci_resource_start(pdev, 0) && pci_resource_len(pdev, 0)) insert_resource(&iomem_resource, &pdev->resource[0]); /* The next five BARs all seem to be rubbish, so just clean * them out */ - for(i=1; i < 6; i++) { + for (i=1; i < 6; i++) { memset(&pdev->resource[i], 0, sizeof(pdev->resource[i])); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic ); #endif #ifdef CONFIG_SCSI_SATA @@ -898,6 +975,7 @@ else request_region(0x170, 8, "libata"); /* port 1 */ } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined ); #endif /* CONFIG_SCSI_SATA */ int pciehp_msi_quirk; @@ -906,163 +984,45 @@ { pciehp_msi_quirk = 1; } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi ); -/* - * The main table of quirks. - * - * Note: any hooks for hotpluggable devices in this table must _NOT_ - * be declared __init. - */ - -static struct pci_fixup pci_fixups[] __devinitdata = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, - /* - * Its not totally clear which chipsets are the problematic ones - * We know 82C586 and 82C596 variants are affected. - */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi }, - - /* Intel LPC interface bridges all have 128 bytes of magic ACPI/TCO regs and 64 bytes of GPIO */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi }, - - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb }, - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge }, - { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy }, - -#ifdef CONFIG_X86_IO_APIC - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, - quirk_amd_8131_ioapic }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic }, -#endif - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic }, - - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce }, - /* - * i82380FB mobile docking controller: its PCI-to-PCI bridge - * is subtractive decoding (transparent), and does indicate this - * in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80 - * instead of 0x01. - */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge }, - - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master }, - - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide }, - - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge }, - - /* - * on Asus P4B boards, the i801SMBus device is disabled at startup. - * this also goes for boards in HP Compaq nc6000 and nc8000 notebooks. - */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc }, - -#ifdef CONFIG_SCSI_SATA - /* Fixup BIOSes that configure Parallel ATA (PATA / IDE) and - * Serial ATA (SATA) into the same PCI ID. - */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, - quirk_intel_ide_combined }, -#endif /* CONFIG_SCSI_SATA */ - - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi }, - - { 0 } -}; - -static void pci_do_fixups(struct pci_dev *dev, int pass, struct pci_fixup *f) +static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { - while (f->pass) { - if (f->pass == pass && - (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && + while (f < end) { + if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { -#ifdef DEBUG - printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); -#endif + pr_debug(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); f->hook(dev); } f++; } } -void pci_fixup_device(int pass, struct pci_dev *dev) -{ - pci_do_fixups(dev, pass, pcibios_fixups); - pci_do_fixups(dev, pass, pci_fixups); +extern struct pci_fixup __start_pci_fixups_header[]; +extern struct pci_fixup __end_pci_fixups_header[]; +extern struct pci_fixup __start_pci_fixups_final[]; +extern struct pci_fixup __end_pci_fixups_final[]; + +void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) +{ + struct pci_fixup *start, *end; + + switch(pass) { + case pci_fixup_header: + start = __start_pci_fixups_header; + end = __end_pci_fixups_header; + break; + + case pci_fixup_final: + start = __start_pci_fixups_final; + end = __end_pci_fixups_final; + break; + default: + /* stupid compiler warning, you would think with an enum... */ + return; + } + pci_do_fixups(dev, start, end); } EXPORT_SYMBOL(pciehp_msi_quirk); diff -Nru a/drivers/pci/remove.c b/drivers/pci/remove.c --- a/drivers/pci/remove.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/pci/remove.c 2004-10-18 14:56:17 -07:00 @@ -59,6 +59,18 @@ } EXPORT_SYMBOL(pci_remove_device_safe); +void pci_remove_bus(struct pci_bus *b) +{ + pci_proc_detach_bus(b); + + spin_lock(&pci_bus_lock); + list_del(&b->node); + spin_unlock(&pci_bus_lock); + + class_device_unregister(&b->class_dev); +} +EXPORT_SYMBOL(pci_remove_bus); + /** * pci_remove_bus_device - remove a PCI device and any children * @dev: the device to remove @@ -77,13 +89,7 @@ struct pci_bus *b = dev->subordinate; pci_remove_behind_bridge(dev); - pci_proc_detach_bus(b); - - spin_lock(&pci_bus_lock); - list_del(&b->node); - spin_unlock(&pci_bus_lock); - - class_device_unregister(&b->class_dev); + pci_remove_bus(b); dev->subordinate = NULL; } diff -Nru a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c --- a/drivers/pci/setup-bus.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/pci/setup-bus.c 2004-10-18 14:57:04 -07:00 @@ -537,10 +537,11 @@ /* Depth first, calculate sizes and alignments of all subordinate buses. */ - for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) + list_for_each(ln, &pci_root_buses) { pci_bus_size_bridges(pci_bus_b(ln)); + } /* Depth last, allocate resources and update the hardware. */ - for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) { + list_for_each(ln, &pci_root_buses) { pci_bus_assign_resources(pci_bus_b(ln)); pci_enable_bridges(pci_bus_b(ln)); } diff -Nru a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c --- a/drivers/pcmcia/au1000_generic.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/pcmcia/au1000_generic.c 2004-10-18 14:56:33 -07:00 @@ -566,7 +566,6 @@ au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) { unsigned int speed; - unsigned long start; u_long flags; if(map->map>=MAX_WIN){ @@ -588,25 +587,19 @@ } spin_lock_irqsave(&pcmcia_lock, flags); - start=map->sys_start; - - if(map->sys_stop==0) - map->sys_stop=MAP_SIZE-1; - if (map->flags & MAP_ATTRIB) { - map->sys_start = pcmcia_socket[sock].phys_attr + + map->static_start = pcmcia_socket[sock].phys_attr + map->card_start; } else { - map->sys_start = pcmcia_socket[sock].phys_mem + + map->static_start = pcmcia_socket[sock].phys_mem + map->card_start; } - map->sys_stop=map->sys_start+(map->sys_stop-start); pcmcia_socket[sock].mem_map[map->map]=*map; spin_unlock_irqrestore(&pcmcia_lock, flags); - debug(3, "set_mem_map %d start %x stop %x card_start %x\n", - map->map, map->sys_start, map->sys_stop, + debug(3, "set_mem_map %d start %x card_start %x\n", + map->map, map->static_start, map->card_start); return 0; diff -Nru a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c --- a/drivers/pcmcia/cardbus.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/pcmcia/cardbus.c 2004-10-18 14:56:27 -07:00 @@ -85,7 +85,7 @@ =====================================================================*/ -static u_int xlate_rom_addr(u_char * b, u_int addr) +static u_int xlate_rom_addr(void __iomem *b, u_int addr) { u_int img = 0, ofs = 0, sz; u_short data; diff -Nru a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c --- a/drivers/pcmcia/cistpl.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/pcmcia/cistpl.c 2004-10-18 14:56:28 -07:00 @@ -103,7 +103,7 @@ * If flags & MAP_ATTRIB, map the attribute space, otherwise * map the memory space. */ -static unsigned char * +static void __iomem * set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) { pccard_mem_map *mem = &s->cis_mem; @@ -114,8 +114,6 @@ printk(KERN_NOTICE "cs: unable to map card memory!\n"); return NULL; } - mem->sys_start = mem->res->start; - mem->sys_stop = mem->res->end; s->cis_virt = ioremap(mem->res->start, s->map_size); } mem->card_start = card_offset; @@ -124,7 +122,7 @@ if (s->features & SS_CAP_STATIC_MAP) { if (s->cis_virt) iounmap(s->cis_virt); - s->cis_virt = ioremap(mem->sys_start, s->map_size); + s->cis_virt = ioremap(mem->static_start, s->map_size); } return s->cis_virt; } @@ -143,7 +141,8 @@ int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, u_int len, void *ptr) { - u_char *sys, *end, *buf = ptr; + void __iomem *sys, *end; + unsigned char *buf = ptr; cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len); @@ -206,7 +205,8 @@ void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, u_int len, void *ptr) { - u_char *sys, *end, *buf = ptr; + void __iomem *sys, *end; + unsigned char *buf = ptr; cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len); diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c --- a/drivers/pcmcia/cs.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/pcmcia/cs.c 2004-10-18 14:56:27 -07:00 @@ -427,8 +427,6 @@ return ret; } /* send_event */ -#define cs_to_timeout(cs) (((cs) * HZ + 99) / 100) - static void socket_remove_drivers(struct pcmcia_socket *skt) { client_t *client; @@ -448,8 +446,7 @@ socket_remove_drivers(skt); skt->state &= SOCKET_INUSE|SOCKET_PRESENT; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(shutdown_delay)); + msleep(shutdown_delay * 10); skt->state &= SOCKET_INUSE; shutdown_socket(skt); } @@ -467,8 +464,7 @@ skt->socket.flags &= ~SS_RESET; skt->ops->set_socket(skt, &skt->socket); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(unreset_delay)); + msleep(unreset_delay * 10); for (i = 0; i < unreset_limit; i++) { skt->ops->get_status(skt, &status); @@ -478,8 +474,7 @@ if (status & SS_READY) return CS_SUCCESS; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(unreset_check)); + msleep(unreset_check * 10); } cs_err(skt, "time out after reset.\n"); @@ -496,8 +491,7 @@ if (!(status & SS_DETECT)) return CS_NO_CARD; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(initial_delay)); + msleep(initial_delay * 10); for (i = 0; i < 100; i++) { skt->ops->get_status(skt, &status); @@ -507,8 +501,7 @@ if (!(status & SS_PENDING)) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(10)); + msleep(100); } if (status & SS_PENDING) { @@ -541,8 +534,7 @@ /* * Wait "vcc_settle" for the supply to stabilise. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(vcc_settle)); + msleep(vcc_settle * 10); skt->ops->get_status(skt, &status); if (!(status & SS_POWERON)) { @@ -659,10 +651,8 @@ if (!(skt->state & SOCKET_SUSPEND)) { int status; - if (!(skt->state & SOCKET_PRESENT)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(2)); - } + if (!(skt->state & SOCKET_PRESENT)) + msleep(20); skt->ops->get_status(skt, &status); if ((skt->state & SOCKET_PRESENT) && @@ -1886,11 +1876,6 @@ (*handle)->dev_info, s); if (!win->ctl.res) return CS_IN_USE; - win->ctl.sys_start = win->ctl.res->start; - win->ctl.sys_stop = win->ctl.res->end; - } else { - win->ctl.sys_start = req->Base; - win->ctl.sys_stop = req->Base + req->Size - 1; } (*handle)->state |= CLIENT_WIN_REQ(w); @@ -1912,7 +1897,11 @@ s->state |= SOCKET_WIN_REQ(w); /* Return window handle */ - req->Base = win->ctl.sys_start; + if (s->features & SS_CAP_STATIC_MAP) { + req->Base = win->ctl.static_start; + } else { + req->Base = win->ctl.res->start; + } *wh = win; return CS_SUCCESS; diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c --- a/drivers/pcmcia/ds.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/pcmcia/ds.c 2004-10-18 14:56:49 -07:00 @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -133,7 +134,7 @@ static int major_dev = -1; -extern struct proc_dir_entry *proc_pccard; +static struct proc_dir_entry *proc_pccard; /*====================================================================*/ @@ -1080,8 +1081,7 @@ * Ugly. But we want to wait for the socket threads to have started up. * We really should let the drivers themselves drive some of this.. */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/4); + msleep(250); init_waitqueue_head(&s->queue); init_waitqueue_head(&s->request); diff -Nru a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c --- a/drivers/pcmcia/hd64465_ss.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/pcmcia/hd64465_ss.c 2004-10-18 14:56:33 -07:00 @@ -636,19 +636,17 @@ hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); struct pccard_mem_map *smem; int map = mem->map; - unsigned long paddr, size; + unsigned long paddr; #if 0 - DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, sys_start=0x%08lx, sys_end=0x%08lx, card_start=0x%08x)\n", - sock, map, mem->flags, mem->sys_start, mem->sys_stop, mem->card_start); + DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, card_start=0x%08x)\n", + sock, map, mem->flags, mem->card_start); #endif if (map >= MAX_WIN) return -EINVAL; smem = &sp->mem_maps[map]; - size = mem->sys_stop - mem->sys_start + 1; - paddr = sp->mem_base; /* base of Attribute mapping */ if (!(mem->flags & MAP_ATTRIB)) paddr += HD64465_PCC_WINDOW; /* base of Common mapping */ @@ -660,8 +658,7 @@ * queries our fixed mapping. I wish this fact had been * documented - Greg Banks. */ - mem->sys_start = paddr; - mem->sys_stop = paddr + size - 1; + mem->static_start = paddr; *smem = *mem; diff -Nru a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c --- a/drivers/pcmcia/i82092.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/pcmcia/i82092.c 2004-10-18 14:57:05 -07:00 @@ -422,7 +422,7 @@ int i; struct resource res = { .start = 0, .end = 0x0fff }; pccard_io_map io = { 0, 0, 0, 0, 1 }; - pccard_mem_map mem = { .res = &res, .sys_stop = 0x0fff, }; + pccard_mem_map mem = { .res = &res, }; enter("i82092aa_init"); @@ -706,11 +706,15 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem) { - unsigned int sock = container_of(socket, struct socket_info, socket)->number; + struct socket_info *sock_info = container_of(socket, struct socket_info, socket); + unsigned int sock = sock_info->number; + struct pci_bus_region region; unsigned short base, i; unsigned char map; enter("i82092aa_set_mem_map"); + + pcibios_resource_to_bus(sock_info->dev, ®ion, mem->res); map = mem->map; if (map > 4) { @@ -719,10 +723,10 @@ } - if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || + if ( (mem->card_start > 0x3ffffff) || (region.start > region.end) || (mem->speed > 1000) ) { leave("i82092aa_set_mem_map: invalid address / speed"); - printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,mem->sys_start, mem->sys_stop, mem->card_start); + printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,region.start, region.end, mem->card_start); return -EINVAL; } @@ -731,11 +735,11 @@ indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_MEM(map)); -/* printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, mem->sys_start,mem->sys_stop,sock,mem->speed,mem->flags & MAP_ACTIVE); */ +/* printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, region.start,region.end,sock,mem->speed,mem->flags & MAP_ACTIVE); */ /* write the start address */ base = I365_MEM(map); - i = (mem->sys_start >> 12) & 0x0fff; + i = (region.start >> 12) & 0x0fff; if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT; if (mem->flags & MAP_0WS) @@ -744,7 +748,7 @@ /* write the stop address */ - i= (mem->sys_stop >> 12) & 0x0fff; + i= (region.end >> 12) & 0x0fff; switch (to_cycles(mem->speed)) { case 0: break; @@ -763,7 +767,7 @@ /* card start */ - i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff; + i = ((mem->card_start - region.start) >> 12) & 0x3fff; if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; if (mem->flags & MAP_ATTRIB) { diff -Nru a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c --- a/drivers/pcmcia/i82365.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/pcmcia/i82365.c 2004-10-18 14:57:03 -07:00 @@ -513,8 +513,7 @@ if (request_irq(irq, i365_count_irq, 0, "scan", i365_count_irq) != 0) return 1; irq_hits = 0; irq_sock = sock; - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); + msleep(10); if (irq_hits) { free_irq(irq, i365_count_irq); debug(2, " spurious hit!\n"); @@ -1159,13 +1158,13 @@ debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5" "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed, - mem->sys_start, mem->sys_stop, mem->card_start); + mem->res->start, mem->res->end, mem->card_start); map = mem->map; if ((map > 4) || (mem->card_start > 0x3ffffff) || - (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) + (mem->res->start > mem->res->end) || (mem->speed > 1000)) return -EINVAL; - if ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)) + if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff)) return -EINVAL; /* Turn off the window before changing anything */ @@ -1173,12 +1172,12 @@ i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); base = I365_MEM(map); - i = (mem->sys_start >> 12) & 0x0fff; + i = (mem->res->start >> 12) & 0x0fff; if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT; if (mem->flags & MAP_0WS) i |= I365_MEM_0WS; i365_set_pair(sock, base+I365_W_START, i); - i = (mem->sys_stop >> 12) & 0x0fff; + i = (mem->res->end >> 12) & 0x0fff; switch (to_cycles(mem->speed)) { case 0: break; case 1: i |= I365_MEM_WS0; break; @@ -1187,7 +1186,7 @@ } i365_set_pair(sock, base+I365_W_STOP, i); - i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff; + i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG; i365_set_pair(sock, base+I365_W_OFF, i); @@ -1309,7 +1308,7 @@ int i; struct resource res = { .start = 0, .end = 0x1000 }; pccard_io_map io = { 0, 0, 0, 0, 1 }; - pccard_mem_map mem = { .res = &res, .sys_stop = 0x1000, }; + pccard_mem_map mem = { .res = &res, }; for (i = 0; i < 2; i++) { io.map = i; diff -Nru a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c --- a/drivers/pcmcia/pd6729.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/pcmcia/pd6729.c 2004-10-18 14:56:50 -07:00 @@ -502,10 +502,10 @@ return -EINVAL; } - if ((mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) { + if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) { printk("pd6729_set_mem_map: invalid address / speed"); /* printk("invalid mem map for socket %i : %lx to %lx with a start of %x\n", - sock, mem->sys_start, mem->sys_stop, mem->card_start); */ + sock, mem->res->start, mem->res->end, mem->card_start); */ return -EINVAL; } @@ -515,7 +515,7 @@ /* write the start address */ base = I365_MEM(map); - i = (mem->sys_start >> 12) & 0x0fff; + i = (mem->res->start >> 12) & 0x0fff; if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT; if (mem->flags & MAP_0WS) @@ -524,7 +524,7 @@ /* write the stop address */ - i= (mem->sys_stop >> 12) & 0x0fff; + i= (mem->res->end >> 12) & 0x0fff; switch (to_cycles(mem->speed)) { case 0: break; @@ -543,11 +543,11 @@ /* Take care of high byte */ indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); - indirect_write(socket, PD67_EXT_DATA, mem->sys_start >> 24); + indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24); /* card start */ - i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff; + i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; if (mem->flags & MAP_ATTRIB) { @@ -577,7 +577,7 @@ int i; struct resource res = { .end = 0x0fff }; pccard_io_map io = { 0, 0, 0, 0, 1 }; - pccard_mem_map mem = { .res = &res, .sys_stop = 0x0fff }; + pccard_mem_map mem = { .res = &res, }; pd6729_set_socket(sock, &dead_socket); for (i = 0; i < 2; i++) { diff -Nru a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c --- a/drivers/pcmcia/pxa2xx_base.c 2004-10-18 14:57:18 -07:00 +++ b/drivers/pcmcia/pxa2xx_base.c 2004-10-18 14:57:18 -07:00 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -177,39 +178,6 @@ ops = (struct pcmcia_low_level *)dev->platform_data; first = ops->first; nr = ops->nr; - - /* Setup GPIOs for PCMCIA/CF alternate function mode. - * - * It would be nice if set_GPIO_mode included support - * for driving GPIO outputs to default high/low state - * before programming GPIOs as outputs. Setting GPIO - * outputs to default high/low state via GPSR/GPCR - * before defining them as outputs should reduce - * the possibility of glitching outputs during GPIO - * setup. This of course assumes external terminators - * are present to hold GPIOs in a defined state. - * - * In the meantime, setup default state of GPIO - * outputs before we enable them as outputs. - */ - - GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | - GPIO_bit(GPIO49_nPWE) | - GPIO_bit(GPIO50_nPIOR) | - GPIO_bit(GPIO51_nPIOW) | - GPIO_bit(GPIO52_nPCE_1) | - GPIO_bit(GPIO53_nPCE_2); - - pxa_gpio_mode(GPIO48_nPOE_MD); - pxa_gpio_mode(GPIO49_nPWE_MD); - pxa_gpio_mode(GPIO50_nPIOR_MD); - pxa_gpio_mode(GPIO51_nPIOW_MD); - pxa_gpio_mode(GPIO52_nPCE_1_MD); - pxa_gpio_mode(GPIO53_nPCE_2_MD); - pxa_gpio_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */ - pxa_gpio_mode(GPIO55_nPREG_MD); - pxa_gpio_mode(GPIO56_nPWAIT_MD); - pxa_gpio_mode(GPIO57_nIOIS16_MD); /* Provide our PXA2xx specific timing routines. */ ops->set_timing = pxa2xx_pcmcia_set_timing; diff -Nru a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c --- a/drivers/pcmcia/pxa2xx_lubbock.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/pcmcia/pxa2xx_lubbock.c 2004-10-18 14:56:50 -07:00 @@ -25,11 +25,41 @@ #include #include #include +#include #include #include "sa1111_generic.h" static int +lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + /* + * Setup default state of GPIO outputs + * before we enable them as outputs. + */ + GPSR(GPIO48_nPOE) = + GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | + GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | + GPIO_bit(GPIO52_nPCE_1) | + GPIO_bit(GPIO53_nPCE_2); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO52_nPCE_1_MD); + pxa_gpio_mode(GPIO53_nPCE_2_MD); + pxa_gpio_mode(GPIO54_pSKTSEL_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + + return sa1111_pcmcia_hw_init(skt); +} + +static int lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { @@ -201,7 +231,7 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = { .owner = THIS_MODULE, - .hw_init = sa1111_pcmcia_hw_init, + .hw_init = lubbock_pcmcia_hw_init, .hw_shutdown = sa1111_pcmcia_hw_shutdown, .socket_state = sa1111_pcmcia_socket_state, .configure_socket = lubbock_pcmcia_configure_socket, diff -Nru a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c --- a/drivers/pcmcia/pxa2xx_mainstone.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/pcmcia/pxa2xx_mainstone.c 2004-10-18 14:56:32 -07:00 @@ -24,6 +24,7 @@ #include #include +#include #include #include "soc_common.h" @@ -38,6 +39,29 @@ static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { + /* + * Setup default state of GPIO outputs + * before we enable them as outputs. + */ + GPSR(GPIO48_nPOE) = + GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | + GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | + GPIO_bit(GPIO85_nPCE_1) | + GPIO_bit(GPIO54_nPCE_2); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO85_nPCE_1_MD); + pxa_gpio_mode(GPIO54_nPCE_2_MD); + pxa_gpio_mode(GPIO79_pSKTSEL_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + skt->irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff -Nru a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c --- a/drivers/pcmcia/rsrc_mgr.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/pcmcia/rsrc_mgr.c 2004-10-18 14:56:33 -07:00 @@ -88,6 +88,9 @@ }; static DECLARE_MUTEX(rsrc_sem); +static unsigned int rsrc_mem_probe; +#define MEM_PROBE_LOW (1 << 0) +#define MEM_PROBE_HIGH (1 << 1) #ifdef CONFIG_PCMCIA_PROBE @@ -301,8 +304,6 @@ { int ret = -1; - s->cis_mem.sys_start = res->start; - s->cis_mem.sys_stop = res->end; s->cis_mem.res = res; s->cis_virt = ioremap(res->start, s->map_size); if (s->cis_virt) { @@ -312,8 +313,6 @@ s->cis_virt = NULL; destroy_cis_cache(s); } - s->cis_mem.sys_start = 0; - s->cis_mem.sys_stop = 0; s->cis_mem.res = NULL; if ((ret != 0) || (info->Chains == 0)) return 0; @@ -325,15 +324,13 @@ { pccard_mem_map map; int i, a = 0, b = -1, d; - void *virt; + void __iomem *virt; virt = ioremap(res->start, s->map_size); if (virt) { map.map = 0; map.flags = MAP_ACTIVE; map.speed = 0; - map.sys_start = res->start; - map.sys_stop = res->end; map.res = res; map.card_start = 0; s->ops->set_mem_map(s, &map); @@ -457,24 +454,21 @@ return do_mem_probe(m->base, m->num, s); } -static void validate_mem(struct pcmcia_socket *s) +static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { resource_map_t *m, mm; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; - static int hi = 0, lo = 0; u_long b, i, ok = 0; - int force_low = !(s->features & SS_CAP_PAGE_REGS); - down(&rsrc_sem); /* We do up to four passes through the list */ - if (!force_low) { - if (hi++ || (inv_probe(mem_db.next, s) > 0)) - goto out; + if (probe_mask & MEM_PROBE_HIGH) { + if (inv_probe(mem_db.next, s) > 0) + return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); } - if (lo++) - goto out; + if ((probe_mask & MEM_PROBE_LOW) == 0) + return; for (m = mem_db.next; m != &mem_db; m = mm.next) { mm = *m; /* Only probe < 1 MB */ @@ -494,38 +488,51 @@ } } } - out: - up(&rsrc_sem); } #else /* CONFIG_PCMCIA_PROBE */ -static void validate_mem(struct pcmcia_socket *s) +static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { - resource_map_t *m, mm; - static int done = 0; + resource_map_t *m, mm; - if (done++ == 0) { - down(&rsrc_sem); for (m = mem_db.next; m != &mem_db; m = mm.next) { - mm = *m; - if (do_mem_probe(mm.base, mm.num, s)) - break; + mm = *m; + if (do_mem_probe(mm.base, mm.num, s)) + break; } - up(&rsrc_sem); - } } #endif /* CONFIG_PCMCIA_PROBE */ +/* + * Locking note: this is the only place where we take + * both rsrc_sem and skt_sem. + */ void pcmcia_validate_mem(struct pcmcia_socket *s) { - down(&s->skt_sem); + if (probe_mem) { + unsigned int probe_mask; + + down(&rsrc_sem); + + probe_mask = MEM_PROBE_LOW; + if (s->features & SS_CAP_PAGE_REGS) + probe_mask = MEM_PROBE_HIGH; - if (probe_mem && s->state & SOCKET_PRESENT) - validate_mem(s); + if (probe_mask & ~rsrc_mem_probe) { + rsrc_mem_probe |= probe_mask; - up(&s->skt_sem); + down(&s->skt_sem); + + if (s->state & SOCKET_PRESENT) + validate_mem(s, probe_mask); + + up(&s->skt_sem); + } + + up(&rsrc_sem); + } } EXPORT_SYMBOL(pcmcia_validate_mem); diff -Nru a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c --- a/drivers/pcmcia/sa1100_h3600.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/pcmcia/sa1100_h3600.c 2004-10-18 14:56:48 -07:00 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -96,8 +97,7 @@ set_h3600_egpio(IPAQ_EGPIO_OPT_ON); clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10*HZ / 1000); + msleep(10); soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff -Nru a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c --- a/drivers/pcmcia/soc_common.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/pcmcia/soc_common.c 2004-10-18 14:56:17 -07:00 @@ -49,6 +49,11 @@ #include "soc_common.h" +/* FIXME: platform dependent resource declaration has to move out of this file */ +#ifdef CONFIG_ARCH_PXA +#include +#endif + #ifdef DEBUG static int pc_debug; @@ -448,9 +453,7 @@ skt->ops->set_timing(skt); - map->sys_stop -= map->sys_start; - map->sys_stop += res->start + map->card_start; - map->sys_start = res->start + map->card_start; + map->static_start = res->start + map->card_start; return 0; } @@ -662,6 +665,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) { struct skt_dev_info *sinfo; + struct soc_pcmcia_socket *skt; int ret, i; down(&soc_pcmcia_sockets_lock); @@ -679,7 +683,7 @@ * Initialise the per-socket structure. */ for (i = 0; i < nr; i++) { - struct soc_pcmcia_socket *skt = &sinfo->skt[i]; + skt = &sinfo->skt[i]; skt->socket.ops = &soc_common_pcmcia_operations; skt->socket.owner = ops->owner; @@ -777,7 +781,7 @@ goto out; do { - struct soc_pcmcia_socket *skt = &sinfo->skt[i]; + skt = &sinfo->skt[i]; del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); diff -Nru a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c --- a/drivers/pcmcia/tcic.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/pcmcia/tcic.c 2004-10-18 14:56:32 -07:00 @@ -829,15 +829,15 @@ debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, " "%#5.5lx-%#5.5lx, %#5.5x)\n", psock, mem->map, mem->flags, - mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); + mem->speed, mem->res->start, mem->res->end, mem->card_start); if ((mem->map > 3) || (mem->card_start > 0x3ffffff) || - (mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) || - (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) + (mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) || + (mem->res->start > mem->res->end) || (mem->speed > 1000)) return -EINVAL; tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); addr = TCIC_MWIN(psock, mem->map); - base = mem->sys_start; len = mem->sys_stop - mem->sys_start; + base = mem->res->start; len = mem->res->end - mem->res->start; if ((len & (len+1)) || (base & len)) return -EINVAL; if (len == 0x0fff) base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT; @@ -846,7 +846,7 @@ tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X); tcic_setw(TCIC_DATA, base); - mmap = mem->card_start - mem->sys_start; + mmap = mem->card_start - mem->res->start; mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK; if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG; tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X); @@ -870,7 +870,7 @@ int i; struct resource res = { .start = 0, .end = 0x1000 }; pccard_io_map io = { 0, 0, 0, 0, 1 }; - pccard_mem_map mem = { .res = &res, .sys_stop = 0x1000, }; + pccard_mem_map mem = { .res = &res, }; for (i = 0; i < 2; i++) { io.map = i; diff -Nru a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c --- a/drivers/pcmcia/yenta_socket.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/pcmcia/yenta_socket.c 2004-10-18 14:56:33 -07:00 @@ -343,14 +343,17 @@ static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + struct pci_bus_region region; int map; unsigned char addr, enable; unsigned int start, stop, card_start; unsigned short word; + pcibios_resource_to_bus(socket->dev, ®ion, mem->res); + map = mem->map; - start = mem->sys_start; - stop = mem->sys_stop; + start = region.start; + stop = region.end; card_start = mem->card_start; if (map > 4 || start > stop || ((start ^ stop) >> 24) || @@ -447,7 +450,7 @@ int i; struct resource res = { .start = 0, .end = 0x0fff }; pccard_io_map io = { 0, 0, 0, 0, 1 }; - pccard_mem_map mem = { .res = &res, .sys_stop = 0x0fff, }; + pccard_mem_map mem = { .res = &res, }; yenta_set_socket(&socket->socket, &dead_socket); for (i = 0; i < 2; i++) { @@ -1088,6 +1091,7 @@ CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250), diff -Nru a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h --- a/drivers/pcmcia/yenta_socket.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/pcmcia/yenta_socket.h 2004-10-18 14:56:28 -07:00 @@ -107,7 +107,7 @@ struct yenta_socket { struct pci_dev *dev; int cb_irq, io_irq; - void *base; + void __iomem *base; struct timer_list poll_timer; struct pcmcia_socket socket; diff -Nru a/drivers/pnp/interface.c b/drivers/pnp/interface.c --- a/drivers/pnp/interface.c 2004-10-18 14:56:11 -07:00 +++ b/drivers/pnp/interface.c 2004-10-18 14:56:11 -07:00 @@ -240,12 +240,14 @@ { struct pnp_dev *dev = to_pnp_dev(dmdev); int i, ret; - pnp_info_buffer_t *buffer = (pnp_info_buffer_t *) - pnp_alloc(sizeof(pnp_info_buffer_t)); - if (!buffer) - return -ENOMEM; + pnp_info_buffer_t *buffer; + if (!dev) return -EINVAL; + + buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); + if (!buffer) + return -ENOMEM; buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; diff -Nru a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c --- a/drivers/pnp/isapnp/core.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/pnp/isapnp/core.c 2004-10-18 14:56:32 -07:00 @@ -655,8 +655,10 @@ if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; option = pnp_register_independent_option(dev); - if (!option) + if (!option) { + kfree(dev); return 1; + } pnp_add_card_device(card,dev); while (1) { diff -Nru a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c --- a/drivers/pnp/pnpbios/bioscalls.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/pnp/pnpbios/bioscalls.c 2004-10-18 14:56:48 -07:00 @@ -69,14 +69,14 @@ #define Q_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(cpu_gdt_table[cpu][(selname) >> 3], __va((u32)(address))); \ -set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \ +set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \ +set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ } while(0) #define Q2_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(cpu_gdt_table[cpu][(selname) >> 3], (u32)(address)); \ -set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \ +set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \ +set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ } while(0) static struct desc_struct bad_bios_desc = { 0, 0x00409200 }; @@ -115,8 +115,8 @@ return PNP_FUNCTION_NOT_SUPPORTED; cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc; /* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave(&pnp_bios_lock, flags); @@ -158,7 +158,7 @@ ); spin_unlock_irqrestore(&pnp_bios_lock, flags); - cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40; put_cpu(); /* If we get here and this is set then the PnP BIOS faulted on us. */ diff -Nru a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c --- a/drivers/pnp/pnpbios/core.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/pnp/pnpbios/core.c 2004-10-18 14:55:54 -07:00 @@ -252,8 +252,10 @@ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; - if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) + if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) { + kfree(node); return -ENODEV; + } if(pnpbios_write_resources_to_node(res, node)<0) { kfree(node); return -1; diff -Nru a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c --- a/drivers/pnp/pnpbios/proc.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/pnp/pnpbios/proc.c 2004-10-18 14:57:04 -07:00 @@ -90,8 +90,10 @@ tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL); if (!tmpbuf) return -ENOMEM; - if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) + if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) { + kfree(tmpbuf); return -EIO; + } escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256; @@ -168,8 +170,10 @@ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -ENOMEM; - if (pnp_bios_get_dev_node(&nodenum, boot, node)) + if (pnp_bios_get_dev_node(&nodenum, boot, node)) { + kfree(node); return -EIO; + } len = node->size - sizeof(struct pnp_bios_node); memcpy(buf, node->data, len); kfree(node); diff -Nru a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c --- a/drivers/pnp/pnpbios/rsparser.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/pnp/pnpbios/rsparser.c 2004-10-18 14:56:28 -07:00 @@ -346,12 +346,12 @@ { unsigned int len, tag; int priority = 0; - struct pnp_option *option; + struct pnp_option *option, *option_independent; if (!p) return NULL; - option = pnp_register_independent_option(dev); + option_independent = option = pnp_register_independent_option(dev); if (!option) return NULL; @@ -428,9 +428,14 @@ case SMALL_TAG_ENDDEP: if (len != 0) goto len_err; + if (option_independent == option) + printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n"); + option = option_independent; break; case SMALL_TAG_END: + if (option_independent != option) + printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_ENDDEP tag\n"); p = p + 2; return (unsigned char *)p; break; diff -Nru a/drivers/pnp/system.c b/drivers/pnp/system.c --- a/drivers/pnp/system.c 2004-10-18 14:57:18 -07:00 +++ b/drivers/pnp/system.c 2004-10-18 14:57:18 -07:00 @@ -104,4 +104,8 @@ return pnp_register_driver(&system_pnp_driver); } -subsys_initcall(pnp_system_init); +/** + * Reserve motherboard resources after PCI claim BARs, + * but before PCI assign resources for uninitialized PCI devices + */ +fs_initcall(pnp_system_init); diff -Nru a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c --- a/drivers/s390/block/dasd_diag.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/s390/block/dasd_diag.c 2004-10-18 14:55:54 -07:00 @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.37 $ + * $Revision: 1.38 $ */ #include @@ -304,8 +304,11 @@ (device->bp_block >> 10), (device->blocks << device->s2b_shift) >> 1); rc = 0; - } else + } else { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "volume has incompatible disk layout"); rc = -EMEDIUMTYPE; + } free_page((long) label); return rc; } diff -Nru a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c --- a/drivers/s390/block/dasd_eckd.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/s390/block/dasd_eckd.c 2004-10-18 14:55:53 -07:00 @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.57 $ + * $Revision: 1.61 $ */ #include @@ -68,6 +68,10 @@ { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4}, { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5}, { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6}, + { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7}, + { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8}, + { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9}, + { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa}, { /* end of list */ }, }; @@ -274,9 +278,11 @@ data->attributes.mode = 0x3; /* ECKD */ - if (private->rdc_data.cu_type == 0x2105 + if ((private->rdc_data.cu_type == 0x2105 || + private->rdc_data.cu_type == 0x2107 || + private->rdc_data.cu_type == 0x1750) && !(private->uses_cdl && trk < 2)) - data->ga_extended |= 0x40; + data->ga_extended |= 0x40; /* Regular Data Format Mode */ geo.cyl = private->rdc_data.no_cyl; geo.head = private->rdc_data.trk_per_cyl; @@ -499,11 +505,13 @@ "sizes of configuration data mismatch" "%d (read) vs %ld (expected)", conf_len, sizeof (struct dasd_eckd_confdata)); + + kfree(conf_data); /* allocated by read_conf_data() */ return 0; /* no errror */ } memcpy(&private->conf_data, conf_data, sizeof (struct dasd_eckd_confdata)); - + kfree(conf_data); /* allocated by read_conf_data() */ return 0; } @@ -903,6 +911,8 @@ switch (cdev->id.cu_type) { case 0x3990: case 0x2105: + case 0x2107: + case 0x1750: return dasd_3990_erp_examine(cqr, irb); case 0x9343: return dasd_9343_erp_examine(cqr, irb); @@ -923,6 +933,8 @@ switch (cdev->id.cu_type) { case 0x3990: case 0x2105: + case 0x2107: + case 0x1750: return dasd_3990_erp_action; case 0x9343: /* Return dasd_9343_erp_action; */ diff -Nru a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c --- a/drivers/s390/block/dcssblk.c 2004-10-18 14:56:18 -07:00 +++ b/drivers/s390/block/dcssblk.c 2004-10-18 14:56:18 -07:00 @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -19,6 +20,7 @@ //#define DCSSBLK_DEBUG /* Debug messages on/off */ #define DCSSBLK_NAME "dcssblk" #define DCSSBLK_MINORS_PER_DISK 1 +#define DCSSBLK_PARM_LEN 400 #ifdef DCSSBLK_DEBUG #define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSSBLK_NAME " debug: " x) @@ -34,6 +36,8 @@ static int dcssblk_release(struct inode *inode, struct file *filp); static int dcssblk_make_request(struct request_queue *q, struct bio *bio); +static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; + static int dcssblk_major; static struct block_device_operations dcssblk_devops = { .owner = THIS_MODULE, @@ -641,6 +645,47 @@ return 0; } +static void +dcssblk_check_params(void) +{ + int rc, i, j, k; + char buf[9]; + struct dcssblk_dev_info *dev_info; + + for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); + i++) { + for (j = i; (dcssblk_segments[j] != ',') && + (dcssblk_segments[j] != '\0') && + (dcssblk_segments[j] != '(') && + (j - i) < 8; j++) + { + buf[j-i] = dcssblk_segments[j]; + } + buf[j-i] = '\0'; + rc = dcssblk_add_store(dcssblk_root_dev, buf, j-i); + if ((rc >= 0) && (dcssblk_segments[j] == '(')) { + for (k = 0; buf[k] != '\0'; k++) + buf[k] = toupper(buf[k]); + if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { + down_read(&dcssblk_devices_sem); + dev_info = dcssblk_get_device_by_name(buf); + up_read(&dcssblk_devices_sem); + if (dev_info) + dcssblk_shared_store(&dev_info->dev, + "0\n", 2); + } + } + while ((dcssblk_segments[j] != ',') && + (dcssblk_segments[j] != '\0')) + { + j++; + } + if (dcssblk_segments[j] == '\0') + break; + i = j; + } +} + /* * The init/exit functions. */ @@ -689,11 +734,22 @@ } dcssblk_major = rc; init_rwsem(&dcssblk_devices_sem); + + dcssblk_check_params(); + PRINT_DEBUG("...finished!\n"); return 0; } module_init(dcssblk_init); module_exit(dcssblk_exit); + +module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); +MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " + "comma-separated list, each name max. 8 chars.\n" + "Adding \"(local)\" to segment name equals echoing 0 to " + "/sys/devices/dcssblk//shared after loading " + "the segment - \n" + "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\""); MODULE_LICENSE("GPL"); diff -Nru a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c --- a/drivers/s390/char/con3215.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/s390/char/con3215.c 2004-10-18 14:56:48 -07:00 @@ -366,10 +366,7 @@ tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -1055,10 +1052,7 @@ raw = (struct raw3215_info *) tty->driver_data; raw3215_flush_buffer(raw); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* diff -Nru a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c --- a/drivers/s390/char/sclp.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/s390/char/sclp.c 2004-10-18 14:56:33 -07:00 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,7 @@ #define SCLP_INIT 0 #define SCLP_RUNNING 1 #define SCLP_READING 2 +#define SCLP_SHUTDOWN 3 #define SCLP_INIT_POLL_INTERVAL 1 #define SCLP_BUSY_POLL_INTERVAL 1 @@ -606,10 +608,12 @@ sccb->mask_length = sizeof(sccb_mask_t); /* copy in the sccb mask of the registered event types */ spin_lock_irqsave(&sclp_lock, flags); - list_for_each(l, &sclp_reg_list) { - t = list_entry(l, struct sclp_register, list); - sccb->receive_mask |= t->receive_mask; - sccb->send_mask |= t->send_mask; + if (!test_bit(SCLP_SHUTDOWN, &sclp_status)) { + list_for_each(l, &sclp_reg_list) { + t = list_entry(l, struct sclp_register, list); + sccb->receive_mask |= t->receive_mask; + sccb->send_mask |= t->send_mask; + } } sccb->sclp_receive_mask = 0; sccb->sclp_send_mask = 0; @@ -647,9 +651,10 @@ /* WRITEMASK failed - we cannot rely on receiving a state change event, so initially, polling is the only alternative for us to ever become operational. */ - if (!timer_pending(&retry_timer) || - !mod_timer(&retry_timer, - jiffies + SCLP_INIT_POLL_INTERVAL*HZ)) { + if (!test_bit(SCLP_SHUTDOWN, &sclp_status) && + (!timer_pending(&retry_timer) || + !mod_timer(&retry_timer, + jiffies + SCLP_INIT_POLL_INTERVAL*HZ))) { retry_timer.function = sclp_init_mask_retry; retry_timer.data = 0; retry_timer.expires = jiffies + @@ -671,6 +676,26 @@ sclp_init_mask(); } +/* Reboot event handler - reset send and receive mask to prevent pending SCLP + * events from interfering with rebooted system. */ +static int +sclp_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + unsigned long flags; + + /* Note: need spinlock to maintain atomicity when accessing global + * variables. */ + spin_lock_irqsave(&sclp_lock, flags); + set_bit(SCLP_SHUTDOWN, &sclp_status); + spin_unlock_irqrestore(&sclp_lock, flags); + sclp_init_mask(); + return NOTIFY_DONE; +} + +static struct notifier_block sclp_reboot_notifier = { + .notifier_call = sclp_reboot_event +}; + /* * sclp setup function. Called early (no kmalloc!) from sclp_console_init(). */ @@ -690,6 +715,10 @@ INIT_LIST_HEAD(&sclp_reg_list); list_add(&sclp_state_change_event.list, &sclp_reg_list); list_add(&sclp_quiesce_event.list, &sclp_reg_list); + + rc = register_reboot_notifier(&sclp_reboot_notifier); + if (rc) + return rc; /* * request the 0x2401 external interrupt diff -Nru a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c --- a/drivers/s390/char/sclp_tty.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/s390/char/sclp_tty.c 2004-10-18 14:57:19 -07:00 @@ -277,10 +277,7 @@ wake_up(&sclp_tty_waitq); /* check if the tty needs a wake up call */ if (sclp_tty != NULL) { - if ((sclp_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - sclp_tty->ldisc.write_wakeup) - (sclp_tty->ldisc.write_wakeup)(sclp_tty); - wake_up_interruptible(&sclp_tty->write_wait); + tty_wakeup(sclp_tty); } } diff -Nru a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c --- a/drivers/s390/char/sclp_vt220.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/s390/char/sclp_vt220.c 2004-10-18 14:56:28 -07:00 @@ -139,10 +139,7 @@ wake_up(&sclp_vt220_waitq); /* Check if the tty needs a wake up call */ if (sclp_vt220_tty != NULL) { - if ((sclp_vt220_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - (sclp_vt220_tty->ldisc.write_wakeup != NULL)) - (sclp_vt220_tty->ldisc.write_wakeup)(sclp_vt220_tty); - wake_up_interruptible(&sclp_vt220_tty->write_wait); + tty_wakeup(sclp_vt220_tty); } } diff -Nru a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c --- a/drivers/s390/cio/blacklist.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/s390/cio/blacklist.c 2004-10-18 14:56:28 -07:00 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/blacklist.c * S/390 common I/O routines -- blacklisting of specific devices - * $Revision: 1.31 $ + * $Revision: 1.33 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -229,7 +229,7 @@ unsigned int irq; CIO_TRACE_EVENT (0, "redoval"); - for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) { + for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { int ret; struct subchannel *sch; diff -Nru a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c --- a/drivers/s390/cio/ccwgroup.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/s390/cio/ccwgroup.c 2004-10-18 14:56:32 -07:00 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup - * $Revision: 1.28 $ + * $Revision: 1.29 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -191,14 +191,12 @@ gdev->cdev[i]->dev.driver_data = gdev; del_drvdata = 1; - *gdev = (struct ccwgroup_device) { - .creator_id = creator_id, - .count = argc, - .dev = { - .bus = &ccwgroup_bus_type, - .parent = root, - .release = ccwgroup_release, - }, + gdev->creator_id = creator_id; + gdev->count = argc; + gdev->dev = (struct device ) { + .bus = &ccwgroup_bus_type, + .parent = root, + .release = ccwgroup_release, }; snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s", diff -Nru a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c --- a/drivers/s390/cio/cio.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/s390/cio/cio.c 2004-10-18 14:57:04 -07:00 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.123 $ + * $Revision: 1.128 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -17,8 +17,8 @@ #include #include #include +#include -#include #include #include #include @@ -141,6 +141,7 @@ sch = (struct subchannel *)(unsigned long)tpi_info->intparm; if (!sch) return 1; + local_bh_disable(); irq_enter (); spin_lock(&sch->lock); memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); @@ -148,6 +149,7 @@ sch->driver->irq(&sch->dev); spin_unlock(&sch->lock); irq_exit (); + __local_bh_enable(); return 1; } @@ -409,10 +411,10 @@ if (ccode) return -ENODEV; - sch->schib.pmcw.ena = 1; - sch->schib.pmcw.isc = isc; - sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; for (retry = 5, ret = 0; retry > 0; retry--) { + sch->schib.pmcw.ena = 1; + sch->schib.pmcw.isc = isc; + sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; ret = cio_modify(sch); if (ret == -ENODEV) break; @@ -463,9 +465,8 @@ */ return -EBUSY; - - sch->schib.pmcw.ena = 0; for (retry = 5, ret = 0; retry > 0; retry--) { + sch->schib.pmcw.ena = 0; ret = cio_modify(sch); if (ret == -ENODEV) break; diff -Nru a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c --- a/drivers/s390/cio/cmf.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/s390/cio/cmf.c 2004-10-18 14:55:46 -07:00 @@ -1,5 +1,5 @@ /* - * linux/drivers/s390/cio/cmf.c ($Revision: 1.15 $) + * linux/drivers/s390/cio/cmf.c ($Revision: 1.16 $) * * Linux on zSeries Channel Measurement Facility support * @@ -526,29 +526,26 @@ time = get_clock() - cdev->private->cmb_start_time; spin_unlock_irqrestore(cdev->ccwlock, flags); - *data = (struct cmbdata) { - /* we only know values before device_busy_time */ - .size = offsetof(struct cmbdata, device_busy_time), - - /* conver to nanoseconds */ - .elapsed_time = (time * 1000) >> 12, - - /* copy data to new structure */ - .ssch_rsch_count = cmb.ssch_rsch_count, - .sample_count = cmb.sample_count, - - /* time fields are converted to nanoseconds while copying */ - .device_connect_time - = time_to_nsec(cmb.device_connect_time), - .function_pending_time - = time_to_nsec(cmb.function_pending_time), - .device_disconnect_time - = time_to_nsec(cmb.device_disconnect_time), - .control_unit_queuing_time - = time_to_nsec(cmb.control_unit_queuing_time), - .device_active_only_time - = time_to_nsec(cmb.device_active_only_time), - }; + memset(data, sizeof(struct cmbdata), 0); + + /* we only know values before device_busy_time */ + data->size = offsetof(struct cmbdata, device_busy_time); + + /* convert to nanoseconds */ + data->elapsed_time = (time * 1000) >> 12; + + /* copy data to new structure */ + data->ssch_rsch_count = cmb.ssch_rsch_count; + data->sample_count = cmb.sample_count; + + /* time fields are converted to nanoseconds while copying */ + data->device_connect_time = time_to_nsec(cmb.device_connect_time); + data->function_pending_time = time_to_nsec(cmb.function_pending_time); + data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time); + data->control_unit_queuing_time + = time_to_nsec(cmb.control_unit_queuing_time); + data->device_active_only_time + = time_to_nsec(cmb.device_active_only_time); return 0; } @@ -739,33 +736,29 @@ time = get_clock() - cdev->private->cmb_start_time; spin_unlock_irqrestore(cdev->ccwlock, flags); - *data = (struct cmbdata) { - /* we only know values before device_busy_time */ - .size = offsetof(struct cmbdata, device_busy_time), - - /* conver to nanoseconds */ - .elapsed_time = (time * 1000) >> 12, - - /* copy data to new structure */ - .ssch_rsch_count = cmb.ssch_rsch_count, - .sample_count = cmb.sample_count, - - /* time fields are converted to nanoseconds while copying */ - .device_connect_time - = time_to_nsec(cmb.device_connect_time), - .function_pending_time - = time_to_nsec(cmb.function_pending_time), - .device_disconnect_time - = time_to_nsec(cmb.device_disconnect_time), - .control_unit_queuing_time - = time_to_nsec(cmb.control_unit_queuing_time), - .device_active_only_time - = time_to_nsec(cmb.device_active_only_time), - .device_busy_time - = time_to_nsec(cmb.device_busy_time), - .initial_command_response_time - = time_to_nsec(cmb.initial_command_response_time), - }; + memset (data, sizeof(struct cmbdata), 0); + + /* we only know values before device_busy_time */ + data->size = offsetof(struct cmbdata, device_busy_time); + + /* conver to nanoseconds */ + data->elapsed_time = (time * 1000) >> 12; + + /* copy data to new structure */ + data->ssch_rsch_count = cmb.ssch_rsch_count; + data->sample_count = cmb.sample_count; + + /* time fields are converted to nanoseconds while copying */ + data->device_connect_time = time_to_nsec(cmb.device_connect_time); + data->function_pending_time = time_to_nsec(cmb.function_pending_time); + data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time); + data->control_unit_queuing_time + = time_to_nsec(cmb.control_unit_queuing_time); + data->device_active_only_time + = time_to_nsec(cmb.device_active_only_time); + data->device_busy_time = time_to_nsec(cmb.device_busy_time); + data->initial_command_response_time + = time_to_nsec(cmb.initial_command_response_time); return 0; } diff -Nru a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c --- a/drivers/s390/cio/css.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/s390/cio/css.c 2004-10-18 14:57:19 -07:00 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/css.c * driver for channel subsystem - * $Revision: 1.80 $ + * $Revision: 1.82 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -278,7 +278,7 @@ { int irq, ret; - for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) { + for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { ret = css_evaluate_subchannel(irq, 1); /* No more memory. It doesn't make sense to continue. No * panic because this can happen in midflight and just @@ -521,6 +521,7 @@ new_slow_sch = kmalloc(sizeof(struct slow_subchannel), GFP_ATOMIC); if (!new_slow_sch) return -ENOMEM; + memset(new_slow_sch, sizeof(struct slow_subchannel), 0); new_slow_sch->schid = schid; spin_lock_irqsave(&slow_subchannel_lock, flags); list_add_tail(&new_slow_sch->slow_list, &slow_subchannels_head); diff -Nru a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c --- a/drivers/s390/cio/device.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/s390/cio/device.c 2004-10-18 14:56:49 -07:00 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device.c * bus driver for ccw devices - * $Revision: 1.120 $ + * $Revision: 1.124 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -540,6 +540,8 @@ return cdev; } +extern int css_get_ssd_info(struct subchannel *sch); + void ccw_device_do_unreg_rereg(void *data) { @@ -581,6 +583,8 @@ device_unregister(&other_sch->dev); } } + /* Update ssd info here. */ + css_get_ssd_info(sch); cdev->private->devno = sch->schib.pmcw.dev; } else need_rename = 0; @@ -633,7 +637,8 @@ sch->dev.driver_data = 0; kfree (cdev->private); kfree (cdev); - goto out; + put_device(&sch->dev); + return; } ret = subchannel_add_files(cdev->dev.parent); @@ -707,18 +712,19 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) { int rc; + struct ccw_device_private *priv; sch->dev.driver_data = cdev; sch->driver = &io_subchannel_driver; cdev->ccwlock = &sch->lock; - *cdev->private = (struct ccw_device_private) { - .devno = sch->schib.pmcw.dev, - .irq = sch->irq, - .state = DEV_STATE_NOT_OPER, - .cmb_list = LIST_HEAD_INIT(cdev->private->cmb_list), - }; - init_waitqueue_head(&cdev->private->wait_q); - init_timer(&cdev->private->timer); + /* Init private data. */ + priv = cdev->private; + priv->devno = sch->schib.pmcw.dev; + priv->irq = sch->irq; + priv->state = DEV_STATE_NOT_OPER; + INIT_LIST_HEAD(&priv->cmb_list); + init_waitqueue_head(&priv->wait_q); + init_timer(&priv->timer); /* Set an initial name for the device. */ snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", diff -Nru a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c --- a/drivers/s390/cio/device_fsm.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/s390/cio/device_fsm.c 2004-10-18 14:56:32 -07:00 @@ -995,6 +995,7 @@ if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; + /* We should also udate ssd info, but this has to wait. */ ccw_device_start_id(cdev, 0); spin_unlock_irqrestore(&sch->lock, flags); } diff -Nru a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c --- a/drivers/s390/cio/device_id.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/s390/cio/device_id.c 2004-10-18 14:55:46 -07:00 @@ -303,10 +303,10 @@ sch = to_subchannel(cdev->dev.parent); irb = (struct irb *) __LC_IRB; - /* Retry sense id for cc=1. */ + /* Retry sense id, if needed. */ if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { - if (irb->scsw.cc == 1) { + if ((irb->scsw.cc == 1) || !irb->scsw.actl) { ret = __ccw_device_sense_id_start(cdev); if (ret && ret != -EBUSY) ccw_device_sense_id_done(cdev, ret); diff -Nru a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c --- a/drivers/s390/cio/qdio.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/s390/cio/qdio.c 2004-10-18 14:56:33 -07:00 @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.84 $" +#define VERSION_QDIO_C "$Revision: 1.86 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher "); @@ -365,7 +365,7 @@ * small window we can miss between resetting it and * checking for PRIMED state */ - if (q->is_iqdio_q) + if (q->is_thinint_q) tiqdio_set_summary_bit((__u32*)q->dev_st_chg_ind); return 0; diff -Nru a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c --- a/drivers/s390/net/ctctty.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/s390/net/ctctty.c 2004-10-18 14:56:32 -07:00 @@ -307,10 +307,7 @@ info->flags &= ~CTC_ASYNC_TX_LINESTAT; if (tty) { - if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } return (skb_queue_empty(&info->tx_queue) ? 0 : 1); @@ -589,9 +586,7 @@ info->lsr |= UART_LSR_TEMT; spin_unlock_irqrestore(&ctc_tty_lock, flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); ex: DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__); return; @@ -1066,8 +1061,7 @@ skb_queue_purge(&info->tx_queue); info->lsr |= UART_LSR_TEMT; } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); info->tty = 0; tty->closing = 0; if (info->blocked_open) { diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c --- a/drivers/s390/net/lcs.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/s390/net/lcs.c 2004-10-18 14:55:55 -07:00 @@ -11,7 +11,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Martin Schwidefsky * - * $Revision: 1.85 $ $Date: 2004/08/04 11:05:43 $ + * $Revision: 1.92 $ $Date: 2004/09/03 08:06:11 $ * * 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 @@ -59,7 +59,7 @@ /** * initialization string for output */ -#define VERSION_LCS_C "$Revision: 1.85 $" +#define VERSION_LCS_C "$Revision: 1.92 $" static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; static char debug_buffer[255]; @@ -70,6 +70,7 @@ static void lcs_tasklet(unsigned long); static void lcs_start_kernel_thread(struct lcs_card *card); static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); +static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *); /** * Debug Facility Stuff @@ -100,9 +101,9 @@ return -ENOMEM; } debug_register_view(lcs_dbf_setup, &debug_hex_ascii_view); - debug_set_level(lcs_dbf_setup, 2); + debug_set_level(lcs_dbf_setup, 4); debug_register_view(lcs_dbf_trace, &debug_hex_ascii_view); - debug_set_level(lcs_dbf_trace, 2); + debug_set_level(lcs_dbf_trace, 4); return 0; } @@ -316,7 +317,106 @@ init_waitqueue_head(&card->write.wait_q); } +static void +lcs_set_allowed_threads(struct lcs_card *card, unsigned long threads) +{ + unsigned long flags; + + spin_lock_irqsave(&card->mask_lock, flags); + card->thread_allowed_mask = threads; + spin_unlock_irqrestore(&card->mask_lock, flags); + wake_up(&card->wait_q); +} +static inline int +lcs_threads_running(struct lcs_card *card, unsigned long threads) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&card->mask_lock, flags); + rc = (card->thread_running_mask & threads); + spin_unlock_irqrestore(&card->mask_lock, flags); + return rc; +} + +static int +lcs_wait_for_threads(struct lcs_card *card, unsigned long threads) +{ + return wait_event_interruptible(card->wait_q, + lcs_threads_running(card, threads) == 0); +} + +static inline int +lcs_set_thread_start_bit(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + + spin_lock_irqsave(&card->mask_lock, flags); + if ( !(card->thread_allowed_mask & thread) || + (card->thread_start_mask & thread) ) { + spin_unlock_irqrestore(&card->mask_lock, flags); + return -EPERM; + } + card->thread_start_mask |= thread; + spin_unlock_irqrestore(&card->mask_lock, flags); + return 0; +} + +static void +lcs_clear_thread_running_bit(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + + spin_lock_irqsave(&card->mask_lock, flags); + card->thread_running_mask &= ~thread; + spin_unlock_irqrestore(&card->mask_lock, flags); + wake_up(&card->wait_q); +} + +static inline int +__lcs_do_run_thread(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&card->mask_lock, flags); + if (card->thread_start_mask & thread){ + if ((card->thread_allowed_mask & thread) && + !(card->thread_running_mask & thread)){ + rc = 1; + card->thread_start_mask &= ~thread; + card->thread_running_mask |= thread; + } else + rc = -EPERM; + } + spin_unlock_irqrestore(&card->mask_lock, flags); + return rc; +} +static int +lcs_do_run_thread(struct lcs_card *card, unsigned long thread) +{ + int rc = 0; + wait_event(card->wait_q, + (rc = __lcs_do_run_thread(card, thread)) >= 0); + return rc; +} + +static int +lcs_do_start_thread(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&card->mask_lock, flags); + LCS_DBF_TEXT_(4, trace, " %02x%02x%02x", + (u8) card->thread_start_mask, + (u8) card->thread_allowed_mask, + (u8) card->thread_running_mask); + rc = (card->thread_start_mask & thread); + spin_unlock_irqrestore(&card->mask_lock, flags); + return rc; +} /** * Initialize channels,card and state machines. @@ -337,34 +437,53 @@ /* Initialize kernel thread task used for LGW commands. */ INIT_WORK(&card->kernel_thread_starter, (void *)lcs_start_kernel_thread,card); - card->thread_mask = 0; + card->thread_start_mask = 0; + card->thread_allowed_mask = 0; + card->thread_running_mask = 0; + init_waitqueue_head(&card->wait_q); spin_lock_init(&card->lock); spin_lock_init(&card->ipm_lock); + spin_lock_init(&card->mask_lock); #ifdef CONFIG_IP_MULTICAST INIT_LIST_HEAD(&card->ipm_list); #endif INIT_LIST_HEAD(&card->lancmd_waiters); } +static inline void +lcs_clear_multicast_list(struct lcs_card *card) +{ +#ifdef CONFIG_IP_MULTICAST + struct lcs_ipm_list *ipm; + unsigned long flags; + + /* Free multicast list. */ + LCS_DBF_TEXT(3, setup, "clmclist"); + spin_lock_irqsave(&card->ipm_lock, flags); + while (!list_empty(&card->ipm_list)){ + ipm = list_entry(card->ipm_list.next, + struct lcs_ipm_list, list); + list_del(&ipm->list); + if (ipm->ipm_state != LCS_IPM_STATE_SET_REQUIRED){ + spin_unlock_irqrestore(&card->ipm_lock, flags); + lcs_send_delipm(card, ipm); + spin_lock_irqsave(&card->ipm_lock, flags); + } + kfree(ipm); + } + spin_unlock_irqrestore(&card->ipm_lock, flags); +#endif +} /** * Cleanup channels,card and state machines. */ static void lcs_cleanup_card(struct lcs_card *card) { - struct list_head *l, *n; - struct lcs_ipm_list *ipm_list; LCS_DBF_TEXT(3, setup, "cleancrd"); LCS_DBF_HEX(2,setup,&card,sizeof(void*)); -#ifdef CONFIG_IP_MULTICAST - /* Free multicast list. */ - list_for_each_safe(l, n, &card->ipm_list) { - ipm_list = list_entry(l, struct lcs_ipm_list, list); - list_del(&ipm_list->list); - kfree(ipm_list); - } -#endif + if (card->dev != NULL) free_netdev(card->dev); /* Cleanup channels. */ @@ -651,6 +770,44 @@ return buffer; } + +static void +lcs_get_reply(struct lcs_reply *reply) +{ + WARN_ON(atomic_read(&reply->refcnt) <= 0); + atomic_inc(&reply->refcnt); +} + +static void +lcs_put_reply(struct lcs_reply *reply) +{ + WARN_ON(atomic_read(&reply->refcnt) <= 0); + if (atomic_dec_and_test(&reply->refcnt)) { + kfree(reply); + } + +} + +static struct lcs_reply * +lcs_alloc_reply(struct lcs_cmd *cmd) +{ + struct lcs_reply *reply; + + LCS_DBF_TEXT(4, trace, "getreply"); + + reply = kmalloc(sizeof(struct lcs_reply), GFP_ATOMIC); + if (!reply) + return NULL; + memset(reply,0,sizeof(struct lcs_reply)); + atomic_set(&reply->refcnt,1); + reply->sequence_no = cmd->sequence_no; + reply->received = 0; + reply->rc = 0; + init_waitqueue_head(&reply->wait_q); + + return reply; +} + /** * Notifier function for lancmd replies. Called from read irq. */ @@ -665,12 +822,14 @@ list_for_each_safe(l, n, &card->lancmd_waiters) { reply = list_entry(l, struct lcs_reply, list); if (reply->sequence_no == cmd->sequence_no) { - list_del(&reply->list); + lcs_get_reply(reply); + list_del_init(&reply->list); if (reply->callback != NULL) reply->callback(card, cmd); reply->received = 1; reply->rc = cmd->return_code; wake_up(&reply->wait_q); + lcs_put_reply(reply); break; } } @@ -683,50 +842,66 @@ void lcs_lancmd_timeout(unsigned long data) { - struct lcs_reply *reply; + struct lcs_reply *reply, *list_reply, *r; + unsigned long flags; LCS_DBF_TEXT(4, trace, "timeout"); reply = (struct lcs_reply *) data; - list_del(&reply->list); - reply->received = 1; - reply->rc = -ETIME; - wake_up(&reply->wait_q); + spin_lock_irqsave(&reply->card->lock, flags); + list_for_each_entry_safe(list_reply, r, + &reply->card->lancmd_waiters,list) { + if (reply == list_reply) { + lcs_get_reply(reply); + list_del_init(&reply->list); + spin_unlock_irqrestore(&reply->card->lock, flags); + reply->received = 1; + reply->rc = -ETIME; + wake_up(&reply->wait_q); + lcs_put_reply(reply); + return; + } + } + spin_unlock_irqrestore(&reply->card->lock, flags); } static int lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer, void (*reply_callback)(struct lcs_card *, struct lcs_cmd *)) { - struct lcs_reply reply; + struct lcs_reply *reply; struct lcs_cmd *cmd; struct timer_list timer; + unsigned long flags; int rc; LCS_DBF_TEXT(4, trace, "sendcmd"); cmd = (struct lcs_cmd *) buffer->data; - cmd->sequence_no = ++card->sequence_no; cmd->return_code = 0; - reply.sequence_no = cmd->sequence_no; - reply.callback = reply_callback; - reply.received = 0; - reply.rc = 0; - init_waitqueue_head(&reply.wait_q); - spin_lock(&card->lock); - list_add_tail(&reply.list, &card->lancmd_waiters); - spin_unlock(&card->lock); + cmd->sequence_no = card->sequence_no++; + reply = lcs_alloc_reply(cmd); + if (!reply) + return -ENOMEM; + reply->callback = reply_callback; + reply->card = card; + spin_lock_irqsave(&card->lock, flags); + list_add_tail(&reply->list, &card->lancmd_waiters); + spin_unlock_irqrestore(&card->lock, flags); + buffer->callback = lcs_release_buffer; rc = lcs_ready_buffer(&card->write, buffer); if (rc) return rc; init_timer(&timer); timer.function = lcs_lancmd_timeout; - timer.data = (unsigned long) &reply; + timer.data = (unsigned long) reply; timer.expires = jiffies + HZ*card->lancmd_timeout; add_timer(&timer); - wait_event(reply.wait_q, reply.received); - del_timer(&timer); - LCS_DBF_TEXT_(4, trace, "rc:%d",reply.rc); - return reply.rc ? -EIO : 0; + wait_event(reply->wait_q, reply->received); + del_timer_sync(&timer); + LCS_DBF_TEXT_(4, trace, "rc:%d",reply->rc); + rc = reply->rc; + lcs_put_reply(reply); + return rc ? -EIO : 0; } /** @@ -940,33 +1115,56 @@ static void lcs_fix_multicast_list(struct lcs_card *card) { - struct list_head *l, *n; - struct lcs_ipm_list *ipm; + struct list_head failed_list; + struct lcs_ipm_list *ipm, *tmp; + unsigned long flags; + int rc; LCS_DBF_TEXT(4,trace, "fixipm"); - spin_lock(&card->ipm_lock); - list_for_each_safe(l, n, &card->ipm_list) { - ipm = list_entry(l, struct lcs_ipm_list, list); + INIT_LIST_HEAD(&failed_list); + spin_lock_irqsave(&card->ipm_lock, flags); +list_modified: + list_for_each_entry_safe(ipm, tmp, &card->ipm_list, list){ switch (ipm->ipm_state) { case LCS_IPM_STATE_SET_REQUIRED: - if (lcs_send_setipm(card, ipm)) + /* del from ipm_list so noone else can tamper with + * this entry */ + list_del_init(&ipm->list); + spin_unlock_irqrestore(&card->ipm_lock, flags); + rc = lcs_send_setipm(card, ipm); + spin_lock_irqsave(&card->ipm_lock, flags); + if (rc) { PRINT_INFO("Adding multicast address failed." "Table possibly full!\n"); - else + /* store ipm in failed list -> will be added + * to ipm_list again, so a retry will be done + * during the next call of this function */ + list_add_tail(&ipm->list, &failed_list); + } else { ipm->ipm_state = LCS_IPM_STATE_ON_CARD; - break; + /* re-insert into ipm_list */ + list_add_tail(&ipm->list, &card->ipm_list); + } + goto list_modified; case LCS_IPM_STATE_DEL_REQUIRED: - lcs_send_delipm(card, ipm); list_del(&ipm->list); + spin_unlock_irqrestore(&card->ipm_lock, flags); + lcs_send_delipm(card, ipm); + spin_lock_irqsave(&card->ipm_lock, flags); kfree(ipm); - break; + goto list_modified; case LCS_IPM_STATE_ON_CARD: break; } } + /* re-insert all entries from the failed_list into ipm_list */ + list_for_each_entry(ipm, &failed_list, list) { + list_del_init(&ipm->list); + list_add_tail(&ipm->list, &card->ipm_list); + } + spin_unlock_irqrestore(&card->ipm_lock, flags); if (card->state == DEV_STATE_UP) netif_wake_queue(card->dev); - spin_unlock(&card->ipm_lock); } /** @@ -985,51 +1183,67 @@ /** * function called by net device to handle multicast address relevant things */ -static int -lcs_register_mc_addresses(void *data) +static inline void +lcs_remove_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) { - struct lcs_card *card; - char buf[MAX_ADDR_LEN]; - struct list_head *l; struct ip_mc_list *im4; - struct in_device *in4_dev; - struct lcs_ipm_list *ipm, *tmp; - - daemonize("regipm"); - LCS_DBF_TEXT(4, trace, "regmulti"); + struct list_head *l; + struct lcs_ipm_list *ipm; + unsigned long flags; + char buf[MAX_ADDR_LEN]; - card = (struct lcs_card *) data; - in4_dev = in_dev_get(card->dev); - if (in4_dev == NULL) - return 0; - read_lock(&in4_dev->lock); - spin_lock(&card->ipm_lock); - /* Check for multicast addresses to be removed. */ + LCS_DBF_TEXT(4, trace, "remmclst"); + spin_lock_irqsave(&card->ipm_lock, flags); list_for_each(l, &card->ipm_list) { ipm = list_entry(l, struct lcs_ipm_list, list); for (im4 = in4_dev->mc_list; im4 != NULL; im4 = im4->next) { lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); - if (memcmp(buf, &ipm->ipm.mac_addr, - LCS_MAC_LENGTH) == 0 && - ipm->ipm.ip_addr == im4->multiaddr) + if ( (ipm->ipm.ip_addr == im4->multiaddr) && + (memcmp(buf, &ipm->ipm.mac_addr, + LCS_MAC_LENGTH) == 0) ) break; } if (im4 == NULL) ipm->ipm_state = LCS_IPM_STATE_DEL_REQUIRED; } - /* Check for multicast addresses to be added. */ + spin_unlock_irqrestore(&card->ipm_lock, flags); +} + +static inline struct lcs_ipm_list * +lcs_check_addr_entry(struct lcs_card *card, struct ip_mc_list *im4, char *buf) +{ + struct lcs_ipm_list *tmp, *ipm = NULL; + struct list_head *l; + unsigned long flags; + + LCS_DBF_TEXT(4, trace, "chkmcent"); + spin_lock_irqsave(&card->ipm_lock, flags); + list_for_each(l, &card->ipm_list) { + tmp = list_entry(l, struct lcs_ipm_list, list); + if ( (tmp->ipm.ip_addr == im4->multiaddr) && + (memcmp(buf, &tmp->ipm.mac_addr, + LCS_MAC_LENGTH) == 0) ) { + ipm = tmp; + break; + } + } + spin_unlock_irqrestore(&card->ipm_lock, flags); + return ipm; +} + +static inline void +lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) +{ + + struct ip_mc_list *im4; + struct lcs_ipm_list *ipm; + char buf[MAX_ADDR_LEN]; + unsigned long flags; + + LCS_DBF_TEXT(4, trace, "setmclst"); for (im4 = in4_dev->mc_list; im4; im4 = im4->next) { lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); - ipm = NULL; - list_for_each(l, &card->ipm_list) { - tmp = list_entry(l, struct lcs_ipm_list, list); - if (memcmp(buf, &tmp->ipm.mac_addr, - LCS_MAC_LENGTH) == 0 && - tmp->ipm.ip_addr == im4->multiaddr) { - ipm = tmp; - break; - } - } + ipm = lcs_check_addr_entry(card, im4, buf); if (ipm != NULL) continue; /* Address already in list. */ ipm = (struct lcs_ipm_list *) @@ -1043,12 +1257,37 @@ memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); ipm->ipm.ip_addr = im4->multiaddr; ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED; + spin_lock_irqsave(&card->ipm_lock, flags); list_add(&ipm->list, &card->ipm_list); + spin_unlock_irqrestore(&card->ipm_lock, flags); } - spin_unlock(&card->ipm_lock); - read_unlock(&in4_dev->lock); +} + +static int +lcs_register_mc_addresses(void *data) +{ + struct lcs_card *card; + struct in_device *in4_dev; + + card = (struct lcs_card *) data; + daemonize("regipm"); + + if (!lcs_do_run_thread(card, LCS_SET_MC_THREAD)) + return 0; + LCS_DBF_TEXT(4, trace, "regmulti"); + + in4_dev = in_dev_get(card->dev); + if (in4_dev == NULL) + goto out; + read_lock(&in4_dev->mc_list_lock); + lcs_remove_mc_addresses(card,in4_dev); + lcs_set_mc_addresses(card, in4_dev); + read_unlock(&in4_dev->mc_list_lock); in_dev_put(in4_dev); + lcs_fix_multicast_list(card); +out: + lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD); return 0; } /** @@ -1062,8 +1301,10 @@ LCS_DBF_TEXT(4, trace, "setmulti"); card = (struct lcs_card *) dev->priv; - set_bit(3, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + + if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) { + schedule_work(&card->kernel_thread_starter); + } } #endif /* CONFIG_IP_MULTICAST */ @@ -1427,6 +1668,7 @@ return -EIO; } + /** * LCS Stop card */ @@ -1440,6 +1682,7 @@ if (card->read.state != CH_STATE_STOPPED && card->write.state != CH_STATE_STOPPED && card->state == DEV_STATE_UP) { + lcs_clear_multicast_list(card); rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); rc = lcs_send_shutdown(card); } @@ -1459,6 +1702,9 @@ card = (struct lcs_card *) data; daemonize("lgwstpln"); + + if (!lcs_do_run_thread(card, LCS_STARTLAN_THREAD)) + return 0; LCS_DBF_TEXT(4, trace, "lgwstpln"); if (card->dev) netif_stop_queue(card->dev); @@ -1471,6 +1717,7 @@ } else PRINT_ERR("LCS Startlan for device %s failed!\n", card->dev->name); + lcs_clear_thread_running_bit(card, LCS_STARTLAN_THREAD); return 0; } @@ -1485,8 +1732,11 @@ struct lcs_card *card; card = (struct lcs_card *) data; - daemonize("lgwstpln"); - LCS_DBF_TEXT(4, trace, "lgwstpln"); + daemonize("lgwstaln"); + + if (!lcs_do_run_thread(card, LCS_STARTUP_THREAD)) + return 0; + LCS_DBF_TEXT(4, trace, "lgwstaln"); if (card->dev) netif_stop_queue(card->dev); rc = lcs_send_startup(card, LCS_INITIATOR_LGW); @@ -1511,6 +1761,7 @@ else PRINT_ERR("LCS Startup for device %s failed!\n", card->dev->name); + lcs_clear_thread_running_bit(card, LCS_STARTUP_THREAD); return 0; } @@ -1526,6 +1777,9 @@ card = (struct lcs_card *) data; daemonize("lgwstop"); + + if (!lcs_do_run_thread(card, LCS_STOPLAN_THREAD)) + return 0; LCS_DBF_TEXT(4, trace, "lgwstop"); if (card->dev) netif_stop_queue(card->dev); @@ -1539,6 +1793,7 @@ rc = lcs_resetcard(card); if (rc != 0) rc = lcs_stopcard(card); + lcs_clear_thread_running_bit(card, LCS_STOPLAN_THREAD); return rc; } @@ -1549,14 +1804,14 @@ lcs_start_kernel_thread(struct lcs_card *card) { LCS_DBF_TEXT(5, trace, "krnthrd"); - if (test_and_clear_bit(0, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_STARTUP_THREAD)) kernel_thread(lcs_lgw_startup_thread, (void *) card, SIGCHLD); - if (test_and_clear_bit(1, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_STARTLAN_THREAD)) kernel_thread(lcs_lgw_startlan_thread, (void *) card, SIGCHLD); - if (test_and_clear_bit(2, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_STOPLAN_THREAD)) kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD); #ifdef CONFIG_IP_MULTICAST - if (test_and_clear_bit(3, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_SET_MC_THREAD)) kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD); #endif } @@ -1571,16 +1826,19 @@ if (cmd->initiator == LCS_INITIATOR_LGW) { switch(cmd->cmd_code) { case LCS_CMD_STARTUP: - set_bit(0, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + if (!lcs_set_thread_start_bit(card, + LCS_STARTUP_THREAD)) + schedule_work(&card->kernel_thread_starter); break; case LCS_CMD_STARTLAN: - set_bit(1, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + if (!lcs_set_thread_start_bit(card, + LCS_STARTLAN_THREAD)) + schedule_work(&card->kernel_thread_starter); break; case LCS_CMD_STOPLAN: - set_bit(2, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + if (!lcs_set_thread_start_bit(card, + LCS_STOPLAN_THREAD)) + schedule_work(&card->kernel_thread_starter); break; default: PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); @@ -1953,7 +2211,9 @@ card->dev->set_multicast_list = lcs_set_multicast_list; #endif netif_stop_queue(card->dev); + lcs_set_allowed_threads(card,0xffffffff); if (recover_state == DEV_STATE_RECOVER) { + lcs_set_multicast_list(card->dev); card->dev->flags |= IFF_UP; netif_wake_queue(card->dev); card->state = DEV_STATE_UP; @@ -1982,7 +2242,9 @@ card = (struct lcs_card *)ccwgdev->dev.driver_data; if (!card) return -ENODEV; - + lcs_set_allowed_threads(card, 0); + if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD)) + return -ERESTARTSYS; LCS_DBF_HEX(3, setup, &card, sizeof(void*)); recover_state = card->state; diff -Nru a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h --- a/drivers/s390/net/lcs.h 2004-10-18 14:56:48 -07:00 +++ b/drivers/s390/net/lcs.h 2004-10-18 14:56:48 -07:00 @@ -6,7 +6,7 @@ #include #include -#define VERSION_LCS_H "$Revision: 1.17 $" +#define VERSION_LCS_H "$Revision: 1.18 $" #define LCS_DBF_TEXT(level, name, text) \ do { \ @@ -152,6 +152,12 @@ DEV_STATE_RECOVER, }; +enum lcs_threads { + LCS_SET_MC_THREAD = 1, + LCS_STARTLAN_THREAD = 2, + LCS_STOPLAN_THREAD = 4, + LCS_STARTUP_THREAD = 8, +}; /** * LCS struct declarations */ @@ -247,9 +253,11 @@ struct lcs_reply { struct list_head list; __u16 sequence_no; + atomic_t refcnt; /* Callback for completion notification. */ void (*callback)(struct lcs_card *, struct lcs_cmd *); wait_queue_head_t wait_q; + struct lcs_card *card; int received; int rc; }; @@ -268,6 +276,7 @@ int buf_idx; }; + /** * definition of the lcs card */ @@ -287,7 +296,11 @@ int lancmd_timeout; struct work_struct kernel_thread_starter; - unsigned long thread_mask; + spinlock_t mask_lock; + unsigned long thread_start_mask; + unsigned long thread_running_mask; + unsigned long thread_allowed_mask; + wait_queue_head_t wait_q; #ifdef CONFIG_IP_MULTICAST struct list_head ipm_list; diff -Nru a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c --- a/drivers/s390/net/qeth_main.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/s390/net/qeth_main.c 2004-10-18 14:56:31 -07:00 @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.130 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.145 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier * - * $Revision: 1.130 $ $Date: 2004/08/05 11:21:50 $ + * $Revision: 1.145 $ $Date: 2004/10/08 15:08:40 $ * * 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 @@ -73,12 +73,13 @@ #include #include #include +#include #include "qeth.h" #include "qeth_mpc.h" #include "qeth_fs.h" -#define VERSION_QETH_C "$Revision: 1.130 $" +#define VERSION_QETH_C "$Revision: 1.145 $" static const char *version = "qeth S/390 OSA-Express driver"; /** @@ -2147,7 +2148,7 @@ skb->mac.raw = skb->data; skb_pull(skb, ETH_ALEN * 2 + sizeof (short)); - eth = skb->mac.ethernet; + eth = eth_hdr(skb); if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) @@ -3834,6 +3835,7 @@ /* return EBUSY because we sent old packet, not * the current one */ rc = -EBUSY; + atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); goto out; } } @@ -4372,12 +4374,13 @@ /* skip 4 bytes (data_len struct member) to get req_len */ if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int))) return -EFAULT; - ureq = kmalloc(req_len, GFP_KERNEL); + ureq = kmalloc(req_len+sizeof(struct qeth_snmp_ureq_hdr), GFP_KERNEL); if (!ureq) { QETH_DBF_TEXT(trace, 2, "snmpnome"); return -ENOMEM; } - if (copy_from_user(ureq, udata, req_len)){ + if (copy_from_user(ureq, udata, + req_len+sizeof(struct qeth_snmp_ureq_hdr))){ kfree(ureq); return -EFAULT; } @@ -4546,7 +4549,8 @@ if (!card) return -ENODEV; - if (card->state != CARD_STATE_UP) + if ((card->state != CARD_STATE_UP) && + (card->state != CARD_STATE_SOFTSETUP)) return -ENODEV; switch (cmd){ @@ -4733,9 +4737,10 @@ QETH_DBF_TEXT(trace, 4, "frvaddr4"); if (!card->vlangrp) return; - in_dev = in_dev_get(card->vlangrp->vlan_devices[vid]); + rcu_read_lock(); + in_dev = __in_dev_get(card->vlangrp->vlan_devices[vid]); if (!in_dev) - return; + goto out; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next){ addr = qeth_get_addr_buffer(QETH_PROT_IPV4); if (addr){ @@ -4746,7 +4751,8 @@ kfree(addr); } } - in_dev_put(in_dev); +out: + rcu_read_unlock(); } static void @@ -4918,9 +4924,9 @@ in_dev = in_dev_get(vg->vlan_devices[i]); if (!in_dev) continue; - read_lock(&in_dev->lock); + read_lock(&in_dev->mc_list_lock); qeth_add_mc(card,in_dev); - read_unlock(&in_dev->lock); + read_unlock(&in_dev->mc_list_lock); in_dev_put(in_dev); } #endif @@ -4935,10 +4941,10 @@ in4_dev = in_dev_get(card->dev); if (in4_dev == NULL) return; - read_lock(&in4_dev->lock); + read_lock(&in4_dev->mc_list_lock); qeth_add_mc(card, in4_dev); qeth_add_vlan_mc(card); - read_unlock(&in4_dev->lock); + read_unlock(&in4_dev->mc_list_lock); in_dev_put(in4_dev); } @@ -5739,7 +5745,7 @@ QETH_DBF_TEXT(trace,3,"ipaipfrg"); if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { - PRINT_INFO("IP fragmentation not supported on %s\n", + PRINT_INFO("Hardware IP fragmentation not supported on %s\n", card->info.if_name); return -EOPNOTSUPP; } @@ -5747,11 +5753,11 @@ rc = qeth_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start IP fragmentation " + PRINT_WARN("Could not start Hardware IP fragmentation " "assist on %s: 0x%x\n", card->info.if_name, rc); } else - PRINT_INFO("IP fragmentation enabled \n"); + PRINT_INFO("Hardware IP fragmentation enabled \n"); return rc; } @@ -6706,19 +6712,26 @@ qeth_arp_constructor(struct neighbour *neigh) { struct net_device *dev = neigh->dev; - struct in_device *in_dev = in_dev_get(dev); + struct in_device *in_dev; + struct neigh_parms *parms; - if (in_dev == NULL) - return -EINVAL; if (!qeth_verify_dev(dev)) { - in_dev_put(in_dev); return qeth_old_arp_constructor(neigh); } + rcu_read_lock(); + in_dev = rcu_dereference(__in_dev_get(dev)); + if (in_dev == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + + parms = in_dev->arp_parms; + __neigh_parms_put(neigh->parms); + neigh->parms = neigh_parms_clone(parms); + rcu_read_unlock(); + neigh->type = inet_addr_type(*(u32 *) neigh->primary_key); - if (in_dev->arp_parms) - neigh->parms = in_dev->arp_parms; - in_dev_put(in_dev); neigh->nud_state = NUD_NOARP; neigh->ops = arp_direct_ops; neigh->output = neigh->ops->queue_xmit; diff -Nru a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h --- a/drivers/s390/s390mach.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/s390/s390mach.h 2004-10-18 14:56:33 -07:00 @@ -63,10 +63,6 @@ #define CRW_ERC_PERRI 0x07 /* perm. error, facility init */ #define CRW_ERC_PMOD 0x08 /* installed parameters modified */ -#define MCHCHK_STATUS_TO_PROCESS 0x00000001 -#define MCHCHK_STATUS_IN_PROGRESS 0x00000002 -#define MCHCHK_STATUS_WAITING 0x00000004 - extern __inline__ int stcrw(struct crw *pcrw ) { int ccode; diff -Nru a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c --- a/drivers/s390/scsi/zfcp_aux.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/s390/scsi/zfcp_aux.c 2004-10-18 14:57:05 -07:00 @@ -29,7 +29,7 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_AUX_REVISION "$Revision: 1.115 $" +#define ZFCP_AUX_REVISION "$Revision: 1.129 $" #include "zfcp_ext.h" @@ -47,11 +47,11 @@ /* miscellaneous */ static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); -static inline int zfcp_sg_list_free(struct zfcp_sg_list *); -static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, void *, - size_t); -static inline int zfcp_sg_list_copy_to_user(void *, struct zfcp_sg_list *, - size_t); +static inline void zfcp_sg_list_free(struct zfcp_sg_list *); +static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, + void __user *, size_t); +static inline int zfcp_sg_list_copy_to_user(void __user *, + struct zfcp_sg_list *, size_t); static int zfcp_cfdc_dev_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -95,7 +95,7 @@ module_param(loglevel, uint, 0); MODULE_PARM_DESC(loglevel, "log levels, 8 nibbles: " - "(unassigned) ERP QDIO DIO Config FSF SCSI Other, " + "FC ERP QDIO CIO Config FSF SCSI Other, " "levels: 0=none 1=normal 2=devel 3=trace"); #ifdef ZFCP_PRINT_FLAGS @@ -257,24 +257,20 @@ static void __init zfcp_init_device_configure(void) { - int found = 0; struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; down(&zfcp_data.config_sema); read_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) - if (strcmp(zfcp_data.init_busid, - zfcp_get_busid_by_adapter(adapter)) == 0) { - zfcp_adapter_get(adapter); - found = 1; - break; - } + adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid); + if (adapter) + zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); - if (!found) + + if (adapter == NULL) goto out_adapter; - port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0); + port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); if (!port) goto out_port; unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); @@ -377,12 +373,13 @@ * -ENOMEM - Insufficient memory * -EFAULT - User space memory I/O operation fault * -EPERM - Cannot create or queue FSF request or create SBALs + * -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) */ static int zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file, unsigned int command, unsigned long buffer) { - struct zfcp_cfdc_sense_data sense_data, *sense_data_user; + struct zfcp_cfdc_sense_data sense_data, __user *sense_data_user; struct zfcp_adapter *adapter = NULL; struct zfcp_fsf_req *fsf_req = NULL; struct zfcp_sg_list *sg_list = NULL; @@ -403,7 +400,7 @@ goto out; } - if ((sense_data_user = (struct zfcp_cfdc_sense_data*)buffer) == NULL) { + if ((sense_data_user = (void __user *) buffer) == NULL) { ZFCP_LOG_INFO("sense data record is required\n"); retval = -EINVAL; goto out; @@ -467,22 +464,17 @@ (sense_data.devno >> 16) & 0xFF, (sense_data.devno & 0xFFFF)); - retval = -ENXIO; read_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { - if (strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), - BUS_ID_SIZE) == 0) { - zfcp_adapter_get(adapter); - retval = 0; - break; - } - } + adapter = zfcp_get_adapter_by_busid(bus_id); + if (adapter) + zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); kfree(bus_id); - if (retval != 0) { + if (adapter == NULL) { ZFCP_LOG_INFO("invalid adapter\n"); + retval = -ENXIO; goto out; } @@ -520,6 +512,12 @@ wait_event(fsf_req->completion_wq, fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) && + (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { + retval = -ENXIO; + goto out; + } + sense_data.fsf_status = fsf_req->qtcb->header.fsf_status; memcpy(&sense_data.fsf_status_qual, &fsf_req->qtcb->header.fsf_status_qual, @@ -559,13 +557,16 @@ } -/* - * function: zfcp_sg_list_alloc - * - * purpose: Create a scatter-gather list of the specified size +/** + * zfcp_sg_list_alloc - create a scatter-gather list of the specified size + * @sg_list: structure describing a scatter gather list + * @size: size of scatter-gather list + * Return: 0 on success, else -ENOMEM * - * returns: 0 - Scatter gather list is created - * -ENOMEM - Insufficient memory (*list_ptr is then set to NULL) + * In sg_list->sg a pointer to the created scatter-gather list is returned, + * or NULL if we run out of memory. sg_list->count specifies the number of + * elements of the scatter-gather list. The maximum size of a single element + * in the scatter-gather list is PAGE_SIZE. */ static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) @@ -573,6 +574,9 @@ struct scatterlist *sg; unsigned int i; int retval = 0; + void *address; + + BUG_ON(sg_list == NULL); sg_list->count = size >> PAGE_SHIFT; if (size & ~PAGE_MASK) @@ -588,7 +592,8 @@ for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) { sg->length = min(size, PAGE_SIZE); sg->offset = 0; - sg->page = alloc_pages(GFP_KERNEL, 0); + address = (void *) get_zeroed_page(GFP_KERNEL); + zfcp_address_to_sg(address, sg); if (sg->page == NULL) { sg_list->count = i; zfcp_sg_list_free(sg_list); @@ -603,41 +608,61 @@ } -/* - * function: zfcp_sg_list_free - * - * purpose: Destroy a scatter-gather list and release memory +/** + * zfcp_sg_list_free - free memory of a scatter-gather list + * @sg_list: structure describing a scatter-gather list * - * returns: Always 0 + * Memory for each element in the scatter-gather list is freed. + * Finally sg_list->sg is freed itself and sg_list->count is reset. */ -static inline int +static inline void zfcp_sg_list_free(struct zfcp_sg_list *sg_list) { struct scatterlist *sg; unsigned int i; - int retval = 0; BUG_ON(sg_list == NULL); for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) __free_pages(sg->page, 0); + sg_list->count = 0; kfree(sg_list->sg); +} - return retval; +/** + * zfcp_sg_size - determine size of a scatter-gather list + * @sg: array of (struct scatterlist) + * @sg_count: elements in array + * Return: size of entire scatter-gather list + */ +size_t +zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) +{ + unsigned int i; + struct scatterlist *p; + size_t size; + + size = 0; + for (i = 0, p = sg; i < sg_count; i++, p++) { + BUG_ON(p == NULL); + size += p->length; + } + + return size; } -/* - * function: zfcp_sg_list_copy_from_user - * - * purpose: Copy data from user space memory to the scatter-gather list - * - * returns: 0 - The data has been copied from user - * -EFAULT - Memory I/O operation fault +/** + * zfcp_sg_list_copy_from_user -copy data from user space to scatter-gather list + * @sg_list: structure describing a scatter-gather list + * @user_buffer: pointer to buffer in user space + * @size: number of bytes to be copied + * Return: 0 on success, -EFAULT if copy_from_user fails. */ static inline int -zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer, +zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, + void __user *user_buffer, size_t size) { struct scatterlist *sg; @@ -645,10 +670,14 @@ void *zfcp_buffer; int retval = 0; + BUG_ON(sg_list == NULL); + + if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) + return -EFAULT; + for (sg = sg_list->sg; size > 0; sg++) { length = min((unsigned int)size, sg->length); - zfcp_buffer = (void*) - ((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset); + zfcp_buffer = zfcp_sg_to_address(sg); if (copy_from_user(zfcp_buffer, user_buffer, length)) { retval = -EFAULT; goto out; @@ -662,16 +691,16 @@ } -/* - * function: zfcp_sg_list_copy_to_user - * - * purpose: Copy data from the scatter-gather list to user space memory - * - * returns: 0 - The data has been copied to user - * -EFAULT - Memory I/O operation fault +/** + * zfcp_sg_list_copy_to_user - copy data from scatter-gather list to user space + * @user_buffer: pointer to buffer in user space + * @sg_list: structure describing a scatter-gather list + * @size: number of bytes to be copied + * Return: 0 on success, -EFAULT if copy_to_user fails */ static inline int -zfcp_sg_list_copy_to_user(void *user_buffer, struct zfcp_sg_list *sg_list, +zfcp_sg_list_copy_to_user(void __user *user_buffer, + struct zfcp_sg_list *sg_list, size_t size) { struct scatterlist *sg; @@ -679,10 +708,14 @@ void *zfcp_buffer; int retval = 0; + BUG_ON(sg_list == NULL); + + if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) + return -EFAULT; + for (sg = sg_list->sg; size > 0; sg++) { - length = min((unsigned int)size, sg->length); - zfcp_buffer = (void*) - ((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset); + length = min((unsigned int) size, sg->length); + zfcp_buffer = zfcp_sg_to_address(sg); if (copy_to_user(user_buffer, zfcp_buffer, length)) { retval = -EFAULT; goto out; @@ -705,13 +738,12 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG /** - * zfcp_get_unit_by_lun - find unit in unit list of port by fcp lun + * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN * @port: pointer to port to search for unit - * @fcp_lun: lun to search for - * Traverses list of all units of a port and returns pointer to a unit - * if lun of a unit matches. + * @fcp_lun: FCP LUN to search for + * Traverse list of all units of a port and return pointer to a unit + * with the given FCP LUN. */ - struct zfcp_unit * zfcp_get_unit_by_lun(struct zfcp_port *port, fcp_lun_t fcp_lun) { @@ -730,13 +762,12 @@ } /** - * zfcp_get_port_by_wwpn - find unit in unit list of port by fcp lun + * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn * @adapter: pointer to adapter to search for port * @wwpn: wwpn to search for - * Traverses list of all ports of an adapter and returns a pointer to a port - * if wwpn of a port matches. + * Traverse list of all ports of an adapter and return pointer to a port + * with the given wwpn. */ - struct zfcp_port * zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) { @@ -745,6 +776,30 @@ list_for_each_entry(port, &adapter->port_list_head, list) { if ((port->wwpn == wwpn) && + !(atomic_read(&port->status) & + (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) { + found = 1; + break; + } + } + return found ? port : NULL; +} + +/** + * zfcp_get_port_by_did - find port in port list of adapter by d_id + * @adapter: pointer to adapter to search for port + * @d_id: d_id to search for + * Traverse list of all ports of an adapter and return pointer to a port + * with the given d_id. + */ +struct zfcp_port * +zfcp_get_port_by_did(struct zfcp_adapter *adapter, u32 d_id) +{ + struct zfcp_port *port; + int found = 0; + + list_for_each_entry(port, &adapter->port_list_head, list) { + if ((port->d_id == d_id) && !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { found = 1; @@ -754,14 +809,38 @@ return found ? port : NULL; } -/* - * Enqueues a logical unit at the end of the unit list associated with the - * specified port. Also sets up some unit internal structures. +/** + * zfcp_get_adapter_by_busid - find adpater in adapter list by bus_id + * @bus_id: bus_id to search for + * Traverse list of all adapters and return pointer to an adapter + * with the given bus_id. + */ +struct zfcp_adapter * +zfcp_get_adapter_by_busid(char *bus_id) +{ + struct zfcp_adapter *adapter; + int found = 0; + + list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { + if ((strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), + BUS_ID_SIZE) == 0) && + !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, + &adapter->status)){ + found = 1; + break; + } + } + return found ? adapter : NULL; +} + +/** + * zfcp_unit_enqueue - enqueue unit to unit list of a port. + * @port: pointer to port where unit is added + * @fcp_lun: FCP LUN of unit to be enqueued + * Return: pointer to enqueued unit on success, NULL on error + * Locks: config_sema must be held to serialize changes to the unit list * - * returns: pointer to unit with a usecount of 1 if a new unit was - * successfully enqueued - * NULL otherwise - * locks: config_sema must be held to serialise changes to the unit list + * Sets up some unit internal structures and creates sysfs entry. */ struct zfcp_unit * zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) @@ -1022,6 +1101,12 @@ debug_unregister(adapter->in_els_dbf); } +void +zfcp_dummy_release(struct device *dev) +{ + return; +} + /* * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. @@ -1113,6 +1198,14 @@ if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) goto sysfs_failed; + adapter->generic_services.parent = &adapter->ccw_device->dev; + adapter->generic_services.release = zfcp_dummy_release; + snprintf(adapter->generic_services.bus_id, BUS_ID_SIZE, + "generic_services"); + + if (device_register(&adapter->generic_services)) + goto generic_services_failed; + /* put allocated adapter at list tail */ write_lock_irq(&zfcp_data.config_lock); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); @@ -1123,6 +1216,8 @@ goto out; + generic_services_failed: + zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); sysfs_failed: dev_set_drvdata(&ccw_device->dev, NULL); failed_low_mem_buffers: @@ -1153,6 +1248,7 @@ int retval = 0; unsigned long flags; + device_unregister(&adapter->generic_services); zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); dev_set_drvdata(&adapter->ccw_device->dev, NULL); /* sanity check: no pending FSF requests */ @@ -1195,15 +1291,22 @@ return; } -/* - * Enqueues a remote port to the port list. All port internal structures - * are set up and the sysfs entry is also generated. +/** + * zfcp_port_enqueue - enqueue port to port list of adapter + * @adapter: adapter where remote port is added + * @wwpn: WWPN of the remote port to be enqueued + * @status: initial status for the port + * @d_id: destination id of the remote port to be enqueued + * Return: pointer to enqueued port on success, NULL on error + * Locks: config_sema must be held to serialize changes to the port list * - * returns: pointer to port or NULL - * locks: config_sema must be held to serialise changes to the port list + * All port internal structures are set up and the sysfs entry is generated. + * d_id is used to enqueue ports with a well known address like the Directory + * Service for nameserver lookup. */ struct zfcp_port * -zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status) +zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, + u32 d_id) { struct zfcp_port *port, *tmp_port; int check_wwpn; @@ -1243,12 +1346,39 @@ atomic_set_mask(status, &port->status); /* setup for sysfs registration */ - if (status & ZFCP_STATUS_PORT_NAMESERVER) - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "nameserver"); - else + if (status & ZFCP_STATUS_PORT_WKA) { + switch (d_id) { + case ZFCP_DID_DIRECTORY_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "directory"); + break; + case ZFCP_DID_MANAGEMENT_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "management"); + break; + case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "key_distribution"); + break; + case ZFCP_DID_ALIAS_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "alias"); + break; + case ZFCP_DID_TIME_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "time"); + break; + default: + kfree(port); + return NULL; + } + port->d_id = d_id; + port->sysfs_device.parent = &adapter->generic_services; + } else { snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", wwpn); port->sysfs_device.parent = &adapter->ccw_device->dev; + } port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); @@ -1287,9 +1417,12 @@ list_add_tail(&port->list, &adapter->port_list_head); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); + if (d_id == ZFCP_DID_DIRECTORY_SERVICE) + if (!adapter->nameserver_port) + adapter->nameserver_port = port; + adapter->ports++; write_unlock_irq(&zfcp_data.config_lock); - adapter->ports++; zfcp_adapter_get(adapter); return port; @@ -1301,8 +1434,8 @@ zfcp_port_wait(port); write_lock_irq(&zfcp_data.config_lock); list_del(&port->list); - write_unlock_irq(&zfcp_data.config_lock); port->adapter->ports--; + write_unlock_irq(&zfcp_data.config_lock); zfcp_adapter_put(port->adapter); zfcp_sysfs_port_remove_files(&port->sysfs_device, atomic_read(&port->status)); @@ -1315,17 +1448,14 @@ { struct zfcp_port *port; - /* generate port structure */ - port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_NAMESERVER); + port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, + ZFCP_DID_DIRECTORY_SERVICE); if (!port) { ZFCP_LOG_INFO("error: enqueue of nameserver port for " "adapter %s failed\n", zfcp_get_busid_by_adapter(adapter)); return -ENXIO; } - /* set special D_ID */ - port->d_id = ZFCP_DID_NAMESERVER; - adapter->nameserver_port = port; zfcp_port_put(port); return 0; @@ -1389,7 +1519,7 @@ read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { if (atomic_test_mask - (ZFCP_STATUS_PORT_NAMESERVER, &port->status)) + (ZFCP_STATUS_PORT_WKA, &port->status)) continue; /* Do we know this port? If not skip it. */ if (!atomic_test_mask @@ -1646,15 +1776,7 @@ ct_iu_req = zfcp_sg_to_address(ct->req); ct_iu_resp = zfcp_sg_to_address(ct->resp); - if (ct_iu_resp->header.revision != ZFCP_CT_REVISION) - goto failed; - if (ct_iu_resp->header.gs_type != ZFCP_CT_DIRECTORY_SERVICE) - goto failed; - if (ct_iu_resp->header.gs_subtype != ZFCP_CT_NAME_SERVER) - goto failed; - if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS) - goto failed; - if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) { + if ((ct->status != 0) || zfcp_check_ct_response(&ct_iu_resp->header)) { /* FIXME: do we need some specific erp entry points */ atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); goto failed; @@ -1665,7 +1787,7 @@ "lookup does not match expected wwpn 0x%016Lx " "for adapter %s\n", ct_iu_req->wwpn, port->wwpn, zfcp_get_busid_by_port(port)); - goto failed; + goto mismatch; } /* looks like a valid d_id */ @@ -1675,19 +1797,185 @@ zfcp_get_busid_by_port(port), port->wwpn, port->d_id); goto out; -failed: - ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " - "0x%016Lx for adapter %s\n", - port->wwpn, zfcp_get_busid_by_port(port)); + mismatch: ZFCP_LOG_DEBUG("CT IUs do not match:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, sizeof(struct ct_iu_gid_pn_req)); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, sizeof(struct ct_iu_gid_pn_resp)); + failed: + ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " + "0x%016Lx for adapter %s\n", + port->wwpn, zfcp_get_busid_by_port(port)); out: zfcp_gid_pn_buffers_free(gid_pn); return; +} + +/* reject CT_IU reason codes acc. to FC-GS-4 */ +static const struct zfcp_rc_entry zfcp_ct_rc[] = { + {0x01, "invalid command code"}, + {0x02, "invalid version level"}, + {0x03, "logical error"}, + {0x04, "invalid CT_IU size"}, + {0x05, "logical busy"}, + {0x07, "protocol error"}, + {0x09, "unable to perform command request"}, + {0x0b, "command not supported"}, + {0x0d, "server not available"}, + {0x0e, "session could not be established"}, + {0xff, "vendor specific error"}, + {0, NULL}, +}; + +/* LS_RJT reason codes acc. to FC-FS */ +static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = { + {0x01, "invalid LS_Command code"}, + {0x03, "logical error"}, + {0x05, "logical busy"}, + {0x07, "protocol error"}, + {0x09, "unable to perform command request"}, + {0x0b, "command not supported"}, + {0x0e, "command already in progress"}, + {0xff, "vendor specific error"}, + {0, NULL}, +}; + +/* reject reason codes according to FC-PH/FC-FS */ +static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { + {0x01, "invalid D_ID"}, + {0x02, "invalid S_ID"}, + {0x03, "Nx_Port not available, temporary"}, + {0x04, "Nx_Port not available, permament"}, + {0x05, "class not supported"}, + {0x06, "delimiter usage error"}, + {0x07, "TYPE not supported"}, + {0x08, "invalid Link_Control"}, + {0x09, "invalid R_CTL field"}, + {0x0a, "invalid F_CTL field"}, + {0x0b, "invalid OX_ID"}, + {0x0c, "invalid RX_ID"}, + {0x0d, "invalid SEQ_ID"}, + {0x0e, "invalid DF_CTL"}, + {0x0f, "invalid SEQ_CNT"}, + {0x10, "invalid parameter field"}, + {0x11, "exchange error"}, + {0x12, "protocol error"}, + {0x13, "incorrect length"}, + {0x14, "unsupported ACK"}, + {0x15, "class of service not supported by entity at FFFFFE"}, + {0x16, "login required"}, + {0x17, "excessive sequences attempted"}, + {0x18, "unable to establish exchange"}, + {0x1a, "fabric path not available"}, + {0x1b, "invalid VC_ID (class 4)"}, + {0x1c, "invalid CS_CTL field"}, + {0x1d, "insufficient resources for VC (class 4)"}, + {0x1f, "invalid class of service"}, + {0x20, "preemption request rejected"}, + {0x21, "preemption not enabled"}, + {0x22, "multicast error"}, + {0x23, "multicast error terminate"}, + {0x24, "process login required"}, + {0xff, "vendor specific reject"}, + {0, NULL}, +}; + +/** + * zfcp_rc_description - return description for given reaon code + * @code: reason code + * @rc_table: table of reason codes and descriptions + */ +static inline const char * +zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) +{ + const char *descr = "unknown reason code"; + + do { + if (code == rc_table->code) { + descr = rc_table->description; + break; + } + rc_table++; + } while (rc_table->code && rc_table->description); + + return descr; +} + +/** + * zfcp_check_ct_response - evaluate reason code for CT_IU + * @rjt: response payload to an CT_IU request + * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code + */ +int +zfcp_check_ct_response(struct ct_hdr *rjt) +{ + if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT) + return 0; + + if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) { + ZFCP_LOG_NORMAL("error: invalid Generic Service command/" + "response code (0x%04hx)\n", + rjt->cmd_rsp_code); + return 1; + } + + ZFCP_LOG_INFO("Generic Service command rejected\n"); + ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n", + zfcp_rc_description(rjt->reason_code, zfcp_ct_rc), + (u32) rjt->reason_code, (u32) rjt->reason_code_expl, + (u32) rjt->vendor_unique); + + return 1; +} + +/** + * zfcp_print_els_rjt - print reject parameter and description for ELS reject + * @rjt_par: reject parameter acc. to FC-PH/FC-FS + * @rc_table: table of reason codes and descriptions + */ +static inline void +zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, + const struct zfcp_rc_entry *rc_table) +{ + ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n", + zfcp_rc_description(rjt_par->reason_code, rc_table), + (u32) rjt_par->action, (u32) rjt_par->reason_code, + (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique); +} + +/** + * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject + * @sq: status qualifier word + * @rjt_par: reject parameter as described in FC-PH and FC-FS + * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else + */ +int +zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par) +{ + int ret = -EIO; + + if (sq == FSF_IOSTAT_NPORT_RJT) { + ZFCP_LOG_INFO("ELS rejected (P_RJT)\n"); + zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); + /* invalid d_id */ + if (rjt_par->reason_code == 0x01) + ret = -EREMCHG; + } else if (sq == FSF_IOSTAT_FABRIC_RJT) { + ZFCP_LOG_INFO("ELS rejected (F_RJT)\n"); + zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); + /* invalid d_id */ + if (rjt_par->reason_code == 0x01) + ret = -EREMCHG; + } else if (sq == FSF_IOSTAT_LS_RJT) { + ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n"); + zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc); + ret = -EREMOTEIO; + } else + ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq); + + return ret; } #undef ZFCP_LOG_AREA diff -Nru a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h --- a/drivers/s390/scsi/zfcp_def.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/s390/scsi/zfcp_def.h 2004-10-18 14:56:32 -07:00 @@ -33,7 +33,7 @@ #define ZFCP_DEF_H /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_DEF_REVISION "$Revision: 1.81 $" +#define ZFCP_DEF_REVISION "$Revision: 1.91 $" /*************************** INCLUDES *****************************************/ @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -72,12 +73,22 @@ /* zfcp version number, it consists of major, minor, and patch-level number */ #define ZFCP_VERSION "4.1.3" +/** + * zfcp_sg_to_address - determine kernel address from struct scatterlist + * @list: struct scatterlist + * Return: kernel address + */ static inline void * zfcp_sg_to_address(struct scatterlist *list) { return (void *) (page_address(list->page) + list->offset); } +/** + * zfcp_address_to_sg - set up struct scatterlist from kernel address + * @address: kernel address + * @list: struct scatterlist + */ static inline void zfcp_address_to_sg(void *address, struct scatterlist *list) { @@ -146,6 +157,9 @@ #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 6 #define ZFCP_EXCHANGE_CONFIG_DATA_SLEEP 50 +/* timeout value for "default timer" for fsf requests */ +#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ); + /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ typedef unsigned long long wwn_t; @@ -158,7 +172,6 @@ /* timeout for name-server lookup (in seconds) */ #define ZFCP_NS_GID_PN_TIMEOUT 10 -#define ZFCP_NS_GA_NXT_TIMEOUT 120 /* largest SCSI command we can process */ /* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */ @@ -276,33 +289,17 @@ #define R_A_TOV 10 /* seconds */ #define ZFCP_ELS_TIMEOUT (2 * R_A_TOV) -#define ZFCP_LS_RJT 0x01 -#define ZFCP_LS_ACC 0x02 #define ZFCP_LS_RTV 0x0E #define ZFCP_LS_RLS 0x0F #define ZFCP_LS_PDISC 0x50 #define ZFCP_LS_ADISC 0x52 -#define ZFCP_LS_RSCN 0x61 -#define ZFCP_LS_RNID 0x78 -#define ZFCP_LS_RLIR 0x7A #define ZFCP_LS_RTV_E_D_TOV_FLAG 0x04000000 -/* LS_ACC Reason Codes */ -#define ZFCP_LS_RJT_INVALID_COMMAND_CODE 0x01 -#define ZFCP_LS_RJT_LOGICAL_ERROR 0x03 -#define ZFCP_LS_RJT_LOGICAL_BUSY 0x05 -#define ZFCP_LS_RJT_PROTOCOL_ERROR 0x07 -#define ZFCP_LS_RJT_UNABLE_TO_PERFORM 0x09 -#define ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED 0x0B -#define ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR 0xFF - -struct zfcp_ls_rjt { - u8 code; - u8 field[3]; - u8 reserved; - u8 reason_code; - u8 reason_expl; - u8 vendor_unique; +struct zfcp_ls_rjt_par { + u8 action; + u8 reason_code; + u8 reason_expl; + u8 vendor_unique; } __attribute__ ((packed)); struct zfcp_ls_rtv { @@ -383,45 +380,10 @@ fc_id_t nport_id; } __attribute__ ((packed)); -struct zfcp_ls_rnid { - u8 code; - u8 field[3]; - u8 node_id_format; - u8 reserved[3]; -} __attribute__((packed)); - -/* common identification data */ -struct zfcp_ls_rnid_common_id { - u64 n_port_name; - u64 node_name; -} __attribute__((packed)); - -/* general topology specific identification data */ -struct zfcp_ls_rnid_general_topology_id { - u8 vendor_unique[16]; - u32 associated_type; - u32 physical_port_number; - u32 nr_attached_nodes; - u8 node_management; - u8 ip_version; - u16 port_number; - u8 ip_address[16]; - u8 reserved[2]; - u16 vendor_specific; -} __attribute__((packed)); - -struct zfcp_ls_rnid_acc { - u8 code; - u8 field[3]; - u8 node_id_format; - u8 common_id_length; - u8 reserved; - u8 specific_id_length; - struct zfcp_ls_rnid_common_id - common_id; - struct zfcp_ls_rnid_general_topology_id - specific_id; -} __attribute__((packed)); +struct zfcp_rc_entry { + u8 code; + const char *description; +}; /* * FC-GS-2 stuff @@ -431,9 +393,9 @@ #define ZFCP_CT_NAME_SERVER 0x02 #define ZFCP_CT_SYNCHRONOUS 0x00 #define ZFCP_CT_GID_PN 0x0121 -#define ZFCP_CT_GA_NXT 0x0100 #define ZFCP_CT_MAX_SIZE 0x1020 #define ZFCP_CT_ACCEPT 0x8002 +#define ZFCP_CT_REJECT 0x8001 /* * FC-GS-4 stuff @@ -530,23 +492,29 @@ __LINE__ , ##args); #define ZFCP_LOG(level, fmt, args...) \ +do { \ if (ZFCP_LOG_CHECK(level)) \ - _ZFCP_LOG(fmt , ##args) + _ZFCP_LOG(fmt, ##args); \ +} while (0) #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL # define ZFCP_LOG_NORMAL(fmt, args...) #else # define ZFCP_LOG_NORMAL(fmt, args...) \ +do { \ if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \ - printk(KERN_ERR ZFCP_NAME": " fmt , ##args); + printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ +} while (0) #endif #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO # define ZFCP_LOG_INFO(fmt, args...) #else # define ZFCP_LOG_INFO(fmt, args...) \ +do { \ if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \ - printk(KERN_ERR ZFCP_NAME": " fmt , ##args); + printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ +} while (0) #endif #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG @@ -568,8 +536,10 @@ #else extern u32 flags_dump; # define ZFCP_LOG_FLAGS(level, fmt, args...) \ +do { \ if (level <= flags_dump) \ - _ZFCP_LOG(fmt , ##args) + _ZFCP_LOG(fmt, ##args); \ +} while (0) #endif /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ @@ -606,7 +576,12 @@ ZFCP_STATUS_ADAPTER_REGISTERED) -#define ZFCP_DID_NAMESERVER 0xFFFFFC +/* FC-PH/FC-GS well-known address identifiers for generic services */ +#define ZFCP_DID_MANAGEMENT_SERVICE 0xFFFFFA +#define ZFCP_DID_TIME_SERVICE 0xFFFFFB +#define ZFCP_DID_DIRECTORY_SERVICE 0xFFFFFC +#define ZFCP_DID_ALIAS_SERVICE 0xFFFFF8 +#define ZFCP_DID_KEY_DISTRIBUTION_SERVICE 0xFFFFF7 /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 @@ -616,7 +591,8 @@ #define ZFCP_STATUS_PORT_NO_SCSI_ID 0x00000010 #define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020 -#define ZFCP_STATUS_PORT_NAMESERVER \ +/* for ports with well known addresses */ +#define ZFCP_STATUS_PORT_WKA \ (ZFCP_STATUS_PORT_NO_WWPN | \ ZFCP_STATUS_PORT_NO_SCSI_ID) @@ -789,43 +765,29 @@ wwn_t wwpn; } __attribute__ ((packed)); -/* nameserver request CT_IU -- for requests where - * a port identifier is required */ -struct ct_iu_ga_nxt_req { - struct ct_hdr header; - fc_id_t d_id; -} __attribute__ ((packed)); - /* FS_ACC IU and data unit for GID_PN nameserver request */ struct ct_iu_gid_pn_resp { struct ct_hdr header; fc_id_t d_id; } __attribute__ ((packed)); -/* FS_ACC IU and data unit for GA_NXT nameserver request */ -struct ct_iu_ga_nxt_resp { - struct ct_hdr header; - u8 port_type; - u8 port_id[3]; - u64 port_wwn; - u8 port_symbolic_name_length; - u8 port_symbolic_name[255]; - u64 node_wwn; - u8 node_symbolic_name_length; - u8 node_symbolic_name[255]; - u64 initial_process_associator; - u8 node_ip[16]; - u32 cos; - u8 fc4_types[32]; - u8 port_ip[16]; - u64 fabric_wwn; - u8 reserved; - u8 hard_address[3]; -} __attribute__ ((packed)); - typedef void (*zfcp_send_ct_handler_t)(unsigned long); -/* used to pass parameters to zfcp_send_ct() */ +/** + * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct + * @port: port where the request is sent to + * @req: scatter-gather list for request + * @resp: scatter-gather list for response + * @req_count: number of elements in request scatter-gather list + * @resp_count: number of elements in response scatter-gather list + * @handler: handler function (called for response to the request) + * @handler_data: data passed to handler function + * @pool: pointer to memory pool for ct request structure + * @timeout: FSF timeout for this request + * @timer: timer (e.g. for request initiated by erp) + * @completion: completion for synchronization purposes + * @status: used to pass error status to calling function + */ struct zfcp_send_ct { struct zfcp_port *port; struct scatterlist *req; @@ -834,7 +796,7 @@ unsigned int resp_count; zfcp_send_ct_handler_t handler; unsigned long handler_data; - mempool_t *pool; /* mempool for ct not for fsf_req */ + mempool_t *pool; int timeout; struct timer_list *timer; struct completion *completion; @@ -851,10 +813,22 @@ struct zfcp_port *port; }; -typedef int (*zfcp_send_els_handler_t)(unsigned long); +typedef void (*zfcp_send_els_handler_t)(unsigned long); -/* used to pass parameters to zfcp_send_els() */ -/* ToDo merge send_ct() and send_els() and corresponding structs */ +/** + * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els + * @port: port where the request is sent to + * @req: scatter-gather list for request + * @resp: scatter-gather list for response + * @req_count: number of elements in request scatter-gather list + * @resp_count: number of elements in response scatter-gather list + * @handler: handler function (called for response to the request) + * @handler_data: data passed to handler function + * @timer: timer (e.g. for request initiated by erp) + * @completion: completion for synchronization purposes + * @ls_code: hex code of ELS command + * @status: used to pass error status to calling function + */ struct zfcp_send_els { struct zfcp_port *port; struct scatterlist *req; @@ -863,6 +837,7 @@ unsigned int resp_count; zfcp_send_els_handler_t handler; unsigned long handler_data; + struct timer_list *timer; struct completion *completion; int ls_code; int status; @@ -892,6 +867,7 @@ struct zfcp_send_ct *send_ct; struct zfcp_send_els *send_els; struct zfcp_status_read status_read; + struct fsf_qtcb_bottom_port *port_data; }; struct zfcp_qdio_queue { @@ -979,6 +955,7 @@ rwlock_t cmd_dbf_lock; struct zfcp_adapter_mempool pool; /* Adapter memory pools */ struct qdio_initialize qdio_init_data; /* for qdio_establish */ + struct device generic_services; /* directory for WKA ports */ }; /* @@ -1080,6 +1057,11 @@ fcp_lun_t init_fcp_lun; }; +/** + * struct zfcp_sg_list - struct describing a scatter-gather list + * @sg: pointer to array of (struct scatterlist) + * @count: number of elements in scatter-gather list + */ struct zfcp_sg_list { struct scatterlist *sg; unsigned int count; diff -Nru a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c --- a/drivers/s390/scsi/zfcp_erp.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/s390/scsi/zfcp_erp.c 2004-10-18 14:56:17 -07:00 @@ -31,12 +31,12 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_ERP_REVISION "$Revision: 1.61 $" +#define ZFCP_ERP_REVISION "$Revision: 1.65 $" #include "zfcp_ext.h" static int zfcp_els(struct zfcp_port *, u8); -static int zfcp_els_handler(unsigned long); +static void zfcp_els_handler(unsigned long); static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int); static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int); @@ -126,6 +126,25 @@ static void zfcp_erp_timeout_handler(unsigned long); static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *); +/** + * zfcp_fsf_request_timeout_handler - called if a request timed out + * @data: pointer to adapter for handler function + * + * This function needs to be called if requests (ELS, Generic Service, + * or SCSI commands) exceed a certain time limit. The assumption is + * that after the time limit the adapter get stuck. So we trigger a reopen of + * the adapter. This should not be used for error recovery, SCSI abort + * commands and SCSI requests from SCSI mid-layer. + */ +void +zfcp_fsf_request_timeout_handler(unsigned long data) +{ + struct zfcp_adapter *adapter; + + adapter = (struct zfcp_adapter *) data; + + zfcp_erp_adapter_reopen(adapter, 0); +} /* * function: zfcp_fsf_scsi_er_timeout_handler @@ -324,6 +343,7 @@ send_els->completion = NULL; req = zfcp_sg_to_address(send_els->req); + memset(req, 0, PAGE_SIZE); *(u32*)req = 0; *(u8*)req = ls_code; @@ -412,185 +432,99 @@ } -/* - * function: zfcp_els_handler - * - * purpose: Handler for all kind of ELSs - * - * returns: 0 - Operation completed successfuly - * -ENXIO - ELS has been rejected - * -EPERM - Port forced reopen failed +/** + * zfcp_els_handler - handler for ELS commands + * @data: pointer to struct zfcp_send_els + * If ELS failed (LS_RJT or timed out) forced reopen of the port is triggered. */ -int +void zfcp_els_handler(unsigned long data) { struct zfcp_send_els *send_els = (struct zfcp_send_els*)data; struct zfcp_port *port = send_els->port; - struct zfcp_ls_rjt *rjt; struct zfcp_ls_rtv_acc *rtv; struct zfcp_ls_rls_acc *rls; struct zfcp_ls_pdisc_acc *pdisc; struct zfcp_ls_adisc_acc *adisc; void *req, *resp; - u8 req_code, resp_code; - int retval = 0; + u8 req_code; + /* request rejected or timed out */ if (send_els->status != 0) { ZFCP_LOG_NORMAL("ELS request timed out, force physical port " "reopen of port 0x%016Lx on adapter %s\n", port->wwpn, zfcp_get_busid_by_port(port)); debug_text_event(port->adapter->erp_dbf, 3, "forcreop"); - retval = zfcp_erp_port_forced_reopen(port, 0); - if (retval != 0) { + if (zfcp_erp_port_forced_reopen(port, 0)) ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx " "on adapter %s failed\n", port->wwpn, zfcp_get_busid_by_port(port)); - retval = -EPERM; - } - goto skip_fsfstatus; + goto out; } - req = (void*)((page_to_pfn(send_els->req->page) << PAGE_SHIFT) + send_els->req->offset); - resp = (void*)((page_to_pfn(send_els->resp->page) << PAGE_SHIFT) + send_els->resp->offset); + req = zfcp_sg_to_address(send_els->req); + resp = zfcp_sg_to_address(send_els->resp); req_code = *(u8*)req; - resp_code = *(u8*)resp; - - switch (resp_code) { - - case ZFCP_LS_RJT: - rjt = (struct zfcp_ls_rjt*)resp; - - switch (rjt->reason_code) { - - case ZFCP_LS_RJT_INVALID_COMMAND_CODE: - ZFCP_LOG_INFO("invalid LS command code " - "(wwpn=0x%016Lx, command=0x%02x)\n", - port->wwpn, req_code); - break; - - case ZFCP_LS_RJT_LOGICAL_ERROR: - ZFCP_LOG_INFO("logical error (wwpn=0x%016Lx, " - "reason_expl=0x%02x)\n", - port->wwpn, rjt->reason_expl); - break; - - case ZFCP_LS_RJT_LOGICAL_BUSY: - ZFCP_LOG_INFO("logical busy (wwpn=0x%016Lx, " - "reason_expl=0x%02x)\n", - port->wwpn, rjt->reason_expl); - break; - - case ZFCP_LS_RJT_PROTOCOL_ERROR: - ZFCP_LOG_INFO("protocol error (wwpn=0x%016Lx, " - "reason_expl=0x%02x)\n", - port->wwpn, rjt->reason_expl); - break; - case ZFCP_LS_RJT_UNABLE_TO_PERFORM: - ZFCP_LOG_INFO("unable to perform command requested " - "(wwpn=0x%016Lx, reason_expl=0x%02x)\n", - port->wwpn, rjt->reason_expl); - break; - - case ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED: - ZFCP_LOG_INFO("command not supported (wwpn=0x%016Lx, " - "command=0x%02x)\n", - port->wwpn, req_code); - break; + switch (req_code) { - case ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR: - ZFCP_LOG_INFO("vendor specific error (wwpn=0x%016Lx, " - "vendor_unique=0x%02x)\n", - port->wwpn, rjt->vendor_unique); - break; - - default: - ZFCP_LOG_NORMAL("ELS rejected by remote port 0x%016Lx " - "on adapter %s (reason_code=0x%02x)\n", - port->wwpn, - zfcp_get_busid_by_port(port), - rjt->reason_code); - } - retval = -ENXIO; - break; - - case ZFCP_LS_ACC: - switch (req_code) { - - case ZFCP_LS_RTV: - rtv = (struct zfcp_ls_rtv_acc*)resp; - ZFCP_LOG_INFO("RTV response from d_id 0x%08x to s_id " - "0x%08x (R_A_TOV=%ds E_D_TOV=%d%cs)\n", - port->d_id, port->adapter->s_id, - rtv->r_a_tov, rtv->e_d_tov, - rtv->qualifier & - ZFCP_LS_RTV_E_D_TOV_FLAG ? 'n' : 'm'); - break; - - case ZFCP_LS_RLS: - rls = (struct zfcp_ls_rls_acc*)resp; - ZFCP_LOG_INFO("RLS response from d_id 0x%08x to s_id " - "0x%08x (link_failure_count=%u, " - "loss_of_sync_count=%u, " - "loss_of_signal_count=%u, " - "primitive_sequence_protocol_error=%u, " - "invalid_transmition_word=%u, " - "invalid_crc_count=%u)\n", - port->d_id, port->adapter->s_id, - rls->link_failure_count, - rls->loss_of_sync_count, - rls->loss_of_signal_count, - rls->prim_seq_prot_error, - rls->invalid_transmition_word, - rls->invalid_crc_count); - break; + case ZFCP_LS_RTV: + rtv = (struct zfcp_ls_rtv_acc*)resp; + ZFCP_LOG_INFO("RTV response from d_id 0x%08x to s_id " + "0x%08x (R_A_TOV=%ds E_D_TOV=%d%cs)\n", + port->d_id, port->adapter->s_id, + rtv->r_a_tov, rtv->e_d_tov, + rtv->qualifier & + ZFCP_LS_RTV_E_D_TOV_FLAG ? 'n' : 'm'); + break; - case ZFCP_LS_PDISC: - pdisc = (struct zfcp_ls_pdisc_acc*)resp; - ZFCP_LOG_INFO("PDISC response from d_id 0x%08x to s_id " - "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " - "vendor='%-16s')\n", port->d_id, - port->adapter->s_id, pdisc->wwpn, - pdisc->wwnn, pdisc->vendor_version); - break; + case ZFCP_LS_RLS: + rls = (struct zfcp_ls_rls_acc*)resp; + ZFCP_LOG_INFO("RLS response from d_id 0x%08x to s_id " + "0x%08x (link_failure_count=%u, " + "loss_of_sync_count=%u, " + "loss_of_signal_count=%u, " + "primitive_sequence_protocol_error=%u, " + "invalid_transmition_word=%u, " + "invalid_crc_count=%u)\n", + port->d_id, port->adapter->s_id, + rls->link_failure_count, + rls->loss_of_sync_count, + rls->loss_of_signal_count, + rls->prim_seq_prot_error, + rls->invalid_transmition_word, + rls->invalid_crc_count); + break; - case ZFCP_LS_ADISC: - adisc = (struct zfcp_ls_adisc_acc*)resp; - ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id " - "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " - "hard_nport_id=0x%08x, " - "nport_id=0x%08x)\n", port->d_id, - port->adapter->s_id, adisc->wwpn, - adisc->wwnn, adisc->hard_nport_id, - adisc->nport_id); - /* FIXME: set wwnn in during open port */ - if (port->wwnn == 0) - port->wwnn = adisc->wwnn; - break; - } + case ZFCP_LS_PDISC: + pdisc = (struct zfcp_ls_pdisc_acc*)resp; + ZFCP_LOG_INFO("PDISC response from d_id 0x%08x to s_id " + "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " + "vendor='%-16s')\n", port->d_id, + port->adapter->s_id, pdisc->wwpn, + pdisc->wwnn, pdisc->vendor_version); break; - default: - ZFCP_LOG_NORMAL("unknown payload code 0x%02x received for " - "request 0x%02x to d_id 0x%08x, reopen needed " - "for port 0x%016Lx on adapter %s\n", resp_code, - req_code, port->d_id, port->wwpn, - zfcp_get_busid_by_port(port)); - retval = zfcp_erp_port_forced_reopen(port, 0); - if (retval != 0) { - ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx on " - "adapter %s failed\n", port->wwpn, - zfcp_get_busid_by_port(port)); - retval = -EPERM; - } + case ZFCP_LS_ADISC: + adisc = (struct zfcp_ls_adisc_acc*)resp; + ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id " + "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " + "hard_nport_id=0x%08x, " + "nport_id=0x%08x)\n", port->d_id, + port->adapter->s_id, adisc->wwpn, + adisc->wwnn, adisc->hard_nport_id, + adisc->nport_id); + /* FIXME: set wwnn in during open port */ + if (port->wwnn == 0) + port->wwnn = adisc->wwnn; + break; } -skip_fsfstatus: + out: __free_pages(send_els->req->page, 0); kfree(send_els->req); kfree(send_els->resp); - - return retval; + kfree(send_els); } @@ -735,14 +669,15 @@ return retval; } -/* - * function: - * - * purpose: Wrappper for zfcp_erp_port_reopen_internal - * used to ensure the correct locking - * - * returns: 0 - initiated action succesfully - * <0 - failed to initiate action +/** + * zfcp_erp_port_reopen - initiate reopen of a remote port + * @port: port to be reopened + * @clear_mask: specifies flags in port status to be cleared + * Return: 0 on success, < 0 on error + * + * This is a wrappper function for zfcp_erp_port_reopen_internal. It ensures + * correct locking. An error recovery task is initiated to do the reopen. + * To wait for the completion of the reopen zfcp_erp_wait should be used. */ int zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask) @@ -802,14 +737,15 @@ return retval; } -/* - * function: - * - * purpose: Wrappper for zfcp_erp_unit_reopen_internal - * used to ensure the correct locking - * - * returns: 0 - initiated action succesfully - * <0 - failed to initiate action +/** + * zfcp_erp_unit_reopen - initiate reopen of a unit + * @unit: unit to be reopened + * @clear_mask: specifies flags in unit status to be cleared + * Return: 0 on success, < 0 on error + * + * This is a wrappper for zfcp_erp_unit_reopen_internal. It ensures correct + * locking. An error recovery task is initiated to do the reopen. + * To wait for the completion of the reopen zfcp_erp_wait should be used. */ int zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask) @@ -1987,12 +1923,10 @@ return retval; } -/* - * function: - * - * purpose: - * - * returns: +/** + * zfcp_erp_wait - wait for completion of error recovery on an adapter + * @adapter: adapter for which to wait for completion of its error recovery + * Return: 0 */ int zfcp_erp_wait(struct zfcp_adapter *adapter) @@ -2130,7 +2064,7 @@ struct zfcp_port *port; list_for_each_entry(port, &adapter->port_list_head, list) - if (!atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status)) + if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) zfcp_erp_port_reopen_internal(port, clear_mask); return retval; @@ -2725,7 +2659,7 @@ { int retval; - if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, + if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &erp_action->port->status)) retval = zfcp_erp_port_strategy_open_nameserver(erp_action); else @@ -2863,10 +2797,10 @@ case ZFCP_ERP_STEP_PORT_OPENING: if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { - ZFCP_LOG_DEBUG("nameserver port is open\n"); + ZFCP_LOG_DEBUG("WKA port is open\n"); retval = ZFCP_ERP_SUCCEEDED; } else { - ZFCP_LOG_DEBUG("open failed for nameserver port\n"); + ZFCP_LOG_DEBUG("open failed for WKA port\n"); retval = ZFCP_ERP_FAILED; } /* this is needed anyway (dont care for retval of wakeup) */ diff -Nru a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h --- a/drivers/s390/scsi/zfcp_ext.h 2004-10-18 14:56:20 -07:00 +++ b/drivers/s390/scsi/zfcp_ext.h 2004-10-18 14:56:20 -07:00 @@ -31,7 +31,7 @@ #ifndef ZFCP_EXT_H #define ZFCP_EXT_H /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_EXT_REVISION "$Revision: 1.51 $" +#define ZFCP_EXT_REVISION "$Revision: 1.57 $" #include "zfcp_def.h" @@ -50,15 +50,16 @@ extern void zfcp_sysfs_unit_release(struct device *); /**************************** CONFIGURATION *********************************/ -extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, - fcp_lun_t fcp_lun); -extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, - wwn_t wwpn); +extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t); +extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, wwn_t); +extern struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *, u32); +struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); extern int zfcp_adapter_debug_register(struct zfcp_adapter *); extern void zfcp_adapter_dequeue(struct zfcp_adapter *); extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); -extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32); +extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, + u32, u32); extern void zfcp_port_dequeue(struct zfcp_port *); extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); extern void zfcp_unit_dequeue(struct zfcp_unit *); @@ -94,8 +95,11 @@ extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); +extern int zfcp_fsf_exchange_port_data(struct zfcp_adapter *, + struct fsf_qtcb_bottom_port *); extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, u32, u32, struct zfcp_sg_list *); +extern void zfcp_fsf_request_timeout_handler(unsigned long); extern void zfcp_fsf_scsi_er_timeout_handler(unsigned long); extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); @@ -108,7 +112,7 @@ extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, struct zfcp_unit *, struct scsi_cmnd *, - int); + struct timer_list*, int); extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fsf_req_cleanup(struct zfcp_fsf_req *); @@ -117,9 +121,11 @@ extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command( unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); -/******************************** FCP ****************************************/ +/******************************* FC/FCP **************************************/ extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *); +extern int zfcp_check_ct_response(struct ct_hdr *); +extern int zfcp_handle_els_rjt(u32, struct zfcp_ls_rjt_par *); /******************************* SCSI ****************************************/ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); @@ -132,10 +138,10 @@ extern void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *); extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); -extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd); -extern int zfcp_scsi_command_sync(struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd); +extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *, + struct scsi_cmnd *, struct timer_list *); +extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, + struct timer_list *); extern struct scsi_transport_template *zfcp_transport_template; extern struct fc_function_template zfcp_transport_functions; diff -Nru a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c --- a/drivers/s390/scsi/zfcp_fsf.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/s390/scsi/zfcp_fsf.c 2004-10-18 14:56:48 -07:00 @@ -29,11 +29,12 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_FSF_C_REVISION "$Revision: 1.55 $" +#define ZFCP_FSF_C_REVISION "$Revision: 1.65 $" #include "zfcp_ext.h" static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *); +static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *); static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *); static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *); static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *); @@ -48,7 +49,7 @@ static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); -static inline int zfcp_fsf_req_create_sbal_check( +static inline int zfcp_fsf_req_sbal_check( unsigned long *, struct zfcp_qdio_queue *, int); static inline int zfcp_use_one_sbal( struct scatterlist *, int, struct scatterlist *, int); @@ -79,10 +80,9 @@ }; static const char zfcp_act_subtable_type[5][8] = { - {"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"} + "unknown", "OS", "WWPN", "DID", "LUN" }; - /****************************************************************/ /*************** FSF related Functions *************************/ /****************************************************************/ @@ -684,13 +684,11 @@ break; case FSF_SQ_ULP_PROGRAMMING_ERROR: ZFCP_LOG_FLAGS(0, "FSF_SQ_ULP_PROGRAMMING_ERROR\n"); - ZFCP_LOG_NORMAL("bug: An illegal amount of data was attempted " - "to be sent to the adapter %s " - "Stopping all operations on this adapter. ", + ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer " + "(adapter %s)\n", zfcp_get_busid_by_adapter(fsf_req->adapter)); debug_text_exception(fsf_req->adapter->erp_dbf, 0, "fsf_sq_ulp_err"); - zfcp_erp_adapter_shutdown(fsf_req->adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: @@ -785,6 +783,11 @@ zfcp_fsf_exchange_config_data_handler(fsf_req); break; + case FSF_QTCB_EXCHANGE_PORT_DATA : + ZFCP_LOG_FLAGS(2, "FSF_QTCB_EXCHANGE_PORT_DATA\n"); + zfcp_fsf_exchange_port_data_handler(fsf_req); + break; + case FSF_QTCB_SEND_ELS : ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_ELS\n"); zfcp_fsf_send_els_handler(fsf_req); @@ -1624,26 +1627,6 @@ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_REQUEST_BUF_NOT_VALID : - ZFCP_LOG_FLAGS(2, "FSF_REQUEST_BUF_NOT_VALID\n"); - ZFCP_LOG_NORMAL("error: The port 0x%016Lx on adapter %s has " - "rejected a generic services command " - "due to invalid request buffer.\n", - port->wwpn, zfcp_get_busid_by_port(port)); - debug_text_event(adapter->erp_dbf, 1, "fsf_s_reqiv"); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_RESPONSE_BUF_NOT_VALID : - ZFCP_LOG_FLAGS(2, "FSF_RESPONSE_BUF_NOT_VALID\n"); - ZFCP_LOG_NORMAL("error: The port 0x%016Lx on adapter %s has " - "rejected a generic services command " - "due to invalid response buffer.\n", - port->wwpn, zfcp_get_busid_by_port(port)); - debug_text_event(adapter->erp_dbf, 1, "fsf_s_resiv"); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_PORT_BOXED : ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n"); ZFCP_LOG_INFO("The remote port 0x%016Lx on adapter %s " @@ -1665,9 +1648,10 @@ } skip_fsfstatus: - if (send_ct->handler != NULL) { + send_ct->status = retval; + + if (send_ct->handler != NULL) send_ct->handler(send_ct->handler_data); - } return retval; } @@ -1769,7 +1753,7 @@ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); /* start QDIO request for this FSF request */ - ret = zfcp_fsf_req_send(fsf_req, NULL); + ret = zfcp_fsf_req_send(fsf_req, els->timer); if (ret) { ZFCP_LOG_DEBUG("error: initiation of ELS request failed " "(adapter %s, port 0x%016Lx)\n", @@ -1863,6 +1847,10 @@ /* ERP strategy will escalate */ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp"); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + retval = + zfcp_handle_els_rjt(header->fsf_status_qual.word[1], + (struct zfcp_ls_rjt_par *) + &header->fsf_status_qual.word[2]); break; case FSF_SQ_RETRY_IF_POSSIBLE: ZFCP_LOG_FLAGS(2, "FSF_SQ_RETRY_IF_POSSIBLE\n"); @@ -1921,15 +1909,6 @@ bottom->resp_buf_length); break; - case FSF_UNKNOWN_COMMAND: - ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n"); - ZFCP_LOG_INFO( - "FSF command 0x%x is not supported by FCP adapter " - "(adapter: %s)\n", fsf_req->fsf_command, - zfcp_get_busid_by_port(port)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_ACCESS_DENIED: ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n"); ZFCP_LOG_NORMAL("Access denied, cannot send ELS " @@ -1971,8 +1950,6 @@ if (send_els->handler != 0) send_els->handler(send_els->handler_data); - kfree(send_els); - return retval; } @@ -2219,6 +2196,111 @@ return 0; } +/** + * zfcp_fsf_exchange_port_data - request information about local port + * @adapter: for which port data is requested + * @data: response to exchange port data request + */ +int +zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_port *data) +{ + volatile struct qdio_buffer_element *sbale; + int retval = 0; + unsigned long lock_flags; + struct zfcp_fsf_req *fsf_req; + struct timer_list *timer; + + if(!(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT)){ + ZFCP_LOG_INFO("error: exchange port data " + "command not supported by adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + return -EOPNOTSUPP; + } + + timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!timer) + return -ENOMEM; + + /* setup new FSF request */ + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, + 0, 0, &lock_flags, &fsf_req); + if (retval < 0) { + ZFCP_LOG_INFO("error: Out of resources. Could not create an " + "exchange port data request for" + "the adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + goto out; + } + + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + + fsf_req->data.port_data = data; + + init_timer(timer); + timer->function = zfcp_fsf_request_timeout_handler; + timer->data = (unsigned long) adapter; + timer->expires = ZFCP_FSF_REQUEST_TIMEOUT; + + retval = zfcp_fsf_req_send(fsf_req, timer); + if (retval) { + ZFCP_LOG_INFO("error: Could not send an exchange port data " + "command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + zfcp_fsf_req_free(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + goto out; + } + + ZFCP_LOG_DEBUG("Exchange Port Data request initiated (adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); + + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + + wait_event(fsf_req->completion_wq, + fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + del_timer_sync(timer); + zfcp_fsf_req_cleanup(fsf_req); + out: + kfree(timer); + return retval; +} + + +/** + * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request + * @fsf_req: pointer to struct zfcp_fsf_req + */ +static void +zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) +{ + struct fsf_qtcb_bottom_port *bottom; + struct fsf_qtcb_bottom_port *data = fsf_req->data.port_data; + + if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) + return; + + switch (fsf_req->qtcb->header.fsf_status) { + case FSF_GOOD : + ZFCP_LOG_FLAGS(2,"FSF_GOOD\n"); + bottom = &fsf_req->qtcb->bottom.port; + memcpy(data, bottom, sizeof(*data)); + break; + + default: + debug_text_event(fsf_req->adapter->erp_dbf, 0, "xchg-port-ng"); + debug_event(fsf_req->adapter->erp_dbf, 0, + &fsf_req->qtcb->header.fsf_status, sizeof(u32)); + } +} + + /* * function: zfcp_fsf_open_port * @@ -3319,19 +3401,19 @@ return retval; } -/* - * function: zfcp_fsf_send_fcp_command_task - * - * purpose: - * - * returns: - * - * note: we do not employ linked commands (not supported by HBA anyway) +/** + * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) + * @adapter: adapter where scsi command is issued + * @unit: unit where command is sent to + * @scsi_cmnd: scsi command to be sent + * @timer: timer to be started when request is initiated + * @req_flags: flags for fsf_request */ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, struct zfcp_unit *unit, - struct scsi_cmnd * scsi_cmnd, int req_flags) + struct scsi_cmnd * scsi_cmnd, + struct timer_list *timer, int req_flags) { struct zfcp_fsf_req *fsf_req = NULL; struct fcp_cmnd_iu *fcp_cmnd_iu; @@ -3486,7 +3568,7 @@ * start QDIO request for this FSF request * covered by an SBALE) */ - retval = zfcp_fsf_req_send(fsf_req, NULL); + retval = zfcp_fsf_req_send(fsf_req, timer); if (unlikely(retval < 0)) { ZFCP_LOG_INFO("error: Could not send FCP command request " "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n", @@ -3788,44 +3870,6 @@ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - /* FIXME: this should be obsolete, isn' it? */ - case FSF_INBOUND_DATA_LENGTH_NOT_VALID: - ZFCP_LOG_FLAGS(0, "FSF_INBOUND_DATA_LENGTH_NOT_VALID\n"); - ZFCP_LOG_NORMAL("bug: An invalid inbound data length field " - "was found in a command for unit 0x%016Lx " - "on port 0x%016Lx on adapter %s.\n", - unit->fcp_lun, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); - /* stop operation for this adapter */ - debug_text_event(fsf_req->adapter->erp_dbf, 0, - "fsf_s_in_dl_nv"); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("idleninv", - fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - /* FIXME: this should be obsolete, isn' it? */ - case FSF_OUTBOUND_DATA_LENGTH_NOT_VALID: - ZFCP_LOG_FLAGS(0, "FSF_OUTBOUND_DATA_LENGTH_NOT_VALID\n"); - ZFCP_LOG_NORMAL("bug: An invalid outbound data length field " - "was found in a command unit 0x%016Lx on port " - "0x%016Lx on adapter %s\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - /* stop operation for this adapter */ - debug_text_event(fsf_req->adapter->erp_dbf, 0, - "fsf_s_out_dl_nv"); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("odleninv", fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_CMND_LENGTH_NOT_VALID: ZFCP_LOG_FLAGS(0, "FSF_CMND_LENGTH_NOT_VALID\n"); ZFCP_LOG_NORMAL @@ -4157,87 +4201,6 @@ } skip_fsfstatus: -#if 0 - /* - * This nasty chop at the problem is not working anymore - * as we do not adjust the retry count anylonger in order - * to have a number of retries that avoids I/O errors. - * The manipulation of the retry count has been removed - * in favour of a safe tape device handling. We must not - * sent SCSI commands more than once to a device if no - * retries are permitted by the high level driver. Generally - * speaking, it was a mess to change retry counts. So it is - * fine that this sort of workaround is gone. - * Then, we had to face a certain number of immediate retries in case of - * busy and queue full conditions (see below). - * This is not acceptable - * for the latter. Queue full conditions are used - * by devices to indicate to a host that the host can rely - * on the completion (or timeout) of at least one outstanding - * command as a suggested trigger for command retries. - * Busy conditions require a different trigger since - * no commands are outstanding for that initiator from the - * devices perspective. - * The drawback of mapping a queue full condition to a - * busy condition is the chance of wasting all retries prior - * to the time when the device indicates that a command - * rejected due to a queue full condition should be re-driven. - * This case would lead to unnecessary I/O errors that - * have to be considered fatal if for example ext3's - * journaling would be torpedoed by such an avoidable - * I/O error. - * So, what issues are there with not mapping a queue-full - * condition to a busy condition? - * Due to the 'exclusive LUN' - * policy enforced by the zSeries FCP channel, this - * Linux instance is the only initiator with regard to - * this adapter. It is safe to rely on the information - * 'don't disturb me now ... and btw. no other commands - * pending for you' (= queue full) sent by the LU, - * since no other Linux can use this LUN via this adapter - * at the same time. If there is a potential race - * introduced by the FCP channel by not inhibiting Linux A - * to give up a LU with commands pending while Linux B - * grabs this LU and sends commands - thus providing - * an exploit at the 'exclusive LUN' policy - then this - * issue has to be considered a hardware problem. It should - * be tracked as such if it really occurs. Even if the - * FCP Channel spec. begs exploiters to wait for the - * completion of all request sent to a LU prior to - * closing this LU connection. - * This spec. statement in conjunction with - * the 'exclusive LUN' policy is not consistent design. - * Another issue is how resource constraints for SCSI commands - * might be handled by the FCP channel (just guessing for now). - * If the FCP channel would always map resource constraints, - * e.g. no free FC exchange ID due to I/O stress caused by - * other sharing Linux instances, to faked queue-full - * conditions then this would be a misinterpretation and - * violation of SCSI standards. - * If there are SCSI stack races as indicated below - * then they need to be fixed just there. - * Providing all issue above are not applicable or will - * be fixed appropriately, removing the following hack - * is the right thing to do. - */ - - /* - * Note: This is a rather nasty chop at the problem. We cannot - * risk adding to the mlqueue however as this will block the - * device. If it is the last outstanding command for this host - * it will remain blocked indefinitely. This would be quite possible - * on the zSeries FCP adapter. - * Also, there exists a race with scsi_insert_special relying on - * scsi_request_fn to recalculate some command data which may not - * happen when q->plugged is true in scsi_request_fn - */ - if (status_byte(scpnt->result) == QUEUE_FULL) { - ZFCP_LOG_DEBUG("Changing QUEUE_FULL to BUSY....\n"); - scpnt->result &= ~(QUEUE_FULL << 1); - scpnt->result |= (BUSY << 1); - } -#endif - ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result); zfcp_cmd_dbf_event_scsi("response", scpnt); @@ -4585,16 +4548,6 @@ retval = -EIO; break; - case FSF_UNKNOWN_COMMAND: - ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n"); - ZFCP_LOG_NORMAL( - "FSF command 0x%x is not supported by the adapter %s\n", - fsf_req->fsf_command, - zfcp_get_busid_by_adapter(adapter)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EINVAL; - break; - case FSF_UNKNOWN_OP_SUBTYPE: ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_OP_SUBTYPE\n"); ZFCP_LOG_NORMAL( @@ -4682,8 +4635,8 @@ } static inline int -zfcp_fsf_req_create_sbal_check(unsigned long *flags, - struct zfcp_qdio_queue *queue, int needed) +zfcp_fsf_req_sbal_check(unsigned long *flags, + struct zfcp_qdio_queue *queue, int needed) { write_lock_irqsave(&queue->queue_lock, *flags); if (likely(atomic_read(&queue->free_count) >= needed)) @@ -4712,30 +4665,25 @@ * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue * @adapter: adapter for which request queue is examined * @req_flags: flags indicating whether to wait for needed SBAL or not - * @lock_flags: lock_flags is queue_lock is taken - * - * locking: on success the queue_lock for the request queue of the adapter - * is held + * @lock_flags: lock_flags if queue_lock is taken + * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS + * Locks: lock adapter->request_queue->queue_lock on success */ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags, unsigned long *lock_flags) { - int condition; + long ret; struct zfcp_qdio_queue *req_queue = &adapter->request_queue; if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) { - wait_event_interruptible_timeout(adapter->request_wq, - (condition = - zfcp_fsf_req_create_sbal_check - (lock_flags, req_queue, 1)), - ZFCP_SBAL_TIMEOUT); - if (!condition) { - return -EIO; - } - } else if (!zfcp_fsf_req_create_sbal_check(lock_flags, req_queue, 1)) { + ret = wait_event_interruptible_timeout(adapter->request_wq, + zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1), + ZFCP_SBAL_TIMEOUT); + if (ret < 0) + return ret; + } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) return -EIO; - } return 0; } diff -Nru a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h --- a/drivers/s390/scsi/zfcp_fsf.h 2004-10-18 14:56:50 -07:00 +++ b/drivers/s390/scsi/zfcp_fsf.h 2004-10-18 14:56:50 -07:00 @@ -84,19 +84,12 @@ #define FSF_SERVICE_CLASS_NOT_SUPPORTED 0x00000006 #define FSF_FCPLUN_NOT_VALID 0x00000009 #define FSF_ACCESS_DENIED 0x00000010 -#define FSF_ACCESS_TYPE_NOT_VALID 0x00000011 #define FSF_LUN_SHARING_VIOLATION 0x00000012 -#define FSF_COMMAND_ABORTED_ULP 0x00000020 -#define FSF_COMMAND_ABORTED_ADAPTER 0x00000021 #define FSF_FCP_COMMAND_DOES_NOT_EXIST 0x00000022 #define FSF_DIRECTION_INDICATOR_NOT_VALID 0x00000030 -#define FSF_INBOUND_DATA_LENGTH_NOT_VALID 0x00000031 /* FIX: obsolete? */ -#define FSF_OUTBOUND_DATA_LENGTH_NOT_VALID 0x00000032 /* FIX: obsolete? */ #define FSF_CMND_LENGTH_NOT_VALID 0x00000033 #define FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED 0x00000040 #define FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED 0x00000041 -#define FSF_REQUEST_BUF_NOT_VALID 0x00000042 -#define FSF_RESPONSE_BUF_NOT_VALID 0x00000043 #define FSF_ELS_COMMAND_REJECTED 0x00000050 #define FSF_GENERIC_COMMAND_REJECTED 0x00000051 #define FSF_OPERATION_PARTIALLY_SUCCESSFUL 0x00000052 @@ -227,6 +220,10 @@ #define FSF_HBA_PORTSTATE_LINKDOWN 0x00000006 #define FSF_HBA_PORTSTATE_ERROR 0x00000007 +/* IO states of adapter */ +#define FSF_IOSTAT_NPORT_RJT 0x00000004 +#define FSF_IOSTAT_FABRIC_RJT 0x00000005 +#define FSF_IOSTAT_LS_RJT 0x00000009 struct fsf_queue_designator; struct fsf_status_read_buffer; diff -Nru a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c --- a/drivers/s390/scsi/zfcp_scsi.c 2004-10-18 14:57:20 -07:00 +++ b/drivers/s390/scsi/zfcp_scsi.c 2004-10-18 14:57:20 -07:00 @@ -31,7 +31,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_SCSI_REVISION "$Revision: 1.65 $" +#define ZFCP_SCSI_REVISION "$Revision: 1.68 $" #include "zfcp_ext.h" @@ -247,15 +247,16 @@ /** * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and * zfcp_scsi_command_sync - * @adapter: adapter for where scsi command is issued + * @adapter: adapter where scsi command is issued * @unit: unit to which scsi command is sent * @scpnt: scsi command to be sent + * @timer: timer to be started if request is successfully initiated * * Note: In scsi_done function must be set in scpnt. */ int zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, - struct scsi_cmnd *scpnt) + struct scsi_cmnd *scpnt, struct timer_list *timer) { int tmp; int retval; @@ -291,7 +292,7 @@ goto out; } - tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, + tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, timer, ZFCP_REQ_AUTO_CLEANUP); if (unlikely(tmp < 0)) { @@ -313,18 +314,28 @@ /** * zfcp_scsi_command_sync - send a SCSI command and wait for completion - * returns 0, errors are indicated by scsi_cmnd->result + * @unit: unit where command is sent to + * @scpnt: scsi command to be sent + * @timer: timer to be started if request is successfully initiated + * Return: 0 + * + * Errors are indicated in scpnt->result */ int -zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt) +zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, + struct timer_list *timer) { + int ret; DECLARE_COMPLETION(wait); scpnt->SCp.ptr = (void *) &wait; /* silent re-use */ - scpnt->done = zfcp_scsi_command_sync_handler; - zfcp_scsi_command_async(unit->port->adapter, unit, scpnt); + scpnt->scsi_done = zfcp_scsi_command_sync_handler; + ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, timer); + if ((ret == 0) && (scpnt->result == 0)) wait_for_completion(&wait); + scpnt->SCp.ptr = NULL; + return 0; } @@ -355,7 +366,7 @@ adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; unit = (struct zfcp_unit *) scpnt->device->hostdata; - return zfcp_scsi_command_async(adapter, unit, scpnt); + return zfcp_scsi_command_async(adapter, unit, scpnt, NULL); } /* @@ -430,7 +441,7 @@ u64 dbf_fsf_req = 0; u64 dbf_fsf_status = 0; u64 dbf_fsf_qual[2] = { 0, 0 }; - char dbf_result[ZFCP_ABORT_DBF_LENGTH] = { "##undef" }; + char dbf_result[ZFCP_ABORT_DBF_LENGTH] = "##undef"; memset(dbf_opcode, 0, ZFCP_ABORT_DBF_LENGTH); memcpy(dbf_opcode, diff -Nru a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c 2004-10-18 14:55:54 -07:00 @@ -26,18 +26,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.33 $" +#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.37 $" #include "zfcp_ext.h" #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG static const char fc_topologies[5][25] = { - {""}, - {"point-to-point"}, - {"fabric"}, - {"arbitrated loop"}, - {"fabric (virt. adapter)"} + "", + "point-to-point", + "fabric", + "arbitrated loop", + "fabric (virt. adapter)" }; /** @@ -74,29 +74,8 @@ adapter->hardware_version); ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number); ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no); - -/** - * zfcp_sysfs_adapter_in_recovery_show - recovery state of adapter - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * - * Show function of "in_recovery" attribute of adapter. Will be - * "0" if no error recovery is pending for adapter, otherwise "1". - */ -static ssize_t -zfcp_sysfs_adapter_in_recovery_show(struct device *dev, char *buf) -{ - struct zfcp_adapter *adapter; - - adapter = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static DEVICE_ATTR(in_recovery, S_IRUGO, - zfcp_sysfs_adapter_in_recovery_show, NULL); +ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask + (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)); /** * zfcp_sysfs_port_add_store - add a port to sysfs tree @@ -127,7 +106,7 @@ if ((endp + 1) < (buf + count)) goto out; - port = zfcp_port_enqueue(adapter, wwpn, 0); + port = zfcp_port_enqueue(adapter, wwpn, 0, 0); if (!port) goto out; @@ -138,7 +117,7 @@ zfcp_port_put(port); out: up(&zfcp_data.config_sema); - return retval ? retval : count; + return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); @@ -197,7 +176,7 @@ zfcp_port_dequeue(port); out: up(&zfcp_data.config_sema); - return retval ? retval : count; + return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store); @@ -241,7 +220,7 @@ zfcp_erp_wait(adapter); out: up(&zfcp_data.config_sema); - return retval ? retval : count; + return retval ? retval : (ssize_t) count; } /** diff -Nru a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c --- a/drivers/s390/scsi/zfcp_sysfs_driver.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/s390/scsi/zfcp_sysfs_driver.c 2004-10-18 14:56:50 -07:00 @@ -26,7 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.14 $" +#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.15 $" #include "zfcp_ext.h" @@ -65,7 +65,7 @@ static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \ char *buf) \ { \ - return sprintf(buf,"%d\n", \ + return sprintf(buf,"%d\n", (unsigned int) \ ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \ } \ \ diff -Nru a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c --- a/drivers/s390/scsi/zfcp_sysfs_port.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/s390/scsi/zfcp_sysfs_port.c 2004-10-18 14:57:04 -07:00 @@ -26,7 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.41 $" +#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.44 $" #include "zfcp_ext.h" @@ -66,6 +66,8 @@ ZFCP_DEFINE_PORT_ATTR(wwnn, "0x%016llx\n", port->wwnn); ZFCP_DEFINE_PORT_ATTR(d_id, "0x%06x\n", port->d_id); ZFCP_DEFINE_PORT_ATTR(scsi_id, "0x%x\n", port->scsi_id); +ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask + (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)); /** * zfcp_sysfs_unit_add_store - add a unit to sysfs tree @@ -107,7 +109,7 @@ zfcp_unit_put(unit); out: up(&zfcp_data.config_sema); - return retval ? retval : count; + return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); @@ -164,7 +166,7 @@ zfcp_unit_dequeue(unit); out: up(&zfcp_data.config_sema); - return retval ? retval : count; + return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); @@ -206,7 +208,7 @@ zfcp_erp_wait(port->adapter); out: up(&zfcp_data.config_sema); - return retval ? retval : count; + return retval ? retval : (ssize_t) count; } /** @@ -233,29 +235,6 @@ zfcp_sysfs_port_failed_store); /** - * zfcp_sysfs_port_in_recovery_show - recovery state of port - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * - * Show function of "in_recovery" attribute of port. Will be - * "0" if no error recovery is pending for port, otherwise "1". - */ -static ssize_t -zfcp_sysfs_port_in_recovery_show(struct device *dev, char *buf) -{ - struct zfcp_port *port; - - port = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_port_in_recovery_show, - NULL); - -/** * zfcp_port_common_attrs * sysfs attributes that are common for all kind of fc ports. */ @@ -300,7 +279,7 @@ retval = sysfs_create_group(&dev->kobj, &zfcp_port_common_attr_group); - if ((flags & ZFCP_STATUS_PORT_NAMESERVER) || retval) + if ((flags & ZFCP_STATUS_PORT_WKA) || retval) return retval; retval = sysfs_create_group(&dev->kobj, &zfcp_port_no_ns_attr_group); @@ -320,7 +299,7 @@ zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) { sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); - if (!(flags & ZFCP_STATUS_PORT_NAMESERVER)) + if (!(flags & ZFCP_STATUS_PORT_WKA)) sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); } diff -Nru a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c --- a/drivers/s390/scsi/zfcp_sysfs_unit.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/s390/scsi/zfcp_sysfs_unit.c 2004-10-18 14:57:19 -07:00 @@ -26,7 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.25 $" +#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.27 $" #include "zfcp_ext.h" @@ -64,6 +64,8 @@ ZFCP_DEFINE_UNIT_ATTR(status, "0x%08x\n", atomic_read(&unit->status)); ZFCP_DEFINE_UNIT_ATTR(scsi_lun, "0x%x\n", unit->scsi_lun); +ZFCP_DEFINE_UNIT_ATTR(in_recovery, "%d\n", atomic_test_mask + (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)); /** * zfcp_sysfs_unit_failed_store - failed state of unit @@ -101,7 +103,7 @@ zfcp_erp_wait(unit->port->adapter); out: up(&zfcp_data.config_sema); - return retval ? retval : count; + return retval ? retval : (ssize_t) count; } /** @@ -126,29 +128,6 @@ static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_unit_failed_show, zfcp_sysfs_unit_failed_store); - -/** - * zfcp_sysfs_unit_in_recovery_show - recovery state of unit - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * - * Show function of "in_recovery" attribute of unit. Will be - * "0" if no error recovery is pending for unit, otherwise "1". - */ -static ssize_t -zfcp_sysfs_unit_in_recovery_show(struct device *dev, char *buf) -{ - struct zfcp_unit *unit; - - unit = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_unit_in_recovery_show, - NULL); static struct attribute *zfcp_unit_attrs[] = { &dev_attr_scsi_lun.attr, diff -Nru a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c --- a/drivers/sbus/char/aurora.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/sbus/char/aurora.c 2004-10-18 14:56:13 -07:00 @@ -1531,8 +1531,7 @@ aurora_shutdown_port(bp, port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; port->event = 0; port->tty = 0; @@ -1743,10 +1742,7 @@ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; restore_flags(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); #ifdef AURORA_DEBUG printk("aurora_flush_buffer: end\n"); #endif @@ -2223,10 +2219,7 @@ return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } #ifdef AURORA_DEBUG printk("do_softint: end\n"); diff -Nru a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c --- a/drivers/sbus/char/bbc_envctrl.c 2004-10-18 14:57:20 -07:00 +++ b/drivers/sbus/char/bbc_envctrl.c 2004-10-18 14:57:20 -07:00 @@ -452,7 +452,7 @@ } } -#define POLL_INTERVAL (5 * HZ) +#define POLL_INTERVAL (5 * 1000) static unsigned long last_warning_jiffies; static struct task_struct *kenvctrld_task; @@ -468,8 +468,7 @@ struct bbc_cpu_temperature *tp; struct bbc_fan_control *fp; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(POLL_INTERVAL); + msleep_interruptible(POLL_INTERVAL); if (signal_pending(current)) break; diff -Nru a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c --- a/drivers/sbus/char/bbc_i2c.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/sbus/char/bbc_i2c.c 2004-10-18 14:56:49 -07:00 @@ -189,13 +189,13 @@ while (limit-- > 0) { u8 val; - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); *status = val = readb(bp->i2c_control_regs + 0); if ((val & I2C_PCF_PIN) == 0) { ret = 0; break; } - schedule_timeout(HZ/4); + msleep_interruptible(250); } remove_wait_queue(&bp->wq, &wait); bp->waiting = 0; diff -Nru a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c --- a/drivers/sbus/char/cpwatchdog.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/sbus/char/cpwatchdog.c 2004-10-18 14:57:03 -07:00 @@ -118,40 +118,26 @@ * UNKNOWN, MAGICAL MYSTERY REGISTER * */ -struct wd_timer_regblk { - volatile __u16 dcntr; /* down counter - hw */ - volatile __u16 dcntr_pad; - volatile __u16 limit; /* limit register - hw */ - volatile __u16 limit_pad; - volatile __u8 status; /* status register - b */ - volatile __u8 status_pad; - volatile __u16 status_pad2; - volatile __u32 pad32; /* yet more padding */ -}; - -struct wd_pld_regblk { - volatile __u8 intr_mask; /* interrupt mask - b */ - volatile __u8 intr_mask_pad; - volatile __u16 intr_mask_pad2; - volatile __u8 status; /* device status - b */ - volatile __u8 status_pad; - volatile __u16 status_pad2; -}; +#define WD_TIMER_REGSZ 16 +#define WD0_OFF 0 +#define WD1_OFF (WD_TIMER_REGSZ * 1) +#define WD2_OFF (WD_TIMER_REGSZ * 2) +#define PLD_OFF (WD_TIMER_REGSZ * 3) + +#define WD_DCNTR 0x00 +#define WD_LIMIT 0x04 +#define WD_STATUS 0x08 -struct wd_regblk { - volatile struct wd_timer_regblk wd0_regs; - volatile struct wd_timer_regblk wd1_regs; - volatile struct wd_timer_regblk wd2_regs; - volatile struct wd_pld_regblk pld_regs; -}; +#define PLD_IMASK (PLD_OFF + 0x00) +#define PLD_STATUS (PLD_OFF + 0x04) /* Individual timer structure */ struct wd_timer { __u16 timeout; __u8 intr_mask; - unsigned char runstatus; - volatile struct wd_timer_regblk* regs; + unsigned char runstatus; + void __iomem *regs; }; /* Device structure @@ -165,7 +151,7 @@ unsigned short opt_timeout; unsigned char initialized; struct wd_timer watchdog[WD_NUMDEVS]; - volatile struct wd_regblk* regs; + void __iomem *regs; }; static struct wd_device wd_dev = { @@ -495,12 +481,12 @@ i, wd_getstatus(&wd_dev.watchdog[i])); } - printk("\tintr_mask at 0x%lx: 0x%x\n", - (unsigned long)(&wd_dev.regs->pld_regs.intr_mask), - readb(&wd_dev.regs->pld_regs.intr_mask)); - printk("\tpld_status at 0x%lx: 0x%x\n", - (unsigned long)(&wd_dev.regs->pld_regs.status), - readb(&wd_dev.regs->pld_regs.status)); + printk("\tintr_mask at %p: 0x%x\n", + wd_dev.regs + PLD_IMASK, + readb(wd_dev.regs + PLD_IMASK)); + printk("\tpld_status at %p: 0x%x\n", + wd_dev.regs + PLD_STATUS, + readb(wd_dev.regs + PLD_STATUS)); } #endif @@ -513,7 +499,7 @@ */ static void wd_toggleintr(struct wd_timer* pTimer, int enable) { - unsigned char curregs = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK); unsigned char setregs = (NULL == pTimer) ? (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : @@ -523,7 +509,7 @@ (curregs &= ~setregs): (curregs |= setregs); - wd_writeb(curregs, &wd_dev.regs->pld_regs.intr_mask); + wd_writeb(curregs, wd_dev.regs + PLD_IMASK); return; } @@ -534,8 +520,8 @@ */ static void wd_pingtimer(struct wd_timer* pTimer) { - if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { - wd_readw(&pTimer->regs->dcntr); + if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { + wd_readw(pTimer->regs + WD_DCNTR); } } @@ -547,7 +533,7 @@ */ static void wd_stoptimer(struct wd_timer* pTimer) { - if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { + if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { wd_toggleintr(pTimer, WD_INTR_OFF); if(wd_dev.isbaddoggie) { @@ -574,7 +560,7 @@ } pTimer->runstatus &= ~WD_STAT_SVCD; - wd_writew(pTimer->timeout, &pTimer->regs->limit); + wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT); wd_toggleintr(pTimer, WD_INTR_ON); } @@ -584,7 +570,7 @@ static void wd_resetbrokentimer(struct wd_timer* pTimer) { wd_toggleintr(pTimer, WD_INTR_ON); - wd_writew(WD_BLIMIT, &pTimer->regs->limit); + wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT); } /* Timer device initialization helper. @@ -593,7 +579,7 @@ static int wd_inittimer(int whichdog) { struct miscdevice *whichmisc; - volatile struct wd_timer_regblk *whichregs; + void __iomem *whichregs; char whichident[8]; int whichmask; __u16 whichlimit; @@ -603,7 +589,7 @@ case WD0_ID: whichmisc = &wd0_miscdev; strcpy(whichident, "RIC"); - whichregs = &wd_dev.regs->wd0_regs; + whichregs = wd_dev.regs + WD0_OFF; whichmask = WD0_INTR_MASK; whichlimit= (0 == wd0_timeout) ? (wd_dev.opt_timeout): @@ -612,7 +598,7 @@ case WD1_ID: whichmisc = &wd1_miscdev; strcpy(whichident, "XIR"); - whichregs = &wd_dev.regs->wd1_regs; + whichregs = wd_dev.regs + WD1_OFF; whichmask = WD1_INTR_MASK; whichlimit= (0 == wd1_timeout) ? (wd_dev.opt_timeout): @@ -621,7 +607,7 @@ case WD2_ID: whichmisc = &wd2_miscdev; strcpy(whichident, "POR"); - whichregs = &wd_dev.regs->wd2_regs; + whichregs = wd_dev.regs + WD2_OFF; whichmask = WD2_INTR_MASK; whichlimit= (0 == wd2_timeout) ? (wd_dev.opt_timeout): @@ -686,8 +672,8 @@ static int wd_getstatus(struct wd_timer* pTimer) { - unsigned char stat = wd_readb(&pTimer->regs->status); - unsigned char intr = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char stat = wd_readb(pTimer->regs + WD_STATUS); + unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK); unsigned char ret = WD_STOPPED; /* determine STOPPED */ @@ -805,7 +791,7 @@ * also now eventually trip. */ for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(WD_S_RUNNING == wd_readb(&wd_dev.watchdog[id].regs->status)) { + if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) { if(wd_dev.opt_enable) { printk(KERN_WARNING "%s%i: timer not stopped at release\n", WD_OBPNAME, id); @@ -818,7 +804,7 @@ "%s%i: defect workaround disabled at release, "\ "timer expires in ~%01i sec\n", WD_OBPNAME, id, - wd_readw(&wd_dev.watchdog[id].regs->limit) / 10); + wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10); } } } diff -Nru a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c --- a/drivers/sbus/char/display7seg.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/sbus/char/display7seg.c 2004-10-18 14:56:49 -07:00 @@ -70,7 +70,7 @@ * FLIP - Inverts display for upside-down mounted board * bits 0-4 - 7-segment display contents */ -volatile u8* d7s_regs = NULL; +static void __iomem* d7s_regs; static inline void d7s_free(void) { diff -Nru a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c --- a/drivers/sbus/char/envctrl.c 2004-10-18 14:56:13 -07:00 +++ b/drivers/sbus/char/envctrl.c 2004-10-18 14:56:13 -07:00 @@ -130,10 +130,8 @@ */ #define ENVCTRL_CPCI_IGNORED_NODE 0x70 -struct pcf8584_reg { - unsigned char data; - unsigned char csr; -}; +#define PCF8584_DATA 0x00 +#define PCF8584_CSR 0x01 /* Each child device can be monitored by up to PCF8584_MAX_CHANNELS. * Property of a port or channel as defined by the firmware. @@ -175,7 +173,7 @@ char mon_type[PCF8584_MAX_CHANNELS]; }; -volatile static struct pcf8584_reg *i2c = NULL; +static void __iomem *i2c; static struct i2c_child_t i2c_childlist[ENVCTRL_MAX_CPU*2]; static unsigned char chnls_mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; static unsigned int warning_temperature = 0; @@ -185,22 +183,6 @@ /* Forward declarations. */ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char); -/* Function description: Read a byte from an i2c controller register. - * Return: A byte from the passed in address. - */ -static inline unsigned char envctrl_readb(volatile unsigned char *p) -{ - return readb(p); -} - -/* Function description: Write a byte to an i2c controller register. - * Return: Nothing. - */ -static inline void envctrl_writeb(unsigned char val, volatile unsigned char *p) -{ - writeb(val, p); -} - /* Function Description: Test the PIN bit (Pending Interrupt Not) * to test when serial transmission is completed . * Return : None. @@ -210,7 +192,7 @@ int limit = 1000000; while (--limit > 0) { - if (!(envctrl_readb(&i2c->csr) & STATUS_PIN)) + if (!(readb(i2c + PCF8584_CSR) & STATUS_PIN)) break; udelay(1); } @@ -228,7 +210,7 @@ while (--limit > 0) { /* Busy bit 0 means busy. */ - if (envctrl_readb(&i2c->csr) & STATUS_BB) + if (readb(i2c + PCF8584_CSR) & STATUS_BB) break; udelay(1); } @@ -245,20 +227,20 @@ envctrl_i2c_test_bb(); /* Load address. */ - envctrl_writeb(addr + 1, &i2c->data); + writeb(addr + 1, i2c + PCF8584_DATA); envctrl_i2c_test_bb(); - envctrl_writeb(OBD_SEND_START, &i2c->csr); + writeb(OBD_SEND_START, i2c + PCF8584_CSR); /* Wait for PIN. */ envtrl_i2c_test_pin(); /* CSR 0 means acknowledged. */ - if (!(envctrl_readb(&i2c->csr) & STATUS_LRB)) { - return envctrl_readb(&i2c->data); + if (!(readb(i2c + PCF8584_CSR) & STATUS_LRB)) { + return readb(i2c + PCF8584_DATA); } else { - envctrl_writeb(OBD_SEND_STOP, &i2c->csr); + writeb(OBD_SEND_STOP, i2c + PCF8584_CSR); return 0; } } @@ -269,10 +251,10 @@ static void envctrl_i2c_write_addr(unsigned char addr) { envctrl_i2c_test_bb(); - envctrl_writeb(addr, &i2c->data); + writeb(addr, i2c + PCF8584_DATA); /* Generate Start condition. */ - envctrl_writeb(OBD_SEND_START, &i2c->csr); + writeb(OBD_SEND_START, i2c + PCF8584_CSR); } /* Function Description: Read 1 byte of data from addr @@ -282,8 +264,8 @@ static unsigned char envctrl_i2c_read_data(void) { envtrl_i2c_test_pin(); - envctrl_writeb(CONTROL_ES0, &i2c->csr); /* Send neg ack. */ - return envctrl_readb(&i2c->data); + writeb(CONTROL_ES0, i2c + PCF8584_CSR); /* Send neg ack. */ + return readb(i2c + PCF8584_DATA); } /* Function Description: Instruct the device which port to read data from. @@ -292,7 +274,7 @@ static void envctrl_i2c_write_data(unsigned char port) { envtrl_i2c_test_pin(); - envctrl_writeb(port, &i2c->data); + writeb(port, i2c + PCF8584_DATA); } /* Function Description: Generate Stop condition after last byte is sent. @@ -301,7 +283,7 @@ static void envctrl_i2c_stop(void) { envtrl_i2c_test_pin(); - envctrl_writeb(OBD_SEND_STOP, &i2c->csr); + writeb(OBD_SEND_STOP, i2c + PCF8584_CSR); } /* Function Description: Read adc device. @@ -323,7 +305,7 @@ envctrl_i2c_read_data(); envctrl_i2c_stop(); - return envctrl_readb(&i2c->data); + return readb(i2c + PCF8584_DATA); } /* Function Description: Read gpio device. @@ -1084,8 +1066,7 @@ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "i2c")) { - i2c = ioremap( edev->resource[0].start, - sizeof(struct pcf8584_reg)); + i2c = ioremap(edev->resource[0].start, 0x2); for_each_edevchild(edev, edev_child) { if (!strcmp("gpio", edev_child->prom_name)) { i2c_childlist[i].i2ctype = I2C_GPIO; @@ -1108,15 +1089,15 @@ } /* Set device address. */ - envctrl_writeb(CONTROL_PIN, &i2c->csr); - envctrl_writeb(PCF8584_ADDRESS, &i2c->data); + writeb(CONTROL_PIN, i2c + PCF8584_CSR); + writeb(PCF8584_ADDRESS, i2c + PCF8584_DATA); /* Set system clock and SCL frequencies. */ - envctrl_writeb(CONTROL_PIN | CONTROL_ES1, &i2c->csr); - envctrl_writeb(CLK_4_43 | BUS_CLK_90, &i2c->data); + writeb(CONTROL_PIN | CONTROL_ES1, i2c + PCF8584_CSR); + writeb(CLK_4_43 | BUS_CLK_90, i2c + PCF8584_DATA); /* Enable serial interface. */ - envctrl_writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, &i2c->csr); + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, i2c + PCF8584_CSR); udelay(200); /* Register the device as a minor miscellaneous device. */ diff -Nru a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c --- a/drivers/sbus/char/flash.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/sbus/char/flash.c 2004-10-18 14:56:32 -07:00 @@ -22,6 +22,7 @@ #include #include #include +#include static spinlock_t flash_lock = SPIN_LOCK_UNLOCKED; static struct { @@ -115,7 +116,7 @@ count = flash.read_size - p; for (i = 0; i < count; i++) { - u8 data = readb(flash.read_base + p + i); + u8 data = upa_readb(flash.read_base + p + i); if (put_user(data, buf)) return -EFAULT; buf++; diff -Nru a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c --- a/drivers/sbus/dvma.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/sbus/dvma.c 2004-10-18 14:57:03 -07:00 @@ -17,14 +17,6 @@ struct sbus_dma *dma_chain; -/* Print out the current values in the DMA control registers */ -extern __inline__ void dump_dma_regs(unsigned long dregs) -{ - printk("DMA CONTROL<%08x> ADDR<%08x> CNT<%08x> TEST<%08x>\n", - sbus_readl(dregs + DMA_CSR), sbus_readl(dregs + DMA_ADDR), - sbus_readl(dregs + DMA_COUNT), sbus_readl(dregs + DMA_TEST)); -} - void __init init_one_dvma(struct sbus_dma *dma, int num_dma) { printk("dma%d: ", num_dma); @@ -64,9 +56,6 @@ break; } printk("\n"); -#if 0 /* Clutters up the screen */ - dump_dma_regs(dma->regs); -#endif } /* Probe this SBus DMA module(s) */ diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c --- a/drivers/scsi/3w-xxxx.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/3w-xxxx.c 2004-10-18 14:57:04 -07:00 @@ -551,7 +551,7 @@ /* Now post the command packet */ if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n"); - tw_dev->srb[request_id] = 0; /* Flag internal command */ + tw_dev->srb[request_id] = NULL; /* Flag internal command */ tw_dev->state[request_id] = TW_S_POSTED; outl(command_que_value, command_que_addr); } else { @@ -718,7 +718,7 @@ tw_state_request_start(tw_dev, &request_id); /* Flag internal command */ - tw_dev->srb[request_id] = 0; + tw_dev->srb[request_id] = NULL; /* Flag chrdev ioctl */ tw_dev->chrdev_request_id = request_id; @@ -2692,7 +2692,7 @@ /* Fake like we just shut down, so notify the card that * we "shut down cleanly". */ - tw_halt(0, 0, 0); // parameters aren't actually used + tw_halt(NULL, 0, NULL); // parameters aren't actually used /* Free up the IO region */ release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c --- a/drivers/scsi/BusLogic.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/BusLogic.c 2004-10-18 14:57:04 -07:00 @@ -142,11 +142,8 @@ static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) { - BusLogic_Announce("***** BusLogic SCSI Driver Version " - BusLogic_DriverVersion " of " - BusLogic_DriverDate " *****\n", HostAdapter); - BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff " - "\n", HostAdapter); + BusLogic_Announce("***** BusLogic SCSI Driver Version " BusLogic_DriverVersion " of " BusLogic_DriverDate " *****\n", HostAdapter); + BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff " "\n", HostAdapter); } @@ -157,9 +154,8 @@ static const char *BusLogic_DriverInfo(struct Scsi_Host *Host) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Host->hostdata; - return HostAdapter->FullModelName; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; + return HostAdapter->FullModelName; } @@ -170,17 +166,14 @@ static void __init BusLogic_RegisterHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - HostAdapter->Next = NULL; - if (BusLogic_FirstRegisteredHostAdapter == NULL) - { - BusLogic_FirstRegisteredHostAdapter = HostAdapter; - BusLogic_LastRegisteredHostAdapter = HostAdapter; - } - else - { - BusLogic_LastRegisteredHostAdapter->Next = HostAdapter; - BusLogic_LastRegisteredHostAdapter = HostAdapter; - } + HostAdapter->Next = NULL; + if (BusLogic_FirstRegisteredHostAdapter == NULL) { + BusLogic_FirstRegisteredHostAdapter = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } else { + BusLogic_LastRegisteredHostAdapter->Next = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } } @@ -191,24 +184,18 @@ static void BusLogic_UnregisterHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - if (HostAdapter == BusLogic_FirstRegisteredHostAdapter) - { - BusLogic_FirstRegisteredHostAdapter = - BusLogic_FirstRegisteredHostAdapter->Next; - if (HostAdapter == BusLogic_LastRegisteredHostAdapter) - BusLogic_LastRegisteredHostAdapter = NULL; - } - else - { - struct BusLogic_HostAdapter *PreviousHostAdapter = - BusLogic_FirstRegisteredHostAdapter; - while (PreviousHostAdapter != NULL && - PreviousHostAdapter->Next != HostAdapter) - PreviousHostAdapter = PreviousHostAdapter->Next; - if (PreviousHostAdapter != NULL) - PreviousHostAdapter->Next = HostAdapter->Next; - } - HostAdapter->Next = NULL; + if (HostAdapter == BusLogic_FirstRegisteredHostAdapter) { + BusLogic_FirstRegisteredHostAdapter = BusLogic_FirstRegisteredHostAdapter->Next; + if (HostAdapter == BusLogic_LastRegisteredHostAdapter) + BusLogic_LastRegisteredHostAdapter = NULL; + } else { + struct BusLogic_HostAdapter *PreviousHostAdapter = BusLogic_FirstRegisteredHostAdapter; + while (PreviousHostAdapter != NULL && PreviousHostAdapter->Next != HostAdapter) + PreviousHostAdapter = PreviousHostAdapter->Next; + if (PreviousHostAdapter != NULL) + PreviousHostAdapter->Next = HostAdapter->Next; + } + HostAdapter->Next = NULL; } @@ -218,33 +205,29 @@ created CCBs are added to Host Adapter's free list. */ -static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, - void *BlockPointer, int BlockSize, - dma_addr_t BlockPointerHandle) -{ - struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) BlockPointer; - unsigned int offset = 0; - memset(BlockPointer, 0, BlockSize); - CCB->AllocationGroupHead = BlockPointerHandle; - CCB->AllocationGroupSize = BlockSize; - while ((BlockSize -= sizeof(struct BusLogic_CCB)) >= 0) - { - CCB->Status = BusLogic_CCB_Free; - CCB->HostAdapter = HostAdapter; - CCB->DMA_Handle = (u32)BlockPointerHandle + offset; - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - CCB->CallbackFunction = BusLogic_QueueCompletedCCB; - CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; - } - CCB->Next = HostAdapter->Free_CCBs; - CCB->NextAll = HostAdapter->All_CCBs; - HostAdapter->Free_CCBs = CCB; - HostAdapter->All_CCBs = CCB; - HostAdapter->AllocatedCCBs++; - CCB++; - offset += sizeof(struct BusLogic_CCB); - } +static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, void *BlockPointer, int BlockSize, dma_addr_t BlockPointerHandle) +{ + struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) BlockPointer; + unsigned int offset = 0; + memset(BlockPointer, 0, BlockSize); + CCB->AllocationGroupHead = BlockPointerHandle; + CCB->AllocationGroupSize = BlockSize; + while ((BlockSize -= sizeof(struct BusLogic_CCB)) >= 0) { + CCB->Status = BusLogic_CCB_Free; + CCB->HostAdapter = HostAdapter; + CCB->DMA_Handle = (u32) BlockPointerHandle + offset; + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + CCB->CallbackFunction = BusLogic_QueueCompletedCCB; + CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; + } + CCB->Next = HostAdapter->Free_CCBs; + CCB->NextAll = HostAdapter->All_CCBs; + HostAdapter->Free_CCBs = CCB; + HostAdapter->All_CCBs = CCB; + HostAdapter->AllocatedCCBs++; + CCB++; + offset += sizeof(struct BusLogic_CCB); + } } @@ -254,23 +237,18 @@ static boolean __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter) { - int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); - void *BlockPointer; - dma_addr_t BlockPointerHandle; - while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) - { - BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, - &BlockPointerHandle); - if (BlockPointer == NULL) - { - BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", - HostAdapter); - return false; - } - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, - BlockPointerHandle); - } - return true; + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); + void *BlockPointer; + dma_addr_t BlockPointerHandle; + while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) { + BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle); + if (BlockPointer == NULL) { + BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", HostAdapter); + return false; + } + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle); + } + return true; } @@ -280,25 +258,19 @@ static void BusLogic_DestroyCCBs(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_CCB *NextCCB = HostAdapter->All_CCBs, *CCB, *Last_CCB = NULL; - HostAdapter->All_CCBs = NULL; - HostAdapter->Free_CCBs = NULL; - while ((CCB = NextCCB) != NULL) - { - NextCCB = CCB->NextAll; - if (CCB->AllocationGroupHead) - { - if (Last_CCB) - pci_free_consistent(HostAdapter->PCI_Device, - Last_CCB->AllocationGroupSize, Last_CCB, - Last_CCB->AllocationGroupHead); - Last_CCB = CCB; - } - } - if (Last_CCB) - pci_free_consistent(HostAdapter->PCI_Device, - Last_CCB->AllocationGroupSize, Last_CCB, - Last_CCB->AllocationGroupHead); + struct BusLogic_CCB *NextCCB = HostAdapter->All_CCBs, *CCB, *Last_CCB = NULL; + HostAdapter->All_CCBs = NULL; + HostAdapter->Free_CCBs = NULL; + while ((CCB = NextCCB) != NULL) { + NextCCB = CCB->NextAll; + if (CCB->AllocationGroupHead) { + if (Last_CCB) + pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead); + Last_CCB = CCB; + } + } + if (Last_CCB) + pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead); } @@ -309,40 +281,30 @@ multiple host adapters share the same IRQ Channel. */ -static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, - int AdditionalCCBs, - boolean SuccessMessageP) -{ - int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); - int PreviouslyAllocated = HostAdapter->AllocatedCCBs; - void *BlockPointer; - dma_addr_t BlockPointerHandle; - if (AdditionalCCBs <= 0) return; - while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) - { - BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, - &BlockPointerHandle); - if (BlockPointer == NULL) break; - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, - BlockPointerHandle); - } - if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) - { - if (SuccessMessageP) - BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", - HostAdapter, - HostAdapter->AllocatedCCBs - PreviouslyAllocated, - HostAdapter->AllocatedCCBs); - return; - } - BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); - if (HostAdapter->DriverQueueDepth > - HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) - { - HostAdapter->DriverQueueDepth = - HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; - HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; - } +static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, boolean SuccessMessageP) +{ + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); + int PreviouslyAllocated = HostAdapter->AllocatedCCBs; + void *BlockPointer; + dma_addr_t BlockPointerHandle; + if (AdditionalCCBs <= 0) + return; + while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) { + BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle); + if (BlockPointer == NULL) + break; + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle); + } + if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) { + if (SuccessMessageP) + BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", HostAdapter, HostAdapter->AllocatedCCBs - PreviouslyAllocated, HostAdapter->AllocatedCCBs); + return; + } + BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); + if (HostAdapter->DriverQueueDepth > HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) { + HostAdapter->DriverQueueDepth = HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; + HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; + } } /* @@ -352,31 +314,27 @@ */ static struct BusLogic_CCB *BusLogic_AllocateCCB(struct BusLogic_HostAdapter - *HostAdapter) + *HostAdapter) { - static unsigned long SerialNumber = 0; - struct BusLogic_CCB *CCB; - CCB = HostAdapter->Free_CCBs; - if (CCB != NULL) - { - CCB->SerialNumber = ++SerialNumber; - HostAdapter->Free_CCBs = CCB->Next; - CCB->Next = NULL; - if (HostAdapter->Free_CCBs == NULL) - BusLogic_CreateAdditionalCCBs(HostAdapter, - HostAdapter->IncrementalCCBs, - true); - return CCB; - } - BusLogic_CreateAdditionalCCBs(HostAdapter, - HostAdapter->IncrementalCCBs, - true); - CCB = HostAdapter->Free_CCBs; - if (CCB == NULL) return NULL; - CCB->SerialNumber = ++SerialNumber; - HostAdapter->Free_CCBs = CCB->Next; - CCB->Next = NULL; - return CCB; + static unsigned long SerialNumber = 0; + struct BusLogic_CCB *CCB; + CCB = HostAdapter->Free_CCBs; + if (CCB != NULL) { + CCB->SerialNumber = ++SerialNumber; + HostAdapter->Free_CCBs = CCB->Next; + CCB->Next = NULL; + if (HostAdapter->Free_CCBs == NULL) + BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true); + return CCB; + } + BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true); + CCB = HostAdapter->Free_CCBs; + if (CCB == NULL) + return NULL; + CCB->SerialNumber = ++SerialNumber; + HostAdapter->Free_CCBs = CCB->Next; + CCB->Next = NULL; + return CCB; } @@ -388,26 +346,17 @@ static void BusLogic_DeallocateCCB(struct BusLogic_CCB *CCB) { - struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; - if (CCB->Command->use_sg != 0) - { - pci_unmap_sg(HostAdapter->PCI_Device, - (struct scatterlist *)CCB->Command->request_buffer, - CCB->Command->use_sg, - scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); - } - else if (CCB->Command->request_bufflen != 0) - { - pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer, - CCB->DataLength, - scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); - } - pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer, - CCB->SenseDataLength, PCI_DMA_FROMDEVICE); - CCB->Command = NULL; - CCB->Status = BusLogic_CCB_Free; - CCB->Next = HostAdapter->Free_CCBs; - HostAdapter->Free_CCBs = CCB; + struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; + if (CCB->Command->use_sg != 0) { + pci_unmap_sg(HostAdapter->PCI_Device, (struct scatterlist *) CCB->Command->request_buffer, CCB->Command->use_sg, scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); + } else if (CCB->Command->request_bufflen != 0) { + pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer, CCB->DataLength, scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); + } + pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE); + CCB->Command = NULL; + CCB->Status = BusLogic_CCB_Free; + CCB->Next = HostAdapter->Free_CCBs; + HostAdapter->Free_CCBs = CCB; } @@ -429,228 +378,205 @@ waiting for the Host Adapter Ready bit to be set in the Status Register. */ -static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, - enum BusLogic_OperationCode OperationCode, - void *ParameterData, - int ParameterLength, - void *ReplyData, - int ReplyLength) -{ - unsigned char *ParameterPointer = (unsigned char *) ParameterData; - unsigned char *ReplyPointer = (unsigned char *) ReplyData; - union BusLogic_StatusRegister StatusRegister; - union BusLogic_InterruptRegister InterruptRegister; - unsigned long ProcessorFlags = 0; - int ReplyBytes = 0, Result; - long TimeoutCounter; - /* - Clear out the Reply Data if provided. - */ - if (ReplyLength > 0) - memset(ReplyData, 0, ReplyLength); - /* - If the IRQ Channel has not yet been acquired, then interrupts must be - disabled while issuing host adapter commands since a Command Complete - interrupt could occur if the IRQ Channel was previously enabled by another - BusLogic Host Adapter or another driver sharing the same IRQ Channel. - */ - if (!HostAdapter->IRQ_ChannelAcquired) - { - local_irq_save(ProcessorFlags); - local_irq_disable(); - } - /* - Wait for the Host Adapter Ready bit to be set and the Command/Parameter - Register Busy bit to be reset in the Status Register. - */ - TimeoutCounter = 10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.HostAdapterReady && - !StatusRegister.sr.CommandParameterRegisterBusy) - break; - udelay(100); - } - if (TimeoutCounter < 0) - { - BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready"; - Result = -2; - goto Done; - } - /* - Write the OperationCode to the Command/Parameter Register. - */ - HostAdapter->HostAdapterCommandCompleted = false; - BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode); - /* - Write any additional Parameter Bytes. - */ - TimeoutCounter = 10000; - while (ParameterLength > 0 && --TimeoutCounter >= 0) - { - /* - Wait 100 microseconds to give the Host Adapter enough time to determine - whether the last value written to the Command/Parameter Register was - valid or not. If the Command Complete bit is set in the Interrupt - Register, then the Command Invalid bit in the Status Register will be - reset if the Operation Code or Parameter was valid and the command - has completed, or set if the Operation Code or Parameter was invalid. - If the Data In Register Ready bit is set in the Status Register, then - the Operation Code was valid, and data is waiting to be read back - from the Host Adapter. Otherwise, wait for the Command/Parameter - Register Busy bit in the Status Register to be reset. - */ - udelay(100); - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister.ir.CommandComplete) break; - if (HostAdapter->HostAdapterCommandCompleted) break; - if (StatusRegister.sr.DataInRegisterReady) break; - if (StatusRegister.sr.CommandParameterRegisterBusy) continue; - BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++); - ParameterLength--; - } - if (TimeoutCounter < 0) - { - BusLogic_CommandFailureReason = - "Timeout waiting for Parameter Acceptance"; - Result = -2; - goto Done; - } - /* - The Modify I/O Address command does not cause a Command Complete Interrupt. - */ - if (OperationCode == BusLogic_ModifyIOAddress) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.CommandInvalid) - { - BusLogic_CommandFailureReason = "Modify I/O Address Invalid"; - Result = -1; - goto Done; - } - if (BusLogic_GlobalOptions.TraceConfiguration) - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " - "(Modify I/O Address)\n", HostAdapter, - OperationCode, StatusRegister.All); - Result = 0; - goto Done; - } - /* - Select an appropriate timeout value for awaiting command completion. - */ - switch (OperationCode) - { - case BusLogic_InquireInstalledDevicesID0to7: - case BusLogic_InquireInstalledDevicesID8to15: - case BusLogic_InquireTargetDevices: - /* Approximately 60 seconds. */ - TimeoutCounter = 60*10000; - break; - default: - /* Approximately 1 second. */ - TimeoutCounter = 10000; - break; - } - /* - Receive any Reply Bytes, waiting for either the Command Complete bit to - be set in the Interrupt Register, or for the Interrupt Handler to set the - Host Adapter Command Completed bit in the Host Adapter structure. - */ - while (--TimeoutCounter >= 0) - { - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister.ir.CommandComplete) break; - if (HostAdapter->HostAdapterCommandCompleted) break; - if (StatusRegister.sr.DataInRegisterReady) - { - if (++ReplyBytes <= ReplyLength) - *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); - else BusLogic_ReadDataInRegister(HostAdapter); - } - if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && - StatusRegister.sr.HostAdapterReady) break; - udelay(100); - } - if (TimeoutCounter < 0) - { - BusLogic_CommandFailureReason = "Timeout waiting for Command Complete"; - Result = -2; - goto Done; - } - /* - Clear any pending Command Complete Interrupt. - */ - BusLogic_InterruptReset(HostAdapter); - /* - Provide tracing information if requested. - */ - if (BusLogic_GlobalOptions.TraceConfiguration) - { - int i; - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", - HostAdapter, OperationCode, - StatusRegister.All, ReplyLength, ReplyBytes); - if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; - for (i = 0; i < ReplyLength; i++) - BusLogic_Notice(" %02X", HostAdapter, - ((unsigned char *) ReplyData)[i]); - BusLogic_Notice("\n", HostAdapter); - } - /* - Process Command Invalid conditions. - */ - if (StatusRegister.sr.CommandInvalid) - { - /* - Some early BusLogic Host Adapters may not recover properly from - a Command Invalid condition, so if this appears to be the case, - a Soft Reset is issued to the Host Adapter. Potentially invalid - commands are never attempted after Mailbox Initialization is - performed, so there should be no Host Adapter state lost by a - Soft Reset in response to a Command Invalid condition. - */ - udelay(1000); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.CommandInvalid || - StatusRegister.sr.Reserved || - StatusRegister.sr.DataInRegisterReady || - StatusRegister.sr.CommandParameterRegisterBusy || - !StatusRegister.sr.HostAdapterReady || - !StatusRegister.sr.InitializationRequired || - StatusRegister.sr.DiagnosticActive || - StatusRegister.sr.DiagnosticFailure) - { - BusLogic_SoftReset(HostAdapter); - udelay(1000); - } - BusLogic_CommandFailureReason = "Command Invalid"; - Result = -1; - goto Done; - } - /* - Handle Excess Parameters Supplied conditions. - */ - if (ParameterLength > 0) - { - BusLogic_CommandFailureReason = "Excess Parameters Supplied"; - Result = -1; - goto Done; - } - /* - Indicate the command completed successfully. - */ - BusLogic_CommandFailureReason = NULL; - Result = ReplyBytes; - /* - Restore the interrupt status if necessary and return. - */ -Done: - if (!HostAdapter->IRQ_ChannelAcquired) - local_irq_restore(ProcessorFlags); - return Result; +static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_OperationCode OperationCode, void *ParameterData, int ParameterLength, void *ReplyData, int ReplyLength) +{ + unsigned char *ParameterPointer = (unsigned char *) ParameterData; + unsigned char *ReplyPointer = (unsigned char *) ReplyData; + union BusLogic_StatusRegister StatusRegister; + union BusLogic_InterruptRegister InterruptRegister; + unsigned long ProcessorFlags = 0; + int ReplyBytes = 0, Result; + long TimeoutCounter; + /* + Clear out the Reply Data if provided. + */ + if (ReplyLength > 0) + memset(ReplyData, 0, ReplyLength); + /* + If the IRQ Channel has not yet been acquired, then interrupts must be + disabled while issuing host adapter commands since a Command Complete + interrupt could occur if the IRQ Channel was previously enabled by another + BusLogic Host Adapter or another driver sharing the same IRQ Channel. + */ + if (!HostAdapter->IRQ_ChannelAcquired) { + local_irq_save(ProcessorFlags); + local_irq_disable(); + } + /* + Wait for the Host Adapter Ready bit to be set and the Command/Parameter + Register Busy bit to be reset in the Status Register. + */ + TimeoutCounter = 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.HostAdapterReady && !StatusRegister.sr.CommandParameterRegisterBusy) + break; + udelay(100); + } + if (TimeoutCounter < 0) { + BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready"; + Result = -2; + goto Done; + } + /* + Write the OperationCode to the Command/Parameter Register. + */ + HostAdapter->HostAdapterCommandCompleted = false; + BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode); + /* + Write any additional Parameter Bytes. + */ + TimeoutCounter = 10000; + while (ParameterLength > 0 && --TimeoutCounter >= 0) { + /* + Wait 100 microseconds to give the Host Adapter enough time to determine + whether the last value written to the Command/Parameter Register was + valid or not. If the Command Complete bit is set in the Interrupt + Register, then the Command Invalid bit in the Status Register will be + reset if the Operation Code or Parameter was valid and the command + has completed, or set if the Operation Code or Parameter was invalid. + If the Data In Register Ready bit is set in the Status Register, then + the Operation Code was valid, and data is waiting to be read back + from the Host Adapter. Otherwise, wait for the Command/Parameter + Register Busy bit in the Status Register to be reset. + */ + udelay(100); + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (InterruptRegister.ir.CommandComplete) + break; + if (HostAdapter->HostAdapterCommandCompleted) + break; + if (StatusRegister.sr.DataInRegisterReady) + break; + if (StatusRegister.sr.CommandParameterRegisterBusy) + continue; + BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++); + ParameterLength--; + } + if (TimeoutCounter < 0) { + BusLogic_CommandFailureReason = "Timeout waiting for Parameter Acceptance"; + Result = -2; + goto Done; + } + /* + The Modify I/O Address command does not cause a Command Complete Interrupt. + */ + if (OperationCode == BusLogic_ModifyIOAddress) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.CommandInvalid) { + BusLogic_CommandFailureReason = "Modify I/O Address Invalid"; + Result = -1; + goto Done; + } + if (BusLogic_GlobalOptions.TraceConfiguration) + BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " "(Modify I/O Address)\n", HostAdapter, OperationCode, StatusRegister.All); + Result = 0; + goto Done; + } + /* + Select an appropriate timeout value for awaiting command completion. + */ + switch (OperationCode) { + case BusLogic_InquireInstalledDevicesID0to7: + case BusLogic_InquireInstalledDevicesID8to15: + case BusLogic_InquireTargetDevices: + /* Approximately 60 seconds. */ + TimeoutCounter = 60 * 10000; + break; + default: + /* Approximately 1 second. */ + TimeoutCounter = 10000; + break; + } + /* + Receive any Reply Bytes, waiting for either the Command Complete bit to + be set in the Interrupt Register, or for the Interrupt Handler to set the + Host Adapter Command Completed bit in the Host Adapter structure. + */ + while (--TimeoutCounter >= 0) { + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (InterruptRegister.ir.CommandComplete) + break; + if (HostAdapter->HostAdapterCommandCompleted) + break; + if (StatusRegister.sr.DataInRegisterReady) { + if (++ReplyBytes <= ReplyLength) + *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); + else + BusLogic_ReadDataInRegister(HostAdapter); + } + if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && StatusRegister.sr.HostAdapterReady) + break; + udelay(100); + } + if (TimeoutCounter < 0) { + BusLogic_CommandFailureReason = "Timeout waiting for Command Complete"; + Result = -2; + goto Done; + } + /* + Clear any pending Command Complete Interrupt. + */ + BusLogic_InterruptReset(HostAdapter); + /* + Provide tracing information if requested. + */ + if (BusLogic_GlobalOptions.TraceConfiguration) { + int i; + BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", HostAdapter, OperationCode, StatusRegister.All, ReplyLength, ReplyBytes); + if (ReplyLength > ReplyBytes) + ReplyLength = ReplyBytes; + for (i = 0; i < ReplyLength; i++) + BusLogic_Notice(" %02X", HostAdapter, ((unsigned char *) ReplyData)[i]); + BusLogic_Notice("\n", HostAdapter); + } + /* + Process Command Invalid conditions. + */ + if (StatusRegister.sr.CommandInvalid) { + /* + Some early BusLogic Host Adapters may not recover properly from + a Command Invalid condition, so if this appears to be the case, + a Soft Reset is issued to the Host Adapter. Potentially invalid + commands are never attempted after Mailbox Initialization is + performed, so there should be no Host Adapter state lost by a + Soft Reset in response to a Command Invalid condition. + */ + udelay(1000); + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.CommandInvalid || + StatusRegister.sr.Reserved || + StatusRegister.sr.DataInRegisterReady || + StatusRegister.sr.CommandParameterRegisterBusy || !StatusRegister.sr.HostAdapterReady || !StatusRegister.sr.InitializationRequired || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.DiagnosticFailure) { + BusLogic_SoftReset(HostAdapter); + udelay(1000); + } + BusLogic_CommandFailureReason = "Command Invalid"; + Result = -1; + goto Done; + } + /* + Handle Excess Parameters Supplied conditions. + */ + if (ParameterLength > 0) { + BusLogic_CommandFailureReason = "Excess Parameters Supplied"; + Result = -1; + goto Done; + } + /* + Indicate the command completed successfully. + */ + BusLogic_CommandFailureReason = NULL; + Result = ReplyBytes; + /* + Restore the interrupt status if necessary and return. + */ + Done: + if (!HostAdapter->IRQ_ChannelAcquired) + local_irq_restore(ProcessorFlags); + return Result; } @@ -662,13 +588,14 @@ static void __init BusLogic_AppendProbeAddressISA(unsigned long IO_Address) { - struct BusLogic_ProbeInfo *ProbeInfo; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return; - ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Device = NULL; + struct BusLogic_ProbeInfo *ProbeInfo; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) + return; + ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_MultiMaster; + ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Device = NULL; } @@ -681,38 +608,27 @@ static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - /* - If BusLogic Driver Options specifications requested that ISA Bus Probes - be inhibited, do not proceed further. - */ - if (BusLogic_ProbeOptions.NoProbeISA) return; - /* - Append the list of standard BusLogic MultiMaster ISA I/O Addresses. - */ - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe330 - : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x330); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe334 - : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x334); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe230 - : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x230); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe234 - : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x234); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe130 - : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x130); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe134 - : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x134); + /* + If BusLogic Driver Options specifications requested that ISA Bus Probes + be inhibited, do not proceed further. + */ + if (BusLogic_ProbeOptions.NoProbeISA) + return; + /* + Append the list of standard BusLogic MultiMaster ISA I/O Addresses. + */ + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x330); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x334); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x230); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x234); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x130); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x134); } @@ -724,30 +640,24 @@ of increasing PCI Bus and Device Number. */ -static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoList, - int ProbeInfoCount) +static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoList, int ProbeInfoCount) { - int LastInterchange = ProbeInfoCount-1, Bound, j; - while (LastInterchange > 0) - { - Bound = LastInterchange; - LastInterchange = 0; - for (j = 0; j < Bound; j++) - { - struct BusLogic_ProbeInfo *ProbeInfo1 = &ProbeInfoList[j]; - struct BusLogic_ProbeInfo *ProbeInfo2 = &ProbeInfoList[j+1]; - if (ProbeInfo1->Bus > ProbeInfo2->Bus || - (ProbeInfo1->Bus == ProbeInfo2->Bus && - (ProbeInfo1->Device > ProbeInfo2->Device))) - { - struct BusLogic_ProbeInfo TempProbeInfo; - memcpy(&TempProbeInfo, ProbeInfo1, sizeof(struct BusLogic_ProbeInfo)); - memcpy(ProbeInfo1, ProbeInfo2, sizeof(struct BusLogic_ProbeInfo)); - memcpy(ProbeInfo2, &TempProbeInfo, sizeof(struct BusLogic_ProbeInfo)); - LastInterchange = j; - } + int LastInterchange = ProbeInfoCount - 1, Bound, j; + while (LastInterchange > 0) { + Bound = LastInterchange; + LastInterchange = 0; + for (j = 0; j < Bound; j++) { + struct BusLogic_ProbeInfo *ProbeInfo1 = &ProbeInfoList[j]; + struct BusLogic_ProbeInfo *ProbeInfo2 = &ProbeInfoList[j + 1]; + if (ProbeInfo1->Bus > ProbeInfo2->Bus || (ProbeInfo1->Bus == ProbeInfo2->Bus && (ProbeInfo1->Device > ProbeInfo2->Device))) { + struct BusLogic_ProbeInfo TempProbeInfo; + memcpy(&TempProbeInfo, ProbeInfo1, sizeof(struct BusLogic_ProbeInfo)); + memcpy(ProbeInfo1, ProbeInfo2, sizeof(struct BusLogic_ProbeInfo)); + memcpy(ProbeInfo2, &TempProbeInfo, sizeof(struct BusLogic_ProbeInfo)); + LastInterchange = j; + } + } } - } } @@ -762,292 +672,226 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - struct BusLogic_ProbeInfo *PrimaryProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; - int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; - int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; - boolean ForceBusDeviceScanningOrder = false; - boolean ForceBusDeviceScanningOrderChecked = false; - boolean StandardAddressSeen[6]; - struct pci_dev *PCI_Device = NULL; - int i; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0; - BusLogic_ProbeInfoCount++; - for (i = 0; i < 6; i++) - StandardAddressSeen[i] = false; - /* - Iterate over the MultiMaster PCI Host Adapters. For each enumerated host - adapter, determine whether its ISA Compatible I/O Port is enabled and if - so, whether it is assigned the Primary I/O Address. A host adapter that is - assigned the Primary I/O Address will always be the preferred boot device. - The MultiMaster BIOS will first recognize a host adapter at the Primary I/O - Address, then any other PCI host adapters, and finally any host adapters - located at the remaining standard ISA I/O Addresses. When a PCI host - adapter is found with its ISA Compatible I/O Port enabled, a command is - issued to disable the ISA Compatible I/O Port, and it is noted that the - particular standard ISA I/O Address need not be probed. - */ - PrimaryProbeInfo->IO_Address = 0; - while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, - PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, - PCI_Device)) != NULL) - { - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; - enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest; - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long BaseAddress0; - unsigned long BaseAddress1; - unsigned long IO_Address; - unsigned long PCI_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); - PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); - - if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) - { - BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " - "MultiMaster Host Adapter\n", NULL, BaseAddress0); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (pci_resource_flags(PCI_Device,1) & IORESOURCE_IO) - { - BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " - "MultiMaster Host Adapter\n", NULL, BaseAddress1); - BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", - NULL, Bus, Device, PCI_Address); - continue; - } - if (IRQ_Channel == 0) - { - BusLogic_Error("BusLogic: IRQ Channel %d invalid for " - "MultiMaster Host Adapter\n", NULL, IRQ_Channel); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (BusLogic_GlobalOptions.TraceProbe) - { - BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " - "detected at\n", NULL); - BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " - "0x%X PCI Address 0x%X\n", NULL, - Bus, Device, IO_Address, PCI_Address); - } - /* - Issue the Inquire PCI Host Adapter Information command to determine - the ISA Compatible I/O Port. If the ISA Compatible I/O Port is - known and enabled, note that the particular Standard ISA I/O - Address should not be probed. - */ - HostAdapter->IO_Address = IO_Address; - BusLogic_InterruptReset(HostAdapter); - if (BusLogic_Command(HostAdapter, - BusLogic_InquirePCIHostAdapterInformation, - NULL, 0, &PCIHostAdapterInformation, - sizeof(PCIHostAdapterInformation)) - == sizeof(PCIHostAdapterInformation)) - { - if (PCIHostAdapterInformation.ISACompatibleIOPort < 6) - StandardAddressSeen[PCIHostAdapterInformation - .ISACompatibleIOPort] = true; - } - else PCIHostAdapterInformation.ISACompatibleIOPort = - BusLogic_IO_Disable; - /* - * Issue the Modify I/O Address command to disable the ISA Compatible - * I/O Port. On PCI Host Adapters, the Modify I/O Address command - * allows modification of the ISA compatible I/O Address that the Host - * Adapter responds to; it does not affect the PCI compliant I/O Address - * assigned at system initialization. - */ - ModifyIOAddressRequest = BusLogic_IO_Disable; - BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress, - &ModifyIOAddressRequest, - sizeof(ModifyIOAddressRequest), NULL, 0); - /* - For the first MultiMaster Host Adapter enumerated, issue the Fetch - Host Adapter Local RAM command to read byte 45 of the AutoSCSI area, - for the setting of the "Use Bus And Device # For PCI Scanning Seq." - option. Issue the Inquire Board ID command since this option is - only valid for the BT-948/958/958D. - */ - if (!ForceBusDeviceScanningOrderChecked) - { - struct BusLogic_FetchHostAdapterLocalRAMRequest - FetchHostAdapterLocalRAMRequest; - struct BusLogic_AutoSCSIByte45 AutoSCSIByte45; - struct BusLogic_BoardID BoardID; - FetchHostAdapterLocalRAMRequest.ByteOffset = - BusLogic_AutoSCSI_BaseOffset + 45; - FetchHostAdapterLocalRAMRequest.ByteCount = - sizeof(AutoSCSIByte45); - BusLogic_Command(HostAdapter, - BusLogic_FetchHostAdapterLocalRAM, - &FetchHostAdapterLocalRAMRequest, - sizeof(FetchHostAdapterLocalRAMRequest), - &AutoSCSIByte45, sizeof(AutoSCSIByte45)); - BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, - NULL, 0, &BoardID, sizeof(BoardID)); - if (BoardID.FirmwareVersion1stDigit == '5') - ForceBusDeviceScanningOrder = - AutoSCSIByte45.ForceBusDeviceScanningOrder; - ForceBusDeviceScanningOrderChecked = true; - } - /* - Determine whether this MultiMaster Host Adapter has its ISA - Compatible I/O Port enabled and is assigned the Primary I/O Address. - If it does, then it is the Primary MultiMaster Host Adapter and must - be recognized first. If it does not, then it is added to the list - for probing after any Primary MultiMaster Host Adapter is probed. - */ - if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) - { - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - PrimaryProbeInfo->IO_Address = IO_Address; - PrimaryProbeInfo->PCI_Address = PCI_Address; - PrimaryProbeInfo->Bus = Bus; - PrimaryProbeInfo->Device = Device; - PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; - PrimaryProbeInfo->PCI_Device = PCI_Device; - PCIMultiMasterCount++; - } - else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) - { - struct BusLogic_ProbeInfo *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = PCI_Device; - NonPrimaryPCIMultiMasterCount++; - PCIMultiMasterCount++; - } - else BusLogic_Warning("BusLogic: Too many Host Adapters " - "detected\n", NULL); - } - /* - If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON - for the first enumerated MultiMaster Host Adapter, and if that host adapter - is a BT-948/958/958D, then the MultiMaster BIOS will recognize MultiMaster - Host Adapters in the order of increasing PCI Bus and Device Number. In - that case, sort the probe information into the same order the BIOS uses. - If this option is OFF, then the MultiMaster BIOS will recognize MultiMaster - Host Adapters in the order they are enumerated by the PCI BIOS, and hence - no sorting is necessary. - */ - if (ForceBusDeviceScanningOrder) - BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[ - NonPrimaryPCIMultiMasterIndex], - NonPrimaryPCIMultiMasterCount); - /* - If no PCI MultiMaster Host Adapter is assigned the Primary I/O Address, - then the Primary I/O Address must be probed explicitly before any PCI - host adapters are probed. - */ - if (!BusLogic_ProbeOptions.NoProbeISA) - if (PrimaryProbeInfo->IO_Address == 0 && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe330 - : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) - { - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - PrimaryProbeInfo->IO_Address = 0x330; - } - /* - Append the list of standard BusLogic MultiMaster ISA I/O Addresses, - omitting the Primary I/O Address which has already been handled. - */ - if (!BusLogic_ProbeOptions.NoProbeISA) - { - if (!StandardAddressSeen[1] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe334 - : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x334); - if (!StandardAddressSeen[2] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe230 - : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x230); - if (!StandardAddressSeen[3] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe234 - : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x234); - if (!StandardAddressSeen[4] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe130 - : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x130); - if (!StandardAddressSeen[5] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe134 - : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x134); - } - /* - Iterate over the older non-compliant MultiMaster PCI Host Adapters, - noting the PCI bus location and assigned IRQ Channel. - */ - PCI_Device = NULL; - while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, - PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, - PCI_Device)) != NULL) - { - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long IO_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = pci_resource_start(PCI_Device, 0); - - if (IO_Address == 0 || IRQ_Channel == 0) continue; - for (i = 0; i < BusLogic_ProbeInfoCount; i++) - { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[i]; - if (ProbeInfo->IO_Address == IO_Address && - ProbeInfo->HostAdapterType == BusLogic_MultiMaster) - { - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->PCI_Address = 0; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = PCI_Device; - break; - } + struct BusLogic_ProbeInfo *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; + int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; + int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; + boolean ForceBusDeviceScanningOrder = false; + boolean ForceBusDeviceScanningOrderChecked = false; + boolean StandardAddressSeen[6]; + struct pci_dev *PCI_Device = NULL; + int i; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) + return 0; + BusLogic_ProbeInfoCount++; + for (i = 0; i < 6; i++) + StandardAddressSeen[i] = false; + /* + Iterate over the MultiMaster PCI Host Adapters. For each enumerated host + adapter, determine whether its ISA Compatible I/O Port is enabled and if + so, whether it is assigned the Primary I/O Address. A host adapter that is + assigned the Primary I/O Address will always be the preferred boot device. + The MultiMaster BIOS will first recognize a host adapter at the Primary I/O + Address, then any other PCI host adapters, and finally any host adapters + located at the remaining standard ISA I/O Addresses. When a PCI host + adapter is found with its ISA Compatible I/O Port enabled, a command is + issued to disable the ISA Compatible I/O Port, and it is noted that the + particular standard ISA I/O Address need not be probed. + */ + PrimaryProbeInfo->IO_Address = 0; + while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) { + struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; + struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; + enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest; + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + unsigned long BaseAddress0; + unsigned long BaseAddress1; + unsigned long IO_Address; + unsigned long PCI_Address; + + if (pci_enable_device(PCI_Device)) + continue; + + if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff)) + continue; + + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); + PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); + + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { + BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "MultiMaster Host Adapter\n", NULL, BaseAddress0); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) { + BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "MultiMaster Host Adapter\n", NULL, BaseAddress1); + BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address); + continue; + } + if (IRQ_Channel == 0) { + BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "MultiMaster Host Adapter\n", NULL, IRQ_Channel); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (BusLogic_GlobalOptions.TraceProbe) { + BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL); + BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address); + } + /* + Issue the Inquire PCI Host Adapter Information command to determine + the ISA Compatible I/O Port. If the ISA Compatible I/O Port is + known and enabled, note that the particular Standard ISA I/O + Address should not be probed. + */ + HostAdapter->IO_Address = IO_Address; + BusLogic_InterruptReset(HostAdapter); + if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation)) + == sizeof(PCIHostAdapterInformation)) { + if (PCIHostAdapterInformation.ISACompatibleIOPort < 6) + StandardAddressSeen[PCIHostAdapterInformation.ISACompatibleIOPort] = true; + } else + PCIHostAdapterInformation.ISACompatibleIOPort = BusLogic_IO_Disable; + /* + * Issue the Modify I/O Address command to disable the ISA Compatible + * I/O Port. On PCI Host Adapters, the Modify I/O Address command + * allows modification of the ISA compatible I/O Address that the Host + * Adapter responds to; it does not affect the PCI compliant I/O Address + * assigned at system initialization. + */ + ModifyIOAddressRequest = BusLogic_IO_Disable; + BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress, &ModifyIOAddressRequest, sizeof(ModifyIOAddressRequest), NULL, 0); + /* + For the first MultiMaster Host Adapter enumerated, issue the Fetch + Host Adapter Local RAM command to read byte 45 of the AutoSCSI area, + for the setting of the "Use Bus And Device # For PCI Scanning Seq." + option. Issue the Inquire Board ID command since this option is + only valid for the BT-948/958/958D. + */ + if (!ForceBusDeviceScanningOrderChecked) { + struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; + struct BusLogic_AutoSCSIByte45 AutoSCSIByte45; + struct BusLogic_BoardID BoardID; + FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset + 45; + FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte45); + BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIByte45, sizeof(AutoSCSIByte45)); + BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID)); + if (BoardID.FirmwareVersion1stDigit == '5') + ForceBusDeviceScanningOrder = AutoSCSIByte45.ForceBusDeviceScanningOrder; + ForceBusDeviceScanningOrderChecked = true; + } + /* + Determine whether this MultiMaster Host Adapter has its ISA + Compatible I/O Port enabled and is assigned the Primary I/O Address. + If it does, then it is the Primary MultiMaster Host Adapter and must + be recognized first. If it does not, then it is added to the list + for probing after any Primary MultiMaster Host Adapter is probed. + */ + if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) { + PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; + PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + PrimaryProbeInfo->IO_Address = IO_Address; + PrimaryProbeInfo->PCI_Address = PCI_Address; + PrimaryProbeInfo->Bus = Bus; + PrimaryProbeInfo->Device = Device; + PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; + PrimaryProbeInfo->PCI_Device = PCI_Device; + PCIMultiMasterCount++; + } else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_MultiMaster; + ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; + ProbeInfo->Bus = Bus; + ProbeInfo->Device = Device; + ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; + NonPrimaryPCIMultiMasterCount++; + PCIMultiMasterCount++; + } else + BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL); } - } - return PCIMultiMasterCount; + /* + If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON + for the first enumerated MultiMaster Host Adapter, and if that host adapter + is a BT-948/958/958D, then the MultiMaster BIOS will recognize MultiMaster + Host Adapters in the order of increasing PCI Bus and Device Number. In + that case, sort the probe information into the same order the BIOS uses. + If this option is OFF, then the MultiMaster BIOS will recognize MultiMaster + Host Adapters in the order they are enumerated by the PCI BIOS, and hence + no sorting is necessary. + */ + if (ForceBusDeviceScanningOrder) + BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[NonPrimaryPCIMultiMasterIndex], NonPrimaryPCIMultiMasterCount); + /* + If no PCI MultiMaster Host Adapter is assigned the Primary I/O Address, + then the Primary I/O Address must be probed explicitly before any PCI + host adapters are probed. + */ + if (!BusLogic_ProbeOptions.NoProbeISA) + if (PrimaryProbeInfo->IO_Address == 0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) { + PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; + PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + PrimaryProbeInfo->IO_Address = 0x330; + } + /* + Append the list of standard BusLogic MultiMaster ISA I/O Addresses, + omitting the Primary I/O Address which has already been handled. + */ + if (!BusLogic_ProbeOptions.NoProbeISA) { + if (!StandardAddressSeen[1] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x334); + if (!StandardAddressSeen[2] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x230); + if (!StandardAddressSeen[3] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x234); + if (!StandardAddressSeen[4] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x130); + if (!StandardAddressSeen[5] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x134); + } + /* + Iterate over the older non-compliant MultiMaster PCI Host Adapters, + noting the PCI bus location and assigned IRQ Channel. + */ + PCI_Device = NULL; + while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) { + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + unsigned long IO_Address; + + if (pci_enable_device(PCI_Device)) + continue; + + if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff)) + continue; + + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = pci_resource_start(PCI_Device, 0); + + if (IO_Address == 0 || IRQ_Channel == 0) + continue; + for (i = 0; i < BusLogic_ProbeInfoCount; i++) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[i]; + if (ProbeInfo->IO_Address == IO_Address && ProbeInfo->HostAdapterType == BusLogic_MultiMaster) { + ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->PCI_Address = 0; + ProbeInfo->Bus = Bus; + ProbeInfo->Device = Device; + ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; + break; + } + } + } + return PCIMultiMasterCount; } @@ -1061,100 +905,77 @@ static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0; - struct pci_dev *PCI_Device = NULL; - /* - Interrogate PCI Configuration Space for any FlashPoint Host Adapters. - */ - while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, - PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, - PCI_Device)) != NULL) - { - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long BaseAddress0; - unsigned long BaseAddress1; - unsigned long IO_Address; - unsigned long PCI_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); - PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); + int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0; + struct pci_dev *PCI_Device = NULL; + /* + Interrogate PCI Configuration Space for any FlashPoint Host Adapters. + */ + while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) { + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + unsigned long BaseAddress0; + unsigned long BaseAddress1; + unsigned long IO_Address; + unsigned long PCI_Address; + + if (pci_enable_device(PCI_Device)) + continue; + + if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff)) + continue; + + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); + PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); #ifndef CONFIG_SCSI_OMIT_FLASHPOINT - if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) - { - BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " - "FlashPoint Host Adapter\n", NULL, BaseAddress0); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) - { - BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " - "FlashPoint Host Adapter\n", NULL, BaseAddress1); - BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", - NULL, Bus, Device, PCI_Address); - continue; - } - if (IRQ_Channel == 0) - { - BusLogic_Error("BusLogic: IRQ Channel %d invalid for " - "FlashPoint Host Adapter\n", NULL, IRQ_Channel); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (BusLogic_GlobalOptions.TraceProbe) - { - BusLogic_Notice("BusLogic: FlashPoint Host Adapter " - "detected at\n", NULL); - BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " - "0x%X PCI Address 0x%X\n", NULL, - Bus, Device, IO_Address, PCI_Address); - } - if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) - { - struct BusLogic_ProbeInfo *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_FlashPoint; - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = PCI_Device; - FlashPointCount++; - } - else BusLogic_Warning("BusLogic: Too many Host Adapters " - "detected\n", NULL); + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { + BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, BaseAddress0); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) { + BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "FlashPoint Host Adapter\n", NULL, BaseAddress1); + BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address); + continue; + } + if (IRQ_Channel == 0) { + BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "FlashPoint Host Adapter\n", NULL, IRQ_Channel); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (BusLogic_GlobalOptions.TraceProbe) { + BusLogic_Notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL); + BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address); + } + if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_FlashPoint; + ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; + ProbeInfo->Bus = Bus; + ProbeInfo->Device = Device; + ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; + FlashPointCount++; + } else + BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL); #else - BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " - "PCI Bus %d Device %d\n", NULL, Bus, Device); - BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " - "but FlashPoint\n", NULL, IO_Address, PCI_Address, IRQ_Channel); - BusLogic_Error("BusLogic: support was omitted in this kernel " - "configuration.\n", NULL); + BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", NULL, Bus, Device); + BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " "but FlashPoint\n", NULL, IO_Address, PCI_Address, IRQ_Channel); + BusLogic_Error("BusLogic: support was omitted in this kernel " "configuration.\n", NULL); #endif - } - /* - The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of - increasing PCI Bus and Device Number, so sort the probe information into - the same order the BIOS uses. - */ - BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[FlashPointIndex], - FlashPointCount); - return FlashPointCount; + } + /* + The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of + increasing PCI Bus and Device Number, so sort the probe information into + the same order the BIOS uses. + */ + BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[FlashPointIndex], FlashPointCount); + return FlashPointCount; } @@ -1174,106 +995,70 @@ static void __init BusLogic_InitializeProbeInfoList(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - /* - If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint - Host Adapters; otherwise, default to the standard ISA MultiMaster probe. - */ - if (!BusLogic_ProbeOptions.NoProbePCI) - { - if (BusLogic_ProbeOptions.MultiMasterFirst) - { - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - } - else if (BusLogic_ProbeOptions.FlashPointFirst) - { - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - } - else - { - int FlashPointCount = - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - int PCIMultiMasterCount = - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - if (FlashPointCount > 0 && PCIMultiMasterCount > 0) - { - struct BusLogic_ProbeInfo *ProbeInfo = - &BusLogic_ProbeInfoList[FlashPointCount]; - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct BusLogic_FetchHostAdapterLocalRAMRequest - FetchHostAdapterLocalRAMRequest; - struct BusLogic_BIOSDriveMapByte Drive0MapByte; - while (ProbeInfo->HostAdapterBusType != BusLogic_PCI_Bus) - ProbeInfo++; - HostAdapter->IO_Address = ProbeInfo->IO_Address; - FetchHostAdapterLocalRAMRequest.ByteOffset = - BusLogic_BIOS_BaseOffset + BusLogic_BIOS_DriveMapOffset + 0; - FetchHostAdapterLocalRAMRequest.ByteCount = - sizeof(Drive0MapByte); - BusLogic_Command(HostAdapter, - BusLogic_FetchHostAdapterLocalRAM, - &FetchHostAdapterLocalRAMRequest, - sizeof(FetchHostAdapterLocalRAMRequest), - &Drive0MapByte, sizeof(Drive0MapByte)); - /* - If the Map Byte for BIOS Drive 0 indicates that BIOS Drive 0 - is controlled by this PCI MultiMaster Host Adapter, then - reverse the probe order so that MultiMaster Host Adapters are - probed before FlashPoint Host Adapters. - */ - if (Drive0MapByte.DiskGeometry != - BusLogic_BIOS_Disk_Not_Installed) - { - struct BusLogic_ProbeInfo - SavedProbeInfo[BusLogic_MaxHostAdapters]; - int MultiMasterCount = - BusLogic_ProbeInfoCount - FlashPointCount; - memcpy(SavedProbeInfo, - BusLogic_ProbeInfoList, - BusLogic_ProbeInfoCount - * sizeof(struct BusLogic_ProbeInfo)); - memcpy(&BusLogic_ProbeInfoList[0], - &SavedProbeInfo[FlashPointCount], - MultiMasterCount * sizeof(struct BusLogic_ProbeInfo)); - memcpy(&BusLogic_ProbeInfoList[MultiMasterCount], - &SavedProbeInfo[0], - FlashPointCount * sizeof(struct BusLogic_ProbeInfo)); + /* + If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint + Host Adapters; otherwise, default to the standard ISA MultiMaster probe. + */ + if (!BusLogic_ProbeOptions.NoProbePCI) { + if (BusLogic_ProbeOptions.MultiMasterFirst) { + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + } else if (BusLogic_ProbeOptions.FlashPointFirst) { + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + } else { + int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + if (FlashPointCount > 0 && PCIMultiMasterCount > 0) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[FlashPointCount]; + struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; + struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; + struct BusLogic_BIOSDriveMapByte Drive0MapByte; + while (ProbeInfo->HostAdapterBusType != BusLogic_PCI_Bus) + ProbeInfo++; + HostAdapter->IO_Address = ProbeInfo->IO_Address; + FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_BIOS_BaseOffset + BusLogic_BIOS_DriveMapOffset + 0; + FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(Drive0MapByte); + BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &Drive0MapByte, sizeof(Drive0MapByte)); + /* + If the Map Byte for BIOS Drive 0 indicates that BIOS Drive 0 + is controlled by this PCI MultiMaster Host Adapter, then + reverse the probe order so that MultiMaster Host Adapters are + probed before FlashPoint Host Adapters. + */ + if (Drive0MapByte.DiskGeometry != BusLogic_BIOS_Disk_Not_Installed) { + struct BusLogic_ProbeInfo SavedProbeInfo[BusLogic_MaxHostAdapters]; + int MultiMasterCount = BusLogic_ProbeInfoCount - FlashPointCount; + memcpy(SavedProbeInfo, BusLogic_ProbeInfoList, BusLogic_ProbeInfoCount * sizeof(struct BusLogic_ProbeInfo)); + memcpy(&BusLogic_ProbeInfoList[0], &SavedProbeInfo[FlashPointCount], MultiMasterCount * sizeof(struct BusLogic_ProbeInfo)); + memcpy(&BusLogic_ProbeInfoList[MultiMasterCount], &SavedProbeInfo[0], FlashPointCount * sizeof(struct BusLogic_ProbeInfo)); + } + } } - } - } - } - else BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter); + } else + BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter); } -#endif /* CONFIG_PCI */ +#endif /* CONFIG_PCI */ /* BusLogic_Failure prints a standardized error message, and then returns false. */ -static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, - char *ErrorMessage) +static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage) { - BusLogic_AnnounceDriver(HostAdapter); - if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) - { - BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n", - HostAdapter); - BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", - HostAdapter, HostAdapter->Bus, HostAdapter->Device, - HostAdapter->IO_Address, HostAdapter->PCI_Address); - } - else BusLogic_Error("While configuring BusLogic Host Adapter at " - "I/O Address 0x%X:\n", HostAdapter, - HostAdapter->IO_Address); - BusLogic_Error("%s FAILED - DETACHING\n", HostAdapter, ErrorMessage); - if (BusLogic_CommandFailureReason != NULL) - BusLogic_Error("ADDITIONAL FAILURE INFO - %s\n", HostAdapter, - BusLogic_CommandFailureReason); - return false; + BusLogic_AnnounceDriver(HostAdapter); + if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) { + BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n", HostAdapter); + BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device, HostAdapter->IO_Address, HostAdapter->PCI_Address); + } else + BusLogic_Error("While configuring BusLogic Host Adapter at " "I/O Address 0x%X:\n", HostAdapter, HostAdapter->IO_Address); + BusLogic_Error("%s FAILED - DETACHING\n", HostAdapter, ErrorMessage); + if (BusLogic_CommandFailureReason != NULL) + BusLogic_Error("ADDITIONAL FAILURE INFO - %s\n", HostAdapter, BusLogic_CommandFailureReason); + return false; } @@ -1283,81 +1068,64 @@ static boolean __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_StatusRegister StatusRegister; - union BusLogic_InterruptRegister InterruptRegister; - union BusLogic_GeometryRegister GeometryRegister; - /* - FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - FlashPointInfo->BaseAddress = - (u32) HostAdapter->IO_Address; - FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel; - FlashPointInfo->Present = false; - if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && - FlashPointInfo->Present)) - { - BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " - "PCI Bus %d Device %d\n", HostAdapter, - HostAdapter->Bus, HostAdapter->Device); - BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, " - "but FlashPoint\n", HostAdapter, - HostAdapter->IO_Address, HostAdapter->PCI_Address); - BusLogic_Error("BusLogic: Probe Function failed to validate it.\n", - HostAdapter); - return false; - } - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", - HostAdapter, HostAdapter->IO_Address); - /* - Indicate the Host Adapter Probe completed successfully. - */ - return true; - } - /* - Read the Status, Interrupt, and Geometry Registers to test if there are I/O - ports that respond, and to check the values to determine if they are from a - BusLogic Host Adapter. A nonexistent I/O port will return 0xFF, in which - case there is definitely no BusLogic Host Adapter at this base I/O Address. - The test here is a subset of that used by the BusLogic Host Adapter BIOS. - */ - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " - "Geometry 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All, - InterruptRegister.All, GeometryRegister.All); - if (StatusRegister.All == 0 || - StatusRegister.sr.DiagnosticActive || - StatusRegister.sr.CommandParameterRegisterBusy || - StatusRegister.sr.Reserved || - StatusRegister.sr.CommandInvalid || - InterruptRegister.ir.Reserved != 0) - return false; - /* - Check the undocumented Geometry Register to test if there is an I/O port - that responded. Adaptec Host Adapters do not implement the Geometry - Register, so this test helps serve to avoid incorrectly recognizing an - Adaptec 1542A or 1542B as a BusLogic. Unfortunately, the Adaptec 1542C - series does respond to the Geometry Register I/O port, but it will be - rejected later when the Inquire Extended Setup Information command is - issued in BusLogic_CheckHostAdapter. The AMI FastDisk Host Adapter is a - BusLogic clone that implements the same interface as earlier BusLogic - Host Adapters, including the undocumented commands, and is therefore - supported by this driver. However, the AMI FastDisk always returns 0x00 - upon reading the Geometry Register, so the extended translation option - should always be left disabled on the AMI FastDisk. - */ - if (GeometryRegister.All == 0xFF) return false; - /* - Indicate the Host Adapter Probe completed successfully. - */ - return true; + union BusLogic_StatusRegister StatusRegister; + union BusLogic_InterruptRegister InterruptRegister; + union BusLogic_GeometryRegister GeometryRegister; + /* + FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->BaseAddress = (u32) HostAdapter->IO_Address; + FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel; + FlashPointInfo->Present = false; + if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && FlashPointInfo->Present)) { + BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device); + BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, " "but FlashPoint\n", HostAdapter, HostAdapter->IO_Address, HostAdapter->PCI_Address); + BusLogic_Error("BusLogic: Probe Function failed to validate it.\n", HostAdapter); + return false; + } + if (BusLogic_GlobalOptions.TraceProbe) + BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", HostAdapter, HostAdapter->IO_Address); + /* + Indicate the Host Adapter Probe completed successfully. + */ + return true; + } + /* + Read the Status, Interrupt, and Geometry Registers to test if there are I/O + ports that respond, and to check the values to determine if they are from a + BusLogic Host Adapter. A nonexistent I/O port will return 0xFF, in which + case there is definitely no BusLogic Host Adapter at this base I/O Address. + The test here is a subset of that used by the BusLogic Host Adapter BIOS. + */ + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); + if (BusLogic_GlobalOptions.TraceProbe) + BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All, InterruptRegister.All, GeometryRegister.All); + if (StatusRegister.All == 0 || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.CommandParameterRegisterBusy || StatusRegister.sr.Reserved || StatusRegister.sr.CommandInvalid || InterruptRegister.ir.Reserved != 0) + return false; + /* + Check the undocumented Geometry Register to test if there is an I/O port + that responded. Adaptec Host Adapters do not implement the Geometry + Register, so this test helps serve to avoid incorrectly recognizing an + Adaptec 1542A or 1542B as a BusLogic. Unfortunately, the Adaptec 1542C + series does respond to the Geometry Register I/O port, but it will be + rejected later when the Inquire Extended Setup Information command is + issued in BusLogic_CheckHostAdapter. The AMI FastDisk Host Adapter is a + BusLogic clone that implements the same interface as earlier BusLogic + Host Adapters, including the undocumented commands, and is therefore + supported by this driver. However, the AMI FastDisk always returns 0x00 + upon reading the Geometry Register, so the extended translation option + should always be left disabled on the AMI FastDisk. + */ + if (GeometryRegister.All == 0xFF) + return false; + /* + Indicate the Host Adapter Probe completed successfully. + */ + return true; } @@ -1370,113 +1138,101 @@ */ static boolean BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter - *HostAdapter, - boolean HardReset) + *HostAdapter, boolean HardReset) { - union BusLogic_StatusRegister StatusRegister; - int TimeoutCounter; - /* - FlashPoint Host Adapters are Hard Reset by the FlashPoint SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - FlashPointInfo->HostSoftReset = !HardReset; - FlashPointInfo->ReportDataUnderrun = true; - HostAdapter->CardHandle = - FlashPoint_HardwareResetHostAdapter(FlashPointInfo); - if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) return false; - /* - Indicate the Host Adapter Hard Reset completed successfully. - */ - return true; - } - /* - Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host - Adapter should respond by setting Diagnostic Active in the Status Register. - */ - if (HardReset) - BusLogic_HardReset(HostAdapter); - else BusLogic_SoftReset(HostAdapter); - /* - Wait until Diagnostic Active is set in the Status Register. - */ - TimeoutCounter = 5*10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.DiagnosticActive) break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " - "Status 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) return false; - /* - Wait 100 microseconds to allow completion of any initial diagnostic - activity which might leave the contents of the Status Register - unpredictable. - */ - udelay(100); - /* - Wait until Diagnostic Active is reset in the Status Register. - */ - TimeoutCounter = 10*10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (!StatusRegister.sr.DiagnosticActive) break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " - "Status 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) return false; - /* - Wait until at least one of the Diagnostic Failure, Host Adapter Ready, - or Data In Register Ready bits is set in the Status Register. - */ - TimeoutCounter = 10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.DiagnosticFailure || - StatusRegister.sr.HostAdapterReady || - StatusRegister.sr.DataInRegisterReady) - break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " - "Status 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) return false; - /* - If Diagnostic Failure is set or Host Adapter Ready is reset, then an - error occurred during the Host Adapter diagnostics. If Data In Register - Ready is set, then there is an Error Code available. - */ - if (StatusRegister.sr.DiagnosticFailure || - !StatusRegister.sr.HostAdapterReady) - { - BusLogic_CommandFailureReason = NULL; - BusLogic_Failure(HostAdapter, "HARD RESET DIAGNOSTICS"); - BusLogic_Error("HOST ADAPTER STATUS REGISTER = %02X\n", - HostAdapter, StatusRegister.All); - if (StatusRegister.sr.DataInRegisterReady) - { - unsigned char ErrorCode = BusLogic_ReadDataInRegister(HostAdapter); - BusLogic_Error("HOST ADAPTER ERROR CODE = %d\n", - HostAdapter, ErrorCode); - } - return false; - } - /* - Indicate the Host Adapter Hard Reset completed successfully. - */ - return true; + union BusLogic_StatusRegister StatusRegister; + int TimeoutCounter; + /* + FlashPoint Host Adapters are Hard Reset by the FlashPoint SCCB Manager. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->HostSoftReset = !HardReset; + FlashPointInfo->ReportDataUnderrun = true; + HostAdapter->CardHandle = FlashPoint_HardwareResetHostAdapter(FlashPointInfo); + if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) + return false; + /* + Indicate the Host Adapter Hard Reset completed successfully. + */ + return true; + } + /* + Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host + Adapter should respond by setting Diagnostic Active in the Status Register. + */ + if (HardReset) + BusLogic_HardReset(HostAdapter); + else + BusLogic_SoftReset(HostAdapter); + /* + Wait until Diagnostic Active is set in the Status Register. + */ + TimeoutCounter = 5 * 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.DiagnosticActive) + break; + udelay(100); + } + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); + if (TimeoutCounter < 0) + return false; + /* + Wait 100 microseconds to allow completion of any initial diagnostic + activity which might leave the contents of the Status Register + unpredictable. + */ + udelay(100); + /* + Wait until Diagnostic Active is reset in the Status Register. + */ + TimeoutCounter = 10 * 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (!StatusRegister.sr.DiagnosticActive) + break; + udelay(100); + } + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); + if (TimeoutCounter < 0) + return false; + /* + Wait until at least one of the Diagnostic Failure, Host Adapter Ready, + or Data In Register Ready bits is set in the Status Register. + */ + TimeoutCounter = 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.DiagnosticFailure || StatusRegister.sr.HostAdapterReady || StatusRegister.sr.DataInRegisterReady) + break; + udelay(100); + } + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); + if (TimeoutCounter < 0) + return false; + /* + If Diagnostic Failure is set or Host Adapter Ready is reset, then an + error occurred during the Host Adapter diagnostics. If Data In Register + Ready is set, then there is an Error Code available. + */ + if (StatusRegister.sr.DiagnosticFailure || !StatusRegister.sr.HostAdapterReady) { + BusLogic_CommandFailureReason = NULL; + BusLogic_Failure(HostAdapter, "HARD RESET DIAGNOSTICS"); + BusLogic_Error("HOST ADAPTER STATUS REGISTER = %02X\n", HostAdapter, StatusRegister.All); + if (StatusRegister.sr.DataInRegisterReady) { + unsigned char ErrorCode = BusLogic_ReadDataInRegister(HostAdapter); + BusLogic_Error("HOST ADAPTER ERROR CODE = %d\n", HostAdapter, ErrorCode); + } + return false; + } + /* + Indicate the Host Adapter Hard Reset completed successfully. + */ + return true; } @@ -1487,35 +1243,30 @@ static boolean __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; - unsigned char RequestedReplyLength; - boolean Result = true; - /* - FlashPoint Host Adapters do not require this protection. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Issue the Inquire Extended Setup Information command. Only genuine - BusLogic Host Adapters and true clones support this command. Adaptec 1542C - series Host Adapters that respond to the Geometry Register I/O port will - fail this command. - */ - RequestedReplyLength = sizeof(ExtendedSetupInformation); - if (BusLogic_Command(HostAdapter, - BusLogic_InquireExtendedSetupInformation, - &RequestedReplyLength, - sizeof(RequestedReplyLength), - &ExtendedSetupInformation, - sizeof(ExtendedSetupInformation)) - != sizeof(ExtendedSetupInformation)) - Result = false; - /* - Provide tracing information if requested and return. - */ - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, - HostAdapter->IO_Address, (Result ? "Found" : "Not Found")); - return Result; + struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; + unsigned char RequestedReplyLength; + boolean Result = true; + /* + FlashPoint Host Adapters do not require this protection. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + return true; + /* + Issue the Inquire Extended Setup Information command. Only genuine + BusLogic Host Adapters and true clones support this command. Adaptec 1542C + series Host Adapters that respond to the Geometry Register I/O port will + fail this command. + */ + RequestedReplyLength = sizeof(ExtendedSetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation)) + != sizeof(ExtendedSetupInformation)) + Result = false; + /* + Provide tracing information if requested and return. + */ + if (BusLogic_GlobalOptions.TraceProbe) + BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, HostAdapter->IO_Address, (Result ? "Found" : "Not Found")); + return Result; } @@ -1527,513 +1278,442 @@ static boolean __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_BoardID BoardID; - struct BusLogic_Configuration Configuration; - struct BusLogic_SetupInformation SetupInformation; - struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; - unsigned char HostAdapterModelNumber[5]; - unsigned char FirmwareVersion3rdDigit; - unsigned char FirmwareVersionLetter; - struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; - struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; - struct BusLogic_AutoSCSIData AutoSCSIData; - union BusLogic_GeometryRegister GeometryRegister; - unsigned char RequestedReplyLength; - unsigned char *TargetPointer, Character; - int TargetID, i; - /* - Configuration Information for FlashPoint Host Adapters is provided in the - FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function. - Initialize fields in the Host Adapter structure from the FlashPoint_Info - structure. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(FlashPointInfo->ModelNumber); i++) - *TargetPointer++ = FlashPointInfo->ModelNumber[i]; - *TargetPointer++ = '\0'; - strcpy(HostAdapter->FirmwareVersion, FlashPoint_FirmwareVersion); - HostAdapter->SCSI_ID = FlashPointInfo->SCSI_ID; - HostAdapter->ExtendedTranslationEnabled = - FlashPointInfo->ExtendedTranslationEnabled; - HostAdapter->ParityCheckingEnabled = - FlashPointInfo->ParityCheckingEnabled; - HostAdapter->BusResetEnabled = !FlashPointInfo->HostSoftReset; - HostAdapter->LevelSensitiveInterrupt = true; - HostAdapter->HostWideSCSI = FlashPointInfo->HostWideSCSI; - HostAdapter->HostDifferentialSCSI = false; - HostAdapter->HostSupportsSCAM = true; - HostAdapter->HostUltraSCSI = true; - HostAdapter->ExtendedLUNSupport = true; - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = FlashPointInfo->LowByteTerminated; - HostAdapter->HighByteTerminated = FlashPointInfo->HighByteTerminated; - HostAdapter->SCAM_Enabled = FlashPointInfo->SCAM_Enabled; - HostAdapter->SCAM_Level2 = FlashPointInfo->SCAM_Level2; - HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; - HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); - HostAdapter->MaxLogicalUnits = 32; - HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; - HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; - HostAdapter->DriverQueueDepth = 255; - HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth; - HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted; - HostAdapter->FastPermitted = FlashPointInfo->FastPermitted; - HostAdapter->UltraPermitted = FlashPointInfo->UltraPermitted; - HostAdapter->WidePermitted = FlashPointInfo->WidePermitted; - HostAdapter->DisconnectPermitted = FlashPointInfo->DisconnectPermitted; - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - goto Common; - } - /* - Issue the Inquire Board ID command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, - &BoardID, sizeof(BoardID)) != sizeof(BoardID)) - return BusLogic_Failure(HostAdapter, "INQUIRE BOARD ID"); - /* - Issue the Inquire Configuration command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, NULL, 0, - &Configuration, sizeof(Configuration)) - != sizeof(Configuration)) - return BusLogic_Failure(HostAdapter, "INQUIRE CONFIGURATION"); - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - /* - Issue the Inquire Extended Setup Information command. - */ - RequestedReplyLength = sizeof(ExtendedSetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &ExtendedSetupInformation, - sizeof(ExtendedSetupInformation)) - != sizeof(ExtendedSetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION"); - /* - Issue the Inquire Firmware Version 3rd Digit command. - */ - FirmwareVersion3rdDigit = '\0'; - if (BoardID.FirmwareVersion1stDigit > '0') - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, - NULL, 0, &FirmwareVersion3rdDigit, - sizeof(FirmwareVersion3rdDigit)) - != sizeof(FirmwareVersion3rdDigit)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); - /* - Issue the Inquire Host Adapter Model Number command. - */ - if (ExtendedSetupInformation.BusType == 'A' && - BoardID.FirmwareVersion1stDigit == '2') - /* BusLogic BT-542B ISA 2.xx */ - strcpy(HostAdapterModelNumber, "542B"); - else if (ExtendedSetupInformation.BusType == 'E' && - BoardID.FirmwareVersion1stDigit == '2' && - (BoardID.FirmwareVersion2ndDigit <= '1' || - (BoardID.FirmwareVersion2ndDigit == '2' && - FirmwareVersion3rdDigit == '0'))) - /* BusLogic BT-742A EISA 2.1x or 2.20 */ - strcpy(HostAdapterModelNumber, "742A"); - else if (ExtendedSetupInformation.BusType == 'E' && - BoardID.FirmwareVersion1stDigit == '0') - /* AMI FastDisk EISA Series 441 0.x */ - strcpy(HostAdapterModelNumber, "747A"); - else - { - RequestedReplyLength = sizeof(HostAdapterModelNumber); - if (BusLogic_Command(HostAdapter, BusLogic_InquireHostAdapterModelNumber, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &HostAdapterModelNumber, - sizeof(HostAdapterModelNumber)) - != sizeof(HostAdapterModelNumber)) - return BusLogic_Failure(HostAdapter, - "INQUIRE HOST ADAPTER MODEL NUMBER"); - } - /* - BusLogic MultiMaster Host Adapters can be identified by their model number - and the major version number of their firmware as follows: - - 5.xx BusLogic "W" Series Host Adapters: - BT-948/958/958D - 4.xx BusLogic "C" Series Host Adapters: - BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF - 3.xx BusLogic "S" Series Host Adapters: - BT-747S/747D/757S/757D/445S/545S/542D - BT-542B/742A (revision H) - 2.xx BusLogic "A" Series Host Adapters: - BT-542B/742A (revision G and below) - 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter - */ - /* - Save the Model Name and Host Adapter Name in the Host Adapter structure. - */ - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(HostAdapterModelNumber); i++) - { - Character = HostAdapterModelNumber[i]; - if (Character == ' ' || Character == '\0') break; - *TargetPointer++ = Character; - } - *TargetPointer++ = '\0'; - /* - Save the Firmware Version in the Host Adapter structure. - */ - TargetPointer = HostAdapter->FirmwareVersion; - *TargetPointer++ = BoardID.FirmwareVersion1stDigit; - *TargetPointer++ = '.'; - *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; - if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') - *TargetPointer++ = FirmwareVersion3rdDigit; - *TargetPointer = '\0'; - /* - Issue the Inquire Firmware Version Letter command. - */ - if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0) - { - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, - NULL, 0, &FirmwareVersionLetter, - sizeof(FirmwareVersionLetter)) - != sizeof(FirmwareVersionLetter)) - return BusLogic_Failure(HostAdapter, - "INQUIRE FIRMWARE VERSION LETTER"); - if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') - *TargetPointer++ = FirmwareVersionLetter; - *TargetPointer = '\0'; - } - /* - Save the Host Adapter SCSI ID in the Host Adapter structure. - */ - HostAdapter->SCSI_ID = Configuration.HostAdapterID; - /* - Determine the Bus Type and save it in the Host Adapter structure, determine - and save the IRQ Channel if necessary, and determine and save the DMA - Channel for ISA Host Adapters. - */ - HostAdapter->HostAdapterBusType = - BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4']; - if (HostAdapter->IRQ_Channel == 0) - { - if (Configuration.IRQ_Channel9) - HostAdapter->IRQ_Channel = 9; - else if (Configuration.IRQ_Channel10) - HostAdapter->IRQ_Channel = 10; - else if (Configuration.IRQ_Channel11) - HostAdapter->IRQ_Channel = 11; - else if (Configuration.IRQ_Channel12) - HostAdapter->IRQ_Channel = 12; - else if (Configuration.IRQ_Channel14) - HostAdapter->IRQ_Channel = 14; - else if (Configuration.IRQ_Channel15) - HostAdapter->IRQ_Channel = 15; - } - if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) - { - if (Configuration.DMA_Channel5) - HostAdapter->DMA_Channel = 5; - else if (Configuration.DMA_Channel6) - HostAdapter->DMA_Channel = 6; - else if (Configuration.DMA_Channel7) - HostAdapter->DMA_Channel = 7; - } - /* - Determine whether Extended Translation is enabled and save it in - the Host Adapter structure. - */ - GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - HostAdapter->ExtendedTranslationEnabled = - GeometryRegister.gr.ExtendedTranslationEnabled; - /* - Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide - SCSI flag, Differential SCSI flag, SCAM Supported flag, and - Ultra SCSI flag in the Host Adapter structure. - */ - HostAdapter->HostAdapterScatterGatherLimit = - ExtendedSetupInformation.ScatterGatherLimit; - HostAdapter->DriverScatterGatherLimit = - HostAdapter->HostAdapterScatterGatherLimit; - if (HostAdapter->HostAdapterScatterGatherLimit > BusLogic_ScatterGatherLimit) - HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; - if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupt) - HostAdapter->LevelSensitiveInterrupt = true; - HostAdapter->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI; - HostAdapter->HostDifferentialSCSI = - ExtendedSetupInformation.HostDifferentialSCSI; - HostAdapter->HostSupportsSCAM = ExtendedSetupInformation.HostSupportsSCAM; - HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI; - /* - Determine whether Extended LUN Format CCBs are supported and save the - information in the Host Adapter structure. - */ - if (HostAdapter->FirmwareVersion[0] == '5' || - (HostAdapter->FirmwareVersion[0] == '4' && HostAdapter->HostWideSCSI)) - HostAdapter->ExtendedLUNSupport = true; - /* - Issue the Inquire PCI Host Adapter Information command to read the - Termination Information from "W" series MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] == '5') - { - if (BusLogic_Command(HostAdapter, - BusLogic_InquirePCIHostAdapterInformation, - NULL, 0, &PCIHostAdapterInformation, - sizeof(PCIHostAdapterInformation)) - != sizeof(PCIHostAdapterInformation)) - return BusLogic_Failure(HostAdapter, - "INQUIRE PCI HOST ADAPTER INFORMATION"); - /* - Save the Termination Information in the Host Adapter structure. - */ - if (PCIHostAdapterInformation.GenericInfoValid) - { - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = - PCIHostAdapterInformation.LowByteTerminated; - HostAdapter->HighByteTerminated = - PCIHostAdapterInformation.HighByteTerminated; - } - } - /* - Issue the Fetch Host Adapter Local RAM command to read the AutoSCSI data - from "W" and "C" series MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] >= '4') - { - FetchHostAdapterLocalRAMRequest.ByteOffset = - BusLogic_AutoSCSI_BaseOffset; - FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIData); - if (BusLogic_Command(HostAdapter, - BusLogic_FetchHostAdapterLocalRAM, - &FetchHostAdapterLocalRAMRequest, - sizeof(FetchHostAdapterLocalRAMRequest), - &AutoSCSIData, sizeof(AutoSCSIData)) - != sizeof(AutoSCSIData)) - return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM"); - /* - Save the Parity Checking Enabled, Bus Reset Enabled, and Termination - Information in the Host Adapter structure. - */ - HostAdapter->ParityCheckingEnabled = AutoSCSIData.ParityCheckingEnabled; - HostAdapter->BusResetEnabled = AutoSCSIData.BusResetEnabled; - if (HostAdapter->FirmwareVersion[0] == '4') - { - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = AutoSCSIData.LowByteTerminated; - HostAdapter->HighByteTerminated = AutoSCSIData.HighByteTerminated; - } - /* - Save the Wide Permitted, Fast Permitted, Synchronous Permitted, - Disconnect Permitted, Ultra Permitted, and SCAM Information in the - Host Adapter structure. - */ - HostAdapter->WidePermitted = AutoSCSIData.WidePermitted; - HostAdapter->FastPermitted = AutoSCSIData.FastPermitted; - HostAdapter->SynchronousPermitted = - AutoSCSIData.SynchronousPermitted; - HostAdapter->DisconnectPermitted = - AutoSCSIData.DisconnectPermitted; - if (HostAdapter->HostUltraSCSI) - HostAdapter->UltraPermitted = AutoSCSIData.UltraPermitted; - if (HostAdapter->HostSupportsSCAM) - { - HostAdapter->SCAM_Enabled = AutoSCSIData.SCAM_Enabled; - HostAdapter->SCAM_Level2 = AutoSCSIData.SCAM_Level2; - } - } - /* - Initialize fields in the Host Adapter structure for "S" and "A" series - MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] < '4') - { - if (SetupInformation.SynchronousInitiationEnabled) - { - HostAdapter->SynchronousPermitted = 0xFF; - if (HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus) - { - if (ExtendedSetupInformation.Misc.FastOnEISA) - HostAdapter->FastPermitted = 0xFF; - if (strcmp(HostAdapter->ModelName, "BT-757") == 0) - HostAdapter->WidePermitted = 0xFF; - } - } - HostAdapter->DisconnectPermitted = 0xFF; - HostAdapter->ParityCheckingEnabled = - SetupInformation.ParityCheckingEnabled; - HostAdapter->BusResetEnabled = true; - } - /* - Determine the maximum number of Target IDs and Logical Units supported by - this driver for Wide and Narrow Host Adapters. - */ - HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); - HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8); - /* - Select appropriate values for the Mailbox Count, Driver Queue Depth, - Initial CCBs, and Incremental CCBs variables based on whether or not Strict - Round Robin Mode is supported. If Strict Round Robin Mode is supported, - then there is no performance degradation in using the maximum possible - number of Outgoing and Incoming Mailboxes and allowing the Tagged and - Untagged Queue Depths to determine the actual utilization. If Strict Round - Robin Mode is not supported, then the Host Adapter must scan all the - Outgoing Mailboxes whenever an Outgoing Mailbox entry is made, which can - cause a substantial performance penalty. The host adapters actually have - room to store the following number of CCBs internally; that is, they can - internally queue and manage this many active commands on the SCSI bus - simultaneously. Performance measurements demonstrate that the Driver Queue - Depth should be set to the Mailbox Count, rather than the Host Adapter - Queue Depth (internal CCB capacity), as it is more efficient to have the - queued commands waiting in Outgoing Mailboxes if necessary than to block - the process in the higher levels of the SCSI Subsystem. - - 192 BT-948/958/958D - 100 BT-946C/956C/956CD/747C/757C/757CD/445C - 50 BT-545C/540CF - 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A - */ - if (HostAdapter->FirmwareVersion[0] == '5') - HostAdapter->HostAdapterQueueDepth = 192; - else if (HostAdapter->FirmwareVersion[0] == '4') - HostAdapter->HostAdapterQueueDepth = - (HostAdapter->HostAdapterBusType != BusLogic_ISA_Bus ? 100 : 50); - else HostAdapter->HostAdapterQueueDepth = 30; - if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) - { - HostAdapter->StrictRoundRobinModeSupport = true; - HostAdapter->MailboxCount = BusLogic_MaxMailboxes; - } - else - { - HostAdapter->StrictRoundRobinModeSupport = false; - HostAdapter->MailboxCount = 32; - } - HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount; - HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; - HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; - /* - Tagged Queuing support is available and operates properly on all "W" series - MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with - firmware version 4.22 and above, and on "S" series MultiMaster Host - Adapters with firmware version 3.35 and above. - */ - HostAdapter->TaggedQueuingPermitted = 0; - switch (HostAdapter->FirmwareVersion[0]) - { - case '5': - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - case '4': - if (strcmp(HostAdapter->FirmwareVersion, "4.22") >= 0) - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - case '3': - if (strcmp(HostAdapter->FirmwareVersion, "3.35") >= 0) - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - } - /* - Determine the Host Adapter BIOS Address if the BIOS is enabled and - save it in the Host Adapter structure. The BIOS is disabled if the - BIOS_Address is 0. - */ - HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12; - /* - ISA Host Adapters require Bounce Buffers if there is more than 16MB memory. - */ - if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus && - (void *) high_memory > (void *) MAX_DMA_ADDRESS) - HostAdapter->BounceBuffersRequired = true; - /* - BusLogic BT-445S Host Adapters prior to board revision E have a hardware - bug whereby when the BIOS is enabled, transfers to/from the same address - range the BIOS occupies modulo 16MB are handled incorrectly. Only properly - functioning BT-445S Host Adapters have firmware version 3.37, so require - that ISA Bounce Buffers be used for the buggy BT-445S models if there is - more than 16MB memory. - */ - if (HostAdapter->BIOS_Address > 0 && - strcmp(HostAdapter->ModelName, "BT-445S") == 0 && - strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 && - (void *) high_memory > (void *) MAX_DMA_ADDRESS) - HostAdapter->BounceBuffersRequired = true; - /* - Initialize parameters common to MultiMaster and FlashPoint Host Adapters. - */ -Common: - /* - Initialize the Host Adapter Full Model Name from the Model Name. - */ - strcpy(HostAdapter->FullModelName, "BusLogic "); - strcat(HostAdapter->FullModelName, HostAdapter->ModelName); - /* - Select an appropriate value for the Tagged Queue Depth either from a - BusLogic Driver Options specification, or based on whether this Host - Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth - is left at 0 for automatic determination in BusLogic_SelectQueueDepths. - Initialize the Untagged Queue Depth. - */ - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - { - unsigned char QueueDepth = 0; - if (HostAdapter->DriverOptions != NULL && - HostAdapter->DriverOptions->QueueDepth[TargetID] > 0) - QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID]; - else if (HostAdapter->BounceBuffersRequired) - QueueDepth = BusLogic_TaggedQueueDepthBB; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - } - if (HostAdapter->BounceBuffersRequired) - HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB; - else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; - if (HostAdapter->DriverOptions != NULL) - HostAdapter->CommonQueueDepth = - HostAdapter->DriverOptions->CommonQueueDepth; - if (HostAdapter->CommonQueueDepth > 0 && - HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth) - HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth; - /* - Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. - Therefore, mask the Tagged Queuing Permitted Default bits with the - Disconnect/Reconnect Permitted bits. - */ - HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted; - /* - Combine the default Tagged Queuing Permitted bits with any BusLogic Driver - Options Tagged Queuing specification. - */ - if (HostAdapter->DriverOptions != NULL) - HostAdapter->TaggedQueuingPermitted = - (HostAdapter->DriverOptions->TaggedQueuingPermitted & - HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | - (HostAdapter->TaggedQueuingPermitted & - ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask); - - /* - Select an appropriate value for Bus Settle Time either from a BusLogic - Driver Options specification, or from BusLogic_DefaultBusSettleTime. - */ - if (HostAdapter->DriverOptions != NULL && - HostAdapter->DriverOptions->BusSettleTime > 0) - HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime; - else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; - /* - Indicate reading the Host Adapter Configuration completed successfully. - */ - return true; + struct BusLogic_BoardID BoardID; + struct BusLogic_Configuration Configuration; + struct BusLogic_SetupInformation SetupInformation; + struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; + unsigned char HostAdapterModelNumber[5]; + unsigned char FirmwareVersion3rdDigit; + unsigned char FirmwareVersionLetter; + struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; + struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; + struct BusLogic_AutoSCSIData AutoSCSIData; + union BusLogic_GeometryRegister GeometryRegister; + unsigned char RequestedReplyLength; + unsigned char *TargetPointer, Character; + int TargetID, i; + /* + Configuration Information for FlashPoint Host Adapters is provided in the + FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function. + Initialize fields in the Host Adapter structure from the FlashPoint_Info + structure. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; + TargetPointer = HostAdapter->ModelName; + *TargetPointer++ = 'B'; + *TargetPointer++ = 'T'; + *TargetPointer++ = '-'; + for (i = 0; i < sizeof(FlashPointInfo->ModelNumber); i++) + *TargetPointer++ = FlashPointInfo->ModelNumber[i]; + *TargetPointer++ = '\0'; + strcpy(HostAdapter->FirmwareVersion, FlashPoint_FirmwareVersion); + HostAdapter->SCSI_ID = FlashPointInfo->SCSI_ID; + HostAdapter->ExtendedTranslationEnabled = FlashPointInfo->ExtendedTranslationEnabled; + HostAdapter->ParityCheckingEnabled = FlashPointInfo->ParityCheckingEnabled; + HostAdapter->BusResetEnabled = !FlashPointInfo->HostSoftReset; + HostAdapter->LevelSensitiveInterrupt = true; + HostAdapter->HostWideSCSI = FlashPointInfo->HostWideSCSI; + HostAdapter->HostDifferentialSCSI = false; + HostAdapter->HostSupportsSCAM = true; + HostAdapter->HostUltraSCSI = true; + HostAdapter->ExtendedLUNSupport = true; + HostAdapter->TerminationInfoValid = true; + HostAdapter->LowByteTerminated = FlashPointInfo->LowByteTerminated; + HostAdapter->HighByteTerminated = FlashPointInfo->HighByteTerminated; + HostAdapter->SCAM_Enabled = FlashPointInfo->SCAM_Enabled; + HostAdapter->SCAM_Level2 = FlashPointInfo->SCAM_Level2; + HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; + HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); + HostAdapter->MaxLogicalUnits = 32; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; + HostAdapter->DriverQueueDepth = 255; + HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth; + HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted; + HostAdapter->FastPermitted = FlashPointInfo->FastPermitted; + HostAdapter->UltraPermitted = FlashPointInfo->UltraPermitted; + HostAdapter->WidePermitted = FlashPointInfo->WidePermitted; + HostAdapter->DisconnectPermitted = FlashPointInfo->DisconnectPermitted; + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + goto Common; + } + /* + Issue the Inquire Board ID command. + */ + if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID)) != sizeof(BoardID)) + return BusLogic_Failure(HostAdapter, "INQUIRE BOARD ID"); + /* + Issue the Inquire Configuration command. + */ + if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, NULL, 0, &Configuration, sizeof(Configuration)) + != sizeof(Configuration)) + return BusLogic_Failure(HostAdapter, "INQUIRE CONFIGURATION"); + /* + Issue the Inquire Setup Information command. + */ + RequestedReplyLength = sizeof(SetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation)) + != sizeof(SetupInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); + /* + Issue the Inquire Extended Setup Information command. + */ + RequestedReplyLength = sizeof(ExtendedSetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation)) + != sizeof(ExtendedSetupInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION"); + /* + Issue the Inquire Firmware Version 3rd Digit command. + */ + FirmwareVersion3rdDigit = '\0'; + if (BoardID.FirmwareVersion1stDigit > '0') + if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, NULL, 0, &FirmwareVersion3rdDigit, sizeof(FirmwareVersion3rdDigit)) + != sizeof(FirmwareVersion3rdDigit)) + return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); + /* + Issue the Inquire Host Adapter Model Number command. + */ + if (ExtendedSetupInformation.BusType == 'A' && BoardID.FirmwareVersion1stDigit == '2') + /* BusLogic BT-542B ISA 2.xx */ + strcpy(HostAdapterModelNumber, "542B"); + else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '2' && (BoardID.FirmwareVersion2ndDigit <= '1' || (BoardID.FirmwareVersion2ndDigit == '2' && FirmwareVersion3rdDigit == '0'))) + /* BusLogic BT-742A EISA 2.1x or 2.20 */ + strcpy(HostAdapterModelNumber, "742A"); + else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '0') + /* AMI FastDisk EISA Series 441 0.x */ + strcpy(HostAdapterModelNumber, "747A"); + else { + RequestedReplyLength = sizeof(HostAdapterModelNumber); + if (BusLogic_Command(HostAdapter, BusLogic_InquireHostAdapterModelNumber, &RequestedReplyLength, sizeof(RequestedReplyLength), &HostAdapterModelNumber, sizeof(HostAdapterModelNumber)) + != sizeof(HostAdapterModelNumber)) + return BusLogic_Failure(HostAdapter, "INQUIRE HOST ADAPTER MODEL NUMBER"); + } + /* + BusLogic MultiMaster Host Adapters can be identified by their model number + and the major version number of their firmware as follows: + + 5.xx BusLogic "W" Series Host Adapters: + BT-948/958/958D + 4.xx BusLogic "C" Series Host Adapters: + BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF + 3.xx BusLogic "S" Series Host Adapters: + BT-747S/747D/757S/757D/445S/545S/542D + BT-542B/742A (revision H) + 2.xx BusLogic "A" Series Host Adapters: + BT-542B/742A (revision G and below) + 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter + */ + /* + Save the Model Name and Host Adapter Name in the Host Adapter structure. + */ + TargetPointer = HostAdapter->ModelName; + *TargetPointer++ = 'B'; + *TargetPointer++ = 'T'; + *TargetPointer++ = '-'; + for (i = 0; i < sizeof(HostAdapterModelNumber); i++) { + Character = HostAdapterModelNumber[i]; + if (Character == ' ' || Character == '\0') + break; + *TargetPointer++ = Character; + } + *TargetPointer++ = '\0'; + /* + Save the Firmware Version in the Host Adapter structure. + */ + TargetPointer = HostAdapter->FirmwareVersion; + *TargetPointer++ = BoardID.FirmwareVersion1stDigit; + *TargetPointer++ = '.'; + *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; + if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') + *TargetPointer++ = FirmwareVersion3rdDigit; + *TargetPointer = '\0'; + /* + Issue the Inquire Firmware Version Letter command. + */ + if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0) { + if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, NULL, 0, &FirmwareVersionLetter, sizeof(FirmwareVersionLetter)) + != sizeof(FirmwareVersionLetter)) + return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER"); + if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') + *TargetPointer++ = FirmwareVersionLetter; + *TargetPointer = '\0'; + } + /* + Save the Host Adapter SCSI ID in the Host Adapter structure. + */ + HostAdapter->SCSI_ID = Configuration.HostAdapterID; + /* + Determine the Bus Type and save it in the Host Adapter structure, determine + and save the IRQ Channel if necessary, and determine and save the DMA + Channel for ISA Host Adapters. + */ + HostAdapter->HostAdapterBusType = BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4']; + if (HostAdapter->IRQ_Channel == 0) { + if (Configuration.IRQ_Channel9) + HostAdapter->IRQ_Channel = 9; + else if (Configuration.IRQ_Channel10) + HostAdapter->IRQ_Channel = 10; + else if (Configuration.IRQ_Channel11) + HostAdapter->IRQ_Channel = 11; + else if (Configuration.IRQ_Channel12) + HostAdapter->IRQ_Channel = 12; + else if (Configuration.IRQ_Channel14) + HostAdapter->IRQ_Channel = 14; + else if (Configuration.IRQ_Channel15) + HostAdapter->IRQ_Channel = 15; + } + if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) { + if (Configuration.DMA_Channel5) + HostAdapter->DMA_Channel = 5; + else if (Configuration.DMA_Channel6) + HostAdapter->DMA_Channel = 6; + else if (Configuration.DMA_Channel7) + HostAdapter->DMA_Channel = 7; + } + /* + Determine whether Extended Translation is enabled and save it in + the Host Adapter structure. + */ + GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); + HostAdapter->ExtendedTranslationEnabled = GeometryRegister.gr.ExtendedTranslationEnabled; + /* + Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide + SCSI flag, Differential SCSI flag, SCAM Supported flag, and + Ultra SCSI flag in the Host Adapter structure. + */ + HostAdapter->HostAdapterScatterGatherLimit = ExtendedSetupInformation.ScatterGatherLimit; + HostAdapter->DriverScatterGatherLimit = HostAdapter->HostAdapterScatterGatherLimit; + if (HostAdapter->HostAdapterScatterGatherLimit > BusLogic_ScatterGatherLimit) + HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; + if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupt) + HostAdapter->LevelSensitiveInterrupt = true; + HostAdapter->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI; + HostAdapter->HostDifferentialSCSI = ExtendedSetupInformation.HostDifferentialSCSI; + HostAdapter->HostSupportsSCAM = ExtendedSetupInformation.HostSupportsSCAM; + HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI; + /* + Determine whether Extended LUN Format CCBs are supported and save the + information in the Host Adapter structure. + */ + if (HostAdapter->FirmwareVersion[0] == '5' || (HostAdapter->FirmwareVersion[0] == '4' && HostAdapter->HostWideSCSI)) + HostAdapter->ExtendedLUNSupport = true; + /* + Issue the Inquire PCI Host Adapter Information command to read the + Termination Information from "W" series MultiMaster Host Adapters. + */ + if (HostAdapter->FirmwareVersion[0] == '5') { + if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation)) + != sizeof(PCIHostAdapterInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE PCI HOST ADAPTER INFORMATION"); + /* + Save the Termination Information in the Host Adapter structure. + */ + if (PCIHostAdapterInformation.GenericInfoValid) { + HostAdapter->TerminationInfoValid = true; + HostAdapter->LowByteTerminated = PCIHostAdapterInformation.LowByteTerminated; + HostAdapter->HighByteTerminated = PCIHostAdapterInformation.HighByteTerminated; + } + } + /* + Issue the Fetch Host Adapter Local RAM command to read the AutoSCSI data + from "W" and "C" series MultiMaster Host Adapters. + */ + if (HostAdapter->FirmwareVersion[0] >= '4') { + FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset; + FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIData); + if (BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIData, sizeof(AutoSCSIData)) + != sizeof(AutoSCSIData)) + return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM"); + /* + Save the Parity Checking Enabled, Bus Reset Enabled, and Termination + Information in the Host Adapter structure. + */ + HostAdapter->ParityCheckingEnabled = AutoSCSIData.ParityCheckingEnabled; + HostAdapter->BusResetEnabled = AutoSCSIData.BusResetEnabled; + if (HostAdapter->FirmwareVersion[0] == '4') { + HostAdapter->TerminationInfoValid = true; + HostAdapter->LowByteTerminated = AutoSCSIData.LowByteTerminated; + HostAdapter->HighByteTerminated = AutoSCSIData.HighByteTerminated; + } + /* + Save the Wide Permitted, Fast Permitted, Synchronous Permitted, + Disconnect Permitted, Ultra Permitted, and SCAM Information in the + Host Adapter structure. + */ + HostAdapter->WidePermitted = AutoSCSIData.WidePermitted; + HostAdapter->FastPermitted = AutoSCSIData.FastPermitted; + HostAdapter->SynchronousPermitted = AutoSCSIData.SynchronousPermitted; + HostAdapter->DisconnectPermitted = AutoSCSIData.DisconnectPermitted; + if (HostAdapter->HostUltraSCSI) + HostAdapter->UltraPermitted = AutoSCSIData.UltraPermitted; + if (HostAdapter->HostSupportsSCAM) { + HostAdapter->SCAM_Enabled = AutoSCSIData.SCAM_Enabled; + HostAdapter->SCAM_Level2 = AutoSCSIData.SCAM_Level2; + } + } + /* + Initialize fields in the Host Adapter structure for "S" and "A" series + MultiMaster Host Adapters. + */ + if (HostAdapter->FirmwareVersion[0] < '4') { + if (SetupInformation.SynchronousInitiationEnabled) { + HostAdapter->SynchronousPermitted = 0xFF; + if (HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus) { + if (ExtendedSetupInformation.Misc.FastOnEISA) + HostAdapter->FastPermitted = 0xFF; + if (strcmp(HostAdapter->ModelName, "BT-757") == 0) + HostAdapter->WidePermitted = 0xFF; + } + } + HostAdapter->DisconnectPermitted = 0xFF; + HostAdapter->ParityCheckingEnabled = SetupInformation.ParityCheckingEnabled; + HostAdapter->BusResetEnabled = true; + } + /* + Determine the maximum number of Target IDs and Logical Units supported by + this driver for Wide and Narrow Host Adapters. + */ + HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); + HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8); + /* + Select appropriate values for the Mailbox Count, Driver Queue Depth, + Initial CCBs, and Incremental CCBs variables based on whether or not Strict + Round Robin Mode is supported. If Strict Round Robin Mode is supported, + then there is no performance degradation in using the maximum possible + number of Outgoing and Incoming Mailboxes and allowing the Tagged and + Untagged Queue Depths to determine the actual utilization. If Strict Round + Robin Mode is not supported, then the Host Adapter must scan all the + Outgoing Mailboxes whenever an Outgoing Mailbox entry is made, which can + cause a substantial performance penalty. The host adapters actually have + room to store the following number of CCBs internally; that is, they can + internally queue and manage this many active commands on the SCSI bus + simultaneously. Performance measurements demonstrate that the Driver Queue + Depth should be set to the Mailbox Count, rather than the Host Adapter + Queue Depth (internal CCB capacity), as it is more efficient to have the + queued commands waiting in Outgoing Mailboxes if necessary than to block + the process in the higher levels of the SCSI Subsystem. + + 192 BT-948/958/958D + 100 BT-946C/956C/956CD/747C/757C/757CD/445C + 50 BT-545C/540CF + 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A + */ + if (HostAdapter->FirmwareVersion[0] == '5') + HostAdapter->HostAdapterQueueDepth = 192; + else if (HostAdapter->FirmwareVersion[0] == '4') + HostAdapter->HostAdapterQueueDepth = (HostAdapter->HostAdapterBusType != BusLogic_ISA_Bus ? 100 : 50); + else + HostAdapter->HostAdapterQueueDepth = 30; + if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) { + HostAdapter->StrictRoundRobinModeSupport = true; + HostAdapter->MailboxCount = BusLogic_MaxMailboxes; + } else { + HostAdapter->StrictRoundRobinModeSupport = false; + HostAdapter->MailboxCount = 32; + } + HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; + /* + Tagged Queuing support is available and operates properly on all "W" series + MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with + firmware version 4.22 and above, and on "S" series MultiMaster Host + Adapters with firmware version 3.35 and above. + */ + HostAdapter->TaggedQueuingPermitted = 0; + switch (HostAdapter->FirmwareVersion[0]) { + case '5': + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + break; + case '4': + if (strcmp(HostAdapter->FirmwareVersion, "4.22") >= 0) + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + break; + case '3': + if (strcmp(HostAdapter->FirmwareVersion, "3.35") >= 0) + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + break; + } + /* + Determine the Host Adapter BIOS Address if the BIOS is enabled and + save it in the Host Adapter structure. The BIOS is disabled if the + BIOS_Address is 0. + */ + HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12; + /* + ISA Host Adapters require Bounce Buffers if there is more than 16MB memory. + */ + if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus && (void *) high_memory > (void *) MAX_DMA_ADDRESS) + HostAdapter->BounceBuffersRequired = true; + /* + BusLogic BT-445S Host Adapters prior to board revision E have a hardware + bug whereby when the BIOS is enabled, transfers to/from the same address + range the BIOS occupies modulo 16MB are handled incorrectly. Only properly + functioning BT-445S Host Adapters have firmware version 3.37, so require + that ISA Bounce Buffers be used for the buggy BT-445S models if there is + more than 16MB memory. + */ + if (HostAdapter->BIOS_Address > 0 && strcmp(HostAdapter->ModelName, "BT-445S") == 0 && strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 && (void *) high_memory > (void *) MAX_DMA_ADDRESS) + HostAdapter->BounceBuffersRequired = true; + /* + Initialize parameters common to MultiMaster and FlashPoint Host Adapters. + */ + Common: + /* + Initialize the Host Adapter Full Model Name from the Model Name. + */ + strcpy(HostAdapter->FullModelName, "BusLogic "); + strcat(HostAdapter->FullModelName, HostAdapter->ModelName); + /* + Select an appropriate value for the Tagged Queue Depth either from a + BusLogic Driver Options specification, or based on whether this Host + Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth + is left at 0 for automatic determination in BusLogic_SelectQueueDepths. + Initialize the Untagged Queue Depth. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) { + unsigned char QueueDepth = 0; + if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->QueueDepth[TargetID] > 0) + QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID]; + else if (HostAdapter->BounceBuffersRequired) + QueueDepth = BusLogic_TaggedQueueDepthBB; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + } + if (HostAdapter->BounceBuffersRequired) + HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB; + else + HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; + if (HostAdapter->DriverOptions != NULL) + HostAdapter->CommonQueueDepth = HostAdapter->DriverOptions->CommonQueueDepth; + if (HostAdapter->CommonQueueDepth > 0 && HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth) + HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth; + /* + Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. + Therefore, mask the Tagged Queuing Permitted Default bits with the + Disconnect/Reconnect Permitted bits. + */ + HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted; + /* + Combine the default Tagged Queuing Permitted bits with any BusLogic Driver + Options Tagged Queuing specification. + */ + if (HostAdapter->DriverOptions != NULL) + HostAdapter->TaggedQueuingPermitted = + (HostAdapter->DriverOptions->TaggedQueuingPermitted & HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | (HostAdapter->TaggedQueuingPermitted & ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask); + + /* + Select an appropriate value for Bus Settle Time either from a BusLogic + Driver Options specification, or from BusLogic_DefaultBusSettleTime. + */ + if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->BusSettleTime > 0) + HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime; + else + HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; + /* + Indicate reading the Host Adapter Configuration completed successfully. + */ + return true; } @@ -2045,210 +1725,144 @@ static boolean __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter *HostAdapter) { - unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1; - unsigned short SynchronousPermitted, FastPermitted; - unsigned short UltraPermitted, WidePermitted; - unsigned short DisconnectPermitted, TaggedQueuingPermitted; - boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth; - char SynchronousString[BusLogic_MaxTargetDevices+1]; - char WideString[BusLogic_MaxTargetDevices+1]; - char DisconnectString[BusLogic_MaxTargetDevices+1]; - char TaggedQueuingString[BusLogic_MaxTargetDevices+1]; - char *SynchronousMessage = SynchronousString; - char *WideMessage = WideString; - char *DisconnectMessage = DisconnectString; - char *TaggedQueuingMessage = TaggedQueuingString; - int TargetID; - BusLogic_Info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", - HostAdapter, HostAdapter->ModelName, - BusLogic_HostAdapterBusNames[HostAdapter->HostAdapterBusType], - (HostAdapter->HostWideSCSI ? " Wide" : ""), - (HostAdapter->HostDifferentialSCSI ? " Differential" : ""), - (HostAdapter->HostUltraSCSI ? " Ultra" : "")); - BusLogic_Info(" Firmware Version: %s, I/O Address: 0x%X, " - "IRQ Channel: %d/%s\n", HostAdapter, - HostAdapter->FirmwareVersion, - HostAdapter->IO_Address, HostAdapter->IRQ_Channel, - (HostAdapter->LevelSensitiveInterrupt ? "Level" : "Edge")); - if (HostAdapter->HostAdapterBusType != BusLogic_PCI_Bus) - { - BusLogic_Info(" DMA Channel: ", HostAdapter); - if (HostAdapter->DMA_Channel > 0) - BusLogic_Info("%d, ", HostAdapter, HostAdapter->DMA_Channel); - else BusLogic_Info("None, ", HostAdapter); - if (HostAdapter->BIOS_Address > 0) - BusLogic_Info("BIOS Address: 0x%X, ", HostAdapter, - HostAdapter->BIOS_Address); - else BusLogic_Info("BIOS Address: None, ", HostAdapter); - } - else - { - BusLogic_Info(" PCI Bus: %d, Device: %d, Address: ", - HostAdapter, HostAdapter->Bus, HostAdapter->Device); - if (HostAdapter->PCI_Address > 0) - BusLogic_Info("0x%X, ", HostAdapter, HostAdapter->PCI_Address); - else BusLogic_Info("Unassigned, ", HostAdapter); - } - BusLogic_Info("Host Adapter SCSI ID: %d\n", HostAdapter, - HostAdapter->SCSI_ID); - BusLogic_Info(" Parity Checking: %s, Extended Translation: %s\n", - HostAdapter, - (HostAdapter->ParityCheckingEnabled - ? "Enabled" : "Disabled"), - (HostAdapter->ExtendedTranslationEnabled - ? "Enabled" : "Disabled")); - AllTargetsMask &= ~(1 << HostAdapter->SCSI_ID); - SynchronousPermitted = HostAdapter->SynchronousPermitted & AllTargetsMask; - FastPermitted = HostAdapter->FastPermitted & AllTargetsMask; - UltraPermitted = HostAdapter->UltraPermitted & AllTargetsMask; - if ((BusLogic_MultiMasterHostAdapterP(HostAdapter) && - (HostAdapter->FirmwareVersion[0] >= '4' || - HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus)) || - BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - CommonSynchronousNegotiation = false; - if (SynchronousPermitted == 0) - { - SynchronousMessage = "Disabled"; - CommonSynchronousNegotiation = true; - } - else if (SynchronousPermitted == AllTargetsMask) - { - if (FastPermitted == 0) - { - SynchronousMessage = "Slow"; - CommonSynchronousNegotiation = true; - } - else if (FastPermitted == AllTargetsMask) - { - if (UltraPermitted == 0) - { - SynchronousMessage = "Fast"; - CommonSynchronousNegotiation = true; - } - else if (UltraPermitted == AllTargetsMask) - { - SynchronousMessage = "Ultra"; - CommonSynchronousNegotiation = true; - } - } - } - if (!CommonSynchronousNegotiation) - { - for (TargetID = 0; - TargetID < HostAdapter->MaxTargetDevices; - TargetID++) - SynchronousString[TargetID] = - ((!(SynchronousPermitted & (1 << TargetID))) ? 'N' : - (!(FastPermitted & (1 << TargetID)) ? 'S' : - (!(UltraPermitted & (1 << TargetID)) ? 'F' : 'U'))); - SynchronousString[HostAdapter->SCSI_ID] = '#'; - SynchronousString[HostAdapter->MaxTargetDevices] = '\0'; - } - } - else SynchronousMessage = - (SynchronousPermitted == 0 ? "Disabled" : "Enabled"); - WidePermitted = HostAdapter->WidePermitted & AllTargetsMask; - if (WidePermitted == 0) - WideMessage = "Disabled"; - else if (WidePermitted == AllTargetsMask) - WideMessage = "Enabled"; - else - { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - WideString[TargetID] = - ((WidePermitted & (1 << TargetID)) ? 'Y' : 'N'); - WideString[HostAdapter->SCSI_ID] = '#'; - WideString[HostAdapter->MaxTargetDevices] = '\0'; - } - DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask; - if (DisconnectPermitted == 0) - DisconnectMessage = "Disabled"; - else if (DisconnectPermitted == AllTargetsMask) - DisconnectMessage = "Enabled"; - else - { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - DisconnectString[TargetID] = - ((DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N'); - DisconnectString[HostAdapter->SCSI_ID] = '#'; - DisconnectString[HostAdapter->MaxTargetDevices] = '\0'; - } - TaggedQueuingPermitted = - HostAdapter->TaggedQueuingPermitted & AllTargetsMask; - if (TaggedQueuingPermitted == 0) - TaggedQueuingMessage = "Disabled"; - else if (TaggedQueuingPermitted == AllTargetsMask) - TaggedQueuingMessage = "Enabled"; - else - { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - TaggedQueuingString[TargetID] = - ((TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N'); - TaggedQueuingString[HostAdapter->SCSI_ID] = '#'; - TaggedQueuingString[HostAdapter->MaxTargetDevices] = '\0'; - } - BusLogic_Info(" Synchronous Negotiation: %s, Wide Negotiation: %s\n", - HostAdapter, SynchronousMessage, WideMessage); - BusLogic_Info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", - HostAdapter, DisconnectMessage, TaggedQueuingMessage); - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - BusLogic_Info(" Scatter/Gather Limit: %d of %d segments, " - "Mailboxes: %d\n", HostAdapter, - HostAdapter->DriverScatterGatherLimit, - HostAdapter->HostAdapterScatterGatherLimit, - HostAdapter->MailboxCount); - BusLogic_Info(" Driver Queue Depth: %d, " - "Host Adapter Queue Depth: %d\n", - HostAdapter, HostAdapter->DriverQueueDepth, - HostAdapter->HostAdapterQueueDepth); - } - else BusLogic_Info(" Driver Queue Depth: %d, " - "Scatter/Gather Limit: %d segments\n", - HostAdapter, HostAdapter->DriverQueueDepth, - HostAdapter->DriverScatterGatherLimit); - BusLogic_Info(" Tagged Queue Depth: ", HostAdapter); - CommonTaggedQueueDepth = true; - for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) - { - CommonTaggedQueueDepth = false; - break; - } - if (CommonTaggedQueueDepth) - { - if (HostAdapter->QueueDepth[0] > 0) - BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]); - else BusLogic_Info("Automatic", HostAdapter); - } - else BusLogic_Info("Individual", HostAdapter); - BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, - HostAdapter->UntaggedQueueDepth); - if (HostAdapter->TerminationInfoValid) - { - if (HostAdapter->HostWideSCSI) - BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, - (HostAdapter->LowByteTerminated - ? (HostAdapter->HighByteTerminated - ? "Both Enabled" : "Low Enabled") - : (HostAdapter->HighByteTerminated - ? "High Enabled" : "Both Disabled"))); - else BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, - (HostAdapter->LowByteTerminated ? - "Enabled" : "Disabled")); - if (HostAdapter->HostSupportsSCAM) - BusLogic_Info(", SCAM: %s", HostAdapter, - (HostAdapter->SCAM_Enabled - ? (HostAdapter->SCAM_Level2 - ? "Enabled, Level 2" : "Enabled, Level 1") - : "Disabled")); - BusLogic_Info("\n", HostAdapter); - } - /* - Indicate reporting the Host Adapter configuration completed successfully. - */ - return true; + unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1; + unsigned short SynchronousPermitted, FastPermitted; + unsigned short UltraPermitted, WidePermitted; + unsigned short DisconnectPermitted, TaggedQueuingPermitted; + boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth; + char SynchronousString[BusLogic_MaxTargetDevices + 1]; + char WideString[BusLogic_MaxTargetDevices + 1]; + char DisconnectString[BusLogic_MaxTargetDevices + 1]; + char TaggedQueuingString[BusLogic_MaxTargetDevices + 1]; + char *SynchronousMessage = SynchronousString; + char *WideMessage = WideString; + char *DisconnectMessage = DisconnectString; + char *TaggedQueuingMessage = TaggedQueuingString; + int TargetID; + BusLogic_Info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", + HostAdapter, HostAdapter->ModelName, + BusLogic_HostAdapterBusNames[HostAdapter->HostAdapterBusType], (HostAdapter->HostWideSCSI ? " Wide" : ""), (HostAdapter->HostDifferentialSCSI ? " Differential" : ""), (HostAdapter->HostUltraSCSI ? " Ultra" : "")); + BusLogic_Info(" Firmware Version: %s, I/O Address: 0x%X, " "IRQ Channel: %d/%s\n", HostAdapter, HostAdapter->FirmwareVersion, HostAdapter->IO_Address, HostAdapter->IRQ_Channel, (HostAdapter->LevelSensitiveInterrupt ? "Level" : "Edge")); + if (HostAdapter->HostAdapterBusType != BusLogic_PCI_Bus) { + BusLogic_Info(" DMA Channel: ", HostAdapter); + if (HostAdapter->DMA_Channel > 0) + BusLogic_Info("%d, ", HostAdapter, HostAdapter->DMA_Channel); + else + BusLogic_Info("None, ", HostAdapter); + if (HostAdapter->BIOS_Address > 0) + BusLogic_Info("BIOS Address: 0x%X, ", HostAdapter, HostAdapter->BIOS_Address); + else + BusLogic_Info("BIOS Address: None, ", HostAdapter); + } else { + BusLogic_Info(" PCI Bus: %d, Device: %d, Address: ", HostAdapter, HostAdapter->Bus, HostAdapter->Device); + if (HostAdapter->PCI_Address > 0) + BusLogic_Info("0x%X, ", HostAdapter, HostAdapter->PCI_Address); + else + BusLogic_Info("Unassigned, ", HostAdapter); + } + BusLogic_Info("Host Adapter SCSI ID: %d\n", HostAdapter, HostAdapter->SCSI_ID); + BusLogic_Info(" Parity Checking: %s, Extended Translation: %s\n", HostAdapter, (HostAdapter->ParityCheckingEnabled ? "Enabled" : "Disabled"), (HostAdapter->ExtendedTranslationEnabled ? "Enabled" : "Disabled")); + AllTargetsMask &= ~(1 << HostAdapter->SCSI_ID); + SynchronousPermitted = HostAdapter->SynchronousPermitted & AllTargetsMask; + FastPermitted = HostAdapter->FastPermitted & AllTargetsMask; + UltraPermitted = HostAdapter->UltraPermitted & AllTargetsMask; + if ((BusLogic_MultiMasterHostAdapterP(HostAdapter) && (HostAdapter->FirmwareVersion[0] >= '4' || HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus)) || BusLogic_FlashPointHostAdapterP(HostAdapter)) { + CommonSynchronousNegotiation = false; + if (SynchronousPermitted == 0) { + SynchronousMessage = "Disabled"; + CommonSynchronousNegotiation = true; + } else if (SynchronousPermitted == AllTargetsMask) { + if (FastPermitted == 0) { + SynchronousMessage = "Slow"; + CommonSynchronousNegotiation = true; + } else if (FastPermitted == AllTargetsMask) { + if (UltraPermitted == 0) { + SynchronousMessage = "Fast"; + CommonSynchronousNegotiation = true; + } else if (UltraPermitted == AllTargetsMask) { + SynchronousMessage = "Ultra"; + CommonSynchronousNegotiation = true; + } + } + } + if (!CommonSynchronousNegotiation) { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + SynchronousString[TargetID] = ((!(SynchronousPermitted & (1 << TargetID))) ? 'N' : (!(FastPermitted & (1 << TargetID)) ? 'S' : (!(UltraPermitted & (1 << TargetID)) ? 'F' : 'U'))); + SynchronousString[HostAdapter->SCSI_ID] = '#'; + SynchronousString[HostAdapter->MaxTargetDevices] = '\0'; + } + } else + SynchronousMessage = (SynchronousPermitted == 0 ? "Disabled" : "Enabled"); + WidePermitted = HostAdapter->WidePermitted & AllTargetsMask; + if (WidePermitted == 0) + WideMessage = "Disabled"; + else if (WidePermitted == AllTargetsMask) + WideMessage = "Enabled"; + else { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + WideString[TargetID] = ((WidePermitted & (1 << TargetID)) ? 'Y' : 'N'); + WideString[HostAdapter->SCSI_ID] = '#'; + WideString[HostAdapter->MaxTargetDevices] = '\0'; + } + DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask; + if (DisconnectPermitted == 0) + DisconnectMessage = "Disabled"; + else if (DisconnectPermitted == AllTargetsMask) + DisconnectMessage = "Enabled"; + else { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + DisconnectString[TargetID] = ((DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N'); + DisconnectString[HostAdapter->SCSI_ID] = '#'; + DisconnectString[HostAdapter->MaxTargetDevices] = '\0'; + } + TaggedQueuingPermitted = HostAdapter->TaggedQueuingPermitted & AllTargetsMask; + if (TaggedQueuingPermitted == 0) + TaggedQueuingMessage = "Disabled"; + else if (TaggedQueuingPermitted == AllTargetsMask) + TaggedQueuingMessage = "Enabled"; + else { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + TaggedQueuingString[TargetID] = ((TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N'); + TaggedQueuingString[HostAdapter->SCSI_ID] = '#'; + TaggedQueuingString[HostAdapter->MaxTargetDevices] = '\0'; + } + BusLogic_Info(" Synchronous Negotiation: %s, Wide Negotiation: %s\n", HostAdapter, SynchronousMessage, WideMessage); + BusLogic_Info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", HostAdapter, DisconnectMessage, TaggedQueuingMessage); + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + BusLogic_Info(" Scatter/Gather Limit: %d of %d segments, " "Mailboxes: %d\n", HostAdapter, HostAdapter->DriverScatterGatherLimit, HostAdapter->HostAdapterScatterGatherLimit, HostAdapter->MailboxCount); + BusLogic_Info(" Driver Queue Depth: %d, " "Host Adapter Queue Depth: %d\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->HostAdapterQueueDepth); + } else + BusLogic_Info(" Driver Queue Depth: %d, " "Scatter/Gather Limit: %d segments\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->DriverScatterGatherLimit); + BusLogic_Info(" Tagged Queue Depth: ", HostAdapter); + CommonTaggedQueueDepth = true; + for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) { + CommonTaggedQueueDepth = false; + break; + } + if (CommonTaggedQueueDepth) { + if (HostAdapter->QueueDepth[0] > 0) + BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]); + else + BusLogic_Info("Automatic", HostAdapter); + } else + BusLogic_Info("Individual", HostAdapter); + BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, HostAdapter->UntaggedQueueDepth); + if (HostAdapter->TerminationInfoValid) { + if (HostAdapter->HostWideSCSI) + BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? (HostAdapter->HighByteTerminated ? "Both Enabled" : "Low Enabled") + : (HostAdapter->HighByteTerminated ? "High Enabled" : "Both Disabled"))); + else + BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? "Enabled" : "Disabled")); + if (HostAdapter->HostSupportsSCAM) + BusLogic_Info(", SCAM: %s", HostAdapter, (HostAdapter->SCAM_Enabled ? (HostAdapter->SCAM_Level2 ? "Enabled, Level 2" : "Enabled, Level 1") + : "Disabled")); + BusLogic_Info("\n", HostAdapter); + } + /* + Indicate reporting the Host Adapter configuration completed successfully. + */ + return true; } @@ -2259,43 +1873,34 @@ static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter) { - if (HostAdapter->IRQ_Channel == 0) - { - BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", - HostAdapter); - return false; - } - /* - Acquire shared access to the IRQ Channel. - */ - if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, - SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0) - { - BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", - HostAdapter, HostAdapter->IRQ_Channel); - return false; - } - HostAdapter->IRQ_ChannelAcquired = true; - /* - Acquire exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_Channel > 0) - { - if (request_dma(HostAdapter->DMA_Channel, - HostAdapter->FullModelName) < 0) - { - BusLogic_Error("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", - HostAdapter, HostAdapter->DMA_Channel); - return false; - } - set_dma_mode(HostAdapter->DMA_Channel, DMA_MODE_CASCADE); - enable_dma(HostAdapter->DMA_Channel); - HostAdapter->DMA_ChannelAcquired = true; - } - /* - Indicate the System Resource Acquisition completed successfully, - */ - return true; + if (HostAdapter->IRQ_Channel == 0) { + BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", HostAdapter); + return false; + } + /* + Acquire shared access to the IRQ Channel. + */ + if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0) { + BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->IRQ_Channel); + return false; + } + HostAdapter->IRQ_ChannelAcquired = true; + /* + Acquire exclusive access to the DMA Channel. + */ + if (HostAdapter->DMA_Channel > 0) { + if (request_dma(HostAdapter->DMA_Channel, HostAdapter->FullModelName) < 0) { + BusLogic_Error("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->DMA_Channel); + return false; + } + set_dma_mode(HostAdapter->DMA_Channel, DMA_MODE_CASCADE); + enable_dma(HostAdapter->DMA_Channel); + HostAdapter->DMA_ChannelAcquired = true; + } + /* + Indicate the System Resource Acquisition completed successfully, + */ + return true; } @@ -2306,26 +1911,24 @@ static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter) { - /* - Release shared access to the IRQ Channel. - */ - if (HostAdapter->IRQ_ChannelAcquired) - free_irq(HostAdapter->IRQ_Channel, HostAdapter); - /* - Release exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_ChannelAcquired) - free_dma(HostAdapter->DMA_Channel); - /* - Release any allocated memory structs not released elsewhere - */ - if (HostAdapter->MailboxSpace) - pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, - HostAdapter->MailboxSpace, - HostAdapter->MailboxSpaceHandle); - HostAdapter->MailboxSpace = NULL; - HostAdapter->MailboxSpaceHandle = 0; - HostAdapter->MailboxSize = 0; + /* + Release shared access to the IRQ Channel. + */ + if (HostAdapter->IRQ_ChannelAcquired) + free_irq(HostAdapter->IRQ_Channel, HostAdapter); + /* + Release exclusive access to the DMA Channel. + */ + if (HostAdapter->DMA_ChannelAcquired) + free_dma(HostAdapter->DMA_Channel); + /* + Release any allocated memory structs not released elsewhere + */ + if (HostAdapter->MailboxSpace) + pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, HostAdapter->MailboxSpace, HostAdapter->MailboxSpaceHandle); + HostAdapter->MailboxSpace = NULL; + HostAdapter->MailboxSpaceHandle = 0; + HostAdapter->MailboxSize = 0; } @@ -2338,114 +1941,94 @@ static boolean BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest; - enum BusLogic_RoundRobinModeRequest RoundRobinModeRequest; - enum BusLogic_SetCCBFormatRequest SetCCBFormatRequest; - int TargetID; - /* - Initialize the pointers to the first and last CCBs that are queued for - completion processing. - */ - HostAdapter->FirstCompletedCCB = NULL; - HostAdapter->LastCompletedCCB = NULL; - /* - Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active, - Command Successful Flag, Active Commands, and Commands Since Reset - for each Target Device. - */ - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; - HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; - HostAdapter->ActiveCommands[TargetID] = 0; - HostAdapter->CommandsSinceReset[TargetID] = 0; - } - /* - FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) goto Done; - /* - Initialize the Outgoing and Incoming Mailbox pointers. - */ - HostAdapter->MailboxSize = HostAdapter->MailboxCount * - (sizeof(struct BusLogic_OutgoingMailbox) + sizeof(struct BusLogic_IncomingMailbox)); - HostAdapter->MailboxSpace = pci_alloc_consistent(HostAdapter->PCI_Device, - HostAdapter->MailboxSize, &HostAdapter->MailboxSpaceHandle); - if (HostAdapter->MailboxSpace == NULL) - return BusLogic_Failure(HostAdapter, "MAILBOX ALLOCATION"); - HostAdapter->FirstOutgoingMailbox = - (struct BusLogic_OutgoingMailbox *) HostAdapter->MailboxSpace; - HostAdapter->LastOutgoingMailbox = - HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->FirstIncomingMailbox = - (struct BusLogic_IncomingMailbox *) (HostAdapter->LastOutgoingMailbox + 1); - HostAdapter->LastIncomingMailbox = - HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - - /* - Initialize the Outgoing and Incoming Mailbox structures. - */ - memset(HostAdapter->FirstOutgoingMailbox, 0, - HostAdapter->MailboxCount * sizeof(struct BusLogic_OutgoingMailbox)); - memset(HostAdapter->FirstIncomingMailbox, 0, - HostAdapter->MailboxCount * sizeof(struct BusLogic_IncomingMailbox)); - /* - Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. - */ - ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; - ExtendedMailboxRequest.BaseMailboxAddress = - (u32) HostAdapter->MailboxSpaceHandle; - if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, - &ExtendedMailboxRequest, - sizeof(ExtendedMailboxRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION"); - /* - Enable Strict Round Robin Mode if supported by the Host Adapter. In - Strict Round Robin Mode, the Host Adapter only looks at the next Outgoing - Mailbox for each new command, rather than scanning through all the - Outgoing Mailboxes to find any that have new commands in them. Strict - Round Robin Mode is significantly more efficient. - */ - if (HostAdapter->StrictRoundRobinModeSupport) - { - RoundRobinModeRequest = BusLogic_StrictRoundRobinMode; - if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, - &RoundRobinModeRequest, - sizeof(RoundRobinModeRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE"); - } - /* - For Host Adapters that support Extended LUN Format CCBs, issue the Set CCB - Format command to allow 32 Logical Units per Target Device. - */ - if (HostAdapter->ExtendedLUNSupport) - { - SetCCBFormatRequest = BusLogic_ExtendedLUNFormatCCB; - if (BusLogic_Command(HostAdapter, BusLogic_SetCCBFormat, - &SetCCBFormatRequest, sizeof(SetCCBFormatRequest), - NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "SET CCB FORMAT"); - } - /* - Announce Successful Initialization. - */ -Done: - if (!HostAdapter->HostAdapterInitialized) - { - BusLogic_Info("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); - BusLogic_Info("\n", HostAdapter); - } - else BusLogic_Warning("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); - HostAdapter->HostAdapterInitialized = true; - /* - Indicate the Host Adapter Initialization completed successfully. - */ - return true; + struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest; + enum BusLogic_RoundRobinModeRequest RoundRobinModeRequest; + enum BusLogic_SetCCBFormatRequest SetCCBFormatRequest; + int TargetID; + /* + Initialize the pointers to the first and last CCBs that are queued for + completion processing. + */ + HostAdapter->FirstCompletedCCB = NULL; + HostAdapter->LastCompletedCCB = NULL; + /* + Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active, + Command Successful Flag, Active Commands, and Commands Since Reset + for each Target Device. + */ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; + HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; + HostAdapter->ActiveCommands[TargetID] = 0; + HostAdapter->CommandsSinceReset[TargetID] = 0; + } + /* + FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + goto Done; + /* + Initialize the Outgoing and Incoming Mailbox pointers. + */ + HostAdapter->MailboxSize = HostAdapter->MailboxCount * (sizeof(struct BusLogic_OutgoingMailbox) + sizeof(struct BusLogic_IncomingMailbox)); + HostAdapter->MailboxSpace = pci_alloc_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, &HostAdapter->MailboxSpaceHandle); + if (HostAdapter->MailboxSpace == NULL) + return BusLogic_Failure(HostAdapter, "MAILBOX ALLOCATION"); + HostAdapter->FirstOutgoingMailbox = (struct BusLogic_OutgoingMailbox *) HostAdapter->MailboxSpace; + HostAdapter->LastOutgoingMailbox = HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; + HostAdapter->FirstIncomingMailbox = (struct BusLogic_IncomingMailbox *) (HostAdapter->LastOutgoingMailbox + 1); + HostAdapter->LastIncomingMailbox = HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; + + /* + Initialize the Outgoing and Incoming Mailbox structures. + */ + memset(HostAdapter->FirstOutgoingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_OutgoingMailbox)); + memset(HostAdapter->FirstIncomingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_IncomingMailbox)); + /* + Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. + */ + ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; + ExtendedMailboxRequest.BaseMailboxAddress = (u32) HostAdapter->MailboxSpaceHandle; + if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, &ExtendedMailboxRequest, sizeof(ExtendedMailboxRequest), NULL, 0) < 0) + return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION"); + /* + Enable Strict Round Robin Mode if supported by the Host Adapter. In + Strict Round Robin Mode, the Host Adapter only looks at the next Outgoing + Mailbox for each new command, rather than scanning through all the + Outgoing Mailboxes to find any that have new commands in them. Strict + Round Robin Mode is significantly more efficient. + */ + if (HostAdapter->StrictRoundRobinModeSupport) { + RoundRobinModeRequest = BusLogic_StrictRoundRobinMode; + if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, &RoundRobinModeRequest, sizeof(RoundRobinModeRequest), NULL, 0) < 0) + return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE"); + } + /* + For Host Adapters that support Extended LUN Format CCBs, issue the Set CCB + Format command to allow 32 Logical Units per Target Device. + */ + if (HostAdapter->ExtendedLUNSupport) { + SetCCBFormatRequest = BusLogic_ExtendedLUNFormatCCB; + if (BusLogic_Command(HostAdapter, BusLogic_SetCCBFormat, &SetCCBFormatRequest, sizeof(SetCCBFormatRequest), NULL, 0) < 0) + return BusLogic_Failure(HostAdapter, "SET CCB FORMAT"); + } + /* + Announce Successful Initialization. + */ + Done: + if (!HostAdapter->HostAdapterInitialized) { + BusLogic_Info("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName); + BusLogic_Info("\n", HostAdapter); + } else + BusLogic_Warning("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName); + HostAdapter->HostAdapterInitialized = true; + /* + Indicate the Host Adapter Initialization completed successfully. + */ + return true; } @@ -2457,127 +2040,106 @@ static boolean __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter *HostAdapter) { - u16 InstalledDevices; - u8 InstalledDevicesID0to7[8]; - struct BusLogic_SetupInformation SetupInformation; - u8 SynchronousPeriod[BusLogic_MaxTargetDevices]; - unsigned char RequestedReplyLength; - int TargetID; - /* - Wait a few seconds between the Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get - confused if they receive SCSI Commands too soon after a SCSI Bus Reset. - */ - BusLogic_Delay(HostAdapter->BusSettleTime); - /* - FlashPoint Host Adapters do not provide for Target Device Inquiry. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Inhibit the Target Device Inquiry if requested. - */ - if (HostAdapter->DriverOptions != NULL && - HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) - return true; - /* - Issue the Inquire Target Devices command for host adapters with firmware - version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command - for older host adapters. This is necessary to force Synchronous Transfer - Negotiation so that the Inquire Setup Information and Inquire Synchronous - Period commands will return valid data. The Inquire Target Devices command - is preferable to Inquire Installed Devices ID 0 to 7 since it only probes - Logical Unit 0 of each Target Device. - */ - if (strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) - { - - /* - * Issue a Inquire Target Devices command. Inquire Target Devices only - * tests Logical Unit 0 of each Target Device unlike the Inquire Installed - * Devices commands which test Logical Units 0 - 7. Two bytes are - * returned, where byte 0 bit 0 set indicates that Target Device 0 exists, - * and so on. - */ - - if (BusLogic_Command(HostAdapter, BusLogic_InquireTargetDevices, NULL, 0, - &InstalledDevices, sizeof(InstalledDevices)) - != sizeof(InstalledDevices)) - return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->TargetFlags[TargetID].TargetExists = - (InstalledDevices & (1 << TargetID) ? true : false); - } - else - { - - /* - * Issue an Inquire Installed Devices command. For each Target Device, - * a byte is returned where bit 0 set indicates that Logical Unit 0 - * exists, bit 1 set indicates that Logical Unit 1 exists, and so on. - */ - - if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7, - NULL, 0, &InstalledDevicesID0to7, - sizeof(InstalledDevicesID0to7)) - != sizeof(InstalledDevicesID0to7)) - return BusLogic_Failure(HostAdapter, - "INQUIRE INSTALLED DEVICES ID 0 TO 7"); - for (TargetID = 0; TargetID < 8; TargetID++) - HostAdapter->TargetFlags[TargetID].TargetExists = - (InstalledDevicesID0to7[TargetID] != 0 ? true : false); - } - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->SynchronousOffset[TargetID] = - (TargetID < 8 - ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset - : SetupInformation.SynchronousValuesID8to15[TargetID-8].Offset); - if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0) - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->TargetFlags[TargetID].WideTransfersActive = - (TargetID < 8 - ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID) - ? true : false) - : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID-8)) - ? true : false)); - /* - Issue the Inquire Synchronous Period command. - */ - if (HostAdapter->FirmwareVersion[0] >= '3') - { - - /* Issue a Inquire Synchronous Period command. For each Target Device, - * a byte is returned which represents the Synchronous Transfer Period - * in units of 10 nanoseconds. - */ - - RequestedReplyLength = sizeof(SynchronousPeriod); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSynchronousPeriod, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SynchronousPeriod, sizeof(SynchronousPeriod)) - != sizeof(SynchronousPeriod)) - return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID]; - } - else - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) - HostAdapter->SynchronousPeriod[TargetID] = - 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] - .TransferPeriod; - /* - Indicate the Target Device Inquiry completed successfully. - */ - return true; + u16 InstalledDevices; + u8 InstalledDevicesID0to7[8]; + struct BusLogic_SetupInformation SetupInformation; + u8 SynchronousPeriod[BusLogic_MaxTargetDevices]; + unsigned char RequestedReplyLength; + int TargetID; + /* + Wait a few seconds between the Host Adapter Hard Reset which initiates + a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get + confused if they receive SCSI Commands too soon after a SCSI Bus Reset. + */ + BusLogic_Delay(HostAdapter->BusSettleTime); + /* + FlashPoint Host Adapters do not provide for Target Device Inquiry. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + return true; + /* + Inhibit the Target Device Inquiry if requested. + */ + if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) + return true; + /* + Issue the Inquire Target Devices command for host adapters with firmware + version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command + for older host adapters. This is necessary to force Synchronous Transfer + Negotiation so that the Inquire Setup Information and Inquire Synchronous + Period commands will return valid data. The Inquire Target Devices command + is preferable to Inquire Installed Devices ID 0 to 7 since it only probes + Logical Unit 0 of each Target Device. + */ + if (strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) { + + /* + * Issue a Inquire Target Devices command. Inquire Target Devices only + * tests Logical Unit 0 of each Target Device unlike the Inquire Installed + * Devices commands which test Logical Units 0 - 7. Two bytes are + * returned, where byte 0 bit 0 set indicates that Target Device 0 exists, + * and so on. + */ + + if (BusLogic_Command(HostAdapter, BusLogic_InquireTargetDevices, NULL, 0, &InstalledDevices, sizeof(InstalledDevices)) + != sizeof(InstalledDevices)) + return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevices & (1 << TargetID) ? true : false); + } else { + + /* + * Issue an Inquire Installed Devices command. For each Target Device, + * a byte is returned where bit 0 set indicates that Logical Unit 0 + * exists, bit 1 set indicates that Logical Unit 1 exists, and so on. + */ + + if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7, NULL, 0, &InstalledDevicesID0to7, sizeof(InstalledDevicesID0to7)) + != sizeof(InstalledDevicesID0to7)) + return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7"); + for (TargetID = 0; TargetID < 8; TargetID++) + HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevicesID0to7[TargetID] != 0 ? true : false); + } + /* + Issue the Inquire Setup Information command. + */ + RequestedReplyLength = sizeof(SetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation)) + != sizeof(SetupInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousOffset[TargetID] = (TargetID < 8 ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset : SetupInformation.SynchronousValuesID8to15[TargetID - 8].Offset); + if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0) + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].WideTransfersActive = (TargetID < 8 ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID) + ? true : false) + : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID - 8)) + ? true : false)); + /* + Issue the Inquire Synchronous Period command. + */ + if (HostAdapter->FirmwareVersion[0] >= '3') { + + /* Issue a Inquire Synchronous Period command. For each Target Device, + * a byte is returned which represents the Synchronous Transfer Period + * in units of 10 nanoseconds. + */ + + RequestedReplyLength = sizeof(SynchronousPeriod); + if (BusLogic_Command(HostAdapter, BusLogic_InquireSynchronousPeriod, &RequestedReplyLength, sizeof(RequestedReplyLength), &SynchronousPeriod, sizeof(SynchronousPeriod)) + != sizeof(SynchronousPeriod)) + return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID]; + } else + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) + HostAdapter->SynchronousPeriod[TargetID] = 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] + .TransferPeriod; + /* + Indicate the Target Device Inquiry completed successfully. + */ + return true; } /* @@ -2590,18 +2152,17 @@ */ static void __init BusLogic_InitializeHostStructure(struct BusLogic_HostAdapter - *HostAdapter, - struct Scsi_Host *Host) + *HostAdapter, struct Scsi_Host *Host) { - Host->max_id = HostAdapter->MaxTargetDevices; - Host->max_lun = HostAdapter->MaxLogicalUnits; - Host->max_channel = 0; - Host->unique_id = HostAdapter->IO_Address; - Host->this_id = HostAdapter->SCSI_ID; - Host->can_queue = HostAdapter->DriverQueueDepth; - Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit; - Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired; - Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth; + Host->max_id = HostAdapter->MaxTargetDevices; + Host->max_lun = HostAdapter->MaxLogicalUnits; + Host->max_channel = 0; + Host->unique_id = HostAdapter->IO_Address; + Host->this_id = HostAdapter->SCSI_ID; + Host->can_queue = HostAdapter->DriverQueueDepth; + Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit; + Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired; + Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth; } /* @@ -2614,38 +2175,29 @@ */ static int BusLogic_SlaveConfigure(struct scsi_device *Device) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Device->host->hostdata; - int TargetID = Device->id; - int QueueDepth = HostAdapter->QueueDepth[TargetID]; - - if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && - (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) - { - if (QueueDepth == 0) - QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth); - } - else - { - HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); - QueueDepth = HostAdapter->UntaggedQueueDepth; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - scsi_adjust_queue_depth(Device, 0, QueueDepth); - } - QueueDepth = 0; - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->TargetFlags[TargetID].TargetExists) - { - QueueDepth += HostAdapter->QueueDepth[TargetID]; - } - if (QueueDepth > HostAdapter->AllocatedCCBs) - BusLogic_CreateAdditionalCCBs(HostAdapter, - QueueDepth - - HostAdapter->AllocatedCCBs, - false); - return 0; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Device->host->hostdata; + int TargetID = Device->id; + int QueueDepth = HostAdapter->QueueDepth[TargetID]; + + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { + if (QueueDepth == 0) + QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth); + } else { + HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); + QueueDepth = HostAdapter->UntaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + scsi_adjust_queue_depth(Device, 0, QueueDepth); + } + QueueDepth = 0; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->TargetFlags[TargetID].TargetExists) { + QueueDepth += HostAdapter->QueueDepth[TargetID]; + } + if (QueueDepth > HostAdapter->AllocatedCCBs) + BusLogic_CreateAdditionalCCBs(HostAdapter, QueueDepth - HostAdapter->AllocatedCCBs, false); + return 0; } /* @@ -2658,162 +2210,145 @@ static int __init BusLogic_DetectHostAdapter(struct scsi_host_template *HostTemplate) { - int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex; - struct BusLogic_HostAdapter *PrototypeHostAdapter; - if (BusLogic_ProbeOptions.NoProbe) return 0; - BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *) - kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), - GFP_ATOMIC); - if (BusLogic_ProbeInfoList == NULL) - { - BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); - return 0; - } - memset(BusLogic_ProbeInfoList, 0, - BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo)); - PrototypeHostAdapter = (struct BusLogic_HostAdapter *) - kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC); - if (PrototypeHostAdapter == NULL) - { - kfree(BusLogic_ProbeInfoList); - BusLogic_Error("BusLogic: Unable to allocate Prototype " - "Host Adapter\n", NULL); - return 0; - } - memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); + int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex; + struct BusLogic_HostAdapter *PrototypeHostAdapter; + if (BusLogic_ProbeOptions.NoProbe) + return 0; + BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *) + kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_ATOMIC); + if (BusLogic_ProbeInfoList == NULL) { + BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); + return 0; + } + memset(BusLogic_ProbeInfoList, 0, BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo)); + PrototypeHostAdapter = (struct BusLogic_HostAdapter *) + kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC); + if (PrototypeHostAdapter == NULL) { + kfree(BusLogic_ProbeInfoList); + BusLogic_Error("BusLogic: Unable to allocate Prototype " "Host Adapter\n", NULL); + return 0; + } + memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); #ifdef MODULE - if (BusLogic != NULL) - BusLogic_Setup(BusLogic); + if (BusLogic != NULL) + BusLogic_Setup(BusLogic); #endif - BusLogic_InitializeProbeInfoList(PrototypeHostAdapter); - for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) - { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex]; - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct Scsi_Host *Host; - if (ProbeInfo->IO_Address == 0) continue; - memset(HostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); - HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType; - HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType; - HostAdapter->IO_Address = ProbeInfo->IO_Address; - HostAdapter->PCI_Address = ProbeInfo->PCI_Address; - HostAdapter->Bus = ProbeInfo->Bus; - HostAdapter->Device = ProbeInfo->Device; - HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; - HostAdapter->AddressCount = - BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; - /* - Probe the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_ProbeHostAdapter(HostAdapter)) continue; - /* - Hard Reset the Host Adapter. If unsuccessful, abort further - initialization. - */ - if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue; - /* - Check the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_CheckHostAdapter(HostAdapter)) continue; - /* - Initialize the Driver Options field if provided. - */ - if (DriverOptionsIndex < BusLogic_DriverOptionsCount) - HostAdapter->DriverOptions = - &BusLogic_DriverOptions[DriverOptionsIndex++]; - /* - Announce the Driver Version and Date, Author's Name, Copyright Notice, - and Electronic Mail Address. - */ - BusLogic_AnnounceDriver(HostAdapter); - /* - Register usage of the I/O Address range. From this point onward, any - failure will be assumed to be due to a problem with the Host Adapter, - rather than due to having mistakenly identified this port as belonging - to a BusLogic Host Adapter. The I/O Address range will not be - released, thereby preventing it from being incorrectly identified as - any other type of Host Adapter. - */ - if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, - "BusLogic")) continue; - /* - Register the SCSI Host structure. - */ - - Host = scsi_host_alloc(HostTemplate, sizeof(struct BusLogic_HostAdapter)); - if(Host==NULL) - { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - continue; - } - HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; - memcpy(HostAdapter, PrototypeHostAdapter, sizeof(struct BusLogic_HostAdapter)); - HostAdapter->SCSI_Host = Host; - HostAdapter->HostNumber = Host->host_no; - /* - Add Host Adapter to the end of the list of registered BusLogic - Host Adapters. - */ - BusLogic_RegisterHostAdapter(HostAdapter); - /* - Read the Host Adapter Configuration, Configure the Host Adapter, - Acquire the System Resources necessary to use the Host Adapter, then - Create the Initial CCBs, Initialize the Host Adapter, and finally - perform Target Device Inquiry. - */ - if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && - BusLogic_ReportHostAdapterConfiguration(HostAdapter) && - BusLogic_AcquireResources(HostAdapter) && - BusLogic_CreateInitialCCBs(HostAdapter) && - BusLogic_InitializeHostAdapter(HostAdapter) && - BusLogic_TargetDeviceInquiry(HostAdapter)) - { - /* - Initialization has been completed successfully. Release and - re-register usage of the I/O Address range so that the Model - Name of the Host Adapter will appear, and initialize the SCSI - Host structure. - */ - release_region(HostAdapter->IO_Address, - HostAdapter->AddressCount); - if(!request_region(HostAdapter->IO_Address, - HostAdapter->AddressCount, - HostAdapter->FullModelName)) { - printk(KERN_WARNING "BusLogic: Release and re-register of " - "port 0x%04lx failed \n", - (unsigned long)HostAdapter->IO_Address); - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - BusLogic_UnregisterHostAdapter(HostAdapter); - scsi_host_put(Host); - } - else { - BusLogic_InitializeHostStructure(HostAdapter, Host); - scsi_add_host(Host, NULL); - scsi_scan_host(Host); - BusLogicHostAdapterCount++; - } - } - else - { - /* - An error occurred during Host Adapter Configuration Querying, Host - Adapter Configuration, Resource Acquisition, CCB Creation, Host - Adapter Initialization, or Target Device Inquiry, so remove Host - Adapter from the list of registered BusLogic Host Adapters, destroy - the CCBs, Release the System Resources, and Unregister the SCSI - Host. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - BusLogic_UnregisterHostAdapter(HostAdapter); - scsi_host_put(Host); - } - } - kfree(PrototypeHostAdapter); - kfree(BusLogic_ProbeInfoList); - BusLogic_ProbeInfoList = NULL; - return BusLogicHostAdapterCount; + BusLogic_InitializeProbeInfoList(PrototypeHostAdapter); + for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex]; + struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; + struct Scsi_Host *Host; + if (ProbeInfo->IO_Address == 0) + continue; + memset(HostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); + HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType; + HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType; + HostAdapter->IO_Address = ProbeInfo->IO_Address; + HostAdapter->PCI_Address = ProbeInfo->PCI_Address; + HostAdapter->Bus = ProbeInfo->Bus; + HostAdapter->Device = ProbeInfo->Device; + HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; + HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; + /* + Probe the Host Adapter. If unsuccessful, abort further initialization. + */ + if (!BusLogic_ProbeHostAdapter(HostAdapter)) + continue; + /* + Hard Reset the Host Adapter. If unsuccessful, abort further + initialization. + */ + if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) + continue; + /* + Check the Host Adapter. If unsuccessful, abort further initialization. + */ + if (!BusLogic_CheckHostAdapter(HostAdapter)) + continue; + /* + Initialize the Driver Options field if provided. + */ + if (DriverOptionsIndex < BusLogic_DriverOptionsCount) + HostAdapter->DriverOptions = &BusLogic_DriverOptions[DriverOptionsIndex++]; + /* + Announce the Driver Version and Date, Author's Name, Copyright Notice, + and Electronic Mail Address. + */ + BusLogic_AnnounceDriver(HostAdapter); + /* + Register usage of the I/O Address range. From this point onward, any + failure will be assumed to be due to a problem with the Host Adapter, + rather than due to having mistakenly identified this port as belonging + to a BusLogic Host Adapter. The I/O Address range will not be + released, thereby preventing it from being incorrectly identified as + any other type of Host Adapter. + */ + if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, "BusLogic")) + continue; + /* + Register the SCSI Host structure. + */ + + Host = scsi_host_alloc(HostTemplate, sizeof(struct BusLogic_HostAdapter)); + if (Host == NULL) { + release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + continue; + } + HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; + memcpy(HostAdapter, PrototypeHostAdapter, sizeof(struct BusLogic_HostAdapter)); + HostAdapter->SCSI_Host = Host; + HostAdapter->HostNumber = Host->host_no; + /* + Add Host Adapter to the end of the list of registered BusLogic + Host Adapters. + */ + BusLogic_RegisterHostAdapter(HostAdapter); + /* + Read the Host Adapter Configuration, Configure the Host Adapter, + Acquire the System Resources necessary to use the Host Adapter, then + Create the Initial CCBs, Initialize the Host Adapter, and finally + perform Target Device Inquiry. + */ + if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && + BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) { + /* + Initialization has been completed successfully. Release and + re-register usage of the I/O Address range so that the Model + Name of the Host Adapter will appear, and initialize the SCSI + Host structure. + */ + release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, HostAdapter->FullModelName)) { + printk(KERN_WARNING "BusLogic: Release and re-register of " "port 0x%04lx failed \n", (unsigned long) HostAdapter->IO_Address); + BusLogic_DestroyCCBs(HostAdapter); + BusLogic_ReleaseResources(HostAdapter); + BusLogic_UnregisterHostAdapter(HostAdapter); + scsi_host_put(Host); + } else { + BusLogic_InitializeHostStructure(HostAdapter, Host); + scsi_add_host(Host, NULL); + scsi_scan_host(Host); + BusLogicHostAdapterCount++; + } + } else { + /* + An error occurred during Host Adapter Configuration Querying, Host + Adapter Configuration, Resource Acquisition, CCB Creation, Host + Adapter Initialization, or Target Device Inquiry, so remove Host + Adapter from the list of registered BusLogic Host Adapters, destroy + the CCBs, Release the System Resources, and Unregister the SCSI + Host. + */ + BusLogic_DestroyCCBs(HostAdapter); + BusLogic_ReleaseResources(HostAdapter); + BusLogic_UnregisterHostAdapter(HostAdapter); + scsi_host_put(Host); + } + } + kfree(PrototypeHostAdapter); + kfree(BusLogic_ProbeInfoList); + BusLogic_ProbeInfoList = NULL; + return BusLogicHostAdapterCount; } @@ -2825,29 +2360,28 @@ static int __exit BusLogic_ReleaseHostAdapter(struct Scsi_Host *Host) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Host->hostdata; - /* - FlashPoint Host Adapters must first be released by the FlashPoint - SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); - /* - Destroy the CCBs and release any system resources acquired to - support Host Adapter. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - /* - Release usage of the I/O Address range. - */ - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - /* - Remove Host Adapter from the list of registered BusLogic Host Adapters. - */ - BusLogic_UnregisterHostAdapter(HostAdapter); - return 0; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; + /* + FlashPoint Host Adapters must first be released by the FlashPoint + SCCB Manager. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); + /* + Destroy the CCBs and release any system resources acquired to + support Host Adapter. + */ + BusLogic_DestroyCCBs(HostAdapter); + BusLogic_ReleaseResources(HostAdapter); + /* + Release usage of the I/O Address range. + */ + release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + /* + Remove Host Adapter from the list of registered BusLogic Host Adapters. + */ + BusLogic_UnregisterHostAdapter(HostAdapter); + return 0; } @@ -2857,20 +2391,17 @@ static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *CCB) { - struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; - CCB->Status = BusLogic_CCB_Completed; - CCB->Next = NULL; - if (HostAdapter->FirstCompletedCCB == NULL) - { - HostAdapter->FirstCompletedCCB = CCB; - HostAdapter->LastCompletedCCB = CCB; - } - else - { - HostAdapter->LastCompletedCCB->Next = CCB; - HostAdapter->LastCompletedCCB = CCB; - } - HostAdapter->ActiveCommands[CCB->TargetID]--; + struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; + CCB->Status = BusLogic_CCB_Completed; + CCB->Next = NULL; + if (HostAdapter->FirstCompletedCCB == NULL) { + HostAdapter->FirstCompletedCCB = CCB; + HostAdapter->LastCompletedCCB = CCB; + } else { + HostAdapter->LastCompletedCCB->Next = CCB; + HostAdapter->LastCompletedCCB = CCB; + } + HostAdapter->ActiveCommands[CCB->TargetID]--; } @@ -2879,57 +2410,50 @@ the Host Adapter Status and Target Device Status. */ -static int BusLogic_ComputeResultCode(struct BusLogic_HostAdapter *HostAdapter, - enum BusLogic_HostAdapterStatus - HostAdapterStatus, - enum BusLogic_TargetDeviceStatus - TargetDeviceStatus) -{ - int HostStatus; - switch (HostAdapterStatus) - { - case BusLogic_CommandCompletedNormally: - case BusLogic_LinkedCommandCompleted: - case BusLogic_LinkedCommandCompletedWithFlag: - HostStatus = DID_OK; - break; - case BusLogic_SCSISelectionTimeout: - HostStatus = DID_TIME_OUT; - break; - case BusLogic_InvalidOutgoingMailboxActionCode: - case BusLogic_InvalidCommandOperationCode: - case BusLogic_InvalidCommandParameter: - BusLogic_Warning("BusLogic Driver Protocol Error 0x%02X\n", - HostAdapter, HostAdapterStatus); - case BusLogic_DataUnderRun: - case BusLogic_DataOverRun: - case BusLogic_UnexpectedBusFree: - case BusLogic_LinkedCCBhasInvalidLUN: - case BusLogic_AutoRequestSenseFailed: - case BusLogic_TaggedQueuingMessageRejected: - case BusLogic_UnsupportedMessageReceived: - case BusLogic_HostAdapterHardwareFailed: - case BusLogic_TargetDeviceReconnectedImproperly: - case BusLogic_AbortQueueGenerated: - case BusLogic_HostAdapterSoftwareError: - case BusLogic_HostAdapterHardwareTimeoutError: - case BusLogic_SCSIParityErrorDetected: - HostStatus = DID_ERROR; - break; - case BusLogic_InvalidBusPhaseRequested: - case BusLogic_TargetFailedResponseToATN: - case BusLogic_HostAdapterAssertedRST: - case BusLogic_OtherDeviceAssertedRST: - case BusLogic_HostAdapterAssertedBusDeviceReset: - HostStatus = DID_RESET; - break; - default: - BusLogic_Warning("Unknown Host Adapter Status 0x%02X\n", - HostAdapter, HostAdapterStatus); - HostStatus = DID_ERROR; - break; - } - return (HostStatus << 16) | TargetDeviceStatus; +static int BusLogic_ComputeResultCode(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_HostAdapterStatus HostAdapterStatus, enum BusLogic_TargetDeviceStatus TargetDeviceStatus) +{ + int HostStatus; + switch (HostAdapterStatus) { + case BusLogic_CommandCompletedNormally: + case BusLogic_LinkedCommandCompleted: + case BusLogic_LinkedCommandCompletedWithFlag: + HostStatus = DID_OK; + break; + case BusLogic_SCSISelectionTimeout: + HostStatus = DID_TIME_OUT; + break; + case BusLogic_InvalidOutgoingMailboxActionCode: + case BusLogic_InvalidCommandOperationCode: + case BusLogic_InvalidCommandParameter: + BusLogic_Warning("BusLogic Driver Protocol Error 0x%02X\n", HostAdapter, HostAdapterStatus); + case BusLogic_DataUnderRun: + case BusLogic_DataOverRun: + case BusLogic_UnexpectedBusFree: + case BusLogic_LinkedCCBhasInvalidLUN: + case BusLogic_AutoRequestSenseFailed: + case BusLogic_TaggedQueuingMessageRejected: + case BusLogic_UnsupportedMessageReceived: + case BusLogic_HostAdapterHardwareFailed: + case BusLogic_TargetDeviceReconnectedImproperly: + case BusLogic_AbortQueueGenerated: + case BusLogic_HostAdapterSoftwareError: + case BusLogic_HostAdapterHardwareTimeoutError: + case BusLogic_SCSIParityErrorDetected: + HostStatus = DID_ERROR; + break; + case BusLogic_InvalidBusPhaseRequested: + case BusLogic_TargetFailedResponseToATN: + case BusLogic_HostAdapterAssertedRST: + case BusLogic_OtherDeviceAssertedRST: + case BusLogic_HostAdapterAssertedBusDeviceReset: + HostStatus = DID_RESET; + break; + default: + BusLogic_Warning("Unknown Host Adapter Status 0x%02X\n", HostAdapter, HostAdapterStatus); + HostStatus = DID_ERROR; + break; + } + return (HostStatus << 16) | TargetDeviceStatus; } @@ -2940,62 +2464,51 @@ static void BusLogic_ScanIncomingMailboxes(struct BusLogic_HostAdapter *HostAdapter) { - /* - Scan through the Incoming Mailboxes in Strict Round Robin fashion, saving - any completed CCBs for further processing. It is essential that for each - CCB and SCSI Command issued, command completion processing is performed - exactly once. Therefore, only Incoming Mailboxes with completion code - Command Completed Without Error, Command Completed With Error, or Command - Aborted At Host Request are saved for completion processing. When an - Incoming Mailbox has a completion code of Aborted Command Not Found, the - CCB had already completed or been aborted before the current Abort request - was processed, and so completion processing has already occurred and no - further action should be taken. - */ - struct BusLogic_IncomingMailbox *NextIncomingMailbox = - HostAdapter->NextIncomingMailbox; - enum BusLogic_CompletionCode CompletionCode; - while ((CompletionCode = NextIncomingMailbox->CompletionCode) != - BusLogic_IncomingMailboxFree) - { - /* - We are only allowed to do this because we limit our architectures we - run on to machines where bus_to_virt() actually works. There *needs* - to be a dma_addr_to_virt() in the new PCI DMA mapping interface to - replace bus_to_virt() or else this code is going to become very - innefficient. - */ - struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) - Bus_to_Virtual(NextIncomingMailbox->CCB); - if (CompletionCode != BusLogic_AbortedCommandNotFound) - { - if (CCB->Status == BusLogic_CCB_Active || - CCB->Status == BusLogic_CCB_Reset) - { - /* - Save the Completion Code for this CCB and queue the CCB - for completion processing. - */ - CCB->CompletionCode = CompletionCode; - BusLogic_QueueCompletedCCB(CCB); - } - else - { - /* - If a CCB ever appears in an Incoming Mailbox and is not marked - as status Active or Reset, then there is most likely a bug in - the Host Adapter firmware. - */ - BusLogic_Warning("Illegal CCB #%ld status %d in " - "Incoming Mailbox\n", HostAdapter, - CCB->SerialNumber, CCB->Status); - } - } - NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree; - if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) - NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - } - HostAdapter->NextIncomingMailbox = NextIncomingMailbox; + /* + Scan through the Incoming Mailboxes in Strict Round Robin fashion, saving + any completed CCBs for further processing. It is essential that for each + CCB and SCSI Command issued, command completion processing is performed + exactly once. Therefore, only Incoming Mailboxes with completion code + Command Completed Without Error, Command Completed With Error, or Command + Aborted At Host Request are saved for completion processing. When an + Incoming Mailbox has a completion code of Aborted Command Not Found, the + CCB had already completed or been aborted before the current Abort request + was processed, and so completion processing has already occurred and no + further action should be taken. + */ + struct BusLogic_IncomingMailbox *NextIncomingMailbox = HostAdapter->NextIncomingMailbox; + enum BusLogic_CompletionCode CompletionCode; + while ((CompletionCode = NextIncomingMailbox->CompletionCode) != BusLogic_IncomingMailboxFree) { + /* + We are only allowed to do this because we limit our architectures we + run on to machines where bus_to_virt() actually works. There *needs* + to be a dma_addr_to_virt() in the new PCI DMA mapping interface to + replace bus_to_virt() or else this code is going to become very + innefficient. + */ + struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) Bus_to_Virtual(NextIncomingMailbox->CCB); + if (CompletionCode != BusLogic_AbortedCommandNotFound) { + if (CCB->Status == BusLogic_CCB_Active || CCB->Status == BusLogic_CCB_Reset) { + /* + Save the Completion Code for this CCB and queue the CCB + for completion processing. + */ + CCB->CompletionCode = CompletionCode; + BusLogic_QueueCompletedCCB(CCB); + } else { + /* + If a CCB ever appears in an Incoming Mailbox and is not marked + as status Active or Reset, then there is most likely a bug in + the Host Adapter firmware. + */ + BusLogic_Warning("Illegal CCB #%ld status %d in " "Incoming Mailbox\n", HostAdapter, CCB->SerialNumber, CCB->Status); + } + } + NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree; + if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) + NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; + } + HostAdapter->NextIncomingMailbox = NextIncomingMailbox; } @@ -3008,153 +2521,126 @@ static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapter) { - if (HostAdapter->ProcessCompletedCCBsActive) return; - HostAdapter->ProcessCompletedCCBsActive = true; - while (HostAdapter->FirstCompletedCCB != NULL) - { - struct BusLogic_CCB *CCB = HostAdapter->FirstCompletedCCB; - struct scsi_cmnd *Command = CCB->Command; - HostAdapter->FirstCompletedCCB = CCB->Next; - if (HostAdapter->FirstCompletedCCB == NULL) - HostAdapter->LastCompletedCCB = NULL; - /* - Process the Completed CCB. - */ - if (CCB->Opcode == BusLogic_BusDeviceReset) - { - int TargetID = CCB->TargetID; - BusLogic_Warning("Bus Device Reset CCB #%ld to Target " - "%d Completed\n", HostAdapter, - CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted); - HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; - HostAdapter->CommandsSinceReset[TargetID] = 0; - HostAdapter->LastResetCompleted[TargetID] = jiffies; - /* - Place CCB back on the Host Adapter's free list. - */ - BusLogic_DeallocateCCB(CCB); -#if 0 /* this needs to be redone different for new EH */ - /* - Bus Device Reset CCBs have the Command field non-NULL only when a - Bus Device Reset was requested for a Command that did not have a - currently active CCB in the Host Adapter (i.e., a Synchronous - Bus Device Reset), and hence would not have its Completion Routine - called otherwise. - */ - while (Command != NULL) - { - struct scsi_cmnd *NextCommand = Command->reset_chain; - Command->reset_chain = NULL; - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - Command = NextCommand; - } + if (HostAdapter->ProcessCompletedCCBsActive) + return; + HostAdapter->ProcessCompletedCCBsActive = true; + while (HostAdapter->FirstCompletedCCB != NULL) { + struct BusLogic_CCB *CCB = HostAdapter->FirstCompletedCCB; + struct scsi_cmnd *Command = CCB->Command; + HostAdapter->FirstCompletedCCB = CCB->Next; + if (HostAdapter->FirstCompletedCCB == NULL) + HostAdapter->LastCompletedCCB = NULL; + /* + Process the Completed CCB. + */ + if (CCB->Opcode == BusLogic_BusDeviceReset) { + int TargetID = CCB->TargetID; + BusLogic_Warning("Bus Device Reset CCB #%ld to Target " "%d Completed\n", HostAdapter, CCB->SerialNumber, TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted); + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; + HostAdapter->CommandsSinceReset[TargetID] = 0; + HostAdapter->LastResetCompleted[TargetID] = jiffies; + /* + Place CCB back on the Host Adapter's free list. + */ + BusLogic_DeallocateCCB(CCB); +#if 0 /* this needs to be redone different for new EH */ + /* + Bus Device Reset CCBs have the Command field non-NULL only when a + Bus Device Reset was requested for a Command that did not have a + currently active CCB in the Host Adapter (i.e., a Synchronous + Bus Device Reset), and hence would not have its Completion Routine + called otherwise. + */ + while (Command != NULL) { + struct scsi_cmnd *NextCommand = Command->reset_chain; + Command->reset_chain = NULL; + Command->result = DID_RESET << 16; + Command->scsi_done(Command); + Command = NextCommand; + } #endif - /* - Iterate over the CCBs for this Host Adapter performing completion - processing for any CCBs marked as Reset for this Target. - */ - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID) - { - Command = CCB->Command; - BusLogic_DeallocateCCB(CCB); - HostAdapter->ActiveCommands[TargetID]--; - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - } - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - } - else - { - /* - Translate the Completion Code, Host Adapter Status, and Target - Device Status into a SCSI Subsystem Result Code. - */ - switch (CCB->CompletionCode) - { - case BusLogic_IncomingMailboxFree: - case BusLogic_AbortedCommandNotFound: - case BusLogic_InvalidCCB: - BusLogic_Warning("CCB #%ld to Target %d Impossible State\n", - HostAdapter, CCB->SerialNumber, CCB->TargetID); - break; - case BusLogic_CommandCompletedWithoutError: - HostAdapter->TargetStatistics[CCB->TargetID] - .CommandsCompleted++; - HostAdapter->TargetFlags[CCB->TargetID] - .CommandSuccessfulFlag = true; - Command->result = DID_OK << 16; - break; - case BusLogic_CommandAbortedAtHostRequest: - BusLogic_Warning("CCB #%ld to Target %d Aborted\n", - HostAdapter, CCB->SerialNumber, CCB->TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[CCB->TargetID] - .CommandAbortsCompleted); - Command->result = DID_ABORT << 16; - break; - case BusLogic_CommandCompletedWithError: - Command->result = - BusLogic_ComputeResultCode(HostAdapter, - CCB->HostAdapterStatus, - CCB->TargetDeviceStatus); - if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) - { - HostAdapter->TargetStatistics[CCB->TargetID] - .CommandsCompleted++; - if (BusLogic_GlobalOptions.TraceErrors) - { - int i; - BusLogic_Notice("CCB #%ld Target %d: Result %X Host " - "Adapter Status %02X " - "Target Status %02X\n", - HostAdapter, CCB->SerialNumber, - CCB->TargetID, Command->result, - CCB->HostAdapterStatus, - CCB->TargetDeviceStatus); - BusLogic_Notice("CDB ", HostAdapter); - for (i = 0; i < CCB->CDB_Length; i++) - BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]); - BusLogic_Notice("\n", HostAdapter); - BusLogic_Notice("Sense ", HostAdapter); - for (i = 0; i < CCB->SenseDataLength; i++) - BusLogic_Notice(" %02X", HostAdapter, - Command->sense_buffer[i]); - BusLogic_Notice("\n", HostAdapter); - } - } - break; - } - /* - When an INQUIRY command completes normally, save the - CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit - Wide Data Transfers Supported) bits. - */ - if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && - CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) - { - struct BusLogic_TargetFlags *TargetFlags = - &HostAdapter->TargetFlags[CCB->TargetID]; - struct SCSI_Inquiry *InquiryResult = - (struct SCSI_Inquiry *) Command->request_buffer; - TargetFlags->TargetExists = true; - TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue; - TargetFlags->WideTransfersSupported = InquiryResult->WBus16; - } - /* - Place CCB back on the Host Adapter's free list. - */ - BusLogic_DeallocateCCB(CCB); - /* - Call the SCSI Command Completion Routine. - */ - Command->scsi_done(Command); + /* + Iterate over the CCBs for this Host Adapter performing completion + processing for any CCBs marked as Reset for this Target. + */ + for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) + if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID) { + Command = CCB->Command; + BusLogic_DeallocateCCB(CCB); + HostAdapter->ActiveCommands[TargetID]--; + Command->result = DID_RESET << 16; + Command->scsi_done(Command); + } + HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; + } else { + /* + Translate the Completion Code, Host Adapter Status, and Target + Device Status into a SCSI Subsystem Result Code. + */ + switch (CCB->CompletionCode) { + case BusLogic_IncomingMailboxFree: + case BusLogic_AbortedCommandNotFound: + case BusLogic_InvalidCCB: + BusLogic_Warning("CCB #%ld to Target %d Impossible State\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); + break; + case BusLogic_CommandCompletedWithoutError: + HostAdapter->TargetStatistics[CCB->TargetID] + .CommandsCompleted++; + HostAdapter->TargetFlags[CCB->TargetID] + .CommandSuccessfulFlag = true; + Command->result = DID_OK << 16; + break; + case BusLogic_CommandAbortedAtHostRequest: + BusLogic_Warning("CCB #%ld to Target %d Aborted\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[CCB->TargetID] + .CommandAbortsCompleted); + Command->result = DID_ABORT << 16; + break; + case BusLogic_CommandCompletedWithError: + Command->result = BusLogic_ComputeResultCode(HostAdapter, CCB->HostAdapterStatus, CCB->TargetDeviceStatus); + if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) { + HostAdapter->TargetStatistics[CCB->TargetID] + .CommandsCompleted++; + if (BusLogic_GlobalOptions.TraceErrors) { + int i; + BusLogic_Notice("CCB #%ld Target %d: Result %X Host " + "Adapter Status %02X " "Target Status %02X\n", HostAdapter, CCB->SerialNumber, CCB->TargetID, Command->result, CCB->HostAdapterStatus, CCB->TargetDeviceStatus); + BusLogic_Notice("CDB ", HostAdapter); + for (i = 0; i < CCB->CDB_Length; i++) + BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]); + BusLogic_Notice("\n", HostAdapter); + BusLogic_Notice("Sense ", HostAdapter); + for (i = 0; i < CCB->SenseDataLength; i++) + BusLogic_Notice(" %02X", HostAdapter, Command->sense_buffer[i]); + BusLogic_Notice("\n", HostAdapter); + } + } + break; + } + /* + When an INQUIRY command completes normally, save the + CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit + Wide Data Transfers Supported) bits. + */ + if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[CCB->TargetID]; + struct SCSI_Inquiry *InquiryResult = (struct SCSI_Inquiry *) Command->request_buffer; + TargetFlags->TargetExists = true; + TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue; + TargetFlags->WideTransfersSupported = InquiryResult->WBus16; + } + /* + Place CCB back on the Host Adapter's free list. + */ + BusLogic_DeallocateCCB(CCB); + /* + Call the SCSI Command Completion Routine. + */ + Command->scsi_done(Command); + } } - } - HostAdapter->ProcessCompletedCCBsActive = false; + HostAdapter->ProcessCompletedCCBsActive = false; } @@ -3163,97 +2649,83 @@ Adapters. */ -static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) -{ - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) DeviceIdentifier; - unsigned long ProcessorFlags; - /* - Acquire exclusive access to Host Adapter. - */ - BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags); - /* - Handle Interrupts appropriately for each Host Adapter type. - */ - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - union BusLogic_InterruptRegister InterruptRegister; - /* - Read the Host Adapter Interrupt Register. - */ - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - if (InterruptRegister.ir.InterruptValid) - { - /* - Acknowledge the interrupt and reset the Host Adapter - Interrupt Register. - */ - BusLogic_InterruptReset(HostAdapter); - /* - Process valid External SCSI Bus Reset and Incoming Mailbox - Loaded Interrupts. Command Complete Interrupts are noted, - and Outgoing Mailbox Available Interrupts are ignored, as - they are never enabled. - */ - if (InterruptRegister.ir.ExternalBusReset) - HostAdapter->HostAdapterExternalReset = true; - else if (InterruptRegister.ir.IncomingMailboxLoaded) - BusLogic_ScanIncomingMailboxes(HostAdapter); - else if (InterruptRegister.ir.CommandComplete) - HostAdapter->HostAdapterCommandCompleted = true; - } - } - else - { - /* - Check if there is a pending interrupt for this Host Adapter. - */ - if (FlashPoint_InterruptPending(HostAdapter->CardHandle)) - switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) - { - case FlashPoint_NormalInterrupt: - break; - case FlashPoint_ExternalBusReset: - HostAdapter->HostAdapterExternalReset = true; - break; - case FlashPoint_InternalError: - BusLogic_Warning("Internal FlashPoint Error detected" - " - Resetting Host Adapter\n", HostAdapter); - HostAdapter->HostAdapterInternalError = true; - break; - } - } - /* - Process any completed CCBs. - */ - if (HostAdapter->FirstCompletedCCB != NULL) - BusLogic_ProcessCompletedCCBs(HostAdapter); - /* - Reset the Host Adapter if requested. - */ - if (HostAdapter->HostAdapterExternalReset) - { - BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", - HostAdapter, HostAdapter->FullModelName); - BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); - BusLogic_ResetHostAdapter(HostAdapter, false); - HostAdapter->HostAdapterExternalReset = false; - } - else if (HostAdapter->HostAdapterInternalError) - { - BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", - HostAdapter, HostAdapter->FullModelName); - BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors); - BusLogic_ResetHostAdapter(HostAdapter, true); - HostAdapter->HostAdapterInternalError = false; - } - /* - Release exclusive access to Host Adapter. - */ - BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags); - return IRQ_HANDLED; +static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier, struct pt_regs *InterruptRegisters) +{ + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) DeviceIdentifier; + unsigned long ProcessorFlags; + /* + Acquire exclusive access to Host Adapter. + */ + BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags); + /* + Handle Interrupts appropriately for each Host Adapter type. + */ + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + union BusLogic_InterruptRegister InterruptRegister; + /* + Read the Host Adapter Interrupt Register. + */ + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + if (InterruptRegister.ir.InterruptValid) { + /* + Acknowledge the interrupt and reset the Host Adapter + Interrupt Register. + */ + BusLogic_InterruptReset(HostAdapter); + /* + Process valid External SCSI Bus Reset and Incoming Mailbox + Loaded Interrupts. Command Complete Interrupts are noted, + and Outgoing Mailbox Available Interrupts are ignored, as + they are never enabled. + */ + if (InterruptRegister.ir.ExternalBusReset) + HostAdapter->HostAdapterExternalReset = true; + else if (InterruptRegister.ir.IncomingMailboxLoaded) + BusLogic_ScanIncomingMailboxes(HostAdapter); + else if (InterruptRegister.ir.CommandComplete) + HostAdapter->HostAdapterCommandCompleted = true; + } + } else { + /* + Check if there is a pending interrupt for this Host Adapter. + */ + if (FlashPoint_InterruptPending(HostAdapter->CardHandle)) + switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) { + case FlashPoint_NormalInterrupt: + break; + case FlashPoint_ExternalBusReset: + HostAdapter->HostAdapterExternalReset = true; + break; + case FlashPoint_InternalError: + BusLogic_Warning("Internal FlashPoint Error detected" " - Resetting Host Adapter\n", HostAdapter); + HostAdapter->HostAdapterInternalError = true; + break; + } + } + /* + Process any completed CCBs. + */ + if (HostAdapter->FirstCompletedCCB != NULL) + BusLogic_ProcessCompletedCCBs(HostAdapter); + /* + Reset the Host Adapter if requested. + */ + if (HostAdapter->HostAdapterExternalReset) { + BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", HostAdapter, HostAdapter->FullModelName); + BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); + BusLogic_ResetHostAdapter(HostAdapter, false); + HostAdapter->HostAdapterExternalReset = false; + } else if (HostAdapter->HostAdapterInternalError) { + BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", HostAdapter, HostAdapter->FullModelName); + BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors); + BusLogic_ResetHostAdapter(HostAdapter, true); + HostAdapter->HostAdapterInternalError = false; + } + /* + Release exclusive access to Host Adapter. + */ + BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags); + return IRQ_HANDLED; } @@ -3264,43 +2736,38 @@ */ static boolean BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter - *HostAdapter, - enum BusLogic_ActionCode ActionCode, - struct BusLogic_CCB *CCB) -{ - struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; - NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox; - if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree) - { - CCB->Status = BusLogic_CCB_Active; - /* - The CCB field must be written before the Action Code field since - the Host Adapter is operating asynchronously and the locking code - does not protect against simultaneous access by the Host Adapter. - */ - NextOutgoingMailbox->CCB = CCB->DMA_Handle; - NextOutgoingMailbox->ActionCode = ActionCode; - BusLogic_StartMailboxCommand(HostAdapter); - if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) - NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox; - if (ActionCode == BusLogic_MailboxStartCommand) - { - HostAdapter->ActiveCommands[CCB->TargetID]++; - if (CCB->Opcode != BusLogic_BusDeviceReset) - HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++; - } - return true; - } - return false; + *HostAdapter, enum BusLogic_ActionCode ActionCode, struct BusLogic_CCB *CCB) +{ + struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; + NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox; + if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree) { + CCB->Status = BusLogic_CCB_Active; + /* + The CCB field must be written before the Action Code field since + the Host Adapter is operating asynchronously and the locking code + does not protect against simultaneous access by the Host Adapter. + */ + NextOutgoingMailbox->CCB = CCB->DMA_Handle; + NextOutgoingMailbox->ActionCode = ActionCode; + BusLogic_StartMailboxCommand(HostAdapter); + if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) + NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; + HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox; + if (ActionCode == BusLogic_MailboxStartCommand) { + HostAdapter->ActiveCommands[CCB->TargetID]++; + if (CCB->Opcode != BusLogic_BusDeviceReset) + HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++; + } + return true; + } + return false; } /* Error Handling (EH) support */ -static int BusLogic_host_reset(Scsi_Cmnd *SCpnt) +static int BusLogic_host_reset(Scsi_Cmnd * SCpnt) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) SCpnt->device->host->hostdata; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) SCpnt->device->host->hostdata; unsigned int id = SCpnt->device->id; struct BusLogic_TargetStatistics *stats = &HostAdapter->TargetStatistics[id]; @@ -3314,237 +2781,190 @@ Outgoing Mailbox for execution by the associated Host Adapter. */ -static int BusLogic_QueueCommand(struct scsi_cmnd *Command, - void (*CompletionRoutine)(struct scsi_cmnd *)) +static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *)) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Command->device->host->hostdata; - struct BusLogic_TargetFlags *TargetFlags = - &HostAdapter->TargetFlags[Command->device->id]; - struct BusLogic_TargetStatistics *TargetStatistics = - HostAdapter->TargetStatistics; - unsigned char *CDB = Command->cmnd; - int CDB_Length = Command->cmd_len; - int TargetID = Command->device->id; - int LogicalUnit = Command->device->lun; - void *BufferPointer = Command->request_buffer; - int BufferLength = Command->request_bufflen; - int SegmentCount = Command->use_sg; - struct BusLogic_CCB *CCB; - /* - SCSI REQUEST_SENSE commands will be executed automatically by the Host - Adapter for any errors, so they should not be executed explicitly unless - the Sense Data is zero indicating that no error occurred. - */ - if (CDB[0] == REQUEST_SENSE && Command->sense_buffer[0] != 0) - { - Command->result = DID_OK << 16; - CompletionRoutine(Command); - return 0; - } - /* - Allocate a CCB from the Host Adapter's free list. In the unlikely event - that there are none available and memory allocation fails, wait 1 second - and try again. If that fails, the Host Adapter is probably hung so signal - an error as a Host Adapter Hard Reset should be initiated soon. - */ - CCB = BusLogic_AllocateCCB(HostAdapter); - if (CCB == NULL) - { - BusLogic_ReleaseHostAdapterLock(HostAdapter); - BusLogic_Delay(1); - BusLogic_AcquireHostAdapterLock(HostAdapter); - CCB = BusLogic_AllocateCCB(HostAdapter); - if (CCB == NULL) - { - Command->result = DID_ERROR << 16; - CompletionRoutine(Command); - return 0; - } - } - /* - Initialize the fields in the BusLogic Command Control Block (CCB). - */ - if (SegmentCount == 0 && BufferLength != 0) - { - CCB->Opcode = BusLogic_InitiatorCCB; - CCB->DataLength = BufferLength; - CCB->DataPointer = - pci_map_single(HostAdapter->PCI_Device, BufferPointer, BufferLength, - scsi_to_pci_dma_dir(Command->sc_data_direction)); - } - else if (SegmentCount != 0) - { - struct scatterlist *ScatterList = (struct scatterlist *) BufferPointer; - int Segment, Count; - - Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount, - scsi_to_pci_dma_dir(Command->sc_data_direction)); - CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; - CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment); - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - CCB->DataPointer = (unsigned int)CCB->DMA_Handle + - ((unsigned long)&CCB->ScatterGatherList - - (unsigned long)CCB); - else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); - for (Segment = 0; Segment < Count; Segment++) - { - CCB->ScatterGatherList[Segment].SegmentByteCount = - sg_dma_len(ScatterList+Segment); - CCB->ScatterGatherList[Segment].SegmentDataPointer = - sg_dma_address(ScatterList+Segment); - } - } - else - { - CCB->Opcode = BusLogic_InitiatorCCB; - CCB->DataLength = BufferLength; - CCB->DataPointer = 0; - } - switch (CDB[0]) - { - case READ_6: - case READ_10: - CCB->DataDirection = BusLogic_DataInLengthChecked; - TargetStatistics[TargetID].ReadCommands++; - BusLogic_IncrementByteCounter( - &TargetStatistics[TargetID].TotalBytesRead, BufferLength); - BusLogic_IncrementSizeBucket( - TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength); - break; - case WRITE_6: - case WRITE_10: - CCB->DataDirection = BusLogic_DataOutLengthChecked; - TargetStatistics[TargetID].WriteCommands++; - BusLogic_IncrementByteCounter( - &TargetStatistics[TargetID].TotalBytesWritten, BufferLength); - BusLogic_IncrementSizeBucket( - TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength); - break; - default: - CCB->DataDirection = BusLogic_UncheckedDataTransfer; - break; - } - CCB->CDB_Length = CDB_Length; - CCB->HostAdapterStatus = 0; - CCB->TargetDeviceStatus = 0; - CCB->TargetID = TargetID; - CCB->LogicalUnit = LogicalUnit; - CCB->TagEnable = false; - CCB->LegacyTagEnable = false; - /* - BusLogic recommends that after a Reset the first couple of commands that - are sent to a Target Device be sent in a non Tagged Queue fashion so that - the Host Adapter and Target Device can establish Synchronous and Wide - Transfer before Queue Tag messages can interfere with the Synchronous and - Wide Negotiation messages. By waiting to enable Tagged Queuing until after - the first BusLogic_MaxTaggedQueueDepth commands have been queued, it is - assured that after a Reset any pending commands are requeued before Tagged - Queuing is enabled and that the Tagged Queuing message will not occur while - the partition table is being printed. In addition, some devices do not - properly handle the transition from non-tagged to tagged commands, so it is - necessary to wait until there are no pending commands for a target device - before queuing tagged commands. - */ - if (HostAdapter->CommandsSinceReset[TargetID]++ >= - BusLogic_MaxTaggedQueueDepth && - !TargetFlags->TaggedQueuingActive && - HostAdapter->ActiveCommands[TargetID] == 0 && - TargetFlags->TaggedQueuingSupported && - (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) - { - TargetFlags->TaggedQueuingActive = true; - BusLogic_Notice("Tagged Queuing now active for Target %d\n", - HostAdapter, TargetID); - } - if (TargetFlags->TaggedQueuingActive) - { - enum BusLogic_QueueTag QueueTag = BusLogic_SimpleQueueTag; - /* - When using Tagged Queuing with Simple Queue Tags, it appears that disk - drive controllers do not guarantee that a queued command will not - remain in a disconnected state indefinitely if commands that read or - write nearer the head position continue to arrive without interruption. - Therefore, for each Target Device this driver keeps track of the last - time either the queue was empty or an Ordered Queue Tag was issued. If - more than 4 seconds (one fifth of the 20 second disk timeout) have - elapsed since this last sequence point, this command will be issued - with an Ordered Queue Tag rather than a Simple Queue Tag, which forces - the Target Device to complete all previously queued commands before - this command may be executed. - */ - if (HostAdapter->ActiveCommands[TargetID] == 0) - HostAdapter->LastSequencePoint[TargetID] = jiffies; - else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4*HZ) - { - HostAdapter->LastSequencePoint[TargetID] = jiffies; - QueueTag = BusLogic_OrderedQueueTag; - } - if (HostAdapter->ExtendedLUNSupport) - { - CCB->TagEnable = true; - CCB->QueueTag = QueueTag; - } - else - { - CCB->LegacyTagEnable = true; - CCB->LegacyQueueTag = QueueTag; - } - } - memcpy(CCB->CDB, CDB, CDB_Length); - CCB->SenseDataLength = sizeof(Command->sense_buffer); - CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, - Command->sense_buffer, - CCB->SenseDataLength, - PCI_DMA_FROMDEVICE); - CCB->Command = Command; - Command->scsi_done = CompletionRoutine; - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - /* - Place the CCB in an Outgoing Mailbox. The higher levels of the SCSI - Subsystem should not attempt to queue more commands than can be placed - in Outgoing Mailboxes, so there should always be one free. In the - unlikely event that there are none available, wait 1 second and try - again. If that fails, the Host Adapter is probably hung so signal an - error as a Host Adapter Hard Reset should be initiated soon. - */ - if (!BusLogic_WriteOutgoingMailbox( - HostAdapter, BusLogic_MailboxStartCommand, CCB)) - { - BusLogic_ReleaseHostAdapterLock(HostAdapter); - BusLogic_Warning("Unable to write Outgoing Mailbox - " - "Pausing for 1 second\n", HostAdapter); - BusLogic_Delay(1); - BusLogic_AcquireHostAdapterLock(HostAdapter); - if (!BusLogic_WriteOutgoingMailbox( - HostAdapter, BusLogic_MailboxStartCommand, CCB)) - { - BusLogic_Warning("Still unable to write Outgoing Mailbox - " - "Host Adapter Dead?\n", HostAdapter); - BusLogic_DeallocateCCB(CCB); - Command->result = DID_ERROR << 16; - Command->scsi_done(Command); - } - } - } - else - { - /* - Call the FlashPoint SCCB Manager to start execution of the CCB. - */ - CCB->Status = BusLogic_CCB_Active; - HostAdapter->ActiveCommands[TargetID]++; - TargetStatistics[TargetID].CommandsAttempted++; - FlashPoint_StartCCB(HostAdapter->CardHandle, CCB); - /* - The Command may have already completed and BusLogic_QueueCompletedCCB - been called, or it may still be pending. - */ - if (CCB->Status == BusLogic_CCB_Completed) - BusLogic_ProcessCompletedCCBs(HostAdapter); - } - return 0; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata; + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[Command->device->id]; + struct BusLogic_TargetStatistics *TargetStatistics = HostAdapter->TargetStatistics; + unsigned char *CDB = Command->cmnd; + int CDB_Length = Command->cmd_len; + int TargetID = Command->device->id; + int LogicalUnit = Command->device->lun; + void *BufferPointer = Command->request_buffer; + int BufferLength = Command->request_bufflen; + int SegmentCount = Command->use_sg; + struct BusLogic_CCB *CCB; + /* + SCSI REQUEST_SENSE commands will be executed automatically by the Host + Adapter for any errors, so they should not be executed explicitly unless + the Sense Data is zero indicating that no error occurred. + */ + if (CDB[0] == REQUEST_SENSE && Command->sense_buffer[0] != 0) { + Command->result = DID_OK << 16; + CompletionRoutine(Command); + return 0; + } + /* + Allocate a CCB from the Host Adapter's free list. In the unlikely event + that there are none available and memory allocation fails, wait 1 second + and try again. If that fails, the Host Adapter is probably hung so signal + an error as a Host Adapter Hard Reset should be initiated soon. + */ + CCB = BusLogic_AllocateCCB(HostAdapter); + if (CCB == NULL) { + BusLogic_ReleaseHostAdapterLock(HostAdapter); + BusLogic_Delay(1); + BusLogic_AcquireHostAdapterLock(HostAdapter); + CCB = BusLogic_AllocateCCB(HostAdapter); + if (CCB == NULL) { + Command->result = DID_ERROR << 16; + CompletionRoutine(Command); + return 0; + } + } + /* + Initialize the fields in the BusLogic Command Control Block (CCB). + */ + if (SegmentCount == 0 && BufferLength != 0) { + CCB->Opcode = BusLogic_InitiatorCCB; + CCB->DataLength = BufferLength; + CCB->DataPointer = pci_map_single(HostAdapter->PCI_Device, BufferPointer, BufferLength, scsi_to_pci_dma_dir(Command->sc_data_direction)); + } else if (SegmentCount != 0) { + struct scatterlist *ScatterList = (struct scatterlist *) BufferPointer; + int Segment, Count; + + Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount, scsi_to_pci_dma_dir(Command->sc_data_direction)); + CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; + CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment); + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) + CCB->DataPointer = (unsigned int) CCB->DMA_Handle + ((unsigned long) &CCB->ScatterGatherList - (unsigned long) CCB); + else + CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); + for (Segment = 0; Segment < Count; Segment++) { + CCB->ScatterGatherList[Segment].SegmentByteCount = sg_dma_len(ScatterList + Segment); + CCB->ScatterGatherList[Segment].SegmentDataPointer = sg_dma_address(ScatterList + Segment); + } + } else { + CCB->Opcode = BusLogic_InitiatorCCB; + CCB->DataLength = BufferLength; + CCB->DataPointer = 0; + } + switch (CDB[0]) { + case READ_6: + case READ_10: + CCB->DataDirection = BusLogic_DataInLengthChecked; + TargetStatistics[TargetID].ReadCommands++; + BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesRead, BufferLength); + BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength); + break; + case WRITE_6: + case WRITE_10: + CCB->DataDirection = BusLogic_DataOutLengthChecked; + TargetStatistics[TargetID].WriteCommands++; + BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesWritten, BufferLength); + BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength); + break; + default: + CCB->DataDirection = BusLogic_UncheckedDataTransfer; + break; + } + CCB->CDB_Length = CDB_Length; + CCB->HostAdapterStatus = 0; + CCB->TargetDeviceStatus = 0; + CCB->TargetID = TargetID; + CCB->LogicalUnit = LogicalUnit; + CCB->TagEnable = false; + CCB->LegacyTagEnable = false; + /* + BusLogic recommends that after a Reset the first couple of commands that + are sent to a Target Device be sent in a non Tagged Queue fashion so that + the Host Adapter and Target Device can establish Synchronous and Wide + Transfer before Queue Tag messages can interfere with the Synchronous and + Wide Negotiation messages. By waiting to enable Tagged Queuing until after + the first BusLogic_MaxTaggedQueueDepth commands have been queued, it is + assured that after a Reset any pending commands are requeued before Tagged + Queuing is enabled and that the Tagged Queuing message will not occur while + the partition table is being printed. In addition, some devices do not + properly handle the transition from non-tagged to tagged commands, so it is + necessary to wait until there are no pending commands for a target device + before queuing tagged commands. + */ + if (HostAdapter->CommandsSinceReset[TargetID]++ >= + BusLogic_MaxTaggedQueueDepth && !TargetFlags->TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] == 0 && TargetFlags->TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { + TargetFlags->TaggedQueuingActive = true; + BusLogic_Notice("Tagged Queuing now active for Target %d\n", HostAdapter, TargetID); + } + if (TargetFlags->TaggedQueuingActive) { + enum BusLogic_QueueTag QueueTag = BusLogic_SimpleQueueTag; + /* + When using Tagged Queuing with Simple Queue Tags, it appears that disk + drive controllers do not guarantee that a queued command will not + remain in a disconnected state indefinitely if commands that read or + write nearer the head position continue to arrive without interruption. + Therefore, for each Target Device this driver keeps track of the last + time either the queue was empty or an Ordered Queue Tag was issued. If + more than 4 seconds (one fifth of the 20 second disk timeout) have + elapsed since this last sequence point, this command will be issued + with an Ordered Queue Tag rather than a Simple Queue Tag, which forces + the Target Device to complete all previously queued commands before + this command may be executed. + */ + if (HostAdapter->ActiveCommands[TargetID] == 0) + HostAdapter->LastSequencePoint[TargetID] = jiffies; + else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4 * HZ) { + HostAdapter->LastSequencePoint[TargetID] = jiffies; + QueueTag = BusLogic_OrderedQueueTag; + } + if (HostAdapter->ExtendedLUNSupport) { + CCB->TagEnable = true; + CCB->QueueTag = QueueTag; + } else { + CCB->LegacyTagEnable = true; + CCB->LegacyQueueTag = QueueTag; + } + } + memcpy(CCB->CDB, CDB, CDB_Length); + CCB->SenseDataLength = sizeof(Command->sense_buffer); + CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE); + CCB->Command = Command; + Command->scsi_done = CompletionRoutine; + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + /* + Place the CCB in an Outgoing Mailbox. The higher levels of the SCSI + Subsystem should not attempt to queue more commands than can be placed + in Outgoing Mailboxes, so there should always be one free. In the + unlikely event that there are none available, wait 1 second and try + again. If that fails, the Host Adapter is probably hung so signal an + error as a Host Adapter Hard Reset should be initiated soon. + */ + if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) { + BusLogic_ReleaseHostAdapterLock(HostAdapter); + BusLogic_Warning("Unable to write Outgoing Mailbox - " "Pausing for 1 second\n", HostAdapter); + BusLogic_Delay(1); + BusLogic_AcquireHostAdapterLock(HostAdapter); + if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) { + BusLogic_Warning("Still unable to write Outgoing Mailbox - " "Host Adapter Dead?\n", HostAdapter); + BusLogic_DeallocateCCB(CCB); + Command->result = DID_ERROR << 16; + Command->scsi_done(Command); + } + } + } else { + /* + Call the FlashPoint SCCB Manager to start execution of the CCB. + */ + CCB->Status = BusLogic_CCB_Active; + HostAdapter->ActiveCommands[TargetID]++; + TargetStatistics[TargetID].CommandsAttempted++; + FlashPoint_StartCCB(HostAdapter->CardHandle, CCB); + /* + The Command may have already completed and BusLogic_QueueCompletedCCB + been called, or it may still be pending. + */ + if (CCB->Status == BusLogic_CCB_Completed) + BusLogic_ProcessCompletedCCBs(HostAdapter); + } + return 0; } @@ -3554,105 +2974,75 @@ static int BusLogic_AbortCommand(struct scsi_cmnd *Command) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Command->device->host->hostdata; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata; - int TargetID = Command->device->id; - struct BusLogic_CCB *CCB; - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); - /* - If this Command has already completed, then no Abort is necessary. - */ - if (Command->serial_number != Command->serial_number_at_timeout) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "Already Completed\n", HostAdapter, TargetID); - return SUCCESS; - } - /* - Attempt to find an Active CCB for this Command. If no Active CCB for this - Command is found, then no Abort is necessary. - */ - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Command == Command) break; - if (CCB == NULL) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "No CCB Found\n", HostAdapter, TargetID); - return SUCCESS; - } - else if (CCB->Status == BusLogic_CCB_Completed) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "CCB Completed\n", HostAdapter, TargetID); - return SUCCESS; - } - else if (CCB->Status == BusLogic_CCB_Reset) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "CCB Reset\n", HostAdapter, TargetID); - return SUCCESS; - } - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - /* - Attempt to Abort this CCB. MultiMaster Firmware versions prior to 5.xx - do not generate Abort Tag messages, but only generate the non-tagged - Abort message. Since non-tagged commands are not sent by the Host - Adapter until the queue of outstanding tagged commands has completed, - and the Abort message is treated as a non-tagged command, it is - effectively impossible to abort commands when Tagged Queuing is active. - Firmware version 5.xx does generate Abort Tag messages, so it is - possible to abort commands when Tagged Queuing is active. - */ - if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && - HostAdapter->FirmwareVersion[0] < '5') - { - BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " - "Abort Tag Not Supported\n", - HostAdapter, CCB->SerialNumber, TargetID); - return FAILURE; - } - else if (BusLogic_WriteOutgoingMailbox( - HostAdapter, BusLogic_MailboxAbortCommand, CCB)) - { - BusLogic_Warning("Aborting CCB #%ld to Target %d\n", - HostAdapter, CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); - return SUCCESS; - } - else - { - BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " - "No Outgoing Mailboxes\n", - HostAdapter, CCB->SerialNumber, TargetID); - return FAILURE; - } - } - else - { - /* - Call the FlashPoint SCCB Manager to abort execution of the CCB. - */ - BusLogic_Warning("Aborting CCB #%ld to Target %d\n", - HostAdapter, CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); - FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB); - /* - The Abort may have already been completed and - BusLogic_QueueCompletedCCB been called, or it - may still be pending. - */ - if (CCB->Status == BusLogic_CCB_Completed) - { - BusLogic_ProcessCompletedCCBs(HostAdapter); - } - return SUCCESS; - } - return SUCCESS; + int TargetID = Command->device->id; + struct BusLogic_CCB *CCB; + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); + /* + If this Command has already completed, then no Abort is necessary. + */ + if (Command->serial_number != Command->serial_number_at_timeout) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "Already Completed\n", HostAdapter, TargetID); + return SUCCESS; + } + /* + Attempt to find an Active CCB for this Command. If no Active CCB for this + Command is found, then no Abort is necessary. + */ + for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) + if (CCB->Command == Command) + break; + if (CCB == NULL) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "No CCB Found\n", HostAdapter, TargetID); + return SUCCESS; + } else if (CCB->Status == BusLogic_CCB_Completed) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Completed\n", HostAdapter, TargetID); + return SUCCESS; + } else if (CCB->Status == BusLogic_CCB_Reset) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Reset\n", HostAdapter, TargetID); + return SUCCESS; + } + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + /* + Attempt to Abort this CCB. MultiMaster Firmware versions prior to 5.xx + do not generate Abort Tag messages, but only generate the non-tagged + Abort message. Since non-tagged commands are not sent by the Host + Adapter until the queue of outstanding tagged commands has completed, + and the Abort message is treated as a non-tagged command, it is + effectively impossible to abort commands when Tagged Queuing is active. + Firmware version 5.xx does generate Abort Tag messages, so it is + possible to abort commands when Tagged Queuing is active. + */ + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->FirmwareVersion[0] < '5') { + BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "Abort Tag Not Supported\n", HostAdapter, CCB->SerialNumber, TargetID); + return FAILURE; + } else if (BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxAbortCommand, CCB)) { + BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); + return SUCCESS; + } else { + BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "No Outgoing Mailboxes\n", HostAdapter, CCB->SerialNumber, TargetID); + return FAILURE; + } + } else { + /* + Call the FlashPoint SCCB Manager to abort execution of the CCB. + */ + BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); + FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB); + /* + The Abort may have already been completed and + BusLogic_QueueCompletedCCB been called, or it + may still be pending. + */ + if (CCB->Status == BusLogic_CCB_Completed) { + BusLogic_ProcessCompletedCCBs(HostAdapter); + } + return SUCCESS; + } + return SUCCESS; } /* @@ -3660,8 +3050,7 @@ currently executing SCSI Commands as having been Reset. */ -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, - boolean HardReset) +static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, boolean HardReset) { struct BusLogic_CCB *CCB; int TargetID; @@ -3670,10 +3059,8 @@ * Attempt to Reset and Reinitialize the Host Adapter. */ - if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && - BusLogic_InitializeHostAdapter(HostAdapter))) { - BusLogic_Error("Resetting %s Failed\n", HostAdapter, - HostAdapter->FullModelName); + if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && BusLogic_InitializeHostAdapter(HostAdapter))) { + BusLogic_Error("Resetting %s Failed\n", HostAdapter, HostAdapter->FullModelName); return FAILURE; } @@ -3721,98 +3108,70 @@ the BIOS, and a warning may be displayed. */ -static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_device *Device, - sector_t capacity, int *Parameters) +static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_device *Device, sector_t capacity, int *Parameters) { - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) sdev->host->hostdata; - struct BIOS_DiskParameters *DiskParameters = (struct BIOS_DiskParameters *) Parameters; - unsigned char *buf; - if (HostAdapter->ExtendedTranslationEnabled && - capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */) - { - if (capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */) - { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - } - else - { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - } - } - else - { - DiskParameters->Heads = 64; - DiskParameters->Sectors = 32; - } - DiskParameters->Cylinders = - (unsigned long)capacity / (DiskParameters->Heads * DiskParameters->Sectors); - buf = scsi_bios_ptable(Device); - if (buf == NULL) return 0; - /* - If the boot sector partition table flag is valid, search for a partition - table entry whose end_head matches one of the standard BusLogic geometry - translations (64/32, 128/32, or 255/63). - */ - if (*(unsigned short *) (buf+64) == 0xAA55) - { - struct partition *FirstPartitionEntry = (struct partition *) buf; - struct partition *PartitionEntry = FirstPartitionEntry; - int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; - unsigned char PartitionEntryEndHead=0, PartitionEntryEndSector=0; - for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) - { - PartitionEntryEndHead = PartitionEntry->end_head; - PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F; - if (PartitionEntryEndHead == 64-1) - { - DiskParameters->Heads = 64; - DiskParameters->Sectors = 32; - break; - } - else if (PartitionEntryEndHead == 128-1) - { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - break; - } - else if (PartitionEntryEndHead == 255-1) - { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - break; - } - PartitionEntry++; - } - if (PartitionNumber == 4) - { - PartitionEntryEndHead = FirstPartitionEntry->end_head; - PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F; - } - DiskParameters->Cylinders = - (unsigned long)capacity / (DiskParameters->Heads * DiskParameters->Sectors); - if (PartitionNumber < 4 && - PartitionEntryEndSector == DiskParameters->Sectors) - { - if (DiskParameters->Cylinders != SavedCylinders) - BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", - HostAdapter, - DiskParameters->Heads, DiskParameters->Sectors); - } - else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) - { - BusLogic_Warning("Warning: Partition Table appears to " - "have Geometry %d/%d which is\n", HostAdapter, - PartitionEntryEndHead + 1, - PartitionEntryEndSector); - BusLogic_Warning("not compatible with current BusLogic " - "Host Adapter Geometry %d/%d\n", HostAdapter, - DiskParameters->Heads, DiskParameters->Sectors); - } - } - kfree(buf); - return 0; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) sdev->host->hostdata; + struct BIOS_DiskParameters *DiskParameters = (struct BIOS_DiskParameters *) Parameters; + unsigned char *buf; + if (HostAdapter->ExtendedTranslationEnabled && capacity >= 2 * 1024 * 1024 /* 1 GB in 512 byte sectors */ ) { + if (capacity >= 4 * 1024 * 1024 /* 2 GB in 512 byte sectors */ ) { + DiskParameters->Heads = 255; + DiskParameters->Sectors = 63; + } else { + DiskParameters->Heads = 128; + DiskParameters->Sectors = 32; + } + } else { + DiskParameters->Heads = 64; + DiskParameters->Sectors = 32; + } + DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors); + buf = scsi_bios_ptable(Device); + if (buf == NULL) + return 0; + /* + If the boot sector partition table flag is valid, search for a partition + table entry whose end_head matches one of the standard BusLogic geometry + translations (64/32, 128/32, or 255/63). + */ + if (*(unsigned short *) (buf + 64) == 0xAA55) { + struct partition *FirstPartitionEntry = (struct partition *) buf; + struct partition *PartitionEntry = FirstPartitionEntry; + int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; + unsigned char PartitionEntryEndHead = 0, PartitionEntryEndSector = 0; + for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) { + PartitionEntryEndHead = PartitionEntry->end_head; + PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F; + if (PartitionEntryEndHead == 64 - 1) { + DiskParameters->Heads = 64; + DiskParameters->Sectors = 32; + break; + } else if (PartitionEntryEndHead == 128 - 1) { + DiskParameters->Heads = 128; + DiskParameters->Sectors = 32; + break; + } else if (PartitionEntryEndHead == 255 - 1) { + DiskParameters->Heads = 255; + DiskParameters->Sectors = 63; + break; + } + PartitionEntry++; + } + if (PartitionNumber == 4) { + PartitionEntryEndHead = FirstPartitionEntry->end_head; + PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F; + } + DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors); + if (PartitionNumber < 4 && PartitionEntryEndSector == DiskParameters->Sectors) { + if (DiskParameters->Cylinders != SavedCylinders) + BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); + } else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) { + BusLogic_Warning("Warning: Partition Table appears to " "have Geometry %d/%d which is\n", HostAdapter, PartitionEntryEndHead + 1, PartitionEntryEndSector); + BusLogic_Warning("not compatible with current BusLogic " "Host Adapter Geometry %d/%d\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); + } + } + kfree(buf); + return 0; } @@ -3820,178 +3179,124 @@ BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/. */ -static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, - char **StartPointer, off_t Offset, - int BytesAvailable, int WriteFlag) -{ - struct BusLogic_HostAdapter *HostAdapter; - struct BusLogic_TargetStatistics *TargetStatistics; - int TargetID, Length; - char *Buffer; - for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; - HostAdapter != NULL; - HostAdapter = HostAdapter->Next) - if (HostAdapter->HostNumber == shost->host_no) break; - if (HostAdapter == NULL) - { - BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n", - NULL, shost->host_no); - return 0; - } - TargetStatistics = HostAdapter->TargetStatistics; - if (WriteFlag) - { - HostAdapter->ExternalHostAdapterResets = 0; - HostAdapter->HostAdapterInternalErrors = 0; - memset(TargetStatistics, 0, - BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics)); - return 0; - } - Buffer = HostAdapter->MessageBuffer; - Length = HostAdapter->MessageBufferLength; - Length += sprintf(&Buffer[Length], "\n\ +static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, char **StartPointer, off_t Offset, int BytesAvailable, int WriteFlag) +{ + struct BusLogic_HostAdapter *HostAdapter; + struct BusLogic_TargetStatistics *TargetStatistics; + int TargetID, Length; + char *Buffer; + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) + if (HostAdapter->HostNumber == shost->host_no) + break; + if (HostAdapter == NULL) { + BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n", NULL, shost->host_no); + return 0; + } + TargetStatistics = HostAdapter->TargetStatistics; + if (WriteFlag) { + HostAdapter->ExternalHostAdapterResets = 0; + HostAdapter->HostAdapterInternalErrors = 0; + memset(TargetStatistics, 0, BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics)); + return 0; + } + Buffer = HostAdapter->MessageBuffer; + Length = HostAdapter->MessageBufferLength; + Length += sprintf(&Buffer[Length], "\n\ Current Driver Queue Depth: %d\n\ -Currently Allocated CCBs: %d\n", - HostAdapter->DriverQueueDepth, - HostAdapter->AllocatedCCBs); - Length += sprintf(&Buffer[Length], "\n\n\ +Currently Allocated CCBs: %d\n", HostAdapter->DriverQueueDepth, HostAdapter->AllocatedCCBs); + Length += sprintf(&Buffer[Length], "\n\n\ DATA TRANSFER STATISTICS\n\ \n\ Target Tagged Queuing Queue Depth Active Attempted Completed\n\ ====== ============== =========== ====== ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], " %2d %s", TargetID, - (TargetFlags->TaggedQueuingSupported - ? (TargetFlags->TaggedQueuingActive - ? " Active" - : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) - ? " Permitted" : " Disabled")) - : "Not Supported")); - Length += sprintf(&Buffer[Length], - " %3d %3u %9u %9u\n", - HostAdapter->QueueDepth[TargetID], - HostAdapter->ActiveCommands[TargetID], - TargetStatistics[TargetID].CommandsAttempted, - TargetStatistics[TargetID].CommandsCompleted); - } - Length += sprintf(&Buffer[Length], "\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += sprintf(&Buffer[Length], " %2d %s", TargetID, (TargetFlags->TaggedQueuingSupported ? (TargetFlags->TaggedQueuingActive ? " Active" : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) + ? " Permitted" : " Disabled")) + : "Not Supported")); + Length += sprintf(&Buffer[Length], + " %3d %3u %9u %9u\n", HostAdapter->QueueDepth[TargetID], HostAdapter->ActiveCommands[TargetID], TargetStatistics[TargetID].CommandsAttempted, TargetStatistics[TargetID].CommandsCompleted); + } + Length += sprintf(&Buffer[Length], "\n\ Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\ ====== ============= ============== =================== ===================\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, - TargetStatistics[TargetID].ReadCommands, - TargetStatistics[TargetID].WriteCommands); - if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u", - TargetStatistics[TargetID].TotalBytesRead.Billions, - TargetStatistics[TargetID].TotalBytesRead.Units); - else - Length += - sprintf(&Buffer[Length], " %9u", - TargetStatistics[TargetID].TotalBytesRead.Units); - if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u\n", - TargetStatistics[TargetID].TotalBytesWritten.Billions, - TargetStatistics[TargetID].TotalBytesWritten.Units); - else - Length += - sprintf(&Buffer[Length], " %9u\n", - TargetStatistics[TargetID].TotalBytesWritten.Units); - } - Length += sprintf(&Buffer[Length], "\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, TargetStatistics[TargetID].ReadCommands, TargetStatistics[TargetID].WriteCommands); + if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0) + Length += sprintf(&Buffer[Length], " %9u%09u", TargetStatistics[TargetID].TotalBytesRead.Billions, TargetStatistics[TargetID].TotalBytesRead.Units); + else + Length += sprintf(&Buffer[Length], " %9u", TargetStatistics[TargetID].TotalBytesRead.Units); + if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0) + Length += sprintf(&Buffer[Length], " %9u%09u\n", TargetStatistics[TargetID].TotalBytesWritten.Billions, TargetStatistics[TargetID].TotalBytesWritten.Units); + else + Length += sprintf(&Buffer[Length], " %9u\n", TargetStatistics[TargetID].TotalBytesWritten.Units); + } + Length += sprintf(&Buffer[Length], "\n\ Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ ====== ======= ========= ========= ========= ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].ReadCommandSizeBuckets[0], - TargetStatistics[TargetID].ReadCommandSizeBuckets[1], - TargetStatistics[TargetID].ReadCommandSizeBuckets[2], - TargetStatistics[TargetID].ReadCommandSizeBuckets[3], - TargetStatistics[TargetID].ReadCommandSizeBuckets[4]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].WriteCommandSizeBuckets[0], - TargetStatistics[TargetID].WriteCommandSizeBuckets[1], - TargetStatistics[TargetID].WriteCommandSizeBuckets[2], - TargetStatistics[TargetID].WriteCommandSizeBuckets[3], - TargetStatistics[TargetID].WriteCommandSizeBuckets[4]); - } - Length += sprintf(&Buffer[Length], "\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[0], + TargetStatistics[TargetID].ReadCommandSizeBuckets[1], TargetStatistics[TargetID].ReadCommandSizeBuckets[2], TargetStatistics[TargetID].ReadCommandSizeBuckets[3], TargetStatistics[TargetID].ReadCommandSizeBuckets[4]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[0], + TargetStatistics[TargetID].WriteCommandSizeBuckets[1], TargetStatistics[TargetID].WriteCommandSizeBuckets[2], TargetStatistics[TargetID].WriteCommandSizeBuckets[3], TargetStatistics[TargetID].WriteCommandSizeBuckets[4]); + } + Length += sprintf(&Buffer[Length], "\n\ Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ ====== ======= ========= ========= ========= ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].ReadCommandSizeBuckets[5], - TargetStatistics[TargetID].ReadCommandSizeBuckets[6], - TargetStatistics[TargetID].ReadCommandSizeBuckets[7], - TargetStatistics[TargetID].ReadCommandSizeBuckets[8], - TargetStatistics[TargetID].ReadCommandSizeBuckets[9]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].WriteCommandSizeBuckets[5], - TargetStatistics[TargetID].WriteCommandSizeBuckets[6], - TargetStatistics[TargetID].WriteCommandSizeBuckets[7], - TargetStatistics[TargetID].WriteCommandSizeBuckets[8], - TargetStatistics[TargetID].WriteCommandSizeBuckets[9]); - } - Length += sprintf(&Buffer[Length], "\n\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[5], + TargetStatistics[TargetID].ReadCommandSizeBuckets[6], TargetStatistics[TargetID].ReadCommandSizeBuckets[7], TargetStatistics[TargetID].ReadCommandSizeBuckets[8], TargetStatistics[TargetID].ReadCommandSizeBuckets[9]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[5], + TargetStatistics[TargetID].WriteCommandSizeBuckets[6], TargetStatistics[TargetID].WriteCommandSizeBuckets[7], TargetStatistics[TargetID].WriteCommandSizeBuckets[8], TargetStatistics[TargetID].WriteCommandSizeBuckets[9]); + } + Length += sprintf(&Buffer[Length], "\n\n\ ERROR RECOVERY STATISTICS\n\ \n\ Command Aborts Bus Device Resets Host Adapter Resets\n\ Target Requested Completed Requested Completed Requested Completed\n\ ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\ ====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], "\ - %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, - TargetStatistics[TargetID].CommandAbortsRequested, - TargetStatistics[TargetID].CommandAbortsAttempted, - TargetStatistics[TargetID].CommandAbortsCompleted, - TargetStatistics[TargetID].BusDeviceResetsRequested, - TargetStatistics[TargetID].BusDeviceResetsAttempted, - TargetStatistics[TargetID].BusDeviceResetsCompleted, - TargetStatistics[TargetID].HostAdapterResetsRequested, - TargetStatistics[TargetID].HostAdapterResetsAttempted, - TargetStatistics[TargetID].HostAdapterResetsCompleted); - } - Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", - HostAdapter->ExternalHostAdapterResets); - Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", - HostAdapter->HostAdapterInternalErrors); - if (Length >= BusLogic_MessageBufferSize) - BusLogic_Error("Message Buffer length %d exceeds size %d\n", - HostAdapter, Length, BusLogic_MessageBufferSize); - if ((Length -= Offset) <= 0) return 0; - if (Length >= BytesAvailable) Length = BytesAvailable; - memcpy(ProcBuffer, HostAdapter->MessageBuffer + Offset, Length); - *StartPointer = ProcBuffer; - return Length; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += sprintf(&Buffer[Length], "\ + %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, TargetStatistics[TargetID].CommandAbortsRequested, TargetStatistics[TargetID].CommandAbortsAttempted, TargetStatistics[TargetID].CommandAbortsCompleted, TargetStatistics[TargetID].BusDeviceResetsRequested, TargetStatistics[TargetID].BusDeviceResetsAttempted, TargetStatistics[TargetID].BusDeviceResetsCompleted, TargetStatistics[TargetID].HostAdapterResetsRequested, TargetStatistics[TargetID].HostAdapterResetsAttempted, TargetStatistics[TargetID].HostAdapterResetsCompleted); + } + Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets); + Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", HostAdapter->HostAdapterInternalErrors); + if (Length >= BusLogic_MessageBufferSize) + BusLogic_Error("Message Buffer length %d exceeds size %d\n", HostAdapter, Length, BusLogic_MessageBufferSize); + if ((Length -= Offset) <= 0) + return 0; + if (Length >= BytesAvailable) + Length = BytesAvailable; + memcpy(ProcBuffer, HostAdapter->MessageBuffer + Offset, Length); + *StartPointer = ProcBuffer; + return Length; } @@ -3999,52 +3304,39 @@ BusLogic_Message prints Driver Messages. */ -static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, - char *Format, - struct BusLogic_HostAdapter *HostAdapter, - ...) -{ - static char Buffer[BusLogic_LineBufferSize]; - static boolean BeginningOfLine = true; - va_list Arguments; - int Length = 0; - va_start(Arguments, HostAdapter); - Length = vsprintf(Buffer, Format, Arguments); - va_end(Arguments); - if (MessageLevel == BusLogic_AnnounceLevel) - { - static int AnnouncementLines = 0; - strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], - Buffer); - HostAdapter->MessageBufferLength += Length; - if (++AnnouncementLines <= 2) - printk("%sscsi: %s", BusLogic_MessageLevelMap[MessageLevel], Buffer); - } - else if (MessageLevel == BusLogic_InfoLevel) - { - strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], - Buffer); - HostAdapter->MessageBufferLength += Length; - if (BeginningOfLine) - { - if (Buffer[0] != '\n' || Length > 1) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); - } - else printk("%s", Buffer); - } - else - { - if (BeginningOfLine) - { - if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); - else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); - } - else printk("%s", Buffer); - } - BeginningOfLine = (Buffer[Length-1] == '\n'); +static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, char *Format, struct BusLogic_HostAdapter *HostAdapter, ...) +{ + static char Buffer[BusLogic_LineBufferSize]; + static boolean BeginningOfLine = true; + va_list Arguments; + int Length = 0; + va_start(Arguments, HostAdapter); + Length = vsprintf(Buffer, Format, Arguments); + va_end(Arguments); + if (MessageLevel == BusLogic_AnnounceLevel) { + static int AnnouncementLines = 0; + strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer); + HostAdapter->MessageBufferLength += Length; + if (++AnnouncementLines <= 2) + printk("%sscsi: %s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + } else if (MessageLevel == BusLogic_InfoLevel) { + strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer); + HostAdapter->MessageBufferLength += Length; + if (BeginningOfLine) { + if (Buffer[0] != '\n' || Length > 1) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer); + } else + printk("%s", Buffer); + } else { + if (BeginningOfLine) { + if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer); + else + printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + } else + printk("%s", Buffer); + } + BeginningOfLine = (Buffer[Length - 1] == '\n'); } @@ -4055,19 +3347,19 @@ static boolean __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword) { - char *Pointer = *StringPointer; - while (*Keyword != '\0') - { - char StringChar = *Pointer++; - char KeywordChar = *Keyword++; - if (StringChar >= 'A' && StringChar <= 'Z') - StringChar += 'a' - 'Z'; - if (KeywordChar >= 'A' && KeywordChar <= 'Z') - KeywordChar += 'a' - 'Z'; - if (StringChar != KeywordChar) return false; - } - *StringPointer = Pointer; - return true; + char *Pointer = *StringPointer; + while (*Keyword != '\0') { + char StringChar = *Pointer++; + char KeywordChar = *Keyword++; + if (StringChar >= 'A' && StringChar <= 'Z') + StringChar += 'a' - 'Z'; + if (KeywordChar >= 'A' && KeywordChar <= 'Z') + KeywordChar += 'a' - 'Z'; + if (StringChar != KeywordChar) + return false; + } + *StringPointer = Pointer; + return true; } @@ -4090,225 +3382,165 @@ static int __init BusLogic_ParseDriverOptions(char *OptionsString) { - while (true) - { - struct BusLogic_DriverOptions *DriverOptions = - &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++]; - int TargetID; - memset(DriverOptions, 0, sizeof(struct BusLogic_DriverOptions)); - while (*OptionsString != '\0' && *OptionsString != ';') - { - /* Probing Options. */ - if (BusLogic_ParseKeyword(&OptionsString, "IO:")) - { - unsigned long IO_Address = - simple_strtoul(OptionsString, &OptionsString, 0); - BusLogic_ProbeOptions.LimitedProbeISA = true; - switch (IO_Address) - { - case 0x330: - BusLogic_ProbeOptions.Probe330 = true; - break; - case 0x334: - BusLogic_ProbeOptions.Probe334 = true; - break; - case 0x230: - BusLogic_ProbeOptions.Probe230 = true; - break; - case 0x234: - BusLogic_ProbeOptions.Probe234 = true; - break; - case 0x130: - BusLogic_ProbeOptions.Probe130 = true; - break; - case 0x134: - BusLogic_ProbeOptions.Probe134 = true; - break; - default: - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid I/O Address 0x%X)\n", - NULL, IO_Address); - return 0; - } - } - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA")) - BusLogic_ProbeOptions.NoProbeISA = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI")) - BusLogic_ProbeOptions.NoProbePCI = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe")) - BusLogic_ProbeOptions.NoProbe = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI")) - BusLogic_ProbeOptions.NoSortPCI = true; - else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst")) - BusLogic_ProbeOptions.MultiMasterFirst = true; - else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst")) - BusLogic_ProbeOptions.FlashPointFirst = true; - /* Tagged Queuing Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || - BusLogic_ParseKeyword(&OptionsString, "QD:[")) - { - for (TargetID = 0; - TargetID < BusLogic_MaxTargetDevices; - TargetID++) - { - unsigned short QueueDepth = - simple_strtoul(OptionsString, &OptionsString, 0); - if (QueueDepth > BusLogic_MaxTaggedQueueDepth) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid Queue Depth %d)\n", - NULL, QueueDepth); - return 0; - } - DriverOptions->QueueDepth[TargetID] = QueueDepth; - if (*OptionsString == ',') - OptionsString++; - else if (*OptionsString == ']') - break; - else - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(',' or ']' expected at '%s')\n", - NULL, OptionsString); - return 0; - } - } - if (*OptionsString != ']') - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(']' expected at '%s')\n", - NULL, OptionsString); - return 0; - } - else OptionsString++; - } - else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || - BusLogic_ParseKeyword(&OptionsString, "QD:")) - { - unsigned short QueueDepth = - simple_strtoul(OptionsString, &OptionsString, 0); - if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid Queue Depth %d)\n", - NULL, QueueDepth); - return 0; - } - DriverOptions->CommonQueueDepth = QueueDepth; - for (TargetID = 0; - TargetID < BusLogic_MaxTargetDevices; - TargetID++) - DriverOptions->QueueDepth[TargetID] = QueueDepth; - } - else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || - BusLogic_ParseKeyword(&OptionsString, "TQ:")) - { - if (BusLogic_ParseKeyword(&OptionsString, "Default")) - { - DriverOptions->TaggedQueuingPermitted = 0x0000; - DriverOptions->TaggedQueuingPermittedMask = 0x0000; - } - else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) - { - DriverOptions->TaggedQueuingPermitted = 0xFFFF; - DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; - } - else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) - { - DriverOptions->TaggedQueuingPermitted = 0x0000; - DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; - } - else - { - unsigned short TargetBit; - for (TargetID = 0, TargetBit = 1; - TargetID < BusLogic_MaxTargetDevices; - TargetID++, TargetBit <<= 1) - switch (*OptionsString++) - { - case 'Y': - DriverOptions->TaggedQueuingPermitted |= TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - break; - case 'N': - DriverOptions->TaggedQueuingPermitted &= ~TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - break; - case 'X': - break; - default: - OptionsString--; - TargetID = BusLogic_MaxTargetDevices; - break; - } + while (true) { + struct BusLogic_DriverOptions *DriverOptions = &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++]; + int TargetID; + memset(DriverOptions, 0, sizeof(struct BusLogic_DriverOptions)); + while (*OptionsString != '\0' && *OptionsString != ';') { + /* Probing Options. */ + if (BusLogic_ParseKeyword(&OptionsString, "IO:")) { + unsigned long IO_Address = simple_strtoul(OptionsString, &OptionsString, 0); + BusLogic_ProbeOptions.LimitedProbeISA = true; + switch (IO_Address) { + case 0x330: + BusLogic_ProbeOptions.Probe330 = true; + break; + case 0x334: + BusLogic_ProbeOptions.Probe334 = true; + break; + case 0x230: + BusLogic_ProbeOptions.Probe230 = true; + break; + case 0x234: + BusLogic_ProbeOptions.Probe234 = true; + break; + case 0x130: + BusLogic_ProbeOptions.Probe130 = true; + break; + case 0x134: + BusLogic_ProbeOptions.Probe134 = true; + break; + default: + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid I/O Address 0x%X)\n", NULL, IO_Address); + return 0; + } + } else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA")) + BusLogic_ProbeOptions.NoProbeISA = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI")) + BusLogic_ProbeOptions.NoProbePCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe")) + BusLogic_ProbeOptions.NoProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI")) + BusLogic_ProbeOptions.NoSortPCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst")) + BusLogic_ProbeOptions.MultiMasterFirst = true; + else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst")) + BusLogic_ProbeOptions.FlashPointFirst = true; + /* Tagged Queuing Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || BusLogic_ParseKeyword(&OptionsString, "QD:[")) { + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) { + unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth > BusLogic_MaxTaggedQueueDepth) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth); + return 0; + } + DriverOptions->QueueDepth[TargetID] = QueueDepth; + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString == ']') + break; + else { + BusLogic_Error("BusLogic: Invalid Driver Options " "(',' or ']' expected at '%s')\n", NULL, OptionsString); + return 0; + } + } + if (*OptionsString != ']') { + BusLogic_Error("BusLogic: Invalid Driver Options " "(']' expected at '%s')\n", NULL, OptionsString); + return 0; + } else + OptionsString++; + } else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || BusLogic_ParseKeyword(&OptionsString, "QD:")) { + unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth); + return 0; + } + DriverOptions->CommonQueueDepth = QueueDepth; + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + DriverOptions->QueueDepth[TargetID] = QueueDepth; + } else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || BusLogic_ParseKeyword(&OptionsString, "TQ:")) { + if (BusLogic_ParseKeyword(&OptionsString, "Default")) { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0x0000; + } else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) { + DriverOptions->TaggedQueuingPermitted = 0xFFFF; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } else { + unsigned short TargetBit; + for (TargetID = 0, TargetBit = 1; TargetID < BusLogic_MaxTargetDevices; TargetID++, TargetBit <<= 1) + switch (*OptionsString++) { + case 'Y': + DriverOptions->TaggedQueuingPermitted |= TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'N': + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'X': + break; + default: + OptionsString--; + TargetID = BusLogic_MaxTargetDevices; + break; + } + } + } + /* Miscellaneous Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || BusLogic_ParseKeyword(&OptionsString, "BST:")) { + unsigned short BusSettleTime = simple_strtoul(OptionsString, &OptionsString, 0); + if (BusSettleTime > 5 * 60) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Bus Settle Time %d)\n", NULL, BusSettleTime); + return 0; + } + DriverOptions->BusSettleTime = BusSettleTime; + } else if (BusLogic_ParseKeyword(&OptionsString, "InhibitTargetInquiry")) + DriverOptions->LocalOptions.InhibitTargetInquiry = true; + /* Debugging Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe")) + BusLogic_GlobalOptions.TraceProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset")) + BusLogic_GlobalOptions.TraceHardwareReset = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration")) + BusLogic_GlobalOptions.TraceConfiguration = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors")) + BusLogic_GlobalOptions.TraceErrors = true; + else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) { + BusLogic_GlobalOptions.TraceProbe = true; + BusLogic_GlobalOptions.TraceHardwareReset = true; + BusLogic_GlobalOptions.TraceConfiguration = true; + BusLogic_GlobalOptions.TraceErrors = true; + } + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString != ';' && *OptionsString != '\0') { + BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " "ignored\n", NULL, OptionsString); + *OptionsString = '\0'; + } + } + if (!(BusLogic_DriverOptionsCount == 0 || BusLogic_ProbeInfoCount == 0 || BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(all or no I/O Addresses must be specified)\n", NULL); + return 0; } - } - /* Miscellaneous Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || - BusLogic_ParseKeyword(&OptionsString, "BST:")) - { - unsigned short BusSettleTime = - simple_strtoul(OptionsString, &OptionsString, 0); - if (BusSettleTime > 5 * 60) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid Bus Settle Time %d)\n", - NULL, BusSettleTime); - return 0; - } - DriverOptions->BusSettleTime = BusSettleTime; - } - else if (BusLogic_ParseKeyword(&OptionsString, - "InhibitTargetInquiry")) - DriverOptions->LocalOptions.InhibitTargetInquiry = true; - /* Debugging Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe")) - BusLogic_GlobalOptions.TraceProbe = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset")) - BusLogic_GlobalOptions.TraceHardwareReset = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration")) - BusLogic_GlobalOptions.TraceConfiguration = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors")) - BusLogic_GlobalOptions.TraceErrors = true; - else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) - { - BusLogic_GlobalOptions.TraceProbe = true; - BusLogic_GlobalOptions.TraceHardwareReset = true; - BusLogic_GlobalOptions.TraceConfiguration = true; - BusLogic_GlobalOptions.TraceErrors = true; - } - if (*OptionsString == ',') - OptionsString++; - else if (*OptionsString != ';' && *OptionsString != '\0') - { - BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " - "ignored\n", NULL, OptionsString); - *OptionsString = '\0'; - } - } - if (!(BusLogic_DriverOptionsCount == 0 || - BusLogic_ProbeInfoCount == 0 || - BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(all or no I/O Addresses must be specified)\n", NULL); - return 0; - } - /* - Tagged Queuing is disabled when the Queue Depth is 1 since queuing - multiple commands is not possible. - */ - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - if (DriverOptions->QueueDepth[TargetID] == 1) - { - unsigned short TargetBit = 1 << TargetID; - DriverOptions->TaggedQueuingPermitted &= ~TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - } - if (*OptionsString == ';') OptionsString++; - if (*OptionsString == '\0') return 0; - } - return 1; + /* + Tagged Queuing is disabled when the Queue Depth is 1 since queuing + multiple commands is not possible. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + if (DriverOptions->QueueDepth[TargetID] == 1) { + unsigned short TargetBit = 1 << TargetID; + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + } + if (*OptionsString == ';') + OptionsString++; + if (*OptionsString == '\0') + return 0; + } + return 1; } /* @@ -4316,21 +3548,21 @@ */ static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .proc_name = "BusLogic", - .proc_info = BusLogic_ProcDirectoryInfo, - .name = "BusLogic", - .info = BusLogic_DriverInfo, - .queuecommand = BusLogic_QueueCommand, - .slave_configure = BusLogic_SlaveConfigure, - .bios_param = BusLogic_BIOSDiskParameters, - .eh_host_reset_handler = BusLogic_host_reset, + .module = THIS_MODULE, + .proc_name = "BusLogic", + .proc_info = BusLogic_ProcDirectoryInfo, + .name = "BusLogic", + .info = BusLogic_DriverInfo, + .queuecommand = BusLogic_QueueCommand, + .slave_configure = BusLogic_SlaveConfigure, + .bios_param = BusLogic_BIOSDiskParameters, + .eh_host_reset_handler = BusLogic_host_reset, #if 0 - .eh_abort_handler = BusLogic_AbortCommand, + .eh_abort_handler = BusLogic_AbortCommand, #endif - .unchecked_isa_dma = 1, - .max_sectors = 128, - .use_clustering = ENABLE_CLUSTERING, + .unchecked_isa_dma = 1, + .max_sectors = 128, + .use_clustering = ENABLE_CLUSTERING, }; /* @@ -4341,11 +3573,10 @@ { int ints[3]; - (void)get_options(str, ARRAY_SIZE(ints), ints); + (void) get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] != 0) { - BusLogic_Error("BusLogic: Obsolete Command Line Entry " - "Format Ignored\n", NULL); + BusLogic_Error("BusLogic: Obsolete Command Line Entry " "Format Ignored\n", NULL); return 0; } if (str == NULL || *str == '\0') @@ -4357,13 +3588,14 @@ * Initialization function */ -static int __init BusLogic_init(void) { +static int __init BusLogic_init(void) +{ #ifdef MODULE if (BusLogic) BusLogic_Setup(BusLogic); #endif - + return BusLogic_DetectHostAdapter(&driver_template) ? 0 : -ENODEV; } @@ -4374,14 +3606,12 @@ static void __exit BusLogic_exit(void) { struct BusLogic_HostAdapter *HostAdapter; - for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; - HostAdapter != NULL; HostAdapter = HostAdapter->Next) { + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) { struct Scsi_Host *host = HostAdapter->SCSI_Host; scsi_remove_host(host); } - for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; - HostAdapter != NULL; HostAdapter = HostAdapter->Next) { + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) { struct Scsi_Host *host = HostAdapter->SCSI_Host; BusLogic_ReleaseHostAdapter(host); } diff -Nru a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h --- a/drivers/scsi/BusLogic.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/scsi/BusLogic.h 2004-10-18 14:56:29 -07:00 @@ -128,17 +128,15 @@ Define the Driver Message Levels. */ -enum BusLogic_MessageLevel -{ - BusLogic_AnnounceLevel = 0, - BusLogic_InfoLevel = 1, - BusLogic_NoticeLevel = 2, - BusLogic_WarningLevel = 3, - BusLogic_ErrorLevel = 4 +enum BusLogic_MessageLevel { + BusLogic_AnnounceLevel = 0, + BusLogic_InfoLevel = 1, + BusLogic_NoticeLevel = 2, + BusLogic_WarningLevel = 3, + BusLogic_ErrorLevel = 4 }; -static char *BusLogic_MessageLevelMap[] = - { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR }; +static char *BusLogic_MessageLevelMap[] = { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR }; /* @@ -166,17 +164,15 @@ of I/O Addresses required by each type. */ -enum BusLogic_HostAdapterType -{ - BusLogic_MultiMaster = 1, - BusLogic_FlashPoint = 2 +enum BusLogic_HostAdapterType { + BusLogic_MultiMaster = 1, + BusLogic_FlashPoint = 2 } PACKED; #define BusLogic_MultiMasterAddressCount 4 #define BusLogic_FlashPointAddressCount 256 -static int BusLogic_HostAdapterAddressCount[3] = - { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount }; +static int BusLogic_HostAdapterAddressCount[3] = { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount }; /* @@ -206,39 +202,35 @@ Define the possible Host Adapter Bus Types. */ -enum BusLogic_HostAdapterBusType -{ - BusLogic_Unknown_Bus = 0, - BusLogic_ISA_Bus = 1, - BusLogic_EISA_Bus = 2, - BusLogic_PCI_Bus = 3, - BusLogic_VESA_Bus = 4, - BusLogic_MCA_Bus = 5 +enum BusLogic_HostAdapterBusType { + BusLogic_Unknown_Bus = 0, + BusLogic_ISA_Bus = 1, + BusLogic_EISA_Bus = 2, + BusLogic_PCI_Bus = 3, + BusLogic_VESA_Bus = 4, + BusLogic_MCA_Bus = 5 } PACKED; -static char *BusLogic_HostAdapterBusNames[] = - { "Unknown", "ISA", "EISA", "PCI", "VESA", "MCA" }; +static char *BusLogic_HostAdapterBusNames[] = { "Unknown", "ISA", "EISA", "PCI", "VESA", "MCA" }; -static enum BusLogic_HostAdapterBusType BusLogic_HostAdapterBusTypes[] = -{ - BusLogic_VESA_Bus, /* BT-4xx */ - BusLogic_ISA_Bus, /* BT-5xx */ - BusLogic_MCA_Bus, /* BT-6xx */ - BusLogic_EISA_Bus, /* BT-7xx */ - BusLogic_Unknown_Bus, /* BT-8xx */ - BusLogic_PCI_Bus /* BT-9xx */ +static enum BusLogic_HostAdapterBusType BusLogic_HostAdapterBusTypes[] = { + BusLogic_VESA_Bus, /* BT-4xx */ + BusLogic_ISA_Bus, /* BT-5xx */ + BusLogic_MCA_Bus, /* BT-6xx */ + BusLogic_EISA_Bus, /* BT-7xx */ + BusLogic_Unknown_Bus, /* BT-8xx */ + BusLogic_PCI_Bus /* BT-9xx */ }; /* Define the possible Host Adapter BIOS Disk Geometry Translations. */ -enum BusLogic_BIOS_DiskGeometryTranslation -{ - BusLogic_BIOS_Disk_Not_Installed = 0, - BusLogic_BIOS_Disk_Installed_64x32 = 1, - BusLogic_BIOS_Disk_Installed_128x32 = 2, - BusLogic_BIOS_Disk_Installed_255x63 = 3 +enum BusLogic_BIOS_DiskGeometryTranslation { + BusLogic_BIOS_Disk_Not_Installed = 0, + BusLogic_BIOS_Disk_Installed_64x32 = 1, + BusLogic_BIOS_Disk_Installed_128x32 = 2, + BusLogic_BIOS_Disk_Installed_255x63 = 3 } PACKED; @@ -247,18 +239,17 @@ */ typedef enum { - false, - true + false, + true } PACKED boolean; /* Define a 10^18 Statistics Byte Counter data type. */ -struct BusLogic_ByteCounter -{ - unsigned int Units; - unsigned int Billions; +struct BusLogic_ByteCounter { + unsigned int Units; + unsigned int Billions; }; @@ -266,58 +257,54 @@ Define the structure for I/O Address and Bus Probing Information. */ -struct BusLogic_ProbeInfo -{ - enum BusLogic_HostAdapterType HostAdapterType; - enum BusLogic_HostAdapterBusType HostAdapterBusType; - unsigned long IO_Address; - unsigned long PCI_Address; - struct pci_dev *PCI_Device; - unsigned char Bus; - unsigned char Device; - unsigned char IRQ_Channel; +struct BusLogic_ProbeInfo { + enum BusLogic_HostAdapterType HostAdapterType; + enum BusLogic_HostAdapterBusType HostAdapterBusType; + unsigned long IO_Address; + unsigned long PCI_Address; + struct pci_dev *PCI_Device; + unsigned char Bus; + unsigned char Device; + unsigned char IRQ_Channel; }; /* Define the Probe Options. */ -struct BusLogic_ProbeOptions -{ - boolean NoProbe:1; /* Bit 0 */ - boolean NoProbeISA:1; /* Bit 1 */ - boolean NoProbePCI:1; /* Bit 2 */ - boolean NoSortPCI:1; /* Bit 3 */ - boolean MultiMasterFirst:1; /* Bit 4 */ - boolean FlashPointFirst:1; /* Bit 5 */ - boolean LimitedProbeISA:1; /* Bit 6 */ - boolean Probe330:1; /* Bit 7 */ - boolean Probe334:1; /* Bit 8 */ - boolean Probe230:1; /* Bit 9 */ - boolean Probe234:1; /* Bit 10 */ - boolean Probe130:1; /* Bit 11 */ - boolean Probe134:1; /* Bit 12 */ +struct BusLogic_ProbeOptions { + boolean NoProbe:1; /* Bit 0 */ + boolean NoProbeISA:1; /* Bit 1 */ + boolean NoProbePCI:1; /* Bit 2 */ + boolean NoSortPCI:1; /* Bit 3 */ + boolean MultiMasterFirst:1; /* Bit 4 */ + boolean FlashPointFirst:1; /* Bit 5 */ + boolean LimitedProbeISA:1; /* Bit 6 */ + boolean Probe330:1; /* Bit 7 */ + boolean Probe334:1; /* Bit 8 */ + boolean Probe230:1; /* Bit 9 */ + boolean Probe234:1; /* Bit 10 */ + boolean Probe130:1; /* Bit 11 */ + boolean Probe134:1; /* Bit 12 */ }; /* Define the Global Options. */ -struct BusLogic_GlobalOptions -{ - boolean TraceProbe:1; /* Bit 0 */ - boolean TraceHardwareReset:1; /* Bit 1 */ - boolean TraceConfiguration:1; /* Bit 2 */ - boolean TraceErrors:1; /* Bit 3 */ +struct BusLogic_GlobalOptions { + boolean TraceProbe:1; /* Bit 0 */ + boolean TraceHardwareReset:1; /* Bit 1 */ + boolean TraceConfiguration:1; /* Bit 2 */ + boolean TraceErrors:1; /* Bit 3 */ }; /* Define the Local Options. */ -struct BusLogic_LocalOptions -{ - boolean InhibitTargetInquiry:1; /* Bit 0 */ +struct BusLogic_LocalOptions { + boolean InhibitTargetInquiry:1; /* Bit 0 */ }; /* @@ -335,198 +322,188 @@ Define the structure of the write-only Control Register. */ -union BusLogic_ControlRegister -{ - unsigned char All; - struct { - unsigned char :4; /* Bits 0-3 */ - boolean SCSIBusReset:1; /* Bit 4 */ - boolean InterruptReset:1; /* Bit 5 */ - boolean SoftReset:1; /* Bit 6 */ - boolean HardReset:1; /* Bit 7 */ - } cr; +union BusLogic_ControlRegister { + unsigned char All; + struct { + unsigned char:4; /* Bits 0-3 */ + boolean SCSIBusReset:1; /* Bit 4 */ + boolean InterruptReset:1; /* Bit 5 */ + boolean SoftReset:1; /* Bit 6 */ + boolean HardReset:1; /* Bit 7 */ + } cr; }; /* Define the structure of the read-only Status Register. */ -union BusLogic_StatusRegister -{ - unsigned char All; - struct { - boolean CommandInvalid:1; /* Bit 0 */ - boolean Reserved:1; /* Bit 1 */ - boolean DataInRegisterReady:1; /* Bit 2 */ - boolean CommandParameterRegisterBusy:1; /* Bit 3 */ - boolean HostAdapterReady:1; /* Bit 4 */ - boolean InitializationRequired:1; /* Bit 5 */ - boolean DiagnosticFailure:1; /* Bit 6 */ - boolean DiagnosticActive:1; /* Bit 7 */ - } sr; +union BusLogic_StatusRegister { + unsigned char All; + struct { + boolean CommandInvalid:1; /* Bit 0 */ + boolean Reserved:1; /* Bit 1 */ + boolean DataInRegisterReady:1; /* Bit 2 */ + boolean CommandParameterRegisterBusy:1; /* Bit 3 */ + boolean HostAdapterReady:1; /* Bit 4 */ + boolean InitializationRequired:1; /* Bit 5 */ + boolean DiagnosticFailure:1; /* Bit 6 */ + boolean DiagnosticActive:1; /* Bit 7 */ + } sr; }; /* Define the structure of the read-only Interrupt Register. */ -union BusLogic_InterruptRegister -{ - unsigned char All; - struct { - boolean IncomingMailboxLoaded:1; /* Bit 0 */ - boolean OutgoingMailboxAvailable:1; /* Bit 1 */ - boolean CommandComplete:1; /* Bit 2 */ - boolean ExternalBusReset:1; /* Bit 3 */ - unsigned char Reserved:3; /* Bits 4-6 */ - boolean InterruptValid:1; /* Bit 7 */ - } ir; +union BusLogic_InterruptRegister { + unsigned char All; + struct { + boolean IncomingMailboxLoaded:1; /* Bit 0 */ + boolean OutgoingMailboxAvailable:1; /* Bit 1 */ + boolean CommandComplete:1; /* Bit 2 */ + boolean ExternalBusReset:1; /* Bit 3 */ + unsigned char Reserved:3; /* Bits 4-6 */ + boolean InterruptValid:1; /* Bit 7 */ + } ir; }; /* Define the structure of the read-only Geometry Register. */ -union BusLogic_GeometryRegister -{ - unsigned char All; - struct { - enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2;/* Bits 0-1 */ - enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2;/* Bits 2-3 */ - unsigned char :3; /* Bits 4-6 */ - boolean ExtendedTranslationEnabled:1; /* Bit 7 */ - } gr; +union BusLogic_GeometryRegister { + unsigned char All; + struct { + enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2; /* Bits 0-1 */ + enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2; /* Bits 2-3 */ + unsigned char:3; /* Bits 4-6 */ + boolean ExtendedTranslationEnabled:1; /* Bit 7 */ + } gr; }; /* Define the BusLogic SCSI Host Adapter Command Register Operation Codes. */ -enum BusLogic_OperationCode -{ - BusLogic_TestCommandCompleteInterrupt = 0x00, - BusLogic_InitializeMailbox = 0x01, - BusLogic_ExecuteMailboxCommand = 0x02, - BusLogic_ExecuteBIOSCommand = 0x03, - BusLogic_InquireBoardID = 0x04, - BusLogic_EnableOutgoingMailboxAvailableInt = 0x05, - BusLogic_SetSCSISelectionTimeout = 0x06, - BusLogic_SetPreemptTimeOnBus = 0x07, - BusLogic_SetTimeOffBus = 0x08, - BusLogic_SetBusTransferRate = 0x09, - BusLogic_InquireInstalledDevicesID0to7 = 0x0A, - BusLogic_InquireConfiguration = 0x0B, - BusLogic_EnableTargetMode = 0x0C, - BusLogic_InquireSetupInformation = 0x0D, - BusLogic_WriteAdapterLocalRAM = 0x1A, - BusLogic_ReadAdapterLocalRAM = 0x1B, - BusLogic_WriteBusMasterChipFIFO = 0x1C, - BusLogic_ReadBusMasterChipFIFO = 0x1D, - BusLogic_EchoCommandData = 0x1F, - BusLogic_HostAdapterDiagnostic = 0x20, - BusLogic_SetAdapterOptions = 0x21, - BusLogic_InquireInstalledDevicesID8to15 = 0x23, - BusLogic_InquireTargetDevices = 0x24, - BusLogic_DisableHostAdapterInterrupt = 0x25, - BusLogic_InitializeExtendedMailbox = 0x81, - BusLogic_ExecuteSCSICommand = 0x83, - BusLogic_InquireFirmwareVersion3rdDigit = 0x84, - BusLogic_InquireFirmwareVersionLetter = 0x85, - BusLogic_InquirePCIHostAdapterInformation = 0x86, - BusLogic_InquireHostAdapterModelNumber = 0x8B, - BusLogic_InquireSynchronousPeriod = 0x8C, - BusLogic_InquireExtendedSetupInformation = 0x8D, - BusLogic_EnableStrictRoundRobinMode = 0x8F, - BusLogic_StoreHostAdapterLocalRAM = 0x90, - BusLogic_FetchHostAdapterLocalRAM = 0x91, - BusLogic_StoreLocalDataInEEPROM = 0x92, - BusLogic_UploadAutoSCSICode = 0x94, - BusLogic_ModifyIOAddress = 0x95, - BusLogic_SetCCBFormat = 0x96, - BusLogic_WriteInquiryBuffer = 0x9A, - BusLogic_ReadInquiryBuffer = 0x9B, - BusLogic_FlashROMUploadDownload = 0xA7, - BusLogic_ReadSCAMData = 0xA8, - BusLogic_WriteSCAMData = 0xA9 +enum BusLogic_OperationCode { + BusLogic_TestCommandCompleteInterrupt = 0x00, + BusLogic_InitializeMailbox = 0x01, + BusLogic_ExecuteMailboxCommand = 0x02, + BusLogic_ExecuteBIOSCommand = 0x03, + BusLogic_InquireBoardID = 0x04, + BusLogic_EnableOutgoingMailboxAvailableInt = 0x05, + BusLogic_SetSCSISelectionTimeout = 0x06, + BusLogic_SetPreemptTimeOnBus = 0x07, + BusLogic_SetTimeOffBus = 0x08, + BusLogic_SetBusTransferRate = 0x09, + BusLogic_InquireInstalledDevicesID0to7 = 0x0A, + BusLogic_InquireConfiguration = 0x0B, + BusLogic_EnableTargetMode = 0x0C, + BusLogic_InquireSetupInformation = 0x0D, + BusLogic_WriteAdapterLocalRAM = 0x1A, + BusLogic_ReadAdapterLocalRAM = 0x1B, + BusLogic_WriteBusMasterChipFIFO = 0x1C, + BusLogic_ReadBusMasterChipFIFO = 0x1D, + BusLogic_EchoCommandData = 0x1F, + BusLogic_HostAdapterDiagnostic = 0x20, + BusLogic_SetAdapterOptions = 0x21, + BusLogic_InquireInstalledDevicesID8to15 = 0x23, + BusLogic_InquireTargetDevices = 0x24, + BusLogic_DisableHostAdapterInterrupt = 0x25, + BusLogic_InitializeExtendedMailbox = 0x81, + BusLogic_ExecuteSCSICommand = 0x83, + BusLogic_InquireFirmwareVersion3rdDigit = 0x84, + BusLogic_InquireFirmwareVersionLetter = 0x85, + BusLogic_InquirePCIHostAdapterInformation = 0x86, + BusLogic_InquireHostAdapterModelNumber = 0x8B, + BusLogic_InquireSynchronousPeriod = 0x8C, + BusLogic_InquireExtendedSetupInformation = 0x8D, + BusLogic_EnableStrictRoundRobinMode = 0x8F, + BusLogic_StoreHostAdapterLocalRAM = 0x90, + BusLogic_FetchHostAdapterLocalRAM = 0x91, + BusLogic_StoreLocalDataInEEPROM = 0x92, + BusLogic_UploadAutoSCSICode = 0x94, + BusLogic_ModifyIOAddress = 0x95, + BusLogic_SetCCBFormat = 0x96, + BusLogic_WriteInquiryBuffer = 0x9A, + BusLogic_ReadInquiryBuffer = 0x9B, + BusLogic_FlashROMUploadDownload = 0xA7, + BusLogic_ReadSCAMData = 0xA8, + BusLogic_WriteSCAMData = 0xA9 }; /* Define the Inquire Board ID reply structure. */ -struct BusLogic_BoardID -{ - unsigned char BoardType; /* Byte 0 */ - unsigned char CustomFeatures; /* Byte 1 */ - unsigned char FirmwareVersion1stDigit; /* Byte 2 */ - unsigned char FirmwareVersion2ndDigit; /* Byte 3 */ +struct BusLogic_BoardID { + unsigned char BoardType; /* Byte 0 */ + unsigned char CustomFeatures; /* Byte 1 */ + unsigned char FirmwareVersion1stDigit; /* Byte 2 */ + unsigned char FirmwareVersion2ndDigit; /* Byte 3 */ }; /* Define the Inquire Configuration reply structure. */ -struct BusLogic_Configuration -{ - unsigned char :5; /* Byte 0 Bits 0-4 */ - boolean DMA_Channel5:1; /* Byte 0 Bit 5 */ - boolean DMA_Channel6:1; /* Byte 0 Bit 6 */ - boolean DMA_Channel7:1; /* Byte 0 Bit 7 */ - boolean IRQ_Channel9:1; /* Byte 1 Bit 0 */ - boolean IRQ_Channel10:1; /* Byte 1 Bit 1 */ - boolean IRQ_Channel11:1; /* Byte 1 Bit 2 */ - boolean IRQ_Channel12:1; /* Byte 1 Bit 3 */ - unsigned char :1; /* Byte 1 Bit 4 */ - boolean IRQ_Channel14:1; /* Byte 1 Bit 5 */ - boolean IRQ_Channel15:1; /* Byte 1 Bit 6 */ - unsigned char :1; /* Byte 1 Bit 7 */ - unsigned char HostAdapterID:4; /* Byte 2 Bits 0-3 */ - unsigned char :4; /* Byte 2 Bits 4-7 */ +struct BusLogic_Configuration { + unsigned char:5; /* Byte 0 Bits 0-4 */ + boolean DMA_Channel5:1; /* Byte 0 Bit 5 */ + boolean DMA_Channel6:1; /* Byte 0 Bit 6 */ + boolean DMA_Channel7:1; /* Byte 0 Bit 7 */ + boolean IRQ_Channel9:1; /* Byte 1 Bit 0 */ + boolean IRQ_Channel10:1; /* Byte 1 Bit 1 */ + boolean IRQ_Channel11:1; /* Byte 1 Bit 2 */ + boolean IRQ_Channel12:1; /* Byte 1 Bit 3 */ + unsigned char:1; /* Byte 1 Bit 4 */ + boolean IRQ_Channel14:1; /* Byte 1 Bit 5 */ + boolean IRQ_Channel15:1; /* Byte 1 Bit 6 */ + unsigned char:1; /* Byte 1 Bit 7 */ + unsigned char HostAdapterID:4; /* Byte 2 Bits 0-3 */ + unsigned char:4; /* Byte 2 Bits 4-7 */ }; /* Define the Inquire Setup Information reply structure. */ -struct BusLogic_SynchronousValue -{ - unsigned char Offset:4; /* Bits 0-3 */ - unsigned char TransferPeriod:3; /* Bits 4-6 */ - boolean Synchronous:1; /* Bit 7 */ -}; - -struct BusLogic_SetupInformation -{ - boolean SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */ - boolean ParityCheckingEnabled:1; /* Byte 0 Bit 1 */ - unsigned char :6; /* Byte 0 Bits 2-7 */ - unsigned char BusTransferRate; /* Byte 1 */ - unsigned char PreemptTimeOnBus; /* Byte 2 */ - unsigned char TimeOffBus; /* Byte 3 */ - unsigned char MailboxCount; /* Byte 4 */ - unsigned char MailboxAddress[3]; /* Bytes 5-7 */ - struct BusLogic_SynchronousValue SynchronousValuesID0to7[8];/* Bytes 8-15 */ - unsigned char DisconnectPermittedID0to7; /* Byte 16 */ - unsigned char Signature; /* Byte 17 */ - unsigned char CharacterD; /* Byte 18 */ - unsigned char HostBusType; /* Byte 19 */ - unsigned char WideTransfersPermittedID0to7; /* Byte 20 */ - unsigned char WideTransfersActiveID0to7; /* Byte 21 */ - struct BusLogic_SynchronousValue SynchronousValuesID8to15[8]; /* Bytes 22-29 */ - unsigned char DisconnectPermittedID8to15; /* Byte 30 */ - unsigned char :8; /* Byte 31 */ - unsigned char WideTransfersPermittedID8to15; /* Byte 32 */ - unsigned char WideTransfersActiveID8to15; /* Byte 33 */ +struct BusLogic_SynchronousValue { + unsigned char Offset:4; /* Bits 0-3 */ + unsigned char TransferPeriod:3; /* Bits 4-6 */ + boolean Synchronous:1; /* Bit 7 */ +}; + +struct BusLogic_SetupInformation { + boolean SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */ + boolean ParityCheckingEnabled:1; /* Byte 0 Bit 1 */ + unsigned char:6; /* Byte 0 Bits 2-7 */ + unsigned char BusTransferRate; /* Byte 1 */ + unsigned char PreemptTimeOnBus; /* Byte 2 */ + unsigned char TimeOffBus; /* Byte 3 */ + unsigned char MailboxCount; /* Byte 4 */ + unsigned char MailboxAddress[3]; /* Bytes 5-7 */ + struct BusLogic_SynchronousValue SynchronousValuesID0to7[8]; /* Bytes 8-15 */ + unsigned char DisconnectPermittedID0to7; /* Byte 16 */ + unsigned char Signature; /* Byte 17 */ + unsigned char CharacterD; /* Byte 18 */ + unsigned char HostBusType; /* Byte 19 */ + unsigned char WideTransfersPermittedID0to7; /* Byte 20 */ + unsigned char WideTransfersActiveID0to7; /* Byte 21 */ + struct BusLogic_SynchronousValue SynchronousValuesID8to15[8]; /* Bytes 22-29 */ + unsigned char DisconnectPermittedID8to15; /* Byte 30 */ + unsigned char:8; /* Byte 31 */ + unsigned char WideTransfersPermittedID8to15; /* Byte 32 */ + unsigned char WideTransfersActiveID8to15; /* Byte 33 */ }; /* Define the Initialize Extended Mailbox request structure. */ -struct BusLogic_ExtendedMailboxRequest -{ - unsigned char MailboxCount; /* Byte 0 */ - u32 BaseMailboxAddress; /* Bytes 1-4 */ +struct BusLogic_ExtendedMailboxRequest { + unsigned char MailboxCount; /* Byte 0 */ + u32 BaseMailboxAddress; /* Bytes 1-4 */ } PACKED; @@ -536,67 +513,63 @@ the Modify I/O Address command. */ -enum BusLogic_ISACompatibleIOPort -{ - BusLogic_IO_330 = 0, - BusLogic_IO_334 = 1, - BusLogic_IO_230 = 2, - BusLogic_IO_234 = 3, - BusLogic_IO_130 = 4, - BusLogic_IO_134 = 5, - BusLogic_IO_Disable = 6, - BusLogic_IO_Disable2 = 7 +enum BusLogic_ISACompatibleIOPort { + BusLogic_IO_330 = 0, + BusLogic_IO_334 = 1, + BusLogic_IO_230 = 2, + BusLogic_IO_234 = 3, + BusLogic_IO_130 = 4, + BusLogic_IO_134 = 5, + BusLogic_IO_Disable = 6, + BusLogic_IO_Disable2 = 7 } PACKED; -struct BusLogic_PCIHostAdapterInformation -{ - enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort;/* Byte 0 */ - unsigned char PCIAssignedIRQChannel; /* Byte 1 */ - boolean LowByteTerminated:1; /* Byte 2 Bit 0 */ - boolean HighByteTerminated:1; /* Byte 2 Bit 1 */ - unsigned char :2; /* Byte 2 Bits 2-3 */ - boolean JP1:1; /* Byte 2 Bit 4 */ - boolean JP2:1; /* Byte 2 Bit 5 */ - boolean JP3:1; /* Byte 2 Bit 6 */ - boolean GenericInfoValid:1; /* Byte 2 Bit 7 */ - unsigned char :8; /* Byte 3 */ +struct BusLogic_PCIHostAdapterInformation { + enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort; /* Byte 0 */ + unsigned char PCIAssignedIRQChannel; /* Byte 1 */ + boolean LowByteTerminated:1; /* Byte 2 Bit 0 */ + boolean HighByteTerminated:1; /* Byte 2 Bit 1 */ + unsigned char:2; /* Byte 2 Bits 2-3 */ + boolean JP1:1; /* Byte 2 Bit 4 */ + boolean JP2:1; /* Byte 2 Bit 5 */ + boolean JP3:1; /* Byte 2 Bit 6 */ + boolean GenericInfoValid:1; /* Byte 2 Bit 7 */ + unsigned char:8; /* Byte 3 */ }; /* Define the Inquire Extended Setup Information reply structure. */ -struct BusLogic_ExtendedSetupInformation -{ - unsigned char BusType; /* Byte 0 */ - unsigned char BIOS_Address; /* Byte 1 */ - unsigned short ScatterGatherLimit; /* Bytes 2-3 */ - unsigned char MailboxCount; /* Byte 4 */ - u32 BaseMailboxAddress; /* Bytes 5-8 */ - struct { - unsigned char :2; /* Byte 9 Bits 0-1 */ - boolean FastOnEISA:1; /* Byte 9 Bit 2 */ - unsigned char :3; /* Byte 9 Bits 3-5 */ - boolean LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */ - unsigned char :1; /* Byte 9 Bit 7 */ - } Misc; - unsigned char FirmwareRevision[3]; /* Bytes 10-12 */ - boolean HostWideSCSI:1; /* Byte 13 Bit 0 */ - boolean HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ - boolean HostSupportsSCAM:1; /* Byte 13 Bit 2 */ - boolean HostUltraSCSI:1; /* Byte 13 Bit 3 */ - boolean HostSmartTermination:1; /* Byte 13 Bit 4 */ - unsigned char :3; /* Byte 13 Bits 5-7 */ +struct BusLogic_ExtendedSetupInformation { + unsigned char BusType; /* Byte 0 */ + unsigned char BIOS_Address; /* Byte 1 */ + unsigned short ScatterGatherLimit; /* Bytes 2-3 */ + unsigned char MailboxCount; /* Byte 4 */ + u32 BaseMailboxAddress; /* Bytes 5-8 */ + struct { + unsigned char:2; /* Byte 9 Bits 0-1 */ + boolean FastOnEISA:1; /* Byte 9 Bit 2 */ + unsigned char:3; /* Byte 9 Bits 3-5 */ + boolean LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */ + unsigned char:1; /* Byte 9 Bit 7 */ + } Misc; + unsigned char FirmwareRevision[3]; /* Bytes 10-12 */ + boolean HostWideSCSI:1; /* Byte 13 Bit 0 */ + boolean HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ + boolean HostSupportsSCAM:1; /* Byte 13 Bit 2 */ + boolean HostUltraSCSI:1; /* Byte 13 Bit 3 */ + boolean HostSmartTermination:1; /* Byte 13 Bit 4 */ + unsigned char:3; /* Byte 13 Bits 5-7 */ } PACKED; /* Define the Enable Strict Round Robin Mode request type. */ -enum BusLogic_RoundRobinModeRequest -{ - BusLogic_AggressiveRoundRobinMode = 0, - BusLogic_StrictRoundRobinMode = 1 +enum BusLogic_RoundRobinModeRequest { + BusLogic_AggressiveRoundRobinMode = 0, + BusLogic_StrictRoundRobinMode = 1 } PACKED; @@ -607,96 +580,93 @@ #define BusLogic_BIOS_BaseOffset 0 #define BusLogic_AutoSCSI_BaseOffset 64 -struct BusLogic_FetchHostAdapterLocalRAMRequest -{ - unsigned char ByteOffset; /* Byte 0 */ - unsigned char ByteCount; /* Byte 1 */ +struct BusLogic_FetchHostAdapterLocalRAMRequest { + unsigned char ByteOffset; /* Byte 0 */ + unsigned char ByteCount; /* Byte 1 */ }; /* Define the Host Adapter Local RAM AutoSCSI structure. */ -struct BusLogic_AutoSCSIData -{ - unsigned char InternalFactorySignature[2]; /* Bytes 0-1 */ - unsigned char InformationByteCount; /* Byte 2 */ - unsigned char HostAdapterType[6]; /* Bytes 3-8 */ - unsigned char :8; /* Byte 9 */ - boolean FloppyEnabled:1; /* Byte 10 Bit 0 */ - boolean FloppySecondary:1; /* Byte 10 Bit 1 */ - boolean LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */ - unsigned char :2; /* Byte 10 Bits 3-4 */ - unsigned char SystemRAMAreaForBIOS:3; /* Byte 10 Bits 5-7 */ - unsigned char DMA_Channel:7; /* Byte 11 Bits 0-6 */ - boolean DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */ - unsigned char IRQ_Channel:7; /* Byte 12 Bits 0-6 */ - boolean IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */ - unsigned char DMA_TransferRate; /* Byte 13 */ - unsigned char SCSI_ID; /* Byte 14 */ - boolean LowByteTerminated:1; /* Byte 15 Bit 0 */ - boolean ParityCheckingEnabled:1; /* Byte 15 Bit 1 */ - boolean HighByteTerminated:1; /* Byte 15 Bit 2 */ - boolean NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */ - boolean FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */ - boolean BusResetEnabled:1; /* Byte 15 Bit 5 */ - boolean :1; /* Byte 15 Bit 6 */ - boolean ActiveNegationEnabled:1; /* Byte 15 Bit 7 */ - unsigned char BusOnDelay; /* Byte 16 */ - unsigned char BusOffDelay; /* Byte 17 */ - boolean HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */ - boolean BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */ - boolean ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */ - boolean MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */ - boolean :1; /* Byte 18 Bit 4 */ - boolean BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */ - boolean BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */ - boolean FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */ - unsigned short DeviceEnabled; /* Bytes 19-20 */ - unsigned short WidePermitted; /* Bytes 21-22 */ - unsigned short FastPermitted; /* Bytes 23-24 */ - unsigned short SynchronousPermitted; /* Bytes 25-26 */ - unsigned short DisconnectPermitted; /* Bytes 27-28 */ - unsigned short SendStartUnitCommand; /* Bytes 29-30 */ - unsigned short IgnoreInBIOSScan; /* Bytes 31-32 */ - unsigned char PCIInterruptPin:2; /* Byte 33 Bits 0-1 */ - unsigned char HostAdapterIOPortAddress:2; /* Byte 33 Bits 2-3 */ - boolean StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */ - boolean VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */ - boolean VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */ - boolean VESABurstReadEnabled:1; /* Byte 33 Bit 7 */ - unsigned short UltraPermitted; /* Bytes 34-35 */ - unsigned int :32; /* Bytes 36-39 */ - unsigned char :8; /* Byte 40 */ - unsigned char AutoSCSIMaximumLUN; /* Byte 41 */ - boolean :1; /* Byte 42 Bit 0 */ - boolean SCAM_Dominant:1; /* Byte 42 Bit 1 */ - boolean SCAM_Enabled:1; /* Byte 42 Bit 2 */ - boolean SCAM_Level2:1; /* Byte 42 Bit 3 */ - unsigned char :4; /* Byte 42 Bits 4-7 */ - boolean INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */ - boolean :1; /* Byte 43 Bit 1 */ - boolean CDROMBootEnabled:1; /* Byte 43 Bit 2 */ - unsigned char :5; /* Byte 43 Bits 3-7 */ - unsigned char BootTargetID:4; /* Byte 44 Bits 0-3 */ - unsigned char BootChannel:4; /* Byte 44 Bits 4-7 */ - unsigned char ForceBusDeviceScanningOrder:1; /* Byte 45 Bit 0 */ - unsigned char :7; /* Byte 45 Bits 1-7 */ - unsigned short NonTaggedToAlternateLUNPermitted; /* Bytes 46-47 */ - unsigned short RenegotiateSyncAfterCheckCondition; /* Bytes 48-49 */ - unsigned char Reserved[10]; /* Bytes 50-59 */ - unsigned char ManufacturingDiagnostic[2]; /* Bytes 60-61 */ - unsigned short Checksum; /* Bytes 62-63 */ +struct BusLogic_AutoSCSIData { + unsigned char InternalFactorySignature[2]; /* Bytes 0-1 */ + unsigned char InformationByteCount; /* Byte 2 */ + unsigned char HostAdapterType[6]; /* Bytes 3-8 */ + unsigned char:8; /* Byte 9 */ + boolean FloppyEnabled:1; /* Byte 10 Bit 0 */ + boolean FloppySecondary:1; /* Byte 10 Bit 1 */ + boolean LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */ + unsigned char:2; /* Byte 10 Bits 3-4 */ + unsigned char SystemRAMAreaForBIOS:3; /* Byte 10 Bits 5-7 */ + unsigned char DMA_Channel:7; /* Byte 11 Bits 0-6 */ + boolean DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */ + unsigned char IRQ_Channel:7; /* Byte 12 Bits 0-6 */ + boolean IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */ + unsigned char DMA_TransferRate; /* Byte 13 */ + unsigned char SCSI_ID; /* Byte 14 */ + boolean LowByteTerminated:1; /* Byte 15 Bit 0 */ + boolean ParityCheckingEnabled:1; /* Byte 15 Bit 1 */ + boolean HighByteTerminated:1; /* Byte 15 Bit 2 */ + boolean NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */ + boolean FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */ + boolean BusResetEnabled:1; /* Byte 15 Bit 5 */ + boolean:1; /* Byte 15 Bit 6 */ + boolean ActiveNegationEnabled:1; /* Byte 15 Bit 7 */ + unsigned char BusOnDelay; /* Byte 16 */ + unsigned char BusOffDelay; /* Byte 17 */ + boolean HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */ + boolean BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */ + boolean ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */ + boolean MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */ + boolean:1; /* Byte 18 Bit 4 */ + boolean BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */ + boolean BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */ + boolean FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */ + unsigned short DeviceEnabled; /* Bytes 19-20 */ + unsigned short WidePermitted; /* Bytes 21-22 */ + unsigned short FastPermitted; /* Bytes 23-24 */ + unsigned short SynchronousPermitted; /* Bytes 25-26 */ + unsigned short DisconnectPermitted; /* Bytes 27-28 */ + unsigned short SendStartUnitCommand; /* Bytes 29-30 */ + unsigned short IgnoreInBIOSScan; /* Bytes 31-32 */ + unsigned char PCIInterruptPin:2; /* Byte 33 Bits 0-1 */ + unsigned char HostAdapterIOPortAddress:2; /* Byte 33 Bits 2-3 */ + boolean StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */ + boolean VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */ + boolean VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */ + boolean VESABurstReadEnabled:1; /* Byte 33 Bit 7 */ + unsigned short UltraPermitted; /* Bytes 34-35 */ + unsigned int:32; /* Bytes 36-39 */ + unsigned char:8; /* Byte 40 */ + unsigned char AutoSCSIMaximumLUN; /* Byte 41 */ + boolean:1; /* Byte 42 Bit 0 */ + boolean SCAM_Dominant:1; /* Byte 42 Bit 1 */ + boolean SCAM_Enabled:1; /* Byte 42 Bit 2 */ + boolean SCAM_Level2:1; /* Byte 42 Bit 3 */ + unsigned char:4; /* Byte 42 Bits 4-7 */ + boolean INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */ + boolean:1; /* Byte 43 Bit 1 */ + boolean CDROMBootEnabled:1; /* Byte 43 Bit 2 */ + unsigned char:5; /* Byte 43 Bits 3-7 */ + unsigned char BootTargetID:4; /* Byte 44 Bits 0-3 */ + unsigned char BootChannel:4; /* Byte 44 Bits 4-7 */ + unsigned char ForceBusDeviceScanningOrder:1; /* Byte 45 Bit 0 */ + unsigned char:7; /* Byte 45 Bits 1-7 */ + unsigned short NonTaggedToAlternateLUNPermitted; /* Bytes 46-47 */ + unsigned short RenegotiateSyncAfterCheckCondition; /* Bytes 48-49 */ + unsigned char Reserved[10]; /* Bytes 50-59 */ + unsigned char ManufacturingDiagnostic[2]; /* Bytes 60-61 */ + unsigned short Checksum; /* Bytes 62-63 */ } PACKED; /* Define the Host Adapter Local RAM Auto SCSI Byte 45 structure. */ -struct BusLogic_AutoSCSIByte45 -{ - unsigned char ForceBusDeviceScanningOrder:1; /* Bit 0 */ - unsigned char :7; /* Bits 1-7 */ +struct BusLogic_AutoSCSIByte45 { + unsigned char ForceBusDeviceScanningOrder:1; /* Bit 0 */ + unsigned char:7; /* Bits 1-7 */ }; /* @@ -705,12 +675,11 @@ #define BusLogic_BIOS_DriveMapOffset 17 -struct BusLogic_BIOSDriveMapByte -{ - unsigned char TargetIDBit3:1; /* Bit 0 */ - unsigned char :2; /* Bits 1-2 */ - enum BusLogic_BIOS_DiskGeometryTranslation DiskGeometry:2; /* Bits 3-4 */ - unsigned char TargetID:3; /* Bits 5-7 */ +struct BusLogic_BIOSDriveMapByte { + unsigned char TargetIDBit3:1; /* Bit 0 */ + unsigned char:2; /* Bits 1-2 */ + enum BusLogic_BIOS_DiskGeometryTranslation DiskGeometry:2; /* Bits 3-4 */ + unsigned char TargetID:3; /* Bits 5-7 */ }; /* @@ -718,21 +687,19 @@ necessary to support more than 8 Logical Units per Target Device. */ -enum BusLogic_SetCCBFormatRequest -{ - BusLogic_LegacyLUNFormatCCB = 0, - BusLogic_ExtendedLUNFormatCCB = 1 +enum BusLogic_SetCCBFormatRequest { + BusLogic_LegacyLUNFormatCCB = 0, + BusLogic_ExtendedLUNFormatCCB = 1 } PACKED; /* Define the Outgoing Mailbox Action Codes. */ -enum BusLogic_ActionCode -{ - BusLogic_OutgoingMailboxFree = 0x00, - BusLogic_MailboxStartCommand = 0x01, - BusLogic_MailboxAbortCommand = 0x02 +enum BusLogic_ActionCode { + BusLogic_OutgoingMailboxFree = 0x00, + BusLogic_MailboxStartCommand = 0x01, + BusLogic_MailboxAbortCommand = 0x02 } PACKED; @@ -742,28 +709,26 @@ completion codes are stored in the CCB; it only uses codes 1, 2, 4, and 5. */ -enum BusLogic_CompletionCode -{ - BusLogic_IncomingMailboxFree = 0x00, - BusLogic_CommandCompletedWithoutError = 0x01, - BusLogic_CommandAbortedAtHostRequest = 0x02, - BusLogic_AbortedCommandNotFound = 0x03, - BusLogic_CommandCompletedWithError = 0x04, - BusLogic_InvalidCCB = 0x05 +enum BusLogic_CompletionCode { + BusLogic_IncomingMailboxFree = 0x00, + BusLogic_CommandCompletedWithoutError = 0x01, + BusLogic_CommandAbortedAtHostRequest = 0x02, + BusLogic_AbortedCommandNotFound = 0x03, + BusLogic_CommandCompletedWithError = 0x04, + BusLogic_InvalidCCB = 0x05 } PACKED; /* Define the Command Control Block (CCB) Opcodes. */ -enum BusLogic_CCB_Opcode -{ - BusLogic_InitiatorCCB = 0x00, - BusLogic_TargetCCB = 0x01, - BusLogic_InitiatorCCB_ScatterGather = 0x02, - BusLogic_InitiatorCCB_ResidualDataLength = 0x03, - BusLogic_InitiatorCCB_ScatterGatherResidual = 0x04, - BusLogic_BusDeviceReset = 0x81 +enum BusLogic_CCB_Opcode { + BusLogic_InitiatorCCB = 0x00, + BusLogic_TargetCCB = 0x01, + BusLogic_InitiatorCCB_ScatterGather = 0x02, + BusLogic_InitiatorCCB_ResidualDataLength = 0x03, + BusLogic_InitiatorCCB_ScatterGatherResidual = 0x04, + BusLogic_BusDeviceReset = 0x81 } PACKED; @@ -771,12 +736,11 @@ Define the CCB Data Direction Codes. */ -enum BusLogic_DataDirection -{ - BusLogic_UncheckedDataTransfer = 0, - BusLogic_DataInLengthChecked = 1, - BusLogic_DataOutLengthChecked = 2, - BusLogic_NoDataTransfer = 3 +enum BusLogic_DataDirection { + BusLogic_UncheckedDataTransfer = 0, + BusLogic_DataInLengthChecked = 1, + BusLogic_DataOutLengthChecked = 2, + BusLogic_NoDataTransfer = 3 }; @@ -785,33 +749,32 @@ return status code 0x0C; it uses 0x12 for both overruns and underruns. */ -enum BusLogic_HostAdapterStatus -{ - BusLogic_CommandCompletedNormally = 0x00, - BusLogic_LinkedCommandCompleted = 0x0A, - BusLogic_LinkedCommandCompletedWithFlag = 0x0B, - BusLogic_DataUnderRun = 0x0C, - BusLogic_SCSISelectionTimeout = 0x11, - BusLogic_DataOverRun = 0x12, - BusLogic_UnexpectedBusFree = 0x13, - BusLogic_InvalidBusPhaseRequested = 0x14, - BusLogic_InvalidOutgoingMailboxActionCode = 0x15, - BusLogic_InvalidCommandOperationCode = 0x16, - BusLogic_LinkedCCBhasInvalidLUN = 0x17, - BusLogic_InvalidCommandParameter = 0x1A, - BusLogic_AutoRequestSenseFailed = 0x1B, - BusLogic_TaggedQueuingMessageRejected = 0x1C, - BusLogic_UnsupportedMessageReceived = 0x1D, - BusLogic_HostAdapterHardwareFailed = 0x20, - BusLogic_TargetFailedResponseToATN = 0x21, - BusLogic_HostAdapterAssertedRST = 0x22, - BusLogic_OtherDeviceAssertedRST = 0x23, - BusLogic_TargetDeviceReconnectedImproperly = 0x24, - BusLogic_HostAdapterAssertedBusDeviceReset = 0x25, - BusLogic_AbortQueueGenerated = 0x26, - BusLogic_HostAdapterSoftwareError = 0x27, - BusLogic_HostAdapterHardwareTimeoutError = 0x30, - BusLogic_SCSIParityErrorDetected = 0x34 +enum BusLogic_HostAdapterStatus { + BusLogic_CommandCompletedNormally = 0x00, + BusLogic_LinkedCommandCompleted = 0x0A, + BusLogic_LinkedCommandCompletedWithFlag = 0x0B, + BusLogic_DataUnderRun = 0x0C, + BusLogic_SCSISelectionTimeout = 0x11, + BusLogic_DataOverRun = 0x12, + BusLogic_UnexpectedBusFree = 0x13, + BusLogic_InvalidBusPhaseRequested = 0x14, + BusLogic_InvalidOutgoingMailboxActionCode = 0x15, + BusLogic_InvalidCommandOperationCode = 0x16, + BusLogic_LinkedCCBhasInvalidLUN = 0x17, + BusLogic_InvalidCommandParameter = 0x1A, + BusLogic_AutoRequestSenseFailed = 0x1B, + BusLogic_TaggedQueuingMessageRejected = 0x1C, + BusLogic_UnsupportedMessageReceived = 0x1D, + BusLogic_HostAdapterHardwareFailed = 0x20, + BusLogic_TargetFailedResponseToATN = 0x21, + BusLogic_HostAdapterAssertedRST = 0x22, + BusLogic_OtherDeviceAssertedRST = 0x23, + BusLogic_TargetDeviceReconnectedImproperly = 0x24, + BusLogic_HostAdapterAssertedBusDeviceReset = 0x25, + BusLogic_AbortQueueGenerated = 0x26, + BusLogic_HostAdapterSoftwareError = 0x27, + BusLogic_HostAdapterHardwareTimeoutError = 0x30, + BusLogic_SCSIParityErrorDetected = 0x34 } PACKED; @@ -819,23 +782,21 @@ Define the SCSI Target Device Status Codes. */ -enum BusLogic_TargetDeviceStatus -{ - BusLogic_OperationGood = 0x00, - BusLogic_CheckCondition = 0x02, - BusLogic_DeviceBusy = 0x08 +enum BusLogic_TargetDeviceStatus { + BusLogic_OperationGood = 0x00, + BusLogic_CheckCondition = 0x02, + BusLogic_DeviceBusy = 0x08 } PACKED; /* Define the Queue Tag Codes. */ -enum BusLogic_QueueTag -{ - BusLogic_SimpleQueueTag = 0, - BusLogic_HeadOfQueueTag = 1, - BusLogic_OrderedQueueTag = 2, - BusLogic_ReservedQT = 3 +enum BusLogic_QueueTag { + BusLogic_SimpleQueueTag = 0, + BusLogic_HeadOfQueueTag = 1, + BusLogic_OrderedQueueTag = 2, + BusLogic_ReservedQT = 3 }; /* @@ -852,22 +813,20 @@ Firmware Interface and the FlashPoint SCCB Manager. */ -struct BusLogic_ScatterGatherSegment -{ - u32 SegmentByteCount; /* Bytes 0-3 */ - u32 SegmentDataPointer; /* Bytes 4-7 */ +struct BusLogic_ScatterGatherSegment { + u32 SegmentByteCount; /* Bytes 0-3 */ + u32 SegmentDataPointer; /* Bytes 4-7 */ }; /* Define the Driver CCB Status Codes. */ -enum BusLogic_CCB_Status -{ - BusLogic_CCB_Free = 0, - BusLogic_CCB_Active = 1, - BusLogic_CCB_Completed = 2, - BusLogic_CCB_Reset = 3 +enum BusLogic_CCB_Status { + BusLogic_CCB_Free = 0, + BusLogic_CCB_Active = 1, + BusLogic_CCB_Completed = 2, + BusLogic_CCB_Reset = 3 } PACKED; @@ -890,82 +849,79 @@ 32 Logical Units per Target Device. */ -struct BusLogic_CCB -{ - /* - MultiMaster Firmware and FlashPoint SCCB Manager Common Portion. - */ - enum BusLogic_CCB_Opcode Opcode; /* Byte 0 */ - unsigned char :3; /* Byte 1 Bits 0-2 */ - enum BusLogic_DataDirection DataDirection:2; /* Byte 1 Bits 3-4 */ - boolean TagEnable:1; /* Byte 1 Bit 5 */ - enum BusLogic_QueueTag QueueTag:2; /* Byte 1 Bits 6-7 */ - unsigned char CDB_Length; /* Byte 2 */ - unsigned char SenseDataLength; /* Byte 3 */ - u32 DataLength; /* Bytes 4-7 */ - u32 DataPointer; /* Bytes 8-11 */ - unsigned char :8; /* Byte 12 */ - unsigned char :8; /* Byte 13 */ - enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 14 */ - enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 15 */ - unsigned char TargetID; /* Byte 16 */ - unsigned char LogicalUnit:5; /* Byte 17 Bits 0-4 */ - boolean LegacyTagEnable:1; /* Byte 17 Bit 5 */ - enum BusLogic_QueueTag LegacyQueueTag:2; /* Byte 17 Bits 6-7 */ - SCSI_CDB_T CDB; /* Bytes 18-29 */ - unsigned char :8; /* Byte 30 */ - unsigned char :8; /* Byte 31 */ - unsigned int :32; /* Bytes 32-35 */ - u32 SenseDataPointer; /* Bytes 36-39 */ - /* - FlashPoint SCCB Manager Defined Portion. - */ - void (*CallbackFunction)(struct BusLogic_CCB *); /* Bytes 40-43 */ - u32 BaseAddress; /* Bytes 44-47 */ - enum BusLogic_CompletionCode CompletionCode; /* Byte 48 */ +struct BusLogic_CCB { + /* + MultiMaster Firmware and FlashPoint SCCB Manager Common Portion. + */ + enum BusLogic_CCB_Opcode Opcode; /* Byte 0 */ + unsigned char:3; /* Byte 1 Bits 0-2 */ + enum BusLogic_DataDirection DataDirection:2; /* Byte 1 Bits 3-4 */ + boolean TagEnable:1; /* Byte 1 Bit 5 */ + enum BusLogic_QueueTag QueueTag:2; /* Byte 1 Bits 6-7 */ + unsigned char CDB_Length; /* Byte 2 */ + unsigned char SenseDataLength; /* Byte 3 */ + u32 DataLength; /* Bytes 4-7 */ + u32 DataPointer; /* Bytes 8-11 */ + unsigned char:8; /* Byte 12 */ + unsigned char:8; /* Byte 13 */ + enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 14 */ + enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 15 */ + unsigned char TargetID; /* Byte 16 */ + unsigned char LogicalUnit:5; /* Byte 17 Bits 0-4 */ + boolean LegacyTagEnable:1; /* Byte 17 Bit 5 */ + enum BusLogic_QueueTag LegacyQueueTag:2; /* Byte 17 Bits 6-7 */ + SCSI_CDB_T CDB; /* Bytes 18-29 */ + unsigned char:8; /* Byte 30 */ + unsigned char:8; /* Byte 31 */ + unsigned int:32; /* Bytes 32-35 */ + u32 SenseDataPointer; /* Bytes 36-39 */ + /* + FlashPoint SCCB Manager Defined Portion. + */ + void (*CallbackFunction) (struct BusLogic_CCB *); /* Bytes 40-43 */ + u32 BaseAddress; /* Bytes 44-47 */ + enum BusLogic_CompletionCode CompletionCode; /* Byte 48 */ #ifndef CONFIG_SCSI_OMIT_FLASHPOINT - unsigned char :8; /* Byte 49 */ - unsigned short OS_Flags; /* Bytes 50-51 */ - unsigned char Private[48]; /* Bytes 52-99 */ + unsigned char:8; /* Byte 49 */ + unsigned short OS_Flags; /* Bytes 50-51 */ + unsigned char Private[48]; /* Bytes 52-99 */ #endif - /* - BusLogic Linux Driver Defined Portion. - */ - dma_addr_t AllocationGroupHead; - unsigned int AllocationGroupSize; - u32 DMA_Handle; - enum BusLogic_CCB_Status Status; - unsigned long SerialNumber; - struct scsi_cmnd *Command; - struct BusLogic_HostAdapter *HostAdapter; - struct BusLogic_CCB *Next; - struct BusLogic_CCB *NextAll; - struct BusLogic_ScatterGatherSegment - ScatterGatherList[BusLogic_ScatterGatherLimit]; + /* + BusLogic Linux Driver Defined Portion. + */ + dma_addr_t AllocationGroupHead; + unsigned int AllocationGroupSize; + u32 DMA_Handle; + enum BusLogic_CCB_Status Status; + unsigned long SerialNumber; + struct scsi_cmnd *Command; + struct BusLogic_HostAdapter *HostAdapter; + struct BusLogic_CCB *Next; + struct BusLogic_CCB *NextAll; + struct BusLogic_ScatterGatherSegment + ScatterGatherList[BusLogic_ScatterGatherLimit]; }; /* Define the 32 Bit Mode Outgoing Mailbox structure. */ -struct BusLogic_OutgoingMailbox -{ - u32 CCB; /* Bytes 0-3 */ - unsigned int :24; /* Bytes 4-6 */ - enum BusLogic_ActionCode ActionCode; /* Byte 7 */ +struct BusLogic_OutgoingMailbox { + u32 CCB; /* Bytes 0-3 */ + unsigned int:24; /* Bytes 4-6 */ + enum BusLogic_ActionCode ActionCode; /* Byte 7 */ }; /* Define the 32 Bit Mode Incoming Mailbox structure. */ -struct BusLogic_IncomingMailbox -{ - u32 CCB; /* Bytes 0-3 */ - enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 4 */ - enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 5 */ - unsigned char :8; /* Byte 6 */ - enum BusLogic_CompletionCode CompletionCode; /* Byte 7 */ +struct BusLogic_IncomingMailbox { + u32 CCB; /* Bytes 0-3 */ + enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 4 */ + enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 5 */ + unsigned char:8; /* Byte 6 */ + enum BusLogic_CompletionCode CompletionCode; /* Byte 7 */ }; @@ -973,29 +929,27 @@ Define the BusLogic Driver Options structure. */ -struct BusLogic_DriverOptions -{ - unsigned short TaggedQueuingPermitted; - unsigned short TaggedQueuingPermittedMask; - unsigned short BusSettleTime; - struct BusLogic_LocalOptions LocalOptions; - unsigned char CommonQueueDepth; - unsigned char QueueDepth[BusLogic_MaxTargetDevices]; +struct BusLogic_DriverOptions { + unsigned short TaggedQueuingPermitted; + unsigned short TaggedQueuingPermittedMask; + unsigned short BusSettleTime; + struct BusLogic_LocalOptions LocalOptions; + unsigned char CommonQueueDepth; + unsigned char QueueDepth[BusLogic_MaxTargetDevices]; }; /* Define the Host Adapter Target Flags structure. */ -struct BusLogic_TargetFlags -{ - boolean TargetExists:1; - boolean TaggedQueuingSupported:1; - boolean WideTransfersSupported:1; - boolean TaggedQueuingActive:1; - boolean WideTransfersActive:1; - boolean CommandSuccessfulFlag:1; - boolean TargetInfoReported:1; +struct BusLogic_TargetFlags { + boolean TargetExists:1; + boolean TaggedQueuingSupported:1; + boolean WideTransfersSupported:1; + boolean TaggedQueuingActive:1; + boolean WideTransfersActive:1; + boolean CommandSuccessfulFlag:1; + boolean TargetInfoReported:1; }; /* @@ -1006,25 +960,24 @@ typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets]; -struct BusLogic_TargetStatistics -{ - unsigned int CommandsAttempted; - unsigned int CommandsCompleted; - unsigned int ReadCommands; - unsigned int WriteCommands; - struct BusLogic_ByteCounter TotalBytesRead; - struct BusLogic_ByteCounter TotalBytesWritten; - BusLogic_CommandSizeBuckets_T ReadCommandSizeBuckets; - BusLogic_CommandSizeBuckets_T WriteCommandSizeBuckets; - unsigned short CommandAbortsRequested; - unsigned short CommandAbortsAttempted; - unsigned short CommandAbortsCompleted; - unsigned short BusDeviceResetsRequested; - unsigned short BusDeviceResetsAttempted; - unsigned short BusDeviceResetsCompleted; - unsigned short HostAdapterResetsRequested; - unsigned short HostAdapterResetsAttempted; - unsigned short HostAdapterResetsCompleted; +struct BusLogic_TargetStatistics { + unsigned int CommandsAttempted; + unsigned int CommandsCompleted; + unsigned int ReadCommands; + unsigned int WriteCommands; + struct BusLogic_ByteCounter TotalBytesRead; + struct BusLogic_ByteCounter TotalBytesWritten; + BusLogic_CommandSizeBuckets_T ReadCommandSizeBuckets; + BusLogic_CommandSizeBuckets_T WriteCommandSizeBuckets; + unsigned short CommandAbortsRequested; + unsigned short CommandAbortsAttempted; + unsigned short CommandAbortsCompleted; + unsigned short BusDeviceResetsRequested; + unsigned short BusDeviceResetsAttempted; + unsigned short BusDeviceResetsCompleted; + unsigned short HostAdapterResetsRequested; + unsigned short HostAdapterResetsAttempted; + unsigned short HostAdapterResetsCompleted; }; /* @@ -1041,183 +994,179 @@ by the FlashPoint SCCB Manager. */ -struct FlashPoint_Info -{ - u32 BaseAddress; /* Bytes 0-3 */ - boolean Present; /* Byte 4 */ - unsigned char IRQ_Channel; /* Byte 5 */ - unsigned char SCSI_ID; /* Byte 6 */ - unsigned char SCSI_LUN; /* Byte 7 */ - unsigned short FirmwareRevision; /* Bytes 8-9 */ - unsigned short SynchronousPermitted; /* Bytes 10-11 */ - unsigned short FastPermitted; /* Bytes 12-13 */ - unsigned short UltraPermitted; /* Bytes 14-15 */ - unsigned short DisconnectPermitted; /* Bytes 16-17 */ - unsigned short WidePermitted; /* Bytes 18-19 */ - boolean ParityCheckingEnabled:1; /* Byte 20 Bit 0 */ - boolean HostWideSCSI:1; /* Byte 20 Bit 1 */ - boolean HostSoftReset:1; /* Byte 20 Bit 2 */ - boolean ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */ - boolean LowByteTerminated:1; /* Byte 20 Bit 4 */ - boolean HighByteTerminated:1; /* Byte 20 Bit 5 */ - boolean ReportDataUnderrun:1; /* Byte 20 Bit 6 */ - boolean SCAM_Enabled:1; /* Byte 20 Bit 7 */ - boolean SCAM_Level2:1; /* Byte 21 Bit 0 */ - unsigned char :7; /* Byte 21 Bits 1-7 */ - unsigned char Family; /* Byte 22 */ - unsigned char BusType; /* Byte 23 */ - unsigned char ModelNumber[3]; /* Bytes 24-26 */ - unsigned char RelativeCardNumber; /* Byte 27 */ - unsigned char Reserved[4]; /* Bytes 28-31 */ - unsigned int OS_Reserved; /* Bytes 32-35 */ - unsigned char TranslationInfo[4]; /* Bytes 36-39 */ - unsigned int Reserved2[5]; /* Bytes 40-59 */ - unsigned int SecondaryRange; /* Bytes 60-63 */ +struct FlashPoint_Info { + u32 BaseAddress; /* Bytes 0-3 */ + boolean Present; /* Byte 4 */ + unsigned char IRQ_Channel; /* Byte 5 */ + unsigned char SCSI_ID; /* Byte 6 */ + unsigned char SCSI_LUN; /* Byte 7 */ + unsigned short FirmwareRevision; /* Bytes 8-9 */ + unsigned short SynchronousPermitted; /* Bytes 10-11 */ + unsigned short FastPermitted; /* Bytes 12-13 */ + unsigned short UltraPermitted; /* Bytes 14-15 */ + unsigned short DisconnectPermitted; /* Bytes 16-17 */ + unsigned short WidePermitted; /* Bytes 18-19 */ + boolean ParityCheckingEnabled:1; /* Byte 20 Bit 0 */ + boolean HostWideSCSI:1; /* Byte 20 Bit 1 */ + boolean HostSoftReset:1; /* Byte 20 Bit 2 */ + boolean ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */ + boolean LowByteTerminated:1; /* Byte 20 Bit 4 */ + boolean HighByteTerminated:1; /* Byte 20 Bit 5 */ + boolean ReportDataUnderrun:1; /* Byte 20 Bit 6 */ + boolean SCAM_Enabled:1; /* Byte 20 Bit 7 */ + boolean SCAM_Level2:1; /* Byte 21 Bit 0 */ + unsigned char:7; /* Byte 21 Bits 1-7 */ + unsigned char Family; /* Byte 22 */ + unsigned char BusType; /* Byte 23 */ + unsigned char ModelNumber[3]; /* Bytes 24-26 */ + unsigned char RelativeCardNumber; /* Byte 27 */ + unsigned char Reserved[4]; /* Bytes 28-31 */ + unsigned int OS_Reserved; /* Bytes 32-35 */ + unsigned char TranslationInfo[4]; /* Bytes 36-39 */ + unsigned int Reserved2[5]; /* Bytes 40-59 */ + unsigned int SecondaryRange; /* Bytes 60-63 */ }; /* Define the BusLogic Driver Host Adapter structure. */ -struct BusLogic_HostAdapter -{ - struct Scsi_Host *SCSI_Host; - struct pci_dev *PCI_Device; - enum BusLogic_HostAdapterType HostAdapterType; - enum BusLogic_HostAdapterBusType HostAdapterBusType; - unsigned long IO_Address; - unsigned long PCI_Address; - unsigned short AddressCount; - unsigned char HostNumber; - unsigned char ModelName[9]; - unsigned char FirmwareVersion[6]; - unsigned char FullModelName[18]; - unsigned char Bus; - unsigned char Device; - unsigned char IRQ_Channel; - unsigned char DMA_Channel; - unsigned char SCSI_ID; - boolean IRQ_ChannelAcquired:1; - boolean DMA_ChannelAcquired:1; - boolean ExtendedTranslationEnabled:1; - boolean ParityCheckingEnabled:1; - boolean BusResetEnabled:1; - boolean LevelSensitiveInterrupt:1; - boolean HostWideSCSI:1; - boolean HostDifferentialSCSI:1; - boolean HostSupportsSCAM:1; - boolean HostUltraSCSI:1; - boolean ExtendedLUNSupport:1; - boolean TerminationInfoValid:1; - boolean LowByteTerminated:1; - boolean HighByteTerminated:1; - boolean BounceBuffersRequired:1; - boolean StrictRoundRobinModeSupport:1; - boolean SCAM_Enabled:1; - boolean SCAM_Level2:1; - boolean HostAdapterInitialized:1; - boolean HostAdapterExternalReset:1; - boolean HostAdapterInternalError:1; - boolean ProcessCompletedCCBsActive; - volatile boolean HostAdapterCommandCompleted; - unsigned short HostAdapterScatterGatherLimit; - unsigned short DriverScatterGatherLimit; - unsigned short MaxTargetDevices; - unsigned short MaxLogicalUnits; - unsigned short MailboxCount; - unsigned short InitialCCBs; - unsigned short IncrementalCCBs; - unsigned short AllocatedCCBs; - unsigned short DriverQueueDepth; - unsigned short HostAdapterQueueDepth; - unsigned short UntaggedQueueDepth; - unsigned short CommonQueueDepth; - unsigned short BusSettleTime; - unsigned short SynchronousPermitted; - unsigned short FastPermitted; - unsigned short UltraPermitted; - unsigned short WidePermitted; - unsigned short DisconnectPermitted; - unsigned short TaggedQueuingPermitted; - unsigned short ExternalHostAdapterResets; - unsigned short HostAdapterInternalErrors; - unsigned short TargetDeviceCount; - unsigned short MessageBufferLength; - u32 BIOS_Address; - struct BusLogic_DriverOptions *DriverOptions; - struct FlashPoint_Info FlashPointInfo; - FlashPoint_CardHandle_T CardHandle; - struct BusLogic_HostAdapter *Next; - struct BusLogic_CCB *All_CCBs; - struct BusLogic_CCB *Free_CCBs; - struct BusLogic_CCB *FirstCompletedCCB; - struct BusLogic_CCB *LastCompletedCCB; - struct BusLogic_CCB *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices]; - struct BusLogic_TargetFlags TargetFlags[BusLogic_MaxTargetDevices]; - unsigned char QueueDepth[BusLogic_MaxTargetDevices]; - unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices]; - unsigned char SynchronousOffset[BusLogic_MaxTargetDevices]; - unsigned char ActiveCommands[BusLogic_MaxTargetDevices]; - unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices]; - unsigned long LastSequencePoint[BusLogic_MaxTargetDevices]; - unsigned long LastResetAttempted[BusLogic_MaxTargetDevices]; - unsigned long LastResetCompleted[BusLogic_MaxTargetDevices]; - struct BusLogic_OutgoingMailbox *FirstOutgoingMailbox; - struct BusLogic_OutgoingMailbox *LastOutgoingMailbox; - struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; - struct BusLogic_IncomingMailbox *FirstIncomingMailbox; - struct BusLogic_IncomingMailbox *LastIncomingMailbox; - struct BusLogic_IncomingMailbox *NextIncomingMailbox; - struct BusLogic_TargetStatistics TargetStatistics[BusLogic_MaxTargetDevices]; - unsigned char *MailboxSpace; - dma_addr_t MailboxSpaceHandle; - unsigned int MailboxSize; - unsigned long CCB_Offset; - char MessageBuffer[BusLogic_MessageBufferSize]; +struct BusLogic_HostAdapter { + struct Scsi_Host *SCSI_Host; + struct pci_dev *PCI_Device; + enum BusLogic_HostAdapterType HostAdapterType; + enum BusLogic_HostAdapterBusType HostAdapterBusType; + unsigned long IO_Address; + unsigned long PCI_Address; + unsigned short AddressCount; + unsigned char HostNumber; + unsigned char ModelName[9]; + unsigned char FirmwareVersion[6]; + unsigned char FullModelName[18]; + unsigned char Bus; + unsigned char Device; + unsigned char IRQ_Channel; + unsigned char DMA_Channel; + unsigned char SCSI_ID; + boolean IRQ_ChannelAcquired:1; + boolean DMA_ChannelAcquired:1; + boolean ExtendedTranslationEnabled:1; + boolean ParityCheckingEnabled:1; + boolean BusResetEnabled:1; + boolean LevelSensitiveInterrupt:1; + boolean HostWideSCSI:1; + boolean HostDifferentialSCSI:1; + boolean HostSupportsSCAM:1; + boolean HostUltraSCSI:1; + boolean ExtendedLUNSupport:1; + boolean TerminationInfoValid:1; + boolean LowByteTerminated:1; + boolean HighByteTerminated:1; + boolean BounceBuffersRequired:1; + boolean StrictRoundRobinModeSupport:1; + boolean SCAM_Enabled:1; + boolean SCAM_Level2:1; + boolean HostAdapterInitialized:1; + boolean HostAdapterExternalReset:1; + boolean HostAdapterInternalError:1; + boolean ProcessCompletedCCBsActive; + volatile boolean HostAdapterCommandCompleted; + unsigned short HostAdapterScatterGatherLimit; + unsigned short DriverScatterGatherLimit; + unsigned short MaxTargetDevices; + unsigned short MaxLogicalUnits; + unsigned short MailboxCount; + unsigned short InitialCCBs; + unsigned short IncrementalCCBs; + unsigned short AllocatedCCBs; + unsigned short DriverQueueDepth; + unsigned short HostAdapterQueueDepth; + unsigned short UntaggedQueueDepth; + unsigned short CommonQueueDepth; + unsigned short BusSettleTime; + unsigned short SynchronousPermitted; + unsigned short FastPermitted; + unsigned short UltraPermitted; + unsigned short WidePermitted; + unsigned short DisconnectPermitted; + unsigned short TaggedQueuingPermitted; + unsigned short ExternalHostAdapterResets; + unsigned short HostAdapterInternalErrors; + unsigned short TargetDeviceCount; + unsigned short MessageBufferLength; + u32 BIOS_Address; + struct BusLogic_DriverOptions *DriverOptions; + struct FlashPoint_Info FlashPointInfo; + FlashPoint_CardHandle_T CardHandle; + struct BusLogic_HostAdapter *Next; + struct BusLogic_CCB *All_CCBs; + struct BusLogic_CCB *Free_CCBs; + struct BusLogic_CCB *FirstCompletedCCB; + struct BusLogic_CCB *LastCompletedCCB; + struct BusLogic_CCB *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices]; + struct BusLogic_TargetFlags TargetFlags[BusLogic_MaxTargetDevices]; + unsigned char QueueDepth[BusLogic_MaxTargetDevices]; + unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices]; + unsigned char SynchronousOffset[BusLogic_MaxTargetDevices]; + unsigned char ActiveCommands[BusLogic_MaxTargetDevices]; + unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices]; + unsigned long LastSequencePoint[BusLogic_MaxTargetDevices]; + unsigned long LastResetAttempted[BusLogic_MaxTargetDevices]; + unsigned long LastResetCompleted[BusLogic_MaxTargetDevices]; + struct BusLogic_OutgoingMailbox *FirstOutgoingMailbox; + struct BusLogic_OutgoingMailbox *LastOutgoingMailbox; + struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; + struct BusLogic_IncomingMailbox *FirstIncomingMailbox; + struct BusLogic_IncomingMailbox *LastIncomingMailbox; + struct BusLogic_IncomingMailbox *NextIncomingMailbox; + struct BusLogic_TargetStatistics TargetStatistics[BusLogic_MaxTargetDevices]; + unsigned char *MailboxSpace; + dma_addr_t MailboxSpaceHandle; + unsigned int MailboxSize; + unsigned long CCB_Offset; + char MessageBuffer[BusLogic_MessageBufferSize]; }; /* Define a structure for the BIOS Disk Parameters. */ -struct BIOS_DiskParameters -{ - int Heads; - int Sectors; - int Cylinders; +struct BIOS_DiskParameters { + int Heads; + int Sectors; + int Cylinders; }; /* Define a structure for the SCSI Inquiry command results. */ -struct SCSI_Inquiry -{ - unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ - unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ - unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ - boolean RMB:1; /* Byte 1 Bit 7 */ - unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ - unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ - unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ - unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ - unsigned char :2; /* Byte 3 Bits 4-5 */ - boolean TrmIOP:1; /* Byte 3 Bit 6 */ - boolean AENC:1; /* Byte 3 Bit 7 */ - unsigned char AdditionalLength; /* Byte 4 */ - unsigned char :8; /* Byte 5 */ - unsigned char :8; /* Byte 6 */ - boolean SftRe:1; /* Byte 7 Bit 0 */ - boolean CmdQue:1; /* Byte 7 Bit 1 */ - boolean :1; /* Byte 7 Bit 2 */ - boolean Linked:1; /* Byte 7 Bit 3 */ - boolean Sync:1; /* Byte 7 Bit 4 */ - boolean WBus16:1; /* Byte 7 Bit 5 */ - boolean WBus32:1; /* Byte 7 Bit 6 */ - boolean RelAdr:1; /* Byte 7 Bit 7 */ - unsigned char VendorIdentification[8]; /* Bytes 8-15 */ - unsigned char ProductIdentification[16]; /* Bytes 16-31 */ - unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ +struct SCSI_Inquiry { + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ + unsigned char:2; /* Byte 3 Bits 4-5 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + boolean AENC:1; /* Byte 3 Bit 7 */ + unsigned char AdditionalLength; /* Byte 4 */ + unsigned char:8; /* Byte 5 */ + unsigned char:8; /* Byte 6 */ + boolean SftRe:1; /* Byte 7 Bit 0 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean:1; /* Byte 7 Bit 2 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean RelAdr:1; /* Byte 7 Bit 7 */ + unsigned char VendorIdentification[8]; /* Bytes 8-15 */ + unsigned char ProductIdentification[16]; /* Bytes 16-31 */ + unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ }; /* @@ -1226,7 +1175,7 @@ static inline void BusLogic_AcquireHostAdapterLock(struct BusLogic_HostAdapter *HostAdapter) { - spin_lock_irq(HostAdapter->SCSI_Host->host_lock); + spin_lock_irq(HostAdapter->SCSI_Host->host_lock); } /* @@ -1235,7 +1184,7 @@ static inline void BusLogic_ReleaseHostAdapterLock(struct BusLogic_HostAdapter *HostAdapter) { - spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); + spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); } @@ -1244,10 +1193,9 @@ but is only called from the interrupt handler. */ -static inline void BusLogic_AcquireHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, - unsigned long *ProcessorFlags) +static inline void BusLogic_AcquireHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, unsigned long *ProcessorFlags) { - spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); + spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); } @@ -1256,10 +1204,9 @@ but is only called from the interrupt handler. */ -static inline void BusLogic_ReleaseHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, - unsigned long *ProcessorFlags) +static inline void BusLogic_ReleaseHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, unsigned long *ProcessorFlags) { - spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); + spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); } @@ -1270,65 +1217,60 @@ static inline void BusLogic_SCSIBusReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.SCSIBusReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.SCSIBusReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline void BusLogic_InterruptReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.InterruptReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.InterruptReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline void BusLogic_SoftReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.SoftReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.SoftReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline void BusLogic_HardReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.HardReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.HardReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline unsigned char BusLogic_ReadStatusRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_StatusRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_StatusRegisterOffset); } static inline void BusLogic_WriteCommandParameterRegister(struct BusLogic_HostAdapter - *HostAdapter, - unsigned char Value) + *HostAdapter, unsigned char Value) { - outb(Value, HostAdapter->IO_Address + BusLogic_CommandParameterRegisterOffset); + outb(Value, HostAdapter->IO_Address + BusLogic_CommandParameterRegisterOffset); } static inline unsigned char BusLogic_ReadDataInRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_DataInRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_DataInRegisterOffset); } static inline unsigned char BusLogic_ReadInterruptRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_InterruptRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_InterruptRegisterOffset); } static inline unsigned char BusLogic_ReadGeometryRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_GeometryRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_GeometryRegisterOffset); } /* @@ -1339,7 +1281,7 @@ static inline void BusLogic_StartMailboxCommand(struct BusLogic_HostAdapter *HostAdapter) { - BusLogic_WriteCommandParameterRegister(HostAdapter, BusLogic_ExecuteMailboxCommand); + BusLogic_WriteCommandParameterRegister(HostAdapter, BusLogic_ExecuteMailboxCommand); } /* @@ -1348,7 +1290,7 @@ static inline void BusLogic_Delay(int Seconds) { - mdelay(1000 * Seconds); + mdelay(1000 * Seconds); } /* @@ -1358,12 +1300,12 @@ static inline u32 Virtual_to_Bus(void *VirtualAddress) { - return (u32) virt_to_bus(VirtualAddress); + return (u32) virt_to_bus(VirtualAddress); } static inline void *Bus_to_Virtual(u32 BusAddress) { - return (void *) bus_to_virt(BusAddress); + return (void *) bus_to_virt(BusAddress); } /* @@ -1374,7 +1316,7 @@ static inline u32 Virtual_to_32Bit_Virtual(void *VirtualAddress) { - return (u32) (unsigned long) VirtualAddress; + return (u32) (unsigned long) VirtualAddress; } /* @@ -1384,7 +1326,8 @@ static inline void BusLogic_IncrementErrorCounter(unsigned short *ErrorCounter) { - if (*ErrorCounter < 65535) (*ErrorCounter)++; + if (*ErrorCounter < 65535) + (*ErrorCounter)++; } /* @@ -1392,40 +1335,35 @@ */ static inline void BusLogic_IncrementByteCounter(struct BusLogic_ByteCounter - *ByteCounter, - unsigned int Amount) + *ByteCounter, unsigned int Amount) { - ByteCounter->Units += Amount; - if (ByteCounter->Units > 999999999) - { - ByteCounter->Units -= 1000000000; - ByteCounter->Billions++; - } + ByteCounter->Units += Amount; + if (ByteCounter->Units > 999999999) { + ByteCounter->Units -= 1000000000; + ByteCounter->Billions++; + } } /* BusLogic_IncrementSizeBucket increments the Bucket for Amount. */ -static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T - CommandSizeBuckets, - unsigned int Amount) -{ - int Index = 0; - if (Amount < 8*1024) - { - if (Amount < 2*1024) - Index = (Amount < 1*1024 ? 0 : 1); - else Index = (Amount < 4*1024 ? 2 : 3); - } - else if (Amount < 128*1024) - { - if (Amount < 32*1024) - Index = (Amount < 16*1024 ? 4 : 5); - else Index = (Amount < 64*1024 ? 6 : 7); - } - else Index = (Amount < 256*1024 ? 8 : 9); - CommandSizeBuckets[Index]++; +static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T CommandSizeBuckets, unsigned int Amount) +{ + int Index = 0; + if (Amount < 8 * 1024) { + if (Amount < 2 * 1024) + Index = (Amount < 1 * 1024 ? 0 : 1); + else + Index = (Amount < 4 * 1024 ? 2 : 3); + } else if (Amount < 128 * 1024) { + if (Amount < 32 * 1024) + Index = (Amount < 16 * 1024 ? 4 : 5); + else + Index = (Amount < 64 * 1024 ? 6 : 7); + } else + Index = (Amount < 256 * 1024 ? 8 : 9); + CommandSizeBuckets[Index]++; } /* @@ -1450,20 +1388,14 @@ static const char *BusLogic_DriverInfo(struct Scsi_Host *); static int BusLogic_DetectHostAdapter(struct scsi_host_template *); static int BusLogic_ReleaseHostAdapter(struct Scsi_Host *); -static int BusLogic_QueueCommand(struct scsi_cmnd *, - void (*CompletionRoutine)(struct scsi_cmnd *)); -static int BusLogic_BIOSDiskParameters(struct scsi_device *, - struct block_device *, - sector_t, int *); -static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, - char **, off_t, int, int); +static int BusLogic_QueueCommand(struct scsi_cmnd *, void (*CompletionRoutine) (struct scsi_cmnd *)); +static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *); +static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int); static int BusLogic_SlaveConfigure(struct scsi_device *); static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *); static irqreturn_t BusLogic_InterruptHandler(int, void *, struct pt_regs *); -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, - boolean HardReset); -static void BusLogic_Message(enum BusLogic_MessageLevel, char *, - struct BusLogic_HostAdapter *, ...); +static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset); +static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...); static int __init BusLogic_Setup(char *); -#endif /* _BUSLOGIC_H */ +#endif /* _BUSLOGIC_H */ diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig 2004-10-18 14:57:03 -07:00 +++ b/drivers/scsi/Kconfig 2004-10-18 14:57:03 -07:00 @@ -320,7 +320,7 @@ config SCSI_AIC7XXX_OLD tristate "Adaptec AIC7xxx support (old driver)" - depends on SCSI + depends on (ISA || EISA || PCI ) && SCSI help WARNING This driver is an older aic7xxx driver and is no longer under active development. Adaptec, Inc. is writing a new driver to @@ -395,15 +395,7 @@ To compile this driver as a module, choose M here: the module will be called in2000. -config SCSI_MEGARAID - tristate "AMI MegaRAID support" - depends on PCI && SCSI - help - This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490 - and 467 SCSI host adapters. - - To compile this driver as a module, choose M here: the - module will be called megaraid. +source "drivers/scsi/megaraid/Kconfig.megaraid" config SCSI_SATA bool "Serial ATA (SATA) support" @@ -595,7 +587,7 @@ config SCSI_EATA_PIO tristate "EATA-PIO (old DPT PM2001, PM2012A) support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI ---help--- This driver supports all EATA-PIO protocol compliant SCSI Host Adapters like the DPT PM2001 and the PM2012A. EATA-DMA compliant @@ -780,6 +772,15 @@ To compile this driver as a module, choose M here: the module will be called ips. +config SCSI_IBMVSCSI + tristate "IBM Virtual SCSI support" + depends on PPC_PSERIES || PPC_ISERIES + help + This is the IBM POWER Virtual SCSI Client + + To compile this driver as a module, choose M here: the + module will be called ibmvscsic. + config SCSI_INITIO tristate "Initio 9100U(W) support" depends on PCI && SCSI && BROKEN @@ -1462,7 +1463,7 @@ config SCSI_MESH tristate "MESH (Power Mac internal SCSI) support" - depends on PPC_PMAC && SCSI + depends on PPC32 && PPC_PMAC && SCSI help Many Power Macintoshes and clones have a MESH (Macintosh Enhanced SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the @@ -1507,7 +1508,7 @@ config JAZZ_ESP bool "MIPS JAZZ FAS216 SCSI support" - depends on MIPS_JAZZ && SCSI + depends on MACH_JAZZ && SCSI help This is the driver for the onboard SCSI host adapter of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile 2004-10-18 14:56:49 -07:00 +++ b/drivers/scsi/Makefile 2004-10-18 14:56:49 -07:00 @@ -95,7 +95,8 @@ obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o obj-$(CONFIG_SCSI_DC390T) += tmscsim.o -obj-$(CONFIG_SCSI_MEGARAID) += megaraid.o +obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o +obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o obj-$(CONFIG_SCSI_SUNESP) += esp.o obj-$(CONFIG_SCSI_GDTH) += gdth.o @@ -119,6 +120,7 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_IPR) += ipr.o +obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c --- a/drivers/scsi/NCR5380.c 2004-10-18 14:56:20 -07:00 +++ b/drivers/scsi/NCR5380.c 2004-10-18 14:56:20 -07:00 @@ -310,12 +310,8 @@ * possible) function may be used. Before the specific driver initialization * code finishes, NCR5380_print_options should be called. */ - static int do_abort(struct Scsi_Host *host); static void do_reset(struct Scsi_Host *host); -static struct NCR5380_hostdata *first_host = NULL; -static struct NCR5380_hostdata *last_host = NULL; -static struct timer_list usleep_timer; /* * initialize_SCp - init the scsi pointer field @@ -533,9 +529,6 @@ #define USLEEP_WAITLONG USLEEP_SLEEP #endif -static struct Scsi_Host *expires_first = NULL; -static spinlock_t timer_lock; /* Guards expires list */ - /* * Function : int should_disconnect (unsigned char cmd) * @@ -578,90 +571,10 @@ } } -/* - * Assumes instance->time_expires has been set in higher level code. - * We should move to a timer per host - * - * Locks: Takes the timer queue lock - */ - -static int NCR5380_set_timer(struct Scsi_Host *instance) +static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout) { - struct Scsi_Host *tmp, **prev; - unsigned long flags; - - if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) { - return -1; - } - - spin_lock_irqsave(&timer_lock, flags); - for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) - if (((struct NCR5380_hostdata *) instance->hostdata)->time_expires < ((struct NCR5380_hostdata *) tmp->hostdata)->time_expires) - break; - - ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp; - *prev = instance; - - mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires); - - spin_unlock_irqrestore(&timer_lock, flags); - return 0; -} - -/** - * NCR5380_timer_fn - handle polled timeouts - * @unused: unused - * - * Walk the list of controllers, find which controllers have exceeded - * their expiry timeout and then schedule the processing co-routine to - * do the real work. - * - * Doing something about unwanted reentrancy here might be useful - * - * Locks: disables irqs, takes and frees the timer lock - */ - -static void NCR5380_timer_fn(unsigned long unused) -{ - struct Scsi_Host *instance; - struct NCR5380_hostdata *hostdata; - unsigned long flags; - - spin_lock_irqsave(&timer_lock, flags); - for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) - { - hostdata = (struct NCR5380_hostdata *) expires_first->hostdata; - schedule_work(&hostdata->coroutine); - instance = hostdata->next_timer; - hostdata->next_timer = NULL; - hostdata->time_expires = 0; - expires_first = instance; - } - - del_timer(&usleep_timer); - if (expires_first) { - usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires; - add_timer(&usleep_timer); - } - spin_unlock_irqrestore(&timer_lock, flags); -} - -/** - * NCR5380_all_init - global setup - * - * Set up the global values and timers needed by the NCR5380 driver - */ - -static inline void NCR5380_all_init(void) -{ - static int done = 0; - if (!done) { - dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n")); - done = 1; - init_timer(&usleep_timer); - spin_lock_init(&timer_lock); - usleep_timer.function = NCR5380_timer_fn; - } + hostdata->time_expires = jiffies + timeout; + schedule_delayed_work(&hostdata->coroutine, hostdata->time_expires); } @@ -788,22 +701,6 @@ } /** - * NCR5380_coroutine_running - coroutine status - * @instance: controller to check - * - * Return true if the co-routine for this controller is running - * or scheduled to run - * - * FIXME: this test function belongs in the workqueue code! - */ - -static int NCR5380_coroutine_running(struct Scsi_Host *instance) -{ - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata; - return test_bit(0, &hostdata->coroutine.pending); -} - -/** * NCR5380_print_status - dump controller info * @instance: controller to dump * @@ -819,8 +716,6 @@ char *start; int len; - printk("NCR5380 : coroutine is%s running.\n", NCR5380_coroutine_running(instance)? "" : "n't"); - NCR5380_dprint(NDEBUG_ANY, instance); NCR5380_dprint_phase(NDEBUG_ANY, instance); @@ -900,7 +795,6 @@ SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi); #endif spin_lock_irq(instance->host_lock); - SPRINTF("NCR5380 : coroutine is%s running.\n", NCR5380_coroutine_running(instance) ? "" : "n't"); if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", instance->host_no); else @@ -912,7 +806,6 @@ SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - spin_unlock_irq(instance->host_lock); *start = buffer; @@ -964,7 +857,7 @@ * Locks: interrupts must be enabled when we are called */ -static int __init NCR5380_init(struct Scsi_Host *instance, int flags) +static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags) { NCR5380_local_declare(); int i, pass; @@ -984,7 +877,6 @@ #endif NCR5380_setup(instance); - NCR5380_all_init(); hostdata->aborted = 0; hostdata->id_mask = 1 << instance->this_id; @@ -1021,18 +913,8 @@ else hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags; - hostdata->next = NULL; - - if (!first_host) - first_host = hostdata; - else - last_host->next = hostdata; - - last_host = hostdata; - hostdata->host = instance; hostdata->time_expires = 0; - hostdata->next_timer = NULL; #ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) @@ -1089,6 +971,19 @@ } /** + * NCR5380_exit - remove an NCR5380 + * @instance: adapter to remove + */ + +static void __devexit NCR5380_exit(struct Scsi_Host *instance) +{ + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; + + cancel_delayed_work(&hostdata->coroutine); + flush_scheduled_work(); +} + +/** * NCR5380_queue_command - queue a command * @cmd: SCSI command * @done: completion handler @@ -1169,6 +1064,7 @@ return 0; } + /** * NCR5380_main - NCR state machines * @@ -1184,28 +1080,11 @@ static void NCR5380_main(void *p) { struct NCR5380_hostdata *hostdata = p; + struct Scsi_Host *instance = hostdata->host; Scsi_Cmnd *tmp, *prev; - struct Scsi_Host *instance; int done; - unsigned long flags = 0; - /* - * We run (with interrupts disabled) until we're sure that none of - * the host adapters have anything that can be done, at which point - * we can exit - * - * Interrupts are enabled before doing various other internal - * instructions, after we've decided that we need to run through - * the loop again. - * - * this should prevent any race conditions. - */ - - instance = hostdata->host; - - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irqsave(instance->host_lock, flags); - + spin_lock_irq(instance->host_lock); do { /* Lock held here */ done = 1; @@ -1286,8 +1165,7 @@ LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; - hostdata->time_expires = jiffies + USLEEP_WAITLONG; - NCR5380_set_timer(instance); + NCR5380_set_timer(hostdata, USLEEP_WAITLONG); } } /* if hostdata->selecting */ if (hostdata->connected @@ -1304,8 +1182,7 @@ break; } while (!done); - if(instance->irq != SCSI_IRQ_NONE) - spin_unlock_irqrestore(instance->host_lock, flags); + spin_unlock_irq(instance->host_lock); } #ifndef DONT_USE_INTR @@ -1330,12 +1207,13 @@ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; int done; unsigned char basr; + unsigned long flags; dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq)); do { done = 1; - spin_lock_irq(instance->host_lock); + spin_lock_irqsave(instance->host_lock, flags); /* Look for pending interrupts */ NCR5380_setup(instance); basr = NCR5380_read(BUS_AND_STATUS_REG); @@ -1386,7 +1264,7 @@ #endif } } /* if BASR_IRQ */ - spin_unlock_irq(instance->host_lock); + spin_unlock_irqrestore(instance->host_lock, flags); if(!done) schedule_work(&hostdata->coroutine); } while (!done); @@ -1469,12 +1347,8 @@ int err; NCR5380_setup(instance); - if (hostdata->selecting) { - if(instance->irq != SCSI_IRQ_NONE) - spin_unlock_irq(instance->host_lock); - goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the - rest of the code nearly the same */ - } + if (hostdata->selecting) + goto part2; hostdata->restart_select = 0; @@ -1495,16 +1369,12 @@ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(MODE_REG, MR_ARBITRATE); - if(instance->irq != SCSI_IRQ_NONE) - spin_unlock_irq(instance->host_lock); /* We can be relaxed here, interrupts are on, we are in workqueue context, the birds are singing in the trees */ - + spin_unlock_irq(instance->host_lock); err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ); - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); - + spin_lock_irq(instance->host_lock); if (err < 0) { printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); @@ -1628,8 +1498,7 @@ if (!value && (hostdata->select_time < HZ/4)) { /* RvC: we still must wait for a device response */ hostdata->select_time++; /* after 25 ticks the device has failed */ - hostdata->time_expires = jiffies + 1; - NCR5380_set_timer(instance); + NCR5380_set_timer(hostdata, 1); return 0; /* RvC: we return here with hostdata->selecting set, to go to sleep */ } @@ -1638,8 +1507,6 @@ waiting period */ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); NCR5380_reselect(instance); printk("scsi%d : reselection after won arbitration?\n", instance->host_no); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1665,8 +1532,6 @@ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); cmd->result = DID_BAD_TARGET << 16; collect_stats(hostdata, cmd); cmd->scsi_done(cmd); @@ -1693,11 +1558,13 @@ */ /* Wait for start of REQ/ACK handshake */ - + + spin_unlock_irq(instance->host_lock); err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); + spin_lock_irq(instance->host_lock); - if(err) - { printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); + if(err) { + printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); goto failed; } @@ -1705,9 +1572,6 @@ dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id)); tmp[0] = IDENTIFY(((instance->irq == SCSI_IRQ_NONE) ? 0 : 1), cmd->device->lun); - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); - len = 1; cmd->tag = 0; @@ -1720,15 +1584,14 @@ hostdata->connected = cmd; hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - initialize_SCp(cmd); - + if (cmd->SCp.ptr != (char *)cmd->sense_buffer) { + initialize_SCp(cmd); + } return 0; /* Selection failed */ failed: - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); return -1; } @@ -1804,8 +1667,7 @@ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed); if (!(tmp & SR_REQ)) { /* timeout condition */ - hostdata->time_expires = jiffies + USLEEP_SLEEP; - NCR5380_set_timer(instance); + NCR5380_set_timer(hostdata, USLEEP_SLEEP); break; } @@ -2643,9 +2505,8 @@ */ NCR5380_transfer_pio(instance, &phase, &len, &data); if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) { - hostdata->time_expires = jiffies + USLEEP_SLEEP; + NCR5380_set_timer(hostdata, USLEEP_SLEEP); dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); - NCR5380_set_timer(instance); return; } break; @@ -2664,9 +2525,8 @@ /* RvC: go to sleep if polling time expired */ if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { - hostdata->time_expires = jiffies + USLEEP_SLEEP; + NCR5380_set_timer(hostdata, USLEEP_SLEEP); dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); - NCR5380_set_timer(instance); return; } } diff -Nru a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h --- a/drivers/scsi/NCR5380.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/scsi/NCR5380.h 2004-10-18 14:56:32 -07:00 @@ -251,7 +251,6 @@ struct NCR5380_hostdata { NCR5380_implementation_fields; /* implementation specific */ struct Scsi_Host *host; /* Host backpointer */ - struct NCR5380_hostdata *next; /* Next in our hot chain */ unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ unsigned char targets_present; /* targets we have connected to, so we can call a select @@ -270,7 +269,6 @@ volatile unsigned aborted:1; /* flag, says aborted */ int flags; unsigned long time_expires; /* in jiffies, set prior to sleeping */ - struct Scsi_Host *next_timer; int select_time; /* timer in select for target response */ volatile Scsi_Cmnd *selecting; struct work_struct coroutine; /* our co-routine */ @@ -295,6 +293,7 @@ static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); #endif static int NCR5380_init(struct Scsi_Host *instance, int flags); +static void NCR5380_exit(struct Scsi_Host *instance); static void NCR5380_information_transfer(struct Scsi_Host *instance); #ifndef DONT_USE_INTR static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c --- a/drivers/scsi/NCR53C9x.c 2004-10-18 14:56:19 -07:00 +++ b/drivers/scsi/NCR53C9x.c 2004-10-18 14:56:19 -07:00 @@ -94,7 +94,7 @@ }; /* The master ring of all esp hosts we are managing in this driver. */ -struct NCR_ESP *espchain = 0; +struct NCR_ESP *espchain; int nesps = 0, esps_in_use = 0, esps_running = 0; irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs); @@ -555,7 +555,7 @@ } else { espchain = esp; } - esp->next = 0; + esp->next = NULL; return esp; } @@ -565,7 +565,7 @@ struct NCR_ESP *elink; if(espchain == esp) { - espchain = 0; + espchain = NULL; } else { for(elink = espchain; elink && (elink->next != esp); elink = elink->next); if(elink) @@ -708,9 +708,9 @@ } /* Initialize the command queues */ - esp->current_SC = 0; - esp->disconnected_SC = 0; - esp->issue_SC = 0; + esp->current_SC = NULL; + esp->disconnected_SC = NULL; + esp->issue_SC = NULL; /* Clear the state machines. */ esp->targets_present = 0; @@ -1728,7 +1728,7 @@ ESPLOG(("esp%d: Weird, being reselected but disconnected " "command queue is empty.\n", esp->esp_id)); esp->snip = 0; - esp->current_SC = 0; + esp->current_SC = NULL; sp->SCp.phase = not_issued; append_SC(&esp->issue_SC, sp); } @@ -3393,7 +3393,7 @@ } static espfunc_t isvc_vector[] = { - 0, + NULL, esp_do_phase_determine, esp_do_resetbus, esp_finish_reset, diff -Nru a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c --- a/drivers/scsi/NCR53c406a.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/scsi/NCR53c406a.c 2004-10-18 14:56:31 -07:00 @@ -606,22 +606,24 @@ } /* called from init/main.c */ -static void __init NCR53c406a_setup(char *str, int *ints) +static int __init NCR53c406a_setup(char *str) { static size_t setup_idx = 0; size_t i; + int ints[4]; DEB(printk("NCR53c406a: Setup called\n"); ); if (setup_idx >= PORT_COUNT - 1) { printk("NCR53c406a: Setup called too many times. Bad LILO params?\n"); - return; + return 0; } + get_options(str, 4, ints); if (ints[0] < 1 || ints[0] > 3) { printk("NCR53c406a: Malformed command line\n"); printk("NCR53c406a: Usage: ncr53c406a=[,[,]]\n"); - return; + return 0; } for (i = 0; i < PORT_COUNT && !port_base; i++) if (ports[i] == ints[1]) { @@ -631,7 +633,7 @@ } if (!port_base) { printk("NCR53c406a: Invalid PORTBASE 0x%x specified\n", ints[1]); - return; + return 0; } if (ints[0] > 1) { @@ -654,6 +656,7 @@ fast_pio = ints[3]; DEB(printk("NCR53c406a: port_base=0x%x, irq=%d, fast_pio=%d\n", port_base, irq_level, fast_pio);) + return 1; } __setup("ncr53c406a=", NCR53c406a_setup); diff -Nru a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c --- a/drivers/scsi/NCR_Q720.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/scsi/NCR_Q720.c 2004-10-18 14:55:55 -07:00 @@ -216,7 +216,21 @@ goto out_free; } - mem_base = (__u32)ioremap(base_addr, mem_size); + if (dma_declare_coherent_memory(dev, base_addr, base_addr, + mem_size, DMA_MEMORY_MAP) + != DMA_MEMORY_MAP) { + printk(KERN_ERR "NCR_Q720: DMA declare memory failed\n"); + goto out_release_region; + } + + /* The first 1k of the memory buffer is a memory map of the registers + */ + mem_base = (__u32)dma_mark_declared_memory_occupied(dev, base_addr, + 1024); + if (IS_ERR((void *)mem_base)) { + printk("NCR_Q720 failed to reserve memory mapped region\n"); + goto out_release; + } /* now also enable accesses in asr 2 */ asr2 = inb(io_base + 0x0a); @@ -296,7 +310,8 @@ return 0; out_release: - iounmap((void *)mem_base); + dma_release_declared_memory(dev); + out_release_region: release_mem_region(base_addr, mem_size); out_free: kfree(p); @@ -321,7 +336,7 @@ if(p->hosts[i]) NCR_Q720_remove_one(p->hosts[i]); - iounmap((void *)p->mem_base); + dma_release_declared_memory(dev); release_mem_region(p->phys_mem_base, p->mem_size); free_irq(p->irq, p); kfree(p); diff -Nru a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README --- a/drivers/scsi/aacraid/README 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/aacraid/README 2004-10-18 14:55:54 -07:00 @@ -10,14 +10,23 @@ Supported Cards/Chipsets ------------------------- - AAR-2410SA SATA + Adaptec 2020S + Adaptec 2025S Adaptec 2120S Adaptec 2200S Adaptec 2230S + Adaptec 2240S + Adaptec 2410SA + Adaptec 2610SA + Adaptec 2810SA + Adaptec 21610SA Adaptec 3230S Adaptec 3240S + Adaptec 4000SAS + Adaptec 4005SAS + Adaptec 4800SAS + Adaptec 4805SAS Adaptec 5400S - ASR-2020S PCI-X Dell PERC 2 Quad Channel Dell PERC 2/Si Dell PERC 3/Si @@ -49,7 +58,6 @@ Mailing List ------------------------- linux-scsi@vger.kernel.org (Interested parties troll here) -http://mbserver.adaptec.com/ (Currently more Community Support than Devel Support) Also note this is very different to Brian's original driver so don't expect him to support it. Adaptec does support this driver. Contact either tech support or Mark Salyzyn. diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c --- a/drivers/scsi/aacraid/aachba.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/scsi/aacraid/aachba.c 2004-10-18 14:56:29 -07:00 @@ -179,6 +179,20 @@ static char *aac_get_status_string(u32 status); #endif +/* + * Non dasd selection is handled entirely in aachba now + */ + +MODULE_PARM(nondasd, "i"); +MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); +MODULE_PARM(dacmode, "i"); +MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); +MODULE_PARM(commit, "i"); +MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on"); + +static int nondasd = -1; +static int dacmode = -1; + /** * aac_get_containers - list containers * @common: adapter to probe @@ -481,8 +495,7 @@ dev->nondasd_support = 0; if(dev->adapter_info.options & AAC_OPT_NONDASD){ -// dev->nondasd_support = 1; -// dmb - temporarily disable nondasd + dev->nondasd_support = 1; } if(nondasd != -1) { dev->nondasd_support = (nondasd!=0); @@ -491,18 +504,30 @@ printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); } - dev->pae_support = 0; + dev->dac_support = 0; if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){ printk(KERN_INFO "%s%d: 64bit support enabled.\n", dev->name, dev->id); - dev->pae_support = 1; + dev->dac_support = 1; } - if(paemode != -1){ - dev->pae_support = (paemode!=0); + if(dacmode != -1) { + dev->dac_support = (dacmode!=0); } - if(dev->pae_support != 0) { - printk(KERN_INFO"%s%d: 64 Bit PAE enabled\n", dev->name, dev->id); - pci_set_dma_mask(dev->pdev, (dma_addr_t)0xFFFFFFFFFFFFFFFFULL); + if(dev->dac_support != 0) { + if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL) && + !pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL)) { + printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n", + dev->name, dev->id); + } else if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFULL) && + !pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFULL)) { + printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n", + dev->name, dev->id); + dev->dac_support = 0; + } else { + printk(KERN_WARNING"%s%d: No suitable DMA available.\n", + dev->name, dev->id); + rcode = -ENOMEM; + } } fib_complete(fibptr); @@ -537,7 +562,7 @@ scsicmd->use_sg, scsicmd->sc_data_direction); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr, + pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen, scsicmd->sc_data_direction); readreply = (struct aac_read_reply *)fib_data(fibptr); @@ -582,7 +607,7 @@ scsicmd->use_sg, scsicmd->sc_data_direction); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr, + pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen, scsicmd->sc_data_direction); @@ -644,7 +669,7 @@ fib_init(cmd_fibcontext); - if(dev->pae_support == 1){ + if(dev->dac_support == 1) { struct aac_read64 *readcmd; readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext); readcmd->command = cpu_to_le32(VM_CtHostRead64); @@ -752,7 +777,7 @@ } fib_init(cmd_fibcontext); - if(dev->pae_support == 1){ + if(dev->dac_support == 1) { struct aac_write64 *writecmd; writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext); writecmd->command = cpu_to_le32(VM_CtHostWrite64); @@ -1220,7 +1245,7 @@ scsicmd->use_sg, scsicmd->sc_data_direction); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (ulong)scsicmd->SCp.ptr, scsicmd->request_bufflen, + pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen, scsicmd->sc_data_direction); /* @@ -1348,7 +1373,12 @@ case SRB_STATUS_DOMAIN_VALIDATION_FAIL: default: #ifdef AAC_DETAILED_STATUS_INFO - printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",le32_to_cpu(srbreply->srb_status&0x3f),aac_get_status_string(le32_to_cpu(srbreply->srb_status)), scsicmd->cmnd[0], le32_to_cpu(srbreply->scsi_status) ); + printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", + le32_to_cpu(srbreply->srb_status & 0x3F), + aac_get_status_string( + le32_to_cpu(srbreply->srb_status) & 0x3F), + scsicmd->cmnd[0], + le32_to_cpu(srbreply->scsi_status)); #endif scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; break; @@ -1358,7 +1388,10 @@ scsicmd->result |= SAM_STAT_CHECK_CONDITION; len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))? sizeof(scsicmd->sense_buffer):srbreply->sense_data_size; - dprintk((KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", le32_to_cpu(srbreply->status), len)); +#ifdef AAC_DETAILED_STATUS_INFO + dprintk((KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", + le32_to_cpu(srbreply->status), len)); +#endif memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); } @@ -1437,7 +1470,7 @@ srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len); - if( dev->pae_support ==1 ) { + if( dev->dac_support == 1 ) { aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg); srbcmd->count = cpu_to_le32(scsicmd->request_bufflen); @@ -1532,7 +1565,7 @@ psg->count = cpu_to_le32(1); psg->sg[0].addr = cpu_to_le32(addr); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)(ulong)addr; + scsicmd->SCp.dma_handle = addr; byte_count = scsicmd->request_bufflen; } return byte_count; @@ -1593,7 +1626,7 @@ psg->sg[0].addr[1] = (u32)(le_addr>>32); psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)(ulong)addr; + scsicmd->SCp.dma_handle = addr; byte_count = scsicmd->request_bufflen; } return byte_count; diff -Nru a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h --- a/drivers/scsi/aacraid/aacraid.h 2004-10-18 14:56:19 -07:00 +++ b/drivers/scsi/aacraid/aacraid.h 2004-10-18 14:56:19 -07:00 @@ -28,10 +28,7 @@ #define aac_phys_to_logical(x) (x+1) #define aac_logical_to_phys(x) (x?x-1:0) -#define AAC_DETAILED_STATUS_INFO - -extern int nondasd; -extern int paemode; +/* #define AAC_DETAILED_STATUS_INFO */ struct diskparm { @@ -404,15 +401,15 @@ }; enum aac_log_level { - LOG_INIT = 10, - LOG_INFORMATIONAL = 20, - LOG_WARNING = 30, - LOG_LOW_ERROR = 40, - LOG_MEDIUM_ERROR = 50, - LOG_HIGH_ERROR = 60, - LOG_PANIC = 70, - LOG_DEBUG = 80, - LOG_WINDBG_PRINT = 90 + LOG_AAC_INIT = 10, + LOG_AAC_INFORMATIONAL = 20, + LOG_AAC_WARNING = 30, + LOG_AAC_LOW_ERROR = 40, + LOG_AAC_MEDIUM_ERROR = 50, + LOG_AAC_HIGH_ERROR = 60, + LOG_AAC_PANIC = 70, + LOG_AAC_DEBUG = 80, + LOG_AAC_WINDBG_PRINT = 90 }; #define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT 0x030b @@ -841,7 +838,7 @@ * lets break them out so we don't have to do an AND to check them */ u8 nondasd_support; - u8 pae_support; + u8 dac_support; }; #define AllocateAndMapFibSpace(dev, MapFibContext) \ diff -Nru a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c --- a/drivers/scsi/aacraid/commctrl.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/aacraid/commctrl.c 2004-10-18 14:56:28 -07:00 @@ -480,7 +480,7 @@ default: data_dir = DMA_NONE; } - if (dev->pae_support == 1) { + if (dev->dac_support == 1) { struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; byte_count = 0; diff -Nru a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c --- a/drivers/scsi/aacraid/commsup.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/scsi/aacraid/commsup.c 2004-10-18 14:56:48 -07:00 @@ -761,7 +761,7 @@ length = 255; if (cp[length] != 0) cp[length] = 0; - if (level == LOG_HIGH_ERROR) + if (level == LOG_AAC_HIGH_ERROR) printk(KERN_WARNING "aacraid:%s", cp); else printk(KERN_INFO "aacraid:%s", cp); diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/aacraid/linit.c 2004-10-18 14:56:28 -07:00 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -62,15 +63,7 @@ "Adaptec Advanced Raid Products, " "and HP NetRAID-4M SCSI driver"); MODULE_LICENSE("GPL"); - - -int nondasd = -1; -module_param(nondasd, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); - -int paemode = -1; -module_param(paemode, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(paemode, "Control whether dma addressing is using PAE. 0=off, 1=on"); +MODULE_VERSION(AAC_DRIVER_VERSION); struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS]; static unsigned aac_count; @@ -83,44 +76,54 @@ * Note: The last field is used to index into aac_drivers below. */ static struct pci_device_id aac_pci_tbl[] = { - { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si */ - { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di */ - { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si */ - { 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Si */ - { 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di */ - { 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di */ - { 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di */ - { 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di */ - { 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di */ - { 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult*/ - { 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat*/ - { 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader)*/ - { 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan)*/ - { 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m)*/ - { 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220*/ - { 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230*/ - - { 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier)*/ - { 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado)*/ - { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020 ZCR PCI-X U320 */ - { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025 ZCR DIMM U320 */ - { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 20 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ - - { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 21 }, /* Perc 320/DC*/ - { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 22 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 23 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 24 }, /* Dell PERC2 "Quad Channel" */ - { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 25 }, /* HP NetRAID-4M */ - + { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */ + { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */ + { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */ + { 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ + { 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di (Viper/PERC3DiV) */ + { 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di (Lexus/PERC3DiL) */ + { 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ + { 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di (Dagger/PERC3DiD) */ + { 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di (Boxster/PERC3DiB) */ + { 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult */ + { 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat */ + { 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader) */ + { 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan) */ + { 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m) */ + { 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220 (Legend Crusader) */ + { 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230 (Legend Vulcan) */ + + { 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier) */ + { 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado) */ + { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */ + { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ + { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 20 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { 0x9005, 0x0286, 0x9005, 0x028d, 0, 0, 21 }, /* ASR-2130S (Lancer) */ + { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 22 }, /* Jupiter Platform */ + { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 23 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ + { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 24 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ + { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 25 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 26 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 27 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 28 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 29 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* SATA 6Ch (Bearcat) */ - - { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 31 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ - { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 32 }, /* ASR-2020SA (ZCR PCI-X SATA) */ - { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 33 }, /* ASR-2025SA (ZCR DIMM SATA) */ + { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* AAR-2610SA PCI SATA 6ch */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 31 }, /* ASR-2240S */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 32 }, /* ASR-4005SAS */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 33 }, /* ASR-4000SAS */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 34 }, /* ASR-4800SAS */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 35 }, /* ASR-4805SAS */ + + { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 36 }, /* Perc 320/DC*/ + { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 37 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 38 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 39 }, /* Dell PERC2/QC */ + { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 40 }, /* HP NetRAID-4M */ + + { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 41 }, /* Dell Catchall */ + { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 42 }, /* Legend Catchall */ + { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 43 }, /* Adaptec Catch All */ + { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 44 }, /* Adaptec Rocket Catch All */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -131,44 +134,54 @@ * for the card. At that time we can remove the channels from here */ static struct aac_driver_ident aac_drivers[] = { - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 2/Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT }, /* catapult*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT }, /* tomcat*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT }, /* Adaptec 2120S (Crusader)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan-2m)*/ - { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT }, /* Legend S220*/ - { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT }, /* Legend S230*/ - - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020ZCR ", 2 }, /* ASR-2020 ZCR PCI-X U320 */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025 ZCR DIMM U320 */ - { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 2 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ - - { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4 }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4 }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT }, /* Dell PERC2 "Quad Channel" */ - { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4 }, /* HP NetRAID-4M */ - + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 2/Si (Iguana/PERC2Si) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Opal/PERC3Di) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Si (SlimFast/PERC3Si */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Viper/PERC3DiV) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Lexus/PERC3DiL) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Dagger/PERC3DiD) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Boxster/PERC3DiB) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT }, /* catapult */ + { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT }, /* tomcat */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT }, /* Adaptec 2120S (Crusader) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan-2m) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT }, /* Legend S220 (Legend Crusader) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT }, /* Legend S230 (Legend Vulcan) */ + + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020ZCR ", 2 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2130S PCI-X ", 1 }, /* ASR-2130S (Lancer) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2 }, /* Jupiter Platform */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ { aac_rx_init, "aacraid", "DELL ", "CERC SR2 ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ { aac_rx_init, "aacraid", "ADAPTEC ", "SO-DIMM SATA ZCR", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "SATA 6Channel ", 1 }, /* SATA 6Ch (Bearcat) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2610SA ", 1 }, /* SATA 6Ch (Bearcat) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS */ - { aac_rkt_init,"aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA (ZCR PCI-X SATA) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA (ZCR DIMM SATA) */ + { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/ + { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4 }, /* Adaptec 5400S (Mustang)*/ + { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4 }, /* Adaptec 5400S (Mustang)*/ + { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT }, /* Dell PERC2/QC */ + { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4 }, /* HP NetRAID-4M */ + + { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Dell Catchall */ + { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Legend Catchall */ + { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Adaptec Catch All */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec Rocket Catch All */ }; #ifdef CONFIG_COMPAT @@ -408,15 +421,17 @@ } } spin_unlock_irqrestore(&dev->list_lock, flags); + if (active) + break; - /* - * We can exit If all the commands are complete - */ - if (active == 0) - return SUCCESS; } + /* + * We can exit If all the commands are complete + */ + if (active == 0) + return SUCCESS; spin_unlock_irq(host->host_lock); - scsi_sleep(HZ); + ssleep(1); spin_lock_irq(host->host_lock); } printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c --- a/drivers/scsi/advansys.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/scsi/advansys.c 2004-10-18 14:56:27 -07:00 @@ -15,16 +15,6 @@ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) * changed its name to ConnectCom Solutions, Inc. * - * There is an AdvanSys Linux WWW page at: - * http://www.connectcom.net/downloads/software/os/linux.html - * http://www.advansys.com/linux.html - * - * The latest released version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux/linux.tgz - * ftp://ftp.connectcom.net/pub/linux/linux.tgz - * - * Please send questions, comments, bug reports to: - * support@connectcom.net */ /* @@ -41,7 +31,6 @@ H. Release History I. Known Problems/Fix List J. Credits (Chronological Order) - K. ConnectCom (AdvanSys) Contact Information A. Linux Kernels Supported by this Driver @@ -2032,9 +2021,6 @@ #define ADV_LIB_VERSION_MAJOR 5 #define ADV_LIB_VERSION_MINOR 14 -/* d_os_dep.h */ -#define ADV_OS_LINUX - /* * Define Adv Library required special types. */ @@ -3370,9 +3356,9 @@ /* * Default EEPROM Configuration structure defined in a_init.c. */ -extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; -extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; -extern ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; +static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; +static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; +static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; /* * DvcGetPhyAddr() flag arguments diff -Nru a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h --- a/drivers/scsi/advansys.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/advansys.h 2004-10-18 14:57:04 -07:00 @@ -13,36 +13,10 @@ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) * changed its name to ConnectCom Solutions, Inc. * - * There is an AdvanSys Linux WWW page at: - * http://www.connectcom.net/downloads/software/os/linux.html - * http://www.advansys.com/linux.html - * - * The latest released version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux/linux.tgz - * ftp://ftp.connectcom.net/pub/linux/linux.tgz - * - * Please send questions, comments, bug reports to: - * linux@connectcom.net or bfrey@turbolinux.com.cn */ #ifndef _ADVANSYS_H #define _ADVANSYS_H - -#include -#ifndef LINUX_VERSION_CODE -#include -#endif /* LINUX_VERSION_CODE */ - -/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) -/* Driver supported only in version 2.2 and version >= 2.4. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \ - (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \ - LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) -#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels." -#endif -#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) -#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0)) /* * Scsi_Host_Template function prototypes. diff -Nru a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c --- a/drivers/scsi/aha1542.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/scsi/aha1542.c 2004-10-18 14:56:32 -07:00 @@ -1479,7 +1479,7 @@ * we are pretty desperate anyways. */ spin_unlock_irq(SCpnt->device->host->host_lock); - scsi_sleep(4 * HZ); + ssleep(4); spin_lock_irq(SCpnt->device->host->host_lock); WAIT(STATUS(SCpnt->device->host->io_port), @@ -1543,7 +1543,7 @@ * we are pretty desperate anyways. */ spin_unlock_irq(SCpnt->device->host->host_lock); - scsi_sleep(4 * HZ); + ssleep(4); spin_lock_irq(SCpnt->device->host->host_lock); WAIT(STATUS(SCpnt->device->host->io_port), diff -Nru a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h --- a/drivers/scsi/aha1542.h 2004-10-18 14:56:48 -07:00 +++ b/drivers/scsi/aha1542.h 2004-10-18 14:56:48 -07:00 @@ -91,10 +91,12 @@ }; /* These belong in scsi.h also */ -#define any2scsi(up, p) \ -(up)[0] = (((unsigned long)(p)) >> 16) ; \ -(up)[1] = (((unsigned long)(p)) >> 8); \ -(up)[2] = ((unsigned long)(p)); +static inline void any2scsi(u8 *p, u32 v) +{ + p[0] = v >> 16; + p[1] = v >> 8; + p[2] = v; +} #define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) diff -Nru a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx 2004-10-18 14:56:29 -07:00 +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx 2004-10-18 14:56:29 -07:00 @@ -46,7 +46,7 @@ config AIC79XX_BUILD_FIRMWARE bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC79XX + depends on SCSI_AIC79XX && !PREVENT_FIRMWARE_BUILD help This option should only be enabled if you are modifying the firmware source to the aic79xx driver and wish to have the generated firmware diff -Nru a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx 2004-10-18 14:56:28 -07:00 @@ -61,7 +61,7 @@ config AIC7XXX_BUILD_FIRMWARE bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC7XXX + depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD help This option should only be enabled if you are modifying the firmware source to the aic7xxx driver and wish to have the generated firmware diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c --- a/drivers/scsi/aic7xxx/aic79xx_osm.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c 2004-10-18 14:56:32 -07:00 @@ -61,6 +61,7 @@ #endif #include /* For fetching system memory size */ +#include /* For ssleep/msleep */ /* * Lock protecting manipulation of the ahd softc list. @@ -415,7 +416,6 @@ /* * Module information and settable options. */ -#ifdef MODULE static char *aic79xx = NULL; /* * Just in case someone uses commas to separate items on the insmod @@ -426,9 +426,8 @@ MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual BSD/GPL"); -#endif +MODULE_VERSION(AIC79XX_DRIVER_VERSION); MODULE_PARM(aic79xx, "s"); MODULE_PARM_DESC(aic79xx, "period delimited, options string.\n" @@ -463,7 +462,6 @@ " Change Read Streaming for Controller's 2 and 3\n" "\n" " options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'"); -#endif static void ahd_linux_handle_scsi_status(struct ahd_softc *, struct ahd_linux_device *, @@ -513,9 +511,6 @@ struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ); -static __inline int - ahd_linux_dv_fallback(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); static int ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, @@ -2915,6 +2910,19 @@ ahd_unlock(ahd, &s); } +static __inline int +ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) +{ + u_long s; + int retval; + + ahd_lock(ahd, &s); + retval = ahd_linux_fallback(ahd, devinfo); + ahd_unlock(ahd, &s); + + return (retval); +} + static void ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, @@ -3163,7 +3171,7 @@ break; } if (status & SSQ_DELAY) - scsi_sleep(1 * HZ); + ssleep(1); break; case SS_START: @@ -3323,7 +3331,7 @@ } if (targ->dv_state_retry <= 10) { if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) - scsi_sleep(ahd->our_id*HZ/10); + msleep(ahd->our_id*1000/10); break; } #ifdef AHD_DEBUG @@ -3367,7 +3375,7 @@ targ->dv_state_retry--; } else if (targ->dv_state_retry < 60) { if ((status & SSQ_DELAY) != 0) - scsi_sleep(1 * HZ); + ssleep(1); } else { #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_DV) { @@ -3549,19 +3557,6 @@ cmd->cmd_len = 6; cmd->cmnd[0] = START_STOP_UNIT; cmd->cmnd[4] = le | SSS_START; -} - -static __inline int -ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - u_long s; - int retval; - - ahd_lock(ahd, &s); - retval = ahd_linux_fallback(ahd, devinfo); - ahd_unlock(ahd, &s); - - return (retval); } static int diff -Nru a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c --- a/drivers/scsi/aic7xxx/aic79xx_pci.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c 2004-10-18 14:56:29 -07:00 @@ -452,8 +452,10 @@ * or read prefetching could be initiated by the * CPU or host bridge. Our device does not support * either, so look for data corruption and/or flaged - * PCI errors. + * PCI errors. First pause without causing another + * chip reset. */ + hcntrl &= ~CHIPRST; ahd_outb(ahd, HCNTRL, hcntrl|PAUSE); while (ahd_is_paused(ahd) == 0) ; diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c 2004-10-18 14:55:54 -07:00 @@ -140,6 +140,7 @@ #include /* For fetching system memory size */ #include /* For block_size() */ +#include /* For ssleep/msleep */ /* * Lock protecting manipulation of the ahc softc list. @@ -436,7 +437,6 @@ /* * Module information and settable options. */ -#ifdef MODULE static char *aic7xxx = NULL; /* * Just in case someone uses commas to separate items on the insmod @@ -447,9 +447,8 @@ MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual BSD/GPL"); -#endif +MODULE_VERSION(AIC7XXX_DRIVER_VERSION); MODULE_PARM(aic7xxx, "s"); MODULE_PARM_DESC(aic7xxx, "period delimited, options string.\n" @@ -479,7 +478,6 @@ "\n" " options aic7xxx 'aic7xxx=probe_eisa_vl.tag_info:{{}.{.10}}.seltime:1'\n" ); -#endif static void ahc_linux_handle_scsi_status(struct ahc_softc *, struct ahc_linux_device *, @@ -2825,7 +2823,7 @@ break; } if (status & SSQ_DELAY) - scsi_sleep(1 * HZ); + ssleep(1); break; case SS_START: @@ -2985,7 +2983,7 @@ } if (targ->dv_state_retry <= 10) { if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) - scsi_sleep(ahc->our_id*HZ/10); + msleep(ahc->our_id*1000/10); break; } #ifdef AHC_DEBUG @@ -3029,7 +3027,7 @@ targ->dv_state_retry--; } else if (targ->dv_state_retry < 60) { if ((status & SSQ_DELAY) != 0) - scsi_sleep(1 * HZ); + ssleep(1); } else { #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c 2004-10-18 14:55:54 -07:00 @@ -1284,8 +1284,10 @@ * or read prefetching could be initiated by the * CPU or host bridge. Our device does not support * either, so look for data corruption and/or flagged - * PCI errors. + * PCI errors. First pause without causing another + * chip reset. */ + hcntrl &= ~CHIPRST; ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); while (ahc_is_paused(ahc) == 0) ; diff -Nru a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile --- a/drivers/scsi/aic7xxx/aicasm/Makefile 2004-10-18 14:56:50 -07:00 +++ b/drivers/scsi/aic7xxx/aicasm/Makefile 2004-10-18 14:56:50 -07:00 @@ -34,10 +34,14 @@ $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) $(LIBS) aicdb.h: - @if [ -e "/usr/include/db3/db_185.h" ]; then \ + @if [ -e "/usr/include/db4/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db3/db_185.h" ]; then \ echo "#include " > aicdb.h; \ elif [ -e "/usr/include/db2/db_185.h" ]; then \ echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db1/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ elif [ -e "/usr/include/db/db_185.h" ]; then \ echo "#include " > aicdb.h; \ elif [ -e "/usr/include/db_185.h" ]; then \ diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c --- a/drivers/scsi/aic7xxx_old.c 2004-10-18 14:57:20 -07:00 +++ b/drivers/scsi/aic7xxx_old.c 2004-10-18 14:57:20 -07:00 @@ -10489,7 +10489,7 @@ aic_outb(p, lastphase | ATNO, SCSISIGO); unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(HZ); + ssleep(1); spin_lock_irq(p->host->host_lock); if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) return FAILED; @@ -10548,7 +10548,7 @@ aic_outb(p, saved_scbptr, SCBPTR); unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(HZ/4); + msleep(1000/4); spin_lock_irq(p->host->host_lock); if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) return FAILED; @@ -10786,7 +10786,7 @@ } unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(HZ/4); + msleep(1000/4); spin_lock_irq(p->host->host_lock); if (p->flags & AHC_ABORT_PENDING) { @@ -10887,7 +10887,7 @@ aic7xxx_run_done_queue(p, TRUE); unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(2 * HZ); + ssleep(2); spin_lock_irq(p->host->host_lock); return SUCCESS; } @@ -11139,6 +11139,7 @@ #include "aic7xxx_old/aic7xxx_proc.c" MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(AIC7XXX_H_VERSION); static Scsi_Host_Template driver_template = { diff -Nru a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c --- a/drivers/scsi/arm/cumana_1.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/arm/cumana_1.c 2004-10-18 14:55:54 -07:00 @@ -321,6 +321,7 @@ scsi_remove_host(host); free_irq(host->irq, host); + NCR5380_exit(host); release_region(host->io_port, host->n_io_port); scsi_host_put(host); } diff -Nru a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c --- a/drivers/scsi/arm/ecoscsi.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/arm/ecoscsi.c 2004-10-18 14:57:04 -07:00 @@ -222,6 +222,7 @@ if (shpnt->irq != IRQ_NONE) free_irq(shpnt->irq, NULL); + NCR5380_exit(host); if (shpnt->io_port) release_region(shpnt->io_port, shpnt->n_io_port); diff -Nru a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c --- a/drivers/scsi/arm/eesox.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/arm/eesox.c 2004-10-18 14:57:04 -07:00 @@ -231,7 +231,8 @@ * Align buffer. */ if (((u32)buf) & 2 && status >= 2) { - *((u16 *)buf)++ = readl(reg_dmadata); + *(u16 *)buf = readl(reg_dmadata); + buf += 2; status -= 2; length -= 2; } @@ -243,8 +244,10 @@ l1 |= readl(reg_dmadata) << 16; l2 = readl(reg_dmadata) & mask; l2 |= readl(reg_dmadata) << 16; - *((u32 *)buf)++ = l1; - *((u32 *)buf)++ = l2; + *(u32 *)buf = l1; + buf += 4; + *(u32 *)buf = l2; + buf += 4; length -= 8; continue; } @@ -255,13 +258,15 @@ l1 = readl(reg_dmadata) & mask; l1 |= readl(reg_dmadata) << 16; - *((u32 *)buf)++ = l1; + *(u32 *)buf = l1; + buf += 4; length -= 4; continue; } if (status >= 2) { - *((u16 *)buf)++ = readl(reg_dmadata); + *(u16 *)buf = readl(reg_dmadata); + buf += 2; length -= 2; } } while (length); @@ -305,7 +310,8 @@ * Align buffer. */ if (((u32)buf) & 2 && status >= 2) { - writel(*((u16 *)buf)++ << 16, reg_dmadata); + writel(*(u16 *)buf << 16, reg_dmadata); + buf += 2; status -= 2; length -= 2; } @@ -313,8 +319,10 @@ if (status >= 8) { unsigned long l1, l2; - l1 = *((u32 *)buf)++; - l2 = *((u32 *)buf)++; + l1 = *(u32 *)buf; + buf += 4; + l2 = *(u32 *)buf; + buf += 4; writel(l1 << 16, reg_dmadata); writel(l1, reg_dmadata); @@ -327,7 +335,8 @@ if (status >= 4) { unsigned long l1; - l1 = *((u32 *)buf)++; + l1 = *(u32 *)buf; + buf += 4; writel(l1 << 16, reg_dmadata); writel(l1, reg_dmadata); @@ -336,7 +345,8 @@ } if (status >= 2) { - writel(*((u16 *)buf)++ << 16, reg_dmadata); + writel(*(u16 *)buf << 16, reg_dmadata); + buf += 2; length -= 2; } } while (length); diff -Nru a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c --- a/drivers/scsi/arm/fas216.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/arm/fas216.c 2004-10-18 14:56:28 -07:00 @@ -2681,7 +2681,7 @@ * IRQs after the sleep. */ spin_unlock_irq(info->host->host_lock); - scsi_sleep(50 * HZ/100); + msleep(50 * 1000/100); spin_lock_irq(info->host->host_lock); /* @@ -2920,7 +2920,7 @@ * scsi standard says wait 250ms */ spin_unlock_irq(info->host->host_lock); - scsi_sleep(100*HZ/100); + msleep(100*1000/100); spin_lock_irq(info->host->host_lock); fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); diff -Nru a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c --- a/drivers/scsi/arm/oak.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/scsi/arm/oak.c 2004-10-18 14:55:46 -07:00 @@ -179,6 +179,7 @@ ecard_set_drvdata(ec, NULL); scsi_remove_host(host); + NCR5380_exit(host); release_region(host->io_port, host->n_io_port); scsi_host_put(host); } diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- a/drivers/scsi/ata_piix.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/scsi/ata_piix.c 2004-10-18 14:56:31 -07:00 @@ -39,6 +39,7 @@ ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ + PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ @@ -58,6 +59,7 @@ ich5_sata = 1, piix4_pata = 2, ich6_sata = 3, + ich6_sata_rm = 4, }; static int piix_init_one (struct pci_dev *pdev, @@ -65,10 +67,8 @@ static void piix_pata_phy_reset(struct ata_port *ap); static void piix_sata_phy_reset(struct ata_port *ap); -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); static unsigned int in_module_init = 1; @@ -87,13 +87,9 @@ { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, - - /* ICH6 operates in two modes, "looks-like-ICH5" mode, - * and enhanced mode, with queueing and other fancy stuff. - * This is distinguished by PCI class code. - */ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, - { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, { } /* terminate list */ }; @@ -108,6 +104,7 @@ static Scsi_Host_Template piix_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -126,17 +123,18 @@ static struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, + .set_dmamode = piix_set_dmamode, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = piix_pata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -151,18 +149,17 @@ static struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = piix_sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -181,7 +178,12 @@ .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, @@ -191,8 +193,9 @@ .sht = &piix_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, @@ -200,7 +203,12 @@ { .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, @@ -211,8 +219,21 @@ .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich6_sata_rm */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, }; @@ -368,11 +389,11 @@ * None (inherited from caller). */ -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) { + unsigned int pio = adev->pio_mode - XFER_PIO_0; struct pci_dev *dev = ap->host_set->pdev; - unsigned int is_slave = (adev->flags & ATA_DFLAG_MASTER) ? 0 : 1; + unsigned int is_slave = (adev->devno != 0); unsigned int master_port= ap->port_no ? 0x42 : 0x40; unsigned int slave_port = 0x44; u16 master_data; @@ -409,7 +430,7 @@ } /** - * piix_set_udmamode - Initialize host controller PATA PIO timings + * piix_set_dmamode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um * @udma: udma mode, 0 - 6 @@ -420,9 +441,9 @@ * None (inherited from caller). */ -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) { + unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ struct pci_dev *dev = ap->host_set->pdev; u8 maslave = ap->port_no ? 0x42 : 0x40; u8 speed = udma; @@ -452,25 +473,38 @@ case XFER_UDMA_3: case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: break; default: BUG(); return; } - if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } else { - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } /* move to PCI layer, integrate w/ MSI stuff */ @@ -485,6 +519,42 @@ } } +#define AHCI_PCI_BAR 5 +#define AHCI_GLOBAL_CTL 0x04 +#define AHCI_ENABLE (1 << 31) +static int piix_disable_ahci(struct pci_dev *pdev) +{ + void *mmio; + unsigned long addr; + u32 tmp; + int rc = 0; + + /* BUG: pci_enable_device has not yet been called. This + * works because this device is usually set up by BIOS. + */ + + addr = pci_resource_start(pdev, AHCI_PCI_BAR); + if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) + return 0; + + mmio = ioremap(addr, 64); + if (!mmio) + return -ENOMEM; + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) { + tmp &= ~AHCI_ENABLE; + writel(tmp, mmio + AHCI_GLOBAL_CTL); + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) + rc = -EIO; + } + + iounmap(mmio); + return rc; +} + /** * piix_init_one - Register PIIX ATA PCI device with kernel services * @pdev: PCI device to register @@ -516,6 +586,12 @@ port_info[0] = &piix_port_info[ent->driver_data]; port_info[1] = NULL; + + if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { u8 tmp; diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c --- a/drivers/scsi/atp870u.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/atp870u.c 2004-10-18 14:56:28 -07:00 @@ -363,7 +363,7 @@ /* * Clear it off the queue */ - dev->id[target_id].curr_req = 0; + dev->id[target_id].curr_req = NULL; dev->working--; spin_unlock_irqrestore(dev->host->host_lock, flags); /* @@ -2263,10 +2263,10 @@ dev->in_snd = 0; dev->in_int = 0; for (k = 0; k < qcnt; k++) { - dev->querequ[k] = 0; + dev->querequ[k] = NULL; } for (k = 0; k < 16; k++) { - dev->id[k].curr_req = 0; + dev->id[k].curr_req = NULL; dev->sp[k] = 0x04; } return 0; diff -Nru a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c --- a/drivers/scsi/cpqfcTScontrol.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/cpqfcTScontrol.c 2004-10-18 14:55:54 -07:00 @@ -116,7 +116,6 @@ cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle); /* printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); */ - memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE)); if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!! { diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c --- a/drivers/scsi/cpqfcTSinit.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/cpqfcTSinit.c 2004-10-18 14:55:54 -07:00 @@ -302,10 +302,16 @@ cpqfc_boards[i].device_id, PciDev))) { + if (pci_enable_device(PciDev)) { + printk(KERN_ERR + "cpqfc: can't enable PCI device at %s\n", pci_name(PciDev)); + goto err_continue; + } + if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) { printk(KERN_WARNING "cpqfc: HBA cannot support required DMA mask, skipping.\n"); - continue; + goto err_disable_dev; } // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes... @@ -314,8 +320,11 @@ HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) ); - if(HostAdapter == NULL) - continue; + if(HostAdapter == NULL) { + printk(KERN_WARNING + "cpqfc: can't register SCSI HBA, skipping.\n"); + goto err_disable_dev; + } DEBUG_PCI( printk(" HBA found!\n")); DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) ); DEBUG_PCI(printk(" PciDev->baseaddress[0]= %lx\n", @@ -367,9 +376,8 @@ DEV_NAME, HostAdapter) ) { - printk(" IRQ %u already used\n", HostAdapter->irq); - scsi_unregister( HostAdapter); - continue; + printk(KERN_WARNING "cpqfc: IRQ %u already used\n", HostAdapter->irq); + goto err_unregister; } // Since we have two 256-byte I/O port ranges (upper @@ -377,22 +385,17 @@ if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME ) ) { - printk(" cpqfcTS address in use: %x\n", + printk(KERN_WARNING "cpqfc: address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU); - free_irq( HostAdapter->irq, HostAdapter); - scsi_unregister( HostAdapter); - continue; + goto err_free_irq; } if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME ) ) { - printk(" cpqfcTS address in use: %x\n", + printk(KERN_WARNING "cpqfc: address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL); - release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff ); - free_irq( HostAdapter->irq, HostAdapter); - scsi_unregister( HostAdapter); - continue; + goto err_release_region_U; } // OK, we have grabbed everything we need now. @@ -424,7 +427,7 @@ // now initialize our hardware... if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) { printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n"); - // FIXME: might want to do something better than nothing here. + goto err_release_region_L; } cpqfcHBAdata->fcStatsTime = jiffies; // (for FC Statistics delta) @@ -455,6 +458,21 @@ spin_lock_irq(HostAdapter->host_lock); NumberOfAdapters++; spin_unlock_irq(HostAdapter->host_lock); + + continue; + +err_release_region_L: + release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff ); +err_release_region_U: + release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff ); +err_free_irq: + free_irq( HostAdapter->irq, HostAdapter); +err_unregister: + scsi_unregister( HostAdapter); +err_disable_dev: + pci_disable_device( PciDev ); +err_continue: + continue; } // end of while() } @@ -811,6 +829,7 @@ cpqfcHBAdata->fcChip.Registers.ReMapMemBase) vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase); */ + pci_disable_device( cpqfcHBAdata->PciDev); LEAVE("cpqfcTS_release"); return 0; diff -Nru a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h --- a/drivers/scsi/dc390.h 2004-10-18 14:56:17 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,32 +0,0 @@ -/*********************************************************************** - * FILE NAME : DC390.H * - * BY : C.L. Huang * - * Description: Device Driver for Tekram DC-390(T) PCI SCSI * - * Bus Master Host Adapter * - ***********************************************************************/ -/* $Id: dc390.h,v 2.43.2.22 2000/12/20 00:39:36 garloff Exp $ */ - -/* - * DC390/AMD 53C974 driver, header file - */ - -#ifndef DC390_H -#define DC390_H - -#include - -#define DC390_BANNER "Tekram DC390/AM53C974" -#define DC390_VERSION "2.1d 2004-05-27" - -/* We don't have eh_abort_handler, eh_device_reset_handler, - * eh_bus_reset_handler, eh_host_reset_handler yet! - * So long: Use old exception handling :-( */ -#define OLD_EH - -#if LINUX_VERSION_CODE < KERNEL_VERSION (2,1,70) || defined (OLD_EH) -# define NEW_EH -#else -# define NEW_EH use_new_eh_code: 1, -# define USE_NEW_EH -#endif -#endif /* DC390_H */ diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c --- a/drivers/scsi/dc395x.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/scsi/dc395x.c 2004-10-18 14:55:55 -07:00 @@ -376,6 +376,8 @@ static void reselect(struct AdapterCtlBlk *acb); static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); +static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb); static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code, @@ -384,13 +386,11 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); -static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); -static inline void set_xfer_rate(struct AdapterCtlBlk *acb, +static void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb); static void waiting_timeout(unsigned long ptr); @@ -989,7 +989,7 @@ srb->sg_count = 0; srb->total_xfer_length = 0; srb->sg_bus_addr = 0; - srb->virt_addr = 0; + srb->virt_addr = NULL; srb->sg_index = 0; srb->adapter_status = 0; srb->target_status = 0; @@ -1676,6 +1676,23 @@ } +#define DC395x_ENABLE_MSGOUT \ + DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \ + srb->state |= SRB_MSGOUT + + +/* abort command */ +static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) +{ + srb->msgout_buf[0] = ABORT; + srb->msg_count = 1; + DC395x_ENABLE_MSGOUT; + srb->state &= ~SRB_MSGIN; + srb->state |= SRB_MSGOUT; +} + + /** * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to * have been triggered for this card. @@ -1999,7 +2016,7 @@ } dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n"); - srb->virt_addr = 0; + srb->virt_addr = NULL; } @@ -2583,11 +2600,6 @@ return 1; } -#define DC395x_ENABLE_MSGOUT \ - DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \ - srb->state |= SRB_MSGOUT - - /* reject_msg */ static inline void msgin_reject(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) @@ -2603,18 +2615,6 @@ } -/* abort command */ -static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) -{ - srb->msgout_buf[0] = ABORT; - srb->msg_count = 1; - DC395x_ENABLE_MSGOUT; - srb->state &= ~SRB_MSGIN; - srb->state |= SRB_MSGOUT; -} - - static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, u8 tag) { @@ -3656,7 +3656,7 @@ } else { acb->acb_flag |= RESET_DETECT; reset_dev_param(acb); - doing_srb_done(acb, DID_RESET, 0, 1); + doing_srb_done(acb, DID_RESET, NULL, 1); /*DC395x_RecoverSRB( acb ); */ acb->active_dcb = NULL; acb->acb_flag = 0; diff -Nru a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c --- a/drivers/scsi/dmx3191d.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/scsi/dmx3191d.c 2004-10-18 14:56:33 -07:00 @@ -106,9 +106,10 @@ static int dmx3191d_release_resources(struct Scsi_Host *instance) { - release_region(instance->io_port, DMX3191D_REGION); if(instance->irq!=SCSI_IRQ_NONE) free_irq(instance->irq, instance); + NCR5380_exit(instance); + release_region(instance->io_port, DMX3191D_REGION); return 0; } diff -Nru a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c --- a/drivers/scsi/dtc.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/scsi/dtc.c 2004-10-18 14:56:48 -07:00 @@ -451,6 +451,7 @@ { if (shost->irq) free_irq(shost->irq, NULL); + NCR5380_exit(shost); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); scsi_unregister(shost); diff -Nru a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c --- a/drivers/scsi/eata_pio.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/scsi/eata_pio.c 2004-10-18 14:56:33 -07:00 @@ -59,6 +59,8 @@ #include #include #include +#include + #include #include @@ -511,8 +513,7 @@ HD(cmd)->state = RESET; spin_unlock_irq(host->host_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(3 * HZ); + msleep(3000); spin_lock_irq(host->host_lock); DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit)); diff -Nru a/drivers/scsi/esp.h b/drivers/scsi/esp.h --- a/drivers/scsi/esp.h 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/esp.h 2004-10-18 14:55:54 -07:00 @@ -77,8 +77,8 @@ /* We get one of these for each ESP probed. */ struct esp { - unsigned long eregs; /* ESP controller registers */ - unsigned long dregs; /* DMA controller registers */ + void __iomem *eregs; /* ESP controller registers */ + void __iomem *dregs; /* DMA controller registers */ struct sbus_dma *dma; /* DMA controller sw state */ struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ struct sbus_dev *sdev; /* Pointer to SBus entry */ diff -Nru a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c --- a/drivers/scsi/fd_mcs.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/fd_mcs.c 2004-10-18 14:56:28 -07:00 @@ -78,6 +78,7 @@ **************************************************************************/ #include +#include #include #include #include @@ -288,7 +289,7 @@ static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 }; static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; -static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; +static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; /* host information */ static int found = 0; @@ -297,16 +298,20 @@ static int user_fifo_count = 0; static int user_fifo_size = 0; -static void fd_mcs_setup(char *str, int *ints) +static int __init fd_mcs_setup(char *str) { static int done_setup = 0; + int ints[3]; + get_options(str, 3, ints); if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) { printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n"); + return 0; } user_fifo_count = ints[0] >= 1 ? ints[1] : 0; user_fifo_size = ints[0] >= 2 ? ints[2] : 0; + return 1; } __setup("fd_mcs=", fd_mcs_setup); @@ -391,7 +396,7 @@ } else { bios = addresses[pos2 >> 6]; port = ports[(pos2 >> 4) & 0x03]; - irq = ints[(pos2 >> 1) & 0x07]; + irq = interrupts[(pos2 >> 1) & 0x07]; } if (irq) { diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c --- a/drivers/scsi/fdomain.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/scsi/fdomain.c 2004-10-18 14:56:48 -07:00 @@ -733,17 +733,20 @@ printk( " %x,", base ); #endif - for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) { - if (base == ports[i]) - ++flag; + for (i = 0; i < PORT_COUNT; i++) { + if (base == ports[i]) { + if (!request_region(base, 0x10, "fdomain")) + break; + if (!fdomain_is_valid_port(base)) { + release_region(base, 0x10); + break; + } + *irq = fdomain_get_irq( base ); + *iobase = base; + return 1; + } } - if (flag && fdomain_is_valid_port( base )) { - *irq = fdomain_get_irq( base ); - *iobase = base; - return 1; - } - /* This is a bad sign. It usually means that someone patched the BIOS signature list (the signatures variable) to contain a BIOS signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */ @@ -764,7 +767,7 @@ for (i = 0; i < PORT_COUNT; i++) { base = ports[i]; - if (check_region( base, 0x10 )) { + if (!request_region(base, 0x10, "fdomain")) { #if DEBUG_DETECT printk( " (%x inuse),", base ); #endif @@ -773,7 +776,10 @@ #if DEBUG_DETECT printk( " %x,", base ); #endif - if ((flag = fdomain_is_valid_port( base ))) break; + flag = fdomain_is_valid_port(base); + if (flag) + break; + release_region(base, 0x10); } #if DEBUG_DETECT @@ -832,6 +838,9 @@ pci_base = pci_resource_start(pdev, 0); pci_irq = pdev->irq; + if (!request_region( pci_base, 0x10, "fdomain" )) + return 0; + /* Now we have the I/O base address and interrupt from the PCI configuration registers. */ @@ -844,8 +853,9 @@ " IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base ); #endif - if (!fdomain_is_valid_port( *iobase )) { + if (!fdomain_is_valid_port(pci_base)) { printk(KERN_ERR "scsi: PCI card detected, but driver not loaded (invalid port)\n" ); + release_region(pci_base, 0x10); return 0; } @@ -870,10 +880,16 @@ printk( "scsi: No BIOS, using port_base = 0x%x, irq = %d\n", port_base, interrupt_level ); #endif + if (!request_region(port_base, 0x10, "fdomain")) { + printk( "scsi: port 0x%x is busy\n", port_base ); + printk( "scsi: Bad LILO/INSMOD parameters?\n" ); + return NULL; + } if (!fdomain_is_valid_port( port_base )) { printk( "scsi: Cannot locate chip at port base 0x%x\n", port_base ); printk( "scsi: Bad LILO/INSMOD parameters?\n" ); + release_region(port_base, 0x10); return NULL; } } else { @@ -915,6 +931,7 @@ if (setup_called) { printk(KERN_ERR "scsi: Bad LILO/INSMOD parameters?\n"); } + release_region(port_base, 0x10); return NULL; } @@ -935,8 +952,10 @@ get resources. */ shpnt = scsi_register( tpnt, 0 ); - if(shpnt == NULL) + if(shpnt == NULL) { + release_region(port_base, 0x10); return NULL; + } shpnt->irq = interrupt_level; shpnt->io_port = port_base; scsi_set_device(shpnt, &pdev->dev); @@ -946,6 +965,7 @@ /* Log IRQ with kernel */ if (!interrupt_level) { printk(KERN_ERR "scsi: Card Detected, but driver not loaded (no IRQ)\n" ); + release_region(port_base, 0x10); return NULL; } else { /* Register the IRQ with the kernel */ @@ -967,13 +987,10 @@ printk(KERN_ERR " Send mail to faith@acm.org\n" ); } printk(KERN_ERR "scsi: Detected, but driver not loaded (IRQ)\n" ); + release_region(port_base, 0x10); return NULL; } } - - /* Log I/O ports with kernel */ - request_region( port_base, 0x10, "fdomain" ); - return shpnt; } diff -Nru a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c --- a/drivers/scsi/g_NCR5380.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/scsi/g_NCR5380.c 2004-10-18 14:56:17 -07:00 @@ -501,6 +501,10 @@ { NCR5380_local_declare(); NCR5380_setup(instance); + + if (instance->irq != SCSI_IRQ_NONE) + free_irq(instance->irq, NULL); + NCR5380_exit(instance); #ifndef CONFIG_SCSI_G_NCR5380_MEM release_region(instance->NCR5380_instance_name, instance->n_io_port); @@ -508,8 +512,6 @@ release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); #endif - if (instance->irq != SCSI_IRQ_NONE) - free_irq(instance->irq, NULL); return 0; } diff -Nru a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c --- a/drivers/scsi/gdth.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/scsi/gdth.c 2004-10-18 14:56:33 -07:00 @@ -571,12 +571,12 @@ #define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) -#define gdth_readb(addr) readb((ulong)(addr)) -#define gdth_readw(addr) readw((ulong)(addr)) -#define gdth_readl(addr) (ulong32)readl((ulong)(addr)) -#define gdth_writeb(b,addr) writeb((b),(ulong)(addr)) -#define gdth_writew(b,addr) writew((b),(ulong)(addr)) -#define gdth_writel(b,addr) writel((ulong32)(b),(ulong)(addr)) +#define gdth_readb(addr) readb(addr) +#define gdth_readw(addr) readw(addr) +#define gdth_readl(addr) readl(addr) +#define gdth_writeb(b,addr) writeb((b),(addr)) +#define gdth_writew(b,addr) writew((b),(addr)) +#define gdth_writel(b,addr) writel((b),(addr)) static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ @@ -618,9 +618,6 @@ }; /* __initfunc, __initdata macros */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -#define __devinitdata -#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #define GDTH_INITFUNC(type, func) type __init func #include @@ -778,7 +775,7 @@ GDTH_INITFUNC(static int, gdth_search_isa(ulong32 bios_adr)) { - void *addr; + void __iomem *addr; ulong32 id; TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); @@ -1053,7 +1050,7 @@ GDTH_INITFUNC(static int, gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)) { - register gdt2_dpram_str *dp2_ptr; + register gdt2_dpram_str __iomem *dp2_ptr; int i; unchar irq_drq,prot_ver; ulong32 retries; @@ -1065,10 +1062,10 @@ printk("GDT-ISA: Initialization error (DPMEM remap error)\n"); return 0; } - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; gdth_writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */ /* reset interface area */ - memset_io((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u)); + memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u)); if (gdth_readl(&dp2_ptr->u) != 0) { printk("GDT-ISA: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); @@ -1153,9 +1150,9 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) { - register gdt6_dpram_str *dp6_ptr; - register gdt6c_dpram_str *dp6c_ptr; - register gdt6m_dpram_str *dp6m_ptr; + register gdt6_dpram_str __iomem *dp6_ptr; + register gdt6c_dpram_str __iomem *dp6c_ptr; + register gdt6m_dpram_str __iomem *dp6m_ptr; ulong32 retries; unchar prot_ver; ushort command; @@ -1183,7 +1180,7 @@ return 0; } /* check and reset interface area */ - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", @@ -1208,7 +1205,7 @@ printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); @@ -1222,7 +1219,7 @@ return 0; } } - memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u)); + memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u)); if (gdth_readl(&dp6_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); @@ -1293,7 +1290,7 @@ return 0; } /* check and reset interface area */ - dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + dp6c_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", @@ -1318,7 +1315,7 @@ printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + dp6c_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); @@ -1332,7 +1329,7 @@ return 0; } } - memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u)); + memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u)); if (gdth_readl(&dp6c_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); @@ -1428,13 +1425,14 @@ pcistr->pdev->rom_address); #endif + dp6m_ptr = ha->brd; + /* Ensure that it is safe to access the non HW portions of DPMEM. * Aditional check needed for Xscale based RAID controllers */ - while( ((int)gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg) ) & 3 ) + while( ((int)gdth_readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 ) gdth_delay(1); /* check and reset interface area */ - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", @@ -1459,7 +1457,7 @@ printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); if (gdth_readl(&dp6m_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); @@ -1473,7 +1471,7 @@ return 0; } } - memset_io((char *)&dp6m_ptr->u,0,sizeof(dp6m_ptr->u)); + memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u)); /* disable board interrupts, deinit services */ gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) | 4, @@ -1556,9 +1554,9 @@ { gdth_ha_str *ha; ulong flags; - gdt2_dpram_str *dp2_ptr; - gdt6_dpram_str *dp6_ptr; - gdt6m_dpram_str *dp6m_ptr; + gdt2_dpram_str __iomem *dp2_ptr; + gdt6_dpram_str __iomem *dp6_ptr; + gdt6m_dpram_str __iomem *dp6m_ptr; TRACE(("gdth_enable_int() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -1569,12 +1567,12 @@ outb(0xff, ha->bmic + EDENABREG); outb(0x01, ha->bmic + EINTENABREG); } else if (ha->type == GDT_ISA) { - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; gdth_writeb(1, &dp2_ptr->io.irqdel); gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index); gdth_writeb(1, &dp2_ptr->io.irqen); } else if (ha->type == GDT_PCI) { - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writeb(1, &dp6_ptr->io.irqdel); gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index); gdth_writeb(1, &dp6_ptr->io.irqen); @@ -1582,7 +1580,7 @@ outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); outb(0x03, PTR2USHORT(&ha->plx->control1)); } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4, &dp6m_ptr->i960r.edoor_en_reg); @@ -1608,15 +1606,15 @@ *pIStatus = inb((ushort)ha->bmic + EDOORREG); else if (ha->type == GDT_ISA) *pIStatus = - gdth_readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Cmd_Index); + gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); else if (ha->type == GDT_PCI) *pIStatus = - gdth_readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Cmd_Index); + gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); else if (ha->type == GDT_PCINEW) *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg)); else if (ha->type == GDT_PCIMPR) *pIStatus = - gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.edoor_reg); + gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg); if (*pIStatus) return i; /* board found */ @@ -1636,14 +1634,14 @@ if (ha->type == GDT_EISA) gdtsema0 = (int)inb(ha->bmic + SEMA0REG); else if (ha->type == GDT_ISA) - gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Sema0); + gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); else if (ha->type == GDT_PCI) - gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Sema0); + gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); else if (ha->type == GDT_PCINEW) gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg)); else if (ha->type == GDT_PCIMPR) gdtsema0 = - (int)gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg); + (int)gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); return (gdtsema0 & 1); } @@ -1679,13 +1677,13 @@ if (ha->type == GDT_EISA) { outb(1, ha->bmic + SEMA0REG); } else if (ha->type == GDT_ISA) { - gdth_writeb(1, &((gdt2_dpram_str *)ha->brd)->u.ic.Sema0); + gdth_writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); } else if (ha->type == GDT_PCI) { - gdth_writeb(1, &((gdt6_dpram_str *)ha->brd)->u.ic.Sema0); + gdth_writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->sema0_reg)); } else if (ha->type == GDT_PCIMPR) { - gdth_writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg); + gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); } } @@ -1694,10 +1692,10 @@ { register gdth_ha_str *ha; register gdth_cmd_str *cmd_ptr; - register gdt6m_dpram_str *dp6m_ptr; - register gdt6c_dpram_str *dp6c_ptr; - gdt6_dpram_str *dp6_ptr; - gdt2_dpram_str *dp2_ptr; + register gdt6m_dpram_str __iomem *dp6m_ptr; + register gdt6c_dpram_str __iomem *dp6c_ptr; + gdt6_dpram_str __iomem *dp6_ptr; + gdt2_dpram_str __iomem *dp2_ptr; ushort cp_count,dp_offset,cmd_no; TRACE(("gdth_copy_command() hanum %d\n",hanum)); @@ -1720,28 +1718,28 @@ /* set offset and service, copy command to DPMEM */ if (ha->type == GDT_ISA) { - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp2_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCI) { - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCINEW) { - dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + dp6c_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6c_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6m_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, @@ -1780,13 +1778,13 @@ outl(ha->ccb_phys, ha->bmic + MAILBOXREG); outb(ha->pccb->Service, ha->bmic + LDOORREG); } else if (ha->type == GDT_ISA) { - gdth_writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event); + gdth_writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event); } else if (ha->type == GDT_PCI) { - gdth_writeb(0, &((gdt6_dpram_str *)ha->brd)->io.event); + gdth_writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->ldoor_reg)); } else if (ha->type == GDT_PCIMPR) { - gdth_writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.ldoor_reg); + gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg); } } @@ -3419,7 +3417,7 @@ /* no GDTH_LOCK_HA() ! */ TRACE2(("gdth_store_event() source %d idx %d\n", source, idx)); if (source == 0) /* no source -> no event */ - return 0; + return NULL; if (ebuffer[elastidx].event_source == source && ebuffer[elastidx].event_idx == idx && @@ -3538,9 +3536,9 @@ #endif { register gdth_ha_str *ha; - gdt6m_dpram_str *dp6m_ptr = NULL; - gdt6_dpram_str *dp6_ptr; - gdt2_dpram_str *dp2_ptr; + gdt6m_dpram_str __iomem *dp6m_ptr = NULL; + gdt6_dpram_str __iomem *dp6_ptr; + gdt2_dpram_str __iomem *dp2_ptr; Scsi_Cmnd *scp; int hanum, rval, i; unchar IStatus; @@ -3619,7 +3617,7 @@ outb(0xff, ha->bmic + EDOORREG); /* acknowledge interrupt */ outb(0x00, ha->bmic + SEMA1REG); /* reset status semaphore */ } else if (ha->type == GDT_ISA) { - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; ha->status = gdth_readw(&dp2_ptr->u.ic.Status); @@ -3634,7 +3632,7 @@ gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */ gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ } else if (ha->type == GDT_PCI) { - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; ha->status = gdth_readw(&dp6_ptr->u.ic.Status); @@ -3662,7 +3660,7 @@ outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; #ifdef INT_COAL @@ -3692,10 +3690,10 @@ if (ha->service != SCREENSERVICE && (ha->fw_vers & 0xff) >= 0x1a) { ha->dvr.severity = gdth_readb - (&((gdt6m_dpram_str *)ha->brd)->i960r.severity); + (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity); for (i = 0; i < 256; ++i) { ha->dvr.event_string[i] = gdth_readb - (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]); + (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]); if (ha->dvr.event_string[i] == 0) break; } diff -Nru a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h --- a/drivers/scsi/gdth.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/gdth.h 2004-10-18 14:56:28 -07:00 @@ -868,7 +868,7 @@ ushort raw_feat; /* feat. raw service (s/g,..)*/ ushort screen_feat; /* feat. raw service (s/g,..)*/ ushort bmic; /* BMIC address (EISA) */ - void *brd; /* DPRAM address */ + void __iomem *brd; /* DPRAM address */ ulong32 brd_phys; /* slot number/BIOS address */ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ gdth_cmd_str *pccb; /* address command structure */ diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/hosts.c 2004-10-18 14:55:54 -07:00 @@ -75,9 +75,9 @@ **/ void scsi_remove_host(struct Scsi_Host *shost) { + scsi_forget_host(shost); scsi_host_cancel(shost, 0); scsi_proc_host_rm(shost); - scsi_forget_host(shost); set_bit(SHOST_DEL, &shost->shost_state); diff -Nru a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ibmvscsi/Makefile 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,5 @@ +obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o + +ibmvscsic-y += ibmvscsi.o +ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o +ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o diff -Nru a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,1393 @@ +/* ------------------------------------------------------------ + * ibmvscsi.c + * (C) Copyright IBM Corporation 1994, 2004 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * Dave Boutcher (sleddog@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * ------------------------------------------------------------ + * Emulation of a SCSI host adapter for Virtual I/O devices + * + * This driver supports the SCSI adapter implemented by the IBM + * Power5 firmware. That SCSI adapter is not a physical adapter, + * but allows Linux SCSI peripheral drivers to directly + * access devices in another logical partition on the physical system. + * + * The virtual adapter(s) are present in the open firmware device + * tree just like real adapters. + * + * One of the capabilities provided on these systems is the ability + * to DMA between partitions. The architecture states that for VSCSI, + * the server side is allowed to DMA to and from the client. The client + * is never trusted to DMA to or from the server directly. + * + * Messages are sent between partitions on a "Command/Response Queue" + * (CRQ), which is just a buffer of 16 byte entries in the receiver's + * Senders cannot access the buffer directly, but send messages by + * making a hypervisor call and passing in the 16 bytes. The hypervisor + * puts the message in the next 16 byte space in round-robbin fashion, + * turns on the high order bit of the message (the valid bit), and + * generates an interrupt to the receiver (if interrupts are turned on.) + * The receiver just turns off the valid bit when they have copied out + * the message. + * + * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit + * (IU) (as defined in the T10 standard available at www.t10.org), gets + * a DMA address for the message, and sends it to the server as the + * payload of a CRQ message. The server DMAs the SRP IU and processes it, + * including doing any additional data transfers. When it is done, it + * DMAs the SRP response back to the same address as the request came from, + * and sends a CRQ message back to inform the client that the request has + * completed. + * + * Note that some of the underlying infrastructure is different between + * machines conforming to the "RS/6000 Platform Architecture" (RPA) and + * the older iSeries hypervisor models. To support both, some low level + * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c. + * The Makefile should pick one, not two, not zero, of these. + * + * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor + * interfaces. It would be really nice to abstract this above an RDMA + * layer. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ibmvscsi.h" + +/* The values below are somewhat arbitrary default values, but + * OS/400 will use 3 busses (disks, CDs, tapes, I think.) + * Note that there are 3 bits of channel value, 6 bits of id, and + * 5 bits of LUN. + */ +static int max_id = 64; +static int max_channel = 3; +static int init_timeout = 5; +static int max_requests = 50; + +#define IBMVSCSI_VERSION "1.5.1" + +MODULE_DESCRIPTION("IBM Virtual SCSI"); +MODULE_AUTHOR("Dave Boutcher"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(IBMVSCSI_VERSION); + +module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_id, "Largest ID value for each channel"); +module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_channel, "Largest channel value"); +module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds"); +module_param_named(max_requests, max_requests, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter"); + +/* ------------------------------------------------------------ + * Routines for the event pool and event structs + */ +/** + * initialize_event_pool: - Allocates and initializes the event pool for a host + * @pool: event_pool to be initialized + * @size: Number of events in pool + * @hostdata: ibmvscsi_host_data who owns the event pool + * + * Returns zero on success. +*/ +static int initialize_event_pool(struct event_pool *pool, + int size, struct ibmvscsi_host_data *hostdata) +{ + int i; + + pool->size = size; + pool->next = 0; + pool->events = kmalloc(pool->size * sizeof(*pool->events), GFP_KERNEL); + if (!pool->events) + return -ENOMEM; + memset(pool->events, 0x00, pool->size * sizeof(*pool->events)); + + pool->iu_storage = + dma_alloc_coherent(hostdata->dev, + pool->size * sizeof(*pool->iu_storage), + &pool->iu_token, 0); + if (!pool->iu_storage) { + kfree(pool->events); + return -ENOMEM; + } + + for (i = 0; i < pool->size; ++i) { + struct srp_event_struct *evt = &pool->events[i]; + memset(&evt->crq, 0x00, sizeof(evt->crq)); + atomic_set(&evt->free, 1); + evt->crq.valid = 0x80; + evt->crq.IU_length = sizeof(*evt->xfer_iu); + evt->crq.IU_data_ptr = pool->iu_token + + sizeof(*evt->xfer_iu) * i; + evt->xfer_iu = pool->iu_storage + i; + evt->hostdata = hostdata; + } + + return 0; +} + +/** + * release_event_pool: - Frees memory of an event pool of a host + * @pool: event_pool to be released + * @hostdata: ibmvscsi_host_data who owns the even pool + * + * Returns zero on success. +*/ +static void release_event_pool(struct event_pool *pool, + struct ibmvscsi_host_data *hostdata) +{ + int i, in_use = 0; + for (i = 0; i < pool->size; ++i) + if (atomic_read(&pool->events[i].free) != 1) + ++in_use; + if (in_use) + printk(KERN_WARNING + "ibmvscsi: releasing event pool with %d " + "events still in use?\n", in_use); + kfree(pool->events); + dma_free_coherent(hostdata->dev, + pool->size * sizeof(*pool->iu_storage), + pool->iu_storage, pool->iu_token); +} + +/** + * valid_event_struct: - Determines if event is valid. + * @pool: event_pool that contains the event + * @evt: srp_event_struct to be checked for validity + * + * Returns zero if event is invalid, one otherwise. +*/ +static int valid_event_struct(struct event_pool *pool, + struct srp_event_struct *evt) +{ + int index = evt - pool->events; + if (index < 0 || index >= pool->size) /* outside of bounds */ + return 0; + if (evt != pool->events + index) /* unaligned */ + return 0; + return 1; +} + +/** + * ibmvscsi_free-event_struct: - Changes status of event to "free" + * @pool: event_pool that contains the event + * @evt: srp_event_struct to be modified + * +*/ +static void free_event_struct(struct event_pool *pool, + struct srp_event_struct *evt) +{ + if (!valid_event_struct(pool, evt)) { + printk(KERN_ERR + "ibmvscsi: Freeing invalid event_struct %p " + "(not in pool %p)\n", evt, pool->events); + return; + } + if (atomic_inc_return(&evt->free) != 1) { + printk(KERN_ERR + "ibmvscsi: Freeing event_struct %p " + "which is not in use!\n", evt); + return; + } +} + +/** + * get_evt_struct: - Gets the next free event in pool + * @pool: event_pool that contains the events to be searched + * + * Returns the next event in "free" state, and NULL if none are free. + * Note that no synchronization is done here, we assume the host_lock + * will syncrhonze things. +*/ +static struct srp_event_struct *get_event_struct(struct event_pool *pool) +{ + int i; + int poolsize = pool->size; + int offset = pool->next; + + for (i = 0; i < poolsize; i++) { + offset = (offset + 1) % poolsize; + if (!atomic_dec_if_positive(&pool->events[offset].free)) { + pool->next = offset; + return &pool->events[offset]; + } + } + + printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n"); + return NULL; +} + +/** + * init_event_struct: Initialize fields in an event struct that are always + * required. + * @evt: The event + * @done: Routine to call when the event is responded to + * @format: SRP or MAD format + * @timeout: timeout value set in the CRQ + */ +static void init_event_struct(struct srp_event_struct *evt_struct, + void (*done) (struct srp_event_struct *), + u8 format, + int timeout) +{ + evt_struct->cmnd = NULL; + evt_struct->cmnd_done = NULL; + evt_struct->crq.format = format; + evt_struct->crq.timeout = timeout; + evt_struct->done = done; +} + +/* ------------------------------------------------------------ + * Routines for receiving SCSI responses from the hosting partition + */ + +/** + * set_srp_direction: Set the fields in the srp related to data + * direction and number of buffers based on the direction in + * the scsi_cmnd and the number of buffers + */ +static void set_srp_direction(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, + int numbuf) +{ + if (numbuf == 0) + return; + + if (numbuf == 1) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) + srp_cmd->data_out_format = SRP_DIRECT_BUFFER; + else + srp_cmd->data_in_format = SRP_DIRECT_BUFFER; + } else { + if (cmd->sc_data_direction == DMA_TO_DEVICE) { + srp_cmd->data_out_format = SRP_INDIRECT_BUFFER; + srp_cmd->data_out_count = numbuf; + } else { + srp_cmd->data_in_format = SRP_INDIRECT_BUFFER; + srp_cmd->data_in_count = numbuf; + } + } +} + +/** + * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format + * @cmd: srp_cmd whose additional_data member will be unmapped + * @dev: device for which the memory is mapped + * +*/ +static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) +{ + int i; + + if ((cmd->data_out_format == SRP_NO_BUFFER) && + (cmd->data_in_format == SRP_NO_BUFFER)) + return; + else if ((cmd->data_out_format == SRP_DIRECT_BUFFER) || + (cmd->data_in_format == SRP_DIRECT_BUFFER)) { + struct memory_descriptor *data = + (struct memory_descriptor *)cmd->additional_data; + dma_unmap_single(dev, data->virtual_address, data->length, + DMA_BIDIRECTIONAL); + } else { + struct indirect_descriptor *indirect = + (struct indirect_descriptor *)cmd->additional_data; + int num_mapped = indirect->head.length / + sizeof(indirect->list[0]); + for (i = 0; i < num_mapped; ++i) { + struct memory_descriptor *data = &indirect->list[i]; + dma_unmap_single(dev, + data->virtual_address, + data->length, DMA_BIDIRECTIONAL); + } + } +} + +/** + * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields + * @cmd: Scsi_Cmnd with the scatterlist + * @srp_cmd: srp_cmd that contains the memory descriptor + * @dev: device for which to map dma memory + * + * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd. + * Returns 1 on success. +*/ +static int map_sg_data(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, struct device *dev) +{ + + int i, sg_mapped; + u64 total_length = 0; + struct scatterlist *sg = cmd->request_buffer; + struct memory_descriptor *data = + (struct memory_descriptor *)srp_cmd->additional_data; + struct indirect_descriptor *indirect = + (struct indirect_descriptor *)data; + + sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL); + + if (sg_mapped == 0) + return 0; + + set_srp_direction(cmd, srp_cmd, sg_mapped); + + /* special case; we can use a single direct descriptor */ + if (sg_mapped == 1) { + data->virtual_address = sg_dma_address(&sg[0]); + data->length = sg_dma_len(&sg[0]); + data->memory_handle = 0; + return 1; + } + + if (sg_mapped > MAX_INDIRECT_BUFS) { + printk(KERN_ERR + "ibmvscsi: More than %d mapped sg entries, got %d\n", + MAX_INDIRECT_BUFS, sg_mapped); + return 0; + } + + indirect->head.virtual_address = 0; + indirect->head.length = sg_mapped * sizeof(indirect->list[0]); + indirect->head.memory_handle = 0; + for (i = 0; i < sg_mapped; ++i) { + struct memory_descriptor *descr = &indirect->list[i]; + struct scatterlist *sg_entry = &sg[i]; + descr->virtual_address = sg_dma_address(sg_entry); + descr->length = sg_dma_len(sg_entry); + descr->memory_handle = 0; + total_length += sg_dma_len(sg_entry); + } + indirect->total_length = total_length; + + return 1; +} + +/** + * map_single_data: - Maps memory and initializes memory decriptor fields + * @cmd: struct scsi_cmnd with the memory to be mapped + * @srp_cmd: srp_cmd that contains the memory descriptor + * @dev: device for which to map dma memory + * + * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd. + * Returns 1 on success. +*/ +static int map_single_data(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, struct device *dev) +{ + struct memory_descriptor *data = + (struct memory_descriptor *)srp_cmd->additional_data; + + data->virtual_address = + dma_map_single(dev, cmd->request_buffer, + cmd->request_bufflen, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(data->virtual_address)) { + printk(KERN_ERR + "ibmvscsi: Unable to map request_buffer for command!\n"); + return 0; + } + data->length = cmd->request_bufflen; + data->memory_handle = 0; + + set_srp_direction(cmd, srp_cmd, 1); + + return 1; +} + +/** + * map_data_for_srp_cmd: - Calls functions to map data for srp cmds + * @cmd: struct scsi_cmnd with the memory to be mapped + * @srp_cmd: srp_cmd that contains the memory descriptor + * @dev: dma device for which to map dma memory + * + * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds + * Returns 1 on success. +*/ +static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, struct device *dev) +{ + switch (cmd->sc_data_direction) { + case DMA_FROM_DEVICE: + case DMA_TO_DEVICE: + break; + case DMA_NONE: + return 1; + case DMA_BIDIRECTIONAL: + printk(KERN_ERR + "ibmvscsi: Can't map DMA_BIDIRECTIONAL to read/write\n"); + return 0; + default: + printk(KERN_ERR + "ibmvscsi: Unknown data direction 0x%02x; can't map!\n", + cmd->sc_data_direction); + return 0; + } + + if (!cmd->request_buffer) + return 1; + if (cmd->use_sg) + return map_sg_data(cmd, srp_cmd, dev); + return map_single_data(cmd, srp_cmd, dev); +} + +/* ------------------------------------------------------------ + * Routines for sending and receiving SRPs + */ +/** + * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq() + * @evt_struct: evt_struct to be sent + * @hostdata: ibmvscsi_host_data of host + * + * Returns the value returned from ibmvscsi_send_crq(). (Zero for success) + * Note that this routine assumes that host_lock is held for synchronization +*/ +static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, + struct ibmvscsi_host_data *hostdata) +{ + struct scsi_cmnd *cmnd = evt_struct->cmnd; + u64 *crq_as_u64 = (u64 *) &evt_struct->crq; + int rc; + + /* If we have exhausted our request limit, just fail this request. + * Note that there are rare cases involving driver generated requests + * (such as task management requests) that the mid layer may think we + * can handle more requests (can_queue) when we actually can't + */ + if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) && + (atomic_dec_if_positive(&hostdata->request_limit) < 0)) { + /* See if the adapter is disabled */ + if (atomic_read(&hostdata->request_limit) < 0) { + if (cmnd) + cmnd->result = DID_ERROR << 16; + if (evt_struct->cmnd_done) + evt_struct->cmnd_done(cmnd); + unmap_cmd_data(&evt_struct->iu.srp.cmd, + hostdata->dev); + free_event_struct(&hostdata->pool, evt_struct); + return 0; + } else { + printk("ibmvscsi: Warning, request_limit exceeded\n"); + unmap_cmd_data(&evt_struct->iu.srp.cmd, + hostdata->dev); + free_event_struct(&hostdata->pool, evt_struct); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + + /* Copy the IU into the transfer area */ + *evt_struct->xfer_iu = evt_struct->iu; + evt_struct->xfer_iu->srp.generic.tag = (u64)evt_struct; + + /* Add this to the sent list. We need to do this + * before we actually send + * in case it comes back REALLY fast + */ + list_add_tail(&evt_struct->list, &hostdata->sent); + + if ((rc = + ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { + list_del(&evt_struct->list); + + cmnd = evt_struct->cmnd; + printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n", + rc); + unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev); + free_event_struct(&hostdata->pool, evt_struct); + if (cmnd) + cmnd->result = DID_ERROR << 16; + if (evt_struct->cmnd_done) + evt_struct->cmnd_done(cmnd); + } + + return 0; +} + +/** + * handle_cmd_rsp: - Handle responses from commands + * @evt_struct: srp_event_struct to be handled + * + * Used as a callback by when sending scsi cmds. + * Gets called by ibmvscsi_handle_crq() +*/ +static void handle_cmd_rsp(struct srp_event_struct *evt_struct) +{ + struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp; + struct scsi_cmnd *cmnd = evt_struct->cmnd; + + if (cmnd) { + cmnd->result = rsp->status; + if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION) + memcpy(cmnd->sense_buffer, + rsp->sense_and_response_data, + rsp->sense_data_list_length); + unmap_cmd_data(&evt_struct->iu.srp.cmd, + evt_struct->hostdata->dev); + + if (rsp->doover) + cmnd->resid = rsp->data_out_residual_count; + else if (rsp->diover) + cmnd->resid = rsp->data_in_residual_count; + } + + if (evt_struct->cmnd_done) + evt_struct->cmnd_done(cmnd); +} + +/** + * lun_from_dev: - Returns the lun of the scsi device + * @dev: struct scsi_device + * +*/ +static inline u16 lun_from_dev(struct scsi_device *dev) +{ + return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun; +} + +/** + * ibmvscsi_queue: - The queuecommand function of the scsi template + * @cmd: struct scsi_cmnd to be executed + * @done: Callback function to be called when cmd is completed +*/ +static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, + void (*done) (struct scsi_cmnd *)) +{ + struct srp_cmd *srp_cmd; + struct srp_event_struct *evt_struct; + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata; + u16 lun = lun_from_dev(cmnd->device); + + evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) + return SCSI_MLQUEUE_HOST_BUSY; + + init_event_struct(evt_struct, + handle_cmd_rsp, + VIOSRP_SRP_FORMAT, + cmnd->timeout); + + evt_struct->cmnd = cmnd; + evt_struct->cmnd_done = done; + + /* Set up the actual SRP IU */ + srp_cmd = &evt_struct->iu.srp.cmd; + memset(srp_cmd, 0x00, sizeof(*srp_cmd)); + srp_cmd->type = SRP_CMD_TYPE; + memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); + srp_cmd->lun = ((u64) lun) << 48; + + if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) { + printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n"); + free_event_struct(&hostdata->pool, evt_struct); + return SCSI_MLQUEUE_HOST_BUSY; + } + + /* Fix up dma address of the buffer itself */ + if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || + (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) { + struct indirect_descriptor *indirect = + (struct indirect_descriptor *)srp_cmd->additional_data; + indirect->head.virtual_address = evt_struct->crq.IU_data_ptr + + offsetof(struct srp_cmd, additional_data) + + offsetof(struct indirect_descriptor, list); + } + + return ibmvscsi_send_srp_event(evt_struct, hostdata); +} + +/* ------------------------------------------------------------ + * Routines for driver initialization + */ +/** + * adapter_info_rsp: - Handle response to MAD adapter info request + * @evt_struct: srp_event_struct with the response + * + * Used as a "done" callback by when sending adapter_info. Gets called + * by ibmvscsi_handle_crq() +*/ +static void adapter_info_rsp(struct srp_event_struct *evt_struct) +{ + struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; + dma_unmap_single(hostdata->dev, + evt_struct->iu.mad.adapter_info.buffer, + evt_struct->iu.mad.adapter_info.common.length, + DMA_BIDIRECTIONAL); + + if (evt_struct->xfer_iu->mad.adapter_info.common.status) { + printk("ibmvscsi: error %d getting adapter info\n", + evt_struct->xfer_iu->mad.adapter_info.common.status); + } else { + printk("ibmvscsi: host srp version: %s, " + "host partition %s (%d), OS %d\n", + hostdata->madapter_info.srp_version, + hostdata->madapter_info.partition_name, + hostdata->madapter_info.partition_number, + hostdata->madapter_info.os_type); + } +} + +/** + * send_mad_adapter_info: - Sends the mad adapter info request + * and stores the result so it can be retrieved with + * sysfs. We COULD consider causing a failure if the + * returned SRP version doesn't match ours. + * @hostdata: ibmvscsi_host_data of host + * + * Returns zero if successful. +*/ +static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) +{ + struct viosrp_adapter_info *req; + struct srp_event_struct *evt_struct; + + memset(&hostdata->madapter_info, 0x00, sizeof(hostdata->madapter_info)); + + evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) { + printk(KERN_ERR "ibmvscsi: couldn't allocate an event " + "for ADAPTER_INFO_REQ!\n"); + return; + } + + init_event_struct(evt_struct, + adapter_info_rsp, + VIOSRP_MAD_FORMAT, + init_timeout * HZ); + + req = &evt_struct->iu.mad.adapter_info; + memset(req, 0x00, sizeof(*req)); + + req->common.type = VIOSRP_ADAPTER_INFO_TYPE; + req->common.length = sizeof(hostdata->madapter_info); + req->buffer = dma_map_single(hostdata->dev, + &hostdata->madapter_info, + sizeof(hostdata->madapter_info), + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(req->buffer)) { + printk(KERN_ERR + "ibmvscsi: Unable to map request_buffer " + "for adapter_info!\n"); + free_event_struct(&hostdata->pool, evt_struct); + return; + } + + if (ibmvscsi_send_srp_event(evt_struct, hostdata)) + printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n"); +}; + +/** + * login_rsp: - Handle response to SRP login request + * @evt_struct: srp_event_struct with the response + * + * Used as a "done" callback by when sending srp_login. Gets called + * by ibmvscsi_handle_crq() +*/ +static void login_rsp(struct srp_event_struct *evt_struct) +{ + struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; + switch (evt_struct->xfer_iu->srp.generic.type) { + case SRP_LOGIN_RSP_TYPE: /* it worked! */ + break; + case SRP_LOGIN_REJ_TYPE: /* refused! */ + printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REQ rejected\n"); + /* Login failed. */ + atomic_set(&hostdata->request_limit, -1); + return; + default: + printk(KERN_ERR + "ibmvscsi: Invalid login response typecode 0x%02x!\n", + evt_struct->xfer_iu->srp.generic.type); + /* Login failed. */ + atomic_set(&hostdata->request_limit, -1); + return; + } + + printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n"); + + if (evt_struct->xfer_iu->srp.login_rsp.request_limit_delta > + (max_requests - 2)) + evt_struct->xfer_iu->srp.login_rsp.request_limit_delta = + max_requests - 2; + + /* Now we know what the real request-limit is */ + atomic_set(&hostdata->request_limit, + evt_struct->xfer_iu->srp.login_rsp.request_limit_delta); + + hostdata->host->can_queue = + evt_struct->xfer_iu->srp.login_rsp.request_limit_delta - 2; + + if (hostdata->host->can_queue < 1) { + printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n"); + return; + } + + send_mad_adapter_info(hostdata); + return; +} + +/** + * send_srp_login: - Sends the srp login + * @hostdata: ibmvscsi_host_data of host + * + * Returns zero if successful. +*/ +static int send_srp_login(struct ibmvscsi_host_data *hostdata) +{ + int rc; + unsigned long flags; + struct srp_login_req *login; + struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) { + printk(KERN_ERR + "ibmvscsi: couldn't allocate an event for login req!\n"); + return FAILED; + } + + init_event_struct(evt_struct, + login_rsp, + VIOSRP_SRP_FORMAT, + init_timeout * HZ); + + login = &evt_struct->iu.srp.login_req; + login->type = SRP_LOGIN_REQ_TYPE; + login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu); + login->required_buffer_formats = 0x0006; + + /* Start out with a request limit of 1, since this is negotiated in + * the login request we are just sending + */ + atomic_set(&hostdata->request_limit, 1); + + spin_lock_irqsave(hostdata->host->host_lock, flags); + rc = ibmvscsi_send_srp_event(evt_struct, hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + return rc; +}; + +/** + * sync_completion: Signal that a synchronous command has completed + * Note that after returning from this call, the evt_struct is freed. + * the caller waiting on this completion shouldn't touch the evt_struct + * again. + */ +static void sync_completion(struct srp_event_struct *evt_struct) +{ + complete(&evt_struct->comp); +} + +/** + * ibmvscsi_abort: Abort a command...from scsi host template + * send this over to the server and wait synchronously for the response + */ +static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) +{ + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)cmd->device->host->hostdata; + struct srp_tsk_mgmt *tsk_mgmt; + struct srp_event_struct *evt; + struct srp_event_struct *tmp_evt, *found_evt; + u16 lun = lun_from_dev(cmd->device); + + /* First, find this command in our sent list so we can figure + * out the correct tag + */ + found_evt = NULL; + list_for_each_entry(tmp_evt, &hostdata->sent, list) { + if (tmp_evt->cmnd == cmd) { + found_evt = tmp_evt; + break; + } + } + + if (!found_evt) + return FAILED; + + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n"); + return FAILED; + } + + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout * HZ); + + tsk_mgmt = &evt->iu.srp.tsk_mgmt; + + /* Set up an abort SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->type = SRP_TSK_MGMT_TYPE; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->task_mgmt_flags = 0x01; /* ABORT TASK */ + tsk_mgmt->managed_task_tag = (u64) found_evt; + + printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n", + tsk_mgmt->lun, tsk_mgmt->managed_task_tag); + + init_completion(&evt->comp); + if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: failed to send abort() event\n"); + return FAILED; + } + + spin_unlock_irq(hostdata->host->host_lock); + wait_for_completion(&evt->comp); + spin_lock_irq(hostdata->host->host_lock); + + /* Because we dropped the spinlock above, it's possible + * The event is no longer in our list. Make sure it didn't + * complete while we were aborting + */ + found_evt = NULL; + list_for_each_entry(tmp_evt, &hostdata->sent, list) { + if (tmp_evt->cmnd == cmd) { + found_evt = tmp_evt; + break; + } + } + + printk(KERN_INFO + "ibmvscsi: successfully aborted task tag 0x%lx\n", + tsk_mgmt->managed_task_tag); + + if (found_evt == NULL) + return SUCCESS; + + cmd->result = (DID_ABORT << 16); + list_del(&found_evt->list); + unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev); + free_event_struct(&found_evt->hostdata->pool, found_evt); + atomic_inc(&hostdata->request_limit); + return SUCCESS; +} + +/** + * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host + * template send this over to the server and wait synchronously for the + * response + */ +static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) +{ + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)cmd->device->host->hostdata; + + struct srp_tsk_mgmt *tsk_mgmt; + struct srp_event_struct *evt; + struct srp_event_struct *tmp_evt, *pos; + u16 lun = lun_from_dev(cmd->device); + + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n"); + return FAILED; + } + + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout * HZ); + + tsk_mgmt = &evt->iu.srp.tsk_mgmt; + + /* Set up a lun reset SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->type = SRP_TSK_MGMT_TYPE; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->task_mgmt_flags = 0x08; /* LUN RESET */ + + printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n", + tsk_mgmt->lun); + + init_completion(&evt->comp); + if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: failed to send reset event\n"); + return FAILED; + } + + spin_unlock_irq(hostdata->host->host_lock); + wait_for_completion(&evt->comp); + spin_lock_irq(hostdata->host->host_lock); + + /* We need to find all commands for this LUN that have not yet been + * responded to, and fail them with DID_RESET + */ + list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { + if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) { + if (tmp_evt->cmnd) + tmp_evt->cmnd->result = (DID_RESET << 16); + list_del(&tmp_evt->list); + unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev); + free_event_struct(&tmp_evt->hostdata->pool, + tmp_evt); + atomic_inc(&hostdata->request_limit); + if (tmp_evt->cmnd_done) + tmp_evt->cmnd_done(tmp_evt->cmnd); + else if (tmp_evt->done) + tmp_evt->done(tmp_evt); + } + } + return SUCCESS; +} + +/** + * purge_requests: Our virtual adapter just shut down. purge any sent requests + * @hostdata: the adapter + */ +static void purge_requests(struct ibmvscsi_host_data *hostdata) +{ + struct srp_event_struct *tmp_evt, *pos; + unsigned long flags; + + spin_lock_irqsave(hostdata->host->host_lock, flags); + list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { + list_del(&tmp_evt->list); + if (tmp_evt->cmnd) { + tmp_evt->cmnd->result = (DID_ERROR << 16); + unmap_cmd_data(&tmp_evt->iu.srp.cmd, + tmp_evt->hostdata->dev); + if (tmp_evt->cmnd_done) + tmp_evt->cmnd_done(tmp_evt->cmnd); + } else { + if (tmp_evt->done) { + tmp_evt->done(tmp_evt); + } + } + free_event_struct(&tmp_evt->hostdata->pool, tmp_evt); + } + spin_unlock_irqrestore(hostdata->host->host_lock, flags); +} + +/** + * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ + * @crq: Command/Response queue + * @hostdata: ibmvscsi_host_data of host + * +*/ +void ibmvscsi_handle_crq(struct viosrp_crq *crq, + struct ibmvscsi_host_data *hostdata) +{ + unsigned long flags; + struct srp_event_struct *evt_struct = + (struct srp_event_struct *)crq->IU_data_ptr; + switch (crq->valid) { + case 0xC0: /* initialization */ + switch (crq->format) { + case 0x01: /* Initialization message */ + printk(KERN_INFO "ibmvscsi: partner initialized\n"); + /* Send back a response */ + if (ibmvscsi_send_crq(hostdata, + 0xC002000000000000LL, 0) == 0) { + /* Now login */ + send_srp_login(hostdata); + } else { + printk(KERN_ERR + "ibmvscsi: Unable to send init rsp\n"); + } + + break; + case 0x02: /* Initialization response */ + printk(KERN_INFO + "ibmvscsi: partner initialization complete\n"); + + /* Now login */ + send_srp_login(hostdata); + break; + default: + printk(KERN_ERR "ibmvscsi: unknown crq message type\n"); + } + return; + case 0xFF: /* Hypervisor telling us the connection is closed */ + printk(KERN_INFO "ibmvscsi: Virtual adapter failed!\n"); + + atomic_set(&hostdata->request_limit, -1); + purge_requests(hostdata); + ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + return; + case 0x80: /* real payload */ + break; + default: + printk(KERN_ERR + "ibmvscsi: got an invalid message type 0x%02x\n", + crq->valid); + return; + } + + /* The only kind of payload CRQs we should get are responses to + * things we send. Make sure this response is to something we + * actually sent + */ + if (!valid_event_struct(&hostdata->pool, evt_struct)) { + printk(KERN_ERR + "ibmvscsi: returned correlation_token 0x%p is invalid!\n", + (void *)crq->IU_data_ptr); + return; + } + + if (crq->format == VIOSRP_SRP_FORMAT) + atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta, + &hostdata->request_limit); + + if (evt_struct->done) + evt_struct->done(evt_struct); + else + printk(KERN_ERR + "ibmvscsi: returned done() is NULL; not running it!\n"); + + /* + * Lock the host_lock before messing with these structures, since we + * are running in a task context + */ + spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags); + list_del(&evt_struct->list); + free_event_struct(&evt_struct->hostdata->pool, evt_struct); + spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags); +} + +/** + * ibmvscsi_get_host_config: Send the command to the server to get host + * configuration data. The data is opaque to us. + */ +static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, + unsigned char *buffer, int length) +{ + struct viosrp_host_config *host_config; + struct srp_event_struct *evt_struct; + int rc; + + evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) { + printk(KERN_ERR + "ibmvscsi: could't allocate event for HOST_CONFIG!\n"); + return -1; + } + + init_event_struct(evt_struct, + sync_completion, + VIOSRP_MAD_FORMAT, + init_timeout * HZ); + + host_config = &evt_struct->iu.mad.host_config; + + /* Set up a lun reset SRP command */ + memset(host_config, 0x00, sizeof(*host_config)); + host_config->common.type = VIOSRP_HOST_CONFIG_TYPE; + host_config->common.length = length; + host_config->buffer = dma_map_single(hostdata->dev, buffer, length, + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(host_config->buffer)) { + printk(KERN_ERR + "ibmvscsi: dma_mapping error " "getting host config\n"); + free_event_struct(&hostdata->pool, evt_struct); + return -1; + } + + init_completion(&evt_struct->comp); + rc = ibmvscsi_send_srp_event(evt_struct, hostdata); + if (rc == 0) { + wait_for_completion(&evt_struct->comp); + dma_unmap_single(hostdata->dev, host_config->buffer, + length, DMA_BIDIRECTIONAL); + } + + return rc; +} + +/* ------------------------------------------------------------ + * sysfs attributes + */ +static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%s\n", + hostdata->madapter_info.srp_version); + return len; +} + +static struct class_device_attribute ibmvscsi_host_srp_version = { + .attr = { + .name = "srp_version", + .mode = S_IRUGO, + }, + .show = show_host_srp_version, +}; + +static ssize_t show_host_partition_name(struct class_device *class_dev, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%s\n", + hostdata->madapter_info.partition_name); + return len; +} + +static struct class_device_attribute ibmvscsi_host_partition_name = { + .attr = { + .name = "partition_name", + .mode = S_IRUGO, + }, + .show = show_host_partition_name, +}; + +static ssize_t show_host_partition_number(struct class_device *class_dev, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%d\n", + hostdata->madapter_info.partition_number); + return len; +} + +static struct class_device_attribute ibmvscsi_host_partition_number = { + .attr = { + .name = "partition_number", + .mode = S_IRUGO, + }, + .show = show_host_partition_number, +}; + +static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%d\n", + hostdata->madapter_info.mad_version); + return len; +} + +static struct class_device_attribute ibmvscsi_host_mad_version = { + .attr = { + .name = "mad_version", + .mode = S_IRUGO, + }, + .show = show_host_mad_version, +}; + +static ssize_t show_host_os_type(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type); + return len; +} + +static struct class_device_attribute ibmvscsi_host_os_type = { + .attr = { + .name = "os_type", + .mode = S_IRUGO, + }, + .show = show_host_os_type, +}; + +static ssize_t show_host_config(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + + /* returns null-terminated host config data */ + if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0) + return strlen(buf); + else + return 0; +} + +static struct class_device_attribute ibmvscsi_host_config = { + .attr = { + .name = "config", + .mode = S_IRUGO, + }, + .show = show_host_config, +}; + +static struct class_device_attribute *ibmvscsi_attrs[] = { + &ibmvscsi_host_srp_version, + &ibmvscsi_host_partition_name, + &ibmvscsi_host_partition_number, + &ibmvscsi_host_mad_version, + &ibmvscsi_host_os_type, + &ibmvscsi_host_config, + NULL +}; + +/* ------------------------------------------------------------ + * SCSI driver registration + */ +static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION, + .proc_name = "ibmvscsi", + .queuecommand = ibmvscsi_queuecommand, + .eh_abort_handler = ibmvscsi_eh_abort_handler, + .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler, + .cmd_per_lun = 16, + .can_queue = 1, /* Updated after SRP_LOGIN */ + .this_id = -1, + .sg_tablesize = MAX_INDIRECT_BUFS, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = ibmvscsi_attrs, +}; + +/** + * Called by bus code for each adapter + */ +static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + struct ibmvscsi_host_data *hostdata; + struct Scsi_Host *host; + struct device *dev = &vdev->dev; + unsigned long wait_switch = 0; + + vdev->dev.driver_data = NULL; + + host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); + if (!host) { + printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n"); + goto scsi_host_alloc_failed; + } + + hostdata = (struct ibmvscsi_host_data *)host->hostdata; + memset(hostdata, 0x00, sizeof(*hostdata)); + INIT_LIST_HEAD(&hostdata->sent); + hostdata->host = host; + hostdata->dev = dev; + atomic_set(&hostdata->request_limit, -1); + + if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, + max_requests) != 0) { + printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n"); + goto init_crq_failed; + } + if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n"); + goto init_pool_failed; + } + + host->max_lun = 8; + host->max_id = max_id; + host->max_channel = max_channel; + + if (scsi_add_host(hostdata->host, hostdata->dev)) + goto add_host_failed; + + /* Try to send an initialization message. Note that this is allowed + * to fail if the other end is not acive. In that case we don't + * want to scan + */ + if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) { + /* + * Wait around max init_timeout secs for the adapter to finish + * initializing. When we are done initializing, we will have a + * valid request_limit. We don't want Linux scanning before + * we are ready. + */ + for (wait_switch = jiffies + (init_timeout * HZ); + time_before(jiffies, wait_switch) && + atomic_read(&hostdata->request_limit) < 0;) { + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100); + } + + /* if we now have a valid request_limit, initiate a scan */ + if (atomic_read(&hostdata->request_limit) > 0) + scsi_scan_host(host); + } + + vdev->dev.driver_data = hostdata; + return 0; + + add_host_failed: + release_event_pool(&hostdata->pool, hostdata); + init_pool_failed: + ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests); + init_crq_failed: + scsi_host_put(host); + scsi_host_alloc_failed: + return -1; +} + +static int ibmvscsi_remove(struct vio_dev *vdev) +{ + struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data; + release_event_pool(&hostdata->pool, hostdata); + ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, + max_requests); + + scsi_remove_host(hostdata->host); + scsi_host_put(hostdata->host); + + return 0; +} + +/** + * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we + * support. + */ +static struct vio_device_id ibmvscsi_device_table[] __devinitdata = { + {"vscsi", "IBM,v-scsi"}, + {0,} +}; + +MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table); +static struct vio_driver ibmvscsi_driver = { + .name = "ibmvscsi", + .id_table = ibmvscsi_device_table, + .probe = ibmvscsi_probe, + .remove = ibmvscsi_remove +}; + +int __init ibmvscsi_module_init(void) +{ + return vio_register_driver(&ibmvscsi_driver); +} + +void __exit ibmvscsi_module_exit(void) +{ + vio_unregister_driver(&ibmvscsi_driver); +} + +module_init(ibmvscsi_module_init); +module_exit(ibmvscsi_module_exit); diff -Nru a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,108 @@ +/* ------------------------------------------------------------ + * ibmvscsi.h + * (C) Copyright IBM Corporation 1994, 2003 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * Dave Boutcher (sleddog@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * ------------------------------------------------------------ + * Emulation of a SCSI host adapter for Virtual I/O devices + * + * This driver allows the Linux SCSI peripheral drivers to directly + * access devices in the hosting partition, either on an iSeries + * hypervisor system or a converged hypervisor system. + */ +#ifndef IBMVSCSI_H +#define IBMVSCSI_H +#include +#include +#include +#include +#include "viosrp.h" + +struct scsi_cmnd; +struct Scsi_Host; + +/* Number of indirect bufs...the list of these has to fit in the + * additional data of the srp_cmd struct along with the indirect + * descriptor + */ +#define MAX_INDIRECT_BUFS 10 + +/* ------------------------------------------------------------ + * Data Structures + */ +/* an RPA command/response transport queue */ +struct crq_queue { + struct viosrp_crq *msgs; + int size, cur; + dma_addr_t msg_token; + spinlock_t lock; +}; + +/* a unit of work for the hosting partition */ +struct srp_event_struct { + union viosrp_iu *xfer_iu; + struct scsi_cmnd *cmnd; + struct list_head list; + void (*done) (struct srp_event_struct *); + struct viosrp_crq crq; + struct ibmvscsi_host_data *hostdata; + atomic_t free; + union viosrp_iu iu; + void (*cmnd_done) (struct scsi_cmnd *); + struct completion comp; +}; + +/* a pool of event structs for use */ +struct event_pool { + struct srp_event_struct *events; + u32 size; + int next; + union viosrp_iu *iu_storage; + dma_addr_t iu_token; +}; + +/* all driver data associated with a host adapter */ +struct ibmvscsi_host_data { + atomic_t request_limit; + struct device *dev; + struct event_pool pool; + struct crq_queue queue; + struct tasklet_struct srp_task; + struct list_head sent; + struct Scsi_Host *host; + struct mad_adapter_info_data madapter_info; +}; + +/* routines for managing a command/response queue */ +int ibmvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests); +void ibmvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests); +void ibmvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata); + +void ibmvscsi_handle_crq(struct viosrp_crq *crq, + struct ibmvscsi_host_data *hostdata); +int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, + u64 word1, u64 word2); + +#endif /* IBMVSCSI_H */ diff -Nru a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,144 @@ +/* ------------------------------------------------------------ + * iSeries_vscsi.c + * (C) Copyright IBM Corporation 1994, 2003 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * Dave Boutcher (sleddog@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * ------------------------------------------------------------ + * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices + * + * This driver allows the Linux SCSI peripheral drivers to directly + * access devices in the hosting partition, either on an iSeries + * hypervisor system or a converged hypervisor system. + */ + +#include +#include +#include +#include +#include +#include +#include "ibmvscsi.h" + +/* global variables */ +static struct ibmvscsi_host_data *single_host_data; + +/* ------------------------------------------------------------ + * Routines for direct interpartition interaction + */ +struct srp_lp_event { + struct HvLpEvent lpevt; /* 0x00-0x17 */ + u32 reserved1; /* 0x18-0x1B; unused */ + u16 version; /* 0x1C-0x1D; unused */ + u16 subtype_rc; /* 0x1E-0x1F; unused */ + struct viosrp_crq crq; /* 0x20-0x3F */ +}; + +/** + * standard interface for handling logical partition events. + */ +static void ibmvscsi_handle_event(struct HvLpEvent *lpevt) +{ + struct srp_lp_event *evt = (struct srp_lp_event *)lpevt; + + if (!evt) { + printk(KERN_ERR "ibmvscsi: received null event\n"); + return; + } + + if (single_host_data == NULL) { + printk(KERN_ERR + "ibmvscsi: received event, no adapter present\n"); + return; + } + + ibmvscsi_handle_crq(&evt->crq, single_host_data); +} + +/* ------------------------------------------------------------ + * Routines for driver initialization + */ +int ibmvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + int rc; + + single_host_data = hostdata; + rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0); + if (rc < 0) { + printk("viopath_open failed with rc %d in open_event_path\n", + rc); + goto viopath_open_failed; + } + + rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event); + if (rc < 0) { + printk("vio_setHandler failed with rc %d in open_event_path\n", + rc); + goto vio_setHandler_failed; + } + return 0; + + vio_setHandler_failed: + viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); + viopath_open_failed: + return -1; +} + +void ibmvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + vio_clearHandler(viomajorsubtype_scsi); + viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); +} + +/** + * reset_crq_queue: - resets a crq after a failure + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + * no-op for iSeries + */ +void ibmvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) +{ +} + +/** + * ibmvscsi_send_crq: - Send a CRQ + * @hostdata: the adapter + * @word1: the first 64 bits of the data + * @word2: the second 64 bits of the data + */ +int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) +{ + single_host_data = hostdata; + return HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_scsi, + HvLpEvent_AckInd_NoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, + VIOVERSION << 16, word1, word2, 0, + 0); +} diff -Nru a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,260 @@ +/* ------------------------------------------------------------ + * rpa_vscsi.c + * (C) Copyright IBM Corporation 1994, 2003 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * ------------------------------------------------------------ + * RPA-specific functions of the SCSI host adapter for Virtual I/O devices + * + * This driver allows the Linux SCSI peripheral drivers to directly + * access devices in the hosting partition, either on an iSeries + * hypervisor system or a converged hypervisor system. + */ + +#include +#include +#include +#include +#include +#include "ibmvscsi.h" + +/* ------------------------------------------------------------ + * Routines for managing the command/response queue + */ +/** + * ibmvscsi_handle_event: - Interrupt handler for crq events + * @irq: number of irq to handle, not used + * @dev_instance: ibmvscsi_host_data of host that received interrupt + * @regs: pt_regs with registers + * + * Disables interrupts and schedules srp_task + * Always returns IRQ_HANDLED + */ +static irqreturn_t ibmvscsi_handle_event(int irq, + void *dev_instance, + struct pt_regs *regs) +{ + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)dev_instance; + vio_disable_interrupts(to_vio_dev(hostdata->dev)); + tasklet_schedule(&hostdata->srp_task); + return IRQ_HANDLED; +} + +/** + * release_crq_queue: - Deallocates data and unregisters CRQ + * @queue: crq_queue to initialize and register + * @host_data: ibmvscsi_host_data of host + * + * Frees irq, deallocates a page for messages, unmaps dma, and unregisters + * the crq with the hypervisor. + */ +void ibmvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + long rc; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + free_irq(vdev->irq, (void *)hostdata); + tasklet_kill(&hostdata->srp_task); + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while ((rc == H_Busy) || (H_isLongBusy(rc))); + dma_unmap_single(hostdata->dev, + queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); + free_page((unsigned long)queue->msgs); +} + +/** + * crq_queue_next_crq: - Returns the next entry in message queue + * @queue: crq_queue to use + * + * Returns pointer to next entry in queue, or NULL if there are no new + * entried in the CRQ. + */ +static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue) +{ + struct viosrp_crq *crq; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + crq = &queue->msgs[queue->cur]; + if (crq->valid & 0x80) { + if (++queue->cur == queue->size) + queue->cur = 0; + } else + crq = NULL; + spin_unlock_irqrestore(&queue->lock, flags); + + return crq; +} + +/** + * ibmvscsi_send_crq: - Send a CRQ + * @hostdata: the adapter + * @word1: the first 64 bits of the data + * @word2: the second 64 bits of the data + */ +int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) +{ + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + + return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); +} + +/** + * ibmvscsi_task: - Process srps asynchronously + * @data: ibmvscsi_host_data of host + */ +static void ibmvscsi_task(void *data) +{ + struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + struct viosrp_crq *crq; + int done = 0; + + while (!done) { + /* Pull all the valid messages off the CRQ */ + while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { + ibmvscsi_handle_crq(crq, hostdata); + crq->valid = 0x00; + } + + vio_enable_interrupts(vdev); + if ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { + vio_disable_interrupts(vdev); + ibmvscsi_handle_crq(crq, hostdata); + crq->valid = 0x00; + } else { + done = 1; + } + } +} + +/** + * initialize_crq_queue: - Initializes and registers CRQ with hypervisor + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + * Allocates a page for messages, maps it for dma, and registers + * the crq with the hypervisor. + * Returns zero on success. + */ +int ibmvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + int rc; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + + queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); + + if (!queue->msgs) + goto malloc_failed; + queue->size = PAGE_SIZE / sizeof(*queue->msgs); + + queue->msg_token = dma_map_single(hostdata->dev, queue->msgs, + queue->size * sizeof(*queue->msgs), + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(queue->msg_token)) + goto map_failed; + + rc = plpar_hcall_norets(H_REG_CRQ, + vdev->unit_address, + queue->msg_token, PAGE_SIZE); + if (rc == 2) { + /* Adapter is good, but other end is not ready */ + printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n"); + } else if (rc != 0) { + printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc); + goto reg_crq_failed; + } + + if (request_irq(vdev->irq, + ibmvscsi_handle_event, + 0, "ibmvscsi", (void *)hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: couldn't register irq 0x%x\n", + vdev->irq); + goto req_irq_failed; + } + + rc = vio_enable_interrupts(vdev); + if (rc != 0) { + printk(KERN_ERR "ibmvscsi: Error %d enabling interrupts!!!\n", + rc); + goto req_irq_failed; + } + + queue->cur = 0; + queue->lock = SPIN_LOCK_UNLOCKED; + + tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task, + (unsigned long)hostdata); + + return 0; + + req_irq_failed: + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while ((rc == H_Busy) || (H_isLongBusy(rc))); + reg_crq_failed: + dma_unmap_single(hostdata->dev, + queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); + map_failed: + free_page((unsigned long)queue->msgs); + malloc_failed: + return -1; +} + +/** + * reset_crq_queue: - resets a crq after a failure + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + */ +void ibmvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) +{ + int rc; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + + /* Close the CRQ */ + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while ((rc == H_Busy) || (H_isLongBusy(rc))); + + /* Clean out the queue */ + memset(queue->msgs, 0x00, PAGE_SIZE); + queue->cur = 0; + + /* And re-open it again */ + rc = plpar_hcall_norets(H_REG_CRQ, + vdev->unit_address, + queue->msg_token, PAGE_SIZE); + if (rc == 2) { + /* Adapter is good, but other end is not ready */ + printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n"); + } else if (rc != 0) { + printk(KERN_WARNING + "ibmvscsi: couldn't register crq--rc 0x%x\n", rc); + } +} diff -Nru a/drivers/scsi/ibmvscsi/srp.h b/drivers/scsi/ibmvscsi/srp.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ibmvscsi/srp.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,225 @@ +/*****************************************************************************/ +/* srp.h -- SCSI RDMA Protocol definitions */ +/* */ +/* Written By: Colin Devilbis, IBM Corporation */ +/* */ +/* Copyright (C) 2003 IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* */ +/* This file contains structures and definitions for the SCSI RDMA Protocol */ +/* (SRP) as defined in the T10 standard available at www.t10.org. This */ +/* file was based on the 16a version of the standard */ +/* */ +/*****************************************************************************/ +#ifndef SRP_H +#define SRP_H + +#define PACKED __attribute__((packed)) + +enum srp_types { + SRP_LOGIN_REQ_TYPE = 0x00, + SRP_LOGIN_RSP_TYPE = 0xC0, + SRP_LOGIN_REJ_TYPE = 0x80, + SRP_I_LOGOUT_TYPE = 0x03, + SRP_T_LOGOUT_TYPE = 0x80, + SRP_TSK_MGMT_TYPE = 0x01, + SRP_CMD_TYPE = 0x02, + SRP_RSP_TYPE = 0xC1, + SRP_CRED_REQ_TYPE = 0x81, + SRP_CRED_RSP_TYPE = 0x41, + SRP_AER_REQ_TYPE = 0x82, + SRP_AER_RSP_TYPE = 0x42 +}; + +enum srp_descriptor_formats { + SRP_NO_BUFFER = 0x00, + SRP_DIRECT_BUFFER = 0x01, + SRP_INDIRECT_BUFFER = 0x02 +}; + +struct memory_descriptor { + u64 virtual_address; + u32 memory_handle; + u32 length; +}; + +struct indirect_descriptor { + struct memory_descriptor head; + u32 total_length; + struct memory_descriptor list[1] PACKED; +}; + +struct srp_generic { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +struct srp_login_req { + u8 type; + u8 reserved1[7]; + u64 tag; + u32 max_requested_initiator_to_target_iulen; + u32 reserved2; + u16 required_buffer_formats; + u8 reserved3:6; + u8 multi_channel_action:2; + u8 reserved4; + u32 reserved5; + u8 initiator_port_identifier[16]; + u8 target_port_identifier[16]; +}; + +struct srp_login_rsp { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; + u32 max_initiator_to_target_iulen; + u32 max_target_to_initiator_iulen; + u16 supported_buffer_formats; + u8 reserved2:6; + u8 multi_channel_result:2; + u8 reserved3; + u8 reserved4[24]; +}; + +struct srp_login_rej { + u8 type; + u8 reserved1[3]; + u32 reason; + u64 tag; + u64 reserved2; + u16 supported_buffer_formats; + u8 reserved3[6]; +}; + +struct srp_i_logout { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +struct srp_t_logout { + u8 type; + u8 reserved1[3]; + u32 reason; + u64 tag; +}; + +struct srp_tsk_mgmt { + u8 type; + u8 reserved1[7]; + u64 tag; + u32 reserved2; + u64 lun PACKED; + u8 reserved3; + u8 reserved4; + u8 task_mgmt_flags; + u8 reserved5; + u64 managed_task_tag; + u64 reserved6; +}; + +struct srp_cmd { + u8 type; + u32 reserved1 PACKED; + u8 data_out_format:4; + u8 data_in_format:4; + u8 data_out_count; + u8 data_in_count; + u64 tag; + u32 reserved2; + u64 lun PACKED; + u8 reserved3; + u8 reserved4:5; + u8 task_attribute:3; + u8 reserved5; + u8 additional_cdb_len; + u8 cdb[16]; + u8 additional_data[0x100 - 0x30]; +}; + +struct srp_rsp { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; + u16 reserved2; + u8 reserved3:2; + u8 diunder:1; + u8 diover:1; + u8 dounder:1; + u8 doover:1; + u8 snsvalid:1; + u8 rspvalid:1; + u8 status; + u32 data_in_residual_count; + u32 data_out_residual_count; + u32 sense_data_list_length; + u32 response_data_list_length; + u8 sense_and_response_data[18]; +}; + +struct srp_cred_req { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; +}; + +struct srp_cred_rsp { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +struct srp_aer_req { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; + u32 reserved2; + u64 lun; + u32 sense_data_list_length; + u32 reserved3; + u8 sense_data[20]; +}; + +struct srp_aer_rsp { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +union srp_iu { + struct srp_generic generic; + struct srp_login_req login_req; + struct srp_login_rsp login_rsp; + struct srp_login_rej login_rej; + struct srp_i_logout i_logout; + struct srp_t_logout t_logout; + struct srp_tsk_mgmt tsk_mgmt; + struct srp_cmd cmd; + struct srp_rsp rsp; + struct srp_cred_req cred_req; + struct srp_cred_rsp cred_rsp; + struct srp_aer_req aer_req; + struct srp_aer_rsp aer_rsp; +}; + +#endif diff -Nru a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ibmvscsi/viosrp.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,126 @@ +/*****************************************************************************/ +/* srp.h -- SCSI RDMA Protocol definitions */ +/* */ +/* Written By: Colin Devilbis, IBM Corporation */ +/* */ +/* Copyright (C) 2003 IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* */ +/* This file contains structures and definitions for IBM RPA (RS/6000 */ +/* platform architecture) implementation of the SRP (SCSI RDMA Protocol) */ +/* standard. SRP is used on IBM iSeries and pSeries platforms to send SCSI */ +/* commands between logical partitions. */ +/* */ +/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ) */ +/* between partitions. The definitions in this file are architected, */ +/* and cannot be changed without breaking compatibility with other versions */ +/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/ +/* between logical partitions */ +/*****************************************************************************/ +#ifndef VIOSRP_H +#define VIOSRP_H +#include "srp.h" + +enum viosrp_crq_formats { + VIOSRP_SRP_FORMAT = 0x01, + VIOSRP_MAD_FORMAT = 0x02, + VIOSRP_OS400_FORMAT = 0x03, + VIOSRP_AIX_FORMAT = 0x04, + VIOSRP_LINUX_FORMAT = 0x06, + VIOSRP_INLINE_FORMAT = 0x07 +}; + +struct viosrp_crq { + u8 valid; /* used by RPA */ + u8 format; /* SCSI vs out-of-band */ + u8 reserved; + u8 status; /* non-scsi failure? (e.g. DMA failure) */ + u16 timeout; /* in seconds */ + u16 IU_length; /* in bytes */ + u64 IU_data_ptr; /* the TCE for transferring data */ +}; + +/* MADs are Management requests above and beyond the IUs defined in the SRP + * standard. + */ +enum viosrp_mad_types { + VIOSRP_EMPTY_IU_TYPE = 0x01, + VIOSRP_ERROR_LOG_TYPE = 0x02, + VIOSRP_ADAPTER_INFO_TYPE = 0x03, + VIOSRP_HOST_CONFIG_TYPE = 0x04 +}; + +/* + * Common MAD header + */ +struct mad_common { + u32 type; + u16 status; + u16 length; + u64 tag; +}; + +/* + * All SRP (and MAD) requests normally flow from the + * client to the server. There is no way for the server to send + * an asynchronous message back to the client. The Empty IU is used + * to hang out a meaningless request to the server so that it can respond + * asynchrouously with something like a SCSI AER + */ +struct viosrp_empty_iu { + struct mad_common common; + u64 buffer; + u32 port; +}; + +struct viosrp_error_log { + struct mad_common common; + u64 buffer; +}; + +struct viosrp_adapter_info { + struct mad_common common; + u64 buffer; +}; + +struct viosrp_host_config { + struct mad_common common; + u64 buffer; +}; + +union mad_iu { + struct viosrp_empty_iu empty_iu; + struct viosrp_error_log error_log; + struct viosrp_adapter_info adapter_info; + struct viosrp_host_config host_config; +}; + +union viosrp_iu { + union srp_iu srp; + union mad_iu mad; +}; + +struct mad_adapter_info_data { + char srp_version[8]; + char partition_name[96]; + u32 partition_number; + u32 mad_version; + u32 os_type; + u32 port_max_txu[8]; /* per-port maximum transfer */ +}; + +#endif diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c --- a/drivers/scsi/imm.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/imm.c 2004-10-18 14:57:04 -07:00 @@ -758,7 +758,7 @@ case DID_OK: break; case DID_NO_CONNECT: - printk("imm: no device at SCSI ID %i\n", cmd->target); + printk("imm: no device at SCSI ID %i\n", cmd->device->id); break; case DID_BUS_BUSY: printk("imm: BUS BUSY - EPP timeout detected\n"); diff -Nru a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c --- a/drivers/scsi/ipr.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/scsi/ipr.c 2004-10-18 14:57:19 -07:00 @@ -1,7 +1,7 @@ /* * ipr.c -- driver for IBM Power Linux RAID adapters * - * Written By: Brian King, IBM Corporation + * Written By: Brian King , IBM Corporation * * Copyright (C) 2003, 2004 IBM Corporation * @@ -93,7 +93,7 @@ /* This table describes the differences between DMA controller chips */ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { - { /* Gemstone */ + { /* Gemstone and Citrine */ .mailbox = 0x0042C, .cache_line_size = 0x20, { @@ -208,6 +208,8 @@ "Synchronization required"}, {0x024E0000, 0, 0, "No ready, IOA shutdown"}, + {0x025A0000, 0, 0, + "Not ready, IOA has been shutdown"}, {0x02670100, 0, 1, "3020: Storage subsystem configuration error"}, {0x03110B00, 0, 0, @@ -880,11 +882,13 @@ **/ static void ipr_log_vpd(struct ipr_std_inq_vpids *vpids, u8 *serial_num) { - char buffer[max_t(int, sizeof(struct ipr_std_inq_vpids), - IPR_SERIAL_NUM_LEN) + 1]; + char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + + IPR_SERIAL_NUM_LEN]; - memcpy(buffer, vpids, sizeof(struct ipr_std_inq_vpids)); - buffer[sizeof(struct ipr_std_inq_vpids)] = '\0'; + memcpy(buffer, vpids->vendor_id, IPR_VENDOR_ID_LEN); + memcpy(buffer + IPR_VENDOR_ID_LEN, vpids->product_id, + IPR_PROD_ID_LEN); + buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0'; ipr_err("Vendor/Product ID: %s\n", buffer); memcpy(buffer, serial_num, IPR_SERIAL_NUM_LEN); @@ -1766,6 +1770,33 @@ #endif /** + * ipr_release_dump - Free adapter dump memory + * @kref: kref struct + * + * Return value: + * nothing + **/ +static void ipr_release_dump(struct kref *kref) +{ + struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref); + struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; + unsigned long lock_flags = 0; + int i; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ioa_cfg->dump = NULL; + ioa_cfg->sdt_state = INACTIVE; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + for (i = 0; i < dump->ioa_dump.next_page_index; i++) + free_page((unsigned long) dump->ioa_dump.ioa_data[i]); + + kfree(dump); + LEAVE; +} + +/** * ipr_worker_thread - Worker thread * @data: ioa config struct * @@ -1791,13 +1822,14 @@ if (ioa_cfg->sdt_state == GET_DUMP) { dump = ioa_cfg->dump; - if (!dump || !kobject_get(&dump->kobj)) { + if (!dump) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return; } + kref_get(&dump->kref); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); ipr_get_ioa_dump(ioa_cfg, dump); - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); if (ioa_cfg->sdt_state == DUMP_OBTAINED) @@ -2008,7 +2040,7 @@ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); /* Wait for a second for any errors to be logged */ - schedule_timeout(HZ); + msleep(1000); } else { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return -EIO; @@ -2392,15 +2424,15 @@ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); dump = ioa_cfg->dump; - if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump || !kobject_get(&dump->kobj)) { + if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return 0; } - + kref_get(&dump->kref); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); if (off > dump->driver_dump.hdr.len) { - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); return 0; } @@ -2450,42 +2482,11 @@ count -= len; } - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); return rc; } /** - * ipr_release_dump - Free adapter dump memory - * @kobj: kobject struct - * - * Return value: - * nothing - **/ -static void ipr_release_dump(struct kobject *kobj) -{ - struct ipr_dump *dump = container_of(kobj,struct ipr_dump,kobj); - struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; - unsigned long lock_flags = 0; - int i; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - ioa_cfg->dump = NULL; - ioa_cfg->sdt_state = INACTIVE; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - for (i = 0; i < dump->ioa_dump.next_page_index; i++) - free_page((unsigned long) dump->ioa_dump.ioa_data[i]); - - kfree(dump); - LEAVE; -} - -static struct kobj_type ipr_dump_kobj_type = { - .release = ipr_release_dump, -}; - -/** * ipr_alloc_dump - Prepare for adapter dump * @ioa_cfg: ioa config struct * @@ -2506,8 +2507,7 @@ } memset(dump, 0, sizeof(struct ipr_dump)); - kobject_init(&dump->kobj); - dump->kobj.ktype = &ipr_dump_kobj_type; + kref_init(&dump->kref); dump->ioa_cfg = ioa_cfg; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -2554,7 +2554,7 @@ ioa_cfg->dump = NULL; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); LEAVE; return 0; @@ -2690,8 +2690,6 @@ struct ipr_resource_entry *res; unsigned long lock_flags = 0; int tcq_active = simple_strtoul(buf, NULL, 10); - int qdepth = IPR_MAX_CMD_PER_LUN; - int tagged = 0; ssize_t len = -ENXIO; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -2699,13 +2697,13 @@ res = (struct ipr_resource_entry *)sdev->hostdata; if (res) { - res->tcq_active = 0; - qdepth = res->qdepth; - if (ipr_is_gscsi(res) && sdev->tagged_supported) { if (tcq_active) { - tagged = MSG_ORDERED_TAG; res->tcq_active = 1; + scsi_activate_tcq(sdev, res->qdepth); + } else { + res->tcq_active = 0; + scsi_deactivate_tcq(sdev, res->qdepth); } len = strlen(buf); @@ -2715,7 +2713,6 @@ } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - scsi_adjust_queue_depth(sdev, tagged, qdepth); return len; } @@ -2785,7 +2782,8 @@ struct block_device *block_device, sector_t capacity, int *parm) { - int heads, sectors, cylinders; + int heads, sectors; + sector_t cylinders; heads = 128; sectors = 32; @@ -2849,8 +2847,8 @@ sdev->scsi_level = 4; if (ipr_is_vset_device(res)) sdev->timeout = IPR_VSET_RW_TIMEOUT; - - sdev->allow_restart = 1; + if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) + sdev->allow_restart = 1; scsi_adjust_queue_depth(sdev, 0, res->qdepth); } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); @@ -3080,7 +3078,7 @@ struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; struct ipr_cmd_pkt *cmd_pkt; - u32 ioasc, ioarcb_addr; + u32 ioasc; int op_found = 0; ENTER; @@ -3101,21 +3099,15 @@ if (!op_found) return SUCCESS; - ioarcb_addr = be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr); - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_ABORT_TASK; - cmd_pkt->cdb[2] = (ioarcb_addr >> 24) & 0xff; - cmd_pkt->cdb[3] = (ioarcb_addr >> 16) & 0xff; - cmd_pkt->cdb[4] = (ioarcb_addr >> 8) & 0xff; - cmd_pkt->cdb[5] = ioarcb_addr & 0xff; + cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; ipr_cmd->u.sdev = scsi_cmd->device; ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]); - ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_ABORT_TASK_TIMEOUT); + ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT); ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); /* @@ -3737,7 +3729,7 @@ switch (ioasc & IPR_IOASC_IOASC_MASK) { case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: - scsi_cmd->result |= (DID_ERROR << 16); + scsi_cmd->result |= (DID_IMM_RETRY << 16); break; case IPR_IOASC_IR_RESOURCE_HANDLE: scsi_cmd->result |= (DID_NO_CONNECT << 16); @@ -3873,7 +3865,7 @@ * We have told the host to stop giving us new requests, but * ERP ops don't count. FIXME */ - if (unlikely(!ioa_cfg->allow_cmds)) + if (unlikely(!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead)) return SCSI_MLQUEUE_HOST_BUSY; /* @@ -5437,13 +5429,15 @@ **/ static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg) { + struct pci_dev *pdev = ioa_cfg->pdev; + ENTER; - free_irq(ioa_cfg->pdev->irq, ioa_cfg); + free_irq(pdev->irq, ioa_cfg); iounmap((void *) ioa_cfg->hdw_dma_regs); - release_mem_region(ioa_cfg->hdw_dma_regs_pci, - pci_resource_len(ioa_cfg->pdev, 0)); + pci_release_regions(pdev); ipr_free_mem(ioa_cfg); scsi_host_put(ioa_cfg->host); + pci_disable_device(pdev); LEAVE; } @@ -5458,7 +5452,7 @@ { struct ipr_cmnd *ipr_cmd; struct ipr_ioarcb *ioarcb; - u32 dma_addr; + dma_addr_t dma_addr; int i; ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev, @@ -5508,14 +5502,15 @@ **/ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) { - int i; + struct pci_dev *pdev = ioa_cfg->pdev; + int i, rc = -ENOMEM; ENTER; ioa_cfg->res_entries = kmalloc(sizeof(struct ipr_resource_entry) * IPR_MAX_PHYSICAL_DEVS, GFP_KERNEL); if (!ioa_cfg->res_entries) - goto cleanup; + goto out; memset(ioa_cfg->res_entries, 0, sizeof(struct ipr_resource_entry) * IPR_MAX_PHYSICAL_DEVS); @@ -5528,24 +5523,24 @@ &ioa_cfg->vpd_cbs_dma); if (!ioa_cfg->vpd_cbs) - goto cleanup; + goto out_free_res_entries; if (ipr_alloc_cmd_blks(ioa_cfg)) - goto cleanup; + goto out_free_vpd_cbs; ioa_cfg->host_rrq = pci_alloc_consistent(ioa_cfg->pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, &ioa_cfg->host_rrq_dma); if (!ioa_cfg->host_rrq) - goto cleanup; + goto out_ipr_free_cmd_blocks; ioa_cfg->cfg_table = pci_alloc_consistent(ioa_cfg->pdev, sizeof(struct ipr_config_table), &ioa_cfg->cfg_table_dma); if (!ioa_cfg->cfg_table) - goto cleanup; + goto out_free_host_rrq; for (i = 0; i < IPR_NUM_HCAMS; i++) { ioa_cfg->hostrcb[i] = pci_alloc_consistent(ioa_cfg->pdev, @@ -5553,9 +5548,8 @@ &ioa_cfg->hostrcb_dma[i]); if (!ioa_cfg->hostrcb[i]) - goto cleanup; + goto out_free_hostrcb_dma; - memset(ioa_cfg->hostrcb[i], 0, sizeof(struct ipr_hostrcb)); ioa_cfg->hostrcb[i]->hostrcb_dma = ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); @@ -5565,19 +5559,35 @@ IPR_NUM_TRACE_ENTRIES, GFP_KERNEL); if (!ioa_cfg->trace) - goto cleanup; + goto out_free_hostrcb_dma; memset(ioa_cfg->trace, 0, sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES); + rc = 0; +out: LEAVE; - return 0; - -cleanup: - ipr_free_mem(ioa_cfg); + return rc; - LEAVE; - return -ENOMEM; +out_free_hostrcb_dma: + while (i-- > 0) { + pci_free_consistent(pdev, sizeof(struct ipr_hostrcb), + ioa_cfg->hostrcb[i], + ioa_cfg->hostrcb_dma[i]); + } + pci_free_consistent(pdev, sizeof(struct ipr_config_table), + ioa_cfg->cfg_table, ioa_cfg->cfg_table_dma); +out_free_host_rrq: + pci_free_consistent(pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, + ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma); +out_ipr_free_cmd_blocks: + ipr_free_cmd_blks(ioa_cfg); +out_free_vpd_cbs: + pci_free_consistent(pdev, sizeof(struct ipr_misc_cbs), + ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma); +out_free_res_entries: + kfree(ioa_cfg->res_entries); + goto out; } /** @@ -5678,7 +5688,7 @@ if ((rc = pci_enable_device(pdev))) { dev_err(&pdev->dev, "Cannot enable adapter\n"); - return rc; + goto out; } dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); @@ -5687,7 +5697,8 @@ if (!host) { dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_disable; } ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; @@ -5697,12 +5708,11 @@ ipr_regs_pci = pci_resource_start(pdev, 0); - if (!request_mem_region(ipr_regs_pci, - pci_resource_len(pdev, 0), IPR_NAME)) { + rc = pci_request_regions(pdev, IPR_NAME); + if (rc < 0) { dev_err(&pdev->dev, "Couldn't register memory range of registers\n"); - scsi_host_put(host); - return -ENOMEM; + goto out_scsi_host_put; } ipr_regs = (unsigned long)ioremap(ipr_regs_pci, @@ -5711,9 +5721,8 @@ if (!ipr_regs) { dev_err(&pdev->dev, "Couldn't map memory range of registers\n"); - release_mem_region(ipr_regs_pci, pci_resource_len(pdev, 0)); - scsi_host_put(host); - return -ENOMEM; + rc = -ENOMEM; + goto out_release_regions; } ioa_cfg->hdw_dma_regs = ipr_regs; @@ -5723,11 +5732,10 @@ ipr_init_ioa_cfg(ioa_cfg, host, pdev); pci_set_master(pdev); - rc = pci_set_dma_mask(pdev, 0xffffffff); - if (rc != PCIBIOS_SUCCESSFUL) { + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc < 0) { dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); - rc = -EIO; goto cleanup_nomem; } @@ -5755,8 +5763,12 @@ if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg))) goto cleanup_nomem; - if ((rc = ipr_alloc_mem(ioa_cfg))) - goto cleanup; + rc = ipr_alloc_mem(ioa_cfg); + if (rc < 0) { + dev_err(&pdev->dev, + "Couldn't allocate enough memory for device driver!\n"); + goto cleanup_nomem; + } ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); rc = request_irq(pdev->irq, ipr_isr, SA_SHIRQ, IPR_NAME, ioa_cfg); @@ -5772,18 +5784,20 @@ spin_unlock(&ipr_driver_lock); LEAVE; - return 0; +out: + return rc; -cleanup: - dev_err(&pdev->dev, "Couldn't allocate enough memory for device driver!\n"); cleanup_nolog: ipr_free_mem(ioa_cfg); cleanup_nomem: iounmap((void *) ipr_regs); - release_mem_region(ipr_regs_pci, pci_resource_len(pdev, 0)); +out_release_regions: + pci_release_regions(pdev); +out_scsi_host_put: scsi_host_put(host); - - return rc; +out_disable: + pci_disable_device(pdev); + goto out; } /** @@ -5988,9 +6002,15 @@ { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_570F, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, { } }; MODULE_DEVICE_TABLE(pci, ipr_pci_table); @@ -6009,16 +6029,14 @@ * ipr_init - Module entry point * * Return value: - * 0 on success / non-zero on failure + * 0 on success / negative value on failure **/ static int __init ipr_init(void) { ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", IPR_DRIVER_VERSION, IPR_DRIVER_DATE); - pci_register_driver(&ipr_driver); - - return 0; + return pci_module_init(&ipr_driver); } /** diff -Nru a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h --- a/drivers/scsi/ipr.h 2004-10-18 14:56:18 -07:00 +++ b/drivers/scsi/ipr.h 2004-10-18 14:56:18 -07:00 @@ -1,7 +1,7 @@ /* * ipr.h -- driver for IBM Power Linux RAID adapters * - * Written By: Brian King, IBM Corporation + * Written By: Brian King , IBM Corporation * * Copyright (C) 2003, 2004 IBM Corporation * @@ -19,6 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * Alan Cox - Removed several careless u32/dma_addr_t errors + * that broke 64bit platforms. */ #ifndef _IPR_H @@ -27,6 +29,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_KDB @@ -36,8 +39,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.0.10" -#define IPR_DRIVER_DATE "(June 7, 2004)" +#define IPR_DRIVER_VERSION "2.0.11" +#define IPR_DRIVER_DATE "(August 3, 2004)" /* * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing @@ -72,6 +75,8 @@ #define IPR_SUBS_DEV_ID_5703 0x0278 #define IPR_SUBS_DEV_ID_572E 0x02D3 #define IPR_SUBS_DEV_ID_573D 0x02D4 +#define IPR_SUBS_DEV_ID_570F 0x02BD +#define IPR_SUBS_DEV_ID_571B 0x02BE #define IPR_NAME "ipr" @@ -148,7 +153,6 @@ #define IPR_BUS_RESET 0x10 #define IPR_ID_HOST_RR_Q 0xC4 #define IPR_QUERY_IOA_CONFIG 0xC5 -#define IPR_ABORT_TASK 0xC7 #define IPR_CANCEL_ALL_REQUESTS 0xCE #define IPR_HOST_CONTROLLED_ASYNC 0xCF #define IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE 0x01 @@ -667,7 +671,7 @@ struct ipr_hostrcb { struct ipr_hcam hcam; - u32 hostrcb_dma; + dma_addr_t hostrcb_dma; struct list_head queue; }; @@ -850,7 +854,7 @@ char cfg_table_start[8]; #define IPR_CFG_TBL_START "cfg" struct ipr_config_table *cfg_table; - u32 cfg_table_dma; + dma_addr_t cfg_table_dma; char resource_table_label[8]; #define IPR_RES_TABLE_LABEL "res_tbl" @@ -861,12 +865,12 @@ char ipr_hcam_label[8]; #define IPR_HCAM_LABEL "hcams" struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS]; - u32 hostrcb_dma[IPR_NUM_HCAMS]; + dma_addr_t hostrcb_dma[IPR_NUM_HCAMS]; struct list_head hostrcb_free_q; struct list_head hostrcb_pending_q; u32 *host_rrq; - u32 host_rrq_dma; + dma_addr_t host_rrq_dma; #define IPR_HRRQ_REQ_RESP_HANDLE_MASK 0xfffffffc #define IPR_HRRQ_RESP_BIT_SET 0x00000002 #define IPR_HRRQ_TOGGLE_BIT 0x00000001 @@ -905,7 +909,7 @@ enum ipr_sdt_state sdt_state; struct ipr_misc_cbs *vpd_cbs; - u32 vpd_cbs_dma; + dma_addr_t vpd_cbs_dma; struct pci_pool *ipr_cmd_pool; @@ -1029,7 +1033,7 @@ }__attribute__((packed, aligned (4))); struct ipr_dump { - struct kobject kobj; + struct kref kref; struct ipr_ioa_cfg *ioa_cfg; struct ipr_driver_dump driver_dump; struct ipr_ioa_dump ioa_dump; diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c --- a/drivers/scsi/ips.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/scsi/ips.c 2004-10-18 14:55:53 -07:00 @@ -215,7 +215,7 @@ #endif #else #define IPS_SG_ADDRESS(sg) (page_address((sg)->page) ? \ - page_address((sg)->page)+(sg)->offset : 0) + page_address((sg)->page)+(sg)->offset : NULL) #define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0) #define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0) #endif @@ -474,21 +474,17 @@ static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); static uint32_t ips_statupd_morpheus(ips_ha_t *); static ips_scb_t *ips_getscb(ips_ha_t *); -static inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_scb_tail(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_wait_head(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_copp_head(ips_copp_queue_t *, +static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); +static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); +static void ips_putq_copp_tail(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline void ips_putq_copp_tail(ips_copp_queue_t *, - ips_copp_wait_item_t *); -static inline ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); -static inline ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); -static inline Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); -static inline Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); -static inline ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, +static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); +static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); +static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); +static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); +static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); +static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); static int ips_is_passthru(Scsi_Cmnd *); static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); @@ -1885,7 +1881,7 @@ /* Fill in a single scb sg_list element from an address */ /* return a -1 if a breakup occurred */ /****************************************************************************/ -static inline int +static int ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, ips_scb_t * scb, int indx, unsigned int e_len) { @@ -2950,7 +2946,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) { METHOD_TRACE("ips_putq_scb_head", 1); @@ -2969,38 +2965,6 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_putq_scb_tail */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the tail of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item) -{ - METHOD_TRACE("ips_putq_scb_tail", 1); - - if (!item) - return; - - item->q_next = NULL; - - if (queue->tail) - queue->tail->q_next = item; - - queue->tail = item; - - if (!queue->head) - queue->head = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_removeq_scb_head */ /* */ /* Routine Description: */ @@ -3010,7 +2974,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb_head(ips_scb_queue_t * queue) { ips_scb_t *item; @@ -3045,7 +3009,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) { ips_scb_t *p; @@ -3082,34 +3046,6 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_putq_wait_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item) -{ - METHOD_TRACE("ips_putq_wait_head", 1); - - if (!item) - return; - - item->host_scribble = (char *) queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_putq_wait_tail */ /* */ /* Routine Description: */ @@ -3119,7 +3055,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) { METHOD_TRACE("ips_putq_wait_tail", 1); @@ -3151,7 +3087,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait_head(ips_wait_queue_t * queue) { Scsi_Cmnd *item; @@ -3186,7 +3122,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) { Scsi_Cmnd *p; @@ -3223,34 +3159,6 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_putq_copp_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) -{ - METHOD_TRACE("ips_putq_copp_head", 1); - - if (!item) - return; - - item->next = queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_putq_copp_tail */ /* */ /* Routine Description: */ @@ -3260,7 +3168,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { METHOD_TRACE("ips_putq_copp_tail", 1); @@ -3292,7 +3200,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t * queue) { ips_copp_wait_item_t *item; @@ -3327,7 +3235,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { ips_copp_wait_item_t *p; @@ -6946,8 +6854,8 @@ { ha->active = 0; ips_free(ha); - ips_ha[index] = 0; - ips_sh[index] = 0; + ips_ha[index] = NULL; + ips_sh[index] = NULL; return -1; } diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/scsi/libata-core.c 2004-10-18 14:55:53 -07:00 @@ -43,18 +43,21 @@ #include #include #include +#include #include "libata.h" static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); -static void __ata_dev_select (struct ata_port *ap, unsigned int device); -static void ata_host_set_pio(struct ata_port *ap); -static void ata_host_set_udma(struct ata_port *ap); -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device); -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device); static void ata_set_mode(struct ata_port *ap); +static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static int fgb(u32 bitmap); +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out); +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; @@ -64,17 +67,17 @@ MODULE_LICENSE("GPL"); /** - * ata_tf_load_pio - send taskfile registers to host controller + * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * - * Outputs ATA taskfile to standard ATA host controller using PIO. + * Outputs ATA taskfile to standard ATA host controller. * * LOCKING: * Inherited from caller. */ -void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -132,23 +135,23 @@ * Inherited from caller. */ -void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, ap->ioaddr.ctl_addr); + writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, (void *) ioaddr->feature_addr); - writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr); - writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr); - writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr); - writeb(tf->hob_lbah, (void *) ioaddr->lbah_addr); + writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr); + writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr); + writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr); + writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr); + writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr); VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", tf->hob_feature, tf->hob_nsect, @@ -158,11 +161,11 @@ } if (is_addr) { - writeb(tf->feature, (void *) ioaddr->feature_addr); - writeb(tf->nsect, (void *) ioaddr->nsect_addr); - writeb(tf->lbal, (void *) ioaddr->lbal_addr); - writeb(tf->lbam, (void *) ioaddr->lbam_addr); - writeb(tf->lbah, (void *) ioaddr->lbah_addr); + writeb(tf->feature, (void __iomem *) ioaddr->feature_addr); + writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr); + writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr); + writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr); + writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr); VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", tf->feature, tf->nsect, @@ -172,26 +175,34 @@ } if (tf->flags & ATA_TFLAG_DEVICE) { - writeb(tf->device, (void *) ioaddr->device_addr); + writeb(tf->device, (void __iomem *) ioaddr->device_addr); VPRINTK("device 0x%X\n", tf->device); } ata_wait_idle(ap); } +void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_tf_load_mmio(ap, tf); + else + ata_tf_load_pio(ap, tf); +} + /** - * ata_exec_command_pio - issue ATA command to host controller + * ata_exec_command - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues PIO write to ATA command register, with proper + * Issues PIO/MMIO write to ATA command register, with proper * synchronization with interrupt handler / other threads. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -212,20 +223,28 @@ * spin_lock_irqsave(host_set lock) */ -void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - writeb(tf->command, (void *) ap->ioaddr.command_addr); + writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr); ata_pause(ap); } +void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_exec_command_mmio(ap, tf); + else + ata_exec_command_pio(ap, tf); +} + /** * ata_exec - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues PIO write to ATA command register, with proper + * Issues PIO/MMIO write to ATA command register, with proper * synchronization with interrupt handler / other threads. * * LOCKING: @@ -248,7 +267,7 @@ * @tf: ATA taskfile register set * * Issues ATA taskfile register set to ATA host controller, - * via PIO, with proper synchronization with interrupt handler and + * with proper synchronization with interrupt handler and * other threads. * * LOCKING: @@ -268,7 +287,7 @@ * @tf: ATA taskfile register set * * Issues ATA taskfile register set to ATA host controller, - * via PIO, with proper synchronization with interrupt handler and + * with proper synchronization with interrupt handler and * other threads. * * LOCKING: @@ -282,18 +301,18 @@ } /** - * ata_tf_read_pio - input device's ATA taskfile shadow registers + * ata_tf_read - input device's ATA taskfile shadow registers * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * * Reads ATA taskfile registers for currently-selected device - * into @tf via PIO. + * into @tf. * * LOCKING: * Inherited from caller. */ -void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -325,38 +344,46 @@ * Inherited from caller. */ -void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->nsect = readb((void *)ioaddr->nsect_addr); - tf->lbal = readb((void *)ioaddr->lbal_addr); - tf->lbam = readb((void *)ioaddr->lbam_addr); - tf->lbah = readb((void *)ioaddr->lbah_addr); - tf->device = readb((void *)ioaddr->device_addr); + tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); + tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); + tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); + tf->lbah = readb((void __iomem *)ioaddr->lbah_addr); + tf->device = readb((void __iomem *)ioaddr->device_addr); if (tf->flags & ATA_TFLAG_LBA48) { - writeb(tf->ctl | ATA_HOB, ap->ioaddr.ctl_addr); - tf->hob_feature = readb((void *)ioaddr->error_addr); - tf->hob_nsect = readb((void *)ioaddr->nsect_addr); - tf->hob_lbal = readb((void *)ioaddr->lbal_addr); - tf->hob_lbam = readb((void *)ioaddr->lbam_addr); - tf->hob_lbah = readb((void *)ioaddr->lbah_addr); + writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr); + tf->hob_feature = readb((void __iomem *)ioaddr->error_addr); + tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr); + tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr); + tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr); + tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr); } } +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_tf_read_mmio(ap, tf); + else + ata_tf_read_pio(ap, tf); +} + /** - * ata_check_status_pio - Read device status reg & clear interrupt + * ata_check_status - Read device status reg & clear interrupt * @ap: port where the device is * * Reads ATA taskfile status register for currently-selected device - * via PIO and return it's value. This also clears pending interrupts + * and return it's value. This also clears pending interrupts * from this device * * LOCKING: * Inherited from caller. */ -u8 ata_check_status_pio(struct ata_port *ap) +static u8 ata_check_status_pio(struct ata_port *ap) { return inb(ap->ioaddr.status_addr); } @@ -372,9 +399,16 @@ * LOCKING: * Inherited from caller. */ -u8 ata_check_status_mmio(struct ata_port *ap) +static u8 ata_check_status_mmio(struct ata_port *ap) +{ + return readb((void __iomem *) ap->ioaddr.status_addr); +} + +u8 ata_check_status(struct ata_port *ap) { - return readb((void *) ap->ioaddr.status_addr); + if (ap->flags & ATA_FLAG_MMIO) + return ata_check_status_mmio(ap); + return ata_check_status_pio(ap); } /** @@ -524,7 +558,7 @@ dev->write_cmd = (cmd >> 8) & 0xff; } -static const char * udma_str[] = { +static const char * xfer_mode_str[] = { "UDMA/16", "UDMA/25", "UDMA/33", @@ -533,6 +567,14 @@ "UDMA/100", "UDMA/133", "UDMA7", + "MWDMA0", + "MWDMA1", + "MWDMA2", + "PIO0", + "PIO1", + "PIO2", + "PIO3", + "PIO4", }; /** @@ -550,16 +592,24 @@ * @udma_mask, or the constant C string "". */ -static const char *ata_udma_string(unsigned int udma_mask) +static const char *ata_mode_string(unsigned int mask) { int i; - for (i = 7; i >= 0; i--) { - if (udma_mask & (1 << i)) - return udma_str[i]; - } + for (i = 7; i >= 0; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--) + if (mask & (1 << i)) + goto out; return ""; + +out: + return xfer_mode_str[i]; } /** @@ -586,7 +636,7 @@ struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); outb(0x55, ioaddr->nsect_addr); outb(0xaa, ioaddr->lbal_addr); @@ -630,19 +680,19 @@ struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); - writeb(0x55, (void *) ioaddr->nsect_addr); - writeb(0xaa, (void *) ioaddr->lbal_addr); + writeb(0x55, (void __iomem *) ioaddr->nsect_addr); + writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); - writeb(0xaa, (void *) ioaddr->nsect_addr); - writeb(0x55, (void *) ioaddr->lbal_addr); + writeb(0xaa, (void __iomem *) ioaddr->nsect_addr); + writeb(0x55, (void __iomem *) ioaddr->lbal_addr); - writeb(0x55, (void *) ioaddr->nsect_addr); - writeb(0xaa, (void *) ioaddr->lbal_addr); + writeb(0x55, (void __iomem *) ioaddr->nsect_addr); + writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); - nsect = readb((void *) ioaddr->nsect_addr); - lbal = readb((void *) ioaddr->lbal_addr); + nsect = readb((void __iomem *) ioaddr->nsect_addr); + lbal = readb((void __iomem *) ioaddr->lbal_addr); if ((nsect == 0x55) && (lbal == 0xaa)) return 1; /* we found a device */ @@ -651,7 +701,7 @@ } /** - * ata_dev_devchk - PATA device presence detection + * ata_devchk - PATA device presence detection * @ap: ATA channel to examine * @device: Device to examine (starting at zero) * @@ -663,7 +713,7 @@ * caller. */ -static unsigned int ata_dev_devchk(struct ata_port *ap, +static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) { if (ap->flags & ATA_FLAG_MMIO) @@ -687,7 +737,7 @@ * the event of failure. */ -static unsigned int ata_dev_classify(struct ata_taskfile *tf) +unsigned int ata_dev_classify(struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, @@ -735,7 +785,7 @@ unsigned int class; u8 err; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); memset(&tf, 0, sizeof(tf)); @@ -798,8 +848,12 @@ } } +void ata_noop_dev_select (struct ata_port *ap, unsigned int device) +{ +} + /** - * __ata_dev_select - Select device 0/1 on ATA bus + * ata_std_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select * @@ -811,7 +865,7 @@ * caller. */ -static void __ata_dev_select (struct ata_port *ap, unsigned int device) +void ata_std_dev_select (struct ata_port *ap, unsigned int device) { u8 tmp; @@ -821,7 +875,7 @@ tmp = ATA_DEVICE_OBS | ATA_DEV1; if (ap->flags & ATA_FLAG_MMIO) { - writeb(tmp, (void *) ap->ioaddr.device_addr); + writeb(tmp, (void __iomem *) ap->ioaddr.device_addr); } else { outb(tmp, ap->ioaddr.device_addr); } @@ -839,7 +893,7 @@ * make either device 0, or device 1, active on the * ATA channel. * - * This is a high-level version of __ata_dev_select(), + * This is a high-level version of ata_std_dev_select(), * which additionally provides the services of inserting * the proper pauses and status polling, where needed. * @@ -856,7 +910,7 @@ if (wait) ata_wait_idle(ap); - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); if (wait) { if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI) @@ -930,10 +984,14 @@ { struct ata_device *dev = &ap->device[device]; unsigned int i; - u16 tmp, udma_modes; + u16 tmp; + unsigned long xfer_modes; u8 status; - struct ata_taskfile tf; unsigned int using_edd; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; if (!ata_dev_present(dev)) { DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n", @@ -953,27 +1011,34 @@ ata_dev_select(ap, device, 1, 1); /* select device 0/1 */ -retry: - ata_tf_init(ap, &tf, device); - tf.ctl |= ATA_NIEN; - tf.protocol = ATA_PROT_PIO; + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->pci_dma_dir = PCI_DMA_FROMDEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; + +retry: if (dev->class == ATA_DEV_ATA) { - tf.command = ATA_CMD_ID_ATA; + qc->tf.command = ATA_CMD_ID_ATA; DPRINTK("do ATA identify\n"); } else { - tf.command = ATA_CMD_ID_ATAPI; + qc->tf.command = ATA_CMD_ID_ATAPI; DPRINTK("do ATAPI identify\n"); } - ata_tf_to_host(ap, &tf); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) + if (rc) goto err_out; + else + wait_for_completion(&wait); status = ata_chk_status(ap); if (status & ATA_ERR) { @@ -988,44 +1053,21 @@ * ATA software reset (SRST, the default) does not appear * to have this problem. */ - if ((using_edd) && (tf.command == ATA_CMD_ID_ATA)) { + if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { u8 err = ata_chk_err(ap); if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; + qc->cursg = 0; + qc->cursg_ofs = 0; + qc->cursect = 0; + qc->nsect = 1; goto retry; } } goto err_out; } - /* make sure we have BSY=0, DRQ=1 */ - if ((status & ATA_DRQ) == 0) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) not returning id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - /* read IDENTIFY [X] DEVICE page */ - if (ap->flags & ATA_FLAG_MMIO) { - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = readw((void *)ap->ioaddr.data_addr); - } else - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = inw(ap->ioaddr.data_addr); - - /* wait for host_idle */ - status = ata_wait_idle(ap); - if (status & (ATA_BUSY | ATA_DRQ)) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) error after id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - ata_irq_on(ap); /* re-enable interrupts */ + swap_buf_le16(dev->id, ATA_ID_WORDS); /* print device capabilities */ printk(KERN_DEBUG "ata%u: dev %u cfg " @@ -1045,12 +1087,13 @@ goto err_out_nosup; } - /* we require UDMA support */ - udma_modes = - tmp = dev->id[ATA_ID_UDMA_MODES]; - if ((tmp & 0xff) == 0) { - printk(KERN_DEBUG "ata%u: no udma\n", ap->id); - goto err_out_nosup; + /* quick-n-dirty find max transfer mode; for printk only */ + xfer_modes = dev->id[ATA_ID_UDMA_MODES]; + if (!xfer_modes) + xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; + if (!xfer_modes) { + xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); + xfer_modes |= (0x7 << ATA_SHIFT_PIO); } ata_dump_id(dev); @@ -1083,7 +1126,7 @@ /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", ap->id, device, - ata_udma_string(udma_modes), + ata_mode_string(xfer_modes), (unsigned long long)dev->n_sectors, dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } @@ -1093,15 +1136,18 @@ if (ata_id_is_ata(dev)) /* sanity check */ goto err_out_nosup; - /* see if 16-byte commands supported */ - tmp = dev->id[0] & 0x3; - if (tmp == 1) - ap->host->max_cmd_len = 16; + rc = atapi_cdb_len(dev->id); + if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { + printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id); + goto err_out_nosup; + } + ap->cdb_len = (unsigned int) rc; + ap->host->max_cmd_len = (unsigned char) ap->cdb_len; /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", ap->id, device, - ata_udma_string(udma_modes)); + ata_mode_string(xfer_modes)); } DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap)); @@ -1171,13 +1217,13 @@ } /** - * sata_phy_reset - + * __sata_phy_reset - * @ap: * * LOCKING: * */ -void sata_phy_reset(struct ata_port *ap) +void __sata_phy_reset(struct ata_port *ap) { u32 sstatus; unsigned long timeout = jiffies + (HZ * 5); @@ -1215,6 +1261,21 @@ return; } + ap->cbl = ATA_CBL_SATA; +} + +/** + * __sata_phy_reset - + * @ap: + * + * LOCKING: + * + */ +void sata_phy_reset(struct ata_port *ap) +{ + __sata_phy_reset(ap); + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; ata_bus_reset(ap); } @@ -1232,6 +1293,101 @@ ap->flags |= ATA_FLAG_PORT_DISABLED; } +static struct { + unsigned int shift; + u8 base; +} xfer_mode_classes[] = { + { ATA_SHIFT_UDMA, XFER_UDMA_0 }, + { ATA_SHIFT_MWDMA, XFER_MW_DMA_0 }, + { ATA_SHIFT_PIO, XFER_PIO_0 }, +}; + +static inline u8 base_from_shift(unsigned int shift) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) + if (xfer_mode_classes[i].shift == shift) + return xfer_mode_classes[i].base; + + return 0xff; +} + +static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) +{ + int ofs, idx; + u8 base; + + if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) + return; + + if (dev->xfer_shift == ATA_SHIFT_PIO) + dev->flags |= ATA_DFLAG_PIO; + + ata_dev_set_xfermode(ap, dev); + + base = base_from_shift(dev->xfer_shift); + ofs = dev->xfer_mode - base; + idx = ofs + dev->xfer_shift; + WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str)); + + DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n", + idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs); + + printk(KERN_INFO "ata%u: dev %u configured for %s\n", + ap->id, dev->devno, xfer_mode_str[idx]); +} + +static int ata_host_set_pio(struct ata_port *ap) +{ + unsigned int mask; + int x, i; + u8 base, xfer_mode; + + mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO); + x = fgb(mask); + if (x < 0) { + printk(KERN_WARNING "ata%u: no PIO support\n", ap->id); + return -1; + } + + base = base_from_shift(ATA_SHIFT_PIO); + xfer_mode = base + x; + + DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n", + (int)base, (int)xfer_mode, mask, x); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->pio_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = ATA_SHIFT_PIO; + if (ap->ops->set_piomode) + ap->ops->set_piomode(ap, dev); + } + } + + return 0; +} + +static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, + unsigned int xfer_shift) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->dma_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = xfer_shift; + if (ap->ops->set_dmamode) + ap->ops->set_dmamode(ap, dev); + } + } +} + /** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @ap: port on which timings will be programmed @@ -1241,29 +1397,28 @@ */ static void ata_set_mode(struct ata_port *ap) { - unsigned int force_pio, i; - - ata_host_set_pio(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + unsigned int i, xfer_shift; + u8 xfer_mode; + int rc; - ata_host_set_udma(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + /* step 1: always set host PIO timings */ + rc = ata_host_set_pio(ap); + if (rc) + goto err_out; -#ifdef ATA_FORCE_PIO - force_pio = 1; -#else - force_pio = 0; -#endif + /* step 2: choose the best data xfer mode */ + xfer_mode = xfer_shift = 0; + rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift); + if (rc) + goto err_out; - if (force_pio) { - ata_dev_set_pio(ap, 0); - ata_dev_set_pio(ap, 1); - } else { - ata_dev_set_udma(ap, 0); - ata_dev_set_udma(ap, 1); - } + /* step 3: if that xfer mode isn't PIO, set host DMA timings */ + if (xfer_shift != ATA_SHIFT_PIO) + ata_host_set_dma(ap, xfer_mode, xfer_shift); + + /* step 4: update devices' xfer mode */ + ata_dev_set_mode(ap, &ap->device[0]); + ata_dev_set_mode(ap, &ap->device[1]); if (ap->flags & ATA_FLAG_PORT_DISABLED) return; @@ -1275,6 +1430,11 @@ struct ata_device *dev = &ap->device[i]; ata_dev_set_protocol(dev); } + + return; + +err_out: + ata_port_disable(ap); } /** @@ -1328,23 +1488,23 @@ unsigned int dev1 = devmask & (1 << 1); unsigned long timeout; - /* if device 0 was found in ata_dev_devchk, wait for its + /* if device 0 was found in ata_devchk, wait for its * BSY bit to clear */ if (dev0) ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); - /* if device 1 was found in ata_dev_devchk, wait for + /* if device 1 was found in ata_devchk, wait for * register access, then wait for BSY to clear */ timeout = jiffies + ATA_TMOUT_BOOT; while (dev1) { u8 nsect, lbal; - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (ap->flags & ATA_FLAG_MMIO) { - nsect = readb((void *) ioaddr->nsect_addr); - lbal = readb((void *) ioaddr->lbal_addr); + nsect = readb((void __iomem *) ioaddr->nsect_addr); + lbal = readb((void __iomem *) ioaddr->lbal_addr); } else { nsect = inb(ioaddr->nsect_addr); lbal = inb(ioaddr->lbal_addr); @@ -1361,11 +1521,11 @@ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); /* is all this really necessary? */ - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); if (dev1) - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (dev0) - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); } /** @@ -1408,11 +1568,11 @@ /* software reset. causes dev0 to be selected */ if (ap->flags & ATA_FLAG_MMIO) { - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); udelay(20); /* FIXME: flush */ - writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr); udelay(20); /* FIXME: flush */ - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); } else { outb(ap->ctl, ioaddr->ctl_addr); udelay(10); @@ -1469,9 +1629,9 @@ if (ap->flags & ATA_FLAG_SATA_RESET) dev0 = 1; else { - dev0 = ata_dev_devchk(ap, 0); + dev0 = ata_devchk(ap, 0); if (slave_possible) - dev1 = ata_dev_devchk(ap, 1); + dev1 = ata_devchk(ap, 1); } if (dev0) @@ -1480,7 +1640,7 @@ devmask |= (1 << 1); /* select device 0 again */ - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); /* issue bus reset */ if (ap->flags & ATA_FLAG_SRST) @@ -1488,7 +1648,7 @@ else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) { /* set up device control */ if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); rc = ata_bus_edd(ap); @@ -1509,9 +1669,9 @@ /* is double-select really necessary? */ if (ap->device[1].class != ATA_DEV_NONE) - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (ap->device[0].class != ATA_DEV_NONE) - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); /* if no devices were detected, disable this port */ if ((ap->device[0].class == ATA_DEV_NONE) && @@ -1521,7 +1681,7 @@ if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { /* set up device control for ATA_FLAG_SATA_RESET */ if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); } @@ -1536,116 +1696,102 @@ DPRINTK("EXIT\n"); } -/** - * ata_host_set_pio - - * @ap: - * - * LOCKING: - */ - -static void ata_host_set_pio(struct ata_port *ap) +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) { struct ata_device *master, *slave; - unsigned int pio, i; - u16 mask; + unsigned int mask; master = &ap->device[0]; slave = &ap->device[1]; assert (ata_dev_present(master) || ata_dev_present(slave)); - mask = ap->pio_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_PIO_MODES] & 0x03); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03); - - /* require pio mode 3 or 4 support for host and all devices */ - if (mask == 0) { - printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n", - ap->id); - goto err_out; + if (shift == ATA_SHIFT_UDMA) { + mask = ap->udma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); + } + else if (shift == ATA_SHIFT_MWDMA) { + mask = ap->mwdma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); + } + else if (shift == ATA_SHIFT_PIO) { + mask = ap->pio_mask; + if (ata_dev_present(master)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + if (ata_dev_present(slave)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + } + else { + mask = 0xffffffff; /* shut up compiler warning */ + BUG(); } - pio = (mask & ATA_ID_PIO4) ? 4 : 3; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].pio_mode = (pio == 3) ? - XFER_PIO_3 : XFER_PIO_4; - if (ap->ops->set_piomode) - ap->ops->set_piomode(ap, &ap->device[i], pio); - } + return mask; +} - return; +/* find greatest bit */ +static int fgb(u32 bitmap) +{ + unsigned int i; + int x = -1; -err_out: - ap->ops->port_disable(ap); + for (i = 0; i < 32; i++) + if (bitmap & (1 << i)) + x = i; + + return x; } /** - * ata_host_set_udma - + * ata_choose_xfer_mode - * @ap: * * LOCKING: + * + * RETURNS: + * Zero on success, negative on error. */ -static void ata_host_set_udma(struct ata_port *ap) -{ - struct ata_device *master, *slave; - u16 mask; - unsigned int i, j; - int udma_mode = -1; - - master = &ap->device[0]; - slave = &ap->device[1]; - - assert (ata_dev_present(master) || ata_dev_present(slave)); - assert ((ap->flags & ATA_FLAG_PORT_DISABLED) == 0); - - DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n", - ap->udma_mask, - (!ata_dev_present(master)) ? 0xff : - (master->id[ATA_ID_UDMA_MODES] & 0xff), - (!ata_dev_present(slave)) ? 0xff : - (slave->id[ATA_ID_UDMA_MODES] & 0xff)); - - mask = ap->udma_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - - i = XFER_UDMA_7; - while (i >= XFER_UDMA_0) { - j = i - XFER_UDMA_0; - DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j); - if (mask & (1 << j)) { - udma_mode = i; - break; +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out) +{ + unsigned int mask, shift; + int x, i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) { + shift = xfer_mode_classes[i].shift; + mask = ata_get_mode_mask(ap, shift); + + x = fgb(mask); + if (x >= 0) { + *xfer_mode_out = xfer_mode_classes[i].base + x; + *xfer_shift_out = shift; + return 0; } - - i--; - } - - /* require udma for host and all attached devices */ - if (udma_mode < 0) { - printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n", - ap->id); - goto err_out; } - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].udma_mode = udma_mode; - if (ap->ops->set_udmamode) - ap->ops->set_udmamode(ap, &ap->device[i], - udma_mode); - } - - return; - -err_out: - ap->ops->port_disable(ap); + return -1; } /** @@ -1658,89 +1804,39 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) { - struct ata_taskfile tf; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; /* set up set-features taskfile */ DPRINTK("set features - xfer mode\n"); - ata_tf_init(ap, &tf, dev->devno); - tf.ctl |= ATA_NIEN; - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = SETFEATURES_XFER; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - if (dev->flags & ATA_DFLAG_PIO) - tf.nsect = dev->pio_mode; - else - tf.nsect = dev->udma_mode; - /* do bus reset */ - ata_tf_to_host(ap, &tf); + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + qc->tf.command = ATA_CMD_SET_FEATURES; + qc->tf.feature = SETFEATURES_XFER; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = dev->xfer_mode; - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - ata_irq_on(ap); /* re-enable interrupts */ + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - ata_wait_idle(ap); + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); DPRINTK("EXIT\n"); } /** - * ata_dev_set_udma - Set ATA device's transfer mode to Ultra DMA - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->udma_mode >= XFER_UDMA_0) && - (dev->udma_mode <= XFER_UDMA_7)); - printk(KERN_INFO "ata%u: dev %u configured for %s\n", - ap->id, device, - udma_str[dev->udma_mode - XFER_UDMA_0]); -} - -/** - * ata_dev_set_pio - Set ATA device's transfer mode to PIO - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - /* force PIO mode */ - dev->flags |= ATA_DFLAG_PIO; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->pio_mode >= XFER_PIO_3) && - (dev->pio_mode <= XFER_PIO_4)); - printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n", - ap->id, device, - dev->pio_mode == 3 ? '3' : '4'); -} - -/** * ata_sg_clean - * @qc: * @@ -1789,7 +1885,7 @@ idx = 0; for (nelem = qc->n_elem; nelem; nelem--,sg++) { - u32 addr, boundary; + u32 addr, offset; u32 sg_len, len; /* determine if physical DMA addr spans 64K boundary. @@ -1800,10 +1896,10 @@ sg_len = sg_dma_len(sg); while (sg_len) { - boundary = (addr & ~0xffff) + (0xffff + 1); + offset = addr & 0xffff; len = sg_len; - if ((addr + sg_len) > boundary) - len = boundary - addr; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; ap->prd[idx].addr = cpu_to_le32(addr); ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff); @@ -2003,7 +2099,7 @@ } drv_stat = ata_wait_idle(ap); - if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + if (!ata_ok(drv_stat)) { ap->pio_task_state = PIO_ST_ERR; return; } @@ -2018,6 +2114,126 @@ ata_qc_complete(qc, drv_stat); } +void swap_buf_le16(u16 *buf, unsigned int buf_words) +{ +#ifdef __BIG_ENDIAN + unsigned int i; + + for (i = 0; i < buf_words; i++) + buf[i] = le16_to_cpu(buf[i]); +#endif /* __BIG_ENDIAN */ +} + +static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int i; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *) buf; + void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + + if (write_data) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(mmio)); + } +} + +static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int dwords = buflen >> 1; + + if (write_data) + outsw(ap->ioaddr.data_addr, buf, dwords); + else + insw(ap->ioaddr.data_addr, buf, dwords); +} + +static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int do_write) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_mmio_data_xfer(ap, buf, buflen, do_write); + else + ata_pio_data_xfer(ap, buf, buflen, do_write); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + struct page *page; + unsigned char *buf; + + if (qc->cursect == (qc->nsect - 1)) + ap->pio_task_state = PIO_ST_LAST; + + page = sg[qc->cursg].page; + buf = kmap(page) + + sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); + + qc->cursect++; + qc->cursg_ofs++; + + if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { + qc->cursg++; + qc->cursg_ofs = 0; + } + + DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + + /* do the actual data transfer */ + do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); + + kunmap(page); +} + +static void atapi_pio_sector(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *dev = qc->dev; + unsigned int i, ireason, bc_lo, bc_hi, bytes; + int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0; + + ap->ops->tf_read(ap, &qc->tf); + ireason = qc->tf.nsect; + bc_lo = qc->tf.lbam; + bc_hi = qc->tf.lbah; + bytes = (bc_hi << 8) | bc_lo; + + /* shall be cleared to zero, indicating xfer of data */ + if (ireason & (1 << 0)) + goto err_out; + + /* make sure transfer direction matches expected */ + i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0; + if (do_write != i_write) + goto err_out; + + /* make sure byte count is multiple of sector size; not + * required by standard (warning! warning!), but IDE driver + * does this to simplify things a bit. We are lazy, and + * follow suit. + */ + if (bytes & (ATA_SECT_SIZE - 1)) + goto err_out; + + for (i = 0; i < (bytes >> 9); i++) + ata_pio_sector(qc); + + return; + +err_out: + printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", + ap->id, dev->devno); + ap->pio_task_state = PIO_ST_ERR; +} + /** * ata_pio_sector - * @ap: @@ -2025,12 +2241,9 @@ * LOCKING: */ -static void ata_pio_sector(struct ata_port *ap) +static void ata_pio_block(struct ata_port *ap) { struct ata_queued_cmd *qc; - struct scatterlist *sg; - struct page *page; - unsigned char *buf; u8 status; /* @@ -2061,36 +2274,29 @@ qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - sg = qc->sg; - - if (qc->cursect == (qc->nsect - 1)) - ap->pio_task_state = PIO_ST_LAST; + if (is_atapi_taskfile(&qc->tf)) + atapi_pio_sector(qc); + else + ata_pio_sector(qc); +} - page = sg[qc->cursg].page; - buf = kmap(page) + - sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); +static void ata_pio_error(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + u8 drv_stat; - qc->cursect++; - qc->cursg_ofs++; + qc = ata_qc_from_tag(ap, ap->active_tag); + assert(qc != NULL); - if (qc->flags & ATA_QCFLAG_SG) - if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { - qc->cursg++; - qc->cursg_ofs = 0; - } + drv_stat = ata_chk_status(ap); + printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", + ap->id, drv_stat); - DPRINTK("data %s, drv_stat 0x%X\n", - qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read", - status); + ap->pio_task_state = PIO_ST_IDLE; - /* do the actual data transfer */ - /* FIXME: mmio-ize */ - if (qc->tf.flags & ATA_TFLAG_WRITE) - outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); - else - insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); + ata_irq_on(ap); - kunmap(page); + ata_qc_complete(qc, drv_stat | ATA_ERR); } static void ata_pio_task(void *_data) @@ -2100,7 +2306,7 @@ switch (ap->pio_task_state) { case PIO_ST: - ata_pio_sector(ap); + ata_pio_block(ap); break; case PIO_ST_LAST: @@ -2113,15 +2319,8 @@ break; case PIO_ST_TMOUT: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; - break; - case PIO_ST_ERR: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; + ata_pio_error(ap); break; } @@ -2180,7 +2379,6 @@ /* fall through */ - case ATA_PROT_NODATA: default: ata_altstatus(ap); drv_stat = ata_chk_status(ap); @@ -2287,8 +2485,6 @@ ata_tf_init(ap, &qc->tf, dev->devno); - if (likely((dev->flags & ATA_DFLAG_PIO) == 0)) - qc->flags |= ATA_QCFLAG_DMA; if (dev->flags & ATA_DFLAG_LBA48) qc->tf.flags |= ATA_TFLAG_LBA48; } @@ -2296,6 +2492,11 @@ return qc; } +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +{ + return 0; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -2335,11 +2536,16 @@ do_clear = 1; } - if (qc->waiting) - complete(qc->waiting); + if (qc->waiting) { + struct completion *waiting = qc->waiting; + qc->waiting = NULL; + complete(waiting); + } if (likely(do_clear)) clear_bit(tag, &ap->qactive); + + VPRINTK("EXIT\n"); } /** @@ -2422,6 +2628,12 @@ break; case ATA_PROT_ATAPI: + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); + queue_work(ata_wq, &ap->packet_task); + break; + + case ATA_PROT_ATAPI_NODATA: ata_tf_to_host_nolock(ap, &qc->tf); queue_work(ata_wq, &ap->packet_task); break; @@ -2441,19 +2653,19 @@ } /** - * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO) + * ata_bmdma_setup - Set up PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) +static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 dmactl; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ mb(); /* make sure PRD table writes are visible to controller */ @@ -2471,17 +2683,17 @@ } /** - * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO) + * ata_bmdma_start - Start a PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) +static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; u8 dmactl; /* start host DMA transaction */ @@ -2509,7 +2721,7 @@ * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) +static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); @@ -2537,7 +2749,7 @@ * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_start_pio (struct ata_queued_cmd *qc) +static void ata_bmdma_start_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; u8 dmactl; @@ -2548,6 +2760,22 @@ ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } +void ata_bmdma_start(struct ata_queued_cmd *qc) +{ + if (qc->ap->flags & ATA_FLAG_MMIO) + ata_bmdma_start_mmio(qc); + else + ata_bmdma_start_pio(qc); +} + +void ata_bmdma_setup(struct ata_queued_cmd *qc) +{ + if (qc->ap->flags & ATA_FLAG_MMIO) + ata_bmdma_setup_mmio(qc); + else + ata_bmdma_setup_pio(qc); +} + void ata_bmdma_irq_clear(struct ata_port *ap) { ata_bmdma_ack_irq(ap); @@ -2581,7 +2809,7 @@ case ATA_PROT_ATAPI: /* check status of DMA engine */ host_stat = ata_bmdma_status(ap); - VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); + VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); /* if it's not our irq... */ if (!(host_stat & ATA_DMA_INTR)) @@ -2592,6 +2820,7 @@ /* fall through */ + case ATA_PROT_ATAPI_NODATA: case ATA_PROT_NODATA: /* check altstatus */ status = ata_altstatus(ap); @@ -2602,7 +2831,8 @@ status = ata_chk_status(ap); if (unlikely(status & ATA_BUSY)) goto idle_irq; - DPRINTK("BUS_NODATA (dev_stat 0x%X)\n", status); + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); /* ack bmdma irq events */ ata_bmdma_ack_irq(ap); @@ -2701,21 +2931,20 @@ /* make sure DRQ is set */ status = ata_chk_status(ap); - if ((status & ATA_DRQ) == 0) + if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) goto err_out; /* send SCSI cdb */ - /* FIXME: mmio-ize */ DPRINTK("send cdb\n"); - outsl(ap->ioaddr.data_addr, - qc->scsicmd->cmnd, ap->host->max_cmd_len / 4); + assert(ap->cdb_len >= 12); + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* if we are DMA'ing, irq handler takes over from here */ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) ap->ops->bmdma_start(qc); /* initiate bmdma */ /* non-data commands are also handled via irq */ - else if (qc->scsicmd->sc_data_direction == SCSI_DATA_NONE) { + else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { /* do nothing */ } @@ -2804,11 +3033,11 @@ ap->host_set = host_set; ap->port_no = port_no; ap->pio_mask = ent->pio_mask; + ap->mwdma_mask = ent->mwdma_mask; ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; ap->cbl = ATA_CBL_NONE; - ap->device[0].flags = ATA_DFLAG_MASTER; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; @@ -2901,19 +3130,23 @@ /* register each port bound to this device */ for (i = 0; i < ent->n_ports; i++) { struct ata_port *ap; + unsigned long xfer_mode_mask; ap = ata_host_add(ent, host_set, i); if (!ap) goto err_out; host_set->ports[i] = ap; + xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | + (ap->mwdma_mask << ATA_SHIFT_MWDMA) | + (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " "bmdma 0x%lX irq %lu\n", ap->id, ap->flags & ATA_FLAG_SATA ? 'S' : 'P', - ata_udma_string(ent->udma_mask), + ata_mode_string(xfer_mode_mask), ap->ioaddr.cmd_addr, ap->ioaddr.ctl_addr, ap->ioaddr.bmdma_addr, @@ -3035,6 +3268,95 @@ ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } +static struct ata_probe_ent * +ata_probe_ent_alloc(int n, struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent; + int i; + + probe_ent = kmalloc(sizeof(*probe_ent) * n, GFP_KERNEL); + if (!probe_ent) { + printk(KERN_ERR DRV_NAME "(%s): out of memory\n", + pci_name(pdev)); + return NULL; + } + + memset(probe_ent, 0, sizeof(*probe_ent) * n); + + for (i = 0; i < n; i++) { + INIT_LIST_HEAD(&probe_ent[i].node); + probe_ent[i].pdev = pdev; + + probe_ent[i].sht = port[i]->sht; + probe_ent[i].host_flags = port[i]->host_flags; + probe_ent[i].pio_mask = port[i]->pio_mask; + probe_ent[i].mwdma_mask = port[i]->mwdma_mask; + probe_ent[i].udma_mask = port[i]->udma_mask; + probe_ent[i].port_ops = port[i]->port_ops; + + } + + return probe_ent; +} + +struct ata_probe_ent * +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(1, pdev, port); + if (!probe_ent) + return NULL; + + probe_ent->n_ports = 2; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + + ata_std_ports(&probe_ent->port[0]); + ata_std_ports(&probe_ent->port[1]); + + return probe_ent; +} + +struct ata_probe_ent * +ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(2, pdev, port); + if (!probe_ent) + return NULL; + + probe_ent[0].n_ports = 1; + probe_ent[0].irq = 14; + + probe_ent[1].n_ports = 1; + probe_ent[1].irq = 15; + + probe_ent[0].port[0].cmd_addr = 0x1f0; + probe_ent[0].port[0].altstatus_addr = + probe_ent[0].port[0].ctl_addr = 0x3f6; + probe_ent[0].port[0].bmdma_addr = pci_resource_start(pdev, 4); + + probe_ent[1].port[0].cmd_addr = 0x170; + probe_ent[1].port[0].altstatus_addr = + probe_ent[1].port[0].ctl_addr = 0x376; + probe_ent[1].port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; + + ata_std_ports(&probe_ent[0].port[0]); + ata_std_ports(&probe_ent[1].port[0]); + + return probe_ent; +} + /** * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized @@ -3052,20 +3374,20 @@ unsigned int n_ports) { struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; - struct ata_port_info *port0, *port1; + struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; int rc; DPRINTK("ENTER\n"); - port0 = port_info[0]; + port[0] = port_info[0]; if (n_ports > 1) - port1 = port_info[1]; + port[1] = port_info[1]; else - port1 = port0; + port[1] = port[0]; - if ((port0->host_flags & ATA_FLAG_NO_LEGACY) == 0) { + if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0) { /* TODO: support transitioning to native mode? */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); mask = (1 << 2) | (1 << 0); @@ -3126,75 +3448,17 @@ if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (legacy_mode) { + probe_ent = ata_pci_init_legacy_mode(pdev, port); + if (probe_ent) + probe_ent2 = &probe_ent[1]; + } else + probe_ent = ata_pci_init_native_mode(pdev, port); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - probe_ent->pdev = pdev; - INIT_LIST_HEAD(&probe_ent->node); - - if (legacy_mode) { - probe_ent2 = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (!probe_ent2) { - rc = -ENOMEM; - goto err_out_free_ent; - } - - memset(probe_ent2, 0, sizeof(*probe_ent)); - probe_ent2->pdev = pdev; - INIT_LIST_HEAD(&probe_ent2->node); - } - - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - probe_ent->sht = port0->sht; - probe_ent->host_flags = port0->host_flags; - probe_ent->pio_mask = port0->pio_mask; - probe_ent->udma_mask = port0->udma_mask; - probe_ent->port_ops = port0->port_ops; - - if (legacy_mode) { - probe_ent->port[0].cmd_addr = 0x1f0; - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = 0x3f6; - probe_ent->n_ports = 1; - probe_ent->irq = 14; - ata_std_ports(&probe_ent->port[0]); - - probe_ent2->port[0].cmd_addr = 0x170; - probe_ent2->port[0].altstatus_addr = - probe_ent2->port[0].ctl_addr = 0x376; - probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; - probe_ent2->n_ports = 1; - probe_ent2->irq = 15; - ata_std_ports(&probe_ent2->port[0]); - - probe_ent2->sht = port1->sht; - probe_ent2->host_flags = port1->host_flags; - probe_ent2->pio_mask = port1->pio_mask; - probe_ent2->udma_mask = port1->udma_mask; - probe_ent2->port_ops = port1->port_ops; - } else { - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - } - pci_set_master(pdev); /* FIXME: check ata_device_add return */ @@ -3203,17 +3467,13 @@ ata_device_add(probe_ent); if (legacy_mode & (1 << 1)) ata_device_add(probe_ent2); - kfree(probe_ent2); } else { ata_device_add(probe_ent); - assert(probe_ent2 == NULL); } kfree(probe_ent); return 0; -err_out_free_ent: - kfree(probe_ent); err_out_regions: if (legacy_mode & (1 << 0)) release_region(0x1f0, 8); @@ -3363,34 +3623,35 @@ EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_issue_prot); EXPORT_SYMBOL_GPL(ata_eng_timeout); -EXPORT_SYMBOL_GPL(ata_tf_load_pio); -EXPORT_SYMBOL_GPL(ata_tf_load_mmio); -EXPORT_SYMBOL_GPL(ata_tf_read_pio); -EXPORT_SYMBOL_GPL(ata_tf_read_mmio); +EXPORT_SYMBOL_GPL(ata_tf_load); +EXPORT_SYMBOL_GPL(ata_tf_read); +EXPORT_SYMBOL_GPL(ata_noop_dev_select); +EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); -EXPORT_SYMBOL_GPL(ata_check_status_pio); -EXPORT_SYMBOL_GPL(ata_check_status_mmio); -EXPORT_SYMBOL_GPL(ata_exec_command_pio); -EXPORT_SYMBOL_GPL(ata_exec_command_mmio); +EXPORT_SYMBOL_GPL(ata_pci_init_legacy_mode); +EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); +EXPORT_SYMBOL_GPL(ata_check_status); +EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_qc_prep); -EXPORT_SYMBOL_GPL(ata_bmdma_setup_pio); -EXPORT_SYMBOL_GPL(ata_bmdma_start_pio); -EXPORT_SYMBOL_GPL(ata_bmdma_setup_mmio); -EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio); +EXPORT_SYMBOL_GPL(ata_bmdma_setup); +EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_phy_reset); +EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); +EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); +EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_id_string); diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/libata-scsi.c 2004-10-18 14:56:28 -07:00 @@ -29,6 +29,7 @@ #include "scsi.h" #include #include +#include #include "libata.h" @@ -36,6 +37,8 @@ static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); /** @@ -67,6 +70,43 @@ return 0; } +int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) +{ + struct ata_port *ap; + struct ata_device *dev; + int val = -EINVAL, rc = -EINVAL; + + ap = (struct ata_port *) &scsidev->host->hostdata[0]; + if (!ap) + goto out; + + dev = ata_scsi_find_dev(ap, scsidev); + if (!dev) { + rc = -ENODEV; + goto out; + } + + switch (cmd) { + case ATA_IOC_GET_IO32: + val = 0; + if (copy_to_user(arg, &val, 1)) + return -EFAULT; + return 0; + + case ATA_IOC_SET_IO32: + val = (unsigned long) arg; + if (val != 0) + return -EINVAL; + return 0; + + default: + rc = -EOPNOTSUPP; + break; + } + +out: + return rc; +} /** * ata_scsi_qc_new - acquire new ata_queued_cmd reference @@ -120,34 +160,158 @@ * ata_to_sense_error - convert ATA error to SCSI error * @qc: Command that we are erroring out * - * Converts an ATA error into a SCSI error. - * - * Right now, this routine is laughably primitive. We - * don't even examine what ATA told us, we just look at - * the command data direction, and return a fatal SCSI - * sense error based on that. + * Converts an ATA error into a SCSI error. While we are at it + * we decode and dump the ATA error for the user so that they + * have some idea what really happened at the non make-believe + * layer. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_to_sense_error(struct ata_queued_cmd *qc) +void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + u8 err = 0; + unsigned char *sb = cmd->sense_buffer; + /* Based on the 3ware driver translation table */ + static unsigned char sense_table[][4] = { + /* BBD|ECC|ID|MAR */ + {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* BBD|ECC|ID */ + {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* ECC|MC|MARK */ + {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error + /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */ + {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error + /* MC|ID|ABRT|TRK0|MARK */ + {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready + /* MCR|MARK */ + {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready + /* Bad address mark */ + {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field + /* TRK0 */ + {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error + /* Abort & !ICRC */ + {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command + /* Media change request */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline + /* SRV */ + {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found + /* Media change */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline + /* ECC */ + {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error + /* BBD - block marked bad */ + {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + static unsigned char stat_table[][4] = { + /* Must be first because BUSY means no other bits valid */ + {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now + {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault + {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now + {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + int i = 0; cmd->result = SAM_STAT_CHECK_CONDITION; - - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = MEDIUM_ERROR; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ - + + /* + * Is this an error we can process/parse + */ + + if(drv_stat & ATA_ERR) + /* Read the err bits */ + err = ata_chk_err(qc->ap); + + /* Display the ATA level error info */ + + printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); + if(drv_stat & 0x80) + { + printk("Busy "); + err = 0; /* Data is not valid in this case */ + } + else { + if(drv_stat & 0x40) printk("DriveReady "); + if(drv_stat & 0x20) printk("DeviceFault "); + if(drv_stat & 0x10) printk("SeekComplete "); + if(drv_stat & 0x08) printk("DataRequest "); + if(drv_stat & 0x04) printk("CorrectedError "); + if(drv_stat & 0x02) printk("Index "); + if(drv_stat & 0x01) printk("Error "); + } + printk("}\n"); + + if(err) + { + printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); + if(err & 0x04) printk("DriveStatusError "); + if(err & 0x80) + { + if(err & 0x04) + printk("BadCRC "); + else + printk("Sector "); + } + if(err & 0x40) printk("UncorrectableError "); + if(err & 0x10) printk("SectorIdNotFound "); + if(err & 0x02) printk("TrackZeroNotFound "); + if(err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + + /* Should we dump sector info here too ?? */ + } + + + /* Look for err */ + while(sense_table[i][0] != 0xFF) + { + /* Look for best matches first */ + if((sense_table[i][0] & err) == sense_table[i][0]) + { + sb[0] = 0x70; + sb[2] = sense_table[i][1]; + sb[7] = 0x0a; + sb[12] = sense_table[i][2]; + sb[13] = sense_table[i][3]; + return; + } + i++; + } + /* No immediate match */ + if(err) + printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); + + /* Fall back to interpreting status bits */ + while(stat_table[i][0] != 0xFF) + { + if(stat_table[i][0] & drv_stat) + { + sb[0] = 0x70; + sb[2] = stat_table[i][1]; + sb[7] = 0x0a; + sb[12] = stat_table[i][2]; + sb[13] = stat_table[i][3]; + return; + } + i++; + } + /* No error ?? */ + printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); /* additional-sense-code[-qualifier] */ + + sb[0] = 0x70; + sb[2] = MEDIUM_ERROR; + sb[7] = 0x0A; if (cmd->sc_data_direction == SCSI_DATA_READ) { - cmd->sense_buffer[12] = 0x11; /* "unrecovered read error" */ - cmd->sense_buffer[13] = 0x04; + sb[12] = 0x11; /* "unrecovered read error" */ + sb[13] = 0x04; } else { - cmd->sense_buffer[12] = 0x0C; /* "write error - */ - cmd->sense_buffer[13] = 0x02; /* auto-reallocation failed" */ + sb[12] = 0x0C; /* "write error - */ + sb[13] = 0x02; /* auto-reallocation failed" */ } } @@ -214,11 +378,135 @@ ap = (struct ata_port *) &host->hostdata[0]; ap->ops->eng_timeout(ap); + /* TODO: this is per-command; when queueing is supported + * this code will either change or move to a more + * appropriate place + */ + host->host_failed--; + DPRINTK("EXIT\n"); return 0; } /** + * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate (ignored) + * + * Sets up an ATA taskfile to issue FLUSH CACHE or + * FLUSH CACHE EXT. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + + tf->flags |= ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + + if ((tf->flags & ATA_TFLAG_LBA48) && + (ata_id_has_flush_ext(qc->dev))) + tf->command = ATA_CMD_FLUSH_EXT; + else + tf->command = ATA_CMD_FLUSH; + + return 0; +} + +/** + * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Converts SCSI VERIFY command to an ATA READ VERIFY command. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + u64 dev_sectors = qc->dev->n_sectors; + u64 sect = 0; + u32 n_sect = 0; + + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + tf->device |= ATA_LBA; + + if (scsicmd[0] == VERIFY) { + sect |= ((u64)scsicmd[2]) << 24; + sect |= ((u64)scsicmd[3]) << 16; + sect |= ((u64)scsicmd[4]) << 8; + sect |= ((u64)scsicmd[5]); + + n_sect |= ((u32)scsicmd[7]) << 8; + n_sect |= ((u32)scsicmd[8]); + } + + else if (scsicmd[0] == VERIFY_16) { + sect |= ((u64)scsicmd[2]) << 56; + sect |= ((u64)scsicmd[3]) << 48; + sect |= ((u64)scsicmd[4]) << 40; + sect |= ((u64)scsicmd[5]) << 32; + sect |= ((u64)scsicmd[6]) << 24; + sect |= ((u64)scsicmd[7]) << 16; + sect |= ((u64)scsicmd[8]) << 8; + sect |= ((u64)scsicmd[9]); + + n_sect |= ((u32)scsicmd[10]) << 24; + n_sect |= ((u32)scsicmd[11]) << 16; + n_sect |= ((u32)scsicmd[12]) << 8; + n_sect |= ((u32)scsicmd[13]); + } + + else + return 1; + + if (!n_sect) + return 1; + if (sect >= dev_sectors) + return 1; + if ((sect + n_sect) > dev_sectors) + return 1; + if (lba48) { + if (n_sect > (64 * 1024)) + return 1; + } else { + if (n_sect > 256) + return 1; + } + + if (lba48) { + tf->hob_nsect = (n_sect >> 8) & 0xff; + + tf->hob_lbah = (sect >> 40) & 0xff; + tf->hob_lbam = (sect >> 32) & 0xff; + tf->hob_lbal = (sect >> 24) & 0xff; + } else + tf->device |= (sect >> 24) & 0xf; + + tf->nsect = n_sect & 0xff; + + tf->hob_lbah = (sect >> 16) & 0xff; + tf->hob_lbam = (sect >> 8) & 0xff; + tf->hob_lbal = sect & 0xff; + + return 0; +} + +/** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate @@ -244,10 +532,6 @@ unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->hob_nsect = 0; - tf->hob_lbal = 0; - tf->hob_lbam = 0; - tf->hob_lbah = 0; tf->protocol = qc->dev->xfer_protocol; tf->device |= ATA_LBA; @@ -339,14 +623,10 @@ { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { - if (is_atapi_taskfile(&qc->tf)) - cmd->result = SAM_STAT_CHECK_CONDITION; - else - ata_to_sense_error(qc); - } else { + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + else cmd->result = SAM_STAT_GOOD; - } qc->scsidone(cmd); @@ -534,7 +814,7 @@ 0, 0x5, /* claim SPC-3 version compatibility */ 2, - 96 - 4 + 95 - 4 }; /* set scsi removeable (RMB) bit per ata bit */ @@ -545,7 +825,7 @@ memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > 36) { + if (buflen > 35) { memcpy(&rbuf[8], "ATA ", 8); ata_dev_id_string(dev, &rbuf[16], ATA_ID_PROD_OFS, 16); ata_dev_id_string(dev, &rbuf[32], ATA_ID_FW_REV_OFS, 4); @@ -964,6 +1244,31 @@ done(cmd); } +static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + cmd->result = SAM_STAT_CHECK_CONDITION; + else { + u8 *scsicmd = cmd->cmnd; + + if (scsicmd[0] == INQUIRY) { + u8 *buf = NULL; + unsigned int buflen; + + buflen = ata_scsi_rbuf_get(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; + } + + qc->scsidone(cmd); + + return 0; +} /** * atapi_xlat - Initialize PACKET taskfile * @qc: command structure to be initialized @@ -979,6 +1284,13 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_device *dev = qc->dev; + int using_pio = (dev->flags & ATA_DFLAG_PIO); + int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); + + qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { @@ -988,19 +1300,18 @@ qc->tf.command = ATA_CMD_PACKET; - /* no data - interrupt-driven */ - if (cmd->sc_data_direction == SCSI_DATA_NONE) - qc->tf.protocol = ATA_PROT_ATAPI; - - /* PIO data xfer - polling */ - else if ((qc->flags & ATA_QCFLAG_DMA) == 0) { - ata_qc_set_polling(qc); - qc->tf.protocol = ATA_PROT_ATAPI; + /* no data, or PIO data xfer */ + if (using_pio || nodata) { + if (nodata) + qc->tf.protocol = ATA_PROT_ATAPI_NODATA; + else + qc->tf.protocol = ATA_PROT_ATAPI; qc->tf.lbam = (8 * 1024) & 0xff; qc->tf.lbah = (8 * 1024) >> 8; + } - /* DMA data xfer - interrupt-driven */ - } else { + /* DMA data xfer */ + else { qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; @@ -1031,19 +1342,19 @@ * Associated ATA device, or %NULL if not found. */ -static inline struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) { struct ata_device *dev; /* skip commands not addressed to targets we simulate */ - if (likely(cmd->device->id < ATA_MAX_DEVICES)) - dev = &ap->device[cmd->device->id]; + if (likely(scsidev->id < ATA_MAX_DEVICES)) + dev = &ap->device[scsidev->id]; else return NULL; - if (unlikely((cmd->device->channel != 0) || - (cmd->device->lun != 0))) + if (unlikely((scsidev->channel != 0) || + (scsidev->lun != 0))) return NULL; if (unlikely(!ata_dev_present(dev))) @@ -1059,6 +1370,7 @@ /** * ata_get_xlat_func - check if SCSI to ATA translation is possible + * @dev: ATA device * @cmd: SCSI command opcode to consider * * Look up the SCSI command given, and determine whether the @@ -1068,7 +1380,7 @@ * Pointer to translation function if possible, %NULL if not. */ -static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd) +static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) { switch (cmd) { case READ_6: @@ -1079,6 +1391,15 @@ case WRITE_10: case WRITE_16: return ata_scsi_rw_xlat; + + case SYNCHRONIZE_CACHE: + if (ata_try_flush_cache(dev)) + return ata_scsi_flush_xlat; + break; + + case VERIFY: + case VERIFY_16: + return ata_scsi_verify_xlat; } return NULL; @@ -1096,11 +1417,12 @@ struct scsi_cmnd *cmd) { #ifdef ATA_DEBUG + struct scsi_device *scsidev = cmd->device; u8 *scsicmd = cmd->cmnd; DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", ap->id, - cmd->device->channel, cmd->device->id, cmd->device->lun, + scsidev->channel, scsidev->id, scsidev->lun, scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], scsicmd[8]); @@ -1130,12 +1452,13 @@ { struct ata_port *ap; struct ata_device *dev; + struct scsi_device *scsidev = cmd->device; - ap = (struct ata_port *) &cmd->device->host->hostdata[0]; + ap = (struct ata_port *) &scsidev->host->hostdata[0]; ata_scsi_dump_cdb(ap, cmd); - dev = ata_scsi_find_dev(ap, cmd); + dev = ata_scsi_find_dev(ap, scsidev); if (unlikely(!dev)) { cmd->result = (DID_BAD_TARGET << 16); done(cmd); @@ -1143,7 +1466,8 @@ } if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(cmd->cmnd[0]); + ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, + cmd->cmnd[0]); if (xlat_func) ata_scsi_translate(ap, dev, cmd, done, xlat_func); @@ -1184,7 +1508,7 @@ switch(scsicmd[0]) { /* no-op's, complete with success */ - case SYNCHRONIZE_CACHE: /* FIXME: temporary */ + case SYNCHRONIZE_CACHE: case REZERO_UNIT: case SEEK_6: case SEEK_10: diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h --- a/drivers/scsi/libata.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/scsi/libata.h 2004-10-18 14:56:17 -07:00 @@ -42,10 +42,11 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); +extern void swap_buf_le16(u16 *buf, unsigned int buf_words); /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc); +extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff -Nru a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c --- a/drivers/scsi/mac_scsi.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/mac_scsi.c 2004-10-18 14:55:54 -07:00 @@ -326,6 +326,7 @@ { if (shpnt->irq != SCSI_IRQ_NONE) free_irq (shpnt->irq, NCR5380_intr); + NCR5380_exit(shpnt); return 0; } diff -Nru a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c --- a/drivers/scsi/mca_53c9x.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/scsi/mca_53c9x.c 2004-10-18 14:56:27 -07:00 @@ -238,15 +238,15 @@ /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; + esp->dma_barrier = NULL; + esp->dma_drain = NULL; + esp->dma_invalidate = NULL; + esp->dma_irq_entry = NULL; + esp->dma_irq_exit = NULL; esp->dma_led_on = dma_led_on; esp->dma_led_off = dma_led_off; - esp->dma_poll = 0; - esp->dma_reset = 0; + esp->dma_poll = NULL; + esp->dma_reset = NULL; /* Set the command buffer */ diff -Nru a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/Kconfig.megaraid 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,77 @@ +config MEGARAID_NEWGEN + bool "LSI Logic New Generation RAID Device Drivers" + depends on PCI && SCSI + help + LSI Logic RAID Device Drivers + +config MEGARAID_MM + tristate "LSI Logic Management Module (New Driver)" + depends on PCI && SCSI && MEGARAID_NEWGEN + help + Management Module provides ioctl, sysfs support for LSI Logic + RAID controllers. + To compile this driver as a module, choose M here: the + module will be called megaraid_mm + + +config MEGARAID_MAILBOX + tristate "LSI Logic MegaRAID Driver (New Driver)" + depends on PCI && SCSI && MEGARAID_MM + help + List of supported controllers + + OEM Product Name VID :DID :SVID:SSID + --- ------------ ---- ---- ---- ---- + Dell PERC3/QC 101E:1960:1028:0471 + Dell PERC3/DC 101E:1960:1028:0493 + Dell PERC3/SC 101E:1960:1028:0475 + Dell PERC3/Di 1028:000E:1028:0123 + Dell PERC4/SC 1000:1960:1028:0520 + Dell PERC4/DC 1000:1960:1028:0518 + Dell PERC4/QC 1000:0407:1028:0531 + Dell PERC4/Di 1028:000F:1028:014A + Dell PERC 4e/Si 1028:0013:1028:016c + Dell PERC 4e/Di 1028:0013:1028:016d + Dell PERC 4e/Di 1028:0013:1028:016e + Dell PERC 4e/Di 1028:0013:1028:016f + Dell PERC 4e/Di 1028:0013:1028:0170 + Dell PERC 4e/DC 1000:0408:1028:0002 + Dell PERC 4e/SC 1000:0408:1028:0001 + LSI MegaRAID SCSI 320-0 1000:1960:1000:A520 + LSI MegaRAID SCSI 320-1 1000:1960:1000:0520 + LSI MegaRAID SCSI 320-2 1000:1960:1000:0518 + LSI MegaRAID SCSI 320-0X 1000:0407:1000:0530 + LSI MegaRAID SCSI 320-2X 1000:0407:1000:0532 + LSI MegaRAID SCSI 320-4X 1000:0407:1000:0531 + LSI MegaRAID SCSI 320-1E 1000:0408:1000:0001 + LSI MegaRAID SCSI 320-2E 1000:0408:1000:0002 + LSI MegaRAID SATA 150-4 1000:1960:1000:4523 + LSI MegaRAID SATA 150-6 1000:1960:1000:0523 + LSI MegaRAID SATA 300-4X 1000:0409:1000:3004 + LSI MegaRAID SATA 300-8X 1000:0409:1000:3008 + INTEL RAID Controller SRCU42X 1000:0407:8086:0532 + INTEL RAID Controller SRCS16 1000:1960:8086:0523 + INTEL RAID Controller SRCU42E 1000:0408:8086:0002 + INTEL RAID Controller SRCZCRX 1000:0407:8086:0530 + INTEL RAID Controller SRCS28X 1000:0409:8086:3008 + INTEL RAID Controller SROMBU42E 1000:0408:8086:3431 + INTEL RAID Controller SROMBU42E 1000:0408:8086:3499 + INTEL RAID Controller SRCU51L 1000:1960:8086:0520 + FSC MegaRAID PCI Express ROMB 1000:0408:1734:1065 + ACER MegaRAID ROMB-2E 1000:0408:1025:004D + + To compile this driver as a module, choose M here: the + module will be called megaraid_mbox + +if MEGARAID_NEWGEN=n +config MEGARAID_LEGACY + tristate "LSI Logic Legacy MegaRAID Driver" + depends on PCI && SCSI + help + This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490 + and 467 SCSI host adapters. This driver also support the all U320 + RAID controllers + + To compile this driver as a module, choose M here: the + module will be called megaraid +endif diff -Nru a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/Makefile 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,2 @@ +obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o +obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o diff -Nru a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/mbox_defs.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,790 @@ +/* + * + * Linux MegaRAID Unified device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * FILE : mbox_defs.h + * + */ +#ifndef _MRAID_MBOX_DEFS_H_ +#define _MRAID_MBOX_DEFS_H_ + +#include + +/* + * Commands and states for mailbox based controllers + */ + +#define MBOXCMD_LREAD 0x01 +#define MBOXCMD_LWRITE 0x02 +#define MBOXCMD_PASSTHRU 0x03 +#define MBOXCMD_ADPEXTINQ 0x04 +#define MBOXCMD_ADAPTERINQ 0x05 +#define MBOXCMD_LREAD64 0xA7 +#define MBOXCMD_LWRITE64 0xA8 +#define MBOXCMD_PASSTHRU64 0xC3 +#define MBOXCMD_EXTPTHRU 0xE3 + +#define MAIN_MISC_OPCODE 0xA4 +#define GET_MAX_SG_SUPPORT 0x01 +#define SUPPORT_EXT_CDB 0x16 + +#define FC_NEW_CONFIG 0xA1 +#define NC_SUBOP_PRODUCT_INFO 0x0E +#define NC_SUBOP_ENQUIRY3 0x0F +#define ENQ3_GET_SOLICITED_FULL 0x02 +#define OP_DCMD_READ_CONFIG 0x04 +#define NEW_READ_CONFIG_8LD 0x67 +#define READ_CONFIG_8LD 0x07 +#define FLUSH_ADAPTER 0x0A +#define FLUSH_SYSTEM 0xFE + +/* + * Command for random deletion of logical drives + */ +#define FC_DEL_LOGDRV 0xA4 +#define OP_SUP_DEL_LOGDRV 0x2A +#define OP_GET_LDID_MAP 0x18 +#define OP_DEL_LOGDRV 0x1C + +/* + * BIOS commands + */ +#define IS_BIOS_ENABLED 0x62 +#define GET_BIOS 0x01 +#define CHNL_CLASS 0xA9 +#define GET_CHNL_CLASS 0x00 +#define SET_CHNL_CLASS 0x01 +#define CH_RAID 0x01 +#define CH_SCSI 0x00 +#define BIOS_PVT_DATA 0x40 +#define GET_BIOS_PVT_DATA 0x00 + + +/* + * Commands to support clustering + */ +#define GET_TARGET_ID 0x7D +#define CLUSTER_OP 0x70 +#define GET_CLUSTER_MODE 0x02 +#define CLUSTER_CMD 0x6E +#define RESERVE_LD 0x01 +#define RELEASE_LD 0x02 +#define RESET_RESERVATIONS 0x03 +#define RESERVATION_STATUS 0x04 +#define RESERVE_PD 0x05 +#define RELEASE_PD 0x06 + + +/* + * Module battery status + */ +#define BATTERY_MODULE_MISSING 0x01 +#define BATTERY_LOW_VOLTAGE 0x02 +#define BATTERY_TEMP_HIGH 0x04 +#define BATTERY_PACK_MISSING 0x08 +#define BATTERY_CHARGE_MASK 0x30 +#define BATTERY_CHARGE_DONE 0x00 +#define BATTERY_CHARGE_INPROG 0x10 +#define BATTERY_CHARGE_FAIL 0x20 +#define BATTERY_CYCLES_EXCEEDED 0x40 + +/* + * Physical drive states. + */ +#define PDRV_UNCNF 0 +#define PDRV_ONLINE 3 +#define PDRV_FAILED 4 +#define PDRV_RBLD 5 +#define PDRV_HOTSPARE 6 + + +/* + * Raid logical drive states. + */ +#define RDRV_OFFLINE 0 +#define RDRV_DEGRADED 1 +#define RDRV_OPTIMAL 2 +#define RDRV_DELETED 3 + +/* + * Read, write and cache policies + */ +#define NO_READ_AHEAD 0 +#define READ_AHEAD 1 +#define ADAP_READ_AHEAD 2 +#define WRMODE_WRITE_THRU 0 +#define WRMODE_WRITE_BACK 1 +#define CACHED_IO 0 +#define DIRECT_IO 1 + +#define MAX_LOGICAL_DRIVES_8LD 8 +#define MAX_LOGICAL_DRIVES_40LD 40 +#define FC_MAX_PHYSICAL_DEVICES 256 +#define MAX_MBOX_CHANNELS 5 +#define MAX_MBOX_TARGET 15 +#define MBOX_MAX_PHYSICAL_DRIVES MAX_MBOX_CHANNELS*MAX_MBOX_TARGET +#define MAX_ROW_SIZE_40LD 32 +#define MAX_ROW_SIZE_8LD 8 +#define SPAN_DEPTH_8_SPANS 8 +#define SPAN_DEPTH_4_SPANS 4 +#define MAX_REQ_SENSE_LEN 0x20 + + + +/** + * struct mbox_t - Driver and f/w handshake structure. + * @cmd : firmware command + * @cmdid : command id + * @numsectors : number of sectors to be transferred + * @lba : Logical Block Address on LD + * @xferaddr : DMA address for data transfer + * @logdrv : logical drive number + * @numsge : number of scatter gather elements in sg list + * @resvd : reserved + * @busy : f/w busy, must wait to issue more commands. + * @numstatus : number of commands completed. + * @status : status of the commands completed + * @completed : array of completed command ids. + * @poll : poll and ack sequence + * @ack : poll and ack sequence + * + * The central handshake structure between the driver and the firmware. This + * structure must be allocated by the driver and aligned at 8-byte boundary. + */ +#define MBOX_MAX_FIRMWARE_STATUS 46 +typedef struct { + uint8_t cmd; + uint8_t cmdid; + uint16_t numsectors; + uint32_t lba; + uint32_t xferaddr; + uint8_t logdrv; + uint8_t numsge; + uint8_t resvd; + uint8_t busy; + uint8_t numstatus; + uint8_t status; + uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; + uint8_t poll; + uint8_t ack; +} __attribute__ ((packed)) mbox_t; + + +/** + * mbox64_t - 64-bit extension for the mailbox + * @segment_lo : the low 32-bits of the address of the scatter-gather list + * @segment_hi : the upper 32-bits of the address of the scatter-gather list + * @mbox : 32-bit mailbox, whose xferadder field must be set to + * 0xFFFFFFFF + * + * This is the extension of the 32-bit mailbox to be able to perform DMA + * beyond 4GB address range. + */ +typedef struct { + uint32_t xferaddr_lo; + uint32_t xferaddr_hi; + mbox_t mbox32; +} __attribute__ ((packed)) mbox64_t; + +/* + * mailbox structure used for internal commands + */ +typedef struct { + u8 cmd; + u8 cmdid; + u8 opcode; + u8 subopcode; + u32 lba; + u32 xferaddr; + u8 logdrv; + u8 rsvd[3]; + u8 numstatus; + u8 status; +} __attribute__ ((packed)) int_mbox_t; + +/** + * mraid_passthru_t - passthru structure to issue commands to physical devices + * @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr + * @ars : set if ARS required after check condition + * @islogical : set if command meant for logical devices + * @logdrv : logical drive number if command for LD + * @channel : Channel on which physical device is located + * @target : SCSI target of the device + * @queuetag : unused + * @queueaction : unused + * @cdb : SCSI CDB + * @cdblen : length of the CDB + * @reqsenselen : amount of request sense data to be returned + * @reqsensearea : Sense information buffer + * @numsge : number of scatter-gather elements in the sg list + * @scsistatus : SCSI status of the command completed. + * @dataxferaddr : DMA data transfer address + * @dataxferlen : amount of the data to be transferred. + */ +typedef struct { + uint8_t timeout :3; + uint8_t ars :1; + uint8_t reserved :3; + uint8_t islogical :1; + uint8_t logdrv; + uint8_t channel; + uint8_t target; + uint8_t queuetag; + uint8_t queueaction; + uint8_t cdb[10]; + uint8_t cdblen; + uint8_t reqsenselen; + uint8_t reqsensearea[MAX_REQ_SENSE_LEN]; + uint8_t numsge; + uint8_t scsistatus; + uint32_t dataxferaddr; + uint32_t dataxferlen; +} __attribute__ ((packed)) mraid_passthru_t; + +typedef struct { + + uint32_t dataxferaddr_lo; + uint32_t dataxferaddr_hi; + mraid_passthru_t pthru32; + +} __attribute__ ((packed)) mega_passthru64_t; + +/** + * mraid_epassthru_t - passthru structure to issue commands to physical devices + * @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr + * @ars : set if ARS required after check condition + * @rsvd1 : reserved field + * @cd_rom : (?) + * @rsvd2 : reserved field + * @islogical : set if command meant for logical devices + * @logdrv : logical drive number if command for LD + * @channel : Channel on which physical device is located + * @target : SCSI target of the device + * @queuetag : unused + * @queueaction : unused + * @cdblen : length of the CDB + * @rsvd3 : reserved field + * @cdb : SCSI CDB + * @numsge : number of scatter-gather elements in the sg list + * @status : SCSI status of the command completed. + * @reqsenselen : amount of request sense data to be returned + * @reqsensearea : Sense information buffer + * @rsvd4 : reserved field + * @dataxferaddr : DMA data transfer address + * @dataxferlen : amount of the data to be transferred. + */ +typedef struct { + uint8_t timeout :3; + uint8_t ars :1; + uint8_t rsvd1 :1; + uint8_t cd_rom :1; + uint8_t rsvd2 :1; + uint8_t islogical :1; + uint8_t logdrv; + uint8_t channel; + uint8_t target; + uint8_t queuetag; + uint8_t queueaction; + uint8_t cdblen; + uint8_t rsvd3; + uint8_t cdb[16]; + uint8_t numsge; + uint8_t status; + uint8_t reqsenselen; + uint8_t reqsensearea[MAX_REQ_SENSE_LEN]; + uint8_t rsvd4; + uint32_t dataxferaddr; + uint32_t dataxferlen; +} __attribute__ ((packed)) mraid_epassthru_t; + + +/** + * mraid_pinfo_t - product info, static information about the controller + * @data_size : current size in bytes (not including resvd) + * @config_signature : Current value is 0x00282008 + * @fw_version : Firmware version + * @bios_version : version of the BIOS + * @product_name : Name given to the controller + * @max_commands : Maximum concurrent commands supported + * @nchannels : Number of SCSI Channels detected + * @fc_loop_present : Number of Fibre Loops detected + * @mem_type : EDO, FPM, SDRAM etc + * @signature : + * @dram_size : In terms of MB + * @subsysid : device PCI subsystem ID + * @subsysvid : device PCI subsystem vendor ID + * @notify_counters : + * @pad1k : 135 + 889 resvd = 1024 total size + * + * This structures holds the information about the controller which is not + * expected to change dynamically. + * + * The current value of config signature is 0x00282008: + * 0x28 = MAX_LOGICAL_DRIVES, + * 0x20 = Number of stripes and + * 0x08 = Number of spans + */ +typedef struct { + uint32_t data_size; + uint32_t config_signature; + uint8_t fw_version[16]; + uint8_t bios_version[16]; + uint8_t product_name[80]; + uint8_t max_commands; + uint8_t nchannels; + uint8_t fc_loop_present; + uint8_t mem_type; + uint32_t signature; + uint16_t dram_size; + uint16_t subsysid; + uint16_t subsysvid; + uint8_t notify_counters; + uint8_t pad1k[889]; +} __attribute__ ((packed)) mraid_pinfo_t; + + +/** + * mraid_notify_t - the notification structure + * @global_counter : Any change increments this counter + * @param_counter : Indicates any params changed + * @param_id : Param modified - defined below + * @param_val : New val of last param modified + * @write_config_counter : write config occurred + * @write_config_rsvd : + * @ldrv_op_counter : Indicates ldrv op started/completed + * @ldrv_opid : ldrv num + * @ldrv_opcmd : ldrv operation - defined below + * @ldrv_opstatus : status of the operation + * @ldrv_state_counter : Indicates change of ldrv state + * @ldrv_state_id : ldrv num + * @ldrv_state_new : New state + * @ldrv_state_old : old state + * @pdrv_state_counter : Indicates change of ldrv state + * @pdrv_state_id : pdrv id + * @pdrv_state_new : New state + * @pdrv_state_old : old state + * @pdrv_fmt_counter : Indicates pdrv format started/over + * @pdrv_fmt_id : pdrv id + * @pdrv_fmt_val : format started/over + * @pdrv_fmt_rsvd : + * @targ_xfer_counter : Indicates SCSI-2 Xfer rate change + * @targ_xfer_id : pdrv Id + * @targ_xfer_val : new Xfer params of last pdrv + * @targ_xfer_rsvd : + * @fcloop_id_chg_counter : Indicates loopid changed + * @fcloopid_pdrvid : pdrv id + * @fcloop_id0 : loopid on fc loop 0 + * @fcloop_id1 : loopid on fc loop 1 + * @fcloop_state_counter : Indicates loop state changed + * @fcloop_state0 : state of fc loop 0 + * @fcloop_state1 : state of fc loop 1 + * @fcloop_state_rsvd : + */ +typedef struct { + uint32_t global_counter; + uint8_t param_counter; + uint8_t param_id; + uint16_t param_val; + uint8_t write_config_counter; + uint8_t write_config_rsvd[3]; + uint8_t ldrv_op_counter; + uint8_t ldrv_opid; + uint8_t ldrv_opcmd; + uint8_t ldrv_opstatus; + uint8_t ldrv_state_counter; + uint8_t ldrv_state_id; + uint8_t ldrv_state_new; + uint8_t ldrv_state_old; + uint8_t pdrv_state_counter; + uint8_t pdrv_state_id; + uint8_t pdrv_state_new; + uint8_t pdrv_state_old; + uint8_t pdrv_fmt_counter; + uint8_t pdrv_fmt_id; + uint8_t pdrv_fmt_val; + uint8_t pdrv_fmt_rsvd; + uint8_t targ_xfer_counter; + uint8_t targ_xfer_id; + uint8_t targ_xfer_val; + uint8_t targ_xfer_rsvd; + uint8_t fcloop_id_chg_counter; + uint8_t fcloopid_pdrvid; + uint8_t fcloop_id0; + uint8_t fcloop_id1; + uint8_t fcloop_state_counter; + uint8_t fcloop_state0; + uint8_t fcloop_state1; + uint8_t fcloop_state_rsvd; +} __attribute__ ((packed)) mraid_notify_t; + + +/** + * mraid_inquiry3_t - enquiry for device information + * + * @data_size : current size in bytes (not including resvd) + * @notify : + * @notify_rsvd : + * @rebuild_rate : rebuild rate (0% - 100%) + * @cache_flush_int : cache flush interval in seconds + * @sense_alert : + * @drive_insert_count : drive insertion count + * @battery_status : + * @num_ldrv : no. of Log Drives configured + * @recon_state : state of reconstruct + * @ldrv_op_status : logdrv Status + * @ldrv_size : size of each log drv + * @ldrv_prop : + * @ldrv_state : state of log drives + * @pdrv_state : state of phys drvs. + * @pdrv_format : + * @targ_xfer : phys device transfer rate + * @pad1k : 761 + 263reserved = 1024 bytes total size + */ +#define MAX_NOTIFY_SIZE 0x80 +#define CUR_NOTIFY_SIZE sizeof(mraid_notify_t) + +typedef struct { + uint32_t data_size; + + mraid_notify_t notify; + + uint8_t notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE]; + + uint8_t rebuild_rate; + uint8_t cache_flush_int; + uint8_t sense_alert; + uint8_t drive_insert_count; + + uint8_t battery_status; + uint8_t num_ldrv; + uint8_t recon_state[MAX_LOGICAL_DRIVES_40LD / 8]; + uint16_t ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8]; + + uint32_t ldrv_size[MAX_LOGICAL_DRIVES_40LD]; + uint8_t ldrv_prop[MAX_LOGICAL_DRIVES_40LD]; + uint8_t ldrv_state[MAX_LOGICAL_DRIVES_40LD]; + uint8_t pdrv_state[FC_MAX_PHYSICAL_DEVICES]; + uint16_t pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16]; + + uint8_t targ_xfer[80]; + uint8_t pad1k[263]; +} __attribute__ ((packed)) mraid_inquiry3_t; + + +/** + * mraid_adapinfo_t - information about the adapter + * @max_commands : max concurrent commands supported + * @rebuild_rate : rebuild rate - 0% thru 100% + * @max_targ_per_chan : max targ per channel + * @nchannels : number of channels on HBA + * @fw_version : firmware version + * @age_of_flash : number of times FW has been flashed + * @chip_set_value : contents of 0xC0000832 + * @dram_size : in MB + * @cache_flush_interval : in seconds + * @bios_version : + * @board_type : + * @sense_alert : + * @write_config_count : increase with every configuration change + * @drive_inserted_count : increase with every drive inserted + * @inserted_drive : channel:Id of inserted drive + * @battery_status : bit 0: battery module missing + * bit 1: VBAD + * bit 2: temprature high + * bit 3: battery pack missing + * bit 4,5: + * 00 - charge complete + * 01 - fast charge in progress + * 10 - fast charge fail + * 11 - undefined + * bit 6: counter > 1000 + * bit 7: Undefined + * @dec_fault_bus_info : + */ +typedef struct { + uint8_t max_commands; + uint8_t rebuild_rate; + uint8_t max_targ_per_chan; + uint8_t nchannels; + uint8_t fw_version[4]; + uint16_t age_of_flash; + uint8_t chip_set_value; + uint8_t dram_size; + uint8_t cache_flush_interval; + uint8_t bios_version[4]; + uint8_t board_type; + uint8_t sense_alert; + uint8_t write_config_count; + uint8_t battery_status; + uint8_t dec_fault_bus_info; +} __attribute__ ((packed)) mraid_adapinfo_t; + + +/** + * mraid_ldrv_info_t - information about the logical drives + * @nldrv : Number of logical drives configured + * @rsvd : + * @size : size of each logical drive + * @prop : + * @state : state of each logical drive + */ +typedef struct { + uint8_t nldrv; + uint8_t rsvd[3]; + uint32_t size[MAX_LOGICAL_DRIVES_8LD]; + uint8_t prop[MAX_LOGICAL_DRIVES_8LD]; + uint8_t state[MAX_LOGICAL_DRIVES_8LD]; +} __attribute__ ((packed)) mraid_ldrv_info_t; + + +/** + * mraid_pdrv_info_t - information about the physical drives + * @pdrv_state : state of each physical drive + */ +typedef struct { + uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES]; + uint8_t rsvd; +} __attribute__ ((packed)) mraid_pdrv_info_t; + + +/** + * mraid_inquiry_t - RAID inquiry, mailbox command 0x05 + * @mraid_adapinfo_t : adapter information + * @mraid_ldrv_info_t : logical drives information + * @mraid_pdrv_info_t : physical drives information + */ +typedef struct { + mraid_adapinfo_t adapter_info; + mraid_ldrv_info_t logdrv_info; + mraid_pdrv_info_t pdrv_info; +} __attribute__ ((packed)) mraid_inquiry_t; + + +/** + * mraid_extinq_t - RAID extended inquiry, mailbox command 0x04 + * + * @raid_inq : raid inquiry + * @phys_drv_format : + * @stack_attn : + * @modem_status : + * @rsvd : + */ +typedef struct { + mraid_inquiry_t raid_inq; + uint16_t phys_drv_format[MAX_MBOX_CHANNELS]; + uint8_t stack_attn; + uint8_t modem_status; + uint8_t rsvd[2]; +} __attribute__ ((packed)) mraid_extinq_t; + + +/** + * adap_device_t - device information + * @channel : channel fpor the device + * @target : target ID of the device + */ +typedef struct { + uint8_t channel; + uint8_t target; +}__attribute__ ((packed)) adap_device_t; + + +/** + * adap_span_40ld_t - 40LD span + * @start_blk : starting block + * @num_blks : number of blocks + */ +typedef struct { + uint32_t start_blk; + uint32_t num_blks; + adap_device_t device[MAX_ROW_SIZE_40LD]; +}__attribute__ ((packed)) adap_span_40ld_t; + + +/** + * adap_span_8ld_t - 8LD span + * @start_blk : starting block + * @num_blks : number of blocks + */ +typedef struct { + uint32_t start_blk; + uint32_t num_blks; + adap_device_t device[MAX_ROW_SIZE_8LD]; +}__attribute__ ((packed)) adap_span_8ld_t; + + +/** + * logdrv_param_t - logical drives parameters + * + * @span_depth : total number of spans + * @level : RAID level + * @read_ahead : read ahead, no read ahead, adaptive read ahead + * @stripe_sz : encoded stripe size + * @status : status of the logical drive + * @write_mode : write mode, write_through/write_back + * @direct_io : direct io or through cache + * @row_size : number of stripes in a row + */ +typedef struct { + uint8_t span_depth; + uint8_t level; + uint8_t read_ahead; + uint8_t stripe_sz; + uint8_t status; + uint8_t write_mode; + uint8_t direct_io; + uint8_t row_size; +} __attribute__ ((packed)) logdrv_param_t; + + +/** + * logdrv_40ld_t - logical drive definition for 40LD controllers + * @lparam : logical drives parameters + * @span : span + */ +typedef struct { + logdrv_param_t lparam; + adap_span_40ld_t span[SPAN_DEPTH_8_SPANS]; +}__attribute__ ((packed)) logdrv_40ld_t; + + +/** + * logdrv_8ld_span8_t - logical drive definition for 8LD controllers + * @lparam : logical drives parameters + * @span : span + * + * 8-LD logical drive with upto 8 spans + */ +typedef struct { + logdrv_param_t lparam; + adap_span_8ld_t span[SPAN_DEPTH_8_SPANS]; +}__attribute__ ((packed)) logdrv_8ld_span8_t; + + +/** + * logdrv_8ld_span4_t - logical drive definition for 8LD controllers + * @lparam : logical drives parameters + * @span : span + * + * 8-LD logical drive with upto 4 spans + */ +typedef struct { + logdrv_param_t lparam; + adap_span_8ld_t span[SPAN_DEPTH_4_SPANS]; +}__attribute__ ((packed)) logdrv_8ld_span4_t; + + +/** + * phys_drive_t - physical device information + * @type : Type of the device + * @cur_status : current status of the device + * @tag_depth : Level of tagging + * @sync_neg : sync negotiation - ENABLE or DISBALE + * @size : configurable size in terms of 512 byte + */ +typedef struct { + uint8_t type; + uint8_t cur_status; + uint8_t tag_depth; + uint8_t sync_neg; + uint32_t size; +}__attribute__ ((packed)) phys_drive_t; + + +/** + * disk_array_40ld_t - disk array for 40LD controllers + * @numldrv : number of logical drives + * @resvd : + * @ldrv : logical drives information + * @pdrv : physical drives information + */ +typedef struct { + uint8_t numldrv; + uint8_t resvd[3]; + logdrv_40ld_t ldrv[MAX_LOGICAL_DRIVES_40LD]; + phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; +}__attribute__ ((packed)) disk_array_40ld_t; + + +/** + * disk_array_8ld_span8_t - disk array for 8LD controllers + * @numldrv : number of logical drives + * @resvd : + * @ldrv : logical drives information + * @pdrv : physical drives information + * + * Disk array for 8LD logical drives with upto 8 spans + */ +typedef struct { + uint8_t numldrv; + uint8_t resvd[3]; + logdrv_8ld_span8_t ldrv[MAX_LOGICAL_DRIVES_8LD]; + phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; +}__attribute__ ((packed)) disk_array_8ld_span8_t; + + +/** + * disk_array_8ld_span4_t - disk array for 8LD controllers + * @numldrv : number of logical drives + * @resvd : + * @ldrv : logical drives information + * @pdrv : physical drives information + * + * Disk array for 8LD logical drives with upto 4 spans + */ +typedef struct { + uint8_t numldrv; + uint8_t resvd[3]; + logdrv_8ld_span4_t ldrv[MAX_LOGICAL_DRIVES_8LD]; + phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; +}__attribute__ ((packed)) disk_array_8ld_span4_t; + + +/** + * private_bios_data - bios private data for boot devices + * @geometry : bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB, + * 0x1000 - 8GB, Others values are invalid + * @unused : bits 4-7 are unused + * @boot_drv : logical drive set as boot drive, 0..7 - for 8LD cards, + * 0..39 - for 40LD cards + * @cksum : 0-(sum of first 13 bytes of this structure) + */ +struct private_bios_data { + uint8_t geometry :4; + uint8_t unused :4; + uint8_t boot_drv; + uint8_t rsvd[12]; + uint16_t cksum; +} __attribute__ ((packed)); + + +/** + * mbox_sgl64 - 64-bit scatter list for mailbox based controllers + * @address : address of the buffer + * @length : data transfer length + */ +typedef struct { + uint64_t address; + uint32_t length; +} __attribute__ ((packed)) mbox_sgl64; + +/** + * mbox_sgl32 - 32-bit scatter list for mailbox based controllers + * @address : address of the buffer + * @length : data transfer length + */ +typedef struct { + uint32_t address; + uint32_t length; +} __attribute__ ((packed)) mbox_sgl32; + +#endif // _MRAID_MBOX_DEFS_H_ + +/* vim: set ts=8 sw=8 tw=78: */ diff -Nru a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/mega_common.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,283 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * FILE : mega_common.h + * + * Libaray of common routine used by all low-level megaraid drivers + */ + +#ifndef _MEGA_COMMON_H_ +#define _MEGA_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define LSI_MAX_CHANNELS 16 +#define LSI_MAX_LOGICAL_DRIVES_64LD (64+1) + + +/** + * scb_t - scsi command control block + * @param ccb : command control block for individual driver + * @param list : list of control blocks + * @param gp : general purpose field for LLDs + * @param sno : all SCBs have a serial number + * @param scp : associated scsi command + * @param state : current state of scb + * @param dma_dir : direction of data transfer + * @param dma_type : transfer with sg list, buffer, or no data transfer + * @param dev_channel : actual channel on the device + * @param dev_target : actual target on the device + * @param status : completion status + * + * This is our central data structure to issue commands the each driver. + * Driver specific data structures are maintained in the ccb field. + * scb provides a field 'gp', which can be used by LLD for its own purposes + * + * dev_channel and dev_target must be initialized with the actual channel and + * target on the controller. + */ +typedef struct { + caddr_t ccb; + struct list_head list; + unsigned long gp; + unsigned int sno; + struct scsi_cmnd *scp; + uint32_t state; + uint32_t dma_direction; + uint32_t dma_type; + uint16_t dev_channel; + uint16_t dev_target; + uint32_t status; +} scb_t; + +/* + * SCB states as it transitions from one state to another + */ +#define SCB_FREE 0x0000 /* on the free list */ +#define SCB_ACTIVE 0x0001 /* off the free list */ +#define SCB_PENDQ 0x0002 /* on the pending queue */ +#define SCB_ISSUED 0x0004 /* issued - owner f/w */ +#define SCB_ABORT 0x0008 /* Got an abort for this one */ +#define SCB_RESET 0x0010 /* Got a reset for this one */ + +/* + * DMA types for scb + */ +#define MRAID_DMA_NONE 0x0000 /* no data transfer for this command */ +#define MRAID_DMA_WSG 0x0001 /* data transfer using a sg list */ +#define MRAID_DMA_WBUF 0x0002 /* data transfer using a contiguous buffer */ + + +/** + * struct adapter_t - driver's initialization structure + * @param dpc_h : tasklet handle + * @param pdev : pci configuration pointer for kernel + * @param host : pointer to host structure of mid-layer + * @param host_lock : pointer to appropriate lock + * @param lock : synchronization lock for mid-layer and driver + * @param quiescent : driver is quiescent for now. + * @param outstanding_cmds : number of commands pending in the driver + * @param kscb_list : pointer to the bulk of SCBs pointers for IO + * @param kscb_pool : pool of free scbs for IO + * @param kscb_pool_lock : lock for pool of free scbs + * @param pend_list : pending commands list + * @param pend_list_lock : exlusion lock for pending commands list + * @param completed_list : list of completed commands + * @param completed_list_lock : exclusion lock for list of completed commands + * @param sglen : max sg elements supported + * @param device_ids : to convert kernel device addr to our devices. + * @param raid_device : raid adapter specific pointer + * @param max_channel : maximum channel number supported - inclusive + * @param max_target : max target supported - inclusive + * @param max_lun : max lun supported - inclusive + * @param unique_id : unique identifier for each adapter + * @param irq : IRQ for this adapter + * @param ito : internal timeout value, (-1) means no timeout + * @param ibuf : buffer to issue internal commands + * @param ibuf_dma_h : dma handle for the above buffer + * @param uscb_list : SCB pointers for user cmds, common mgmt module + * @param uscb_pool : pool of SCBs for user commands + * @param uscb_pool_lock : exclusion lock for these SCBs + * @param max_cmds : max outstanding commands + * @param fw_version : firmware version + * @param bios_version : bios version + * @param max_cdb_sz : biggest CDB size supported. + * @param ha : is high availability present - clustering + * @param init_id : initiator ID, the default value should be 7 + * @param max_sectors : max sectors per request + * @param cmd_per_lun : max outstanding commands per LUN + * @param being_detached : set when unloading, no more mgmt calls + * + * + * mraid_setup_device_map() can be called anytime after the device map is + * available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is + * required, usually from LLD's queue entry point. The formar API sets up the + * MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the + * device in question is a logical drive. + * + * quiescent flag should be set by the driver if it is not accepting more + * commands + * + * NOTE: The fields of this structures are placed to minimize cache misses + */ + +// amount of space required to store the bios and firmware version strings +#define VERSION_SIZE 16 + +typedef struct { + struct tasklet_struct dpc_h; + struct pci_dev *pdev; + struct Scsi_Host *host; + spinlock_t *host_lock; + spinlock_t lock; + uint8_t quiescent; + int outstanding_cmds; + scb_t *kscb_list; + struct list_head kscb_pool; + spinlock_t kscb_pool_lock; + struct list_head pend_list; + spinlock_t pend_list_lock; + struct list_head completed_list; + spinlock_t completed_list_lock; + uint16_t sglen; + int device_ids[LSI_MAX_CHANNELS] + [LSI_MAX_LOGICAL_DRIVES_64LD]; + caddr_t raid_device; + uint8_t max_channel; + uint16_t max_target; + uint8_t max_lun; + + uint32_t unique_id; + uint8_t irq; + uint8_t ito; + caddr_t ibuf; + dma_addr_t ibuf_dma_h; + scb_t *uscb_list; + struct list_head uscb_pool; + spinlock_t uscb_pool_lock; + int max_cmds; + uint8_t fw_version[VERSION_SIZE]; + uint8_t bios_version[VERSION_SIZE]; + uint8_t max_cdb_sz; + uint8_t ha; + uint16_t init_id; + uint16_t max_sectors; + uint16_t cmd_per_lun; + atomic_t being_detached; +} adapter_t; + +#define SCSI_FREE_LIST_LOCK(adapter) (&adapter->kscb_pool_lock) +#define USER_FREE_LIST_LOCK(adapter) (&adapter->uscb_pool_lock) +#define PENDING_LIST_LOCK(adapter) (&adapter->pend_list_lock) +#define COMPLETED_LIST_LOCK(adapter) (&adapter->completed_list_lock) + + +// conversion from scsi command +#define SCP2HOST(scp) (scp)->device->host // to host +#define SCP2HOSTDATA(scp) SCP2HOST(scp)->hostdata // to soft state +#define SCP2CHANNEL(scp) (scp)->device->channel // to channel +#define SCP2TARGET(scp) (scp)->device->id // to target +#define SCP2LUN(scp) (scp)->device->lun // to LUN + +// generic macro to convert scsi command and host to controller's soft state +#define SCSIHOST2ADAP(host) (((caddr_t *)(host->hostdata))[0]) +#define SCP2ADAPTER(scp) (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp)) + + +/** + * MRAID_GET_DEVICE_MAP - device ids + * @param adp - Adapter's soft state + * @param scp - mid-layer scsi command pointer + * @param p_chan - physical channel on the controller + * @param target - target id of the device or logical drive number + * @param islogical - set if the command is for the logical drive + * + * Macro to retrieve information about device class, logical or physical and + * the corresponding physical channel and target or logical drive number + **/ +#define MRAID_IS_LOGICAL(adp, scp) \ + (SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0 + +#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical) \ + /* \ + * Is the request coming for the virtual channel \ + */ \ + islogical = MRAID_IS_LOGICAL(adp, scp); \ + \ + /* \ + * Get an index into our table of drive ids mapping \ + */ \ + if (islogical) { \ + p_chan = 0xFF; \ + target = \ + (adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)]; \ + } \ + else { \ + p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)] \ + [SCP2TARGET(scp)] >> 8) & 0xFF; \ + target = ((adp)->device_ids[SCP2CHANNEL(scp)] \ + [SCP2TARGET(scp)] & 0xFF); \ + } + +/* + * ### Helper routines ### + */ +#define LSI_DBGLVL mraid_debug_level // each LLD must define a global + // mraid_debug_level + +#ifdef DEBUG +#if defined (_ASSERT_PANIC) +#define ASSERT_ACTION panic +#else +#define ASSERT_ACTION printk +#endif + +#define ASSERT(expression) \ + if (!(expression)) { \ + ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \ + #expression, __FILE__, __LINE__, __FUNCTION__); \ + } +#else +#define ASSERT(expression) +#endif + +/* + * struct mraid_pci_blk - structure holds DMA memory block info + * @param vaddr : virtual address to a memory block + * @param dma_addr : DMA handle to a memory block + * + * This structure is filled up for the caller. It is the responsibilty of the + * caller to allocate this array big enough to store addresses for all + * requested elements + */ +struct mraid_pci_blk { + caddr_t vaddr; + dma_addr_t dma_addr; +}; + +#endif // _MEGA_COMMON_H_ + +// vim: set ts=8 sw=8 tw=78: diff -Nru a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/megaraid_ioctl.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,291 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * FILE : megaraid_ioctl.h + * + * Definitions to interface with user level applications + */ + +#ifndef _MEGARAID_IOCTL_H_ +#define _MEGARAID_IOCTL_H_ + +#include +#include + +#include "mbox_defs.h" + +/** + * con_log() - console log routine + * @param level : indicates the severity of the message. + * @fparam mt : format string + * + * con_log displays the error messages on the console based on the current + * debug level. Also it attaches the appropriate kernel severity level with + * the message. + * + * + * consolge messages debug levels + */ +#define CL_ANN 0 /* print unconditionally, announcements */ +#define CL_DLEVEL1 1 /* debug level 1, informative */ +#define CL_DLEVEL2 2 /* debug level 2, verbose */ +#define CL_DLEVEL3 3 /* debug level 3, very verbose */ + +#define con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt; + +/* + * Definitions & Declarations needed to use common management module + */ + +#define MEGAIOC_MAGIC 'm' +#define MEGAIOCCMD _IOWR(MEGAIOC_MAGIC, 0, mimd_t) + +#define MEGAIOC_QNADAP 'm' /* Query # of adapters */ +#define MEGAIOC_QDRVRVER 'e' /* Query driver version */ +#define MEGAIOC_QADAPINFO 'g' /* Query adapter information */ + +#define USCSICMD 0x80 +#define UIOC_RD 0x00001 +#define UIOC_WR 0x00002 + +#define MBOX_CMD 0x00000 +#define GET_DRIVER_VER 0x10000 +#define GET_N_ADAP 0x20000 +#define GET_ADAP_INFO 0x30000 +#define GET_CAP 0x40000 +#define GET_STATS 0x50000 +#define GET_IOCTL_VERSION 0x01 + +#define EXT_IOCTL_SIGN_SZ 16 +#define EXT_IOCTL_SIGN "$$_EXTD_IOCTL_$$" + +#define MBOX_LEGACY 0x00 /* ioctl has legacy mbox*/ +#define MBOX_HPE 0x01 /* ioctl has hpe mbox */ + +#define APPTYPE_MIMD 0x00 /* old existing apps */ +#define APPTYPE_UIOC 0x01 /* new apps using uioc */ + +#define IOCTL_ISSUE 0x00000001 /* Issue ioctl */ +#define IOCTL_ABORT 0x00000002 /* Abort previous ioctl */ + +#define DRVRTYPE_MBOX 0x00000001 /* regular mbox driver */ +#define DRVRTYPE_HPE 0x00000002 /* new hpe driver */ + +#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | (adapno) ) +#define GETADAP(mkadap) ((mkadap) ^ MEGAIOC_MAGIC << 8) + +#define MAX_DMA_POOLS 5 /* 4k, 8k, 16k, 32k, 64k*/ + + +/** + * struct uioc_t - the common ioctl packet structure + * + * @signature : Must be "$$_EXTD_IOCTL_$$" + * @mb_type : Type of the mail box (MB_LEGACY or MB_HPE) + * @app_type : Type of the issuing application (existing or new) + * @opcode : Opcode of the command + * @adapno : Adapter number + * @cmdbuf : Pointer to buffer - can point to mbox or plain data buffer + * @xferlen : xferlen for DCMD and non mailbox commands + * @data_dir : Direction of the data transfer + * @status : Status from the driver + * @reserved : reserved bytes for future expansion + * + * @user_data : user data transfer address is saved in this + * @user_data_len: length of the data buffer sent by user app + * @user_pthru : user passthru address is saves in this (null if DCMD) + * @pthru32 : kernel address passthru (allocated per kioc) + * @pthru32_h : physicall address of @pthru32 + * @list : for kioc free pool list maintenance + * @done : call back routine for llds to call when kioc is completed + * @buf_vaddr : dma pool buffer attached to kioc for data transfer + * @buf_paddr : physical address of the dma pool buffer + * @pool_index : index of the dma pool that @buf_vaddr is taken from + * @free_buf : indicates if buffer needs to be freed after kioc completes + * + * Note : All LSI drivers understand only this packet. Any other + * : format sent by applications would be converted to this. + */ +typedef struct uioc { + +/* User Apps: */ + + uint8_t signature[EXT_IOCTL_SIGN_SZ]; + uint16_t mb_type; + uint16_t app_type; + uint32_t opcode; + uint32_t adapno; + uint64_t cmdbuf; + uint32_t xferlen; + uint32_t data_dir; + int32_t status; + uint8_t reserved[128]; + +/* Driver Data: */ + void __user * user_data; + uint32_t user_data_len; + mraid_passthru_t __user *user_pthru; + + mraid_passthru_t *pthru32; + dma_addr_t pthru32_h; + + struct list_head list; + void (*done)(struct uioc*); + + caddr_t buf_vaddr; + dma_addr_t buf_paddr; + uint8_t pool_index; + uint8_t free_buf; + +} __attribute__ ((aligned(1024),packed)) uioc_t; + + +/** + * struct mraid_hba_info - information about the controller + * + * @param pci_vendor_id : PCI vendor id + * @param pci_device_id : PCI device id + * @param subsystem_vendor_id : PCI subsystem vendor id + * @param subsystem_device_id : PCI subsystem device id + * @param baseport : base port of hba memory + * @param pci_bus : PCI bus + * @param pci_dev_fn : PCI device/function values + * @param irq : interrupt vector for the device + * + * Extended information of 256 bytes about the controller. Align on the single + * byte boundary so that 32-bit applications can be run on 64-bit platform + * drivers withoug re-compilation. + * NOTE: reduce the number of reserved bytes whenever new field are added, so + * that total size of the structure remains 256 bytes. + */ +typedef struct mraid_hba_info { + + uint16_t pci_vendor_id; + uint16_t pci_device_id; + uint16_t subsys_vendor_id; + uint16_t subsys_device_id; + + uint64_t baseport; + uint8_t pci_bus; + uint8_t pci_dev_fn; + uint8_t pci_slot; + uint8_t irq; + + uint32_t unique_id; + uint32_t host_no; + + uint8_t num_ldrv; +} __attribute__ ((aligned(256), packed)) mraid_hba_info_t; + + +/** + * mcontroller : adapter info structure for old mimd_t apps + * + * @base : base address + * @irq : irq number + * @numldrv : number of logical drives + * @pcibus : pci bus + * @pcidev : pci device + * @pcifun : pci function + * @pciid : pci id + * @pcivendor : vendor id + * @pcislot : slot number + * @uid : unique id + */ +typedef struct mcontroller { + + uint64_t base; + uint8_t irq; + uint8_t numldrv; + uint8_t pcibus; + uint16_t pcidev; + uint8_t pcifun; + uint16_t pciid; + uint16_t pcivendor; + uint8_t pcislot; + uint32_t uid; + +} __attribute__ ((packed)) mcontroller_t; + + +/** + * mm_dmapool_t : Represents one dma pool with just one buffer + * + * @vaddr : Virtual address + * @paddr : DMA physicall address + * @bufsize : In KB - 4 = 4k, 8 = 8k etc. + * @handle : Handle to the dma pool + * @lock : lock to synchronize access to the pool + * @in_use : If pool already in use, attach new block + */ +typedef struct mm_dmapool { + caddr_t vaddr; + dma_addr_t paddr; + uint32_t buf_size; + struct dma_pool *handle; + spinlock_t lock; + uint8_t in_use; +} mm_dmapool_t; + + +/** + * mraid_mmadp_t: Structure that drivers pass during (un)registration + * + * @unique_id : Any unique id (usually PCI bus+dev+fn) + * @drvr_type : megaraid or hpe (DRVRTYPE_MBOX or DRVRTYPE_HPE) + * @drv_data : Driver specific; not touched by the common module + * @timeout : timeout for issued kiocs + * @max_kioc : Maximum ioctl packets acceptable by the lld + * @pdev : pci dev; used for allocating dma'ble memory + * @issue_uioc : Driver supplied routine to issue uioc_t commands + * : issue_uioc(drvr_data, kioc, ISSUE/ABORT, uioc_done) + * @list : attach with the global list of adapters + * @kioc_list : block of mem for @max_kioc number of kiocs + * @kioc_pool : pool of free kiocs + * @kioc_pool_lock : protection for free pool + * @kioc_semaphore : so as not to exceed @max_kioc parallel ioctls + * @mbox_list : block of mem for @max_kioc number of mboxes + * @pthru_dma_pool : DMA pool to allocate passthru packets + * @dma_pool_list : array of dma pools + */ + +typedef struct mraid_mmadp { + +/* Filled by driver */ + + uint32_t unique_id; + uint32_t drvr_type; + unsigned long drvr_data; + uint8_t timeout; + uint8_t max_kioc; + + struct pci_dev *pdev; + + int(*issue_uioc)(unsigned long, uioc_t *, uint32_t); + +/* Maintained by common module */ + + struct list_head list; + uioc_t *kioc_list; + struct list_head kioc_pool; + spinlock_t kioc_pool_lock; + struct semaphore kioc_semaphore; + + mbox64_t *mbox_list; + struct dma_pool *pthru_dma_pool; + mm_dmapool_t dma_pool_list[MAX_DMA_POOLS]; + +} mraid_mmadp_t; + +int mraid_mm_register_adp(mraid_mmadp_t *); +int mraid_mm_unregister_adp(uint32_t); + +#endif /* _MEGARAID_IOCTL_H_ */ diff -Nru a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/megaraid_mbox.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,3891 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * FILE : megaraid_mbox.c + * Version : v2.20.4 (September 27 2004) + * + * Authors: + * Atul Mukker + * Sreenivas Bagalkote + * Manoj Jose + * + * List of supported controllers + * + * OEM Product Name VID DID SSVID SSID + * --- ------------ --- --- ---- ---- + * Dell PERC3/QC 101E 1960 1028 0471 + * Dell PERC3/DC 101E 1960 1028 0493 + * Dell PERC3/SC 101E 1960 1028 0475 + * Dell PERC3/Di 1028 1960 1028 0123 + * Dell PERC4/SC 1000 1960 1028 0520 + * Dell PERC4/DC 1000 1960 1028 0518 + * Dell PERC4/QC 1000 0407 1028 0531 + * Dell PERC4/Di 1028 000F 1028 014A + * Dell PERC 4e/Si 1028 0013 1028 016c + * Dell PERC 4e/Di 1028 0013 1028 016d + * Dell PERC 4e/Di 1028 0013 1028 016e + * Dell PERC 4e/Di 1028 0013 1028 016f + * Dell PERC 4e/Di 1028 0013 1028 0170 + * Dell PERC 4e/DC 1000 0408 1028 0002 + * Dell PERC 4e/SC 1000 0408 1028 0001 + * + * + * LSI MegaRAID SCSI 320-0 1000 1960 1000 A520 + * LSI MegaRAID SCSI 320-1 1000 1960 1000 0520 + * LSI MegaRAID SCSI 320-2 1000 1960 1000 0518 + * LSI MegaRAID SCSI 320-0X 1000 0407 1000 0530 + * LSI MegaRAID SCSI 320-2X 1000 0407 1000 0532 + * LSI MegaRAID SCSI 320-4X 1000 0407 1000 0531 + * LSI MegaRAID SCSI 320-1E 1000 0408 1000 0001 + * LSI MegaRAID SCSI 320-2E 1000 0408 1000 0002 + * LSI MegaRAID SATA 150-4 1000 1960 1000 4523 + * LSI MegaRAID SATA 150-6 1000 1960 1000 0523 + * LSI MegaRAID SATA 300-4X 1000 0409 1000 3004 + * LSI MegaRAID SATA 300-8X 1000 0409 1000 3008 + * + * INTEL RAID Controller SRCU42X 1000 0407 8086 0532 + * INTEL RAID Controller SRCS16 1000 1960 8086 0523 + * INTEL RAID Controller SRCU42E 1000 0408 8086 0002 + * INTEL RAID Controller SRCZCRX 1000 0407 8086 0530 + * INTEL RAID Controller SRCS28X 1000 0409 8086 3008 + * INTEL RAID Controller SROMBU42E 1000 0408 8086 3431 + * INTEL RAID Controller SROMBU42E 1000 0408 8086 3499 + * INTEL RAID Controller SRCU51L 1000 1960 8086 0520 + * + * + * FSC MegaRAID PCI Express ROMB 1000 0408 1734 1065 + * + * + * ACER MegaRAID ROMB-2E 1000 0408 1025 004D + * + * + * For history of changes, see Documentation/ChangeLog.megaraid + */ + +#include "megaraid_mbox.h" + +static int megaraid_init(void); +static void megaraid_exit(void); + +static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *); +static void megaraid_detach_one(struct pci_dev *); +static void megaraid_mbox_shutdown(struct device *); + +static int megaraid_io_attach(adapter_t *); +static void megaraid_io_detach(adapter_t *); + +static int megaraid_init_mbox(adapter_t *); +static void megaraid_fini_mbox(adapter_t *); + +static int megaraid_alloc_cmd_packets(adapter_t *); +static void megaraid_free_cmd_packets(adapter_t *); + +static int megaraid_mbox_setup_dma_pools(adapter_t *); +static void megaraid_mbox_teardown_dma_pools(adapter_t *); + +static int megaraid_abort_handler(struct scsi_cmnd *); +static int megaraid_reset_handler(struct scsi_cmnd *); + +static int mbox_post_sync_cmd(adapter_t *, uint8_t []); +static int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []); +static int megaraid_busywait_mbox(mraid_device_t *); +static int megaraid_mbox_product_info(adapter_t *); +static int megaraid_mbox_extended_cdb(adapter_t *); +static int megaraid_mbox_support_ha(adapter_t *, uint16_t *); +static int megaraid_mbox_support_random_del(adapter_t *); +static int megaraid_mbox_get_max_sg(adapter_t *); +static void megaraid_mbox_enum_raid_scsi(adapter_t *); +static void megaraid_mbox_flush_cache(adapter_t *); + +static void megaraid_mbox_display_scb(adapter_t *, scb_t *); +static void megaraid_mbox_setup_device_map(adapter_t *); + +static int megaraid_queue_command(struct scsi_cmnd *, + void (*)(struct scsi_cmnd *)); +static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static void megaraid_mbox_runpendq(adapter_t *, scb_t *); +static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, + struct scsi_cmnd *); +static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *, + struct scsi_cmnd *); + +static irqreturn_t megaraid_isr(int, void *, struct pt_regs *); + +static void megaraid_mbox_dpc(unsigned long); + +static int megaraid_cmm_register(adapter_t *); +static int megaraid_cmm_unregister(adapter_t *); +static int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t); +static int megaraid_mbox_mm_command(adapter_t *, uioc_t *); +static void megaraid_mbox_mm_done(adapter_t *, scb_t *); +static int gather_hbainfo(adapter_t *, mraid_hba_info_t *); +static int wait_till_fw_empty(adapter_t *); + + + +MODULE_AUTHOR("LSI Logic Corporation"); +MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MEGARAID_VERSION); + +/* + * ### modules parameters for driver ### + */ + +/** + * Set to enable driver to expose unconfigured disk to kernel + */ +static int megaraid_expose_unconf_disks = 0; +module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0); +MODULE_PARM_DESC(unconf_disks, + "Set to expose unconfigured disks to kernel (default=0)"); + +/** + * driver wait time if the adapter's mailbox is busy + */ +static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT; +module_param_named(busy_wait, max_mbox_busy_wait, int, 0); +MODULE_PARM_DESC(busy_wait, + "Max wait for mailbox in microseconds if busy (default=10)"); + +/** + * number of sectors per IO command + */ +static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS; +module_param_named(max_sectors, megaraid_max_sectors, int, 0); +MODULE_PARM_DESC(max_sectors, + "Maximum number of sectors per IO command (default=128)"); + +/** + * number of commands per logical unit + */ +static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN; +module_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0); +MODULE_PARM_DESC(cmd_per_lun, + "Maximum number of commands per logical unit (default=64)"); + + +/** + * Fast driver load option, skip scanning for physical devices during load. + * This would result in non-disk devices being skipped during driver load + * time. These can be later added though, using /proc/scsi/scsi + */ +static unsigned int megaraid_fast_load = 0; +module_param_named(fast_load, megaraid_fast_load, int, 0); +MODULE_PARM_DESC(fast_load, + "Faster loading of the driver, skips physical devices! (default=0)"); + + +/** + * mraid_debug level - threshold for amount of information to be displayed by + * the driver. This level can be changed through modules parameters, ioctl or + * sysfs/proc interface. By default, print the announcement messages only. + */ +int mraid_debug_level = CL_ANN; +module_param_named(debug_level, mraid_debug_level, int, 0); +MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)"); + +/* + * ### global data ### + */ +static uint8_t megaraid_mbox_version[8] = + { 0x02, 0x20, 0x04, 0x00, 9, 27, 20, 4 }; + + +/* + * PCI table for all supported controllers. + */ +static struct pci_device_id pci_id_table_g[] = { + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4_DI_DISCOVERY, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_DI_DISCOVERY, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4_SC, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_SC, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4_DC, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_DC, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4_QC, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_QC, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4_DI_EVERGLADES, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_DI_EVERGLADES, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_SI_BIGBEND, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_SI_BIGBEND, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_KOBUK, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_KOBUK, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_CORVETTE, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_CORVETTE, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_EXPEDITION, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_GUADALUPE, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4E_DC_320_2E, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DC_320_2E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4E_SC_320_1E, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_SC_320_1E, + }, + { + PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID3, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC3_QC, + }, + { + PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID3, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC3_DC, + }, + { + PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID3, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC3_SC, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_0, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_0, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_1, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_1, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_2, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_2, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_0x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_2x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_4x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_1E, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_2E, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_I4_133_RAID, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_I4_133_RAID, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_150_4, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_150_4, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_150_6, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_150_6, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_300_4x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_300_4x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_300_8x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_300_8x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCU42X, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCU42X, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCS16, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCS16, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCU42E, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCU42E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCZCRX, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCS28X, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCS28X, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB, + PCI_SUBSYS_ID_FSC, + PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E, + PCI_VENDOR_ID_AI, + PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E, + }, + {0} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, pci_id_table_g); + + +static struct pci_driver megaraid_pci_driver_g = { + .name = "megaraid", + .id_table = pci_id_table_g, + .probe = megaraid_probe_one, + .remove = __devexit_p(megaraid_detach_one), + .driver = { + .shutdown = megaraid_mbox_shutdown, + } +}; + + +/* + * Scsi host template for megaraid unified driver + */ +static struct scsi_host_template megaraid_template_g = { + .module = THIS_MODULE, + .name = "LSI Logic MegaRAID driver", + .proc_name = "megaraid", + .queuecommand = megaraid_queue_command, + .eh_abort_handler = megaraid_abort_handler, + .eh_device_reset_handler = megaraid_reset_handler, + .eh_bus_reset_handler = megaraid_reset_handler, + .eh_host_reset_handler = megaraid_reset_handler, + .use_clustering = ENABLE_CLUSTERING, +}; + + +/** + * megaraid_init - module load hook + * + * We register ourselves as hotplug enabled module and let PCI subsystem + * discover our adaters + **/ +static int __init +megaraid_init(void) +{ + int rval; + + // Announce the driver version + con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION, + MEGARAID_EXT_VERSION)); + + // check validity of module parameters + if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: max commands per lun reset to %d\n", + MBOX_MAX_SCSI_CMDS)); + + megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS; + } + + + // register as a PCI hot-plug driver module + if ((rval = pci_module_init(&megaraid_pci_driver_g))) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not register hotplug support.\n")); + } + + return rval; +} + + +/** + * megaraid_exit - driver unload entry point + * + * We simply unwrap the megaraid_init routine here + */ +static void __exit +megaraid_exit(void) +{ + con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); + + // unregister as PCI hotplug driver + pci_unregister_driver(&megaraid_pci_driver_g); + + return; +} + + +/** + * megaraid_probe_one - PCI hotplug entry point + * @param pdev : handle to this controller's PCI configuration space + * @param id : pci device id of the class of controllers + * + * This routine should be called whenever a new adapter is detected by the + * PCI hotplug susbsytem. + **/ +static int __devinit +megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + adapter_t *adapter; + + + // detected a new controller + con_log(CL_ANN, (KERN_INFO + "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device)); + + con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); + + if (pci_enable_device(pdev)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: pci_enable_device failed\n")); + + return -ENODEV; + } + + // Enable bus-mastering on this controller + pci_set_master(pdev); + + // Allocate the per driver initialization structure + adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL); + + if (adapter == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__)); + + goto out_probe_one; + } + memset(adapter, 0, sizeof(adapter_t)); + + + // set up PCI related soft state and other pre-known parameters + adapter->unique_id = pdev->bus->number << 8 | pdev->devfn; + adapter->irq = pdev->irq; + adapter->pdev = pdev; + + atomic_set(&adapter->being_detached, 0); + + // Setup the default DMA mask. This would be changed later on + // depending on hardware capabilities + if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFF) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: pci_set_dma_mask failed:%d\n", __LINE__)); + + goto out_free_adapter; + } + + + // Initialize the synchronization lock for kernel and LLD + spin_lock_init(&adapter->lock); + adapter->host_lock = &adapter->lock; + + + // Initialize the command queues: the list of free SCBs and the list + // of pending SCBs. + INIT_LIST_HEAD(&adapter->kscb_pool); + spin_lock_init(SCSI_FREE_LIST_LOCK(adapter)); + + INIT_LIST_HEAD(&adapter->pend_list); + spin_lock_init(PENDING_LIST_LOCK(adapter)); + + INIT_LIST_HEAD(&adapter->completed_list); + spin_lock_init(COMPLETED_LIST_LOCK(adapter)); + + + // Start the mailbox based controller + if (megaraid_init_mbox(adapter) != 0) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: maibox adapter did not initialize\n")); + + goto out_free_adapter; + } + + // Register with LSI Common Management Module + if (megaraid_cmm_register(adapter) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not register with management module\n")); + + goto out_fini_mbox; + } + + // setup adapter handle in PCI soft state + pci_set_drvdata(pdev, adapter); + + // attach with scsi mid-layer + if (megaraid_io_attach(adapter) != 0) { + + con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n")); + + goto out_cmm_unreg; + } + + return 0; + +out_cmm_unreg: + pci_set_drvdata(pdev, NULL); + megaraid_cmm_unregister(adapter); +out_fini_mbox: + megaraid_fini_mbox(adapter); +out_free_adapter: + kfree(adapter); +out_probe_one: + pci_disable_device(pdev); + + return -ENODEV; +} + + +/** + * megaraid_detach_one - release the framework resources and call LLD release + * routine + * @param pdev : handle for our PCI cofiguration space + * + * This routine is called during driver unload. We free all the allocated + * resources and call the corresponding LLD so that it can also release all + * its resources. + * + * This routine is also called from the PCI hotplug system + **/ +static void +megaraid_detach_one(struct pci_dev *pdev) +{ + adapter_t *adapter; + struct Scsi_Host *host; + + + // Start a rollback on this adapter + adapter = pci_get_drvdata(pdev); + + if (!adapter) { + con_log(CL_ANN, (KERN_CRIT + "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device)); + + return; + } + else { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device)); + } + + + host = adapter->host; + + // do not allow any more requests from the management module for this + // adapter. + // FIXME: How do we account for the request which might still be + // pending with us? + atomic_set(&adapter->being_detached, 1); + + // detach from the IO sub-system + megaraid_io_detach(adapter); + + // reset the device state in the PCI structure. We check this + // condition when we enter here. If the device state is NULL, + // that would mean the device has already been removed + pci_set_drvdata(pdev, NULL); + + // Unregister from common management module + // + // FIXME: this must return success or failure for conditions if there + // is a command pending with LLD or not. + megaraid_cmm_unregister(adapter); + + // finalize the mailbox based controller and release all resources + megaraid_fini_mbox(adapter); + + kfree(adapter); + + scsi_host_put(host); + + pci_disable_device(pdev); + + return; +} + + +/** + * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA + * @param device : generice driver model device + * + * Shutdown notification, perform flush cache + */ +static void +megaraid_mbox_shutdown(struct device *device) +{ + adapter_t *adapter = pci_get_drvdata(to_pci_dev(device)); + static int counter; + + if (!adapter) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: null device in shutdown\n")); + return; + } + + // flush caches now + con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...", + counter++)); + + megaraid_mbox_flush_cache(adapter); + + con_log(CL_ANN, ("done\n")); +} + + +/** + * megaraid_io_attach - attach a device with the IO subsystem + * @param adapter : controller's soft state + * + * Attach this device with the IO subsystem + **/ +static int +megaraid_io_attach(adapter_t *adapter) +{ + struct Scsi_Host *host; + + // Initialize SCSI Host structure + host = scsi_host_alloc(&megaraid_template_g, 8); + if (!host) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: scsi_register failed\n")); + + return -1; + } + + SCSIHOST2ADAP(host) = (caddr_t)adapter; + adapter->host = host; + + // export the parameters required by the mid-layer + scsi_assign_lock(host, adapter->host_lock); + scsi_set_device(host, &adapter->pdev->dev); + + host->irq = adapter->irq; + host->unique_id = adapter->unique_id; + host->can_queue = adapter->max_cmds; + host->this_id = adapter->init_id; + host->sg_tablesize = adapter->sglen; + host->max_sectors = adapter->max_sectors; + host->cmd_per_lun = adapter->cmd_per_lun; + host->max_channel = adapter->max_channel; + host->max_id = adapter->max_target; + host->max_lun = adapter->max_lun; + + + // notify mid-layer about the new controller + if (scsi_add_host(host, &adapter->pdev->dev)) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: scsi_add_host failed\n")); + + scsi_host_put(host); + + return -1; + } + + scsi_scan_host(host); + + return 0; +} + + +/** + * megaraid_io_detach - detach a device from the IO subsystem + * @param adapter : controller's soft state + * + * Detach this device from the IO subsystem + **/ +static void +megaraid_io_detach(adapter_t *adapter) +{ + struct Scsi_Host *host; + + con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n")); + + host = adapter->host; + + scsi_remove_host(host); + + return; +} + + +/* + * START: Mailbox Low Level Driver + * + * This is section specific to the single mailbox based controllers + */ + +/** + * megaraid_init_mbox - initialize controller + * @param adapter - our soft state + * + * . Allocate 16-byte aligned mailbox memory for firmware handshake + * . Allocate controller's memory resources + * . Find out all initialization data + * . Allocate memory required for all the commands + * . Use internal library of FW routines, build up complete soft state + */ +static int __init +megaraid_init_mbox(adapter_t *adapter) +{ + struct pci_dev *pdev; + mraid_device_t *raid_dev; + int i; + + + adapter->ito = MBOX_TIMEOUT; + pdev = adapter->pdev; + + /* + * Allocate and initialize the init data structure for mailbox + * controllers + */ + raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL); + if (raid_dev == NULL) return -1; + + memset(raid_dev, 0, sizeof(mraid_device_t)); + + /* + * Attach the adapter soft state to raid device soft state + */ + adapter->raid_device = (caddr_t)raid_dev; + raid_dev->fast_load = megaraid_fast_load; + + + // our baseport + raid_dev->baseport = pci_resource_start(pdev, 0); + + if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: mem region busy\n")); + + goto out_free_raid_dev; + } + + raid_dev->baseaddr = (unsigned long) + ioremap_nocache(raid_dev->baseport, 128); + + if (!raid_dev->baseaddr) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not map hba memory\n") ); + + goto out_release_regions; + } + + // + // Setup the rest of the soft state using the library of FW routines + // + + // request IRQ and register the interrupt service routine + if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid", + adapter)) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); + + goto out_iounmap; + } + + + // initialize the mutual exclusion lock for the mailbox + spin_lock_init(&raid_dev->mailbox_lock); + + // allocate memory required for commands + if (megaraid_alloc_cmd_packets(adapter) != 0) { + goto out_free_irq; + } + + // Product info + if (megaraid_mbox_product_info(adapter) != 0) { + goto out_alloc_cmds; + } + + // Do we support extended CDBs + adapter->max_cdb_sz = 10; + if (megaraid_mbox_extended_cdb(adapter) == 0) { + adapter->max_cdb_sz = 16; + } + + /* + * Do we support cluster environment, if we do, what is the initiator + * id. + * NOTE: In a non-cluster aware firmware environment, the LLD should + * return 7 as initiator id. + */ + adapter->ha = 0; + adapter->init_id = -1; + if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) { + adapter->ha = 1; + } + + /* + * Prepare the device ids array to have the mapping between the kernel + * device address and megaraid device address. + * We export the physical devices on their actual addresses. The + * logical drives are exported on a virtual SCSI channel + */ + megaraid_mbox_setup_device_map(adapter); + + // If the firmware supports random deletion, update the device id map + if (megaraid_mbox_support_random_del(adapter)) { + + // Change the logical drives numbers in device_ids array one + // slot in device_ids is reserved for target id, that's why + // "<=" below + for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) { + adapter->device_ids[adapter->max_channel][i] += 0x80; + } + adapter->device_ids[adapter->max_channel][adapter->init_id] = + 0xFF; + } + + /* + * find out the maximum number of scatter-gather elements supported by + * this firmware + */ + adapter->sglen = megaraid_mbox_get_max_sg(adapter); + + // enumerate RAID and SCSI channels so that all devices on SCSI + // channels can later be exported, including disk devices + megaraid_mbox_enum_raid_scsi(adapter); + + /* + * Other parameters required by upper layer + * + * maximum number of sectors per IO command + */ + adapter->max_sectors = megaraid_max_sectors; + + /* + * number of queued commands per LUN. + */ + adapter->cmd_per_lun = megaraid_cmd_per_lun; + + // Set the DMA mask to 64-bit. All supported controllers as capable of + // DMA in this range + if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFFFFFFFFFFULL) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not set DMA mask for 64-bit.\n")); + + goto out_alloc_cmds; + } + + // setup tasklet for DPC + tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc, + (unsigned long)adapter); + + con_log(CL_DLEVEL1, (KERN_INFO + "megaraid mbox hba successfully initialized\n")); + + return 0; + +out_alloc_cmds: + megaraid_free_cmd_packets(adapter); +out_free_irq: + free_irq(adapter->irq, adapter); +out_iounmap: + iounmap((caddr_t)raid_dev->baseaddr); +out_release_regions: + pci_release_regions(pdev); +out_free_raid_dev: + kfree(raid_dev); + + return -1; +} + + +/** + * megaraid_fini_mbox - undo controller initialization + * @param adapter : our soft state + */ +static void +megaraid_fini_mbox(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + + // flush all caches + megaraid_mbox_flush_cache(adapter); + + tasklet_kill(&adapter->dpc_h); + + megaraid_free_cmd_packets(adapter); + + free_irq(adapter->irq, adapter); + + iounmap((caddr_t)raid_dev->baseaddr); + + pci_release_regions(adapter->pdev); + + kfree(raid_dev); + + return; +} + + +/** + * megaraid_alloc_cmd_packets - allocate shared mailbox + * @param adapter : soft state of the raid controller + * + * Allocate and align the shared mailbox. This maibox is used to issue + * all the commands. For IO based controllers, the mailbox is also regsitered + * with the FW. Allocate memory for all commands as well. + * This is our big allocator + */ +static int +megaraid_alloc_cmd_packets(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + struct pci_dev *pdev; + unsigned long align; + scb_t *scb; + mbox_ccb_t *ccb; + struct mraid_pci_blk *epthru_pci_blk; + struct mraid_pci_blk *sg_pci_blk; + struct mraid_pci_blk *mbox_pci_blk; + int i; + + pdev = adapter->pdev; + + /* + * Setup the mailbox + * Allocate the common 16-byte aligned memory for the handshake + * mailbox. + */ + raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev, + sizeof(mbox64_t), &raid_dev->una_mbox64_dma); + + if (!raid_dev->una_mbox64) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + return -1; + } + memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t)); + + /* + * Align the mailbox at 16-byte boundary + */ + raid_dev->mbox = &raid_dev->una_mbox64->mbox32; + + raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) & + (~0UL ^ 0xFUL)); + + raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8); + + align = ((void *)raid_dev->mbox - + ((void *)&raid_dev->una_mbox64->mbox32)); + + raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 + + align; + + // Allocate memory for commands issued internally + adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE, + &adapter->ibuf_dma_h); + if (!adapter->ibuf) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + + goto out_free_common_mbox; + } + memset(adapter->ibuf, 0, MBOX_IBUF_SIZE); + + // Allocate memory for our SCSI Command Blocks and their associated + // memory + + /* + * Allocate memory for the base list of scb. Later allocate memory for + * CCBs and embedded components of each CCB and point the pointers in + * scb to the allocated components + * NOTE: The code to allocate SCB will be duplicated in all the LLD + * since the calling routine does not yet know the number of available + * commands. + */ + adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS, + GFP_KERNEL); + + if (adapter->kscb_list == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + goto out_free_ibuf; + } + memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS); + + // memory allocation for our command packets + if (megaraid_mbox_setup_dma_pools(adapter) != 0) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + goto out_free_scb_list; + } + + // Adjust the scb pointers and link in the free pool + epthru_pci_blk = raid_dev->epthru_pool; + sg_pci_blk = raid_dev->sg_pool; + mbox_pci_blk = raid_dev->mbox_pool; + + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + scb = adapter->kscb_list + i; + ccb = raid_dev->ccb_list + i; + + ccb->mbox = (mbox_t *)(mbox_pci_blk[i].vaddr + 16); + ccb->raw_mbox = (uint8_t *)ccb->mbox; + ccb->mbox64 = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8); + ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16; + + // make sure the mailbox is aligned properly + if (ccb->mbox_dma_h & 0x0F) { + con_log(CL_ANN, (KERN_CRIT + "megaraid mbox: not aligned on 16-bytes\n")); + + goto out_teardown_dma_pools; + } + + ccb->epthru = (mraid_epassthru_t *) + epthru_pci_blk[i].vaddr; + ccb->epthru_dma_h = epthru_pci_blk[i].dma_addr; + ccb->pthru = (mraid_passthru_t *)ccb->epthru; + ccb->pthru_dma_h = ccb->epthru_dma_h; + + + ccb->sgl64 = (mbox_sgl64 *)sg_pci_blk[i].vaddr; + ccb->sgl_dma_h = sg_pci_blk[i].dma_addr; + ccb->sgl32 = (mbox_sgl32 *)ccb->sgl64; + + scb->ccb = (caddr_t)ccb; + scb->gp = 0; + + scb->sno = i; // command index + + scb->scp = NULL; + scb->state = SCB_FREE; + scb->dma_direction = PCI_DMA_NONE; + scb->dma_type = MRAID_DMA_NONE; + scb->dev_channel = -1; + scb->dev_target = -1; + + // put scb in the free pool + list_add_tail(&scb->list, &adapter->kscb_pool); + } + + return 0; + +out_teardown_dma_pools: + megaraid_mbox_teardown_dma_pools(adapter); +out_free_scb_list: + kfree(adapter->kscb_list); +out_free_ibuf: + pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, + adapter->ibuf_dma_h); +out_free_common_mbox: + pci_free_consistent(adapter->pdev, sizeof(mbox64_t), + (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); + + return -1; +} + + +/** + * megaraid_free_cmd_packets - free memory + * @param adapter : soft state of the raid controller + * + * Release memory resources allocated for commands + */ +static void +megaraid_free_cmd_packets(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + + megaraid_mbox_teardown_dma_pools(adapter); + + kfree(adapter->kscb_list); + + pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE, + (void *)adapter->ibuf, adapter->ibuf_dma_h); + + pci_free_consistent(adapter->pdev, sizeof(mbox64_t), + (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); + return; +} + + +/** + * megaraid_mbox_setup_dma_pools - setup dma pool for command packets + * @param adapter : HBA soft state + * + * setup the dma pools for mailbox, passthru and extended passthru structures, + * and scatter-gather lists + */ +static int +megaraid_mbox_setup_dma_pools(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + struct mraid_pci_blk *epthru_pci_blk; + struct mraid_pci_blk *sg_pci_blk; + struct mraid_pci_blk *mbox_pci_blk; + int i; + + + + // Allocate memory for 16-bytes aligned mailboxes + raid_dev->mbox_pool_handle = pci_pool_create("megaraid mbox pool", + adapter->pdev, + sizeof(mbox64_t) + 16, + 16, 0); + + if (raid_dev->mbox_pool_handle == NULL) { + goto fail_setup_dma_pool; + } + + mbox_pci_blk = raid_dev->mbox_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + mbox_pci_blk[i].vaddr = pci_pool_alloc( + raid_dev->mbox_pool_handle, + GFP_KERNEL, + &mbox_pci_blk[i].dma_addr); + if (!mbox_pci_blk[i].vaddr) { + goto fail_setup_dma_pool; + } + } + + /* + * Allocate memory for each embedded passthru strucuture pointer + * Request for a 128 bytes aligned structure for each passthru command + * structure + * Since passthru and extended passthru commands are exclusive, they + * share common memory pool. Passthru structures piggyback on memory + * allocted to extended passthru since passthru is smaller of the two + */ + raid_dev->epthru_pool_handle = pci_pool_create("megaraid mbox pthru", + adapter->pdev, sizeof(mraid_epassthru_t), 128, 0); + + if (raid_dev->epthru_pool_handle == NULL) { + goto fail_setup_dma_pool; + } + + epthru_pci_blk = raid_dev->epthru_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + epthru_pci_blk[i].vaddr = pci_pool_alloc( + raid_dev->epthru_pool_handle, + GFP_KERNEL, + &epthru_pci_blk[i].dma_addr); + if (!epthru_pci_blk[i].vaddr) { + goto fail_setup_dma_pool; + } + } + + + // Allocate memory for each scatter-gather list. Request for 512 bytes + // alignment for each sg list + raid_dev->sg_pool_handle = pci_pool_create("megaraid mbox sg", + adapter->pdev, + sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE, + 512, 0); + + if (raid_dev->sg_pool_handle == NULL) { + goto fail_setup_dma_pool; + } + + sg_pci_blk = raid_dev->sg_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + sg_pci_blk[i].vaddr = pci_pool_alloc( + raid_dev->sg_pool_handle, + GFP_KERNEL, + &sg_pci_blk[i].dma_addr); + if (!sg_pci_blk[i].vaddr) { + goto fail_setup_dma_pool; + } + } + + return 0; + +fail_setup_dma_pool: + megaraid_mbox_teardown_dma_pools(adapter); + return -1; +} + + +/** + * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets + * @param adapter : HBA soft state + * + * teardown the dma pool for mailbox, passthru and extended passthru + * structures, and scatter-gather lists + */ +static void +megaraid_mbox_teardown_dma_pools(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + struct mraid_pci_blk *epthru_pci_blk; + struct mraid_pci_blk *sg_pci_blk; + struct mraid_pci_blk *mbox_pci_blk; + int i; + + + sg_pci_blk = raid_dev->sg_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) { + pci_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr, + sg_pci_blk[i].dma_addr); + } + if (raid_dev->sg_pool_handle) + pci_pool_destroy(raid_dev->sg_pool_handle); + + + epthru_pci_blk = raid_dev->epthru_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) { + pci_pool_free(raid_dev->epthru_pool_handle, + epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr); + } + if (raid_dev->epthru_pool_handle) + pci_pool_destroy(raid_dev->epthru_pool_handle); + + + mbox_pci_blk = raid_dev->mbox_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) { + pci_pool_free(raid_dev->mbox_pool_handle, + mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr); + } + if (raid_dev->mbox_pool_handle) + pci_pool_destroy(raid_dev->mbox_pool_handle); + + return; +} + + +/** + * megaraid_alloc_scb - detach and return a scb from the free list + * @adapter : controller's soft state + * + * return the scb from the head of the free list. NULL if there are none + * available + **/ +static inline scb_t * +megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp) +{ + struct list_head *head = &adapter->kscb_pool; + scb_t *scb = NULL; + unsigned long flags; + + // detach scb from free pool + spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); + + if (list_empty(head)) { + spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); + return NULL; + } + + scb = list_entry(head->next, scb_t, list); + list_del_init(&scb->list); + + spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); + + scb->state = SCB_ACTIVE; + scb->scp = scp; + scb->dma_type = MRAID_DMA_NONE; + + return scb; +} + + +/** + * megaraid_dealloc_scb - return the scb to the free pool + * @adapter : controller's soft state + * @scb : scb to be freed + * + * return the scb back to the free list of scbs. The caller must 'flush' the + * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc. + * NOTE NOTE: Make sure the scb is not on any list before calling this + * routine. + **/ +static inline void +megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb) +{ + unsigned long flags; + + // put scb in the free pool + scb->state = SCB_FREE; + scb->scp = NULL; + spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); + + list_add(&scb->list, &adapter->kscb_pool); + + spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); + + return; +} + + +/** + * megaraid_mbox_mksgl - make the scatter-gather list + * @adapter - controller's soft state + * @scb - scsi control block + * + * prepare the scatter-gather list + */ +static inline int +megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb) +{ + struct scatterlist *sgl; + mbox_ccb_t *ccb; + struct page *page; + unsigned long offset; + struct scsi_cmnd *scp; + int sgcnt; + int i; + + + scp = scb->scp; + ccb = (mbox_ccb_t *)scb->ccb; + + // no mapping required if no data to be transferred + if (!scp->request_buffer || !scp->request_bufflen) + return 0; + + if (!scp->use_sg) { /* scatter-gather list not used */ + + page = virt_to_page(scp->request_buffer); + + offset = ((unsigned long)scp->request_buffer & ~PAGE_MASK); + + ccb->buf_dma_h = pci_map_page(adapter->pdev, page, offset, + scp->request_bufflen, + scb->dma_direction); + scb->dma_type = MRAID_DMA_WBUF; + + /* + * We need to handle special 64-bit commands that need a + * minimum of 1 SG + */ + sgcnt = 1; + ccb->sgl64[0].address = ccb->buf_dma_h; + ccb->sgl64[0].length = scp->request_bufflen; + + return sgcnt; + } + + sgl = (struct scatterlist *)scp->request_buffer; + + // The number of sg elements returned must not exceed our limit + sgcnt = pci_map_sg(adapter->pdev, sgl, scp->use_sg, + scb->dma_direction); + + if (sgcnt > adapter->sglen) { + con_log(CL_ANN, (KERN_CRIT + "megaraid critical: too many sg elements:%d\n", + sgcnt)); + BUG(); + } + + scb->dma_type = MRAID_DMA_WSG; + + for (i = 0; i < sgcnt; i++, sgl++) { + ccb->sgl64[i].address = sg_dma_address(sgl); + ccb->sgl64[i].length = sg_dma_len(sgl); + } + + // Return count of SG nodes + return sgcnt; +} + + +/** + * mbox_post_cmd - issue a mailbox command + * @adapter - controller's soft state + * @scb - command to be issued + * + * post the command to the controller if mailbox is availble. + */ +static inline int +mbox_post_cmd(adapter_t *adapter, scb_t *scb) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox64_t *mbox64; + mbox_t *mbox; + mbox_ccb_t *ccb; + unsigned long flags; + unsigned int i = 0; + + + ccb = (mbox_ccb_t *)scb->ccb; + mbox = raid_dev->mbox; + mbox64 = raid_dev->mbox64; + + /* + * Check for busy mailbox. If it is, return failure - the caller + * should retry later. + */ + spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); + + if (unlikely(mbox->busy)) { + do { + udelay(1); + i++; + rmb(); + } while(mbox->busy && (i < max_mbox_busy_wait)); + + if (mbox->busy) { + + spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); + + return -1; + } + } + + + // Copy this command's mailbox data into "adapter's" mailbox + memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22); + mbox->cmdid = scb->sno; + + adapter->outstanding_cmds++; + + if (scb->dma_direction == PCI_DMA_TODEVICE) { + if (!scb->scp->use_sg) { // sg list not used + pci_dma_sync_single(adapter->pdev, ccb->buf_dma_h, + scb->scp->request_bufflen, + PCI_DMA_TODEVICE); + } + else { + pci_dma_sync_sg(adapter->pdev, scb->scp->request_buffer, + scb->scp->use_sg, PCI_DMA_TODEVICE); + } + } + + mbox->busy = 1; // Set busy + mbox->poll = 0; + mbox->ack = 0; + wmb(); + + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); + + spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); + + return 0; +} + + +/** + * megaraid_queue_command - generic queue entry point for all LLDs + * @scp : pointer to the scsi command to be executed + * @done : callback routine to be called after the cmd has be completed + * + * Queue entry point for mailbox based controllers. + */ +static int +megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *)) +{ + adapter_t *adapter; + scb_t *scb; + int if_busy; + + adapter = SCP2ADAPTER(scp); + scp->scsi_done = done; + scp->result = 0; + + ASSERT(spin_is_locked(adapter->host_lock)); + + spin_unlock(adapter->host_lock); + + /* + * Allocate and build a SCB request + * if_busy flag will be set if megaraid_mbox_build_cmd() command could + * not allocate scb. We will return non-zero status in that case. + * NOTE: scb can be null even though certain commands completed + * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would + * return 0 in that case, and we would do the callback right away. + */ + if_busy = 0; + scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy); + + if (scb) { + megaraid_mbox_runpendq(adapter, scb); + } + + spin_lock(adapter->host_lock); + + if (!scb) { // command already completed + done(scp); + } + + return if_busy; +} + + +/** + * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid + * firmware lingua + * @adapter - controller's soft state + * @scp - mid-layer scsi command pointer + * @busy - set if request could not be completed because of lack of + * resources + * + * convert the command issued by mid-layer to format understood by megaraid + * firmware. We also complete certain command without sending them to firmware + */ +static scb_t * +megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) +{ + mraid_device_t *rdev = ADAP2RAIDDEV(adapter); + int channel; + int target; + int islogical; + mbox_ccb_t *ccb; + mraid_passthru_t *pthru; + mbox64_t *mbox64; + mbox_t *mbox; + scb_t *scb; + char skip[] = "skipping"; + char scan[] = "scanning"; + char *ss; + + + /* + * Get the appropriate device map for the device this command is + * intended for + */ + MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical); + + /* + * Logical drive commands + */ + if (islogical) { + switch (scp->cmnd[0]) { + case TEST_UNIT_READY: + /* + * Do we support clustering and is the support enabled + * If no, return success always + */ + if (!adapter->ha) { + scp->result = (DID_OK << 16); + return NULL; + } + + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + scb->dma_direction = scp->sc_data_direction; + scb->dev_channel = 0xFF; + scb->dev_target = target; + ccb = (mbox_ccb_t *)scb->ccb; + + /* + * The command id will be provided by the command + * issuance routine + */ + ccb->raw_mbox[0] = CLUSTER_CMD; + ccb->raw_mbox[2] = RESERVATION_STATUS; + ccb->raw_mbox[3] = target; + + return scb; + + case MODE_SENSE: + if (scp->use_sg) { + struct scatterlist *sgl; + caddr_t vaddr; + + sgl = (struct scatterlist *)scp->request_buffer; + if (sgl->page) { + vaddr = (caddr_t) + (page_address((&sgl[0])->page) + + (&sgl[0])->offset); + + memset(vaddr, 0, scp->cmnd[4]); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: invalid sg:%d\n", + __LINE__)); + } + } + else { + memset(scp->request_buffer, 0, scp->cmnd[4]); + } + scp->result = (DID_OK << 16); + return NULL; + + case INQUIRY: + /* + * Display the channel scan for logical drives + * Do not display scan for a channel if already done. + */ + if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { + + con_log(CL_ANN, (KERN_INFO + "scsi[%d]: scanning scsi channel %d", + adapter->host->host_no, + SCP2CHANNEL(scp))); + + con_log(CL_ANN, ( + " [virtual] for logical drives\n")); + + rdev->last_disp |= (1L << SCP2CHANNEL(scp)); + } + + /* Fall through */ + + case READ_CAPACITY: + /* + * Do not allow LUN > 0 for logical drives and + * requests for more than 40 logical drives + */ + if (SCP2LUN(scp)) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + + /* Allocate a SCB and initialize passthru */ + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = 0xFF; + scb->dev_target = target; + pthru = ccb->pthru; + mbox = ccb->mbox; + mbox64 = ccb->mbox64; + + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; + pthru->islogical = 1; + pthru->logdrv = target; + pthru->cdblen = scp->cmd_len; + memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); + + mbox->cmd = MBOXCMD_PASSTHRU64; + scb->dma_direction = scp->sc_data_direction; + + pthru->dataxferlen = scp->request_bufflen; + pthru->dataxferaddr = ccb->sgl_dma_h; + pthru->numsge = megaraid_mbox_mksgl(adapter, + scb); + + mbox->xferaddr = 0xFFFFFFFF; + mbox64->xferaddr_lo = (uint32_t )ccb->pthru_dma_h; + mbox64->xferaddr_hi = 0; + + return scb; + + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + + /* + * Allocate a SCB and initialize mailbox + */ + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = 0xFF; + scb->dev_target = target; + mbox = ccb->mbox; + mbox64 = ccb->mbox64; + mbox->logdrv = target; + + /* + * A little HACK: 2nd bit is zero for all scsi read + * commands and is set for all scsi write commands + */ + mbox->cmd = (scp->cmnd[0] & 0x02) ? MBOXCMD_LWRITE64: + MBOXCMD_LREAD64 ; + + /* + * 6-byte READ(0x08) or WRITE(0x0A) cdb + */ + if (scp->cmd_len == 6) { + mbox->numsectors = (uint32_t)scp->cmnd[4]; + mbox->lba = + ((uint32_t)scp->cmnd[1] << 16) | + ((uint32_t)scp->cmnd[2] << 8) | + (uint32_t)scp->cmnd[3]; + + mbox->lba &= 0x1FFFFF; + } + + /* + * 10-byte READ(0x28) or WRITE(0x2A) cdb + */ + else if (scp->cmd_len == 10) { + mbox->numsectors = + (uint32_t)scp->cmnd[8] | + ((uint32_t)scp->cmnd[7] << 8); + mbox->lba = + ((uint32_t)scp->cmnd[2] << 24) | + ((uint32_t)scp->cmnd[3] << 16) | + ((uint32_t)scp->cmnd[4] << 8) | + (uint32_t)scp->cmnd[5]; + } + + /* + * 12-byte READ(0xA8) or WRITE(0xAA) cdb + */ + else if (scp->cmd_len == 12) { + mbox->lba = + ((uint32_t)scp->cmnd[2] << 24) | + ((uint32_t)scp->cmnd[3] << 16) | + ((uint32_t)scp->cmnd[4] << 8) | + (uint32_t)scp->cmnd[5]; + + mbox->numsectors = + ((uint32_t)scp->cmnd[6] << 24) | + ((uint32_t)scp->cmnd[7] << 16) | + ((uint32_t)scp->cmnd[8] << 8) | + (uint32_t)scp->cmnd[9]; + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid: unsupported CDB length\n")); + + megaraid_dealloc_scb(adapter, scb); + + scp->result = (DID_ERROR << 16); + return NULL; + } + + scb->dma_direction = scp->sc_data_direction; + + // Calculate Scatter-Gather info + mbox64->xferaddr_lo = (uint32_t )ccb->sgl_dma_h; + mbox->numsge = megaraid_mbox_mksgl(adapter, + scb); + mbox->xferaddr = 0xFFFFFFFF; + mbox64->xferaddr_hi = 0; + + return scb; + + case RESERVE: + case RELEASE: + /* + * Do we support clustering and is the support enabled + */ + if (!adapter->ha) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + /* + * Allocate a SCB and initialize mailbox + */ + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = 0xFF; + scb->dev_target = target; + ccb->raw_mbox[0] = CLUSTER_CMD; + ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? + RESERVE_LD : RELEASE_LD; + + ccb->raw_mbox[3] = target; + scb->dma_direction = scp->sc_data_direction; + + return scb; + + default: + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + } + else { // Passthru device commands + + // Do not allow access to target id > 15 or LUN > 7 + if (target > 15 || SCP2LUN(scp) > 7) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + // if fast load option was set and scan for last device is + // over, reset the fast_load flag so that during a possible + // next scan, devices can be made available + if (rdev->fast_load && (target == 15) && + (SCP2CHANNEL(scp) == adapter->max_channel -1)) { + + con_log(CL_ANN, (KERN_INFO + "megaraid[%d]: physical device scan re-enabled\n", + adapter->host->host_no)); + rdev->fast_load = 0; + } + + /* + * Display the channel scan for physical devices + */ + if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { + + ss = rdev->fast_load ? skip : scan; + + con_log(CL_ANN, (KERN_INFO + "scsi[%d]: %s scsi channel %d [Phy %d]", + adapter->host->host_no, ss, SCP2CHANNEL(scp), + channel)); + + con_log(CL_ANN, ( + " for non-raid devices\n")); + + rdev->last_disp |= (1L << SCP2CHANNEL(scp)); + } + + // disable channel sweep if fast load option given + if (rdev->fast_load) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + // Allocate a SCB and initialize passthru + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = channel; + scb->dev_target = target; + scb->dma_direction = scp->sc_data_direction; + mbox = ccb->mbox; + mbox64 = ccb->mbox64; + + // Does this firmware support extended CDBs + if (adapter->max_cdb_sz == 16) { + mbox->cmd = MBOXCMD_EXTPTHRU; + + megaraid_mbox_prepare_epthru(adapter, scb, scp); + + mbox64->xferaddr_lo = (uint32_t)ccb->epthru_dma_h; + mbox64->xferaddr_hi = 0; + mbox->xferaddr = 0xFFFFFFFF; + } + else { + mbox->cmd = MBOXCMD_PASSTHRU64; + + megaraid_mbox_prepare_pthru(adapter, scb, scp); + + mbox64->xferaddr_lo = (uint32_t)ccb->pthru_dma_h; + mbox64->xferaddr_hi = 0; + mbox->xferaddr = 0xFFFFFFFF; + } + return scb; + } + + // NOT REACHED +} + + +/** + * megaraid_mbox_runpendq - execute commands queued in the pending queue + * @adapter : controller's soft state + * @scb : SCB to be queued in the pending list + * + * scan the pending list for commands which are not yet issued and try to + * post to the controller. The SCB can be a null pointer, which would indicate + * no SCB to be queue, just try to execute the ones in the pending list. + * + * NOTE: We do not actually traverse the pending list. The SCBs are plucked + * out from the head of the pending list. If it is successfully issued, the + * next SCB is at the head now. + */ +static void +megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q) +{ + scb_t *scb; + unsigned long flags; + + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + + if (scb_q) { + scb_q->state = SCB_PENDQ; + list_add_tail(&scb_q->list, &adapter->pend_list); + } + + // if the adapter in not in quiescent mode, post the commands to FW + if (adapter->quiescent) { + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + return; + } + + while (!list_empty(&adapter->pend_list)) { + + ASSERT(spin_is_locked(PENDING_LIST_LOCK(adapter))); + + scb = list_entry(adapter->pend_list.next, scb_t, list); + + // remove the scb from the pending list and try to + // issue. If we are unable to issue it, put back in + // the pending list and return + + list_del_init(&scb->list); + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + // if mailbox was busy, return SCB back to pending + // list. Make sure to add at the head, since that's + // where it would have been removed from + + scb->state = SCB_ISSUED; + + if (mbox_post_cmd(adapter, scb) != 0) { + + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + + scb->state = SCB_PENDQ; + + list_add(&scb->list, &adapter->pend_list); + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), + flags); + + return; + } + + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + } + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + + return; +} + + +/** + * megaraid_mbox_prepare_pthru - prepare a command for physical devices + * @adapter - pointer to controller's soft state + * @scb - scsi control block + * @scp - scsi command from the mid-layer + * + * prepare a command for the scsi physical devices + */ +static void +megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb, + struct scsi_cmnd *scp) +{ + mbox_ccb_t *ccb; + mraid_passthru_t *pthru; + uint8_t channel; + uint8_t target; + + ccb = (mbox_ccb_t *)scb->ccb; + pthru = ccb->pthru; + channel = scb->dev_channel; + target = scb->dev_target; + + pthru->timeout = 1; // 0=6sec, 1=60sec, 2=10min, 3=3hrs + pthru->ars = 1; + pthru->islogical = 0; + pthru->channel = 0; + pthru->target = (channel << 4) | target; + pthru->logdrv = SCP2LUN(scp); + pthru->reqsenselen = 14; + pthru->cdblen = scp->cmd_len; + + memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); + + if (scp->request_bufflen) { + pthru->dataxferlen = scp->request_bufflen; + pthru->dataxferaddr = ccb->sgl_dma_h; + pthru->numsge = megaraid_mbox_mksgl(adapter, scb); + } + else { + pthru->dataxferaddr = 0; + pthru->dataxferlen = 0; + pthru->numsge = 0; + } + return; +} + + +/** + * megaraid_mbox_prepare_epthru - prepare a command for physical devices + * @adapter - pointer to controller's soft state + * @scb - scsi control block + * @scp - scsi command from the mid-layer + * + * prepare a command for the scsi physical devices. This rountine prepares + * commands for devices which can take extended CDBs (>10 bytes) + */ +static void +megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb, + struct scsi_cmnd *scp) +{ + mbox_ccb_t *ccb; + mraid_epassthru_t *epthru; + uint8_t channel; + uint8_t target; + + ccb = (mbox_ccb_t *)scb->ccb; + epthru = ccb->epthru; + channel = scb->dev_channel; + target = scb->dev_target; + + epthru->timeout = 1; // 0=6sec, 1=60sec, 2=10min, 3=3hrs + epthru->ars = 1; + epthru->islogical = 0; + epthru->channel = 0; + epthru->target = (channel << 4) | target; + epthru->logdrv = SCP2LUN(scp); + epthru->reqsenselen = 14; + epthru->cdblen = scp->cmd_len; + + memcpy(epthru->cdb, scp->cmnd, scp->cmd_len); + + if (scp->request_bufflen) { + epthru->dataxferlen = scp->request_bufflen; + epthru->dataxferaddr = ccb->sgl_dma_h; + epthru->numsge = megaraid_mbox_mksgl(adapter, scb); + } + else { + epthru->dataxferaddr = 0; + epthru->dataxferlen = 0; + epthru->numsge = 0; + } + return; +} + + +/** + * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs + * @adapter - controller's soft state + * + * Interrupt ackrowledgement sequence for memory mapped HBAs. Find out the + * completed command and put them on the completed list for later processing. + * + * Returns: 1 if the interrupt is valid, 0 otherwise + */ +static inline int +megaraid_ack_sequence(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + scb_t *scb; + uint8_t nstatus; + uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; + struct list_head clist; + int handled; + uint32_t dword; + unsigned long flags; + int i, j; + + + mbox = raid_dev->mbox; + + // move the SCBs from the firmware completed array to our local list + INIT_LIST_HEAD(&clist); + + // loop till F/W has more commands for us to complete + handled = 0; + spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); + do { + /* + * Check if a valid interrupt is pending. If found, force the + * interrupt line low. + */ + dword = RDOUTDOOR(raid_dev); + if (dword != 0x10001234) break; + + handled = 1; + + WROUTDOOR(raid_dev, 0x10001234); + + nstatus = 0; + // wait for valid numstatus to post + for (i = 0; i < 0xFFFFF; i++) { + if (mbox->numstatus != 0xFF) { + nstatus = mbox->numstatus; + break; + } + rmb(); + } + mbox->numstatus = 0xFF; + + adapter->outstanding_cmds -= nstatus; + + for (i = 0; i < nstatus; i++) { + + // wait for valid command index to post + for (j = 0; j < 0xFFFFF; j++) { + if (mbox->completed[i] != 0xFF) break; + rmb(); + } + completed[i] = mbox->completed[i]; + mbox->completed[i] = 0xFF; + + if (completed[i] == 0xFF) { + con_log(CL_ANN, (KERN_CRIT + "megaraid: command posting timed out\n")); + + BUG(); + continue; + } + + // Get SCB associated with this command id + if (completed[i] >= MBOX_MAX_SCSI_CMDS) { + // a cmm command + scb = adapter->uscb_list + (completed[i] - + MBOX_MAX_SCSI_CMDS); + } + else { + // an os command + scb = adapter->kscb_list + completed[i]; + } + + scb->status = mbox->status; + list_add_tail(&scb->list, &clist); + } + + // Acknowledge interrupt + WRINDOOR(raid_dev, 0x02); + + } while(1); + + spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); + + + // put the completed commands in the completed list. DPC would + // complete these commands later + spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); + + list_splice(&clist, &adapter->completed_list); + + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); + + + // schedule the DPC if there is some work for it + if (handled) + tasklet_schedule(&adapter->dpc_h); + + return handled; +} + + +/** + * megaraid_isr - isr for memory based mailbox based controllers + * @irq - irq + * @devp - pointer to our soft state + * @regs - unused + * + * Interrupt service routine for memory-mapped mailbox controllers. + */ +static irqreturn_t +megaraid_isr(int irq, void *devp, struct pt_regs *regs) +{ + adapter_t *adapter = devp; + int handled; + + handled = megaraid_ack_sequence(adapter); + + /* Loop through any pending requests */ + if (!adapter->quiescent) { + megaraid_mbox_runpendq(adapter, NULL); + } + + return IRQ_RETVAL(handled); +} + + +/** + * megaraid_mbox_sync_scb - sync kernel buffers + * @adapter : controller's soft state + * @scb : pointer to the resource packet + * + * DMA sync if required. + */ +static inline void +megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb) +{ + mbox_ccb_t *ccb; + + ccb = (mbox_ccb_t *)scb->ccb; + + switch (scb->dma_type) { + + case MRAID_DMA_WBUF: + if (scb->dma_direction == PCI_DMA_FROMDEVICE) { + pci_dma_sync_single(adapter->pdev, + ccb->buf_dma_h, + scb->scp->request_bufflen, + PCI_DMA_FROMDEVICE); + } + + pci_unmap_page(adapter->pdev, ccb->buf_dma_h, + scb->scp->request_bufflen, scb->dma_direction); + + break; + + case MRAID_DMA_WSG: + if (scb->dma_direction == PCI_DMA_FROMDEVICE) { + pci_dma_sync_sg(adapter->pdev, + scb->scp->request_buffer, + scb->scp->use_sg, PCI_DMA_FROMDEVICE); + } + + pci_unmap_sg(adapter->pdev, scb->scp->request_buffer, + scb->scp->use_sg, scb->dma_direction); + + break; + + default: + break; + } + + return; +} + + +/** + * megaraid_mbox_dpc - the tasklet to complete the commands from completed list + * @devp : pointer to HBA soft state + * + * Pick up the commands from the completed list and send back to the owners. + * This is a reentrant function and does not assume any locks are held while + * it is being called. + */ +static void +megaraid_mbox_dpc(unsigned long devp) +{ + adapter_t *adapter = (adapter_t *)devp; + mraid_device_t *raid_dev; + struct list_head clist; + struct scatterlist *sgl; + scb_t *scb; + scb_t *tmp; + struct scsi_cmnd *scp; + mraid_passthru_t *pthru; + mraid_epassthru_t *epthru; + mbox_ccb_t *ccb; + int islogical; + int pdev_index; + int pdev_state; + mbox_t *mbox; + unsigned long flags; + uint8_t c; + int status; + + + if (!adapter) return; + + raid_dev = ADAP2RAIDDEV(adapter); + + // move the SCBs from the completed list to our local list + INIT_LIST_HEAD(&clist); + + spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); + + list_splice_init(&adapter->completed_list, &clist); + + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); + + + list_for_each_entry_safe(scb, tmp, &clist, list) { + + status = scb->status; + scp = scb->scp; + ccb = (mbox_ccb_t *)scb->ccb; + pthru = ccb->pthru; + epthru = ccb->epthru; + mbox = ccb->mbox; + + // Make sure f/w has completed a valid command + if (scb->state != SCB_ISSUED) { + con_log(CL_ANN, (KERN_CRIT + "megaraid critical err: invalid command %d:%d:%p\n", + scb->sno, scb->state, scp)); + BUG(); + continue; // Must never happen! + } + + // check for the management command and complete it right away + if (scb->sno >= MBOX_MAX_SCSI_CMDS) { + scb->state = SCB_FREE; + scb->status = status; + + // remove from local clist + list_del_init(&scb->list); + + megaraid_mbox_mm_done(adapter, scb); + + continue; + } + + // Was an abort issued for this command earlier + if (scb->state & SCB_ABORT) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: aborted cmd %lx[%x] completed\n", + scp->serial_number, scb->sno)); + } + + /* + * If the inquiry came of a disk drive which is not part of + * any RAID array, expose it to the kernel. For this to be + * enabled, user must set the "megaraid_expose_unconf_disks" + * flag to 1 by specifying it on module parameter list. + * This would enable data migration off drives from other + * configurations. + */ + islogical = MRAID_IS_LOGICAL(adapter, scp); + if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0 + && IS_RAID_CH(raid_dev, scb->dev_channel)) { + + if (scp->use_sg) { + sgl = (struct scatterlist *) + scp->request_buffer; + + if (sgl->page) { + c = *(unsigned char *) + (page_address((&sgl[0])->page) + + (&sgl[0])->offset); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: invalid sg:%d\n", + __LINE__)); + c = 0; + } + } + else { + c = *(uint8_t *)scp->request_buffer; + } + + if ((c & 0x1F ) == TYPE_DISK) { + pdev_index = (scb->dev_channel * 16) + + scb->dev_target; + pdev_state = + raid_dev->pdrv_state[pdev_index] & 0x0F; + + if (pdev_state == PDRV_ONLINE || + pdev_state == PDRV_FAILED || + pdev_state == PDRV_RBLD || + pdev_state == PDRV_HOTSPARE || + megaraid_expose_unconf_disks == 0) { + + status = 0xF0; + } + } + } + + // Convert MegaRAID status to Linux error code + switch (status) { + + case 0x00: + + scp->result = (DID_OK << 16); + break; + + case 0x02: + + /* set sense_buffer and result fields */ + if (mbox->cmd == MBOXCMD_PASSTHRU || + mbox->cmd == MBOXCMD_PASSTHRU64) { + + memcpy(scp->sense_buffer, pthru->reqsensearea, + 14); + + scp->result = DRIVER_SENSE << 24 | + DID_OK << 16 | CHECK_CONDITION << 1; + } + else { + if (mbox->cmd == MBOXCMD_EXTPTHRU) { + + memcpy(scp->sense_buffer, + epthru->reqsensearea, 14); + + scp->result = DRIVER_SENSE << 24 | + DID_OK << 16 | + CHECK_CONDITION << 1; + } else { + scp->sense_buffer[0] = 0x70; + scp->sense_buffer[2] = ABORTED_COMMAND; + scp->result = CHECK_CONDITION << 1; + } + } + break; + + case 0x08: + + scp->result = DID_BUS_BUSY << 16 | status; + break; + + default: + + /* + * If TEST_UNIT_READY fails, we know RESERVATION_STATUS + * failed + */ + if (scp->cmnd[0] == TEST_UNIT_READY) { + scp->result = DID_ERROR << 16 | + RESERVATION_CONFLICT << 1; + } + else + /* + * Error code returned is 1 if Reserve or Release + * failed or the input parameter is invalid + */ + if (status == 1 && (scp->cmnd[0] == RESERVE || + scp->cmnd[0] == RELEASE)) { + + scp->result = DID_ERROR << 16 | + RESERVATION_CONFLICT << 1; + } + else { + scp->result = DID_BAD_TARGET << 16 | status; + } + } + + // print a debug message for all failed commands + if (status) { + megaraid_mbox_display_scb(adapter, scb); + } + + // Free our internal resources and call the mid-layer callback + // routine + megaraid_mbox_sync_scb(adapter, scb); + + // remove from local clist + list_del_init(&scb->list); + + // put back in free list + megaraid_dealloc_scb(adapter, scb); + + // send the scsi packet back to kernel + spin_lock(adapter->host_lock); + scp->scsi_done(scp); + spin_unlock(adapter->host_lock); + } + + return; +} + + +/** + * megaraid_abort_handler - abort the scsi command + * @scp : command to be aborted + * + * Abort a previous SCSI request. Only commands on the pending list can be + * aborted. All the commands issued to the F/W must complete. + **/ +static int +megaraid_abort_handler(struct scsi_cmnd *scp) +{ + adapter_t *adapter; + mraid_device_t *raid_dev; + scb_t *scb; + scb_t *tmp; + int found; + unsigned long flags; + int i; + + + adapter = SCP2ADAPTER(scp); + raid_dev = ADAP2RAIDDEV(adapter); + + ASSERT(spin_is_locked(adapter->host_lock)); + + con_log(CL_ANN, (KERN_WARNING + "megaraid: aborting-%ld cmd=%x \n", + scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp), + SCP2TARGET(scp), SCP2LUN(scp))); + + // If FW has stopped responding, simply return failure + if (raid_dev->hw_error) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: hw error, not aborting\n")); + return FAILED; + } + + // There might a race here, where the command was completed by the + // firmware and now it is on the completed list. Before we could + // complete the command to the kernel in dpc, the abort came. + // Find out if this is the case to avoid the race. + scb = NULL; + spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); + list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) { + + if (scb->scp == scp) { // Found command + + list_del_init(&scb->list); // from completed list + + con_log(CL_ANN, (KERN_WARNING + "megaraid: %ld:%d[%d:%d], abort from completed list\n", + scp->serial_number, scb->sno, + scb->dev_channel, scb->dev_target)); + + scp->result = (DID_ABORT << 16); + scp->scsi_done(scp); + + megaraid_dealloc_scb(adapter, scb); + + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), + flags); + + return SUCCESS; + } + } + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); + + + // Find out if this command is still on the pending list. If it is and + // was never issued, abort and return success. If the command is owned + // by the firmware, we must wait for it to complete by the FW. + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { + + if (scb->scp == scp) { // Found command + + list_del_init(&scb->list); // from pending list + + ASSERT(!(scb->state & SCB_ISSUED)); + + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: %ld[%d:%d], driver owner\n", + scp->serial_number, scb->dev_channel, + scb->dev_target)); + + scp->result = (DID_ABORT << 16); + scp->scsi_done(scp); + + megaraid_dealloc_scb(adapter, scb); + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), + flags); + + return SUCCESS; + } + } + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + + // Check do we even own this command, in which case this would be + // owned by the firmware. The only way to locate the FW scb is to + // traverse through the list of all SCB, since driver does not + // maintain these SCBs on any list + found = 0; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + scb = adapter->kscb_list + i; + + if (scb->scp == scp) { + + found = 1; + + if (!(scb->state & SCB_ISSUED)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: %ld%d[%d:%d], invalid state\n", + scp->serial_number, scb->sno, scb->dev_channel, + scb->dev_target)); + BUG(); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: %ld:%d[%d:%d], fw owner\n", + scp->serial_number, scb->sno, scb->dev_channel, + scb->dev_target)); + } + } + } + + if (!found) { + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: scsi cmd:%ld, do now own\n", + scp->serial_number)); + + // FIXME: Should there be a callback for this command? + return SUCCESS; + } + + // We cannot actually abort a command owned by firmware, return + // failure and wait for reset. In host reset handler, we will find out + // if the HBA is still live + return FAILED; +} + + +/** + * megaraid_reset_handler - device reset hadler for mailbox based driver + * @scp : reference command + * + * Reset handler for the mailbox based controller. First try to find out if + * the FW is still live, in which case the outstanding commands counter mut go + * down to 0. If that happens, also issue the reservation reset command to + * relinquish (possible) reservations on the logical drives connected to this + * host + **/ +static int +megaraid_reset_handler(struct scsi_cmnd *scp) +{ + adapter_t *adapter; + scb_t *scb; + scb_t *tmp; + mraid_device_t *raid_dev; + unsigned long flags; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + int recovery_window; + int recovering; + int i; + + adapter = SCP2ADAPTER(scp); + raid_dev = ADAP2RAIDDEV(adapter); + + ASSERT(spin_is_locked(adapter->host_lock)); + + con_log(CL_ANN, (KERN_WARNING "megaraid: reseting the host...\n")); + + // return failure if adapter is not responding + if (raid_dev->hw_error) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: hw error, cannot reset\n")); + return FAILED; + } + + + // Under exceptional conditions, FW can take up to 3 minutes to + // complete command processing. Wait for additional 2 minutes for the + // pending commands counter to go down to 0. If it doesn't, let the + // controller be marked offline + // Also, reset all the commands currently owned by the driver + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { + + list_del_init(&scb->list); // from pending list + + con_log(CL_ANN, (KERN_WARNING + "megaraid: %ld:%d[%d:%d], reset from pending list\n", + scp->serial_number, scb->sno, + scb->dev_channel, scb->dev_target)); + + scp->result = (DID_RESET << 16); + scp->scsi_done(scp); + + megaraid_dealloc_scb(adapter, scb); + } + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + if (adapter->outstanding_cmds) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: %d outstanding commands. Max wait %d sec\n", + adapter->outstanding_cmds, MBOX_RESET_WAIT)); + } + + spin_unlock(adapter->host_lock); + + recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; + + recovering = adapter->outstanding_cmds; + + for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) { + + megaraid_ack_sequence(adapter); + + // print a message once every 5 seconds only + if (!(i % 5)) { + con_log(CL_ANN, ( + "megaraid mbox: Wait for %d commands to complete:%d\n", + adapter->outstanding_cmds, + MBOX_RESET_WAIT - i)); + } + + // bailout if no recovery happended in reset time + if ((i == MBOX_RESET_WAIT) && + (recovering == adapter->outstanding_cmds)) { + break; + } + + msleep(1000); + } + + spin_lock(adapter->host_lock); + + // If still outstanding commands, bail out + if (adapter->outstanding_cmds) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: critical hardware error!\n")); + + raid_dev->hw_error = 1; + + return FAILED; + } + else { + con_log(CL_ANN, (KERN_NOTICE + "megaraid mbox: reset sequence completed sucessfully\n")); + } + + + // If the controller supports clustering, reset reservations + if (!adapter->ha) return SUCCESS; + + // clear reservations if any + raw_mbox[0] = CLUSTER_CMD; + raw_mbox[2] = RESET_RESERVATIONS; + + rval = SUCCESS; + if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) { + con_log(CL_ANN, + (KERN_INFO "megaraid: reservation reset\n")); + } + else { + rval = FAILED; + con_log(CL_ANN, (KERN_WARNING + "megaraid: reservation reset failed\n")); + } + + return rval; +} + + +/* + * START: internal commands library + * + * This section of the driver has the common routine used by the driver and + * also has all the FW routines + */ + +/** + * mbox_post_sync_cmd() - blocking command to the mailbox based controllers + * @adapter - controller's soft state + * @raw_mbox - the mailbox + * + * Issue a scb in synchronous and non-interrupt mode for mailbox based + * controllers + */ +static int +mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[]) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox64_t *mbox64; + mbox_t *mbox; + uint8_t status; + int i; + + + mbox64 = raid_dev->mbox64; + mbox = raid_dev->mbox; + + /* + * Wait until mailbox is free + */ + if (megaraid_busywait_mbox(raid_dev) != 0) + goto blocked_mailbox; + + /* + * Copy mailbox data into host structure + */ + memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); + mbox->cmdid = 0xFE; + mbox->busy = 1; + mbox->poll = 0; + mbox->ack = 0; + mbox->numstatus = 0xFF; + mbox->status = 0xFF; + + wmb(); + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); + + // wait for maximum 1 second for status to post. If the status is not + // available within 1 second, assume FW is initializing and wait + // for an extended amount of time + if (mbox->numstatus == 0xFF) { // status not yet available + udelay(25);; + + for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) { + rmb(); + msleep(1); + } + + + if (i == 1000) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid mailbox: wait for FW to boot ")); + + for (i = 0; (mbox->numstatus == 0xFF) && + (i < MBOX_RESET_WAIT); i++) { + rmb(); + con_log(CL_ANN, ("\b\b\b\b\b[%03d]", + MBOX_RESET_WAIT - i)); + msleep(1000); + } + + if (i == MBOX_RESET_WAIT) { + + con_log(CL_ANN, ( + "\nmegaraid mailbox: status not available\n")); + + return -1; + } + con_log(CL_ANN, ("\b\b\b\b\b[ok] \n")); + } + } + + // wait for maximum 1 second for poll semaphore + if (mbox->poll != 0x77) { + udelay(25); + + for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) { + rmb(); + msleep(1); + } + + if (i == 1000) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: could not get poll semaphore\n")); + return -1; + } + } + + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); + wmb(); + + // wait for maximum 1 second for acknowledgement + if (RDINDOOR(raid_dev) & 0x2) { + udelay(25); + + for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) { + rmb(); + msleep(1); + } + + if (i == 1000) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: could not acknowledge\n")); + return -1; + } + } + mbox->poll = 0; + mbox->ack = 0x77; + + status = mbox->status; + + // invalidate the completed command id array. After command + // completion, firmware would write the valid id. + mbox->numstatus = 0xFF; + mbox->status = 0xFF; + for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) { + mbox->completed[i] = 0xFF; + } + + return status; + +blocked_mailbox: + + con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") ); + return -1; +} + + +/** + * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers + * @adapter - controller's soft state + * @raw_mbox - the mailbox + * + * Issue a scb in synchronous and non-interrupt mode for mailbox based + * controllers. This is a faster version of the synchronous command and + * therefore can be called in interrupt-context as well + */ +static int +mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + long i; + + + mbox = raid_dev->mbox; + + // return immediately if the mailbox is busy + if (mbox->busy) return -1; + + // Copy mailbox data into host structure + memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14); + mbox->cmdid = 0xFE; + mbox->busy = 1; + mbox->poll = 0; + mbox->ack = 0; + mbox->numstatus = 0xFF; + mbox->status = 0xFF; + + wmb(); + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); + + for (i = 0; i < 0xFFFFF; i++) { + if (mbox->numstatus != 0xFF) break; + } + + if (i == 0xFFFFF) { + // We may need to re-calibrate the counter + con_log(CL_ANN, (KERN_CRIT + "megaraid: fast sync command timed out\n")); + } + + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); + wmb(); + + return mbox->status; +} + + +/** + * megaraid_busywait_mbox() - Wait until the controller's mailbox is available + * @raid_dev - RAID device (HBA) soft state + * + * wait until the controller's mailbox is available to accept more commands. + * wait for at most 1 second + */ +static int +megaraid_busywait_mbox(mraid_device_t *raid_dev) +{ + mbox_t *mbox = raid_dev->mbox; + int i = 0; + + if (mbox->busy) { + udelay(25); + for (i = 0; mbox->busy && i < 1000; i++) + msleep(1); + } + + if (i < 1000) return 0; + else return -1; +} + + +/** + * megaraid_mbox_product_info - some static information about the controller + * @adapter - our soft state + * + * issue commands to the controller to grab some parameters required by our + * caller. + */ +static int +megaraid_mbox_product_info(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + mraid_pinfo_t *pinfo; + dma_addr_t pinfo_dma_h; + mraid_inquiry3_t *mraid_inq3; + int i; + + + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + mbox = (mbox_t *)raw_mbox; + + /* + * Issue an ENQUIRY3 command to find out certain adapter parameters, + * e.g., max channels, max commands etc. + */ + pinfo = pci_alloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + &pinfo_dma_h); + + if (pinfo == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + + return -1; + } + memset(pinfo, 0, sizeof(mraid_pinfo_t)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = FC_NEW_CONFIG; + raw_mbox[2] = NC_SUBOP_ENQUIRY3; + raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; + + // Issue the command + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + + con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n")); + + pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + pinfo, pinfo_dma_h); + + return -1; + } + + /* + * Collect information about state of each physical drive + * attached to the controller. We will expose all the disks + * which are not part of RAID + */ + mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf; + for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) { + raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i]; + } + + /* + * Get product info for information like number of channels, + * maximum commands supported. + */ + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + mbox->xferaddr = (uint32_t)pinfo_dma_h; + + raw_mbox[0] = FC_NEW_CONFIG; + raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; + + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: product info failed\n")); + + pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + pinfo, pinfo_dma_h); + + return -1; + } + + /* + * Setup some parameters for host, as required by our caller + */ + adapter->max_channel = pinfo->nchannels; + + /* + * we will export all the logical drives on a single channel. + * Add 1 since inquires do not come for inititor ID + */ + adapter->max_target = MAX_LOGICAL_DRIVES_40LD + 1; + adapter->max_lun = 8; // up to 8 LUNs for non-disk devices + + /* + * These are the maximum outstanding commands for the scsi-layer + */ + adapter->max_cmds = MBOX_MAX_SCSI_CMDS; + + memset(adapter->fw_version, 0, VERSION_SIZE); + memset(adapter->bios_version, 0, VERSION_SIZE); + + memcpy(adapter->fw_version, pinfo->fw_version, 4); + adapter->fw_version[4] = 0; + + memcpy(adapter->bios_version, pinfo->bios_version, 4); + adapter->bios_version[4] = 0; + + con_log(CL_ANN, (KERN_NOTICE + "megaraid: fw version:[%s] bios version:[%s]\n", + adapter->fw_version, adapter->bios_version)); + + pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo, + pinfo_dma_h); + + return 0; +} + + + +/** + * megaraid_mbox_extended_cdb - check for support for extended CDBs + * @adapter - soft state for the controller + * + * this routine check whether the controller in question supports extended + * ( > 10 bytes ) CDBs + */ +static int +megaraid_mbox_extended_cdb(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = MAIN_MISC_OPCODE; + raw_mbox[2] = SUPPORT_EXT_CDB; + + /* + * Issue the command + */ + rval = 0; + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + rval = -1; + } + + return rval; +} + + +/** + * megaraid_mbox_support_ha - Do we support clustering + * @adapter - soft state for the controller + * @init_id - ID of the initiator + * + * Determine if the firmware supports clustering and the ID of the initiator. + */ +static int +megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = GET_TARGET_ID; + + // Issue the command + *init_id = 7; + rval = -1; + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + + *init_id = *(uint8_t *)adapter->ibuf; + + con_log(CL_ANN, (KERN_INFO + "megaraid: cluster firmware, initiator ID: %d\n", + *init_id)); + + rval = 0; + } + + return rval; +} + + +/** + * megaraid_mbox_support_random_del - Do we support random deletion + * @adapter - soft state for the controller + * + * Determine if the firmware supports random deletion + * Return: 1 is operation supported, 0 otherwise + */ +static int +megaraid_mbox_support_random_del(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + raw_mbox[0] = FC_DEL_LOGDRV; + raw_mbox[0] = OP_SUP_DEL_LOGDRV; + + // Issue the command + rval = 0; + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + + con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n")); + + rval = 1; + } + + return rval; +} + + +/** + * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware + * @adapter - soft state for the controller + * + * Find out the maximum number of scatter-gather elements supported by the + * firmware + */ +static int +megaraid_mbox_get_max_sg(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int nsg; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = MAIN_MISC_OPCODE; + raw_mbox[2] = GET_MAX_SG_SUPPORT; + + // Issue the command + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + nsg = *(uint8_t *)adapter->ibuf; + } + else { + nsg = MBOX_DEFAULT_SG_SIZE; + } + + if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE; + + return nsg; +} + + +/** + * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels + * @adapter - soft state for the controller + * + * Enumerate the RAID and SCSI channels for ROMB platoforms so that channels + * can be exported as regular SCSI channels + */ +static void +megaraid_mbox_enum_raid_scsi(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = CHNL_CLASS; + raw_mbox[2] = GET_CHNL_CLASS; + + // Issue the command. If the command fails, all channels are RAID + // channels + raid_dev->channel_class = 0xFF; + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + raid_dev->channel_class = *(uint8_t *)adapter->ibuf; + } + + return; +} + + +/** + * megaraid_mbox_flush_cache - flush adapter and disks cache + * @param adapter : soft state for the controller + * + * Flush adapter cache followed by disks cache + */ +static void +megaraid_mbox_flush_cache(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + raw_mbox[0] = FLUSH_ADAPTER; + + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + con_log(CL_ANN, ("megaraid: flush adapter failed\n")); + } + + raw_mbox[0] = FLUSH_SYSTEM; + + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + con_log(CL_ANN, ("megaraid: flush disks cache failed\n")); + } + + return; +} + + +/** + * megaraid_mbox_display_scb - display SCB information, mostly debug purposes + * @param adapter : controllers' soft state + * @param scb : SCB to be displayed + * @param level : debug level for console print + * + * Diplay information about the given SCB iff the current debug level is + * verbose + */ +static void +megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb) +{ + mbox_ccb_t *ccb; + struct scsi_cmnd *scp; + mbox_t *mbox; + int level; + int i; + + + ccb = (mbox_ccb_t *)scb->ccb; + scp = scb->scp; + mbox = ccb->mbox; + + level = CL_DLEVEL3; + + con_log(level, (KERN_NOTICE + "megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status, + mbox->cmd, scb->sno)); + + con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n", + mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, + mbox->numsge)); + + if (!scp) return; + + con_log(level, (KERN_NOTICE "scsi cmnd: ")); + + for (i = 0; i < scp->cmd_len; i++) { + con_log(level, ("%#2.02x ", scp->cmnd[i])); + } + + con_log(level, ("\n")); + + return; +} + + +/** + * megaraid_mbox_setup_device_map - manage device ids + * @adapter : Driver's soft state + * + * Manange the device ids to have an appropraite mapping between the kernel + * scsi addresses and megaraid scsi and logical drive addresses. We export + * scsi devices on their actual addresses, whereas the logical drives are + * exported on a virtual scsi channel. + **/ +static void +megaraid_mbox_setup_device_map(adapter_t *adapter) +{ + uint8_t c; + uint8_t t; + + /* + * First fill the values on the logical drive channel + */ + for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) + adapter->device_ids[adapter->max_channel][t] = + (t < adapter->init_id) ? t : t - 1; + + adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF; + + /* + * Fill the values on the physical devices channels + */ + for (c = 0; c < adapter->max_channel; c++) + for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) + adapter->device_ids[c][t] = (c << 8) | t; +} + + +/* + * END: internal commands library + */ + +/* + * START: Interface for the common management module + * + * This is the module, which interfaces with the common mangement module to + * provide support for ioctl and sysfs + */ + +/** + * megaraid_cmm_register - register with the mangement module + * @param adapter : HBA soft state + * + * Register with the management module, which allows applications to issue + * ioctl calls to the drivers. This interface is used by the management module + * to setup sysfs support as well. + */ +static int +megaraid_cmm_register(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mraid_mmadp_t adp; + scb_t *scb; + mbox_ccb_t *ccb; + int rval; + int i; + + // Allocate memory for the base list of scb for management module. + adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS, + GFP_KERNEL); + + if (adapter->uscb_list == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + return -1; + } + memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS); + + + // Initialize the synchronization parameters for resources for + // commands for management module + INIT_LIST_HEAD(&adapter->uscb_pool); + + spin_lock_init(USER_FREE_LIST_LOCK(adapter)); + + + + // link all the packets. Note, CCB for commands, coming from the + // commom management module, mailbox physical address are already + // setup by it. We just need placeholder for that in our local command + // control blocks + for (i = 0; i < MBOX_MAX_USER_CMDS; i++) { + + scb = adapter->uscb_list + i; + ccb = raid_dev->uccb_list + i; + + scb->ccb = (caddr_t)ccb; + ccb->mbox64 = raid_dev->umbox64 + i; + ccb->mbox = &ccb->mbox64->mbox32; + ccb->raw_mbox = (uint8_t *)ccb->mbox; + + scb->gp = 0; + + // COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR + // COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER) + scb->sno = i + MBOX_MAX_SCSI_CMDS; + + scb->scp = NULL; + scb->state = SCB_FREE; + scb->dma_direction = PCI_DMA_NONE; + scb->dma_type = MRAID_DMA_NONE; + scb->dev_channel = -1; + scb->dev_target = -1; + + // put scb in the free pool + list_add_tail(&scb->list, &adapter->uscb_pool); + } + + adp.unique_id = adapter->unique_id; + adp.drvr_type = DRVRTYPE_MBOX; + adp.drvr_data = (unsigned long)adapter; + adp.pdev = adapter->pdev; + adp.issue_uioc = megaraid_mbox_mm_handler; + adp.timeout = 30; + adp.max_kioc = MBOX_MAX_USER_CMDS; + + if ((rval = mraid_mm_register_adp(&adp)) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: did not register with CMM\n")); + + kfree(adapter->uscb_list); + } + + return rval; +} + + +/** + * megaraid_cmm_unregister - un-register with the mangement module + * @param adapter : HBA soft state + * + * Un-register with the management module. + * FIXME: mgmt module must return failure for unregister if it has pending + * commands in LLD + */ +static int +megaraid_cmm_unregister(adapter_t *adapter) +{ + kfree(adapter->uscb_list); + mraid_mm_unregister_adp(adapter->unique_id); + return 0; +} + + +/** + * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD + * @param drvr_data : LLD specific data + * @param kioc : CMM interface packet + * @param action : command action + * + * This routine is invoked whenever the Common Mangement Module (CMM) has a + * command for us. The 'action' parameter specifies if this is a new command + * or otherwise. + */ +static int +megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action) +{ + adapter_t *adapter; + + if (action != IOCTL_ISSUE) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: unsupported management action:%#2x\n", + action)); + return (-ENOTSUPP); + } + + adapter = (adapter_t *)drvr_data; + + // make sure this adapter is not being detached right now. + if (atomic_read(&adapter->being_detached)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: reject management request, detaching\n")); + return (-ENODEV); + } + + switch (kioc->opcode) { + + case GET_ADAP_INFO: + + kioc->status = gather_hbainfo(adapter, (mraid_hba_info_t *) + (unsigned long)kioc->buf_vaddr); + + kioc->done(kioc); + + return kioc->status; + + case MBOX_CMD: + + return megaraid_mbox_mm_command(adapter, kioc); + + default: + kioc->status = (-EINVAL); + kioc->done(kioc); + return (-EINVAL); + } + + return 0; // not reached +} + +/** + * megaraid_mbox_mm_command - issues commands routed through CMM + * @param adapter : HBA soft state + * @param kioc : management command packet + * + * Issues commands, which are routed through the management module. + */ +static int +megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc) +{ + struct list_head *head = &adapter->uscb_pool; + mbox64_t *mbox64; + uint8_t *raw_mbox; + scb_t *scb; + mbox_ccb_t *ccb; + unsigned long flags; + + // detach one scb from free pool + spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); + + if (list_empty(head)) { // should never happen because of CMM + + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: bug in cmm handler, lost resources\n")); + + spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); + + return (-EINVAL); + } + + scb = list_entry(head->next, scb_t, list); + list_del_init(&scb->list); + + spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); + + scb->state = SCB_ACTIVE; + scb->dma_type = MRAID_DMA_NONE; + + ccb = (mbox_ccb_t *)scb->ccb; + mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; + raw_mbox = (uint8_t *)&mbox64->mbox32; + + memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t)); + + scb->gp = (unsigned long)kioc; + + /* + * If it is a logdrv random delete operation, we have to wait till + * there are no outstanding cmds at the fw and then issue it directly + */ + if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { + + if (wait_till_fw_empty(adapter)) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid mbox: LD delete, timed out\n")); + + kioc->status = -ETIME; + + scb->status = -1; + + megaraid_mbox_mm_done(adapter, scb); + + return (-ETIME); + } + + INIT_LIST_HEAD(&scb->list); + + scb->state = SCB_ISSUED; + if (mbox_post_cmd(adapter, scb) != 0) { + + con_log(CL_ANN, (KERN_NOTICE + "megaraid mbox: LD delete, mailbox busy\n")); + + kioc->status = -EBUSY; + + scb->status = -1; + + megaraid_mbox_mm_done(adapter, scb); + + return (-EBUSY); + } + + return 0; + } + + // put the command on the pending list and execute + megaraid_mbox_runpendq(adapter, scb); + + return 0; +} + + +static int +wait_till_fw_empty(adapter_t *adapter) +{ + unsigned long flags = 0; + int i; + + + /* + * Set the quiescent flag to stop issuing cmds to FW. + */ + spin_lock_irqsave(adapter->host_lock, flags); + adapter->quiescent++; + spin_unlock_irqrestore(adapter->host_lock, flags); + + /* + * Wait till there are no more cmds outstanding at FW. Try for at most + * 60 seconds + */ + for (i = 0; i < 60 && adapter->outstanding_cmds; i++) { + con_log(CL_DLEVEL1, (KERN_INFO + "megaraid: FW has %d pending commands\n", + adapter->outstanding_cmds)); + + msleep(1000); + } + + return adapter->outstanding_cmds; +} + + +/** + * megaraid_mbox_mm_done - callback for CMM commands + * @adapter : HBA soft state + * @scb : completed command + * + * Callback routine for internal commands originated from the management + * module. + */ +static void +megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) +{ + uioc_t *kioc; + mbox64_t *mbox64; + uint8_t *raw_mbox; + unsigned long flags; + + kioc = (uioc_t *)scb->gp; + kioc->status = 0; + mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; + mbox64->mbox32.status = scb->status; + raw_mbox = (uint8_t *)&mbox64->mbox32; + + + // put scb in the free pool + scb->state = SCB_FREE; + scb->scp = NULL; + + spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); + + list_add(&scb->list, &adapter->uscb_pool); + + spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); + + // if a delete logical drive operation succeeded, restart the + // controller + if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { + + adapter->quiescent--; + + megaraid_mbox_runpendq(adapter, NULL); + } + + kioc->done(kioc); + + return; +} + + +/** + * gather_hbainfo - HBA characteristics for the applications + * @param adapter : HBA soft state + * @param hinfo : pointer to the caller's host info strucuture + */ +static int +gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo) +{ + uint8_t dmajor; + + dmajor = megaraid_mbox_version[0]; + + hinfo->pci_vendor_id = adapter->pdev->vendor; + hinfo->pci_device_id = adapter->pdev->device; + hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor; + hinfo->subsys_device_id = adapter->pdev->subsystem_device; + + hinfo->pci_bus = adapter->pdev->bus->number; + hinfo->pci_dev_fn = adapter->pdev->devfn; + hinfo->pci_slot = PCI_SLOT(adapter->pdev->devfn); + hinfo->irq = adapter->host->irq; + hinfo->baseport = ADAP2RAIDDEV(adapter)->baseport; + + hinfo->unique_id = (hinfo->pci_bus << 8) | adapter->pdev->devfn; + hinfo->host_no = adapter->host->host_no; + + return 0; +} + +/* + * END: Interface for the common management module + */ + + +/* + * END: Mailbox Low Level Driver + */ +module_init(megaraid_init); +module_exit(megaraid_exit); + +/* vim: set ts=8 sw=8 tw=78 ai si: */ diff -Nru a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/megaraid_mbox.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,268 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * FILE : megaraid_mbox.h + */ + +#ifndef _MEGARAID_H_ +#define _MEGARAID_H_ + + +#include "mega_common.h" +#include "mbox_defs.h" +#include "megaraid_ioctl.h" + + +#define MEGARAID_VERSION "2.20.4.0" +#define MEGARAID_EXT_VERSION "(Release Date: Mon Sep 27 22:15:07 EDT 2004)" + + +/* + * Define some PCI values here until they are put in the kernel + */ +#define PCI_DEVICE_ID_PERC4_DI_DISCOVERY 0x000E +#define PCI_SUBSYS_ID_PERC4_DI_DISCOVERY 0x0123 + +#define PCI_DEVICE_ID_PERC4_SC 0x1960 +#define PCI_SUBSYS_ID_PERC4_SC 0x0520 + +#define PCI_DEVICE_ID_PERC4_DC 0x1960 +#define PCI_SUBSYS_ID_PERC4_DC 0x0518 + +#define PCI_DEVICE_ID_PERC4_QC 0x0407 +#define PCI_SUBSYS_ID_PERC4_QC 0x0531 + +#define PCI_DEVICE_ID_PERC4_DI_EVERGLADES 0x000F +#define PCI_SUBSYS_ID_PERC4_DI_EVERGLADES 0x014A + +#define PCI_DEVICE_ID_PERC4E_SI_BIGBEND 0x0013 +#define PCI_SUBSYS_ID_PERC4E_SI_BIGBEND 0x016c + +#define PCI_DEVICE_ID_PERC4E_DI_KOBUK 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_KOBUK 0x016d + +#define PCI_DEVICE_ID_PERC4E_DI_CORVETTE 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_CORVETTE 0x016e + +#define PCI_DEVICE_ID_PERC4E_DI_EXPEDITION 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION 0x016f + +#define PCI_DEVICE_ID_PERC4E_DI_GUADALUPE 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE 0x0170 + +#define PCI_DEVICE_ID_PERC4E_DC_320_2E 0x0408 +#define PCI_SUBSYS_ID_PERC4E_DC_320_2E 0x0002 + +#define PCI_DEVICE_ID_PERC4E_SC_320_1E 0x0408 +#define PCI_SUBSYS_ID_PERC4E_SC_320_1E 0x0001 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0 0xA520 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1 0x0520 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2 0x0518 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0x 0x0407 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x 0x0530 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2x 0x0407 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x 0x0532 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_4x 0x0407 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x 0x0531 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1E 0x0408 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E 0x0001 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2E 0x0408 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E 0x0002 + +#define PCI_DEVICE_ID_MEGARAID_I4_133_RAID 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_I4_133_RAID 0x0522 + +#define PCI_DEVICE_ID_MEGARAID_SATA_150_4 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SATA_150_4 0x4523 + +#define PCI_DEVICE_ID_MEGARAID_SATA_150_6 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SATA_150_6 0x0523 + +#define PCI_DEVICE_ID_MEGARAID_SATA_300_4x 0x0409 +#define PCI_SUBSYS_ID_MEGARAID_SATA_300_4x 0x3004 + +#define PCI_DEVICE_ID_MEGARAID_SATA_300_8x 0x0409 +#define PCI_SUBSYS_ID_MEGARAID_SATA_300_8x 0x3008 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCU42X 0x0407 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42X 0x0532 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCS16 0x1960 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCS16 0x0523 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCU42E 0x0408 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42E 0x0002 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCZCRX 0x0407 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX 0x0530 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCS28X 0x0409 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCS28X 0x3008 + +#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF 0x0408 +#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF 0x3431 + +#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH 0x0408 +#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH 0x3499 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x1960 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x0520 + +#define PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB 0x0408 +#define PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB 0x1065 + +#define PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E 0x0408 +#define PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E 0x004D + +#define PCI_SUBSYS_ID_PERC3_QC 0x0471 +#define PCI_SUBSYS_ID_PERC3_DC 0x0493 +#define PCI_SUBSYS_ID_PERC3_SC 0x0475 + +#ifndef PCI_SUBSYS_ID_FSC +#define PCI_SUBSYS_ID_FSC 0x1734 +#endif + +#define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel +#define MBOX_MAX_USER_CMDS 32 // number of cmds for applications +#define MBOX_DEF_CMD_PER_LUN 64 // default commands per lun +#define MBOX_DEFAULT_SG_SIZE 26 // default sg size supported by all fw +#define MBOX_MAX_SG_SIZE 32 // maximum scatter-gather list size +#define MBOX_MAX_SECTORS 128 // maximum sectors per IO +#define MBOX_TIMEOUT 30 // timeout value for internal cmds +#define MBOX_BUSY_WAIT 10 // max usec to wait for busy mailbox +#define MBOX_RESET_WAIT 180 // wait these many seconds in reset +#define MBOX_RESET_EXT_WAIT 120 // extended wait reset + +/* + * maximum transfer that can happen through the firmware commands issued + * internnaly from the driver. + */ +#define MBOX_IBUF_SIZE 4096 + + +/** + * mbox_ccb_t - command control block specific to mailbox based controllers + * @raw_mbox : raw mailbox pointer + * @mbox : mailbox + * @mbox64 : extended mailbox + * @mbox_dma_h : maibox dma address + * @sgl64 : 64-bit scatter-gather list + * @sgl32 : 32-bit scatter-gather list + * @sgl_dma_h : dma handle for the scatter-gather list + * @pthru : passthru structure + * @pthru_dma_h : dma handle for the passthru structure + * @epthru : extended passthru structure + * @epthru_dma_h : dma handle for extended passthru structure + * @buf_dma_h : dma handle for buffers w/o sg list + * + * command control block specific to the mailbox based controllers + */ +typedef struct { + uint8_t *raw_mbox; + mbox_t *mbox; + mbox64_t *mbox64; + dma_addr_t mbox_dma_h; + mbox_sgl64 *sgl64; + mbox_sgl32 *sgl32; + dma_addr_t sgl_dma_h; + mraid_passthru_t *pthru; + dma_addr_t pthru_dma_h; + mraid_epassthru_t *epthru; + dma_addr_t epthru_dma_h; + dma_addr_t buf_dma_h; +} mbox_ccb_t; + + +/** + * mraid_device_t - adapter soft state structure for mailbox controllers + * @param una_mbox64 : 64-bit mbox - unaligned + * @param una_mbox64_dma : mbox dma addr - unaligned + * @param mbox : 32-bit mbox - aligned + * @param mbox64 : 64-bit mbox - aligned + * @param mbox_dma : mbox dma addr - aligned + * @param mailbox_lock : exclusion lock for the mailbox + * @param baseport : base port of hba memory + * @param baseaddr : mapped addr of hba memory + * @param mbox_pool : pool of mailboxes + * @param mbox_pool_handle : handle for the mailbox pool memory + * @param epthru_pool : a pool for extended passthru commands + * @param epthru_pool_handle : handle to the pool above + * @param sg_pool : pool of scatter-gather lists for this driver + * @param sg_pool_handle : handle to the pool above + * @param ccb_list : list of our command control blocks + * @param uccb_list : list of cmd control blocks for mgmt module + * @param umbox64 : array of mailbox for user commands (cmm) + * @param pdrv_state : array for state of each physical drive. + * @param last_disp : flag used to show device scanning + * @param hw_error : set if FW not responding + * @param fast_load : If set, skip physical device scanning + * @channel_class : channel class, RAID or SCSI + * + * Initialization structure for mailbox controllers: memory based and IO based + * All the fields in this structure are LLD specific and may be discovered at + * init() or start() time. + * + * NOTE: The fields of this structures are placed to minimize cache misses + */ +typedef struct { + mbox64_t *una_mbox64; + dma_addr_t una_mbox64_dma; + mbox_t *mbox; + mbox64_t *mbox64; + dma_addr_t mbox_dma; + spinlock_t mailbox_lock; + unsigned long baseport; + unsigned long baseaddr; + struct mraid_pci_blk mbox_pool[MBOX_MAX_SCSI_CMDS]; + struct dma_pool *mbox_pool_handle; + struct mraid_pci_blk epthru_pool[MBOX_MAX_SCSI_CMDS]; + struct dma_pool *epthru_pool_handle; + struct mraid_pci_blk sg_pool[MBOX_MAX_SCSI_CMDS]; + struct dma_pool *sg_pool_handle; + mbox_ccb_t ccb_list[MBOX_MAX_SCSI_CMDS]; + mbox_ccb_t uccb_list[MBOX_MAX_USER_CMDS]; + mbox64_t umbox64[MBOX_MAX_USER_CMDS]; + + uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES]; + uint32_t last_disp; + int hw_error; + int fast_load; + uint8_t channel_class; +} mraid_device_t; + +// route to raid device from adapter +#define ADAP2RAIDDEV(adp) ((mraid_device_t *)((adp)->raid_device)) + +#define MAILBOX_LOCK(rdev) (&(rdev)->mailbox_lock) + +// Find out if this channel is a RAID or SCSI +#define IS_RAID_CH(rdev, ch) (((rdev)->channel_class >> (ch)) & 0x01) + + +#define RDINDOOR(rdev) readl((rdev)->baseaddr + 0x20) +#define RDOUTDOOR(rdev) readl((rdev)->baseaddr + 0x2C) +#define WRINDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x20) +#define WROUTDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x2C) + +#endif // _MEGARAID_H_ + +// vim: set ts=8 sw=8 tw=78: diff -Nru a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/megaraid_mm.c 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,1160 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * FILE : megaraid_mm.c + * Version : v2.20.2.0 (August 19 2004) + * + * Common management module + */ + +#include "megaraid_mm.h" + + +// Entry points for char node driver +static int mraid_mm_open(struct inode *, struct file *); +static int mraid_mm_ioctl(struct inode *, struct file *, uint, unsigned long); + + +// routines to convert to and from the old the format +static int mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *); +static int kioc_to_mimd(uioc_t *, mimd_t __user *); + + +// Helper functions +static int handle_drvrcmd(void __user *, uint8_t, int *); +static int lld_ioctl(mraid_mmadp_t *, uioc_t *); +static void ioctl_done(uioc_t *); +static void lld_timedout(unsigned long); +static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *); +static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *); +static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *); +static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *); +static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int); +static int mraid_mm_setup_dma_pools(mraid_mmadp_t *); +static void mraid_mm_free_adp_resources(mraid_mmadp_t *); +static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *); + +#ifdef CONFIG_COMPAT +static int mraid_mm_compat_ioctl(unsigned int, unsigned int, unsigned long, + struct file *); +#endif + +MODULE_AUTHOR("LSI Logic Corporation"); +MODULE_DESCRIPTION("LSI Logic Management Module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(LSI_COMMON_MOD_VERSION); + +static int dbglevel = CL_ANN; +module_param_named(dlevel, dbglevel, int, 0); +MODULE_PARM_DESC(dlevel, "Debug level (default=0)"); + +EXPORT_SYMBOL(mraid_mm_register_adp); +EXPORT_SYMBOL(mraid_mm_unregister_adp); + +static int majorno; +static uint32_t drvr_ver = 0x02200100; + +static int adapters_count_g; +static struct list_head adapters_list_g; + +wait_queue_head_t wait_q; + +static struct file_operations lsi_fops = { + .open = mraid_mm_open, + .ioctl = mraid_mm_ioctl, + .owner = THIS_MODULE, +}; + +/** + * mraid_mm_open - open routine for char node interface + * @inod : unused + * @filep : unused + * + * allow ioctl operations by apps only if they superuser privilege + */ +static int +mraid_mm_open(struct inode *inode, struct file *filep) +{ + /* + * Only allow superuser to access private ioctl interface + */ + if (!capable(CAP_SYS_ADMIN)) return (-EACCES); + + return 0; +} + +/** + * mraid_mm_ioctl - module entry-point for ioctls + * @inode : inode (ignored) + * @filep : file operations pointer (ignored) + * @cmd : ioctl command + * @arg : user ioctl packet + */ +static int +mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, + unsigned long arg) +{ + uioc_t *kioc; + char signature[EXT_IOCTL_SIGN_SZ] = {0}; + int rval; + mraid_mmadp_t *adp; + uint8_t old_ioctl; + int drvrcmd_rval; + void __user *argp = (void __user *)arg; + + /* + * Make sure only USCSICMD are issued through this interface. + * MIMD application would still fire different command. + */ + + if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) { + return (-EINVAL); + } + + /* + * Look for signature to see if this is the new or old ioctl format. + */ + if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: copy from usr addr failed\n")); + return (-EFAULT); + } + + if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0) + old_ioctl = 0; + else + old_ioctl = 1; + + /* + * At present, we don't support the new ioctl packet + */ + if (!old_ioctl ) + return (-EINVAL); + + /* + * If it is a driver ioctl (as opposed to fw ioctls), then we can + * handle the command locally. rval > 0 means it is not a drvr cmd + */ + rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval); + + if (rval < 0) + return rval; + else if (rval == 0) + return drvrcmd_rval; + + rval = 0; + if ((adp = mraid_mm_get_adapter(argp, &rval)) == NULL) { + return rval; + } + + /* + * The following call will block till a kioc is available + */ + kioc = mraid_mm_alloc_kioc(adp); + + /* + * User sent the old mimd_t ioctl packet. Convert it to uioc_t. + */ + if ((rval = mimd_to_kioc(argp, adp, kioc))) { + mraid_mm_dealloc_kioc(adp, kioc); + return rval; + } + + kioc->done = ioctl_done; + + /* + * Issue the IOCTL to the low level driver + */ + if ((rval = lld_ioctl(adp, kioc))) { + mraid_mm_dealloc_kioc(adp, kioc); + return rval; + } + + /* + * Convert the kioc back to user space + */ + rval = kioc_to_mimd(kioc, argp); + + /* + * Return the kioc to free pool + */ + mraid_mm_dealloc_kioc(adp, kioc); + + return rval; +} + + +/** + * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet + * @umimd : User space mimd_t ioctl packet + * @adapter : pointer to the adapter (OUT) + */ +static mraid_mmadp_t * +mraid_mm_get_adapter(mimd_t __user *umimd, int *rval) +{ + mraid_mmadp_t *adapter; + mimd_t mimd; + uint32_t adapno; + int iterator; + + + if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) { + *rval = -EFAULT; + return NULL; + } + + adapno = GETADAP(mimd.ui.fcs.adapno); + + if (adapno >= adapters_count_g) { + *rval = -ENODEV; + return NULL; + } + + adapter = NULL; + iterator = 0; + + list_for_each_entry(adapter, &adapters_list_g, list) { + if (iterator++ == adapno) break; + } + + if (!adapter) { + *rval = -ENODEV; + return NULL; + } + + return adapter; +} + +/* + * handle_drvrcmd - This routine checks if the opcode is a driver + * cmd and if it is, handles it. + * @arg : packet sent by the user app + * @old_ioctl : mimd if 1; uioc otherwise + */ +static int +handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval) +{ + mimd_t __user *umimd; + mimd_t kmimd; + uint8_t opcode; + uint8_t subopcode; + + if (old_ioctl) + goto old_packet; + else + goto new_packet; + +new_packet: + return (-ENOTSUPP); + +old_packet: + *rval = 0; + umimd = arg; + + if (copy_from_user(&kmimd, umimd, sizeof(mimd_t))) + return (-EFAULT); + + opcode = kmimd.ui.fcs.opcode; + subopcode = kmimd.ui.fcs.subopcode; + + /* + * If the opcode is 0x82 and the subopcode is either GET_DRVRVER or + * GET_NUMADP, then we can handle. Otherwise we should return 1 to + * indicate that we cannot handle this. + */ + if (opcode != 0x82) + return 1; + + switch (subopcode) { + + case MEGAIOC_QDRVRVER: + + if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t))) + return (-EFAULT); + + return 0; + + case MEGAIOC_QNADAP: + + *rval = adapters_count_g; + + if (copy_to_user(kmimd.data, &adapters_count_g, + sizeof(uint32_t))) + return (-EFAULT); + + return 0; + + default: + /* cannot handle */ + return 1; + } + + return 0; +} + + +/** + * mimd_to_kioc - Converter from old to new ioctl format + * + * @umimd : user space old MIMD IOCTL + * @kioc : kernel space new format IOCTL + * + * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The + * new packet is in kernel space so that driver can perform operations on it + * freely. + */ + +static int +mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc) +{ + mbox64_t *mbox64; + mbox_t *mbox; + mraid_passthru_t *pthru32; + uint32_t adapno; + uint8_t opcode; + uint8_t subopcode; + mimd_t mimd; + + if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) + return (-EFAULT); + + /* + * Applications are not allowed to send extd pthru + */ + if ((mimd.mbox[0] == MBOXCMD_PASSTHRU64) || + (mimd.mbox[0] == MBOXCMD_EXTPTHRU)) + return (-EINVAL); + + opcode = mimd.ui.fcs.opcode; + subopcode = mimd.ui.fcs.subopcode; + adapno = GETADAP(mimd.ui.fcs.adapno); + + if (adapno >= adapters_count_g) + return (-ENODEV); + + kioc->adapno = adapno; + kioc->mb_type = MBOX_LEGACY; + kioc->app_type = APPTYPE_MIMD; + + switch (opcode) { + + case 0x82: + + if (subopcode == MEGAIOC_QADAPINFO) { + + kioc->opcode = GET_ADAP_INFO; + kioc->data_dir = UIOC_RD; + kioc->xferlen = sizeof(mraid_hba_info_t); + + if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) + return (-ENOMEM); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: Invalid subop\n")); + return (-EINVAL); + } + + break; + + case 0x81: + + kioc->opcode = MBOX_CMD; + kioc->xferlen = mimd.ui.fcs.length; + kioc->user_data_len = kioc->xferlen; + kioc->user_data = mimd.ui.fcs.buffer; + + if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) + return (-ENOMEM); + + if (mimd.outlen) kioc->data_dir = UIOC_RD; + if (mimd.inlen) kioc->data_dir |= UIOC_WR; + + break; + + case 0x80: + + kioc->opcode = MBOX_CMD; + kioc->xferlen = (mimd.outlen > mimd.inlen) ? + mimd.outlen : mimd.inlen; + kioc->user_data_len = kioc->xferlen; + kioc->user_data = mimd.data; + + if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) + return (-ENOMEM); + + if (mimd.outlen) kioc->data_dir = UIOC_RD; + if (mimd.inlen) kioc->data_dir |= UIOC_WR; + + break; + + default: + return (-EINVAL); + } + + /* + * If driver command, nothing else to do + */ + if (opcode == 0x82) + return 0; + + /* + * This is a mailbox cmd; copy the mailbox from mimd + */ + mbox64 = (mbox64_t *)((unsigned long)kioc->cmdbuf); + mbox = &mbox64->mbox32; + memcpy(mbox, mimd.mbox, 14); + + if (mbox->cmd != MBOXCMD_PASSTHRU) { // regular DCMD + + mbox->xferaddr = (uint32_t)kioc->buf_paddr; + + if (kioc->data_dir & UIOC_WR) { + if (copy_from_user(kioc->buf_vaddr, kioc->user_data, + kioc->xferlen)) { + return (-EFAULT); + } + } + + return 0; + } + + /* + * This is a regular 32-bit pthru cmd; mbox points to pthru struct. + * Just like in above case, the beginning for memblk is treated as + * a mailbox. The passthru will begin at next 1K boundary. And the + * data will start 1K after that. + */ + pthru32 = kioc->pthru32; + kioc->user_pthru = &umimd->pthru; + mbox->xferaddr = (uint32_t)kioc->pthru32_h; + + if (copy_from_user(pthru32, kioc->user_pthru, + sizeof(mraid_passthru_t))) { + return (-EFAULT); + } + + pthru32->dataxferaddr = kioc->buf_paddr; + if (kioc->data_dir & UIOC_WR) { + if (copy_from_user(kioc->buf_vaddr, kioc->user_data, + pthru32->dataxferlen)) { + return (-EFAULT); + } + } + + return 0; +} + +/** + * mraid_mm_attch_buf - Attach a free dma buffer for required size + * + * @adp : Adapter softstate + * @kioc : kioc that the buffer needs to be attached to + * @xferlen : required length for buffer + * + * First we search for a pool with smallest buffer that is >= @xferlen. If + * that pool has no free buffer, we will try for the next bigger size. If none + * is available, we will try to allocate the smallest buffer that is >= + * @xferlen and attach it the pool. + */ +static int +mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen) +{ + mm_dmapool_t *pool; + int right_pool = -1; + unsigned long flags; + int i; + + kioc->pool_index = -1; + kioc->buf_vaddr = NULL; + kioc->buf_paddr = 0; + kioc->free_buf = 0; + + /* + * We need xferlen amount of memory. See if we can get it from our + * dma pools. If we don't get exact size, we will try bigger buffer + */ + + for (i = 0; i < MAX_DMA_POOLS; i++) { + + pool = &adp->dma_pool_list[i]; + + if (xferlen > pool->buf_size) + continue; + + if (right_pool == -1) + right_pool = i; + + spin_lock_irqsave(&pool->lock, flags); + + if (!pool->in_use) { + + pool->in_use = 1; + kioc->pool_index = i; + kioc->buf_vaddr = pool->vaddr; + kioc->buf_paddr = pool->paddr; + + spin_unlock_irqrestore(&pool->lock, flags); + return 0; + } + else { + spin_unlock_irqrestore(&pool->lock, flags); + continue; + } + } + + /* + * If xferlen doesn't match any of our pools, return error + */ + if (right_pool == -1) + return -EINVAL; + + /* + * We did not get any buffer from the preallocated pool. Let us try + * to allocate one new buffer. NOTE: This is a blocking call. + */ + pool = &adp->dma_pool_list[right_pool]; + + spin_lock_irqsave(&pool->lock, flags); + + kioc->pool_index = right_pool; + kioc->free_buf = 1; + kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, + &kioc->buf_paddr); + spin_unlock_irqrestore(&pool->lock, flags); + + if (!kioc->buf_vaddr) + return -ENOMEM; + + return 0; +} + +/** + * mraid_mm_alloc_kioc - Returns a uioc_t from free list + * @adp : Adapter softstate for this module + * + * The kioc_semaphore is initialized with number of kioc nodes in the + * free kioc pool. If the kioc pool is empty, this function blocks till + * a kioc becomes free. + */ +static uioc_t * +mraid_mm_alloc_kioc(mraid_mmadp_t *adp) +{ + uioc_t *kioc; + struct list_head* head; + unsigned long flags; + + down(&adp->kioc_semaphore); + + spin_lock_irqsave(&adp->kioc_pool_lock, flags); + + head = &adp->kioc_pool; + + if (list_empty(head)) { + up(&adp->kioc_semaphore); + spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); + + con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n")); + return NULL; + } + + kioc = list_entry(head->next, uioc_t, list); + list_del_init(&kioc->list); + + spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); + + memset((caddr_t)(unsigned long)kioc->cmdbuf, 0, sizeof(mbox64_t)); + memset((caddr_t) kioc->pthru32, 0, sizeof(mraid_passthru_t)); + + kioc->buf_vaddr = NULL; + kioc->buf_paddr = 0; + kioc->pool_index =-1; + kioc->free_buf = 0; + kioc->user_data = NULL; + kioc->user_data_len = 0; + kioc->user_pthru = NULL; + + return kioc; +} + +/** + * mraid_mm_dealloc_kioc - Return kioc to free pool + * + * @adp : Adapter softstate + * @kioc : uioc_t node to be returned to free pool + */ +static void +mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc) +{ + mm_dmapool_t *pool; + unsigned long flags; + + pool = &adp->dma_pool_list[kioc->pool_index]; + + /* This routine may be called in non-isr context also */ + spin_lock_irqsave(&pool->lock, flags); + + /* + * While attaching the dma buffer, if we didn't get the required + * buffer from the pool, we would have allocated it at the run time + * and set the free_buf flag. We must free that buffer. Otherwise, + * just mark that the buffer is not in use + */ + if (kioc->free_buf == 1) + pci_pool_free(pool->handle, kioc->buf_vaddr, kioc->buf_paddr); + else + pool->in_use = 0; + + spin_unlock_irqrestore(&pool->lock, flags); + + /* Return the kioc to the free pool */ + spin_lock_irqsave(&adp->kioc_pool_lock, flags); + list_add(&kioc->list, &adp->kioc_pool); + spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); + + /* increment the free kioc count */ + up(&adp->kioc_semaphore); + + return; +} + +/** + * lld_ioctl - Routine to issue ioctl to low level drvr + * + * @adp : The adapter handle + * @kioc : The ioctl packet with kernel addresses + */ +static int +lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc) +{ + int rval; + struct timer_list timer; + struct timer_list *tp = NULL; + + kioc->status = -ENODATA; + rval = adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE); + + if (rval) return rval; + + /* + * Start the timer + */ + if (adp->timeout > 0) { + tp = &timer; + init_timer(tp); + + tp->function = lld_timedout; + tp->data = (unsigned long)kioc; + tp->expires = jiffies + adp->timeout * HZ; + + add_timer(tp); + } + + /* + * Wait till the low level driver completes the ioctl. After this + * call, the ioctl either completed successfully or timedout. + */ + wait_event(wait_q, (kioc->status != -ENODATA)); + if (tp) { + del_timer_sync(tp); + } + + return kioc->status; +} + + +/** + * ioctl_done - callback from the low level driver + * + * @kioc : completed ioctl packet + */ +static void +ioctl_done(uioc_t *kioc) +{ + /* + * When the kioc returns from driver, make sure it still doesn't + * have ENODATA in status. Otherwise, driver will hang on wait_event + * forever + */ + if (kioc->status == -ENODATA) { + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: lld didn't change status!\n")); + + kioc->status = -EINVAL; + } + + wake_up(&wait_q); +} + + +/* + * lld_timedout : callback from the expired timer + * + * @ptr : ioctl packet that timed out + */ +static void +lld_timedout(unsigned long ptr) +{ + uioc_t *kioc = (uioc_t *)ptr; + + kioc->status = -ETIME; + + con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n")); + + wake_up(&wait_q); +} + + +/** + * kioc_to_mimd : Converter from new back to old format + * + * @kioc : Kernel space IOCTL packet (successfully issued) + * @mimd : User space MIMD packet + */ +static int +kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd) +{ + mimd_t kmimd; + uint8_t opcode; + uint8_t subopcode; + + mbox64_t *mbox64; + mraid_passthru_t __user *upthru32; + mraid_passthru_t *kpthru32; + mcontroller_t cinfo; + mraid_hba_info_t *hinfo; + + + if (copy_from_user(&kmimd, mimd, sizeof(mimd_t))) + return (-EFAULT); + + opcode = kmimd.ui.fcs.opcode; + subopcode = kmimd.ui.fcs.subopcode; + + if (opcode == 0x82) { + switch (subopcode) { + + case MEGAIOC_QADAPINFO: + + hinfo = (mraid_hba_info_t *)(unsigned long) + kioc->buf_vaddr; + + hinfo_to_cinfo(hinfo, &cinfo); + + if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo))) + return (-EFAULT); + + return 0; + + default: + return (-EINVAL); + } + + return 0; + } + + mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; + + if (kioc->user_pthru) { + + upthru32 = kioc->user_pthru; + kpthru32 = kioc->pthru32; + + if (copy_to_user(&upthru32->scsistatus, + &kpthru32->scsistatus, + sizeof(uint8_t))) { + return (-EFAULT); + } + } + + if (kioc->user_data) { + if (copy_to_user(kioc->user_data, kioc->buf_vaddr, + kioc->user_data_len)) { + return (-EFAULT); + } + } + + if (copy_to_user(&mimd->mbox[17], + &mbox64->mbox32.status, sizeof(uint8_t))) { + return (-EFAULT); + } + + return 0; +} + + +/** + * hinfo_to_cinfo - Convert new format hba info into old format + * + * @hinfo : New format, more comprehensive adapter info + * @cinfo : Old format adapter info to support mimd_t apps + */ +static void +hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo) +{ + if (!hinfo || !cinfo) + return; + + cinfo->base = hinfo->baseport; + cinfo->irq = hinfo->irq; + cinfo->numldrv = hinfo->num_ldrv; + cinfo->pcibus = hinfo->pci_bus; + cinfo->pcidev = hinfo->pci_slot; + cinfo->pcifun = PCI_FUNC(hinfo->pci_dev_fn); + cinfo->pciid = hinfo->pci_device_id; + cinfo->pcivendor = hinfo->pci_vendor_id; + cinfo->pcislot = hinfo->pci_slot; + cinfo->uid = hinfo->unique_id; +} + + +/* + * mraid_mm_register_adp - Registration routine for low level drvrs + * + * @adp : Adapter objejct + */ +int +mraid_mm_register_adp(mraid_mmadp_t *lld_adp) +{ + mraid_mmadp_t *adapter; + mbox64_t *mbox_list; + uioc_t *kioc; + uint32_t rval; + int i; + + + if (lld_adp->drvr_type != DRVRTYPE_MBOX) + return (-EINVAL); + + adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); + + if (!adapter) { + rval = -ENOMEM; + goto memalloc_error; + } + + memset(adapter, 0, sizeof(mraid_mmadp_t)); + + adapter->unique_id = lld_adp->unique_id; + adapter->drvr_type = lld_adp->drvr_type; + adapter->drvr_data = lld_adp->drvr_data; + adapter->pdev = lld_adp->pdev; + adapter->issue_uioc = lld_adp->issue_uioc; + adapter->timeout = lld_adp->timeout; + adapter->max_kioc = lld_adp->max_kioc; + + /* + * Allocate single blocks of memory for all required kiocs, + * mailboxes and passthru structures. + */ + adapter->kioc_list = kmalloc(sizeof(uioc_t) * lld_adp->max_kioc, + GFP_KERNEL); + adapter->mbox_list = kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc, + GFP_KERNEL); + adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool", + adapter->pdev, + sizeof(mraid_passthru_t), + 16, 0); + + if (!adapter->kioc_list || !adapter->mbox_list || + !adapter->pthru_dma_pool) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + + rval = (-ENOMEM); + + goto memalloc_error; + } + + /* + * Slice kioc_list and make a kioc_pool with the individiual kiocs + */ + INIT_LIST_HEAD(&adapter->kioc_pool); + spin_lock_init(&adapter->kioc_pool_lock); + sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc); + + mbox_list = (mbox64_t *)adapter->mbox_list; + + for (i = 0; i < lld_adp->max_kioc; i++) { + + kioc = adapter->kioc_list + i; + kioc->cmdbuf = (uint64_t)(unsigned long)(mbox_list + i); + kioc->pthru32 = pci_pool_alloc(adapter->pthru_dma_pool, + GFP_KERNEL, &kioc->pthru32_h); + + if (!kioc->pthru32) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: out of memory, %s %d\n", + __FUNCTION__, __LINE__)); + + rval = (-ENOMEM); + + goto pthru_dma_pool_error; + } + + list_add_tail(&kioc->list, &adapter->kioc_pool); + } + + // Setup the dma pools for data buffers + if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) { + goto dma_pool_error; + } + + list_add_tail(&adapter->list, &adapters_list_g); + + adapters_count_g++; + + return 0; + +dma_pool_error: + /* Do nothing */ + +pthru_dma_pool_error: + + for (i = 0; i < lld_adp->max_kioc; i++) { + kioc = adapter->kioc_list + i; + if (kioc->pthru32) { + pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32, + kioc->pthru32_h); + } + } + +memalloc_error: + + if (adapter->kioc_list) + kfree(adapter->kioc_list); + + if (adapter->mbox_list) + kfree(adapter->mbox_list); + + if (adapter->pthru_dma_pool) + pci_pool_destroy(adapter->pthru_dma_pool); + + if (adapter) + kfree(adapter); + + return rval; +} + +/** + * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter + * + * @adp : Adapter softstate + * + * We maintain a pool of dma buffers per each adapter. Each pool has one + * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers. + * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We + * dont' want to waste too much memory by allocating more buffers per each + * pool. + */ +static int +mraid_mm_setup_dma_pools(mraid_mmadp_t *adp) +{ + mm_dmapool_t *pool; + int bufsize; + int i; + + /* + * Create MAX_DMA_POOLS number of pools + */ + bufsize = MRAID_MM_INIT_BUFF_SIZE; + + for (i = 0; i < MAX_DMA_POOLS; i++){ + + pool = &adp->dma_pool_list[i]; + + pool->buf_size = bufsize; + spin_lock_init(&pool->lock); + + pool->handle = pci_pool_create("megaraid mm data buffer", + adp->pdev, bufsize, 16, 0); + + if (!pool->handle) { + goto dma_pool_setup_error; + } + + pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, + &pool->paddr); + + if (!pool->vaddr) + goto dma_pool_setup_error; + + bufsize = bufsize * 2; + } + + return 0; + +dma_pool_setup_error: + + mraid_mm_teardown_dma_pools(adp); + return (-ENOMEM); +} + + +/* + * mraid_mm_unregister_adp - Unregister routine for low level drivers + * Assume no outstanding ioctls to llds. + * + * @unique_id : UID of the adpater + */ +int +mraid_mm_unregister_adp(uint32_t unique_id) +{ + mraid_mmadp_t *adapter; + mraid_mmadp_t *tmp; + + list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) { + + + if (adapter->unique_id == unique_id) { + + adapters_count_g--; + + list_del_init(&adapter->list); + + mraid_mm_free_adp_resources(adapter); + + kfree(adapter); + + con_log(CL_ANN, ( + "megaraid cmm: Unregistered one adapter:%#x\n", + unique_id)); + + return 0; + } + } + + return (-ENODEV); +} + +/** + * mraid_mm_free_adp_resources - Free adapter softstate + * + * @adp : Adapter softstate + */ +static void +mraid_mm_free_adp_resources(mraid_mmadp_t *adp) +{ + uioc_t *kioc; + int i; + + mraid_mm_teardown_dma_pools(adp); + + for (i = 0; i < adp->max_kioc; i++) { + + kioc = adp->kioc_list + i; + + pci_pool_free(adp->pthru_dma_pool, kioc->pthru32, + kioc->pthru32_h); + } + + kfree(adp->kioc_list); + + kfree(adp->mbox_list); + + pci_pool_destroy(adp->pthru_dma_pool); + + + return; +} + + +/** + * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers + * + * @adp : Adapter softstate + */ +static void +mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp) +{ + int i; + mm_dmapool_t *pool; + + for (i = 0; i < MAX_DMA_POOLS; i++) { + + pool = &adp->dma_pool_list[i]; + + if (pool->handle) { + + if (pool->vaddr) + pci_pool_free(pool->handle, pool->vaddr, + pool->paddr); + + pci_pool_destroy(pool->handle); + pool->handle = NULL; + } + } + + return; +} + +/** + * mraid_mm_init : Module entry point + */ +static int __init +mraid_mm_init(void) +{ + // Announce the driver version + con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n", + LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION)); + + majorno = register_chrdev(0, "megadev", &lsi_fops); + + if (majorno < 0) { + con_log(CL_ANN, ("megaraid cmm: cannot get major\n")); + return majorno; + } + + init_waitqueue_head(&wait_q); + + INIT_LIST_HEAD(&adapters_list_g); + +#ifdef CONFIG_COMPAT + register_ioctl32_conversion(MEGAIOCCMD, mraid_mm_compat_ioctl); +#endif + + return 0; +} + + +/** + * mraid_mm_compat_ioctl : 32bit to 64bit ioctl conversion routine + */ +#ifdef CONFIG_COMPAT +static int +mraid_mm_compat_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filep) +{ + struct inode *inode = filep->f_dentry->d_inode; + + return mraid_mm_ioctl(inode, filep, cmd, arg); +} +#endif + +/** + * mraid_mm_exit : Module exit point + */ +static void __exit +mraid_mm_exit(void) +{ + con_log(CL_DLEVEL1 , ("exiting common mod\n")); + + unregister_chrdev(majorno, "megadev"); + unregister_ioctl32_conversion(MEGAIOCCMD); +} + +module_init(mraid_mm_init); +module_exit(mraid_mm_exit); + +/* vi: set ts=8 sw=8 tw=78: */ diff -Nru a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/megaraid/megaraid_mm.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,102 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * FILE : megaraid_mm.h + */ + +#ifndef MEGARAID_MM_H +#define MEGARAID_MM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mbox_defs.h" +#include "megaraid_ioctl.h" + + +#define LSI_COMMON_MOD_VERSION "2.20.2.0" +#define LSI_COMMON_MOD_EXT_VERSION \ + "(Release Date: Thu Aug 19 09:58:33 EDT 2004)" + + +#define LSI_DBGLVL dbglevel + +// The smallest dma pool +#define MRAID_MM_INIT_BUFF_SIZE 4096 + +/** + * mimd_t : Old style ioctl packet structure (deprecated) + * + * @inlen : + * @outlen : + * @fca : + * @opcode : + * @subopcode : + * @adapno : + * @buffer : + * @pad : + * @length : + * @mbox : + * @pthru : + * @data : + * @pad : + * + * Note : This structure is DEPRECATED. New applications must use + * : uioc_t structure instead. All new hba drivers use the new + * : format. If we get this mimd packet, we will convert it into + * : new uioc_t format and send it to the hba drivers. + */ + +typedef struct mimd { + + uint32_t inlen; + uint32_t outlen; + + union { + uint8_t fca[16]; + struct { + uint8_t opcode; + uint8_t subopcode; + uint16_t adapno; +#if BITS_PER_LONG == 32 + uint8_t __user *buffer; + uint8_t pad[4]; +#endif +#if BITS_PER_LONG == 64 + uint8_t __user *buffer; +#endif + uint32_t length; + } __attribute__ ((packed)) fcs; + } __attribute__ ((packed)) ui; + + uint8_t mbox[18]; /* 16 bytes + 2 status bytes */ + mraid_passthru_t pthru; + +#if BITS_PER_LONG == 32 + char __user *data; /* buffer <= 4096 for 0x80 commands */ + char pad[4]; +#endif +#if BITS_PER_LONG == 64 + char __user *data; +#endif + +} __attribute__ ((packed))mimd_t; + +#endif // MEGARAID_MM_H + +// vi: set ts=8 sw=8 tw=78: diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c --- a/drivers/scsi/megaraid.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/scsi/megaraid.c 2004-10-18 14:55:53 -07:00 @@ -25,11 +25,8 @@ * 518, 520, 531, 532 * * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, - * and others. Please send updates to the public mailing list - * linux-megaraid-devel@dell.com, and subscribe to and read archives of this - * list at http://lists.us.dell.com/. - * - * For history of changes, see ChangeLog.megaraid. + * and others. Please send updates to the mailing list + * linux-scsi@vger.kernel.org . * */ @@ -53,9 +50,12 @@ #include "megaraid.h" +#define MEGARAID_MODULE_VERSION "2.00.3" + MODULE_AUTHOR ("LSI Logic Corporation"); MODULE_DESCRIPTION ("LSI Logic MegaRAID driver"); MODULE_LICENSE ("GPL"); +MODULE_VERSION(MEGARAID_MODULE_VERSION); static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN; MODULE_PARM(max_cmd_per_lun, "i"); diff -Nru a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c --- a/drivers/scsi/nsp32.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/nsp32.c 2004-10-18 14:56:28 -07:00 @@ -267,8 +267,8 @@ static int nsp32_prom_read (nsp32_hw_data *, int); static int nsp32_prom_read_bit (nsp32_hw_data *); static void nsp32_prom_write_bit(nsp32_hw_data *, int); -static inline void nsp32_prom_set (nsp32_hw_data *, int, int); -static inline int nsp32_prom_get (nsp32_hw_data *, int); +static void nsp32_prom_set (nsp32_hw_data *, int, int); +static int nsp32_prom_get (nsp32_hw_data *, int); /* debug/warning/info message */ static void nsp32_message (const char *, int, char *, char *, ...); @@ -3342,7 +3342,7 @@ return val; } -static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) +static void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) { int base = data->BaseAddress; int tmp; @@ -3360,7 +3360,7 @@ udelay(10); } -static inline int nsp32_prom_get(nsp32_hw_data *data, int bit) +static int nsp32_prom_get(nsp32_hw_data *data, int bit) { int base = data->BaseAddress; int tmp, ret; diff -Nru a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c --- a/drivers/scsi/pas16.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/pas16.c 2004-10-18 14:55:54 -07:00 @@ -605,6 +605,7 @@ { if (shost->irq) free_irq(shost->irq, NULL); + NCR5380_exit(shost); if (shost->dma_channel != 0xff) free_dma(shost->dma_channel); if (shost->io_port && shost->n_io_port) diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c --- a/drivers/scsi/pcmcia/nsp_cs.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/pcmcia/nsp_cs.c 2004-10-18 14:57:04 -07:00 @@ -1528,7 +1528,7 @@ thislength = pos - (buffer + offset); if(thislength < 0) { - *start = 0; + *start = NULL; return 0; } diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c --- a/drivers/scsi/qla1280.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/scsi/qla1280.c 2004-10-18 14:57:05 -07:00 @@ -4,7 +4,7 @@ * QLogic QLA1280 (Ultra2) and QLA12160 (Ultra3) SCSI driver * Copyright (C) 2000 Qlogic Corporation (www.qlogic.com) * Copyright (C) 2001-2004 Jes Sorensen, Wild Open Source Inc. -* Copyright (C) 2003 Christoph Hellwig +* Copyright (C) 2003-2004 Christoph Hellwig * * 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 @@ -17,9 +17,12 @@ * General Public License for more details. * ******************************************************************************/ -#define QLA1280_VERSION "3.24.3" +#define QLA1280_VERSION "3.24.4" /***************************************************************************** Revision History: + Rev 3.24.4 June 7, 2004 Christoph Hellwig + - restructure firmware loading, cleanup initialization code + - prepare support for ISP1020/1040 chips Rev 3.24.3 January 19, 2004, Jes Sorensen - Handle PCI DMA mask settings correctly - Correct order of error handling in probe_one, free_irq should not @@ -485,6 +488,14 @@ #define ia64_platform_is(foo) (!strcmp(x, platform_name)) #endif + +#define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020) +#define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \ + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240) +#define IS_ISP1x160(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160 || \ + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160) + + static int qla1280_probe_one(struct pci_dev *, const struct pci_device_id *); static void qla1280_remove_one(struct pci_dev *); @@ -501,9 +512,7 @@ /* * QLogic ISP1280 Hardware Support Function Prototypes. */ -static int qla1280_isp_firmware(struct scsi_qla_host *); -static int qla1280_chip_diag(struct scsi_qla_host *); -static int qla1280_setup_chip(struct scsi_qla_host *); +static int qla1280_load_firmware(struct scsi_qla_host *); static int qla1280_init_rings(struct scsi_qla_host *); static int qla1280_nvram_config(struct scsi_qla_host *); static int qla1280_mailbox_command(struct scsi_qla_host *, @@ -1384,16 +1393,10 @@ uint8_t mr; uint16_t mb[MAILBOX_REGISTER_COUNT]; struct nvram *nv; - int is1x160, status; + int status; nv = &ha->nvram; - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) - is1x160 = 1; - else - is1x160 = 0; - mr = BIT_3 | BIT_2 | BIT_1 | BIT_0; /* Set Target Parameters. */ @@ -1403,17 +1406,16 @@ mb[2] = (nv->bus[bus].target[target].parameter.c << 8); - if (is1x160) - mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; - else - mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; - mb[3] |= nv->bus[bus].target[target].sync_period; - - if (is1x160) { + if (IS_ISP1x160(ha)) { mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - mb[6] = nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8; - mb[6] |= nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; + mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) | + nv->bus[bus].target[target].sync_period; + mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) | + nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; mr |= BIT_6; + } else { + mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) | + nv->bus[bus].target[target].sync_period; } status = qla1280_mailbox_command(ha, mr, &mb[0]); @@ -1476,8 +1478,7 @@ (driver_setup.wide_mask && (~driver_setup.wide_mask & (1 << target)))) nv->bus[bus].target[target].parameter.f.enable_wide = 0; - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) { + if (IS_ISP1x160(ha)) { if (driver_setup.no_ppr || (driver_setup.ppr_mask && (~driver_setup.ppr_mask & (1 << target)))) @@ -1802,17 +1803,8 @@ */ spin_lock_irqsave(HOST_LOCK, flags); #endif - /* If firmware needs to be loaded */ - if (qla1280_isp_firmware(ha)) { - if (!(status = qla1280_chip_diag(ha))) { - status = qla1280_setup_chip(ha); - } - } else { - printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", - ha->host_no); - status = 1; - } + status = qla1280_load_firmware(ha); if (status) { printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n", ha->host_no); @@ -1823,36 +1815,24 @@ dprintk(1, "scsi(%ld): Configure NVRAM parameters\n", ha->host_no); qla1280_nvram_config(ha); - if (!ha->flags.disable_host_adapter && !qla1280_init_rings(ha)) { - /* Issue SCSI reset. */ - /* dg 03/13 if we can't reset twice then bus is dead */ - for (bus = 0; bus < ha->ports; bus++) { - if (!ha->bus_settings[bus].disable_scsi_reset){ - if (qla1280_bus_reset(ha, bus)) { - if (qla1280_bus_reset(ha, bus)) { - ha->bus_settings[bus].scsi_bus_dead = 1; - } - } - } - } + if (ha->flags.disable_host_adapter) { + status = 1; + goto out; + } - /* - * qla1280_bus_reset() will take care of issueing markers, - * no need to do that here as well! - */ -#if 0 - /* Issue marker command. */ - ha->flags.reset_marker = 0; - for (bus = 0; bus < ha->ports; bus++) { - ha->bus_settings[bus].reset_marker = 0; - qla1280_marker(ha, bus, 0, 0, MK_SYNC_ALL); - } -#endif + status = qla1280_init_rings(ha); + if (status) + goto out; - ha->flags.online = 1; - } else - status = 1; + /* Issue SCSI reset, if we can't reset twice then bus is dead */ + for (bus = 0; bus < ha->ports; bus++) { + if (!ha->bus_settings[bus].disable_scsi_reset && + qla1280_bus_reset(ha, bus) && + qla1280_bus_reset(ha, bus)) + ha->bus_settings[bus].scsi_bus_dead = 1; + } + ha->flags.online = 1; out: #if LINUX_VERSION_CODE >= 0x020500 spin_unlock_irqrestore(HOST_LOCK, flags); @@ -1945,13 +1925,13 @@ int status = 0; int cnt; uint16_t data; - dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", ®->id_l); dprintk(1, "scsi(%ld): Verifying chip\n", ha->host_no); /* Soft reset chip and wait for it to finish. */ WRT_REG_WORD(®->ictrl, ISP_RESET); + /* * We can't do a traditional PCI write flush here by reading * back the register. The card will not respond once the reset @@ -1969,145 +1949,138 @@ data = RD_REG_WORD(®->ictrl); } - if (cnt) { - /* Reset register cleared by chip reset. */ - dprintk(3, "qla1280_chip_diag: reset register cleared by " - "chip reset\n"); + if (!cnt) + goto fail; - WRT_REG_WORD(®->cfg_1, 0); + /* Reset register cleared by chip reset. */ + dprintk(3, "qla1280_chip_diag: reset register cleared by chip reset\n"); - /* Reset RISC and disable BIOS which - allows RISC to execute out of RAM. */ -#if 0 - WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); -#else - WRT_REG_WORD(®->host_cmd, HC_RESET_RISC | - HC_RELEASE_RISC | HC_DISABLE_BIOS); -#endif - RD_REG_WORD(®->id_l); /* Flush PCI write */ - data = qla1280_debounce_register(®->mailbox0); - /* - * I *LOVE* this code! - */ - for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) { - udelay(5); - data = RD_REG_WORD(®->mailbox0); - } + WRT_REG_WORD(®->cfg_1, 0); - if (cnt) { - /* Check product ID of chip */ - dprintk(3, "qla1280_chip_diag: Checking product " - "ID of chip\n"); - - if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || - (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && - RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || - RD_REG_WORD(®->mailbox3) != PROD_ID_3 || - RD_REG_WORD(®->mailbox4) != PROD_ID_4) { - printk(KERN_INFO "qla1280: Wrong product ID = " - "0x%x,0x%x,0x%x,0x%x\n", - RD_REG_WORD(®->mailbox1), - RD_REG_WORD(®->mailbox2), - RD_REG_WORD(®->mailbox3), - RD_REG_WORD(®->mailbox4)); - status = 1; - } else { - /* - * Enable ints early!!! - */ - qla1280_enable_intrs(ha); - - dprintk(1, "qla1280_chip_diag: Checking " - "mailboxes of chip\n"); - /* Wrap Incoming Mailboxes Test. */ - mb[0] = MBC_MAILBOX_REGISTER_TEST; - mb[1] = 0xAAAA; - mb[2] = 0x5555; - mb[3] = 0xAA55; - mb[4] = 0x55AA; - mb[5] = 0xA5A5; - mb[6] = 0x5A5A; - mb[7] = 0x2525; - if (!(status = qla1280_mailbox_command(ha, - 0xff, - &mb - [0]))) { - if (mb[1] != 0xAAAA || - mb[2] != 0x5555 || - mb[3] != 0xAA55 || - mb[4] != 0x55AA || - mb[5] != 0xA5A5 || - mb[6] != 0x5A5A || - mb[7] != 0x2525) { - status = 1; - printk(KERN_INFO "qla1280: " - "Failed mbox check\n"); - } - } - } - } else - status = 1; - } else - status = 1; + /* Reset RISC and disable BIOS which + allows RISC to execute out of RAM. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC | + HC_RELEASE_RISC | HC_DISABLE_BIOS); + + RD_REG_WORD(®->id_l); /* Flush PCI write */ + data = qla1280_debounce_register(®->mailbox0); + + /* + * I *LOVE* this code! + */ + for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) { + udelay(5); + data = RD_REG_WORD(®->mailbox0); + } + + if (!cnt) + goto fail; + + /* Check product ID of chip */ + dprintk(3, "qla1280_chip_diag: Checking product ID of chip\n"); + + if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || + (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && + RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || + RD_REG_WORD(®->mailbox3) != PROD_ID_3 || + RD_REG_WORD(®->mailbox4) != PROD_ID_4) { + printk(KERN_INFO "qla1280: Wrong product ID = " + "0x%x,0x%x,0x%x,0x%x\n", + RD_REG_WORD(®->mailbox1), + RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3), + RD_REG_WORD(®->mailbox4)); + goto fail; + } + /* + * Enable ints early!!! + */ + qla1280_enable_intrs(ha); + + dprintk(1, "qla1280_chip_diag: Checking mailboxes of chip\n"); + /* Wrap Incoming Mailboxes Test. */ + mb[0] = MBC_MAILBOX_REGISTER_TEST; + mb[1] = 0xAAAA; + mb[2] = 0x5555; + mb[3] = 0xAA55; + mb[4] = 0x55AA; + mb[5] = 0xA5A5; + mb[6] = 0x5A5A; + mb[7] = 0x2525; + + status = qla1280_mailbox_command(ha, 0xff, mb); if (status) - dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); - else - dprintk(3, "qla1280_chip_diag: exiting normally\n"); + goto fail; + if (mb[1] != 0xAAAA || mb[2] != 0x5555 || mb[3] != 0xAA55 || + mb[4] != 0x55AA || mb[5] != 0xA5A5 || mb[6] != 0x5A5A || + mb[7] != 0x2525) { + printk(KERN_INFO "qla1280: Failed mbox check\n"); + goto fail; + } + + dprintk(3, "qla1280_chip_diag: exiting normally\n"); + return 0; + fail: + dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); return status; } -/* - * Setup chip - * Load and start RISC firmware. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success. - */ -#define DUMP_IT_BACK 0 /* for debug of RISC loading */ static int -qla1280_setup_chip(struct scsi_qla_host *ha) +qla1280_load_firmware_pio(struct scsi_qla_host *ha) { - int status = 0; - uint16_t risc_address; - uint16_t *risc_code_address; - int risc_code_size; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t cnt; - int num, i; -#if DUMP_IT_BACK - uint8_t *sp; - uint8_t *tbuf; - dma_addr_t p_tbuf; -#endif + uint16_t risc_address, *risc_code_address, risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT], i; + int err; - ENTER("qla1280_setup_chip"); + /* Load RISC code. */ + risc_address = *ql1280_board_tbl[ha->devnum].fwstart; + risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; + risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; - dprintk(1, "scsi(%ld): Setup chip\n", ha->host_no); + for (i = 0; i < risc_code_size; i++) { + mb[0] = MBC_WRITE_RAM_WORD; + mb[1] = risc_address + i; + mb[2] = risc_code_address[i]; + + err = qla1280_mailbox_command(ha, BIT_0 | BIT_1 | BIT_2, mb); + if (err) { + printk(KERN_ERR "scsi(%li): Failed to load firmware\n", + ha->host_no); + return err; + } + } + return 0; +} + +#define DUMP_IT_BACK 0 /* for debug of RISC loading */ +static int +qla1280_load_firmware_dma(struct scsi_qla_host *ha) +{ + uint16_t risc_address, *risc_code_address, risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT], cnt; + int err = 0, num, i; #if DUMP_IT_BACK - /* get consistent memory allocated for setup_chip */ + uint8_t *sp, *tbuf; + dma_addr_t p_tbuf; + tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); + if (!tbuf) + return -ENOMEM; #endif /* Load RISC code. */ risc_address = *ql1280_board_tbl[ha->devnum].fwstart; risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; - risc_code_size = (int) *ql1280_board_tbl[ha->devnum].fwlen; + risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; - dprintk(1, "qla1280_setup_chip: DMA RISC code (%i) words\n", - risc_code_size); + dprintk(1, "%s: DMA RISC code (%i) words\n", + __FUNCTION__, risc_code_size); num = 0; - while (risc_code_size > 0 && !status) { + while (risc_code_size > 0) { int warn __attribute__((unused)) = 0; cnt = 2000 >> 1; @@ -2129,15 +2102,16 @@ mb[2] = (ha->request_dma >> 16) & 0xffff; mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; mb[6] = pci_dma_hi32(ha->request_dma) >> 16; - dprintk(2, "qla1280_setup_chip: op=%d 0x%p = 0x%4x,0x%4x," - "0x%4x,0x%4x\n", mb[0], (void *)(long)ha->request_dma, - mb[6], mb[7], mb[2], mb[3]); - if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | - BIT_2 | BIT_1 | BIT_0, - &mb[0]))) { + dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n", + __FUNCTION__, mb[0], + (void *)(long)ha->request_dma, + mb[6], mb[7], mb[2], mb[3]); + err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | + BIT_1 | BIT_0, mb); + if (err) { printk(KERN_ERR "scsi(%li): Failed to load partial " "segment of f\n", ha->host_no); - break; + goto out; } #if DUMP_IT_BACK @@ -2149,22 +2123,22 @@ mb[7] = pci_dma_hi32(p_tbuf) & 0xffff; mb[6] = pci_dma_hi32(p_tbuf) >> 16; - if ((status = qla1280_mailbox_command(ha, - BIT_4 | BIT_3 | BIT_2 | - BIT_1 | BIT_0, - &mb[0]))) { + err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | + BIT_1 | BIT_0, mb); + if (err) { printk(KERN_ERR "Failed to dump partial segment of f/w\n"); - break; + goto out; } sp = (uint8_t *)ha->request_ring; for (i = 0; i < (cnt << 1); i++) { if (tbuf[i] != sp[i] && warn++ < 10) { - printk(KERN_ERR "qla1280_setup_chip: FW " - "compare error @ byte(0x%x) loop#=%x\n", - i, num); - printk(KERN_ERR "setup_chip: FWbyte=%x " - "FWfromChip=%x\n", sp[i], tbuf[i]); + printk(KERN_ERR "%s: FW compare error @ " + "byte(0x%x) loop#=%x\n", + __FUNCTION__, i, num); + printk(KERN_ERR "%s: FWbyte=%x " + "FWfromChip=%x\n", + __FUNCTION__, sp[i], tbuf[i]); /*break; */ } } @@ -2175,37 +2149,69 @@ num++; } - /* Verify checksum of loaded RISC code. */ - if (!status) { - dprintk(1, "qla1280_setup_chip: Verifying checksum of " - "loaded RISC code.\n"); - mb[0] = MBC_VERIFY_CHECKSUM; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - - if (!(status = - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) { - /* Start firmware execution. */ - dprintk(1, - "qla1280_setup_chip: start firmware running.\n"); - mb[0] = MBC_EXECUTE_FIRMWARE; - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - } else - printk(KERN_ERR "scsi(%li): qla1280_setup_chip: " - "Failed checksum\n", ha->host_no); - } - + out: #if DUMP_IT_BACK - /* free consistent memory allocated for setup_chip */ pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); #endif + return err; +} - if (status) - dprintk(2, "qla1280_setup_chip: **** FAILED ****\n"); +static int +qla1280_start_firmware(struct scsi_qla_host *ha) +{ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int err; - LEAVE("qla1280_setup_chip"); - return status; + dprintk(1, "%s: Verifying checksum of loaded RISC code.\n", + __FUNCTION__); + + /* Verify checksum of loaded RISC code. */ + mb[0] = MBC_VERIFY_CHECKSUM; + /* mb[1] = ql12_risc_code_addr01; */ + mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); + if (err) { + printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no); + return err; + } + + /* Start firmware execution. */ + dprintk(1, "%s: start firmware running.\n", __FUNCTION__); + mb[0] = MBC_EXECUTE_FIRMWARE; + mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + if (err) { + printk(KERN_ERR "scsi(%li): Failed to start firmware\n", + ha->host_no); + } + + return err; +} + +static int +qla1280_load_firmware(struct scsi_qla_host *ha) +{ + int err = -ENODEV; + + /* If firmware needs to be loaded */ + if (!qla1280_isp_firmware(ha)) { + printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", + ha->host_no); + goto out; + } + + err = qla1280_chip_diag(ha); + if (err) + goto out; + if (IS_ISP1040(ha)) + err = qla1280_load_firmware_pio(ha); + else + err = qla1280_load_firmware_dma(ha); + if (err) + goto out; + err = qla1280_start_firmware(ha); + out: + return err; } /* @@ -2271,123 +2277,9 @@ return status; } -/* - * NVRAM configuration. - * - * Input: - * ha = adapter block pointer. - * ha->request_ring = request ring virtual address - * - * Output: - * host adapters parameters in host adapter block - * - * Returns: - * 0 = success. - */ -static int -qla1280_nvram_config(struct scsi_qla_host *ha) +static void +qla1280_print_settings(struct nvram *nv) { - struct device_reg *reg = ha->iobase; - struct nvram *nv; - int is1x160, status = 0; - int bus, target, lun; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t mask; - - ENTER("qla1280_nvram_config"); - - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) - is1x160 = 1; - else - is1x160 = 0; - - nv = &ha->nvram; - if (!ha->nvram_valid) { - dprintk(1, "Using defaults for NVRAM: \n"); - memset(nv, 0, sizeof(struct nvram)); - - /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ - nv->firmware_feature.f.enable_fast_posting = 1; - nv->firmware_feature.f.disable_synchronous_backoff = 1; - - nv->termination.f.scsi_bus_0_control = 3; - nv->termination.f.scsi_bus_1_control = 3; - nv->termination.f.auto_term_support = 1; - - /* - * Set default FIFO magic - What appropriate values - * would be here is unknown. This is what I have found - * testing with 12160s. - * Now, I would love the magic decoder ring for this one, - * the header file provided by QLogic seems to be bogus - * or incomplete at best. - */ - nv->isp_config.c = 0x44; - - if (is1x160) - nv->isp_parameter = 0x01; - - for (bus = 0; bus < MAX_BUSES; bus++) { - nv->bus[bus].config_1.initiator_id = 7; - nv->bus[bus].bus_reset_delay = 5; - /* 8 = 5.0 clocks */ - nv->bus[bus].config_2.async_data_setup_time = 8; - nv->bus[bus].config_2.req_ack_active_negation = 1; - nv->bus[bus].config_2.data_line_active_negation = 1; - nv->bus[bus].selection_timeout = 250; - nv->bus[bus].max_queue_depth = 256; - - for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. - renegotiate_on_error = 1; - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - tag_queuing = 1; - nv->bus[bus].target[target].parameter.f. - enable_sync = 1; -#if 1 /* Some SCSI Processors do not seem to like this */ - nv->bus[bus].target[target].parameter.f. - enable_wide = 1; -#endif - nv->bus[bus].target[target].parameter.f. - parity_checking = 1; - nv->bus[bus].target[target].parameter.f. - disconnect_allowed = 1; - nv->bus[bus].target[target].execution_throttle= - nv->bus[bus].max_queue_depth - 1; - if (is1x160) { - nv->bus[bus].target[target].flags. - flags1x160.device_enable = 1; - nv->bus[bus].target[target].flags. - flags1x160.sync_offset = 0x0e; - nv->bus[bus].target[target]. - sync_period = 9; - nv->bus[bus].target[target]. - ppr_1x160.flags.enable_ppr = 1; - nv->bus[bus].target[target].ppr_1x160. - flags.ppr_options = 2; - nv->bus[bus].target[target].ppr_1x160. - flags.ppr_bus_width = 1; - } else { - nv->bus[bus].target[target].flags. - flags1x80.device_enable = 1; - nv->bus[bus].target[target].flags. - flags1x80.sync_offset = 0x8; - nv->bus[bus].target[target]. - sync_period = 10; - } - } - } - } else { - /* Always force AUTO sense for LINUX SCSI */ - for (bus = 0; bus < MAX_BUSES; bus++) - for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - } - } dprintk(1, "qla1280 : initiator scsi id bus[0]=%d\n", nv->bus[0].config_1.initiator_id); dprintk(1, "qla1280 : initiator scsi id bus[1]=%d\n", @@ -2433,36 +2325,264 @@ nv->bus[0].max_queue_depth); dprintk(1, "qla1280 : max queue depth[1]=%d\n", nv->bus[1].max_queue_depth); +} + +static void +qla1280_set_target_defaults(struct scsi_qla_host *ha, int bus, int target) +{ + struct nvram *nv = &ha->nvram; + + nv->bus[bus].target[target].parameter.f.renegotiate_on_error = 1; + nv->bus[bus].target[target].parameter.f.auto_request_sense = 1; + nv->bus[bus].target[target].parameter.f.tag_queuing = 1; + nv->bus[bus].target[target].parameter.f.enable_sync = 1; +#if 1 /* Some SCSI Processors do not seem to like this */ + nv->bus[bus].target[target].parameter.f.enable_wide = 1; +#endif + if (!IS_ISP1040(ha)) + nv->bus[bus].target[target].parameter.f.parity_checking = 1; + + nv->bus[bus].target[target].parameter.f.disconnect_allowed = 1; + nv->bus[bus].target[target].execution_throttle = + nv->bus[bus].max_queue_depth - 1; + + if (IS_ISP1x160(ha)) { + nv->bus[bus].target[target].flags.flags1x160.device_enable = 1; + nv->bus[bus].target[target].flags.flags1x160.sync_offset = 0x0e; + nv->bus[bus].target[target].sync_period = 9; + nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1; + nv->bus[bus].target[target].ppr_1x160.flags.ppr_options = 2; + nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width = 1; + } else { + nv->bus[bus].target[target].flags.flags1x80.device_enable = 1; + nv->bus[bus].target[target].flags.flags1x80.sync_offset = 12; + nv->bus[bus].target[target].sync_period = 10; + } +} + +static void +qla1280_set_defaults(struct scsi_qla_host *ha) +{ + struct nvram *nv = &ha->nvram; + int bus, target; + + dprintk(1, "Using defaults for NVRAM: \n"); + memset(nv, 0, sizeof(struct nvram)); + + /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ + nv->firmware_feature.f.enable_fast_posting = 1; + nv->firmware_feature.f.disable_synchronous_backoff = 1; + nv->termination.f.scsi_bus_0_control = 3; + nv->termination.f.scsi_bus_1_control = 3; + nv->termination.f.auto_term_support = 1; + + /* + * Set default FIFO magic - What appropriate values would be here + * is unknown. This is what I have found testing with 12160s. + * + * Now, I would love the magic decoder ring for this one, the + * header file provided by QLogic seems to be bogus or incomplete + * at best. + */ + nv->isp_config.c = ISP_CFG1_BENAB|ISP_CFG1_F128; + if (IS_ISP1x160(ha)) + nv->isp_parameter = 0x01; /* fast memory enable */ + + for (bus = 0; bus < MAX_BUSES; bus++) { + nv->bus[bus].config_1.initiator_id = 7; + nv->bus[bus].config_2.req_ack_active_negation = 1; + nv->bus[bus].config_2.data_line_active_negation = 1; + nv->bus[bus].selection_timeout = 250; + nv->bus[bus].max_queue_depth = 256; + + if (IS_ISP1040(ha)) { + nv->bus[bus].bus_reset_delay = 3; + nv->bus[bus].config_2.async_data_setup_time = 6; + nv->bus[bus].retry_delay = 1; + } else { + nv->bus[bus].bus_reset_delay = 5; + nv->bus[bus].config_2.async_data_setup_time = 8; + } + + for (target = 0; target < MAX_TARGETS; target++) + qla1280_set_target_defaults(ha, bus, target); + } +} + +static int +qla1280_config_target(struct scsi_qla_host *ha, int bus, int target) +{ + struct nvram *nv = &ha->nvram; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int status, lun; + + /* Set Target Parameters. */ + mb[0] = MBC_SET_TARGET_PARAMETERS; + mb[1] = (uint16_t) (bus ? target | BIT_7 : target); + mb[1] <<= 8; + + /* + * Do not enable wide, sync, and ppr for the initial + * INQUIRY run. We enable this later if we determine + * the target actually supports it. + */ + nv->bus[bus].target[target].parameter.f. + auto_request_sense = 1; + nv->bus[bus].target[target].parameter.f. + stop_queue_on_check = 0; + + if (IS_ISP1x160(ha)) + nv->bus[bus].target[target].ppr_1x160. + flags.enable_ppr = 0; + + /* + * No sync, wide, etc. while probing + */ + mb[2] = (nv->bus[bus].target[target].parameter.c << 8) & + ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); + + if (IS_ISP1x160(ha)) + mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; + else + mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; + mb[3] |= nv->bus[bus].target[target].sync_period; + + status = qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]); + + /* Save Tag queuing enable flag. */ + mb[0] = BIT_0 << target; + if (nv->bus[bus].target[target].parameter.f.tag_queuing) + ha->bus_settings[bus].qtag_enables |= mb[0]; + + /* Save Device enable flag. */ + if (IS_ISP1x160(ha)) { + if (nv->bus[bus].target[target].flags.flags1x160.device_enable) + ha->bus_settings[bus].device_enables |= mb[0]; + ha->bus_settings[bus].lun_disables |= 0; + } else { + if (nv->bus[bus].target[target].flags.flags1x80.device_enable) + ha->bus_settings[bus].device_enables |= mb[0]; + /* Save LUN disable flag. */ + if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) + ha->bus_settings[bus].lun_disables |= mb[0]; + } + + /* Set Device Queue Parameters. */ + for (lun = 0; lun < MAX_LUNS; lun++) { + mb[0] = MBC_SET_DEVICE_QUEUE; + mb[1] = (uint16_t)(bus ? target | BIT_7 : target); + mb[1] = mb[1] << 8 | lun; + mb[2] = nv->bus[bus].max_queue_depth; + mb[3] = nv->bus[bus].target[target].execution_throttle; + status |= qla1280_mailbox_command(ha, 0x0f, &mb[0]); + } + + return status; +} + +static int +qla1280_config_bus(struct scsi_qla_host *ha, int bus) +{ + struct nvram *nv = &ha->nvram; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int target, status; + + /* SCSI Reset Disable. */ + ha->bus_settings[bus].disable_scsi_reset = + nv->bus[bus].config_1.scsi_reset_disable; + + /* Initiator ID. */ + ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; + mb[0] = MBC_SET_INITIATOR_ID; + mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : + ha->bus_settings[bus].id; + status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + + /* Reset Delay. */ + ha->bus_settings[bus].bus_reset_delay = + nv->bus[bus].bus_reset_delay; + + /* Command queue depth per device. */ + ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; + + /* Set target parameters. */ + for (target = 0; target < MAX_TARGETS; target++) + status |= qla1280_config_target(ha, bus, target); + + return status; +} + +static int +qla1280_nvram_config(struct scsi_qla_host *ha) +{ + struct device_reg *reg = ha->iobase; + struct nvram *nv = &ha->nvram; + int bus, target, status = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint16_t mask; + + ENTER("qla1280_nvram_config"); + + if (ha->nvram_valid) { + /* Always force AUTO sense for LINUX SCSI */ + for (bus = 0; bus < MAX_BUSES; bus++) + for (target = 0; target < MAX_TARGETS; target++) { + nv->bus[bus].target[target].parameter.f. + auto_request_sense = 1; + } + } else { + qla1280_set_defaults(ha); + } + + qla1280_print_settings(nv); /* Disable RISC load of firmware. */ ha->flags.disable_risc_code_load = nv->cntr_flags_1.disable_loading_risc_code; - /* Set ISP hardware DMA burst */ - mb[0] = nv->isp_config.c; - /* Enable DMA arbitration on dual channel controllers */ - if (ha->ports > 1) - mb[0] |= BIT_13; - WRT_REG_WORD(®->cfg_1, mb[0]); - -#if 1 /* Is this safe? */ - /* Set SCSI termination. */ - WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); - mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); - WRT_REG_WORD(®->gpio_data, mb[0]); -#endif + if (IS_ISP1040(ha)) { + uint16_t hwrev, cfg1, cdma_conf, ddma_conf; + + hwrev = RD_REG_WORD(®->cfg_0) & ISP_CFG0_HWMSK; + + cfg1 = RD_REG_WORD(®->cfg_1); + cdma_conf = RD_REG_WORD(®->cdma_cfg); + ddma_conf = RD_REG_WORD(®->ddma_cfg); + + /* Busted fifo, says mjacob. */ + if (hwrev == ISP_CFG0_1040A) + WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64); + else + WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64 | ISP_CFG1_BENAB); + + WRT_REG_WORD(®->cdma_cfg, cdma_conf | CDMA_CONF_BENAB); + WRT_REG_WORD(®->ddma_cfg, cdma_conf | DDMA_CONF_BENAB); + } else { + /* Set ISP hardware DMA burst */ + mb[0] = nv->isp_config.c; + /* Enable DMA arbitration on dual channel controllers */ + if (ha->ports > 1) + mb[0] |= BIT_13; + WRT_REG_WORD(®->cfg_1, mb[0]); + + /* Set SCSI termination. */ + WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); + mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); + WRT_REG_WORD(®->gpio_data, mb[0]); + } /* ISP parameter word. */ mb[0] = MBC_SET_SYSTEM_PARAMETER; mb[1] = nv->isp_parameter; status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); -#if 0 - /* clock rate - for qla1240 and older, only */ - mb[0] = MBC_SET_CLOCK_RATE; - mb[1] = 0x50; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); -#endif + if (IS_ISP1x40(ha)) { + /* clock rate - for qla1240 and older, only */ + mb[0] = MBC_SET_CLOCK_RATE; + mb[1] = 40; + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); + } + /* Firmware feature word. */ mb[0] = MBC_SET_FIRMWARE_FEATURES; mask = BIT_5 | BIT_1 | BIT_0; @@ -2515,112 +2635,18 @@ mb[2] = 2; /* Command DMA Channel Burst Enable */ status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + mb[0] = MBC_SET_TAG_AGE_LIMIT; + mb[1] = 8; + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + /* Selection timeout. */ mb[0] = MBC_SET_SELECTION_TIMEOUT; mb[1] = nv->bus[0].selection_timeout; mb[2] = nv->bus[1].selection_timeout; status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); - for (bus = 0; bus < ha->ports; bus++) { - /* SCSI Reset Disable. */ - ha->bus_settings[bus].disable_scsi_reset = - nv->bus[bus].config_1.scsi_reset_disable; - - /* Initiator ID. */ - ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; - mb[0] = MBC_SET_INITIATOR_ID; - mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : - ha->bus_settings[bus].id; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - - /* Reset Delay. */ - ha->bus_settings[bus].bus_reset_delay = - nv->bus[bus].bus_reset_delay; - - /* Command queue depth per device. */ - ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; - - /* Set target parameters. */ - for (target = 0; target < MAX_TARGETS; target++) { - uint8_t mr = BIT_2 | BIT_1 | BIT_0; - - /* Set Target Parameters. */ - mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; - /* - * Do not enable wide, sync, and ppr for the initial - * INQUIRY run. We enable this later if we determine - * the target actually supports it. - */ - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - stop_queue_on_check = 0; - - if (is1x160) - nv->bus[bus].target[target].ppr_1x160. - flags.enable_ppr = 0; - /* - * No sync, wide, etc. while probing - */ - mb[2] = (nv->bus[bus].target[target].parameter.c << 8)& - ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); - - if (is1x160) - mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; - else - mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; - mb[3] |= nv->bus[bus].target[target].sync_period; - mr |= BIT_3; - - /* - * We don't want to enable ppr etc. before we have - * determined that the target actually supports it - */ -#if 0 - if (is1x160) { - mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - - mb[6] = nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8; - mb[6] |= nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; - mr |= BIT_6; - } -#endif - - status = qla1280_mailbox_command(ha, mr, &mb[0]); - - /* Save Tag queuing enable flag. */ - mb[0] = BIT_0 << target; - if (nv->bus[bus].target[target].parameter.f.tag_queuing) - ha->bus_settings[bus].qtag_enables |= mb[0]; - - /* Save Device enable flag. */ - if (is1x160) { - if (nv->bus[bus].target[target].flags.flags1x160.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; - ha->bus_settings[bus].lun_disables |= 0; - } else { - if (nv->bus[bus].target[target].flags.flags1x80.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; - /* Save LUN disable flag. */ - if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) - ha->bus_settings[bus].lun_disables |= mb[0]; - } - - - /* Set Device Queue Parameters. */ - for (lun = 0; lun < MAX_LUNS; lun++) { - mb[0] = MBC_SET_DEVICE_QUEUE; - mb[1] = (uint16_t)(bus ? target | BIT_7 : target); - mb[1] = mb[1] << 8 | lun; - mb[2] = nv->bus[bus].max_queue_depth; - mb[3] = nv->bus[bus].target[target].execution_throttle; - status |= qla1280_mailbox_command(ha, 0x0f, - &mb[0]); - } - } - } + for (bus = 0; bus < ha->ports; bus++) + status |= qla1280_config_bus(ha, bus); if (status) dprintk(2, "qla1280_nvram_config: **** FAILED ****\n"); @@ -4231,6 +4257,7 @@ static int qla1280_abort_isp(struct scsi_qla_host *ha) { + struct device_reg *reg = ha->iobase; struct srb *sp; int status = 0; int cnt; @@ -4238,69 +4265,53 @@ ENTER("qla1280_abort_isp"); - if (!ha->flags.abort_isp_active && ha->flags.online) { - struct device_reg *reg = ha->iobase; - ha->flags.abort_isp_active = 1; + if (ha->flags.abort_isp_active || !ha->flags.online) + goto out; + + ha->flags.abort_isp_active = 1; - /* Disable ISP interrupts. */ - qla1280_disable_intrs(ha); - WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); - RD_REG_WORD(®->id_l); + /* Disable ISP interrupts. */ + qla1280_disable_intrs(ha); + WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); + RD_REG_WORD(®->id_l); - printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n", - ha->host_no); - /* Dequeue all commands in outstanding command list. */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - struct scsi_cmnd *cmd; - sp = ha->outstanding_cmds[cnt]; - if (sp) { + printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n", + ha->host_no); + /* Dequeue all commands in outstanding command list. */ + for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + struct scsi_cmnd *cmd; + sp = ha->outstanding_cmds[cnt]; + if (sp) { - cmd = sp->cmd; - CMD_RESULT(cmd) = DID_RESET << 16; + cmd = sp->cmd; + CMD_RESULT(cmd) = DID_RESET << 16; - sp->cmd = NULL; - ha->outstanding_cmds[cnt] = NULL; + sp->cmd = NULL; + ha->outstanding_cmds[cnt] = NULL; - (*cmd->scsi_done)(cmd); + (*cmd->scsi_done)(cmd); - sp->flags = 0; - } + sp->flags = 0; } + } - /* If firmware needs to be loaded */ - if (qla1280_isp_firmware (ha)) { - if (!(status = qla1280_chip_diag(ha))) - status = qla1280_setup_chip(ha); - } + status = qla1280_load_firmware(ha); + if (status) + goto out; - if (!status) { - /* Setup adapter based on NVRAM parameters. */ - qla1280_nvram_config (ha); - - if (!(status = qla1280_init_rings(ha))) { - /* Issue SCSI reset. */ - for (bus = 0; bus < ha->ports; bus++) { - qla1280_bus_reset(ha, bus); - } - /* - * qla1280_bus_reset() will do the marker - * dance - no reason to repeat here! - */ -#if 0 - /* Issue marker command. */ - ha->flags.reset_marker = 0; - for (bus = 0; bus < ha->ports; bus++) { - ha->bus_settings[bus]. - reset_marker = 0; - qla1280_marker(ha, bus, 0, 0, - MK_SYNC_ALL); - } -#endif - ha->flags.abort_isp_active = 0; - } - } - } + /* Setup adapter based on NVRAM parameters. */ + qla1280_nvram_config (ha); + status = qla1280_init_rings(ha); + if (status) + goto out; + + /* Issue SCSI reset. */ + for (bus = 0; bus < ha->ports; bus++) + qla1280_bus_reset(ha, bus); + + ha->flags.abort_isp_active = 0; + out: if (status) { printk(KERN_WARNING "qla1280: ISP error recovery failed, board disabled"); @@ -4936,6 +4947,7 @@ MODULE_AUTHOR("Qlogic & Jes Sorensen"); MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA1280_VERSION); /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h --- a/drivers/scsi/qla1280.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/qla1280.h 2004-10-18 14:57:04 -07:00 @@ -62,6 +62,7 @@ #define WRT_REG_WORD(addr, data) writew(data, addr) #else /* MEMORY_MAPPED_IO */ #define RD_REG_WORD(addr) inw((unsigned long)addr) +#define RD_REG_WORD_dmasync(addr) RD_REG_WORD(addr) #define WRT_REG_WORD(addr, data) outw(data, (unsigned long)addr) #endif /* MEMORY_MAPPED_IO */ @@ -126,7 +127,20 @@ uint16_t id_l; /* ID low */ uint16_t id_h; /* ID high */ uint16_t cfg_0; /* Configuration 0 */ +#define ISP_CFG0_HWMSK 0x000f /* Hardware revision mask */ +#define ISP_CFG0_1020 BIT_0 /* ISP1020 */ +#define ISP_CFG0_1020A BIT_1 /* ISP1020A */ +#define ISP_CFG0_1040 BIT_2 /* ISP1040 */ +#define ISP_CFG0_1040A BIT_3 /* ISP1040A */ +#define ISP_CFG0_1040B BIT_4 /* ISP1040B */ +#define ISP_CFG0_1040C BIT_5 /* ISP1040C */ uint16_t cfg_1; /* Configuration 1 */ +#define ISP_CFG1_F128 BIT_6 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F64 BIT_4|BIT_5 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F32 BIT_5 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F16 BIT_4 /* 128-byte FIFO threshold */ +#define ISP_CFG1_BENAB BIT_2 /* Global Bus burst enable */ +#define ISP_CFG1_SXP BIT_0 /* SXP register select */ uint16_t ictrl; /* Interface control */ #define ISP_RESET BIT_0 /* ISP soft reset */ #define ISP_EN_INT BIT_1 /* ISP enable interrupts. */ @@ -147,7 +161,42 @@ uint16_t flash_data; /* Flash BIOS data */ uint16_t flash_address; /* Flash BIOS address */ - uint16_t unused_1[0x2e]; /* 0x14-0x6f Gap */ + uint16_t unused_1[0x06]; + + /* cdma_* and ddma_* are 1040 only */ + uint16_t cdma_cfg; +#define CDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ +#define CDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ +#define CDMA_CONF_BENAB BIT_1 /* Bus burst enable */ +#define CDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ + uint16_t cdma_ctrl; + uint16_t cdma_status; + uint16_t cdma_fifo_status; + uint16_t cdma_count; + uint16_t cdma_reserved; + uint16_t cdma_address_count_0; + uint16_t cdma_address_count_1; + uint16_t cdma_address_count_2; + uint16_t cdma_address_count_3; + + uint16_t unused_2[0x06]; + + uint16_t ddma_cfg; +#define DDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ +#define DDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ +#define DDMA_CONF_BENAB BIT_1 /* Bus burst enable */ +#define DDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ + uint16_t ddma_ctrl; + uint16_t ddma_status; + uint16_t ddma_fifo_status; + uint16_t ddma_xfer_count_low; + uint16_t ddma_xfer_count_high; + uint16_t ddma_addr_count_0; + uint16_t ddma_addr_count_1; + uint16_t ddma_addr_count_2; + uint16_t ddma_addr_count_3; + + uint16_t unused_3[0x0e]; uint16_t mailbox0; /* Mailbox 0 */ uint16_t mailbox1; /* Mailbox 1 */ @@ -158,18 +207,18 @@ uint16_t mailbox6; /* Mailbox 6 */ uint16_t mailbox7; /* Mailbox 7 */ - uint16_t unused_2[0x20];/* 0x80-0xbf Gap */ + uint16_t unused_4[0x20];/* 0x80-0xbf Gap */ uint16_t host_cmd; /* Host command and control */ #define HOST_INT BIT_7 /* host interrupt bit */ #define BIOS_ENABLE BIT_0 - uint16_t unused_6[0x5]; /* 0xc2-0xcb Gap */ + uint16_t unused_5[0x5]; /* 0xc2-0xcb Gap */ uint16_t gpio_data; uint16_t gpio_enable; - uint16_t unused_7[0x11]; /* d0-f0 */ + uint16_t unused_6[0x11]; /* d0-f0 */ uint16_t scsiControlPins; /* f2 */ }; diff -Nru a/drivers/scsi/qla2xxx/ql2100.c b/drivers/scsi/qla2xxx/ql2100.c --- a/drivers/scsi/qla2xxx/ql2100.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/qla2xxx/ql2100.c 2004-10-18 14:56:28 -07:00 @@ -89,3 +89,4 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP21xx FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff -Nru a/drivers/scsi/qla2xxx/ql2200.c b/drivers/scsi/qla2xxx/ql2200.c --- a/drivers/scsi/qla2xxx/ql2200.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/scsi/qla2xxx/ql2200.c 2004-10-18 14:55:46 -07:00 @@ -89,3 +89,4 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP22xx FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff -Nru a/drivers/scsi/qla2xxx/ql2300.c b/drivers/scsi/qla2xxx/ql2300.c --- a/drivers/scsi/qla2xxx/ql2300.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/qla2xxx/ql2300.c 2004-10-18 14:57:04 -07:00 @@ -100,3 +100,4 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP2300 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff -Nru a/drivers/scsi/qla2xxx/ql2322.c b/drivers/scsi/qla2xxx/ql2322.c --- a/drivers/scsi/qla2xxx/ql2322.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/scsi/qla2xxx/ql2322.c 2004-10-18 14:56:27 -07:00 @@ -105,3 +105,4 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP2322 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff -Nru a/drivers/scsi/qla2xxx/ql6312.c b/drivers/scsi/qla2xxx/ql6312.c --- a/drivers/scsi/qla2xxx/ql6312.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/qla2xxx/ql6312.c 2004-10-18 14:57:04 -07:00 @@ -87,3 +87,4 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP6312 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff -Nru a/drivers/scsi/qla2xxx/ql6322.c b/drivers/scsi/qla2xxx/ql6322.c --- a/drivers/scsi/qla2xxx/ql6322.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/scsi/qla2xxx/ql6322.c 2004-10-18 14:57:03 -07:00 @@ -105,3 +105,4 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP6322 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff -Nru a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c --- a/drivers/scsi/qla2xxx/qla_init.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/scsi/qla2xxx/qla_init.c 2004-10-18 14:57:03 -07:00 @@ -783,7 +783,6 @@ static void qla2x00_update_fw_options(scsi_qla_host_t *ha) { - /* Setup seriallink options */ uint16_t swing, emphasis; memset(ha->fw_options, 0, sizeof(ha->fw_options)); @@ -807,7 +806,6 @@ emphasis = ha->fw_seriallink_options[0] & (BIT_4 | BIT_3); emphasis >>= 3; ha->fw_options[10] = (emphasis << 14) | (swing << 8) | 0x3; - /* 2G settings */ swing = ha->fw_seriallink_options[0] & (BIT_7 | BIT_6 | BIT_5); swing >>= 5; @@ -818,7 +816,7 @@ /* Return command IOCBs without waiting for an ABTS to complete. */ ha->fw_options[3] |= BIT_13; - /* Update Serial Link options. */ + /* Update firmware options. */ qla2x00_set_fw_options(ha, ha->fw_options); } @@ -843,7 +841,7 @@ /* Clear outstanding commands array. */ for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) - ha->outstanding_cmds[cnt] = 0; + ha->outstanding_cmds[cnt] = NULL; ha->current_outstanding_cmd = 0; @@ -869,15 +867,15 @@ spin_unlock_irqrestore(&ha->hardware_lock, flags); + /* Update any ISP specific firmware options before initialization. */ + qla2x00_update_fw_options(ha); + DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); rval = qla2x00_init_firmware(ha, sizeof(init_cb_t)); if (rval) { DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n", ha->host_no)); } else { - /* Update any ISP specific firmware options. */ - qla2x00_update_fw_options(ha); - DEBUG3(printk("scsi(%ld): Init firmware -- success.\n", ha->host_no)); } @@ -4133,7 +4131,7 @@ for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { sp = ha->outstanding_cmds[cnt]; if (sp) { - ha->outstanding_cmds[cnt] = 0; + ha->outstanding_cmds[cnt] = NULL; if (ha->actthreads) ha->actthreads--; sp->lun_queue->out_cnt--; diff -Nru a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c --- a/drivers/scsi/qla2xxx/qla_iocb.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/scsi/qla2xxx/qla_iocb.c 2004-10-18 14:56:33 -07:00 @@ -22,6 +22,8 @@ #include #include +#include + static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); @@ -337,6 +339,7 @@ uint16_t req_cnt; uint16_t tot_dsds; device_reg_t *reg; + char tag[2]; /* Setup device pointers. */ ret = 0; @@ -415,14 +418,17 @@ cmd_pkt->lun = cpu_to_le16(fclun->lun); /* Update tagged queuing modifier */ - cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG); - if (cmd->device->tagged_supported) { - switch (cmd->tag) { - case HEAD_OF_QUEUE_TAG: + if (scsi_populate_tag_msg(cmd, tag)) { + switch (tag[0]) { + case MSG_SIMPLE_TAG: + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_SIMPLE_TAG); + break; + case MSG_HEAD_TAG: cmd_pkt->control_flags = __constant_cpu_to_le16(CF_HEAD_TAG); break; - case ORDERED_QUEUE_TAG: + case MSG_ORDERED_TAG: cmd_pkt->control_flags = __constant_cpu_to_le16(CF_ORDERED_TAG); break; diff -Nru a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c --- a/drivers/scsi/qla2xxx/qla_os.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/qla2xxx/qla_os.c 2004-10-18 14:57:04 -07:00 @@ -1663,7 +1663,7 @@ goto out; /* Waiting for our command in done_queue to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(ha)) + if (!qla2x00_eh_wait_for_pending_commands(ha)) rval = FAILED; out: @@ -1784,7 +1784,7 @@ ql2xmaxqdepth = queue_depth; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + scsi_activate_tcq(sdev, queue_depth); qla_printk(KERN_INFO, ha, "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue " @@ -3590,7 +3590,7 @@ { srb_t *sp; - sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); + sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); if (sp) atomic_set(&sp->ref_count, 1); return (sp); @@ -4517,3 +4517,4 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff -Nru a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h --- a/drivers/scsi/qla2xxx/qla_version.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/scsi/qla2xxx/qla_version.h 2004-10-18 14:56:29 -07:00 @@ -19,9 +19,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.00.00b14-k" +#define QLA2XXX_VERSION "8.00.00b15-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 0 #define QLA_DRIVER_PATCH_VER 0 -#define QLA_DRIVER_BETA_VER 14 +#define QLA_DRIVER_BETA_VER 15 diff -Nru a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c --- a/drivers/scsi/qlogicpti.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/scsi/qlogicpti.c 2004-10-18 14:56:48 -07:00 @@ -987,7 +987,7 @@ static char buf[80]; struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %lx", + sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %p", __irq_itoa(qpti->qhost->irq), qpti->qregs); return buf; } diff -Nru a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h --- a/drivers/scsi/qlogicpti.h 2004-10-18 14:55:55 -07:00 +++ b/drivers/scsi/qlogicpti.h 2004-10-18 14:55:55 -07:00 @@ -335,7 +335,7 @@ /* Software state for the driver. */ struct qlogicpti { /* These are the hot elements in the cache, so they come first. */ - unsigned long qregs; /* Adapter registers */ + void __iomem *qregs; /* Adapter registers */ struct pti_queue_entry *res_cpu; /* Ptr to RESPONSE bufs (CPU) */ struct pti_queue_entry *req_cpu; /* Ptr to REQUEST bufs (CPU) */ @@ -370,7 +370,7 @@ struct host_param host_param; struct dev_param dev_param[MAX_TARGETS]; - unsigned long sreg; + void __iomem *sreg; #define SREG_TPOWER 0x80 /* State of termpwr */ #define SREG_FUSE 0x40 /* State of on board fuse */ #define SREG_PDISAB 0x20 /* Disable state for power on */ diff -Nru a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c --- a/drivers/scsi/sata_nv.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/scsi/sata_nv.c 2004-10-18 14:56:17 -07:00 @@ -20,6 +20,10 @@ * If you do not delete the provisions above, a recipient may use your * version of this file under either the OSL or the GPL. * + * 0.03 + * - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using + * mmio_base, which is only set for the CK804/MCP04 case. + * * 0.02 * - Added support for CK804 SATA controller. * @@ -40,13 +44,12 @@ #include #define DRV_NAME "sata_nv" -#define DRV_VERSION "0.02" +#define DRV_VERSION "0.03" #define NV_PORTS 2 #define NV_PIO_MASK 0x1f +#define NV_MWDMA_MASK 0x07 #define NV_UDMA_MASK 0x7f -#define NV_PORT0_BMDMA_REG_OFFSET 0x00 -#define NV_PORT1_BMDMA_REG_OFFSET 0x08 #define NV_PORT0_SCR_REG_OFFSET 0x00 #define NV_PORT1_SCR_REG_OFFSET 0x40 @@ -177,11 +180,12 @@ static Scsi_Host_Template nv_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = ATA_MAX_PRD, + .sg_tablesize = LIBATA_MAX_PRD, .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, @@ -194,13 +198,14 @@ static struct ata_port_operations nv_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .exec_command = ata_exec_command_pio, - .check_status = ata_check_status_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -213,6 +218,18 @@ .host_stop = nv_host_stop, }; +static struct ata_port_info nv_port_info = { + .sht = &nv_sht, + .host_flags = ATA_FLAG_SATA | + ATA_FLAG_SATA_RESET | + ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_ops, +}; + MODULE_AUTHOR("NVIDIA"); MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller"); MODULE_LICENSE("GPL"); @@ -293,6 +310,7 @@ { static int printed_version = 0; struct nv_host *host; + struct ata_port_info *ppi; struct ata_probe_ent *probe_ent = NULL; int rc; @@ -314,7 +332,8 @@ if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &nv_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; @@ -328,39 +347,6 @@ host->host_desc = &nv_device_tbl[ent->driver_data]; - memset(probe_ent, 0, sizeof(*probe_ent)); - INIT_LIST_HEAD(&probe_ent->node); - - probe_ent->pdev = pdev; - probe_ent->sht = &nv_sht; - probe_ent->host_flags = ATA_FLAG_SATA | - ATA_FLAG_SATA_RESET | - ATA_FLAG_SRST | - ATA_FLAG_NO_LEGACY; - - probe_ent->port_ops = &nv_ops; - probe_ent->n_ports = NV_PORTS; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - probe_ent->pio_mask = NV_PIO_MASK; - probe_ent->udma_mask = NV_UDMA_MASK; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = - pci_resource_start(pdev, 4) | NV_PORT0_BMDMA_REG_OFFSET; - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = - pci_resource_start(pdev, 4) | NV_PORT1_BMDMA_REG_OFFSET; - probe_ent->private_data = host; if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) { @@ -369,7 +355,7 @@ probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); if (probe_ent->mmio_base == NULL) - goto err_out_free_ent; + goto err_out_iounmap; base = (unsigned long)probe_ent->mmio_base; @@ -393,12 +379,16 @@ rc = ata_device_add(probe_ent); if (rc != NV_PORTS) - goto err_out_free_ent; + goto err_out_iounmap; kfree(probe_ent); return 0; +err_out_iounmap: + if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) + iounmap(probe_ent->mmio_base); + err_out_free_ent: kfree(probe_ent); @@ -415,33 +405,33 @@ u8 intr_mask; outb(NV_INT_STATUS_HOTPLUG, - (unsigned long)probe_ent->mmio_base + NV_INT_STATUS); + probe_ent->port[0].scr_addr + NV_INT_STATUS); - intr_mask = inb((unsigned long)probe_ent->mmio_base + NV_INT_ENABLE); + intr_mask = inb(probe_ent->port[0].scr_addr + NV_INT_ENABLE); intr_mask |= NV_INT_ENABLE_HOTPLUG; - outb(intr_mask, (unsigned long)probe_ent->mmio_base + NV_INT_ENABLE); + outb(intr_mask, probe_ent->port[0].scr_addr + NV_INT_ENABLE); } static void nv_disable_hotplug(struct ata_host_set *host_set) { u8 intr_mask; - intr_mask = inb((unsigned long)host_set->mmio_base + NV_INT_ENABLE); + intr_mask = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); - outb(intr_mask, (unsigned long)host_set->mmio_base + NV_INT_ENABLE); + outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); } static void nv_check_hotplug(struct ata_host_set *host_set) { u8 intr_status; - intr_status = inb((unsigned long)host_set->mmio_base + NV_INT_STATUS); + intr_status = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); // Clear interrupt status. - outb(0xff, (unsigned long)host_set->mmio_base + NV_INT_STATUS); + outb(0xff, host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); if (intr_status & NV_INT_STATUS_HOTPLUG) { if (intr_status & NV_INT_STATUS_PDEV_ADDED) diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/scsi/sata_promise.c 2004-10-18 14:56:48 -07:00 @@ -74,7 +74,6 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); @@ -83,14 +82,13 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static void pdc_irq_clear(struct ata_port *ap); static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -109,9 +107,10 @@ static struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, .phy_reset = pdc_phy_reset, .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, @@ -130,7 +129,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -140,7 +140,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -269,26 +270,26 @@ VPRINTK("ENTER\n"); - ata_qc_prep(qc); - - i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + ata_qc_prep(qc); + /* fall through */ - if (qc->tf.flags & ATA_TFLAG_LBA48) - i = pdc_prep_lba48(&qc->tf, pp->pkt, i); - else - i = pdc_prep_lba28(&qc->tf, pp->pkt, i); + case ATA_PROT_NODATA: + i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, + qc->dev->devno, pp->pkt); - pdc_pkt_footer(&qc->tf, pp->pkt, i); -} + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, pp->pkt, i); + else + i = pdc_prep_lba28(&qc->tf, pp->pkt, i); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; + pdc_pkt_footer(&qc->tf, pp->pkt, i); + break; - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); + default: + break; + } } static void pdc_eng_timeout(struct ata_port *ap) @@ -315,17 +316,9 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -358,13 +351,8 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_complete(ap, qc, have_err); - handled = 1; - break; - - case ATA_PROT_NODATA: /* command completion, but no data xfer */ - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + case ATA_PROT_NODATA: + status = ata_wait_idle(ap); if (have_err) status |= ATA_ERR; ata_qc_complete(qc, status); @@ -440,7 +428,7 @@ return IRQ_RETVAL(handled); } -static inline void pdc_dma_start(struct ata_queued_cmd *qc) +static inline void pdc_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; @@ -462,7 +450,8 @@ { switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_start(qc); + case ATA_PROT_NODATA: + pdc_packet_start(qc); return 0; case ATA_PROT_ATAPI_DMA: @@ -478,15 +467,17 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - WARN_ON (tf->protocol == ATA_PROT_DMA); - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - WARN_ON (tf->protocol == ATA_PROT_DMA); - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command(ap, tf); } @@ -539,8 +530,7 @@ writel(tmp, mmio + PDC_TBG_MODE); readl(mmio + PDC_TBG_MODE); /* flush */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(10) + 1); + msleep(10); /* adjust slew rate control register. */ tmp = readl(mmio + PDC_SLEW_CTL); @@ -601,6 +591,7 @@ probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; diff -Nru a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c --- a/drivers/scsi/sata_sil.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/scsi/sata_sil.c 2004-10-18 14:55:53 -07:00 @@ -6,7 +6,7 @@ * on emails. * * Copyright 2003 Red Hat, Inc. - * Copyright 2003 Benjamin Herrenschmidt + * Copyright 2003 Benjamin Herrenschmidt * * The contents of this file are subject to the Open * Software License version 1.1 that can be found at @@ -106,6 +106,7 @@ static Scsi_Host_Template sil_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -124,14 +125,15 @@ static struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, - .tf_load = ata_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, - .exec_command = ata_exec_command_mmio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, .post_set_mode = sil_post_set_mode, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -149,7 +151,8 @@ .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, /* sil_3114 */ @@ -157,7 +160,8 @@ .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, @@ -363,6 +367,7 @@ probe_ent->sht = sil_port_info[ent->driver_data].sht; probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2; probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask; + probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask; probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; diff -Nru a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c --- a/drivers/scsi/sata_sis.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/scsi/sata_sis.c 2004-10-18 14:56:32 -07:00 @@ -76,6 +76,7 @@ static Scsi_Host_Template sis_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -93,13 +94,14 @@ static struct ata_port_operations sis_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -111,6 +113,16 @@ .port_stop = ata_port_stop, }; +static struct ata_port_info sis_port_info = { + .sht = &sis_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | + ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, + .mwdma_mask = 0x7, + .udma_mask = 0x7f, + .port_ops = &sis_ops, +}; + MODULE_AUTHOR("Uwe Koziolek"); MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller"); @@ -184,6 +196,7 @@ struct ata_probe_ent *probe_ent = NULL; int rc; u32 genctl; + struct ata_port_info *ppi; rc = pci_enable_device(pdev); if (rc) @@ -200,20 +213,13 @@ if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &sis_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - probe_ent->pdev = pdev; - INIT_LIST_HEAD(&probe_ent->node); - - probe_ent->sht = &sis_sht; - probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | - ATA_FLAG_NO_LEGACY; - /* check and see if the SCRs are in IO space or PCI cfg space */ pci_read_config_dword(pdev, SIS_GENCTL, &genctl); if ((genctl & GENCTL_IOMAPPED_SCR) == 0) @@ -230,31 +236,12 @@ probe_ent->host_flags |= SIS_FLAG_CFGSCR; } - probe_ent->pio_mask = 0x03; - probe_ent->udma_mask = 0x7f; - probe_ent->port_ops = &sis_ops; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) + if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) { probe_ent->port[0].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) probe_ent->port[1].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64; - - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; + } pci_set_master(pdev); pci_enable_intx(pdev); @@ -284,6 +271,6 @@ pci_unregister_driver(&sis_pci_driver); } - module_init(sis_init); module_exit(sis_exit); + diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c --- a/drivers/scsi/sata_svw.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/scsi/sata_svw.c 2004-10-18 14:56:33 -07:00 @@ -148,7 +148,73 @@ } } +/** + * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO) + * @qc: Info associated with this ATA transaction. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ + +void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + void *mmio = (void *) ap->ioaddr.bmdma_addr; + /* load PRD table addr. */ + mb(); /* make sure PRD table writes are visible to controller */ + writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = readb(mmio + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + writeb(dmactl, mmio + ATA_DMA_CMD); + + /* issue r/w command if this is not a ATA DMA command*/ + if (qc->tf.protocol != ATA_PROT_DMA) + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO) + * @qc: Info associated with this ATA transaction. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void *mmio = (void *) ap->ioaddr.bmdma_addr; + u8 dmactl; + + /* start host DMA transaction */ + dmactl = readb(mmio + ATA_DMA_CMD); + writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); + /* There is a race condition in certain SATA controllers that can + be seen when the r/w command is given to the controller before the + host DMA is started. On a Read command, the controller would initiate + the command to the drive even before it sees the DMA start. When there + are very fast drives connected to the controller, or when the data request + hits in the drive cache, there is the possibility that the drive returns a part + or all of the requested data to the controller before the DMA start is issued. + In this case, the controller would become confused as to what to do with the data. + In the worst case when all the data is returned back to the controller, the + controller could hang. In other cases it could return partial data returning + in data corruption. This problem has been seen in PPC systems and can also appear + on an system with very fast disks, where the SATA controller is sitting behind a + number of bridges, and hence there is significant latency between the r/w command + and the start command. */ + /* issue r/w command if the access is to ATA*/ + if (qc->tf.protocol == ATA_PROT_DMA) + ap->ops->exec_command(ap, &qc->tf); +} + + static u8 k2_stat_check_status(struct ata_port *ap) { return readl((void *) ap->ioaddr.status_addr); @@ -205,6 +271,7 @@ static Scsi_Host_Template k2_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -229,10 +296,11 @@ .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, - .exec_command = ata_exec_command_mmio, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, + .bmdma_setup = k2_bmdma_setup_mmio, + .bmdma_start = k2_bmdma_start_mmio, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -343,6 +411,7 @@ * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ @@ -371,6 +440,8 @@ static struct pci_device_id k2_sata_pci_tbl[] = { { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { } }; @@ -387,6 +458,7 @@ { return pci_module_init(&k2_sata_pci_driver); } + static void __exit k2_sata_exit(void) { diff -Nru a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c --- a/drivers/scsi/sata_sx4.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/scsi/sata_sx4.c 2004-10-18 14:55:53 -07:00 @@ -146,8 +146,6 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc20621_dma_setup(struct ata_queued_cmd *qc); -static void pdc20621_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); @@ -157,8 +155,6 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, @@ -172,11 +168,13 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); static void pdc20621_irq_clear(struct ata_port *ap); +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -195,14 +193,13 @@ static struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, .phy_reset = pdc_20621_phy_reset, - .bmdma_setup = pdc20621_dma_setup, - .bmdma_start = pdc20621_dma_start, .qc_prep = pdc20621_qc_prep, - .qc_issue = ata_qc_issue_prot, + .qc_issue = pdc20621_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, .irq_clear = pdc20621_irq_clear, @@ -217,7 +214,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_20621_ops, }, @@ -377,7 +375,10 @@ /* dimm dma S/G, and next-pkt */ dw = i >> 2; - buf32[dw] = cpu_to_le32(dimm_sg); + if (tf->protocol == ATA_PROT_NODATA) + buf32[dw] = 0; + else + buf32[dw] = cpu_to_le32(dimm_sg); buf32[dw + 1] = 0; i += 8; @@ -437,7 +438,7 @@ buf32[dw + 3]); } -static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +static void pdc20621_dma_prep(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -449,8 +450,7 @@ unsigned int i, last, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; - if (!(qc->flags & ATA_QCFLAG_DMAMAP)) - return; + assert(qc->flags & ATA_QCFLAG_DMAMAP); VPRINTK("ata%u: ENTER\n", ap->id); @@ -501,6 +501,56 @@ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); } +static void pdc20621_nodata_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pdc_port_priv *pp = ap->private_data; + void *mmio = ap->host_set->mmio_base; + struct pdc_host_priv *hpriv = ap->host_set->private_data; + void *dimm_mmio = hpriv->dimm_mmio; + unsigned int portno = ap->port_no; + unsigned int i; + + VPRINTK("ata%u: ENTER\n", ap->id); + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno); + + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i); + else + i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i); + + pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i); + + /* copy three S/G tables and two packets to DIMM MMIO window */ + memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP), + &pp->dimm_buf, PDC_DIMM_HEADER_SZ); + + /* force host FIFO dump */ + writel(0x00000001, mmio + PDC_20621_GENERAL_CTL); + + readl(dimm_mmio); /* MMIO PCI posting flush */ + + VPRINTK("ata pkt buf ofs %u, mmio copied\n", i); +} + +static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pdc20621_dma_prep(qc); + break; + case ATA_PROT_NODATA: + pdc20621_nodata_prep(qc); + break; + default: + break; + } +} + static void __pdc20621_push_hdma(struct ata_queued_cmd *qc, unsigned int seq, u32 pkt_ofs) @@ -576,13 +626,7 @@ static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { } #endif /* ATA_VERBOSE_DEBUG */ -static void pdc20621_dma_setup(struct ata_queued_cmd *qc) -{ - /* nothing for now. later, we will call standard - * code in libata-core for ATAPI here */ -} - -static void pdc20621_dma_start(struct ata_queued_cmd *qc) +static void pdc20621_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; @@ -590,24 +634,21 @@ void *mmio = host_set->mmio_base; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); - unsigned int doing_hdma = 0, port_ofs; + unsigned int port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; VPRINTK("ata%u: ENTER\n", ap->id); + wmb(); /* flush PRD, pkt writes */ + port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no); /* if writing, we (1) DMA to DIMM, then (2) do ATA command */ - if (rw) { - doing_hdma = 1; + if (rw && qc->tf.protocol == ATA_PROT_DMA) { seq += 4; - } - - wmb(); /* flush PRD, pkt writes */ - if (doing_hdma) { pdc20621_dump_hdma(qc); pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT); VPRINTK("queued ofs 0x%x (%u), seq %u\n", @@ -628,6 +669,25 @@ } } +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + pdc20621_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + return ata_qc_issue_prot(qc); +} + static inline unsigned int pdc20621_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc, unsigned int doing_hdma, @@ -648,7 +708,8 @@ if (doing_hdma) { VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } @@ -685,7 +746,8 @@ else { VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } handled = 1; @@ -779,16 +841,6 @@ return IRQ_RETVAL(handled); } -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; - - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); -} - static void pdc_eng_timeout(struct ata_port *ap) { u8 drv_stat; @@ -813,17 +865,9 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -842,15 +886,17 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command(ap, tf); } @@ -1384,6 +1430,7 @@ probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; @@ -1394,21 +1441,11 @@ probe_ent->private_data = hpriv; base += PDC_CHIP0_OFS; + probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); pdc_sata_setup_port(&probe_ent->port[1], base + 0x280); - - /* notice 4-port boards */ - switch (board_idx) { - case board_20621: - probe_ent->n_ports = 4; - - pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); - pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); - break; - default: - BUG(); - break; - } + pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); + pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); pci_set_master(pdev); diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c --- a/drivers/scsi/sata_via.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/scsi/sata_via.c 2004-10-18 14:56:17 -07:00 @@ -81,6 +81,7 @@ static Scsi_Host_Template svia_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -99,15 +100,16 @@ static struct ata_port_operations svia_sata_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -123,6 +125,15 @@ .port_stop = ata_port_stop, }; +static struct ata_port_info svia_port_info = { + .sht = &svia_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + .port_ops = &svia_sata_ops, +}; + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); MODULE_LICENSE("GPL"); @@ -156,6 +167,7 @@ static int printed_version; unsigned int i; int rc; + struct ata_port_info *ppi; struct ata_probe_ent *probe_ent; u8 tmp8; @@ -196,41 +208,17 @@ if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &svia_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", pci_name(pdev)); rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - INIT_LIST_HEAD(&probe_ent->node); - probe_ent->pdev = pdev; - probe_ent->sht = &svia_sht; - probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | - ATA_FLAG_NO_LEGACY; - probe_ent->port_ops = &svia_sata_ops; - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + probe_ent->port[0].scr_addr = svia_scr_addr(pci_resource_start(pdev, 5), 0); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; probe_ent->port[1].scr_addr = svia_scr_addr(pci_resource_start(pdev, 5), 1); diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c --- a/drivers/scsi/sata_vsc.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/scsi/sata_vsc.c 2004-10-18 14:56:32 -07:00 @@ -190,6 +190,7 @@ static Scsi_Host_Template vsc_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -210,11 +211,12 @@ .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, - .exec_command = ata_exec_command_mmio, - .check_status = ata_check_status_mmio, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -320,6 +322,7 @@ * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/scsi/scsi.c 2004-10-18 14:56:32 -07:00 @@ -897,15 +897,16 @@ */ if (tags <= 0) return; - /* - * Limit max queue depth on a single lun to 256 for now. Remember, - * we allocate a struct scsi_command for each of these and keep it - * around forever. Too deep of a depth just wastes memory. - */ - if (tags > 256) - return; spin_lock_irqsave(&device_request_lock, flags); + spin_lock(sdev->request_queue->queue_lock); + + /* Check to see if the queue is managed by the block layer + * if it is, and we fail to adjust the depth, exit */ + if (blk_queue_tagged(sdev->request_queue) && + blk_queue_resize_tags(sdev->request_queue, tags) != 0) + goto out; + sdev->queue_depth = tags; switch (tagged) { case MSG_ORDERED_TAG: @@ -926,6 +927,8 @@ sdev->queue_depth = tags; break; } + out: + spin_unlock(sdev->request_queue->queue_lock); spin_unlock_irqrestore(&device_request_lock, flags); } diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/scsi/scsi_error.c 2004-10-18 14:55:54 -07:00 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -42,8 +42,8 @@ * These should *probably* be handled by the host itself. * Since it is allowed to sleep, it probably should. */ -#define BUS_RESET_SETTLE_TIME (10*HZ) -#define HOST_RESET_SETTLE_TIME (10*HZ) +#define BUS_RESET_SETTLE_TIME (10) +#define HOST_RESET_SETTLE_TIME (10) /* called with shost->host_lock held */ void scsi_eh_wakeup(struct Scsi_Host *shost) @@ -643,15 +643,13 @@ * Notes: * This has the unfortunate side effect that if a shost adapter does * not automatically request sense information, that we end up shutting - * it down before we request it. All shosts should be doing this - * anyways, so for now all I have to say is tough noogies if you end up - * in here. On second thought, this is probably a good idea. We - * *really* want to give authors an incentive to automatically request - * this. + * it down before we request it. * - * In 2.5 this capability will be going away. + * All drivers should request sense information internally these days, + * so for now all I have to say is tough noogies if you end up in here. * - * Really? --hch + * XXX: Long term this code should go away, but that needs an audit of + * all LLDDs first. **/ static int scsi_eh_get_sense(struct list_head *work_q, struct list_head *done_q) @@ -1044,7 +1042,7 @@ if (rtn == SUCCESS) { if (!scmd->device->host->hostt->skip_settle_delay) - scsi_sleep(BUS_RESET_SETTLE_TIME); + ssleep(BUS_RESET_SETTLE_TIME); spin_lock_irqsave(scmd->device->host->host_lock, flags); scsi_report_bus_reset(scmd->device->host, scmd->device->channel); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); @@ -1076,7 +1074,7 @@ if (rtn == SUCCESS) { if (!scmd->device->host->hostt->skip_settle_delay) - scsi_sleep(HOST_RESET_SETTLE_TIME); + ssleep(HOST_RESET_SETTLE_TIME); spin_lock_irqsave(scmd->device->host->host_lock, flags); scsi_report_bus_reset(scmd->device->host, scmd->device->channel); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); @@ -1216,43 +1214,6 @@ } /** - * scsi_sleep_done - timer function for scsi_sleep - * @sem: semphore to signal - * - **/ -static void scsi_sleep_done(unsigned long data) -{ - struct semaphore *sem = (struct semaphore *)data; - - if (sem) - up(sem); -} - -/** - * scsi_sleep - sleep for specified timeout - * @timeout: timeout value - * - **/ -void scsi_sleep(int timeout) -{ - DECLARE_MUTEX_LOCKED(sem); - struct timer_list timer; - - init_timer(&timer); - timer.data = (unsigned long)&sem; - timer.expires = jiffies + timeout; - timer.function = (void (*)(unsigned long))scsi_sleep_done; - - SCSI_LOG_ERROR_RECOVERY(5, printk("sleeping for timer tics %d\n", - timeout)); - - add_timer(&timer); - - down(&sem); - del_timer(&timer); -} - -/** * scsi_decide_disposition - Disposition a cmd on return from LLD. * @scmd: SCSI cmd to examine. * @@ -1639,8 +1600,6 @@ int rtn; DECLARE_MUTEX_LOCKED(sem); - lock_kernel(); - /* * Flush resources */ @@ -1651,8 +1610,6 @@ shost->eh_wait = &sem; shost->ehandler = current; - - unlock_kernel(); /* * Wake up the thread that created us. diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c --- a/drivers/scsi/scsi_ioctl.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/scsi_ioctl.c 2004-10-18 14:57:04 -07:00 @@ -391,6 +391,21 @@ if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; + /* Check for deprecated ioctls ... all the ioctls which don't + * follow the new unique numbering scheme are deprecated */ + switch (cmd) { + case SCSI_IOCTL_SEND_COMMAND: + case SCSI_IOCTL_TEST_UNIT_READY: + case SCSI_IOCTL_BENCHMARK_COMMAND: + case SCSI_IOCTL_SYNC: + case SCSI_IOCTL_START_UNIT: + case SCSI_IOCTL_STOP_UNIT: + printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); + break; + default: + break; + } + switch (cmd) { case SCSI_IOCTL_GET_IDLUN: if (verify_area(VERIFY_WRITE, arg, sizeof(struct scsi_idlun))) @@ -417,12 +432,8 @@ case SCSI_IOCTL_DOORUNLOCK: return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); case SCSI_IOCTL_TEST_UNIT_READY: - scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = 0; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = 0; - return ioctl_internal_command(sdev, scsi_cmd, - IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); + return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT, + NORMAL_RETRIES); case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; scsi_cmd[1] = 0; diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/scsi/scsi_lib.c 2004-10-18 14:56:32 -07:00 @@ -954,6 +954,22 @@ return BLKPREP_KILL; } +static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct scsi_device *sdev = q->queuedata; + struct scsi_driver *drv; + + if (sdev->sdev_state != SDEV_RUNNING) + return -ENXIO; + + drv = *(struct scsi_driver **) disk->private_data; + if (drv->issue_flush) + return drv->issue_flush(&sdev->sdev_gendev, error_sector); + + return -EOPNOTSUPP; +} + static int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device *sdev = q->queuedata; @@ -1335,7 +1351,8 @@ blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); - + blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); + if (!shost->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); return q; @@ -1554,6 +1571,34 @@ return ret; } + +int +scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) +{ + struct scsi_request *sreq; + char cmd[] = { + TEST_UNIT_READY, 0, 0, 0, 0, 0, + }; + int result; + + sreq = scsi_allocate_request(sdev, GFP_KERNEL); + if (!sreq) + return -ENOMEM; + + sreq->sr_data_direction = DMA_NONE; + scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); + + if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && + (sreq->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION && + sdev->removable) { + sdev->changed = 1; + sreq->sr_result = 0; + } + result = sreq->sr_result; + scsi_release_request(sreq); + return result; +} +EXPORT_SYMBOL(scsi_test_unit_ready); /** * scsi_device_set_state - Take the given device through the device diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/scsi/scsi_scan.c 2004-10-18 14:56:49 -07:00 @@ -200,7 +200,7 @@ * scsi_Device pointer, or NULL on failure. **/ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, - uint channel, uint id, uint lun) + uint channel, uint id, uint lun, void *hostdata) { struct scsi_device *sdev, *device; unsigned long flags; @@ -224,6 +224,8 @@ INIT_LIST_HEAD(&sdev->starved_entry); spin_lock_init(&sdev->list_lock); + /* usually NULL and set by ->slave_alloc instead */ + sdev->hostdata = hostdata; /* if the device needs this changing, it may do so in the * slave_configure function */ @@ -697,7 +699,7 @@ **/ static int scsi_probe_and_add_lun(struct Scsi_Host *host, uint channel, uint id, uint lun, int *bflagsp, - struct scsi_device **sdevp, int rescan) + struct scsi_device **sdevp, int rescan, void *hostdata) { struct scsi_device *sdev; struct scsi_request *sreq; @@ -726,7 +728,7 @@ } } - sdev = scsi_alloc_sdev(host, channel, id, lun); + sdev = scsi_alloc_sdev(host, channel, id, lun, hostdata); if (!sdev) goto out; sreq = scsi_allocate_request(sdev, GFP_ATOMIC); @@ -874,7 +876,7 @@ */ for (lun = 1; lun < max_dev_lun; ++lun) if ((scsi_probe_and_add_lun(shost, channel, id, lun, - NULL, NULL, rescan) != SCSI_SCAN_LUN_PRESENT) && + NULL, NULL, rescan, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun) return; } @@ -1085,7 +1087,7 @@ int res; res = scsi_probe_and_add_lun(sdev->host, sdev->channel, - sdev->id, lun, NULL, NULL, rescan); + sdev->id, lun, NULL, NULL, rescan, NULL); if (res == SCSI_SCAN_NO_RESPONSE) { /* * Got some results, but now none, abort. @@ -1111,14 +1113,15 @@ return 0; } -struct scsi_device *scsi_add_device(struct Scsi_Host *shost, - uint channel, uint id, uint lun) +struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, + uint id, uint lun, void *hostdata) { struct scsi_device *sdev; int res; down(&shost->scan_mutex); - res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev, 1); + res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, + &sdev, 1, hostdata); if (res != SCSI_SCAN_LUN_PRESENT) sdev = ERR_PTR(-ENODEV); up(&shost->scan_mutex); @@ -1178,7 +1181,7 @@ * Scan for a specific host/chan/id/lun. */ scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL, - rescan); + rescan, NULL); return; } @@ -1187,7 +1190,7 @@ * would not configure LUN 0 until all LUNs are scanned. */ res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev, - rescan); + rescan, NULL); if (res == SCSI_SCAN_LUN_PRESENT) { if (scsi_report_lun_scan(sdev, bflags, rescan) != 0) /* @@ -1316,7 +1319,7 @@ { struct scsi_device *sdev; - sdev = scsi_alloc_sdev(shost, 0, shost->this_id, 0); + sdev = scsi_alloc_sdev(shost, 0, shost->this_id, 0, NULL); if (sdev) { sdev->borken = 0; } diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c --- a/drivers/scsi/scsi_syms.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/scsi/scsi_syms.c 2004-10-18 14:56:31 -07:00 @@ -69,11 +69,9 @@ EXPORT_SYMBOL(scsi_get_host_dev); EXPORT_SYMBOL(scsi_free_host_dev); -EXPORT_SYMBOL(scsi_sleep); - EXPORT_SYMBOL(scsi_io_completion); -EXPORT_SYMBOL(scsi_add_device); +EXPORT_SYMBOL(__scsi_add_device); EXPORT_SYMBOL(scsi_remove_device); EXPORT_SYMBOL(scsi_device_cancel); diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/scsi/scsi_sysfs.c 2004-10-18 14:56:17 -07:00 @@ -525,8 +525,11 @@ **/ void scsi_remove_device(struct scsi_device *sdev) { + struct Scsi_Host *shost = sdev->host; + + down(&shost->scan_mutex); if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) - return; + goto out; class_device_unregister(&sdev->sdev_classdev); if (sdev->transport_classdev.class) @@ -538,6 +541,9 @@ if (sdev->host->transportt->cleanup) sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); + +out: + up(&shost->scan_mutex); } int scsi_register_driver(struct device_driver *drv) diff -Nru a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c --- a/drivers/scsi/scsiiom.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/scsi/scsiiom.c 2004-10-18 14:55:54 -07:00 @@ -213,8 +213,17 @@ } #endif + +static void __inline__ +dc390_InvalidCmd(struct dc390_acb* pACB) +{ + if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ | SRB_MSGOUT)) + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); +} + + static irqreturn_t __inline__ -DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct dc390_acb *pACB, *pACB2; struct dc390_dcb *pDCB; @@ -594,7 +603,7 @@ } /* abort command */ -static void __inline__ +static void dc390_EnableMsgOut_Abort ( struct dc390_acb* pACB, struct dc390_srb* pSRB ) { pSRB->MsgOutBuf[0] = ABORT; @@ -890,14 +899,22 @@ if (pSRB == pACB->pTmpSRB) { - if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", - pDCB->TargetID, pDCB->TargetLUN); - else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); - - pSRB->pSRBDCB = pDCB; - dc390_EnableMsgOut_Abort (pACB, pSRB); - if (pDCB) pDCB->DCBFlag |= ABORT_DEV; - return; + if (pDCB) + printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); + else + printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); + + /* Try to recover - some broken disks react badly to tagged INQUIRY */ + if (pDCB && pACB->scan_devices && pDCB->GoingSRBCnt == 1) { + pSRB = pDCB->pGoingSRB; + pDCB->pActiveSRB = pSRB; + } else { + pSRB->pSRBDCB = pDCB; + dc390_EnableMsgOut_Abort(pACB, pSRB); + if (pDCB) + pDCB->DCBFlag |= ABORT_DEV; + return; + } } if( pSRB->SGIndex < pSRB->SGcount ) @@ -1138,7 +1155,7 @@ } DC390_write8 (ScsiCmd, EN_SEL_RESEL); pSRB = pDCB->pActiveSRB; - pACB->pActiveDCB = 0; + pACB->pActiveDCB = NULL; pSRB->ScsiPhase = SCSI_NOP0; if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) { @@ -1158,7 +1175,7 @@ dc390_Free_insert (pACB, pSRB); pSRB = psrb; } - pDCB->pGoingSRB = 0; + pDCB->pGoingSRB = NULL; dc390_Waiting_process (pACB); } else @@ -1187,7 +1204,7 @@ { disc1: dc390_freetag (pDCB, pSRB); - pDCB->pActiveSRB = 0; + pDCB->pActiveSRB = NULL; pSRB->SRBState = SRB_FREE; dc390_SRBdone( pACB, pDCB, pSRB); } @@ -1325,6 +1342,35 @@ } +static void __inline__ +dc390_RequestSense(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB) +{ + struct scsi_cmnd *pcmd; + + pcmd = pSRB->pcmd; + + REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense(Cmd %02x, Id %02x, LUN %02x)\n",\ + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN)); + + pSRB->SRBFlag |= AUTO_REQSENSE; + pSRB->SavedSGCount = pcmd->use_sg; + pSRB->SavedTotXLen = pSRB->TotalXferredLen; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ + + /* We are called from SRBdone, original PCI mapping has been removed + * already, new one is set up from StartSCSI */ + pSRB->SGIndex = 0; + + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if (dc390_StartSCSI(pACB, pDCB, pSRB)) { + dc390_Going_to_Waiting(pDCB, pSRB); + dc390_waiting_timer(pACB, HZ/5); + } +} + + static void dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ) { @@ -1352,26 +1398,7 @@ pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; pSRB->TargetStatus = CHECK_CONDITION << 1; -#ifdef DC390_REMOVABLEDEBUG - switch (pcmd->sense_buffer[2] & 0x0f) - { - case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - } -#endif + //pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status); if (status == (CHECK_CONDITION << 1)) { @@ -1525,23 +1552,6 @@ pDCB->Inquiry7 = ptr->Flags; ckc_e: - if( pACB->scan_devices ) - { - if( pcmd->cmnd[0] == TEST_UNIT_READY || - pcmd->cmnd[0] == INQUIRY) - { -#ifdef DC390_DEBUG0 - printk (KERN_INFO "DC390: %s: result: %08x", - (pcmd->cmnd[0] == INQUIRY? "INQUIRY": "TEST_UNIT_READY"), - pcmd->result); - if (pcmd->result & (DRIVER_SENSE << 24)) printk (" (sense: %02x %02x %02x %02x)\n", - pcmd->sense_buffer[0], pcmd->sense_buffer[1], - pcmd->sense_buffer[2], pcmd->sense_buffer[3]); - else printk ("\n"); -#endif - } - } - if( pcmd->cmnd[0] == INQUIRY && (pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) ) { @@ -1586,18 +1596,6 @@ psrb2 = psrb->pNextSRB; pcmd = psrb->pcmd; dc390_Free_insert (pACB, psrb); -#ifndef USE_NEW_EH - /* New EH will crash on being given timed out cmnds */ - if (pcmd == cmd) - pcmd->result = MK_RES(0,DID_ABORT,0,0); - else - pcmd->result = MK_RES(0,DID_RESET,0,0); - -/* ReleaseSRB( pDCB, pSRB ); */ - - DEBUG0(printk (KERN_DEBUG "DC390: DoingSRB_Done: done pid %li\n", pcmd->pid)); - pcmd->scsi_done( pcmd ); -#endif psrb = psrb2; } pdcb->GoingSRBCnt = 0; @@ -1646,59 +1644,11 @@ pACB->ACBFlag |= RESET_DETECT; dc390_ResetDevParam( pACB ); - dc390_DoingSRB_Done( pACB, 0 ); + dc390_DoingSRB_Done( pACB, NULL ); //dc390_RecoverSRB( pACB ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; dc390_Waiting_process( pACB ); } return; -} - - -static void __inline__ -dc390_RequestSense( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ) -{ - struct scsi_cmnd *pcmd; - - pcmd = pSRB->pcmd; - - REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN)); - - pSRB->SRBFlag |= AUTO_REQSENSE; - //pSRB->Segment0[0] = (u32) pSRB->CmdBlock[0]; - //pSRB->Segment0[1] = (u32) pSRB->CmdBlock[4]; - //pSRB->Segment1[0] = ((u32)(pcmd->cmd_len) << 8) + pSRB->SGcount; - //pSRB->Segment1[1] = pSRB->TotalXferredLen; - pSRB->SavedSGCount = pcmd->use_sg; - pSRB->SavedTotXLen = pSRB->TotalXferredLen; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ - - /* We are called from SRBdone, original PCI mapping has been removed - * already, new one is set up from StartSCSI */ - pSRB->SGIndex = 0; - - //pSRB->CmdBlock[0] = REQUEST_SENSE; - //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5; - //(u16) pSRB->CmdBlock[2] = 0; - //(u16) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); - //pSRB->ScsiCmdLen = 6; - - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { - dc390_Going_to_Waiting ( pDCB, pSRB ); - dc390_waiting_timer (pACB, HZ/5); - } -} - - - -static void __inline__ -dc390_InvalidCmd( struct dc390_acb* pACB ) -{ - if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); } diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/scsi/sd.c 2004-10-18 14:56:49 -07:00 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -62,12 +63,18 @@ #include "scsi_logging.h" - /* - * Remaining dev_t-handling stuff + * More than enough for everybody ;) The huge number of majors + * is a leftover from 16bit dev_t days, we don't really need that + * much numberspace. */ #define SD_MAJORS 16 -#define SD_DISKS 32768 /* anything between 256 and 262144 */ + +/* + * This is limited by the naming scheme enforced in sd_probe, + * add another character to it if you really need more disks. + */ +#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) /* * Time out in seconds for disks and Magneto-opticals (which are slower). @@ -96,8 +103,7 @@ unsigned RCD : 1; /* state of disk RCD bit, unused */ }; - -static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; +static DEFINE_IDR(sd_index_idr); static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; /* This semaphore is used to mediate the 0->1 reference get in the @@ -113,6 +119,7 @@ static void sd_shutdown(struct device *dev); static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *); +static int sd_issue_flush(struct device *, sector_t *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer); @@ -126,9 +133,11 @@ }, .rescan = sd_rescan, .init_command = sd_init_command, + .issue_flush = sd_issue_flush, }; -/* Device no to disk mapping: +/* + * Device no to disk mapping: * * major disc2 disc p1 * |............|.............|....|....| <- dev_t @@ -141,7 +150,6 @@ * As we stay compatible with our numbering scheme, we can reuse * the well-know SCSI majors 8, 65--71, 136--143. */ - static int sd_major(int major_idx) { switch (major_idx) { @@ -157,14 +165,6 @@ } } -static unsigned int make_sd_dev(unsigned int sd_nr, unsigned int part) -{ - return (part & 0xf) | ((sd_nr & 0xf) << 4) | - (sd_major((sd_nr & 0xf0) >> 4) << 20) | (sd_nr & 0xfff00); -} - -/* reverse mapping dev -> (sd_nr, part) not currently needed */ - #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref) static inline struct scsi_disk *scsi_disk(struct gendisk *disk) @@ -180,16 +180,14 @@ if (disk->private_data == NULL) goto out; sdkp = scsi_disk(disk); - if (!kref_get(&sdkp->kref)) - goto out_sdkp; + kref_get(&sdkp->kref); if (scsi_device_get(sdkp->device)) goto out_put; up(&sd_ref_sem); return sdkp; out_put: - kref_put(&sdkp->kref); - out_sdkp: + kref_put(&sdkp->kref, scsi_disk_release); sdkp = NULL; out: up(&sd_ref_sem); @@ -200,7 +198,7 @@ { down(&sd_ref_sem); scsi_device_put(sdkp->device); - kref_put(&sdkp->kref); + kref_put(&sdkp->kref, scsi_disk_release); up(&sd_ref_sem); } @@ -648,7 +646,7 @@ */ retval = -ENODEV; if (scsi_block_when_processing_errors(sdp)) - retval = scsi_ioctl(sdp, SCSI_IOCTL_TEST_UNIT_READY, NULL); + retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); /* * Unable to test, unit probably not ready. This usually @@ -676,6 +674,62 @@ return 1; } +static int sd_sync_cache(struct scsi_device *sdp) +{ + struct scsi_request *sreq; + int retries, res; + + if (!scsi_device_online(sdp)) + return -ENODEV; + + sreq = scsi_allocate_request(sdp, GFP_KERNEL); + if (!sreq) { + printk("FAILED\n No memory for request\n"); + return -ENOMEM; + } + + sreq->sr_data_direction = DMA_NONE; + for (retries = 3; retries > 0; --retries) { + unsigned char cmd[10] = { 0 }; + + cmd[0] = SYNCHRONIZE_CACHE; + /* + * Leave the rest of the command zero to indicate + * flush everything. + */ + scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); + if (sreq->sr_result == 0) + break; + } + + res = sreq->sr_result; + if (res) { + printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + "host = %d, driver = %02x\n ", + status_byte(res), msg_byte(res), + host_byte(res), driver_byte(res)); + if (driver_byte(res) & DRIVER_SENSE) + scsi_print_req_sense("sd", sreq); + } + + scsi_release_request(sreq); + return res; +} + +static int sd_issue_flush(struct device *dev, sector_t *error_sector) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_disk *sdkp = dev_get_drvdata(dev); + + if (!sdkp) + return -ENODEV; + + if (!sdkp->WCE) + return 0; + + return sd_sync_cache(sdp); +} + static void sd_rescan(struct device *dev) { struct scsi_disk *sdkp = dev_get_drvdata(dev); @@ -1347,7 +1401,7 @@ struct scsi_disk *sdkp; struct gendisk *gd; u32 index; - int error, devno; + int error; error = -ENODEV; if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)) @@ -1362,27 +1416,23 @@ goto out; memset (sdkp, 0, sizeof(*sdkp)); - kref_init(&sdkp->kref, scsi_disk_release); + kref_init(&sdkp->kref); - /* Note: We can accomodate 64 partitions, but the genhd code - * assumes partitions allocate consecutive minors, which they don't. - * So for now stay with max 16 partitions and leave two spare bits. - * Later, we may change the genhd code and the alloc_disk() call - * and the ->minors assignment here. KG, 2004-02-10 - */ gd = alloc_disk(16); if (!gd) goto out_free; + if (!idr_pre_get(&sd_index_idr, GFP_KERNEL)) + goto out_put; + spin_lock(&sd_index_lock); - index = find_first_zero_bit(sd_index_bits, SD_DISKS); - if (index == SD_DISKS) { - spin_unlock(&sd_index_lock); + error = idr_get_new(&sd_index_idr, NULL, &index); + spin_unlock(&sd_index_lock); + + if (index >= SD_MAX_DISKS) error = -EBUSY; + if (error) goto out_put; - } - __set_bit(index, sd_index_bits); - spin_unlock(&sd_index_lock); sdkp->device = sdp; sdkp->driver = &sd_template; @@ -1397,15 +1447,14 @@ sdp->timeout = SD_MOD_TIMEOUT; } - devno = make_sd_dev(index, 0); - gd->major = MAJOR(devno); - gd->first_minor = MINOR(devno); + gd->major = sd_major((index & 0xf0) >> 4); + gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); gd->minors = 16; gd->fops = &sd_fops; if (index < 26) { sprintf(gd->disk_name, "sd%c", 'a' + index % 26); - } else if (index < (26*27)) { + } else if (index < (26 + 1) * 26) { sprintf(gd->disk_name, "sd%c%c", 'a' + index / 26 - 1,'a' + index % 26); } else { @@ -1464,7 +1513,7 @@ del_gendisk(sdkp->disk); sd_shutdown(dev); down(&sd_ref_sem); - kref_put(&sdkp->kref); + kref_put(&sdkp->kref, scsi_disk_release); up(&sd_ref_sem); return 0; @@ -1485,7 +1534,7 @@ struct gendisk *disk = sdkp->disk; spin_lock(&sd_index_lock); - clear_bit(sdkp->index, sd_index_bits); + idr_remove(&sd_index_idr, sdkp->index); spin_unlock(&sd_index_lock); disk->private_data = NULL; @@ -1503,52 +1552,17 @@ static void sd_shutdown(struct device *dev) { struct scsi_device *sdp = to_scsi_device(dev); - struct scsi_disk *sdkp; - struct scsi_request *sreq; - int retries, res; + struct scsi_disk *sdkp = dev_get_drvdata(dev); - sdkp = dev_get_drvdata(dev); if (!sdkp) - return; /* this can happen */ + return; /* this can happen */ - if (!scsi_device_online(sdp) || !sdkp->WCE) + if (!sdkp->WCE) return; - printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ", + printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", sdkp->disk->disk_name); - - sreq = scsi_allocate_request(sdp, GFP_KERNEL); - if (!sreq) { - printk("FAILED\n No memory for request\n"); - return; - } - - sreq->sr_data_direction = DMA_NONE; - for (retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; - - cmd[0] = SYNCHRONIZE_CACHE; - /* - * Leave the rest of the command zero to indicate - * flush everything. - */ - scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); - if (sreq->sr_result == 0) - break; - } - - res = sreq->sr_result; - if (res) { - printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " - "host = %d, driver = %02x\n ", - status_byte(res), msg_byte(res), - host_byte(res), driver_byte(res)); - if (driver_byte(res) & DRIVER_SENSE) - scsi_print_req_sense("sd", sreq); - } - - scsi_release_request(sreq); - printk("\n"); + sd_sync_cache(sdp); } /** diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/scsi/sg.c 2004-10-18 14:56:29 -07:00 @@ -47,8 +47,9 @@ #include #include #include - #include +#include + #include "scsi.h" #include #include @@ -205,8 +206,6 @@ static Sg_request *sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); -static int sg_ms_to_jif(unsigned int msecs); -static inline unsigned sg_jif_to_ms(int jifs); static int sg_allow_access(unsigned char opcode, char dev_type); static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static Sg_device *sg_get_dev(int dev); @@ -611,7 +610,7 @@ return -EBUSY; /* reserve buffer already being used */ } } - timeout = sg_ms_to_jif(srp->header.timeout); + timeout = msecs_to_jiffies(srp->header.timeout); if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) { sg_remove_request(sfp, srp); return -EMSGSIZE; @@ -719,19 +718,6 @@ return 0; } -static inline unsigned -sg_jif_to_ms(int jifs) -{ - if (jifs <= 0) - return 0U; - else { - unsigned int j = (unsigned int) jifs; - return (j < - (UINT_MAX / 1000)) ? ((j * 1000) / HZ) : ((j / HZ) * - 1000); - } -} - static int sg_ioctl(struct inode *inode, struct file *filp, unsigned int cmd_in, unsigned long arg) @@ -941,7 +927,7 @@ srp->header.driver_status; rinfo[val].duration = srp->done ? srp->header.duration : - sg_jif_to_ms( + jiffies_to_msecs( jiffies - srp->header.duration); rinfo[val].orphan = srp->orphan; rinfo[val].sg_io_owned = srp->sg_io_owned; @@ -1263,7 +1249,7 @@ srp->header.resid = SCpnt->resid; /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = - sg_jif_to_ms(jiffies - (int) srp->header.duration); + jiffies_to_msecs(jiffies - srp->header.duration); if (0 != SRpnt->sr_result) { memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof (srp->sense_b)); @@ -1547,7 +1533,7 @@ } if (delay) - scsi_sleep(2); /* dirty detach so delay device destruction */ + msleep(10); /* dirty detach so delay device destruction */ } /* Set 'perm' (4th argument) to 0 to disable module_param's definition @@ -2587,17 +2573,6 @@ free_pages((unsigned long) buff, order); } -static int -sg_ms_to_jif(unsigned int msecs) -{ - if ((UINT_MAX / 2U) < msecs) - return INT_MAX; /* special case, set largest possible */ - else - return ((int) msecs < - (INT_MAX / 1000)) ? (((int) msecs * HZ) / 1000) - : (((int) msecs / 1000) * HZ); -} - static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE, INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, MODE_SENSE, MODE_SENSE_10, LOG_SENSE @@ -2960,7 +2935,7 @@ for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " "(res)sgat=%d low_dma=%d\n", k + 1, - sg_jif_to_ms(fp->timeout), + jiffies_to_msecs(fp->timeout), fp->reserve.bufflen, (int) fp->reserve.k_use_sg, (int) fp->low_dma); @@ -2996,8 +2971,8 @@ seq_printf(s, " dur=%d", hp->duration); else seq_printf(s, " t_o/elap=%d/%d", - new_interface ? hp->timeout : sg_jif_to_ms(fp->timeout), - sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0)); + new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout), + jiffies_to_msecs(hp->duration ? (jiffies - hp->duration) : 0)); seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); } diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/scsi/sr.c 2004-10-18 14:57:19 -07:00 @@ -140,15 +140,13 @@ if (disk->private_data == NULL) goto out; cd = scsi_cd(disk); - if (!kref_get(&cd->kref)) - goto out_null; + kref_get(&cd->kref); if (scsi_device_get(cd->device)) goto out_put; goto out; out_put: - kref_put(&cd->kref); - out_null: + kref_put(&cd->kref, sr_kref_release); cd = NULL; out: up(&sr_ref_sem); @@ -159,7 +157,7 @@ { down(&sr_ref_sem); scsi_device_put(cd->device); - kref_put(&cd->kref); + kref_put(&cd->kref, sr_kref_release); up(&sr_ref_sem); } @@ -183,7 +181,7 @@ return -EINVAL; } - retval = scsi_ioctl(cd->device, SCSI_IOCTL_TEST_UNIT_READY, NULL); + retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES); if (retval) { /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, @@ -576,7 +574,7 @@ goto fail; memset(cd, 0, sizeof(*cd)); - kref_init(&cd->kref, sr_kref_release); + kref_init(&cd->kref); disk = alloc_disk(1); if (!disk) @@ -937,7 +935,7 @@ del_gendisk(cd->disk); down(&sr_ref_sem); - kref_put(&cd->kref); + kref_put(&cd->kref, sr_kref_release); up(&sr_ref_sem); return 0; diff -Nru a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c --- a/drivers/scsi/sr_ioctl.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/scsi/sr_ioctl.c 2004-10-18 14:56:33 -07:00 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -131,7 +132,7 @@ printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); if (retries++ < 10) { /* sleep 2 sec and try again */ - scsi_sleep(2 * HZ); + ssleep(2); goto retry; } else { /* 20 secs are enough? */ diff -Nru a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h --- a/drivers/scsi/sym53c8xx_2/sym_defs.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/sym53c8xx_2/sym_defs.h 2004-10-18 14:56:28 -07:00 @@ -53,6 +53,9 @@ #ifndef SYM_DEFS_H #define SYM_DEFS_H +#define SYM_VERSION "2.1.18j" +#define SYM_DRIVER_NAME "sym-" SYM_VERSION + /* * Vendor. */ diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c --- a/drivers/scsi/sym53c8xx_2/sym_glue.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c 2004-10-18 14:57:19 -07:00 @@ -143,13 +143,6 @@ } /* - * Driver host data structure. - */ -struct host_data { - struct sym_hcb *ncb; -}; - -/* * Used by the eh thread to wait for command completion. * It is allocated on the eh thread stack. */ @@ -220,47 +213,12 @@ return use_sg; } -static void __sync_scsi_data_for_cpu(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - int dma_dir = cmd->sc_data_direction; - - switch(SYM_UCMD_PTR(cmd)->data_mapped) { - case 2: - pci_dma_sync_sg_for_cpu(pdev, cmd->buffer, cmd->use_sg, dma_dir); - break; - case 1: - pci_dma_sync_single_for_cpu(pdev, SYM_UCMD_PTR(cmd)->data_mapping, - cmd->request_bufflen, dma_dir); - break; - } -} - -static void __sync_scsi_data_for_device(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - int dma_dir = cmd->sc_data_direction; - - switch(SYM_UCMD_PTR(cmd)->data_mapped) { - case 2: - pci_dma_sync_sg_for_device(pdev, cmd->buffer, cmd->use_sg, dma_dir); - break; - case 1: - pci_dma_sync_single_for_device(pdev, SYM_UCMD_PTR(cmd)->data_mapping, - cmd->request_bufflen, dma_dir); - break; - } -} - #define unmap_scsi_data(np, cmd) \ __unmap_scsi_data(np->s.device, cmd) #define map_scsi_single_data(np, cmd) \ __map_scsi_single_data(np->s.device, cmd) #define map_scsi_sg_data(np, cmd) \ __map_scsi_sg_data(np->s.device, cmd) -#define sync_scsi_data_for_cpu(np, cmd) \ - __sync_scsi_data_for_cpu(np->s.device, cmd) -#define sync_scsi_data_for_device(np, cmd) \ - __sync_scsi_data_for_device(np->s.device, cmd) - /* * Complete a pending CAM CCB. */ @@ -417,27 +375,6 @@ /* - * Called on successfull INQUIRY response. - */ -void sym_sniff_inquiry(struct sym_hcb *np, struct scsi_cmnd *cmd, int resid) -{ - int retv; - - if (!cmd || cmd->use_sg) - return; - - sync_scsi_data_for_cpu(np, cmd); - retv = __sym_sniff_inquiry(np, cmd->device->id, cmd->device->lun, - (u_char *) cmd->request_buffer, - cmd->request_bufflen - resid); - sync_scsi_data_for_device(np, cmd); - if (retv < 0) - return; - else if (retv) - sym_update_trans_settings(np, &np->target[cmd->device->id]); -} - -/* * Build the scatter/gather array for an I/O. */ @@ -730,14 +667,15 @@ */ static void sym_requeue_awaiting_cmds(struct sym_hcb *np) { - struct scsi_cmnd *cmd; - struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd); + struct sym_ucmd *ucp; SYM_QUEHEAD tmp_cmdq; int sts; sym_que_move(&np->s.wait_cmdq, &tmp_cmdq); while ((ucp = (struct sym_ucmd *) sym_remque_head(&tmp_cmdq)) != 0) { + struct scsi_cmnd *cmd; + sym_insque_tail(&ucp->link_cmdq, &np->s.busy_cmdq); cmd = SYM_SCMD_PTR(ucp); sts = sym_queue_command(np, cmd); @@ -1118,12 +1056,7 @@ np = ((struct host_data *) host->hostdata)->ncb; tp = &np->target[device->id]; - - /* - * Get user settings for transfer parameters. - */ - tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16); - sym_update_trans_settings(np, tp); + tp->sdev = device; /* * Allocate the LCB if not yet. @@ -2283,6 +2216,7 @@ } MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(SYM_VERSION); /* * Driver host template. @@ -2383,13 +2317,6 @@ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; - if (tp->tinfo.curr.options & PPR_OPT_DT) { - if (offset > np->maxoffs_dt) - offset = np->maxoffs_dt; - } else { - if (offset > np->maxoffs) - offset = np->maxoffs; - } tp->tinfo.goal.offset = offset; } @@ -2407,23 +2334,11 @@ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; - if (period <= 9 && np->minsync_dt) { - if (period < np->minsync_dt) - period = np->minsync_dt; - tp->tinfo.goal.options = PPR_OPT_DT; - tp->tinfo.goal.period = period; - if (!tp->tinfo.curr.offset || - tp->tinfo.curr.offset > np->maxoffs_dt) - tp->tinfo.goal.offset = np->maxoffs_dt; - } else { - if (period < np->minsync) - period = np->minsync; - tp->tinfo.goal.options = 0; - tp->tinfo.goal.period = period; - if (!tp->tinfo.curr.offset || - tp->tinfo.curr.offset > np->maxoffs) - tp->tinfo.goal.offset = np->maxoffs; - } + /* have to have DT for these transfers */ + if (period <= np->minsync) + tp->tinfo.goal.options |= PPR_OPT_DT; + + tp->tinfo.goal.period = period; } static void sym2_get_width(struct scsi_device *sdev) @@ -2439,6 +2354,10 @@ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; + /* It is illegal to have DT set on narrow transfers */ + if (width == 0) + tp->tinfo.goal.options &= ~PPR_OPT_DT; + tp->tinfo.goal.width = width; } @@ -2455,17 +2374,10 @@ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; - if (!dt) { - /* if clearing DT, then we may need to reduce the - * period and the offset */ - if (tp->tinfo.curr.period < np->minsync) - tp->tinfo.goal.period = np->minsync; - if (tp->tinfo.curr.offset > np->maxoffs) - tp->tinfo.goal.offset = np->maxoffs; - tp->tinfo.goal.options &= ~PPR_OPT_DT; - } else { + if (dt) tp->tinfo.goal.options |= PPR_OPT_DT; - } + else + tp->tinfo.goal.options &= ~PPR_OPT_DT; } diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h --- a/drivers/scsi/sym53c8xx_2/sym_glue.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h 2004-10-18 14:57:04 -07:00 @@ -90,7 +90,6 @@ #define SYM_OPT_HANDLE_DIR_UNKNOWN #define SYM_OPT_HANDLE_DEVICE_QUEUEING #define SYM_OPT_NVRAM_PRE_READ -#define SYM_OPT_SNIFF_INQUIRY #define SYM_OPT_LIMIT_COMMAND_REORDERING #define SYM_OPT_ANNOUNCE_TRANSFER_RATE @@ -289,32 +288,32 @@ * MEMORY mapped IO input / output */ -#define INB_OFF(o) readb((char *)np->s.mmio_va + sym_offb(o)) -#define OUTB_OFF(o, val) writeb((val), (char *)np->s.mmio_va + sym_offb(o)) +#define INB_OFF(o) readb(np->s.mmio_va + sym_offb(o)) +#define OUTB_OFF(o, val) writeb((val), np->s.mmio_va + sym_offb(o)) #if defined(__BIG_ENDIAN) && !defined(SYM_CONF_CHIP_BIG_ENDIAN) -#define INW_OFF(o) readw_l2b((char *)np->s.mmio_va + sym_offw(o)) -#define INL_OFF(o) readl_l2b((char *)np->s.mmio_va + (o)) +#define INW_OFF(o) readw_l2b(np->s.mmio_va + sym_offw(o)) +#define INL_OFF(o) readl_l2b(np->s.mmio_va + (o)) -#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->s.mmio_va + sym_offw(o)) -#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->s.mmio_va + (o)) +#define OUTW_OFF(o, val) writew_b2l((val), np->s.mmio_va + sym_offw(o)) +#define OUTL_OFF(o, val) writel_b2l((val), np->s.mmio_va + (o)) #elif defined(__LITTLE_ENDIAN) && defined(SYM_CONF_CHIP_BIG_ENDIAN) -#define INW_OFF(o) readw_b2l((char *)np->s.mmio_va + sym_offw(o)) -#define INL_OFF(o) readl_b2l((char *)np->s.mmio_va + (o)) +#define INW_OFF(o) readw_b2l(np->s.mmio_va + sym_offw(o)) +#define INL_OFF(o) readl_b2l(np->s.mmio_va + (o)) -#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->s.mmio_va + sym_offw(o)) -#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->s.mmio_va + (o)) +#define OUTW_OFF(o, val) writew_l2b((val), np->s.mmio_va + sym_offw(o)) +#define OUTL_OFF(o, val) writel_l2b((val), np->s.mmio_va + (o)) #else -#define INW_OFF(o) readw_raw((char *)np->s.mmio_va + sym_offw(o)) -#define INL_OFF(o) readl_raw((char *)np->s.mmio_va + (o)) +#define INW_OFF(o) readw_raw(np->s.mmio_va + sym_offw(o)) +#define INL_OFF(o) readl_raw(np->s.mmio_va + (o)) -#define OUTW_OFF(o, val) writew_raw((val), (char *)np->s.mmio_va + sym_offw(o)) -#define OUTL_OFF(o, val) writel_raw((val), (char *)np->s.mmio_va + (o)) +#define OUTW_OFF(o, val) writew_raw((val), np->s.mmio_va + sym_offw(o)) +#define OUTL_OFF(o, val) writel_raw((val), np->s.mmio_va + (o)) #endif @@ -391,8 +390,8 @@ struct Scsi_Host *host; - void * mmio_va; /* MMIO kernel virtual address */ - void * ram_va; /* RAM kernel virtual address */ + void __iomem * mmio_va; /* MMIO kernel virtual address */ + void __iomem * ram_va; /* RAM kernel virtual address */ u_long io_port; /* IO port address cookie */ u_short io_ws; /* IO window size */ int irq; /* IRQ number */ @@ -424,7 +423,7 @@ int irq; /* port and address fields to fit INB, OUTB macros */ u_long io_port; - void * mmio_va; + void __iomem * mmio_va; char inst_name[16]; }; @@ -437,6 +436,13 @@ struct sym_nvram *nvram; u_short device_id; u_char host_id; +}; + +/* + * Driver host data structure. + */ +struct host_data { + struct sym_hcb *ncb; }; /* diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c 2004-10-18 14:55:53 -07:00 @@ -49,10 +49,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - -#define SYM_VERSION "2.1.18j" -#define SYM_DRIVER_NAME "sym-" SYM_VERSION - #include "sym_glue.h" #include "sym_nvram.h" @@ -1042,28 +1038,11 @@ for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { tcb_p tp = &np->target[i]; - tp->tinfo.user.scsi_version = tp->tinfo.curr.scsi_version= 2; - tp->tinfo.user.spi_version = tp->tinfo.curr.spi_version = 2; - tp->tinfo.user.period = np->minsync; - tp->tinfo.user.offset = np->maxoffs; - tp->tinfo.user.width = np->maxwide ? BUS_16_BIT : BUS_8_BIT; tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); tp->usrtags = SYM_SETUP_MAX_TAG; sym_nvram_setup_target (np, i, nvram); - /* - * Some single-ended devices may crash on receiving a - * PPR negotiation attempt. Only try PPR if we're in - * LVD mode. - */ - if (np->features & FE_ULTRA3) { - tp->tinfo.user.options |= PPR_OPT_DT; - tp->tinfo.user.period = np->minsync_dt; - tp->tinfo.user.offset = np->maxoffs_dt; - tp->tinfo.user.spi_version = 3; - } - if (!tp->usrtags) tp->usrflags &= ~SYM_TAGS_ENABLED; } @@ -1497,6 +1476,55 @@ } #endif +static void sym_check_goals(struct scsi_device *sdev) +{ + struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; + struct sym_trans *st = &np->target[sdev->id].tinfo.goal; + + /* here we enforce all the fiddly SPI rules */ + + if (!scsi_device_wide(sdev)) + st->width = 0; + + if (!scsi_device_sync(sdev)) { + st->options = 0; + st->period = 0; + st->offset = 0; + return; + } + + if (scsi_device_dt(sdev)) { + if (scsi_device_dt_only(sdev)) + st->options |= PPR_OPT_DT; + + if (st->offset == 0) + st->options &= ~PPR_OPT_DT; + } else { + st->options &= ~PPR_OPT_DT; + } + + if (!(np->features & FE_ULTRA3)) + st->options &= ~PPR_OPT_DT; + + if (st->options & PPR_OPT_DT) { + /* all DT transfers must be wide */ + st->width = 1; + if (st->offset > np->maxoffs_dt) + st->offset = np->maxoffs_dt; + if (st->period < np->minsync_dt) + st->period = np->minsync_dt; + if (st->period > np->maxsync_dt) + st->period = np->maxsync_dt; + } else { + if (st->offset > np->maxoffs) + st->offset = np->maxoffs; + if (st->period < np->minsync) + st->period = np->minsync; + if (st->period > np->maxsync) + st->period = np->maxsync; + } +} + /* * Prepare the next negotiation message if needed. * @@ -1508,6 +1536,10 @@ { tcb_p tp = &np->target[cp->target]; int msglen = 0; + struct scsi_device *sdev = tp->sdev; + + if (likely(sdev)) + sym_check_goals(sdev); /* * Early C1010 chips need a work-around for DT @@ -1518,19 +1550,21 @@ /* * negotiate using PPR ? */ - if (tp->tinfo.goal.options & PPR_OPT_MASK) + if (scsi_device_dt(sdev)) { nego = NS_PPR; - /* - * negotiate wide transfers ? - */ - else if (tp->tinfo.curr.width != tp->tinfo.goal.width) - nego = NS_WIDE; - /* - * negotiate synchronous transfers? - */ - else if (tp->tinfo.curr.period != tp->tinfo.goal.period || - tp->tinfo.curr.offset != tp->tinfo.goal.offset) - nego = NS_SYNC; + } else { + /* + * negotiate wide transfers ? + */ + if (tp->tinfo.curr.width != tp->tinfo.goal.width) + nego = NS_WIDE; + /* + * negotiate synchronous transfers? + */ + else if (tp->tinfo.curr.period != tp->tinfo.goal.period || + tp->tinfo.curr.offset != tp->tinfo.goal.offset) + nego = NS_SYNC; + } switch (nego) { case NS_SYNC: @@ -3999,7 +4033,6 @@ static int sym_sync_nego_check(hcb_p np, int req, int target) { - tcb_p tp = &np->target[target]; u_char chg, ofs, per, fak, div; if (DEBUG_FLAGS & DEBUG_NEGO) { @@ -4019,19 +4052,11 @@ if (ofs) { if (ofs > np->maxoffs) {chg = 1; ofs = np->maxoffs;} - if (req) { - if (ofs > tp->tinfo.user.offset) - {chg = 1; ofs = tp->tinfo.user.offset;} - } } if (ofs) { if (per < np->minsync) {chg = 1; per = np->minsync;} - if (req) { - if (per < tp->tinfo.user.period) - {chg = 1; per = tp->tinfo.user.period;} - } } /* @@ -4151,10 +4176,6 @@ } if (!wide || !(np->features & FE_ULTRA3)) dt &= ~PPR_OPT_DT; - if (req) { - if (wide > tp->tinfo.user.width) - {chg = 1; wide = tp->tinfo.user.width;} - } if (!(np->features & FE_U3EN)) /* Broken U3EN bit not supported */ dt &= ~PPR_OPT_DT; @@ -4168,10 +4189,6 @@ } else if (ofs > np->maxoffs) {chg = 1; ofs = np->maxoffs;} - if (req) { - if (ofs > tp->tinfo.user.offset) - {chg = 1; ofs = tp->tinfo.user.offset;} - } } if (ofs) { @@ -4181,10 +4198,6 @@ } else if (per < np->minsync) {chg = 1; per = np->minsync;} - if (req) { - if (per < tp->tinfo.user.period) - {chg = 1; per = tp->tinfo.user.period;} - } } /* @@ -4286,7 +4299,6 @@ static int sym_wide_nego_check(hcb_p np, int req, int target) { - tcb_p tp = &np->target[target]; u_char chg, wide; if (DEBUG_FLAGS & DEBUG_NEGO) { @@ -4305,10 +4317,6 @@ if (wide > np->maxwide) { chg = 1; wide = np->maxwide; - } - if (req) { - if (wide > tp->tinfo.user.width) - {chg = 1; wide = tp->tinfo.user.width;} } if (DEBUG_FLAGS & DEBUG_NEGO) { diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h 2004-10-18 14:56:28 -07:00 @@ -69,11 +69,6 @@ * When this option is set, the driver will use a queue per * device and handle QUEUE FULL status requeuing internally. * - * SYM_OPT_SNIFF_INQUIRY - * When this option is set, the driver sniff out successful - * INQUIRY response and performs negotiations accordingly. - * (set for Linux) - * * SYM_OPT_LIMIT_COMMAND_REORDERING * When this option is set, the driver tries to limit tagged * command reordering to some reasonnable value. @@ -82,7 +77,6 @@ #if 0 #define SYM_OPT_HANDLE_DIR_UNKNOWN #define SYM_OPT_HANDLE_DEVICE_QUEUEING -#define SYM_OPT_SNIFF_INQUIRY #define SYM_OPT_LIMIT_COMMAND_REORDERING #endif @@ -364,7 +358,6 @@ struct sym_tinfo { struct sym_trans curr; struct sym_trans goal; - struct sym_trans user; #ifdef SYM_OPT_ANNOUNCE_TRANSFER_RATE struct sym_trans prev; #endif @@ -465,18 +458,7 @@ */ u_char usrflags; u_short usrtags; - -#ifdef SYM_OPT_SNIFF_INQUIRY - /* - * Some minimal information from INQUIRY response. - */ - u32 cmdq_map[(SYM_CONF_MAX_LUN+31)/32]; - u_char inq_version; - u_char inq_byte7; - u_char inq_byte56; - u_char inq_byte7_valid; -#endif - + struct scsi_device *sdev; }; /* @@ -1167,26 +1149,6 @@ #ifdef SYM_OPT_ANNOUNCE_TRANSFER_RATE void sym_announce_transfer_rate(hcb_p np, int target); #endif - -/* - * Optionnaly, the driver may sniff inquiry data. - */ -#ifdef SYM_OPT_SNIFF_INQUIRY -#define INQ7_CMDQ (0x02) -#define INQ7_SYNC (0x10) -#define INQ7_WIDE16 (0x20) - -#define INQ56_CLOCKING (3<<2) -#define INQ56_ST_ONLY (0<<2) -#define INQ56_DT_ONLY (1<<2) -#define INQ56_ST_DT (3<<2) - -void sym_update_trans_settings(hcb_p np, tcb_p tp); -int -__sym_sniff_inquiry(hcb_p np, u_char tn, u_char ln, - u_char *inq_data, int inq_len); -#endif - /* * Build a scatter/gather entry. diff -Nru a/drivers/scsi/sym53c8xx_2/sym_misc.c b/drivers/scsi/sym53c8xx_2/sym_misc.c --- a/drivers/scsi/sym53c8xx_2/sym_misc.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/scsi/sym53c8xx_2/sym_misc.c 2004-10-18 14:56:50 -07:00 @@ -216,121 +216,3 @@ #undef __tprev #undef __tcurr #endif /* SYM_OPT_ANNOUNCE_TRANSFER_RATE */ - - -#ifdef SYM_OPT_SNIFF_INQUIRY -/* - * Update transfer settings according to user settings - * and bits sniffed out from INQUIRY response. - */ -void sym_update_trans_settings(hcb_p np, tcb_p tp) -{ - memcpy(&tp->tinfo.goal, &tp->tinfo.user, sizeof(tp->tinfo.goal)); - - if (tp->inq_version >= 4) { - switch(tp->inq_byte56 & INQ56_CLOCKING) { - case INQ56_ST_ONLY: - tp->tinfo.goal.options = 0; - break; - case INQ56_DT_ONLY: - case INQ56_ST_DT: - default: - break; - } - } - - if (!((tp->inq_byte7 & tp->inq_byte7_valid) & INQ7_WIDE16)) { - tp->tinfo.goal.width = 0; - tp->tinfo.goal.options = 0; - } - - if (!((tp->inq_byte7 & tp->inq_byte7_valid) & INQ7_SYNC)) { - tp->tinfo.goal.offset = 0; - tp->tinfo.goal.options = 0; - } - - if (tp->tinfo.goal.options & PPR_OPT_DT) { - if (tp->tinfo.goal.offset > np->maxoffs_dt) - tp->tinfo.goal.offset = np->maxoffs_dt; - } - else { - if (tp->tinfo.goal.offset > np->maxoffs) - tp->tinfo.goal.offset = np->maxoffs; - } -} - -/* - * Snoop target capabilities from INQUIRY response. - * We only believe device versions >= SCSI-2 that use - * appropriate response data format (2). But it seems - * that some CCS devices also support SYNC (?). - */ -int -__sym_sniff_inquiry(hcb_p np, u_char tn, u_char ln, - u_char *inq_data, int inq_len) -{ - tcb_p tp = &np->target[tn]; - u_char inq_version; - u_char inq_byte7; - u_char inq_byte56; - - if (!inq_data || inq_len < 2) - return -1; - - /* - * Check device type and qualifier. - */ - if ((inq_data[0] & 0xe0) == 0x60) - return -1; - - /* - * Get SPC version. - */ - if (inq_len <= 2) - return -1; - inq_version = inq_data[2] & 0x7; - - /* - * Get SYNC/WIDE16 capabilities. - */ - inq_byte7 = tp->inq_byte7; - if (inq_version >= 2 && (inq_data[3] & 0xf) == 2) { - if (inq_len > 7) - inq_byte7 = inq_data[7]; - } - else if (inq_version == 1 && (inq_data[3] & 0xf) == 1) - inq_byte7 = INQ7_SYNC; - - /* - * Get Tagged Command Queuing capability. - */ - if (inq_byte7 & INQ7_CMDQ) - sym_set_bit(tp->cmdq_map, ln); - else - sym_clr_bit(tp->cmdq_map, ln); - inq_byte7 &= ~INQ7_CMDQ; - - /* - * Get CLOCKING capability. - */ - inq_byte56 = tp->inq_byte56; - if (inq_version >= 4 && inq_len > 56) - inq_byte56 = inq_data[56]; -#if 0 -printf("XXXXXX [%d] inq_version=%x inq_byte7=%x inq_byte56=%x XXXXX\n", - inq_len, inq_version, inq_byte7, inq_byte56); -#endif - /* - * Trigger a negotiation if needed. - */ - if (tp->inq_version != inq_version || - tp->inq_byte7 != inq_byte7 || - tp->inq_byte56 != inq_byte56) { - tp->inq_version = inq_version; - tp->inq_byte7 = inq_byte7; - tp->inq_byte56 = inq_byte56; - return 1; - } - return 0; -} -#endif /* SYM_OPT_SNIFF_INQUIRY */ diff -Nru a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c --- a/drivers/scsi/sym53c8xx_2/sym_nvram.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c 2004-10-18 14:56:33 -07:00 @@ -53,11 +53,6 @@ #include "sym_glue.h" #include "sym_nvram.h" -/* - * Some poor and bogus sync table that refers to Tekram NVRAM layout. - */ -static u_char Tekram_sync[16] = - {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10}; #ifdef SYM_CONF_DEBUG_NVRAM static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; #endif @@ -100,8 +95,6 @@ struct sym_tcb *tp = &np->target[target]; Symbios_target *tn = &nvram->target[target]; - tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0; - tp->tinfo.user.width = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT; tp->usrtags = (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0; @@ -121,15 +114,6 @@ { struct sym_tcb *tp = &np->target[target]; struct Tekram_target *tn = &nvram->target[target]; - int i; - - if (tn->flags & TEKRAM_SYNC_NEGO) { - i = tn->sync_index & 0xf; - tp->tinfo.user.period = Tekram_sync[i]; - } - - tp->tinfo.user.width = (tn->flags & TEKRAM_WIDE_NEGO) ? - BUS_16_BIT : BUS_8_BIT; if (tn->flags & TEKRAM_TAGGED_COMMANDS) { tp->usrtags = 2 << nvram->max_tags_index; diff -Nru a/drivers/scsi/t128.c b/drivers/scsi/t128.c --- a/drivers/scsi/t128.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/scsi/t128.c 2004-10-18 14:57:03 -07:00 @@ -284,6 +284,7 @@ { if (shost->irq) free_irq(shost->irq, NULL); + NCR5380_exit(shost); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); scsi_unregister(shost); diff -Nru a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c --- a/drivers/scsi/tmscsim.c 2004-10-18 14:57:19 -07:00 +++ b/drivers/scsi/tmscsim.c 2004-10-18 14:57:19 -07:00 @@ -240,17 +240,15 @@ #include #include -#if 0 #include #include #include -#else -#include "scsi.h" -#endif #include #include -#include "dc390.h" + +#define DC390_BANNER "Tekram DC390/AM53C974" +#define DC390_VERSION "2.1d 2004-05-27" #define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI @@ -291,20 +289,14 @@ static void dc390_DoingSRB_Done( struct dc390_acb* pACB, struct scsi_cmnd * cmd); static void dc390_ScsiRstDetect( struct dc390_acb* pACB ); static void dc390_ResetSCSIBus( struct dc390_acb* pACB ); -static void __inline__ dc390_RequestSense( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ); -static void __inline__ dc390_InvalidCmd( struct dc390_acb* pACB ); -static void __inline__ dc390_EnableMsgOut_Abort (struct dc390_acb*, struct dc390_srb*); +static void dc390_EnableMsgOut_Abort(struct dc390_acb*, struct dc390_srb*); static irqreturn_t do_DC390_Interrupt( int, void *, struct pt_regs *); static int dc390_initAdapter(struct Scsi_Host *psh, unsigned long io_port, u8 Irq, u8 index ); static void dc390_updateDCB (struct dc390_acb* pACB, struct dc390_dcb* pDCB); -static int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start, - off_t offset, int length, int inout); - static struct dc390_acb* dc390_pACB_start= NULL; static struct dc390_acb* dc390_pACB_current = NULL; -static unsigned long dc390_lastabortedpid = 0; static u32 dc390_laststatus = 0; static u8 dc390_adapterCnt = 0; @@ -612,16 +604,12 @@ **********************************************************************/ static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun) { - struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return 0; + struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL; while (pDCB->TargetID != id || pDCB->TargetLUN != lun) { pDCB = pDCB->pNextDCB; if (pDCB == pACB->pLinkDCB) - { - DCBDEBUG(printk (KERN_WARNING "DC390: DCB not found (DCB=%p, DCBmap[%2x]=%2x)\n", - pDCB, id, pACB->DCBmap[id])); - return 0; - } + return NULL; } DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n", \ pDCB, pDCB->TargetID, pDCB->TargetLUN)); @@ -942,8 +930,6 @@ { pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; - //pSRB->ScsiCmdLen = pcmd->cmd_len; - //memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); pSRB->SGIndex = 0; pSRB->AdaptStatus = 0; @@ -991,28 +977,6 @@ struct dc390_srb* pSRB; struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata; - DEBUG0(/* if(pACB->scan_devices) */ \ - printk(KERN_INFO "DC390: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li), buffer=%p\n",\ - cmd->cmnd[0],cmd->device->id,cmd->device->lun,cmd->pid, cmd->buffer)); - - /* TODO: Change the policy: Always accept TEST_UNIT_READY or INQUIRY - * commands and alloc a DCB for the device if not yet there. DCB will - * be removed in dc390_SRBdone if SEL_TIMEOUT */ - if (!(pACB->scan_devices) && !(pACB->DCBmap[cmd->device->id] & (1 << cmd->device->lun))) { - printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n", - cmd->device->id, cmd->device->lun); - goto fail; - } - - /* Should it be: BUG_ON(!pDCB); ? */ - - if (!pDCB) - { /* should never happen */ - printk (KERN_ERR "DC390: no DCB found, target %02x lun %02x\n", - cmd->device->id, cmd->device->lun); - goto fail; - } - pACB->Cmds++; cmd->scsi_done = done; cmd->result = 0; @@ -1033,145 +997,7 @@ requeue: return 1; - fail: - cmd->result = DID_BAD_TARGET << 16; - done(cmd); - return 0; -} - -/* We ignore mapping problems, as we expect everybody to respect - * valid partition tables. Waiting for complaints ;-) */ - -#ifdef CONFIG_SCSI_DC390T_TRADMAP -/* - * The next function, partsize(), is copied from scsicam.c. - * - * This is ugly code duplication, but I didn't find another way to solve it: - * We want to respect the partition table and if it fails, we apply the - * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do - * the job, because we don't know, whether the values returned are from - * the part. table or determined by setsize(). Unfortunately the setsize() - * values differ from the ones chosen by the DC390 BIOS. - * - * Looking forward to seeing suggestions for a better solution! KG, 98/10/14 - */ -#include - -/* - * Function : static int partsize(unsigned char *buf, unsigned long - * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); - * - * Purpose : to determine the BIOS mapping used to create the partition - * table, storing the results in *cyls, *hds, and *secs - * - * Returns : -1 on failure, 0 on success. - * - */ - -static int partsize(unsigned char *buf, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, unsigned int *secs) { - struct partition *p, *largest = NULL; - int i, largest_cyl; - int cyl, ext_cyl, end_head, end_cyl, end_sector; - unsigned int logical_end, physical_end, ext_physical_end; - - - if (*(unsigned short *) (buf+64) == 0xAA55) { - for (largest_cyl = -1, p = (struct partition *) buf, - i = 0; i < 4; ++i, ++p) { - if (!p->sys_ind) - continue; - cyl = p->cyl + ((p->sector & 0xc0) << 2); - if (cyl > largest_cyl) { - largest_cyl = cyl; - largest = p; - } - } - } - - if (largest) { - end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); - end_head = largest->end_head; - end_sector = largest->end_sector & 0x3f; - - physical_end = end_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; - - /* This is the actual _sector_ number at the end */ - logical_end = get_unaligned(&largest->start_sect) - + get_unaligned(&largest->nr_sects); - - /* This is for >1023 cylinders */ - ext_cyl= (logical_end-(end_head * end_sector + end_sector)) - /(end_head + 1) / end_sector; - ext_physical_end = ext_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; - - if ((logical_end == physical_end) || - (end_cyl==1023 && ext_physical_end==logical_end)) { - *secs = end_sector; - *hds = end_head + 1; - *cyls = capacity / ((end_head + 1) * end_sector); - return 0; - } - } - return -1; -} - -/*********************************************************************** - * Function: - * DC390_bios_param - * - * Description: - * Return the disk geometry for the given SCSI device. - * Respect the partition table, otherwise try own heuristic - * - * Note: - * In contrary to other externally callable funcs (DC390_), we don't lock - ***********************************************************************/ -static int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - int heads, sectors, cylinders; - struct dc390_acb* pACB = (struct dc390_acb*) sdev->host->hostdata; - int ret_code = -1; - int size = capacity; - unsigned char *buf; - - if ((buf = scsi_bios_ptable(bdev))) - { - /* try to infer mapping from partition table */ - ret_code = partsize (buf, (unsigned long) size, (unsigned int *) geom + 2, - (unsigned int *) geom + 0, (unsigned int *) geom + 1); - kfree (buf); - } - if (ret_code == -1) - { - heads = 64; - sectors = 32; - cylinders = size / (heads * sectors); - - if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) - { - heads = 255; - sectors = 63; - cylinders = size / (heads * sectors); - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - } - - return (0); } -#else -static int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - return scsicam_bios_param (bdev, capacity, geom); -} -#endif static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB) { @@ -1219,146 +1045,54 @@ } -/*********************************************************************** - * Function : int DC390_abort (struct scsi_cmnd *cmd) - * - * Purpose : Abort an errant SCSI command - * - * Inputs : cmd - command to abort - * - * Returns : 0 on success, -1 on failure. - * - * Status: Buggy ! - ***********************************************************************/ - -static int DC390_abort (struct scsi_cmnd *cmd) +static int DC390_abort(struct scsi_cmnd *cmd) { - struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; - struct dc390_srb *pSRB, *psrb; - u32 count, i; - int status; - //unsigned long sbac; - struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata; - - printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n", - cmd->pid, cmd->device->id, cmd->device->lun); - - if( !pDCB ) goto NOT_RUN; - - /* Added 98/07/02 KG */ - /* - pSRB = pDCB->pActiveSRB; - if (pSRB && pSRB->pcmd == cmd ) - goto ON_GOING; - */ - - pSRB = pDCB->pWaitingSRB; - if( !pSRB ) - goto ON_GOING; + struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata; + struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; + struct dc390_srb *pSRB, *psrb; - /* Now scan Waiting queue */ - if( pSRB->pcmd == cmd ) - { - pDCB->pWaitingSRB = pSRB->pNextSRB; - goto IN_WAIT; - } - else - { - psrb = pSRB; - if( !(psrb->pNextSRB) ) - goto ON_GOING; - while( psrb->pNextSRB->pcmd != cmd ) - { - psrb = psrb->pNextSRB; - if( !(psrb->pNextSRB) || psrb == pSRB) - goto ON_GOING; - } - pSRB = psrb->pNextSRB; - psrb->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pWaitLast ) - pDCB->pWaitLast = psrb; -IN_WAIT: - dc390_Free_insert (pACB, pSRB); + printk("DC390: Abort command (pid %li, Device %02i-%02i)\n", + cmd->pid, cmd->device->id, cmd->device->lun); + + pSRB = pDCB->pWaitingSRB; + if (!pSRB) + goto on_going; + + /* Now scan Waiting queue */ + if (pSRB->pcmd != cmd) { + psrb = pSRB; + if (!(psrb->pNextSRB)) + goto on_going; + + while (psrb->pNextSRB->pcmd != cmd) { + psrb = psrb->pNextSRB; + if (!(psrb->pNextSRB) || psrb == pSRB) + goto on_going; + } + + pSRB = psrb->pNextSRB; + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pWaitLast) + pDCB->pWaitLast = psrb; + } else + pDCB->pWaitingSRB = pSRB->pNextSRB; + + dc390_Free_insert(pACB, pSRB); pDCB->WaitSRBCnt--; INIT_LIST_HEAD((struct list_head*)&cmd->SCp); - status = SCSI_ABORT_SUCCESS; - goto ABO_X; - } - /* SRB has already been sent ! */ -ON_GOING: - /* abort() is too stupid for already sent commands at the moment. - * If it's called we are in trouble anyway, so let's dump some info - * into the syslog at least. (KG, 98/08/20,99/06/20) */ - dc390_dumpinfo (pACB, pDCB, pSRB); - pSRB = pDCB->pGoingSRB; - pDCB->DCBFlag |= ABORT_DEV_; - /* Now for the hard part: The command is currently processed */ - for( count = pDCB->GoingSRBCnt, i=0; ipcmd != cmd ) - pSRB = pSRB->pNextSRB; - else - { - if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) ) - { - status = SCSI_ABORT_BUSY; - printk ("DC390: Abort current command (pid %li, SRB %p)\n", - cmd->pid, pSRB); - goto ABO_X; - } - else - { - status = SCSI_ABORT_SNOOZE; - goto ABO_X; - } - } - } + return SUCCESS; -NOT_RUN: - status = SCSI_ABORT_NOT_RUNNING; +on_going: + /* abort() is too stupid for already sent commands at the moment. + * If it's called we are in trouble anyway, so let's dump some info + * into the syslog at least. (KG, 98/08/20,99/06/20) */ + dc390_dumpinfo(pACB, pDCB, pSRB); -ABO_X: - cmd->result = DID_ABORT << 16; - printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status); -#if 0 - if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */ - { - /* Let's do something to help the bus getting clean again */ - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, DMA_COMMAND); - //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - //DC390_write8 (ScsiCmd, RESET_ATN_CMD); - DC390_write8 (ScsiCmd, NOP_CMD); - //udelay (10000); - //DC390_read8 (INT_Status); - //DC390_write8 (ScsiCmd, EN_SEL_RESEL); - } - sbac = DC390_read32 (DMA_ScsiBusCtrl); - if (sbac & SCSI_BUSY) - { /* clear BSY, SEL and ATN */ - printk (KERN_WARNING "DC390: Reset SCSI device: "); - //DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES); - //udelay (250); - //sbac = DC390_read32 (DMA_ScsiBusCtrl); - //printk ("%08lx ", sbac); - //DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM)); - //udelay (100); - //sbac = DC390_read32 (DMA_ScsiBusCtrl); - //printk ("%08lx ", sbac); - DC390_write8 (ScsiCmd, RST_DEVICE_CMD); - udelay (250); - DC390_write8 (ScsiCmd, NOP_CMD); - sbac = DC390_read32 (DMA_ScsiBusCtrl); - printk ("%08lx\n", sbac); - } -#endif - dc390_lastabortedpid = cmd->pid; - //do_DC390_Interrupt (pACB->IRQLevel, 0, 0); -#ifndef USE_NEW_EH - if (status == SCSI_ABORT_SUCCESS) cmd->scsi_done(cmd); -#endif - return( status ); + pDCB->DCBFlag |= ABORT_DEV_; + printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->pid); + + return FAILED; } @@ -1385,93 +1119,38 @@ } -#if 0 -/* Moves all SRBs from Going to Waiting for all DCBs */ -static void dc390_RecoverSRB( struct dc390_acb* pACB ) +static int DC390_bus_reset (struct scsi_cmnd *cmd) { - struct dc390_dcb *pDCB, *pdcb; - struct dc390_srb *psrb, *psrb2; - u32 cnt, i; - - pDCB = pACB->pLinkDCB; - if( !pDCB ) return; - pdcb = pDCB; - do - { - cnt = pdcb->GoingSRBCnt; - psrb = pdcb->pGoingSRB; - for (i=0; ipNextSRB; -/* dc390_RewaitSRB( pDCB, psrb ); */ - if( pdcb->pWaitingSRB ) - { - psrb2->pNextSRB = pdcb->pWaitingSRB; - pdcb->pWaitingSRB = psrb2; - } - else - { - pdcb->pWaitingSRB = psrb2; - pdcb->pWaitLast = psrb2; - psrb2->pNextSRB = NULL; - } - } - pdcb->GoingSRBCnt = 0; - pdcb->pGoingSRB = NULL; - pdcb->TagMask = 0; - pdcb = pdcb->pNextDCB; - } while( pdcb != pDCB ); -} -#endif + struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata; + u8 bval; -/*********************************************************************** - * Function : int DC390_reset (struct scsi_cmnd *cmd, ...) - * - * Purpose : perform a hard reset on the SCSI bus - * - * Inputs : cmd - command which caused the SCSI RESET - * resetFlags - how hard to try - * - * Returns : 0 on success. - ***********************************************************************/ + del_timer (&pACB->Waiting_Timer); -static int DC390_reset (struct scsi_cmnd *cmd) -{ - u8 bval; - struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata; + bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST; + DC390_write8(CtrlReg1, bval); /* disable IRQ on bus reset */ - printk(KERN_INFO "DC390: RESET ... "); + pACB->ACBFlag |= RESET_DEV; + dc390_ResetSCSIBus(pACB); - if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); - bval = DC390_read8 (CtrlReg1); - bval |= DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* disable IRQ on bus reset */ - - pACB->ACBFlag |= RESET_DEV; - dc390_ResetSCSIBus( pACB ); - - dc390_ResetDevParam( pACB ); - udelay (1000); - pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + dc390_ResetDevParam(pACB); + udelay(1000); + pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - DC390_read8 (INT_Status); /* Reset Pending INT */ + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); + DC390_read8(INT_Status); /* Reset Pending INT */ - dc390_DoingSRB_Done( pACB, cmd ); - /* dc390_RecoverSRB (pACB); */ - pACB->pActiveDCB = NULL; + dc390_DoingSRB_Done(pACB, cmd); - pACB->ACBFlag = 0; - bval = DC390_read8 (CtrlReg1); - bval &= ~DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */ + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0; - dc390_Waiting_process( pACB ); + bval = DC390_read8(CtrlReg1) & ~DIS_INT_ON_SCSI_RST; + DC390_write8(CtrlReg1, bval); /* re-enable interrupt */ - printk("done\n"); - return( SCSI_RESET_SUCCESS ); + dc390_Waiting_process(pACB); + + return SUCCESS; } #include "scsiiom.c" @@ -1548,7 +1227,6 @@ static void __devinit dc390_initACB (struct Scsi_Host *psh, unsigned long io_port, u8 Irq, u8 index) { struct dc390_acb* pACB; - u8 i; psh->can_queue = MAX_CMD_QUEUE; psh->cmd_per_lun = MAX_CMD_PER_LUN; @@ -1595,8 +1273,6 @@ dc390_linkSRB( pACB ); pACB->pTmpSRB = &pACB->TmpSRB; dc390_initSRB( pACB->pTmpSRB ); - for(i=0; iDCBmap[i] = 0; pACB->sel_timeout = SEL_TIMEOUT; pACB->glitch_cfg = EATER_25NS; pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = 0; @@ -1706,7 +1382,7 @@ static int dc390_slave_alloc(struct scsi_device *scsi_device) { struct dc390_acb *pACB = (struct dc390_acb*) scsi_device->host->hostdata; - struct dc390_dcb *pDCB, *pDCB2 = 0; + struct dc390_dcb *pDCB, *pDCB2 = NULL; uint id = scsi_device->id; uint lun = scsi_device->lun; @@ -1757,7 +1433,6 @@ pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; } - pACB->DCBmap[id] |= (1 << lun); dc390_updateDCB(pACB, pDCB); pACB->scan_devices = 1; @@ -1781,8 +1456,6 @@ BUG_ON(pDCB->GoingSRBCnt > 1); - pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN); - if (pDCB == pACB->pLinkDCB) { if (pACB->pLastDCB == pDCB) { pDCB->pNextDCB = NULL; @@ -1818,15 +1491,13 @@ static struct scsi_host_template driver_template = { .module = THIS_MODULE, .proc_name = "tmscsim", - .proc_info = DC390_proc_info, .name = DC390_BANNER " V" DC390_VERSION, .slave_alloc = dc390_slave_alloc, .slave_configure = dc390_slave_configure, .slave_destroy = dc390_slave_destroy, .queuecommand = DC390_queue_command, .eh_abort_handler = DC390_abort, - .eh_bus_reset_handler = DC390_reset, - .bios_param = DC390_bios_param, + .eh_bus_reset_handler = DC390_bus_reset, .can_queue = 42, .this_id = 7, .sg_tablesize = SG_ALL, @@ -1938,152 +1609,6 @@ scsi_host_put(scsi_host); pci_set_drvdata(dev, NULL); } - -/******************************************************************** - * Function: DC390_proc_info(char* buffer, char **start, - * off_t offset, int length, int hostno, int inout) - * - * Purpose: return SCSI Adapter/Device Info - * - * Input: buffer: Pointer to a buffer where to write info - * start : - * offset: - * hostno: Host adapter index - * inout : Read (=0) or set(!=0) info - * - * Output: buffer: contains info - * length; length of info in buffer - * - * return value: length - * - ********************************************************************/ - -#undef SPRINTF -#define SPRINTF(args...) pos += sprintf(pos, ## args) - -#define YESNO(YN) \ - if (YN) SPRINTF(" Yes "); \ - else SPRINTF(" No ") - - -static int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start, - off_t offset, int length, int inout) -{ - int dev, spd, spd1; - char *pos = buffer; - struct dc390_acb* pACB; - struct dc390_dcb* pDCB; - - pACB = dc390_pACB_start; - - while(pACB != (struct dc390_acb*)-1) - { - if (shpnt == pACB->pScsiHost) - break; - pACB = pACB->pNextACB; - } - - if (pACB == (struct dc390_acb*)-1) return(-ESRCH); - - if(inout) /* Has data been written to the file ? */ - return -ENOSYS; - - SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, "); - SPRINTF("Driver Version %s\n", DC390_VERSION); - - SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); - SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex); - SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase); - SPRINTF("IRQ %02i\n", pACB->IRQLevel); - - SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun); - SPRINTF("AdapterID %i, SelTimeout %i ms, DelayReset %i s\n", - shpnt->this_id, (pACB->sel_timeout*164)/100, - dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); - - SPRINTF("TagMaxNum %i, Status 0x%02x, ACBFlag 0x%02x, GlitchEater %i ns\n", - pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12); - - SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %i, Out of SRB conds %i\n", - pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB); - SPRINTF(" Lost arbitrations %i, Sel. connected %i, Connected: %s\n", - pACB->SelLost, pACB->SelConn, pACB->Connected? "Yes": "No"); - - SPRINTF("Nr of DCBs: %i\n", pACB->DCBCnt); - SPRINTF("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n", - pACB->DCBmap[0], pACB->DCBmap[1], pACB->DCBmap[2], pACB->DCBmap[3], - pACB->DCBmap[4], pACB->DCBmap[5], pACB->DCBmap[6], pACB->DCBmap[7]); - - SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd\n"); - - pDCB = pACB->pLinkDCB; - for (dev = 0; dev < pACB->DCBCnt; dev++) - { - SPRINTF("%02i %02i %02i ", dev, pDCB->TargetID, pDCB->TargetLUN); - YESNO(pDCB->DevMode & PARITY_CHK_); - YESNO(pDCB->SyncMode & SYNC_NEGO_DONE); - YESNO(pDCB->DevMode & EN_DISCONNECT_); - YESNO(pDCB->DevMode & SEND_START_); - YESNO(pDCB->SyncMode & EN_TAG_QUEUEING); - if (pDCB->SyncOffset & 0x0f) - { - int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++; - SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2); - spd = 40/(sp); spd1 = 40%(sp); - spd1 = (spd1 * 10 + sp/2) / (sp); - SPRINTF(" %2i.%1i M %02i", spd, spd1, (pDCB->SyncOffset & 0x0f)); - } - else SPRINTF(" (%03i ns) ", (pDCB->NegoPeriod) << 2); - /* Add more info ...*/ - SPRINTF (" %02i\n", pDCB->MaxCommand); - pDCB = pDCB->pNextDCB; - } - if (timer_pending(&pACB->Waiting_Timer)) SPRINTF ("Waiting queue timer running\n"); - else SPRINTF ("\n"); - pDCB = pACB->pLinkDCB; - - for (dev = 0; dev < pACB->DCBCnt; dev++) - { - struct dc390_srb* pSRB; - if (pDCB->WaitSRBCnt) - SPRINTF ("DCB (%02i-%i): Waiting: %i:", pDCB->TargetID, pDCB->TargetLUN, - pDCB->WaitSRBCnt); - for (pSRB = pDCB->pWaitingSRB; pSRB; pSRB = pSRB->pNextSRB) - SPRINTF(" %li", pSRB->pcmd->pid); - if (pDCB->GoingSRBCnt) - SPRINTF ("\nDCB (%02i-%i): Going : %i:", pDCB->TargetID, pDCB->TargetLUN, - pDCB->GoingSRBCnt); - for (pSRB = pDCB->pGoingSRB; pSRB; pSRB = pSRB->pNextSRB) -#if 0 //def DC390_DEBUGTRACE - SPRINTF(" %s\n ", pSRB->debugtrace); -#else - SPRINTF(" %li", pSRB->pcmd->pid); -#endif - if (pDCB->WaitSRBCnt || pDCB->GoingSRBCnt) SPRINTF ("\n"); - pDCB = pDCB->pNextDCB; - } - -#ifdef DC390_DEBUGDCB - SPRINTF ("DCB list for ACB %p:\n", pACB); - pDCB = pACB->pLinkDCB; - SPRINTF ("%p", pDCB); - for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB=pDCB->pNextDCB) - SPRINTF ("->%p", pDCB->pNextDCB); - SPRINTF("\n"); -#endif - - *start = buffer + offset; - - if (pos - buffer < offset) - return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - else - return length; -} - -#undef YESNO -#undef SPRINTF static struct pci_driver dc390_driver = { .name = "tmscsim", diff -Nru a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h --- a/drivers/scsi/tmscsim.h 2004-10-18 14:57:03 -07:00 +++ b/drivers/scsi/tmscsim.h 2004-10-18 14:57:03 -07:00 @@ -163,7 +163,6 @@ struct dc390_srb *pTmpSRB; u8 msgin123[4]; -u8 DCBmap[MAX_SCSI_ID]; u8 Connected; u8 pad; diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c --- a/drivers/scsi/wd7000.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/scsi/wd7000.c 2004-10-18 14:57:04 -07:00 @@ -190,7 +190,6 @@ #include -#define ANY2SCSI_INLINE /* undef this to use old macros */ #undef WD7000_DEBUG /* general debug */ #ifdef WD7000_DEBUG #define dprintk printk @@ -726,55 +725,17 @@ __setup("wd7000=", wd7000_setup); -#ifdef ANY2SCSI_INLINE -/* - * Since they're used a lot, I've redone the following from the macros - * formerly in wd7000.h, hopefully to speed them up by getting rid of - * all the shifting (it may not matter; GCC might have done as well anyway). - * - * xany2scsi and xscsi2int were not being used, and are no longer defined. - * (They were simply 4-byte versions of these routines). - */ -typedef union { /* let's cheat... */ - int i; - unchar u[sizeof(int)]; /* the sizeof(int) makes it more portable */ -} i_u; - - static inline void any2scsi(unchar * scsi, int any) { - *scsi++ = ((i_u) any).u[2]; - *scsi++ = ((i_u) any).u[1]; - *scsi++ = ((i_u) any).u[0]; + *scsi++ = (unsigned)any >> 16; + *scsi++ = (unsigned)any >> 8; + *scsi++ = any; } - static inline int scsi2int(unchar * scsi) { - i_u result; - - result.i = 0; /* clears unused bytes */ - result.u[2] = *scsi++; - result.u[1] = *scsi++; - result.u[0] = *scsi++; - - return (result.i); + return (scsi[0] << 16) | (scsi[1] << 8) | scsi[2]; } -#else -/* - * These are the old ones - I've just moved them here... - */ -#undef any2scsi -#define any2scsi(up, p) (up)[0] = (((unsigned long) (p)) >> 16); \ - (up)[1] = ((unsigned long) (p)) >> 8; \ - (up)[2] = ((unsigned long) (p)); - -#undef scsi2int -#define scsi2int(up) ( (((unsigned long) *(up)) << 16) + \ - (((unsigned long) (up)[1]) << 8) + \ - ((unsigned long) (up)[2]) ) -#endif - static inline void wd7000_enable_intr(Adapter * host) { diff -Nru a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c --- a/drivers/serial/68328serial.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/serial/68328serial.c 2004-10-18 14:57:04 -07:00 @@ -435,10 +435,7 @@ return; #if 0 if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } #endif } @@ -858,10 +855,7 @@ cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1185,11 +1179,13 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; +#warning "This is not and has never been valid so fix it" +#if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) (tty->ldisc.close)(tty); @@ -1198,6 +1194,7 @@ if (tty->ldisc.open) (tty->ldisc.open)(tty); } +#endif if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; diff -Nru a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c --- a/drivers/serial/68360serial.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/serial/68360serial.c 2004-10-18 14:57:04 -07:00 @@ -700,12 +700,8 @@ if (!tty) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) + tty_wakeup(tty); } @@ -1152,10 +1148,7 @@ /* There is nothing to "flush", whatever we gave the CPM * is on its way out. */ - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); info->flags &= ~TX_WAKEUP; } @@ -1716,8 +1709,7 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; @@ -2592,7 +2584,7 @@ state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; - printk(KERN_INFO "ttyS%02d at irq 0x%02x is an %s\n", + printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n", i, (unsigned int)(state->irq), (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC"); diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/serial/8250.c 2004-10-18 14:55:54 -07:00 @@ -130,6 +130,7 @@ struct timer_list timer; /* "no irq" timer */ struct list_head list; /* ports on this IRQ */ unsigned int capabilities; /* port capabilities */ + unsigned int tx_loadsz; /* transmit fifo load size */ unsigned short rev; unsigned char acr; unsigned char ier; @@ -156,23 +157,23 @@ /* * Here we define the default xmit fifo size used for each type of UART. */ -static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { - { "unknown", 1, 0 }, - { "8250", 1, 0 }, - { "16450", 1, 0 }, - { "16550", 1, 0 }, - { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "Cirrus", 1, 0 }, - { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, - { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "Startech", 1, 0 }, - { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI }, - { "XScale", 32, UART_CLEAR_FIFO | UART_USE_FIFO }, +static const struct serial8250_config uart_config[PORT_MAX_8250+1] = { + { "unknown", 1, 1, 0 }, + { "8250", 1, 1, 0 }, + { "16450", 1, 1, 0 }, + { "16550", 1, 1, 0 }, + { "16550A", 16, 16, UART_CAP_FIFO }, + { "Cirrus", 1, 1, 0 }, + { "ST16650", 1, 1, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "ST16650V2", 32, 16, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "TI16750", 64, 64, UART_CAP_FIFO | UART_CAP_SLEEP }, + { "Startech", 1, 1, 0 }, + { "16C950/954", 128, 128, UART_CAP_FIFO }, + { "ST16654", 64, 32, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "XR16850", 128, 128, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "RSA", 2048, 2048, UART_CAP_FIFO }, + { "NS16550A", 16, 16, UART_CAP_FIFO | UART_NATSEMI }, + { "XScale", 32, 32, UART_CAP_FIFO }, }; static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) @@ -187,6 +188,9 @@ case UPIO_MEM: return readb(up->port.membase + offset); + case UPIO_MEM32: + return readl(up->port.membase + offset); + default: return inb(up->port.iobase + offset); } @@ -207,6 +211,10 @@ writeb(value, up->port.membase + offset); break; + case UPIO_MEM32: + writel(value, up->port.membase + offset); + break; + default: outb(value, up->port.iobase + offset); } @@ -243,6 +251,41 @@ return value; } +/* + * FIFO support. + */ +static inline void serial8250_clear_fifos(struct uart_8250_port *p) +{ + if (p->capabilities & UART_CAP_FIFO) { + serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(p, UART_FCR, 0); + } +} + +/* + * IER sleep support. UARTs which have EFRs need the "extended + * capability" bit enabled. Note that on XR16C850s, we need to + * reset LCR to write to IER. + */ +static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +{ + if (p->capabilities & UART_CAP_SLEEP) { + if (p->capabilities & UART_CAP_EFR) { + serial_outp(p, UART_LCR, 0xBF); + serial_outp(p, UART_EFR, UART_EFR_ECB); + serial_outp(p, UART_LCR, 0); + } + serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_outp(p, UART_LCR, 0xBF); + serial_outp(p, UART_EFR, 0); + serial_outp(p, UART_LCR, 0); + } + } +} + #ifdef CONFIG_SERIAL_8250_RSA /* * Attempts to turn on the RSA FIFO. Returns zero on failure. @@ -697,8 +740,9 @@ #endif serial_outp(up, UART_LCR, save_lcr); - up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; + up->port.fifosize = uart_config[up->port.type].fifo_size; up->capabilities = uart_config[up->port.type].flags; + up->tx_loadsz = uart_config[up->port.type].tx_loadsz; if (up->port.type == PORT_UNKNOWN) goto out; @@ -711,10 +755,7 @@ serial_outp(up, UART_RSA_FRR, 0); #endif serial_outp(up, UART_MCR, save_mcr); - serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(up, UART_FCR, 0); + serial8250_clear_fifos(up); (void)serial_in(up, UART_RX); serial_outp(up, UART_IER, 0); @@ -923,7 +964,7 @@ return; } - count = up->port.fifosize; + count = up->tx_loadsz; do { serial_out(up, UART_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -1227,12 +1268,7 @@ * Clear the FIFO buffers and disable them. * (they will be reeanbled in set_termios()) */ - if (up->capabilities & UART_CLEAR_FIFO) { - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); - } + serial8250_clear_fifos(up); /* * Clear the interrupt registers. @@ -1254,6 +1290,23 @@ } /* + * For a XR16C850, we need to set the trigger levels + */ + if (up->port.type == PORT_16850) { + unsigned char fctr; + + serial_outp(up, UART_LCR, 0xbf); + + fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); + serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_outp(up, UART_TRG, UART_TRG_96); + serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_outp(up, UART_TRG, UART_TRG_96); + + serial_outp(up, UART_LCR, 0); + } + + /* * If the "interrupt" for this port doesn't correspond with any * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. @@ -1345,10 +1398,7 @@ * Disable break condition and FIFOs */ serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); + serial8250_clear_fifos(up); #ifdef CONFIG_SERIAL_8250_RSA /* @@ -1440,7 +1490,7 @@ up->rev == 0x5201) quot ++; - if (up->capabilities & UART_USE_FIFO) { + if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { if (baud < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; #ifdef CONFIG_SERIAL_8250_RSA @@ -1514,7 +1564,7 @@ serial_out(up, UART_IER, up->ier); - if (up->capabilities & UART_STARTECH) { + if (up->capabilities & UART_CAP_EFR) { serial_outp(up, UART_LCR, 0xBF); serial_outp(up, UART_EFR, termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0); @@ -1554,71 +1604,12 @@ serial8250_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uart_8250_port *up = (struct uart_8250_port *)port; - if (state) { - /* sleep */ - if (up->capabilities & UART_STARTECH) { - /* Arrange to enter sleep mode */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_IER, UART_IERX_SLEEP); - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, 0); - serial_outp(up, UART_LCR, 0); - } - if (up->port.type == PORT_16750) { - /* Arrange to enter sleep mode */ - serial_outp(up, UART_IER, UART_IERX_SLEEP); - } + struct uart_8250_port *p = (struct uart_8250_port *)port; - if (up->pm) - up->pm(port, state, oldstate); - } else { - /* wake */ - if (up->capabilities & UART_STARTECH) { - /* Wake up UART */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - /* - * Turn off LCR == 0xBF so we actually set the IER - * register on the XR16C850 - */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_IER, 0); - /* - * Now reset LCR so we can turn off the ECB bit - */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, 0); - /* - * For a XR16C850, we need to set the trigger levels - */ - if (up->port.type == PORT_16850) { - unsigned char fctr; + serial8250_set_sleep(p, state != 0); - fctr = serial_inp(up, UART_FCTR) & - ~(UART_FCTR_RX | UART_FCTR_TX); - serial_outp(up, UART_FCTR, fctr | - UART_FCTR_TRGD | - UART_FCTR_RX); - serial_outp(up, UART_TRG, UART_TRG_96); - serial_outp(up, UART_FCTR, fctr | - UART_FCTR_TRGD | - UART_FCTR_TX); - serial_outp(up, UART_TRG, UART_TRG_96); - } - serial_outp(up, UART_LCR, 0); - } - - if (up->port.type == PORT_16750) { - /* Wake up UART */ - serial_outp(up, UART_IER, 0); - } - - if (up->pm) - up->pm(port, state, oldstate); - } + if (p->pm) + p->pm(port, state, oldstate); } /* diff -Nru a/drivers/serial/8250.h b/drivers/serial/8250.h --- a/drivers/serial/8250.h 2004-10-18 14:55:53 -07:00 +++ b/drivers/serial/8250.h 2004-10-18 14:55:53 -07:00 @@ -33,6 +33,20 @@ unsigned short iomem_reg_shift; }; +/* + * This replaces serial_uart_config in include/linux/serial.h + */ +struct serial8250_config { + const char *name; + unsigned int fifo_size; + unsigned int tx_loadsz; + unsigned int flags; +}; + +#define UART_CAP_FIFO (1 << 8) /* UART has FIFO */ +#define UART_CAP_EFR (1 << 9) /* UART has EFR */ +#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */ + #undef SERIAL_DEBUG_PCI #if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) diff -Nru a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c --- a/drivers/serial/8250_pci.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/serial/8250_pci.c 2004-10-18 14:56:49 -07:00 @@ -83,7 +83,7 @@ struct serial_private { unsigned int nr; - void *remapped_bar[PCI_NUM_BAR_RESOURCES]; + void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES]; struct pci_serial_quirk *quirk; int line[0]; }; @@ -243,7 +243,8 @@ */ static int __devinit pci_plx9050_init(struct pci_dev *dev) { - u8 *p, irq_config; + u8 irq_config; + void __iomem *p; if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) { moan_device("no memory in bar 0", dev); @@ -272,12 +273,12 @@ p = ioremap(pci_resource_start(dev, 0), 0x80); if (p == NULL) return -ENOMEM; - writel(irq_config, (unsigned long)p + 0x4c); + writel(irq_config, p + 0x4c); /* * Read the register back to ensure that it took effect. */ - readl((unsigned long)p + 0x4c); + readl(p + 0x4c); iounmap(p); return 0; @@ -397,7 +398,8 @@ static int pci_siig10x_init(struct pci_dev *dev) { - u16 data, *p; + u16 data; + void __iomem *p; switch (dev->device & 0xfff8) { case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ @@ -415,8 +417,8 @@ if (p == NULL) return -ENOMEM; - writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28); - readw((unsigned long)p + 0x28); + writew(readw(p + 0x28) & data, p + 0x28); + readw(p + 0x28); iounmap(p); return 0; } @@ -1068,6 +1070,9 @@ pbn_computone_6, pbn_computone_8, pbn_sbsxrsio, + pbn_exar_XR17C152, + pbn_exar_XR17C154, + pbn_exar_XR17C158, }; /* @@ -1488,7 +1493,30 @@ .base_baud = 460800, .uart_offset = 256, .reg_shift = 4, - } + }, + /* + * Exar Corp. XR17C15[248] Dual/Quad/Octal UART + * Only basic 16550A support. + * XR17C15[24] are not tested, but they should work. + */ + [pbn_exar_XR17C152] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_exar_XR17C154] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_exar_XR17C158] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x200, + }, }; /* @@ -2146,6 +2174,22 @@ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b3_8_115200 }, + + /* + * Exar Corp. XR17C15[248] Dual/Quad/Octal UART + */ + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C152 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C154 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C158 }, /* * These entries match devices with class COMMUNICATION_SERIAL, diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig --- a/drivers/serial/Kconfig 2004-10-18 14:57:03 -07:00 +++ b/drivers/serial/Kconfig 2004-10-18 14:57:03 -07:00 @@ -450,7 +450,7 @@ config PDC_CONSOLE bool "PDC software console support" - depends on PARISC && !SERIAL_MUX + depends on PARISC && !SERIAL_MUX && VT default n help Saying Y here will enable the software based PDC console to be @@ -682,6 +682,7 @@ bool "SGI Altix L1 serial console support" depends on IA64_GENERIC || IA64_SGI_SN2 select SERIAL_CORE + select SERIAL_CORE_CONSOLE help If you have an SGI Altix and you would like to use the system controller serial port as your console (you want this!), @@ -713,5 +714,17 @@ Select the MPC52xx console baud rate. This value is only used if the bootloader doesn't pass in the console baudrate + +config SERIAL_ICOM + tristate "IBM Multiport Serial Adapter" + depends on PPC_ISERIES || PPC_PSERIES + select SERIAL_CORE + help + This driver is for a family of multiport serial adapters + including 2 port RVX, 2 port internal modem, 4 port internal + modem and a split 1 port RVX and 1 port internal modem. + + This driver can also be built as a module. If so, the module + will be called icom. endmenu diff -Nru a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c --- a/drivers/serial/amba-pl011.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/serial/amba-pl011.c 2004-10-18 14:57:05 -07:00 @@ -696,7 +696,6 @@ int bits = 8; int parity = 'n'; int flow = 'n'; - int ret; /* * Check whether an invalid uart number has been specified, and diff -Nru a/drivers/serial/bast_sio.c b/drivers/serial/bast_sio.c --- a/drivers/serial/bast_sio.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/serial/bast_sio.c 2004-10-18 14:55:54 -07:00 @@ -1,3 +1,19 @@ +/* linux/drivers/serial/bast_sio.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 23-Sep-2004 BJD Added copyright header + * 23-Sep-2004 BJD Added serial port remove code +*/ + #include #include #include @@ -20,10 +36,6 @@ { struct serial_struct serial_req; -#if 0 - printk("BAST: SuperIO serial (%08lx,%d)\n", port, irq); -#endif - serial_req.flags = UPF_AUTOPROBE | UPF_SHARE_IRQ; serial_req.baud_base = BASE_BAUD; serial_req.irq = irq; @@ -37,11 +49,13 @@ #define SERIAL_BASE (S3C2410_CS2 + BAST_PA_SUPERIO) +static int port[2] = { -1, -1 }; + static int __init serial_bast_init(void) { if (machine_is_bast()) { - serial_bast_register(SERIAL_BASE + 0x2f8, IRQ_PCSERIAL1); - serial_bast_register(SERIAL_BASE + 0x3f8, IRQ_PCSERIAL2); + port[0] = serial_bast_register(SERIAL_BASE + 0x2f8, IRQ_PCSERIAL1); + port[1] = serial_bast_register(SERIAL_BASE + 0x3f8, IRQ_PCSERIAL2); } return 0; @@ -49,7 +63,10 @@ static void __exit serial_bast_exit(void) { - /* todo -> remove both our ports */ + if (port[0] != -1) + unregister_serial(port[0]); + if (port[1] != -1) + unregister_serial(port[1]); } diff -Nru a/drivers/serial/icom.c b/drivers/serial/icom.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/serial/icom.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,1702 @@ +/* + * icom.c + * + * Copyright (C) 2001 IBM Corporation. All rights reserved. + * + * Serial device driver. + * + * Based on code from serial.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#define SERIAL_DO_RESTART +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "icom.h" + +/*#define ICOM_TRACE enable port trace capabilities */ + +#define ICOM_DRIVER_NAME "icom" +#define ICOM_VERSION_STR "1.3.1" +#define NR_PORTS 128 +#define ICOM_PORT ((struct icom_port *)port) +#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj) + +static const struct pci_device_id icom_pci_table[] = { + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = ADAPTER_V1, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX, + .driver_data = ADAPTER_V2, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM, + .driver_data = ADAPTER_V2, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL, + .driver_data = ADAPTER_V2, + }, + {} +}; + +struct lookup_proc_table start_proc[4] = { + {0, ICOM_CONTROL_START_A}, + {0, ICOM_CONTROL_START_B}, + {0, ICOM_CONTROL_START_C}, + {0, ICOM_CONTROL_START_D} +}; + + +struct lookup_proc_table stop_proc[4] = { + {0, ICOM_CONTROL_STOP_A}, + {0, ICOM_CONTROL_STOP_B}, + {0, ICOM_CONTROL_STOP_C}, + {0, ICOM_CONTROL_STOP_D} +}; + +struct lookup_int_table int_mask_tbl[4] = { + {0, ICOM_INT_MASK_PRC_A}, + {0, ICOM_INT_MASK_PRC_B}, + {0, ICOM_INT_MASK_PRC_C}, + {0, ICOM_INT_MASK_PRC_D}, +}; + + +MODULE_DEVICE_TABLE(pci, icom_pci_table); + +static LIST_HEAD(icom_adapter_head); + +/* spinlock for adapter initialization and changing adapter operations */ +static spinlock_t icom_lock; + +#ifdef ICOM_TRACE +static inline void trace(struct icom_port *, char *, unsigned long) {}; +#else +static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; +#endif + +static void msleep(unsigned long msecs) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(MSECS_TO_JIFFIES(msecs)); +} + +static void free_port_memory(struct icom_port *icom_port) +{ + struct pci_dev *dev = icom_port->adapter->pci_dev; + + trace(icom_port, "RET_PORT_MEM", 0); + if (icom_port->recv_buf) { + pci_free_consistent(dev, 4096, icom_port->recv_buf, + icom_port->recv_buf_pci); + icom_port->recv_buf = 0; + } + if (icom_port->xmit_buf) { + pci_free_consistent(dev, 4096, icom_port->xmit_buf, + icom_port->xmit_buf_pci); + icom_port->xmit_buf = 0; + } + if (icom_port->statStg) { + pci_free_consistent(dev, 4096, icom_port->statStg, + icom_port->statStg_pci); + icom_port->statStg = 0; + } + + if (icom_port->xmitRestart) { + pci_free_consistent(dev, 4096, icom_port->xmitRestart, + icom_port->xmitRestart_pci); + icom_port->xmitRestart = 0; + } +} + +static int __init get_port_memory(struct icom_port *icom_port) +{ + int index; + unsigned long stgAddr; + unsigned long startStgAddr; + unsigned long offset; + struct pci_dev *dev = icom_port->adapter->pci_dev; + + icom_port->xmit_buf = + pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci); + if (!icom_port->xmit_buf) { + dev_err(&dev->dev, "Can not allocate Transmit buffer\n"); + return -ENOMEM; + } + + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->xmit_buf); + + icom_port->recv_buf = + pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci); + if (!icom_port->recv_buf) { + dev_err(&dev->dev, "Can not allocate Receive buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->recv_buf); + + icom_port->statStg = + pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci); + if (!icom_port->statStg) { + dev_err(&dev->dev, "Can not allocate Status buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->statStg); + + icom_port->xmitRestart = + pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci); + if (!icom_port->xmitRestart) { + dev_err(&dev->dev, + "Can not allocate xmit Restart buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + + memset(icom_port->statStg, 0, 4096); + + /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that + indicates that frames are to be transmitted + */ + + stgAddr = (unsigned long) icom_port->statStg; + for (index = 0; index < NUM_XBUFFS; index++) { + trace(icom_port, "FOD_ADDR", stgAddr); + stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]); + if (index < (NUM_XBUFFS - 1)) { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + icom_port->statStg->xmit[index].leLengthASD = + (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + trace(icom_port, "FOD_ADDR", stgAddr); + trace(icom_port, "FOD_XBUFF", + (unsigned long) icom_port->xmit_buf); + icom_port->statStg->xmit[index].leBuffer = + cpu_to_le32(icom_port->xmit_buf_pci); + } else if (index == (NUM_XBUFFS - 1)) { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + icom_port->statStg->xmit[index].leLengthASD = + (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + trace(icom_port, "FOD_XBUFF", + (unsigned long) icom_port->xmit_buf); + icom_port->statStg->xmit[index].leBuffer = + cpu_to_le32(icom_port->xmit_buf_pci); + } else { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + } + } + /* FIDs */ + startStgAddr = stgAddr; + + /* fill in every entry, even if no buffer */ + for (index = 0; index < NUM_RBUFFS; index++) { + trace(icom_port, "FID_ADDR", stgAddr); + stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]); + icom_port->statStg->rcv[index].leLength = 0; + icom_port->statStg->rcv[index].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + if (index < (NUM_RBUFFS - 1) ) { + offset = stgAddr - (unsigned long) icom_port->statStg; + icom_port->statStg->rcv[index].leNext = + cpu_to_le32(icom_port-> statStg_pci + offset); + trace(icom_port, "FID_RBUFF", + (unsigned long) icom_port->recv_buf); + icom_port->statStg->rcv[index].leBuffer = + cpu_to_le32(icom_port->recv_buf_pci); + } else if (index == (NUM_RBUFFS -1) ) { + offset = startStgAddr - (unsigned long) icom_port->statStg; + icom_port->statStg->rcv[index].leNext = + cpu_to_le32(icom_port-> statStg_pci + offset); + trace(icom_port, "FID_RBUFF", + (unsigned long) icom_port->recv_buf + 2048); + icom_port->statStg->rcv[index].leBuffer = + cpu_to_le32(icom_port->recv_buf_pci + 2048); + } else { + icom_port->statStg->rcv[index].leNext = 0; + icom_port->statStg->rcv[index].leBuffer = 0; + } + } + + return 0; +} + +static void stop_processor(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + + port = icom_port->port; + if (port == 0 || port == 1) + stop_proc[port].global_control_reg = &icom_port->global_reg->control; + else + stop_proc[port].global_control_reg = &icom_port->global_reg->control_2; + + + if (port < 4) { + temp = readl(stop_proc[port].global_control_reg); + temp = + (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id; + writel(temp, stop_proc[port].global_control_reg); + + /* write flush */ + readl(stop_proc[port].global_control_reg); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); +} + +static void start_processor(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + + port = icom_port->port; + if (port == 0 || port == 1) + start_proc[port].global_control_reg = &icom_port->global_reg->control; + else + start_proc[port].global_control_reg = &icom_port->global_reg->control_2; + if (port < 4) { + temp = readl(start_proc[port].global_control_reg); + temp = + (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id; + writel(temp, start_proc[port].global_control_reg); + + /* write flush */ + readl(start_proc[port].global_control_reg); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); +} + +static void load_code(struct icom_port *icom_port) +{ + const struct firmware *fw; + char *iram_ptr; + int index; + int status = 0; + char *dram_ptr = (char *) icom_port->dram; + dma_addr_t temp_pci; + unsigned char *new_page = NULL; + unsigned char cable_id = NO_CABLE; + struct pci_dev *dev = icom_port->adapter->pci_dev; + + /* Clear out any pending interrupts */ + writew(0x3FFF, (void *) icom_port->int_reg); + + trace(icom_port, "CLEAR_INTERRUPTS", 0); + + /* Stop processor */ + stop_processor(icom_port); + + /* Zero out DRAM */ + memset_io(dram_ptr, 0, 512); + + /* Load Call Setup into Adapter */ + if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_DCE_IRAM_OFFSET) { + dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + iram_ptr = (char *) icom_port->dram + ICOM_IRAM_OFFSET; + for (index = 0; index < fw->size; index++) + writeb(fw->data[index], &iram_ptr[index]); + + release_firmware(fw); + + /* Load Resident DCE portion of Adapter */ + if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_IRAM_SIZE) { + dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + iram_ptr = (char *) icom_port->dram + ICOM_IRAM_OFFSET; + for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++) + writeb(fw->data[index], &iram_ptr[index]); + + release_firmware(fw); + + /* Set Hardware level */ + if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2) + writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); + + /* Start the processor in Adapter */ + start_processor(icom_port); + + writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL), + &(icom_port->dram->HDLCConfigReg)); + writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */ + writeb(0x00, &(icom_port->dram->CmdReg)); + writeb(0x10, &(icom_port->dram->async_config3)); + writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC | + ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2)); + + /*Set up data in icom DRAM to indicate where personality + *code is located and its length. + */ + new_page = pci_alloc_consistent(dev, 4096, &temp_pci); + + if (!new_page) { + dev_err(&dev->dev, "Can not allocate DMA buffer\n"); + status = -1; + goto load_code_exit; + } + + if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_DCE_IRAM_OFFSET) { + dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + for (index = 0; index < fw->size; index++) + new_page[index] = fw->data[index]; + + release_firmware(fw); + + writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length); + writel(temp_pci, &icom_port->dram->mac_load_addr); + + /*Setting the syncReg to 0x80 causes adapter to start downloading + the personality code into adapter instruction RAM. + Once code is loaded, it will begin executing and, based on + information provided above, will start DMAing data from + shared memory to adapter DRAM. + */ + /* the wait loop below verifies this write operation has been done + and processed + */ + writeb(START_DOWNLOAD, &icom_port->dram->sync); + + /* Wait max 1 Sec for data download and processor to start */ + for (index = 0; index < 10; index++) { + msleep(100); + if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE) + break; + } + + if (index == 10) + status = -1; + + /* + * check Cable ID + */ + cable_id = readb(&icom_port->dram->cable_id); + + if (cable_id & ICOM_CABLE_ID_VALID) { + /* Get cable ID into the lower 4 bits (standard form) */ + cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4; + icom_port->cable_id = cable_id; + } else { + dev_err(&dev->dev,"Invalid or no cable attached\n"); + icom_port->cable_id = NO_CABLE; + } + + load_code_exit: + + if (status != 0) { + /* Clear out any pending interrupts */ + writew(0x3FFF, (void *) icom_port->int_reg); + + /* Turn off port */ + writeb(ICOM_DISABLE, &(icom_port->dram->disable)); + + /* Stop processor */ + stop_processor(icom_port); + + dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n"); + } + + if (new_page != NULL) + pci_free_consistent(dev, 4096, new_page, temp_pci); +} + +static int startup(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned char cable_id, raw_cable_id; + unsigned long flags; + int port; + + trace(icom_port, "STARTUP", 0); + + if (icom_port->dram == 0x00000000) { + /* should NEVER be zero */ + dev_err(&icom_port->adapter->pci_dev->dev, + "Unusable Port, port configuration missing\n"); + return -ENODEV; + } + + /* + * check Cable ID + */ + raw_cable_id = readb(&icom_port->dram->cable_id); + trace(icom_port, "CABLE_ID", raw_cable_id); + + /* Get cable ID into the lower 4 bits (standard form) */ + cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; + + /* Check for valid Cable ID */ + if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || + (cable_id != icom_port->cable_id)) { + + /* reload adapter code, pick up any potential changes in cable id */ + load_code(icom_port); + + /* still no sign of cable, error out */ + raw_cable_id = readb(&icom_port->dram->cable_id); + cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; + if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || + (icom_port->cable_id == NO_CABLE)) + return -EIO; + } + + /* + * Finally, clear and enable interrupts + */ + spin_lock_irqsave(&icom_lock, flags); + port = icom_port->port; + if (port == 0 || port == 1) + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; + else + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; + + if (port == 0 || port == 2) + writew(0x00FF,(void *) icom_port->int_reg); + else + writew(0x3F00,(void *) icom_port->int_reg); + if (port < 4) { + temp = readl(int_mask_tbl[port].global_int_mask); + writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); + + /* write flush */ + readl(int_mask_tbl[port].global_int_mask); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); + return 0; +} + +static void shutdown(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned char cmdReg; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + trace(icom_port, "SHUTDOWN", 0); + + /* + * disable all interrupts + */ + port = icom_port->port; + if (port == 0 || port == 1) + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; + else + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; + + if (port < 4) { + temp = readl(int_mask_tbl[port].global_int_mask); + writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); + + /* write flush */ + readl(int_mask_tbl[port].global_int_mask); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + spin_unlock_irqrestore(&icom_lock, flags); + + /* + * disable break condition + */ + cmdReg = readb(&icom_port->dram->CmdReg); + if ((cmdReg | CMD_SND_BREAK) == CMD_SND_BREAK) { + writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); + } +} + +static int icom_write(struct uart_port *port) +{ + unsigned long data_count; + unsigned char cmdReg; + unsigned long offset; + int temp_tail = port->info->xmit.tail; + + trace(ICOM_PORT, "WRITE", 0); + + if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + SA_FLAGS_READY_TO_XMIT) { + trace(ICOM_PORT, "WRITE_FULL", 0); + return 0; + } + + data_count = 0; + while ((port->info->xmit.head != temp_tail) && + (data_count <= XMIT_BUFF_SZ)) { + + ICOM_PORT->xmit_buf[data_count++] = + port->info->xmit.buf[temp_tail]; + + temp_tail++; + temp_tail &= (UART_XMIT_SIZE - 1); + } + + if (data_count) { + ICOM_PORT->statStg->xmit[0].flags = + cpu_to_le16(SA_FLAGS_READY_TO_XMIT); + ICOM_PORT->statStg->xmit[0].leLength = + cpu_to_le16(data_count); + offset = + (unsigned long) &ICOM_PORT->statStg->xmit[0] - + (unsigned long) ICOM_PORT->statStg; + *ICOM_PORT->xmitRestart = + cpu_to_le32(ICOM_PORT->statStg_pci + offset); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg | CMD_XMIT_RCV_ENABLE, + &ICOM_PORT->dram->CmdReg); + writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd); + trace(ICOM_PORT, "WRITE_START", data_count); + /* write flush */ + readb(&ICOM_PORT->dram->StartXmitCmd); + } + + return data_count; +} + +static inline void check_modem_status(struct icom_port *icom_port) +{ + static char old_status = 0; + char delta_status; + unsigned char status; + + spin_lock(&icom_port->uart_port.lock); + + /*modem input register */ + status = readb(&icom_port->dram->isr); + trace(icom_port, "CHECK_MODEM", status); + delta_status = status ^ old_status; + if (delta_status) { + if (delta_status & ICOM_RI) + icom_port->uart_port.icount.rng++; + if (delta_status & ICOM_DSR) + icom_port->uart_port.icount.dsr++; + if (delta_status & ICOM_DCD) + uart_handle_dcd_change(&icom_port->uart_port, + delta_status & ICOM_DCD); + if (delta_status & ICOM_CTS) + uart_handle_cts_change(&icom_port->uart_port, + delta_status & ICOM_CTS); + + wake_up_interruptible(&icom_port->uart_port.info-> + delta_msr_wait); + old_status = status; + } + spin_unlock(&icom_port->uart_port.lock); +} + +static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) +{ + unsigned short int count; + int i; + + if (port_int_reg & (INT_XMIT_COMPLETED)) { + trace(icom_port, "XMIT_COMPLETE", 0); + + /* clear buffer in use bit */ + icom_port->statStg->xmit[0].flags &= + cpu_to_le16(~SA_FLAGS_READY_TO_XMIT); + + count = (unsigned short int) + cpu_to_le16(icom_port->statStg->xmit[0].leLength); + icom_port->uart_port.icount.tx += count; + + for (i=0; iuart_port.info->xmit); i++) { + + icom_port->uart_port.info->xmit.tail++; + icom_port->uart_port.info->xmit.tail &= + (UART_XMIT_SIZE - 1); + } + + if (!icom_write(&icom_port->uart_port)) + /* activate write queue */ + uart_write_wakeup(&icom_port->uart_port); + } else + trace(icom_port, "XMIT_DISABLED", 0); +} + +static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) +{ + short int count, rcv_buff; + struct tty_struct *tty = icom_port->uart_port.info->tty; + unsigned short int status; + struct uart_icount *icount; + unsigned long offset; + + trace(icom_port, "RCV_COMPLETE", 0); + rcv_buff = icom_port->next_rcv; + + status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + while (status & SA_FL_RCV_DONE) { + + trace(icom_port, "FID_STATUS", status); + count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); + + trace(icom_port, "RCV_COUNT", count); + if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) + count = TTY_FLIPBUF_SIZE - tty->flip.count; + + trace(icom_port, "REAL_COUNT", count); + + offset = + cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - + icom_port->recv_buf_pci; + + memcpy(tty->flip.char_buf_ptr,(unsigned char *) + ((unsigned long)icom_port->recv_buf + offset), count); + + if (count > 0) { + tty->flip.count += count - 1; + tty->flip.char_buf_ptr += count - 1; + + memset(tty->flip.flag_buf_ptr, 0, count); + tty->flip.flag_buf_ptr += count - 1; + } + + icount = &icom_port->uart_port.icount; + icount->rx += count; + + /* Break detect logic */ + if ((status & SA_FLAGS_FRAME_ERROR) + && (tty->flip.char_buf_ptr[0] == 0x00)) { + status &= ~SA_FLAGS_FRAME_ERROR; + status |= SA_FLAGS_BREAK_DET; + trace(icom_port, "BREAK_DET", 0); + } + + if (status & + (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | + SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { + + if (status & SA_FLAGS_BREAK_DET) + icount->brk++; + if (status & SA_FLAGS_PARITY_ERROR) + icount->parity++; + if (status & SA_FLAGS_FRAME_ERROR) + icount->frame++; + if (status & SA_FLAGS_OVERRUN) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (status & icom_port->ignore_status_mask) { + trace(icom_port, "IGNORE_CHAR", 0); + goto ignore_char; + } + + status &= icom_port->read_status_mask; + + if (status & SA_FLAGS_BREAK_DET) { + *tty->flip.flag_buf_ptr = TTY_BREAK; + } else if (status & SA_FLAGS_PARITY_ERROR) { + trace(icom_port, "PARITY_ERROR", 0); + *tty->flip.flag_buf_ptr = TTY_PARITY; + } else if (status & SA_FLAGS_FRAME_ERROR) + *tty->flip.flag_buf_ptr = TTY_FRAME; + + if (status & SA_FLAGS_OVERRUN) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + icom_port->statStg->rcv[rcv_buff].flags = 0; + icom_port->statStg->rcv[rcv_buff].leLength = 0; + icom_port->statStg->rcv[rcv_buff].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + + rcv_buff++; + if (rcv_buff == NUM_RBUFFS) + rcv_buff = 0; + + status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + } + icom_port->next_rcv = rcv_buff; + tty_flip_buffer_push(tty); +} + +static void process_interrupt(u16 port_int_reg, + struct icom_port *icom_port) +{ + + spin_lock(&icom_port->uart_port.lock); + trace(icom_port, "INTERRUPT", port_int_reg); + + if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) + xmit_interrupt(port_int_reg, icom_port); + + if (port_int_reg & INT_RCV_COMPLETED) + recv_interrupt(port_int_reg, icom_port); + + spin_unlock(&icom_port->uart_port.lock); +} + +static irqreturn_t icom_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + unsigned long int_reg; + u32 adapter_interrupts; + u16 port_int_reg; + struct icom_adapter *icom_adapter; + struct icom_port *icom_port; + + /* find icom_port for this interrupt */ + icom_adapter = (struct icom_adapter *) dev_id; + + if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { + int_reg = icom_adapter->base_addr + 0x8024; + + adapter_interrupts = readl((void *) int_reg); + + if (adapter_interrupts & 0x00003FFF) { + /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */ + icom_port = &icom_adapter->port_info[2]; + port_int_reg = (u16) adapter_interrupts; + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + if (adapter_interrupts & 0x3FFF0000) { + /* port 3 interrupt */ + icom_port = &icom_adapter->port_info[3]; + if (icom_port->status == ICOM_PORT_ACTIVE) { + port_int_reg = + (u16) (adapter_interrupts >> 16); + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + } + + /* Clear out any pending interrupts */ + writel(adapter_interrupts, (void *) int_reg); + + int_reg = icom_adapter->base_addr + 0x8004; + } else { + int_reg = icom_adapter->base_addr + 0x4004; + } + + adapter_interrupts = readl((void *) int_reg); + + if (adapter_interrupts & 0x00003FFF) { + /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */ + icom_port = &icom_adapter->port_info[0]; + port_int_reg = (u16) adapter_interrupts; + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + if (adapter_interrupts & 0x3FFF0000) { + /* port 1 interrupt */ + icom_port = &icom_adapter->port_info[1]; + if (icom_port->status == ICOM_PORT_ACTIVE) { + port_int_reg = (u16) (adapter_interrupts >> 16); + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + } + + /* Clear out any pending interrupts */ + writel(adapter_interrupts, (void *) int_reg); + + /* flush the write */ + adapter_interrupts = readl((void *) int_reg); + + return IRQ_HANDLED; +} + +/* + * ------------------------------------------------------------------ + * Begin serial-core API + * ------------------------------------------------------------------ + */ +static unsigned int icom_tx_empty(struct uart_port *port) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + SA_FLAGS_READY_TO_XMIT) + ret = TIOCSER_TEMT; + else + ret = 0; + + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned char local_osr; + + trace(ICOM_PORT, "SET_MODEM", 0); + local_osr = readb(&ICOM_PORT->dram->osr); + + if (mctrl & TIOCM_RTS) { + trace(ICOM_PORT, "RAISE_RTS", 0); + local_osr |= ICOM_RTS; + } else { + trace(ICOM_PORT, "LOWER_RTS", 0); + local_osr &= ~ICOM_RTS; + } + + if (mctrl & TIOCM_DTR) { + trace(ICOM_PORT, "RAISE_DTR", 0); + local_osr |= ICOM_DTR; + } else { + trace(ICOM_PORT, "LOWER_DTR", 0); + local_osr &= ~ICOM_DTR; + } + + writeb(local_osr, &ICOM_PORT->dram->osr); +} + +static unsigned int icom_get_mctrl(struct uart_port *port) +{ + unsigned char status; + unsigned int result; + + trace(ICOM_PORT, "GET_MODEM", 0); + + status = readb(&ICOM_PORT->dram->isr); + + result = ((status & ICOM_DCD) ? TIOCM_CAR : 0) + | ((status & ICOM_RI) ? TIOCM_RNG : 0) + | ((status & ICOM_DSR) ? TIOCM_DSR : 0) + | ((status & ICOM_CTS) ? TIOCM_CTS : 0); + return result; +} + +static void icom_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + unsigned char cmdReg; + + if (tty_stop) { + trace(ICOM_PORT, "STOP", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg); + } +} + +static void icom_start_tx(struct uart_port *port, unsigned int tty_start) +{ + unsigned char cmdReg; + + trace(ICOM_PORT, "START", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT) + writeb(cmdReg & ~CMD_HOLD_XMIT, + &ICOM_PORT->dram->CmdReg); + + icom_write(port); +} + +static void icom_send_xchar(struct uart_port *port, char ch) +{ + unsigned char xdata; + int index; + unsigned long flags; + + trace(ICOM_PORT, "SEND_XCHAR", ch); + + /* wait .1 sec to send char */ + for (index = 0; index < 10; index++) { + spin_lock_irqsave(&port->lock, flags); + xdata = readb(&ICOM_PORT->dram->xchar); + if (xdata == 0x00) { + trace(ICOM_PORT, "QUICK_WRITE", 0); + writeb(ch, &ICOM_PORT->dram->xchar); + + /* flush write operation */ + xdata = readb(&ICOM_PORT->dram->xchar); + spin_unlock_irqrestore(&port->lock, flags); + break; + } + spin_unlock_irqrestore(&port->lock, flags); + msleep(10); + } +} + +static void icom_stop_rx(struct uart_port *port) +{ + unsigned char cmdReg; + + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); +} + +static void icom_enable_ms(struct uart_port *port) +{ + /* no-op */ +} + +static void icom_break(struct uart_port *port, int break_state) +{ + unsigned char cmdReg; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + trace(ICOM_PORT, "BREAK", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + if (break_state == -1) { + writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + } else { + writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static int icom_open(struct uart_port *port) +{ + int retval; + + kobject_get(&ICOM_PORT->adapter->kobj); + retval = startup(ICOM_PORT); + + if (retval) { + kobject_put(&ICOM_PORT->adapter->kobj); + trace(ICOM_PORT, "STARTUP_ERROR", 0); + return retval; + } + + return 0; +} + +static void icom_close(struct uart_port *port) +{ + unsigned char cmdReg; + + trace(ICOM_PORT, "CLOSE", 0); + + /* stop receiver */ + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE, + &ICOM_PORT->dram->CmdReg); + + shutdown(ICOM_PORT); + + kobject_put(&ICOM_PORT->adapter->kobj); +} + +static void icom_set_termios(struct uart_port *port, + struct termios *termios, + struct termios *old_termios) +{ + int baud; + unsigned cflag, iflag; + int bits; + char new_config2; + char new_config3 = 0; + char tmp_byte; + int index; + int rcv_buff, xmit_buff; + unsigned long offset; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + trace(ICOM_PORT, "CHANGE_SPEED", 0); + + cflag = termios->c_cflag; + iflag = termios->c_iflag; + + new_config2 = ICOM_ACFG_DRIVE1; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: /* 5 bits/char */ + new_config2 |= ICOM_ACFG_5BPC; + bits = 7; + break; + case CS6: /* 6 bits/char */ + new_config2 |= ICOM_ACFG_6BPC; + bits = 8; + break; + case CS7: /* 7 bits/char */ + new_config2 |= ICOM_ACFG_7BPC; + bits = 9; + break; + case CS8: /* 8 bits/char */ + new_config2 |= ICOM_ACFG_8BPC; + bits = 10; + break; + default: + bits = 10; + break; + } + if (cflag & CSTOPB) { + /* 2 stop bits */ + new_config2 |= ICOM_ACFG_2STOP_BIT; + bits++; + } + if (cflag & PARENB) { + /* parity bit enabled */ + new_config2 |= ICOM_ACFG_PARITY_ENAB; + trace(ICOM_PORT, "PARENB", 0); + bits++; + } + if (cflag & PARODD) { + /* odd parity */ + new_config2 |= ICOM_ACFG_PARITY_ODD; + trace(ICOM_PORT, "PARODD", 0); + } + + /* Determine divisor based on baud rate */ + baud = uart_get_baud_rate(port, termios, old_termios, + icom_acfg_baud[0], + icom_acfg_baud[BAUD_TABLE_LIMIT]); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + + for (index = 0; index < BAUD_TABLE_LIMIT; index++) { + if (icom_acfg_baud[index] == baud) { + new_config3 = index; + break; + } + } + + uart_update_timeout(port, cflag, baud); + + /* CTS flow control flag and modem status interrupts */ + tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + if (cflag & CRTSCTS) + tmp_byte |= HDLC_HDW_FLOW; + else + tmp_byte &= ~HDLC_HDW_FLOW; + writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); + + /* + * Set up parity check flag + */ + ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE; + if (iflag & INPCK) + ICOM_PORT->read_status_mask |= + SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR; + + if ((iflag & BRKINT) || (iflag & PARMRK)) + ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET; + + /* + * Characters to ignore + */ + ICOM_PORT->ignore_status_mask = 0; + if (iflag & IGNPAR) + ICOM_PORT->ignore_status_mask |= + SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR; + if (iflag & IGNBRK) { + ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (iflag & IGNPAR) + ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN; + } + + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE; + + /* Turn off Receiver to prepare for reset */ + writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg); + + for (index = 0; index < 10; index++) { + if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) { + break; + } + } + + /* clear all current buffers of data */ + for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) { + ICOM_PORT->statStg->rcv[rcv_buff].flags = 0; + ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0; + ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + } + + for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) { + ICOM_PORT->statStg->xmit[xmit_buff].flags = 0; + } + + /* activate changes and start xmit and receiver here */ + /* Enable the receiver */ + writeb(new_config3, &(ICOM_PORT->dram->async_config3)); + writeb(new_config2, &(ICOM_PORT->dram->async_config2)); + tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL; + writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); + writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */ + writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */ + + /* reset processor */ + writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg); + + for (index = 0; index < 10; index++) { + if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) { + break; + } + } + + /* Enable Transmitter and Reciever */ + offset = + (unsigned long) &ICOM_PORT->statStg->rcv[0] - + (unsigned long) ICOM_PORT->statStg; + writel(ICOM_PORT->statStg_pci + offset, + &ICOM_PORT->dram->RcvStatusAddr); + ICOM_PORT->next_rcv = 0; + ICOM_PORT->put_length = 0; + *ICOM_PORT->xmitRestart = 0; + writel(ICOM_PORT->xmitRestart_pci, + &ICOM_PORT->dram->XmitStatusAddr); + trace(ICOM_PORT, "XR_ENAB", 0); + writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *icom_type(struct uart_port *port) +{ + return "icom"; +} + +static void icom_release_port(struct uart_port *port) +{ +} + +static int icom_request_port(struct uart_port *port) +{ + return 0; +} + +static void icom_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_ICOM; +} + +static struct uart_ops icom_ops = { + .tx_empty = icom_tx_empty, + .set_mctrl = icom_set_mctrl, + .get_mctrl = icom_get_mctrl, + .stop_tx = icom_stop_tx, + .start_tx = icom_start_tx, + .send_xchar = icom_send_xchar, + .stop_rx = icom_stop_rx, + .enable_ms = icom_enable_ms, + .break_ctl = icom_break, + .startup = icom_open, + .shutdown = icom_close, + .set_termios = icom_set_termios, + .type = icom_type, + .release_port = icom_release_port, + .request_port = icom_request_port, + .config_port = icom_config_port, +}; + +#define ICOM_CONSOLE NULL + +static struct uart_driver icom_uart_driver = { + .owner = THIS_MODULE, + .driver_name = ICOM_DRIVER_NAME, + .dev_name = "ttyA", + .major = ICOM_MAJOR, + .minor = ICOM_MINOR_START, + .nr = NR_PORTS, + .cons = ICOM_CONSOLE, +}; + +static int __devinit icom_init_ports(struct icom_adapter *icom_adapter) +{ + u32 subsystem_id = icom_adapter->subsystem_id; + int retval = 0; + int i; + struct icom_port *icom_port; + + if (icom_adapter->version == ADAPTER_V1) { + icom_adapter->numb_ports = 2; + + for (i = 0; i < 2; i++) { + icom_port = &icom_adapter->port_info[i]; + icom_port->port = i; + icom_port->status = ICOM_PORT_ACTIVE; + icom_port->imbed_modem = ICOM_UNKNOWN; + } + } else { + if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) { + icom_adapter->numb_ports = 4; + + for (i = 0; i < 4; i++) { + icom_port = &icom_adapter->port_info[i]; + + icom_port->port = i; + icom_port->status = ICOM_PORT_ACTIVE; + icom_port->imbed_modem = ICOM_IMBED_MODEM; + } + } else { + icom_adapter->numb_ports = 4; + + icom_adapter->port_info[0].port = 0; + icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE; + + if (subsystem_id == + PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) { + icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM; + } else { + icom_adapter->port_info[0].imbed_modem = ICOM_RVX; + } + + icom_adapter->port_info[1].status = ICOM_PORT_OFF; + + icom_adapter->port_info[2].port = 2; + icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE; + icom_adapter->port_info[2].imbed_modem = ICOM_RVX; + icom_adapter->port_info[3].status = ICOM_PORT_OFF; + } + } + + return retval; +} + +static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num) +{ + if (icom_adapter->version == ADAPTER_V1) { + icom_port->global_reg = (struct icom_regs *) ((char *) + icom_adapter->base_addr + 0x4000); + icom_port->int_reg = (unsigned long) icom_adapter->base_addr + + 0x4004 + 2 - 2 * port_num; + } else { + icom_port->global_reg = (struct icom_regs *) ((char *) + icom_adapter->base_addr + 0x8000); + if (icom_port->port < 2) + icom_port->int_reg = (unsigned long) icom_adapter->base_addr + + 0x8004 + 2 - 2 * icom_port->port; + else + icom_port->int_reg = (unsigned long) icom_adapter->base_addr + + 0x8024 + 2 - 2 * (icom_port->port - 2); + } +} +static int __init icom_load_ports(struct icom_adapter *icom_adapter) +{ + struct icom_port *icom_port; + int port_num; + int retval; + + for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) { + + icom_port = &icom_adapter->port_info[port_num]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + icom_port_active(icom_port, icom_adapter, port_num); + icom_port->dram = (struct func_dram *) ((char *) + icom_adapter->base_addr + + 0x2000 * icom_port->port); + + icom_port->adapter = icom_adapter; + + /* get port memory */ + if ((retval = get_port_memory(icom_port)) != 0) { + dev_err(&icom_port->adapter->pci_dev->dev, + "Memory allocation for port FAILED\n"); + } + } + } + return 0; +} + +static int __devinit icom_alloc_adapter(struct icom_adapter + **icom_adapter_ref) +{ + int adapter_count = 0; + struct icom_adapter *icom_adapter; + struct icom_adapter *cur_adapter_entry; + struct list_head *tmp; + + icom_adapter = (struct icom_adapter *) + kmalloc(sizeof(struct icom_adapter), GFP_KERNEL); + + if (!icom_adapter) { + return -ENOMEM; + } + + memset(icom_adapter, 0, sizeof(struct icom_adapter)); + + list_for_each(tmp, &icom_adapter_head) { + cur_adapter_entry = + list_entry(tmp, struct icom_adapter, + icom_adapter_entry); + if (cur_adapter_entry->index != adapter_count) { + break; + } + adapter_count++; + } + + icom_adapter->index = adapter_count; + list_add_tail(&icom_adapter->icom_adapter_entry, tmp); + + *icom_adapter_ref = icom_adapter; + return 0; +} + +static void icom_free_adapter(struct icom_adapter *icom_adapter) +{ + list_del(&icom_adapter->icom_adapter_entry); + kfree(icom_adapter); +} + +static void icom_remove_adapter(struct icom_adapter *icom_adapter) +{ + struct icom_port *icom_port; + int index; + + for (index = 0; index < icom_adapter->numb_ports; index++) { + icom_port = &icom_adapter->port_info[index]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + dev_info(&icom_adapter->pci_dev->dev, + "Device removed\n"); + + uart_remove_one_port(&icom_uart_driver, + &icom_port->uart_port); + + /* be sure that DTR and RTS are dropped */ + writeb(0x00, &icom_port->dram->osr); + + /* Wait 0.1 Sec for simple Init to complete */ + msleep(100); + + /* Stop proccessor */ + stop_processor(icom_port); + + free_port_memory(icom_port); + } + } + + free_irq(icom_adapter->irq_number, (void *) icom_adapter); + iounmap((void *) icom_adapter->base_addr); + icom_free_adapter(icom_adapter); + pci_release_regions(icom_adapter->pci_dev); +} + +static void icom_kobj_release(struct kobject *kobj) +{ + struct icom_adapter *icom_adapter; + + icom_adapter = to_icom_adapter(kobj); + icom_remove_adapter(icom_adapter); +} + +static struct kobj_type icom_kobj_type = { + .release = icom_kobj_release, +}; + +static int __devinit icom_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + int index; + unsigned int command_reg; + int retval; + struct icom_adapter *icom_adapter; + struct icom_port *icom_port; + + retval = pci_enable_device(dev); + if (retval) { + dev_err(&dev->dev, "Device enable FAILED\n"); + return retval; + } + + if ( (retval = pci_request_regions(dev, "icom"))) { + dev_err(&dev->dev, "pci_request_region FAILED\n"); + pci_disable_device(dev); + return retval; + } + + pci_set_master(dev); + + if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { + dev_err(&dev->dev, "PCI Config read FAILED\n"); + return retval; + } + + pci_write_config_dword(dev, PCI_COMMAND, + command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER + | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + + if (ent->driver_data == ADAPTER_V1) { + pci_write_config_dword(dev, 0x44, 0x8300830A); + } else { + pci_write_config_dword(dev, 0x44, 0x42004200); + pci_write_config_dword(dev, 0x48, 0x42004200); + } + + + retval = icom_alloc_adapter(&icom_adapter); + if (retval) { + dev_err(&dev->dev, "icom_alloc_adapter FAILED\n"); + retval = -EIO; + goto probe_exit0; + } + + icom_adapter->base_addr_pci = pci_resource_start(dev, 0); + icom_adapter->irq_number = dev->irq; + icom_adapter->pci_dev = dev; + icom_adapter->version = ent->driver_data; + icom_adapter->subsystem_id = ent->subdevice; + + + retval = icom_init_ports(icom_adapter); + if (retval) { + dev_err(&dev->dev, "Port configuration failed\n"); + goto probe_exit1; + } + + icom_adapter->base_addr = + (unsigned long) ioremap(icom_adapter->base_addr_pci, + pci_resource_len(dev, 0)); + + if (!icom_adapter->base_addr) + goto probe_exit1; + + /* save off irq and request irq line */ + if ( (retval = request_irq(dev->irq, icom_interrupt, + SA_INTERRUPT | SA_SHIRQ, ICOM_DRIVER_NAME, + (void *) icom_adapter))) { + goto probe_exit2; + } + + retval = icom_load_ports(icom_adapter); + + for (index = 0; index < icom_adapter->numb_ports; index++) { + icom_port = &icom_adapter->port_info[index]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + icom_port->uart_port.irq = icom_port->adapter->irq_number; + icom_port->uart_port.type = PORT_ICOM; + icom_port->uart_port.iotype = UPIO_MEM; + icom_port->uart_port.membase = + (char *) icom_adapter->base_addr_pci; + icom_port->uart_port.fifosize = 16; + icom_port->uart_port.ops = &icom_ops; + icom_port->uart_port.line = + icom_port->port + icom_adapter->index * 4; + if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) { + icom_port->status = ICOM_PORT_OFF; + dev_err(&dev->dev, "Device add failed\n"); + } else + dev_info(&dev->dev, "Device added\n"); + } + } + + kobject_init(&icom_adapter->kobj); + icom_adapter->kobj.ktype = &icom_kobj_type; + return 0; + +probe_exit2: + iounmap((void *) icom_adapter->base_addr); +probe_exit1: + icom_free_adapter(icom_adapter); + +probe_exit0: + pci_release_regions(dev); + pci_disable_device(dev); + + return retval; + + +} + +static void __devexit icom_remove(struct pci_dev *dev) +{ + struct icom_adapter *icom_adapter; + struct list_head *tmp; + + list_for_each(tmp, &icom_adapter_head) { + icom_adapter = list_entry(tmp, struct icom_adapter, + icom_adapter_entry); + if (icom_adapter->pci_dev == dev) { + kobject_put(&icom_adapter->kobj); + return; + } + } + + dev_err(&dev->dev, "Unable to find device to remove\n"); +} + +static struct pci_driver icom_pci_driver = { + .name = ICOM_DRIVER_NAME, + .id_table = icom_pci_table, + .probe = icom_probe, + .remove = __devexit_p(icom_remove), +}; + +static int __init icom_init(void) +{ + int ret; + + spin_lock_init(&icom_lock); + icom_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + + ret = uart_register_driver(&icom_uart_driver); + if (ret) + return ret; + + ret = pci_register_driver(&icom_pci_driver); + + if (ret < 0) + uart_unregister_driver(&icom_uart_driver); + + return ret; +} + +static void __exit icom_exit(void) +{ + pci_unregister_driver(&icom_pci_driver); + uart_unregister_driver(&icom_uart_driver); +} + +module_init(icom_init); +module_exit(icom_exit); + +#ifdef ICOM_TRACE +static inline void trace(struct icom_port *icom_port, char *trace_pt, + unsigned long trace_data) +{ + dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", + icom_port->port, trace_pt, trace_data); +} +#endif + +MODULE_AUTHOR("Michael Anderson "); +MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); +MODULE_SUPPORTED_DEVICE + ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters"); +MODULE_LICENSE("GPL"); + diff -Nru a/drivers/serial/icom.h b/drivers/serial/icom.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/serial/icom.h 2004-10-18 14:57:21 -07:00 @@ -0,0 +1,290 @@ +/* + * icom.h + * + * Copyright (C) 2001 Michael Anderson, IBM Corporation + * + * Serial device driver include file. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1) +static int icom_acfg_baud[] = { + 300, + 600, + 900, + 1200, + 1800, + 2400, + 3600, + 4800, + 7200, + 9600, + 14400, + 19200, + 28800, + 38400, + 57600, + 76800, + 115200, + 153600, + 230400, + 307200, + 460800, +}; + +struct icom_regs { + u32 control; /* Adapter Control Register */ + u32 interrupt; /* Adapter Interrupt Register */ + u32 int_mask; /* Adapter Interrupt Mask Reg */ + u32 int_pri; /* Adapter Interrupt Priority r */ + u32 int_reg_b; /* Adapter non-masked Interrupt */ + u32 resvd01; + u32 resvd02; + u32 resvd03; + u32 control_2; /* Adapter Control Register 2 */ + u32 interrupt_2; /* Adapter Interrupt Register 2 */ + u32 int_mask_2; /* Adapter Interrupt Mask 2 */ + u32 int_pri_2; /* Adapter Interrupt Prior 2 */ + u32 int_reg_2b; /* Adapter non-masked 2 */ +}; + +struct func_dram { + u32 reserved[108]; /* 0-1B0 reserved by personality code */ + u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */ + u8 RcvStnAddr; /* 1B4 Receive Station Addr */ + u8 IdleState; /* 1B5 Idle State */ + u8 IdleMonitor; /* 1B6 Idle Monitor */ + u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */ + u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */ + u8 StartXmitCmd; /* 1BC Start Xmit Command */ + u8 HDLCConfigReg; /* 1BD Reserved */ + u8 CauseCode; /* 1BE Cause code for fatal error */ + u8 xchar; /* 1BF High priority send */ + u32 reserved3; /* 1C0-1C3 Reserved */ + u8 PrevCmdReg; /* 1C4 Reserved */ + u8 CmdReg; /* 1C5 Command Register */ + u8 async_config2; /* 1C6 Async Config Byte 2 */ + u8 async_config3; /* 1C7 Async Config Byte 3 */ + u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */ + u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */ + u8 misc_flags; /* 1DD misc flags */ +#define V2_HARDWARE 0x40 +#define ICOM_HDW_ACTIVE 0x01 + u8 call_length; /* 1DE Phone #/CFI buff ln */ + u8 call_length2; /* 1DF Upper byte (unused) */ + u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */ + u16 timer_value; /* 1E4-1E5 general timer value */ + u8 timer_command; /* 1E6 general timer cmd */ + u8 dce_command; /* 1E7 dce command reg */ + u8 dce_cmd_status; /* 1E8 dce command stat */ + u8 x21_r1_ioff; /* 1E9 dce ready counter */ + u8 x21_r0_ioff; /* 1EA dce not ready ctr */ + u8 x21_ralt_ioff; /* 1EB dce CNR counter */ + u8 x21_r1_ion; /* 1EC dce ready I on ctr */ + u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */ + u8 ier; /* 1EE Interrupt Enable */ + u8 isr; /* 1EF Input Signal Reg */ + u8 osr; /* 1F0 Output Signal Reg */ + u8 reset; /* 1F1 Reset/Reload Reg */ + u8 disable; /* 1F2 Disable Reg */ + u8 sync; /* 1F3 Sync Reg */ + u8 error_stat; /* 1F4 Error Status */ + u8 cable_id; /* 1F5 Cable ID */ + u8 cs_length; /* 1F6 CS Load Length */ + u8 mac_length; /* 1F7 Mac Load Length */ + u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */ + u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */ +}; + +/* + * adapter defines and structures + */ +#define ICOM_CONTROL_START_A 0x00000008 +#define ICOM_CONTROL_STOP_A 0x00000004 +#define ICOM_CONTROL_START_B 0x00000002 +#define ICOM_CONTROL_STOP_B 0x00000001 +#define ICOM_CONTROL_START_C 0x00000008 +#define ICOM_CONTROL_STOP_C 0x00000004 +#define ICOM_CONTROL_START_D 0x00000002 +#define ICOM_CONTROL_STOP_D 0x00000001 +#define ICOM_IRAM_OFFSET 0x1000 +#define ICOM_IRAM_SIZE 0x0C00 +#define ICOM_DCE_IRAM_OFFSET 0x0A00 +#define ICOM_CABLE_ID_VALID 0x01 +#define ICOM_CABLE_ID_MASK 0xF0 +#define ICOM_DISABLE 0x80 +#define CMD_XMIT_RCV_ENABLE 0xC0 +#define CMD_XMIT_ENABLE 0x40 +#define CMD_RCV_DISABLE 0x00 +#define CMD_RCV_ENABLE 0x80 +#define CMD_RESTART 0x01 +#define CMD_HOLD_XMIT 0x02 +#define CMD_SND_BREAK 0x04 +#define RS232_CABLE 0x06 +#define V24_CABLE 0x0E +#define V35_CABLE 0x0C +#define V36_CABLE 0x02 +#define NO_CABLE 0x00 +#define START_DOWNLOAD 0x80 +#define ICOM_INT_MASK_PRC_A 0x00003FFF +#define ICOM_INT_MASK_PRC_B 0x3FFF0000 +#define ICOM_INT_MASK_PRC_C 0x00003FFF +#define ICOM_INT_MASK_PRC_D 0x3FFF0000 +#define INT_RCV_COMPLETED 0x1000 +#define INT_XMIT_COMPLETED 0x2000 +#define INT_IDLE_DETECT 0x0800 +#define INT_RCV_DISABLED 0x0400 +#define INT_XMIT_DISABLED 0x0200 +#define INT_RCV_XMIT_SHUTDOWN 0x0100 +#define INT_FATAL_ERROR 0x0080 +#define INT_CABLE_PULL 0x0020 +#define INT_SIGNAL_CHANGE 0x0010 +#define HDLC_PPP_PURE_ASYNC 0x02 +#define HDLC_FF_FILL 0x00 +#define HDLC_HDW_FLOW 0x01 +#define START_XMIT 0x80 +#define ICOM_ACFG_DRIVE1 0x20 +#define ICOM_ACFG_NO_PARITY 0x00 +#define ICOM_ACFG_PARITY_ENAB 0x02 +#define ICOM_ACFG_PARITY_ODD 0x01 +#define ICOM_ACFG_8BPC 0x00 +#define ICOM_ACFG_7BPC 0x04 +#define ICOM_ACFG_6BPC 0x08 +#define ICOM_ACFG_5BPC 0x0C +#define ICOM_ACFG_1STOP_BIT 0x00 +#define ICOM_ACFG_2STOP_BIT 0x10 +#define ICOM_DTR 0x80 +#define ICOM_RTS 0x40 +#define ICOM_RI 0x08 +#define ICOM_DSR 0x80 +#define ICOM_DCD 0x20 +#define ICOM_CTS 0x40 + +#define NUM_XBUFFS 1 +#define NUM_RBUFFS 2 +#define RCV_BUFF_SZ 0x0200 +#define XMIT_BUFF_SZ 0x1000 +struct statusArea { + /**********************************************/ + /* Transmit Status Area */ + /**********************************************/ + struct xmit_status_area{ + u32 leNext; /* Next entry in Little Endian on Adapter */ + u32 leNextASD; + u32 leBuffer; /* Buffer for entry in LE for Adapter */ + u16 leLengthASD; + u16 leOffsetASD; + u16 leLength; /* Length of data in segment */ + u16 flags; +#define SA_FLAGS_DONE 0x0080 /* Done with Segment */ +#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */ +#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */ +#define SA_FLAGS_READY_TO_XMIT 0x0800 +#define SA_FLAGS_STAT_MASK 0x007F + } xmit[NUM_XBUFFS]; + + /**********************************************/ + /* Receive Status Area */ + /**********************************************/ + struct { + u32 leNext; /* Next entry in Little Endian on Adapter */ + u32 leNextASD; + u32 leBuffer; /* Buffer for entry in LE for Adapter */ + u16 WorkingLength; /* size of segment */ + u16 reserv01; + u16 leLength; /* Length of data in segment */ + u16 flags; +#define SA_FL_RCV_DONE 0x0010 /* Data ready */ +#define SA_FLAGS_OVERRUN 0x0040 +#define SA_FLAGS_PARITY_ERROR 0x0080 +#define SA_FLAGS_FRAME_ERROR 0x0001 +#define SA_FLAGS_FRAME_TRUNC 0x0002 +#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */ +#define SA_FLAGS_RCV_MASK 0xFFE6 + } rcv[NUM_RBUFFS]; +}; + +struct icom_adapter; + + +#define ICOM_MAJOR 243 +#define ICOM_MINOR_START 0 + +struct icom_port { + struct uart_port uart_port; + u8 imbed_modem; +#define ICOM_UNKNOWN 1 +#define ICOM_RVX 2 +#define ICOM_IMBED_MODEM 3 + unsigned char cable_id; + unsigned char read_status_mask; + unsigned char ignore_status_mask; + unsigned long int_reg; + struct icom_regs *global_reg; + struct func_dram *dram; + int port; + struct statusArea *statStg; + dma_addr_t statStg_pci; + u32 *xmitRestart; + dma_addr_t xmitRestart_pci; + unsigned char *xmit_buf; + dma_addr_t xmit_buf_pci; + unsigned char *recv_buf; + dma_addr_t recv_buf_pci; + int next_rcv; + int put_length; + int status; +#define ICOM_PORT_ACTIVE 1 /* Port exists. */ +#define ICOM_PORT_OFF 0 /* Port does not exist. */ + int load_in_progress; + struct icom_adapter *adapter; +}; + +struct icom_adapter { + unsigned long base_addr; + unsigned long base_addr_pci; + unsigned char irq_number; + struct pci_dev *pci_dev; + struct icom_port port_info[4]; + int index; + int version; +#define ADAPTER_V1 0x0001 +#define ADAPTER_V2 0x0002 + u32 subsystem_id; +#define FOUR_PORT_MODEL 0x0252 +#define V2_TWO_PORTS_RVX 0x021A +#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 + int numb_ports; + struct list_head icom_adapter_entry; + struct kobject kobj; +}; + +/* prototype */ +extern void iCom_sercons_init(void); + +struct lookup_proc_table { + u32 *global_control_reg; + unsigned long processor_id; +}; + +struct lookup_int_table { + u32 *global_int_mask; + unsigned long processor_id; +}; + +#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000) diff -Nru a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c --- a/drivers/serial/mcfserial.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/serial/mcfserial.c 2004-10-18 14:56:29 -07:00 @@ -424,11 +424,7 @@ tty = info->tty; if (!tty) return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } @@ -835,10 +831,7 @@ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; local_irq_restore(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1232,11 +1225,12 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; info->event = 0; info->tty = 0; +#if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) (tty->ldisc.close)(tty); @@ -1245,6 +1239,7 @@ if (tty->ldisc.open) (tty->ldisc.open)(tty); } +#endif if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; diff -Nru a/drivers/serial/pxa.c b/drivers/serial/pxa.c --- a/drivers/serial/pxa.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/serial/pxa.c 2004-10-18 14:57:03 -07:00 @@ -40,6 +40,7 @@ #include #include #include +#include #if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ diff -Nru a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c --- a/drivers/serial/s3c2410.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/serial/s3c2410.c 2004-10-18 14:56:31 -07:00 @@ -26,8 +26,6 @@ #include #include -#include - #if 0 #include #define dbg(x...) llprintk(x) @@ -677,7 +675,7 @@ default: case S3C2410_LCON_PNONE: - /* nothing */ + *parity = 'n'; } /* now calculate the baud rate */ diff -Nru a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c --- a/drivers/serial/serial_core.c 2004-10-18 14:56:20 -07:00 +++ b/drivers/serial/serial_core.c 2004-10-18 14:56:20 -07:00 @@ -107,15 +107,7 @@ static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; - struct tty_struct *tty; - - tty = state->info->tty; - if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } + tty_wakeup(state->info->tty); } static inline void @@ -403,7 +395,7 @@ if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else - quot = port->uartclk / (16 * baud); + quot = (port->uartclk + (8 * baud)) / (16 * baud); return quot; } @@ -581,10 +573,7 @@ spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1216,7 +1205,7 @@ { struct uart_state *state = tty->driver_data; struct uart_port *port; - + BUG_ON(!kernel_locked()); if (!state || !state->port) @@ -1239,12 +1228,12 @@ * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("uart_close: bad serial port count; tty->count is 1, " + printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { - printk("rs_close: bad serial port count for %s: %d\n", + printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", tty->name, state->count); state->count = 0; } @@ -1280,8 +1269,9 @@ uart_shutdown(state); uart_flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); + tty->closing = 0; state->info->tty = NULL; @@ -1978,6 +1968,7 @@ printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: + case UPIO_MEM32: printk("MMIO 0x%lx", port->mapbase); break; } diff -Nru a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c --- a/drivers/serial/serial_cs.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/serial/serial_cs.c 2004-10-18 14:56:31 -07:00 @@ -363,9 +363,10 @@ /*====================================================================*/ -static int simple_config(dev_link_t * link) +static int simple_config(dev_link_t *link) { static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + static int size_table[2] = { 8, 16 }; client_handle_t handle = link->handle; struct serial_info *info = link->priv; tuple_t tuple; @@ -374,6 +375,7 @@ cistpl_cftable_entry_t *cf = &parse.cftable_entry; config_info_t config; int i, j, try; + int s; /* If the card is already configured, look up the port and irq */ i = pcmcia_get_configuration_info(handle, &config); @@ -399,29 +401,30 @@ tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; /* Two tries: without IO aliases, then with aliases */ - for (try = 0; try < 2; try++) { - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - if (i != CS_SUCCESS) - goto next_entry; - if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && - (cf->io.win[0].base != 0)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = (try == 0) ? - 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); - if (i == CS_SUCCESS) - goto found_port; + for (s = 0; s < 2; s++) { + for (try = 0; try < 2; try++) { + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if (i != CS_SUCCESS) + goto next_entry; + if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && + (cf->io.win[0].base != 0)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.IOAddrLines = (try == 0) ? + 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + i = pcmcia_request_io(link->handle, &link->io); + if (i == CS_SUCCESS) + goto found_port; + } +next_entry: + i = next_tuple(handle, &tuple, &parse); } - next_entry: - i = next_tuple(handle, &tuple, &parse); } } - /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ diff -Nru a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c --- a/drivers/serial/sn_console.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/serial/sn_console.c 2004-10-18 14:56:29 -07:00 @@ -50,6 +50,7 @@ #include #include +#include #include #include #include @@ -80,6 +81,12 @@ #define DEVICE_MAJOR 204 #define DEVICE_MINOR 40 +#ifdef CONFIG_MAGIC_SYSRQ +static char sysrq_serial_str[] = "\eSYS"; +static char *sysrq_serial_ptr = sysrq_serial_str; +static unsigned long sysrq_requested; +#endif /* CONFIG_MAGIC_SYSRQ */ + /* * Port definition - this kinda drives it all */ @@ -532,13 +539,15 @@ * sn_receive_chars - Grab characters, pass them to tty layer * @port: Port to operate on * @regs: Saved registers (needed by uart_handle_sysrq_char) + * @flags: irq flags * * Note: If we're not registered with the serial core infrastructure yet, * we don't try to send characters to it... * */ static void -sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs) +sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs, + unsigned long flags) { int ch; struct tty_struct *tty; @@ -569,10 +578,34 @@ "obtaining data from the console (0x%0x)\n", ch); break; } -#if defined(CONFIG_SERIAL_SGI_L1_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (uart_handle_sysrq_char(&port->sc_port, ch, regs)) - continue; -#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE && CONFIG_MAGIC_SYSRQ */ +#ifdef CONFIG_MAGIC_SYSRQ + if (sysrq_requested) { + unsigned long sysrq_timeout = sysrq_requested + HZ*5; + + sysrq_requested = 0; + if (ch && time_before(jiffies, sysrq_timeout)) { + spin_unlock_irqrestore(&port->sc_port.lock, flags); + handle_sysrq(ch, regs, NULL); + spin_lock_irqsave(&port->sc_port.lock, flags); + /* ignore actual sysrq command char */ + continue; + } + } + if (ch == *sysrq_serial_ptr) { + if (!(*++sysrq_serial_ptr)) { + sysrq_requested = jiffies; + sysrq_serial_ptr = sysrq_serial_str; + } + /* + * ignore the whole sysrq string except for the + * leading escape + */ + if (ch != '\e') + continue; + } + else + sysrq_serial_ptr = sysrq_serial_str; +#endif /* CONFIG_MAGIC_SYSRQ */ /* record the character to pass up to the tty layer */ if (tty) { @@ -583,8 +616,6 @@ if (tty->flip.count == TTY_FLIPBUF_SIZE) break; } - else { - } port->sc_port.icount.rx++; } @@ -695,7 +726,7 @@ spin_lock_irqsave(&port->sc_port.lock, flags); if (status & SAL_CONSOLE_INTR_RECV) { - sn_receive_chars(port, regs); + sn_receive_chars(port, regs, flags); } if (status & SAL_CONSOLE_INTR_XMIT) { sn_transmit_chars(port, TRANSMIT_BUFFERED); @@ -714,7 +745,8 @@ static int sn_sal_connect_interrupt(struct sn_cons_port *port) { - if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, SA_INTERRUPT, + if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, + SA_INTERRUPT | SA_SHIRQ, "SAL console driver", port) >= 0) { return SGI_UART_VECTOR; } @@ -743,7 +775,7 @@ if (!port->sc_port.irq) { spin_lock_irqsave(&port->sc_port.lock, flags); - sn_receive_chars(port, NULL); + sn_receive_chars(port, NULL, flags); sn_transmit_chars(port, TRANSMIT_RAW); spin_unlock_irqrestore(&port->sc_port.lock, flags); mod_timer(&port->sc_timer, @@ -851,7 +883,6 @@ * Kernel console definitions */ -#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE static void sn_sal_console_write(struct console *, const char *, unsigned); static int __init sn_sal_console_setup(struct console *, char *); extern struct uart_driver sal_console_uart; @@ -867,9 +898,6 @@ }; #define SAL_CONSOLE &sal_console -#else -#define SAL_CONSOLE 0 -#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE */ static struct uart_driver sal_console_uart = { .owner = THIS_MODULE, @@ -895,11 +923,11 @@ { int retval; - printk(KERN_INFO "sn_console: Console driver init\n"); - if (!ia64_platform_is("sn2")) return -ENODEV; + printk(KERN_INFO "sn_console: Console driver init\n"); + if (USE_DYNAMIC_MINOR == 1) { misc.minor = MISC_DYNAMIC_MINOR; misc.name = DEVICE_NAME_DYNAMIC; @@ -969,8 +997,6 @@ module_init(sn_sal_module_init); module_exit(sn_sal_module_exit); -#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE - /** * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required * @puts_raw : puts function to do the writing @@ -1085,7 +1111,9 @@ spin_unlock_irqrestore(&port->sc_port.lock, flags); puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) } +#endif } else { /* Not yet registered with serial core - simple case */ @@ -1190,5 +1218,3 @@ } console_initcall(sn_sal_serial_console_init); - -#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE */ diff -Nru a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c --- a/drivers/serial/sunsab.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/serial/sunsab.c 2004-10-18 14:56:28 -07:00 @@ -768,25 +768,6 @@ writeb((readb(&up->regs->rw.ccr2) & ~0xc0) | ((ebrg >> 2) & 0xc0), &up->regs->rw.ccr2); - if (cflag & CRTSCTS) { - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_RTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FCTS, - &up->regs->rw.mode); - up->interrupt_mask1 &= ~SAB82532_IMR1_CSC; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - } else { - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FCTS, - &up->regs->rw.mode); - up->interrupt_mask1 |= SAB82532_IMR1_CSC; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - } writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RAC, &up->regs->rw.mode); } @@ -940,6 +921,7 @@ writeb(up->interrupt_mask1, &up->regs->w.imr1); sunsab_convert_to_sab(up, con->cflag, 0, baud); + sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); spin_unlock_irqrestore(&up->port.lock, flags); diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c --- a/drivers/serial/sunsu.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/serial/sunsu.c 2004-10-18 14:56:17 -07:00 @@ -98,7 +98,7 @@ unsigned int irq; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -520,7 +520,7 @@ /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -534,7 +534,7 @@ case 0: #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -994,7 +994,7 @@ static int sunsu_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int lsr; @@ -1014,7 +1014,7 @@ static int sunsu_serio_open(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int ret; @@ -1031,7 +1031,7 @@ static void sunsu_serio_close(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunsu_serio_lock, flags); @@ -1284,54 +1284,58 @@ .major = TTY_MAJOR, }; -static int __init sunsu_kbd_ms_init(void) +static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) { - struct uart_sunsu_port *up; - int i; + struct serio *serio; - for (i = 0, up = sunsu_ports; i < 2; i++, up++) { - up->port.line = i; - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); + up->port.line = channel; + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); - if (up->su_type == SU_PORT_KBD) - up->cflag = B1200 | CS8 | CLOCAL | CREAD; - else - up->cflag = B4800 | CS8 | CLOCAL | CREAD; + if (up->su_type == SU_PORT_KBD) + up->cflag = B1200 | CS8 | CLOCAL | CREAD; + else + up->cflag = B4800 | CS8 | CLOCAL | CREAD; - sunsu_autoconfig(up); - if (up->port.type == PORT_UNKNOWN) - continue; + sunsu_autoconfig(up); + if (up->port.type == PORT_UNKNOWN) + return -1; - printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", - i, - up->port.membase, __irq_itoa(up->irq), - sunsu_type(&up->port)); + printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", + channel, + up->port.membase, __irq_itoa(up->irq), + sunsu_type(&up->port)); #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(*serio)); - up->serio.driver = up; + serio->port_data = up; - up->serio.type = SERIO_RS232; + serio->type = SERIO_RS232; if (up->su_type == SU_PORT_KBD) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "sukbd"; + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "sukbd", sizeof(serio->name)); } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "sums"; + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "sums", sizeof(serio->name)); } - up->serio.phys = (i == 0 ? "su/serio0" : "su/serio1"); + strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"), + sizeof(serio->phys)); - up->serio.write = sunsu_serio_write; - up->serio.open = sunsu_serio_open; - up->serio.close = sunsu_serio_close; + serio->write = sunsu_serio_write; + serio->open = sunsu_serio_open; + serio->close = sunsu_serio_close; - serio_register_port(&up->serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "su%d: not enough memory for serio port\n", + channel); + } #endif - sunsu_startup(&up->port); - } + sunsu_startup(&up->port); return 0; } @@ -1680,10 +1684,12 @@ if (scan.msx != -1 && scan.kbx != -1) { sunsu_ports[0].su_type = SU_PORT_MS; sunsu_ports[0].port_node = scan.msnode; + sunsu_kbd_ms_init(&sunsu_ports[0], 0); + sunsu_ports[1].su_type = SU_PORT_KBD; sunsu_ports[1].port_node = scan.kbnode; + sunsu_kbd_ms_init(&sunsu_ports[1], 1); - sunsu_kbd_ms_init(); return 0; } @@ -1715,7 +1721,10 @@ if (up->su_type == SU_PORT_MS || up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } #endif } else if (up->port.type != PORT_UNKNOWN) { uart_remove_one_port(&sunsu_reg, &up->port); diff -Nru a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c --- a/drivers/serial/sunzilog.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/serial/sunzilog.c 2004-10-18 14:57:04 -07:00 @@ -107,7 +107,7 @@ unsigned char prev_status; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -291,7 +291,7 @@ /* Stop-A is handled by drivers/char/keyboard.c now. */ #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (ZS_IS_MOUSE(up)) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -306,7 +306,7 @@ case 0: #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -1295,7 +1295,7 @@ static int sunzilog_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1309,7 +1309,7 @@ static int sunzilog_serio_open(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; int ret; @@ -1326,7 +1326,7 @@ static void sunzilog_serio_close(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1545,33 +1545,44 @@ up->curregs[R15] = BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); sunzilog_convert_to_zs(up, up->cflag, 0, brg); + sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + __sunzilog_startup(up); +} #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); +static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) +{ + struct serio *serio; - up->serio.driver = up; + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(*serio)); - up->serio.type = SERIO_RS232; - if (channel == KEYBOARD_LINE) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "zskbd"; - } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "zsms"; - } - up->serio.phys = (channel == KEYBOARD_LINE ? - "zs/serio0" : "zs/serio1"); + serio->port_data = up; - up->serio.write = sunzilog_serio_write; - up->serio.open = sunzilog_serio_open; - up->serio.close = sunzilog_serio_close; - - serio_register_port(&up->serio); -#endif + serio->type = SERIO_RS232; + if (channel == KEYBOARD_LINE) { + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "zskbd", sizeof(serio->name)); + } else { + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "zsms", sizeof(serio->name)); + } + strlcpy(serio->phys, + (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), + sizeof(serio->phys)); + + serio->write = sunzilog_serio_write; + serio->open = sunzilog_serio_open; + serio->close = sunzilog_serio_close; - sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); - __sunzilog_startup(up); + serio_register_port(serio); + } else { + printk(KERN_WARNING "zs%d: not enough memory for serio port\n", + channel); + } } +#endif static void __init sunzilog_init_hw(void) { @@ -1615,6 +1626,11 @@ } spin_unlock_irqrestore(&up->port.lock, flags); + +#ifdef CONFIG_SERIO + if (i == KEYBOARD_LINE || i == MOUSE_LINE) + sunzilog_register_serio(up, i); +#endif } } @@ -1732,10 +1748,15 @@ for (i = 0; i < NUM_CHANNELS; i++) { struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) - continue; - - uart_remove_one_port(&sunzilog_reg, &up->port); + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +#ifdef CONFIG_SERIO + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } +#endif + } else + uart_remove_one_port(&sunzilog_reg, &up->port); } uart_unregister_driver(&sunzilog_reg); diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c --- a/drivers/tc/zs.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/tc/zs.c 2004-10-18 14:56:50 -07:00 @@ -211,10 +211,6 @@ static void change_speed(struct dec_serial *info); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -683,10 +679,7 @@ return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -706,7 +699,7 @@ save_flags(flags); cli(); #ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%02d (irq %d)...", info->line, info->irq); + printk("starting up ttyS%d (irq %d)...", info->line, info->irq); #endif /* @@ -950,16 +943,16 @@ save_flags(flags); while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; if (from_user) { down(&tmp_buf_sem); copy_from_user(tmp_buf, buf, c); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); up(&tmp_buf_sem); } else @@ -1010,10 +1003,7 @@ cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1356,7 +1346,7 @@ } #ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttyS%02d, count = %d\n", info->line, info->count); + printk("rs_close ttyS%d, count = %d\n", info->line, info->count); #endif if ((tty->count == 1) && (info->count != 1)) { /* @@ -1371,7 +1361,7 @@ info->count = 1; } if (--info->count < 0) { - printk("rs_close: bad serial port count for ttyS%02d: %d\n", + printk("rs_close: bad serial port count for ttyS%d: %d\n", info->line, info->count); info->count = 0; } @@ -1407,8 +1397,7 @@ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; @@ -1446,7 +1435,7 @@ if (char_time == 0) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(char_time); @@ -1531,7 +1520,7 @@ retval = 0; add_wait_queue(&info->open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttyS%02d, count = %d\n", + printk("block_til_ready before block: ttyS%d, count = %d\n", info->line, info->count); #endif cli(); @@ -1565,7 +1554,7 @@ break; } #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttyS%02d, count = %d\n", + printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); #endif schedule(); @@ -1576,7 +1565,7 @@ info->count++; info->blocked_open--; #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttyS%02d, count = %d\n", + printk("block_til_ready after blocking: ttyS%d, count = %d\n", info->line, info->count); #endif if (retval) @@ -1742,14 +1731,10 @@ * We're called early and memory managment isn't up, yet. * Thus check_region would fail. */ - if (check_region((unsigned long) + if (!request_region((unsigned long) zs_channels[n_channels].control, - ZS_CHAN_IO_SIZE) < 0) { + ZS_CHAN_IO_SIZE, "SCC")) panic("SCC I/O region is not free"); - } - request_region((unsigned long) - zs_channels[n_channels].control, - ZS_CHAN_IO_SIZE, "SCC"); #endif zs_soft[n_channels].zs_channel = &zs_channels[n_channels]; zs_soft[n_channels].irq = zs_parms->irq; @@ -1896,7 +1881,7 @@ info->tqueue.data = info; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); - printk("ttyS%02d at 0x%08x (irq = %d)", info->line, + printk("ttyS%d at 0x%08x (irq = %d)", info->line, info->port, info->irq); printk(" is a Z85C30 SCC\n"); tty_register_device(serial_driver, info->line, NULL); diff -Nru a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c --- a/drivers/telephony/ixj.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/telephony/ixj.c 2004-10-18 14:55:54 -07:00 @@ -7718,6 +7718,23 @@ cleanup(); } +static IXJ *new_ixj(unsigned long port) +{ + IXJ *res; + if (!request_region(port, 16, "ixj DSP")) { + printk(KERN_INFO "ixj: can't get I/O address 0x%lx\n", port); + return NULL; + } + res = ixj_alloc(); + if (!res) { + release_region(port, 16); + printk(KERN_INFO "ixj: out of memory\n"); + return NULL; + } + res->DSPbase = port; + return res; +} + int __init ixj_probe_isapnp(int *cnt) { int probe = 0; @@ -7750,15 +7767,9 @@ return -ENODEV; } - result = check_region(pnp_port_start(dev, 0), 16); - if (result) { - printk(KERN_INFO "ixj: can't get I/O address 0x%lx\n", pnp_port_start(dev, 0)); + j = new_ixj(pnp_port_start(dev, 0)); + if (!j) break; - } - - j = ixj_alloc(); - j->DSPbase = pnp_port_start(dev,0); - request_region(j->DSPbase, 16, "ixj DSP"); if (func != 0x110) j->XILINXbase = pnp_port_start(dev, 1); /* get real port */ @@ -7806,22 +7817,15 @@ int __init ixj_probe_isa(int *cnt) { - int i, result, probe; + int i, probe; /* Use passed parameters for older kernels without PnP */ for (i = 0; i < IXJMAX; i++) { if (dspio[i]) { - IXJ *j; + IXJ *j = new_ixj(dspio[i]); - if ((result = check_region(ixj[*cnt].DSPbase, 16)) < 0) { - printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[*cnt].DSPbase); + if (!j) break; - } - - j = ixj_alloc(); - - j->DSPbase = dspio[i]; - request_region(j->DSPbase, 16, "ixj DSP"); j->XILINXbase = xio[i]; j->cardtype = 0; @@ -7840,7 +7844,6 @@ struct pci_dev *pci = NULL; int i, probe = 0; IXJ *j = NULL; - int result; for (i = 0; i < IXJMAX - *cnt; i++) { pci = pci_find_device(0x15E2, 0x0500, pci); @@ -7849,20 +7852,12 @@ if (pci_enable_device(pci)) break; - if ((result = check_region(pci_resource_start(pci, 0), 16)) < 0) { - printk(KERN_INFO "ixj: can't get I/O address\n"); + j = new_ixj(pci_resource_start(pci, 0)); + if (!j) break; - } - /* Grab a device slot */ - j = ixj_alloc(); - if(j == NULL) - break; - - j->DSPbase = pci_resource_start(pci, 0); j->serial = (PCIEE_GetSerialNumber)pci_resource_start(pci, 2); j->XILINXbase = j->DSPbase + 0x10; - request_region(j->DSPbase, 16, "ixj DSP"); j->cardtype = QTI_PHONEJACK_PCI; j->board = *cnt; probe = ixj_selfprobe(j); diff -Nru a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h --- a/drivers/telephony/ixj.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/telephony/ixj.h 2004-10-18 14:57:04 -07:00 @@ -1188,12 +1188,12 @@ unsigned int cid_rec_codec; unsigned int cid_rec_volume; unsigned char cid_rec_flag; - char rec_mode; + signed char rec_mode; unsigned int play_codec; unsigned int cid_play_codec; unsigned int cid_play_volume; unsigned char cid_play_flag; - char play_mode; + signed char play_mode; IXJ_FLAGS flags; unsigned long busyflags; unsigned int rec_frame_size; diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/class/audio.c 2004-10-18 14:57:04 -07:00 @@ -1954,9 +1954,9 @@ struct usb_audio_state *s; down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) { + list_for_each(mdevs, &s->mixerlist) { ms = list_entry(mdevs, struct usb_mixerdev, list); if (ms->dev_mixer == minor) goto mixer_found; @@ -2640,9 +2640,9 @@ for (;;) { down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (adevs = s->audiolist.next; adevs != &s->audiolist; adevs = adevs->next) { + list_for_each(adevs, &s->audiolist) { as = list_entry(adevs, struct usb_audiodev, list); if (!((as->dev_audio ^ minor) & ~0xf)) goto device_found; @@ -3831,7 +3831,7 @@ usb_set_intfdata (intf, NULL); /* deregister all audio and mixer devices, so no new processes can open this device */ - for(list = s->audiolist.next; list != &s->audiolist; list = list->next) { + list_for_each(list, &s->audiolist) { as = list_entry(list, struct usb_audiodev, list); usbin_disc(as); usbout_disc(as); @@ -3843,7 +3843,7 @@ } as->dev_audio = -1; } - for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) { + list_for_each(list, &s->mixerlist) { ms = list_entry(list, struct usb_mixerdev, list); if (ms->dev_mixer >= 0) { unregister_sound_mixer(ms->dev_mixer); diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c --- a/drivers/usb/class/bluetty.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/class/bluetty.c 2004-10-18 14:56:49 -07:00 @@ -988,21 +988,13 @@ static void bluetooth_softint(void *private) { struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__); - struct tty_struct *tty; dbg("%s", __FUNCTION__); - if (!bluetooth) { + if (!bluetooth) return; - } - tty = bluetooth->tty; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - dbg("%s - write wakeup call.", __FUNCTION__); - (tty->ldisc.write_wakeup)(tty); - } - - wake_up_interruptible(&tty->write_wait); + tty_wakeup(bluetooth->tty); } diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/class/cdc-acm.c 2004-10-18 14:56:33 -07:00 @@ -142,7 +142,7 @@ case ACM_IRQ_LINE_STATE: - newctrl = le16_to_cpu(get_unaligned((__u16 *) data)); + newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); @@ -248,16 +248,11 @@ static void acm_softint(void *private) { struct acm *acm = private; - struct tty_struct *tty = acm->tty; dbg("Entering acm_softint.\n"); if (!ACM_READY(acm)) return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); + tty_wakeup(acm->tty); } /* @@ -367,7 +362,7 @@ acm->writeurb->dev = acm->dev; acm->ready_for_write = 0; - stat = usb_submit_urb(acm->writeurb, GFP_NOIO); + stat = usb_submit_urb(acm->writeurb, from_user ? GFP_KERNEL : GFP_ATOMIC); if (stat < 0) { dbg("usb_submit_urb(write bulk) failed"); acm->ready_for_write = 1; @@ -583,19 +578,25 @@ } if (!union_header) { - dev_dbg(&intf->dev,"No union descriptor, giving up\n"); - return -ENODEV; - } - - control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); - if (!control_interface || !data_interface) { - dev_dbg(&intf->dev,"no interfaces\n"); - return -ENODEV; + if (call_interface_num > 0) { + dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); + control_interface = intf; + } else { + dev_dbg(&intf->dev,"No union descriptor, giving up\n"); + return -ENODEV; + } + } else { + control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); + if (!control_interface || !data_interface) { + dev_dbg(&intf->dev,"no interfaces\n"); + return -ENODEV; + } } - if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); + if (data_interface_num != call_interface_num) + dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); if (usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev,"The data interface isn't available\n"); diff -Nru a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h --- a/drivers/usb/class/cdc-acm.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/class/cdc-acm.h 2004-10-18 14:57:04 -07:00 @@ -70,7 +70,7 @@ */ struct acm_line { - __u32 speed; + __le32 speed; __u8 stopbits; __u8 parity; __u8 databits; diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c --- a/drivers/usb/class/usb-midi.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/class/usb-midi.c 2004-10-18 14:55:54 -07:00 @@ -55,39 +55,39 @@ /* ------------------------------------------------------------------------- */ static int singlebyte = 0; -MODULE_PARM(singlebyte,"i"); +module_param(singlebyte, int, 0); MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet"); static int maxdevices = 4; -MODULE_PARM(maxdevices,"i"); +module_param(maxdevices, int, 0); MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device"); static int uvendor = -1; -MODULE_PARM(uvendor,"i"); +module_param(uvendor, int, 0); MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface"); static int uproduct = -1; -MODULE_PARM(uproduct,"i"); +module_param(uproduct, int, 0); MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface"); static int uinterface = -1; -MODULE_PARM(uinterface,"i"); +module_param(uinterface, int, 0); MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface"); static int ualt = -1; -MODULE_PARM(ualt,"i"); +module_param(ualt, int, 0); MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface"); static int umin = -1; -MODULE_PARM(umin,"i"); +module_param(umin, int, 0); MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface"); static int umout = -1; -MODULE_PARM(umout,"i"); +module_param(umout, int, 0); MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface"); static int ucable = -1; -MODULE_PARM(ucable,"i"); +module_param(ucable, int, 0); MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface"); /** Note -- the usb_string() returns only Latin-1 characters. @@ -95,7 +95,7 @@ * unicode16LE-to-JIS routine is needed to wrap around usb_get_string(). **/ static unsigned short ulangid = 0x0409; /** 0x0411 for Japanese **/ -MODULE_PARM(ulangid,"h"); +module_param(ulangid, ushort, 0); MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices"); MODULE_AUTHOR("NAGANO Daisuke "); @@ -817,9 +817,9 @@ for(;;) { down(&open_sem); - for (devs = mididevs.next; devs != &mididevs; devs = devs->next) { + list_for_each(devs, &mididevs) { s = list_entry(devs, struct usb_midi_state, mididev); - for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) { + list_for_each(mdevs, &s->midiDevList) { m = list_entry(mdevs, struct usb_mididev, list); if ( !((m->dev_midi ^ minor) & ~0xf) ) goto device_found; @@ -2012,7 +2012,7 @@ s->usbdev = NULL; usb_set_intfdata (intf, NULL); - for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) { + list_for_each(list, &s->midiDevList) { m = list_entry(list, struct usb_mididev, list); wake_up(&(m->min.ep->wait)); wake_up(&(m->mout.ep->wait)); diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/usb/class/usblp.c 2004-10-18 14:56:17 -07:00 @@ -221,7 +221,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp); /* forward reference to make our lives easier */ -extern struct usb_driver usblp_driver; +static struct usb_driver usblp_driver; /* * Functions for usblp control messages. @@ -397,10 +397,6 @@ { info("usblp%d: removed", usblp->minor); - usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, - usblp->writebuf, usblp->writeurb->transfer_dma); - usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, - usblp->readbuf, usblp->readurb->transfer_dma); kfree (usblp->device_id_string); kfree (usblp->statusbuf); usb_free_urb(usblp->writeurb); @@ -1129,7 +1125,7 @@ /* First two bytes are length in big-endian. * They count themselves, and we copy them into * the user's buffer. */ - length = be16_to_cpu(*((u16 *)usblp->device_id_string)); + length = be16_to_cpu(*((__be16 *)usblp->device_id_string)); if (length < 2) length = 2; else if (length >= USBLP_DEVICE_ID_SIZE) @@ -1159,6 +1155,10 @@ usb_set_intfdata (intf, NULL); usblp_unlink_urbs(usblp); + usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, + usblp->writebuf, usblp->writeurb->transfer_dma); + usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, + usblp->readbuf, usblp->readurb->transfer_dma); if (!usblp->used) usblp_cleanup (usblp); @@ -1208,6 +1208,6 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_PARM(proto_bias, "i"); +module_param(proto_bias, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig --- a/drivers/usb/core/Kconfig 2004-10-18 14:57:03 -07:00 +++ b/drivers/usb/core/Kconfig 2004-10-18 14:57:03 -07:00 @@ -60,3 +60,40 @@ If you are unsure about this, say N here. +config USB_SUSPEND + bool "USB suspend/resume (EXPERIMENTAL)" + depends on USB && PM && EXPERIMENTAL + help + If you say Y here, you can use driver calls or the sysfs + "power/state" file to suspend or resume individual USB + peripherals. There are many related features, such as + remote wakeup and driver-specific suspend processing, that + may not yet work as expected. + + If you are unsure about this, say N here. + + +config USB_OTG + bool + depends on USB && EXPERIMENTAL + select USB_SUSPEND + default n + + +config USB_OTG_WHITELIST + bool "Rely on OTG Targeted Peripherals List" + depends on USB_OTG + default y + help + If you say Y here, the "otg_whitelist.h" file will be used as a + product whitelist, so USB peripherals not listed there will be + rejected during enumeration. This behavior is required by the + USB OTG specification for all devices not on your product's + "Targeted Peripherals List". + + Otherwise, peripherals not listed there will only generate a + warning and enumeration will continue. That's more like what + normal Linux-USB hosts do (other than the warning), and is + convenient for many stages of product development. + + diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c --- a/drivers/usb/core/config.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/core/config.c 2004-10-18 14:55:54 -07:00 @@ -106,7 +106,7 @@ return buffer - buffer0 + i; } -static void usb_release_interface_cache(struct kref *ref) +void usb_release_interface_cache(struct kref *ref) { struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); int j; @@ -356,7 +356,7 @@ if (!intfc) return -ENOMEM; memset(intfc, 0, len); - kref_init(&intfc->ref, usb_release_interface_cache); + kref_init(&intfc->ref); } /* Skip over any Class Specific or Vendor Specific descriptors; @@ -422,7 +422,8 @@ for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) - kref_put(&cf->intf_cache[i]->ref); + kref_put(&cf->intf_cache[i]->ref, + usb_release_interface_cache); } } kfree(dev->config); diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c --- a/drivers/usb/core/devices.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/core/devices.c 2004-10-18 14:57:04 -07:00 @@ -283,9 +283,8 @@ /* TBD: * 0. TBDs - * 1. marking active config and ifaces (code lists all, but should mark + * 1. marking active interface altsettings (code lists all, but should mark * which ones are active, if any) - * 2. add status to each endpoint line */ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active) @@ -584,7 +583,7 @@ /* enumerate busses */ down (&usb_bus_list_lock); - for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { + list_for_each(buslist, &usb_bus_list) { /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/usb/core/devio.c 2004-10-18 14:56:32 -07:00 @@ -72,6 +72,8 @@ } while (0) +#define MAX_USBFS_BUFFER_SIZE 16384 + static inline int connected (struct usb_device *dev) { return dev->state != USB_STATE_NOTATTACHED; @@ -555,8 +557,10 @@ snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); + up(&dev->serialize); i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + down(&dev->serialize); if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); @@ -584,8 +588,10 @@ printk ("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } + up(&dev->serialize); i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + down(&dev->serialize); } free_page((unsigned long)tbuf); if (i<0) { @@ -619,6 +625,8 @@ if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; + if (len1 > MAX_USBFS_BUFFER_SIZE) + return -EINVAL; if (!(tbuf = kmalloc(len1, GFP_KERNEL))) return -ENOMEM; tmo = (bulk.timeout * HZ + 999) / 1000; @@ -627,7 +635,9 @@ kfree(tbuf); return -EINVAL; } + up(&dev->serialize); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + down(&dev->serialize); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { kfree(tbuf); @@ -641,7 +651,9 @@ return -EFAULT; } } + up(&dev->serialize); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + down(&dev->serialize); } kfree(tbuf); if (i < 0) { @@ -849,7 +861,7 @@ case USBDEVFS_URB_TYPE_BULK: uurb.number_of_packets = 0; - if (uurb.buffer_length > 16384) + if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) return -EFAULT; @@ -891,7 +903,7 @@ interval = 1 << min (15, ep_desc->bInterval - 1); else interval = ep_desc->bInterval; - if (uurb.buffer_length > 16384) + if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) return -EFAULT; diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/core/hcd-pci.c 2004-10-18 14:56:29 -07:00 @@ -65,7 +65,7 @@ { struct hc_driver *driver; unsigned long resource, len; - void *base; + void __iomem *base; struct usb_hcd *hcd; int retval, region; char buf [8], *bufp = buf; @@ -121,7 +121,7 @@ dev_dbg (&dev->dev, "no i/o regions available\n"); return -EBUSY; } - base = (void *) resource; + base = (void __iomem *) resource; } // driver->reset(), later on, will transfer device from diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/core/hcd.c 2004-10-18 14:56:33 -07:00 @@ -708,6 +708,7 @@ bus->busnum = busnum; } else { printk (KERN_ERR "%s: too many buses\n", usbcore_name); + up(&usb_bus_list_lock); return -E2BIG; } @@ -790,6 +791,8 @@ usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64; retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { + usb_dev->bus->root_hub = NULL; + up (&usb_bus_list_lock); dev_dbg (parent_dev, "can't read %s device descriptor %d\n", usb_dev->dev.bus_id, retval); return (retval < 0) ? retval : -EMSGSIZE; @@ -1311,13 +1314,10 @@ rescan: /* (re)block new requests, as best we can */ - if (endpoint & USB_DIR_IN) { - usb_endpoint_halt (udev, epnum, 0); + if (endpoint & USB_DIR_IN) udev->epmaxpacketin [epnum] = 0; - } else { - usb_endpoint_halt (udev, epnum, 1); + else udev->epmaxpacketout [epnum] = 0; - } /* then kill any current requests */ spin_lock (&hcd_data_lock); @@ -1402,6 +1402,45 @@ return hcd->driver->hub_resume (hcd); return 0; } + +#endif + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_OTG + +/** + * usb_bus_start_enum - start immediate enumeration (for OTG) + * @bus: the bus (must use hcd framework) + * @port: 1-based number of port; usually bus->otg_port + * Context: in_interrupt() + * + * Starts enumeration, with an immediate reset followed later by + * khubd identifying and possibly configuring the device. + * This is needed by OTG controller drivers, where it helps meet + * HNP protocol timing requirements for starting a port reset. + */ +int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) +{ + struct usb_hcd *hcd; + int status = -EOPNOTSUPP; + + /* NOTE: since HNP can't start by grabbing the bus's address0_sem, + * boards with root hubs hooked up to internal devices (instead of + * just the OTG port) may need more attention to resetting... + */ + hcd = container_of (bus, struct usb_hcd, self); + if (port_num && hcd->driver->start_port_reset) + status = hcd->driver->start_port_reset(hcd, port_num); + + /* run khubd shortly after (first) root port reset finishes; + * it may issue others, until at least 50 msecs have passed. + */ + if (status == 0) + mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10)); + return status; +} +EXPORT_SYMBOL (usb_bus_start_enum); #endif diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/core/hcd.h 2004-10-18 14:56:28 -07:00 @@ -77,7 +77,7 @@ unsigned can_wakeup:1; /* hw supports wakeup? */ unsigned remote_wakeup:1;/* sw should use wakeup? */ int irq; /* irq allocated */ - void *regs; /* device memory/io */ + void __iomem *regs; /* device memory/io */ #ifdef CONFIG_PCI int region; /* pci region for regs */ @@ -212,6 +212,7 @@ char *buf, u16 wLength); int (*hub_suspend)(struct usb_hcd *); int (*hub_resume)(struct usb_hcd *); + int (*start_port_reset)(struct usb_hcd *, unsigned port_num); }; extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); @@ -375,8 +376,6 @@ extern int usb_find_interface_driver (struct usb_device *dev, struct usb_interface *interface); - -#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep))) #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/core/hub.c 2004-10-18 14:56:29 -07:00 @@ -36,7 +36,7 @@ #include "hcd.h" #include "hub.h" -/* Protect all struct usb_device state members */ +/* Protect struct usb_device state and children members */ static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED; /* Wakes up khubd */ @@ -143,7 +143,7 @@ unsigned changed = 0; int cursor = -1; - if (hdev->state != USB_STATE_CONFIGURED) + if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing) return; for (i = 0; i < hub->descriptor->bNbrPorts; i++) { @@ -269,6 +269,9 @@ spin_unlock(&hub_event_lock); resubmit: + if (hub->quiescing) + return; + if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) dev_err (&hub->intf->dev, "resubmit --> %d\n", status); @@ -623,6 +626,33 @@ static unsigned highspeed_hubs; +static void hub_quiesce(struct usb_hub *hub) +{ + /* stop khubd and related activity */ + hub->quiescing = 1; + usb_kill_urb(hub->urb); + if (hub->has_indicators) + cancel_delayed_work(&hub->leds); + if (hub->has_indicators || hub->tt.hub) + flush_scheduled_work(); +} + +#ifdef CONFIG_USB_SUSPEND + +static void hub_reactivate(struct usb_hub *hub) +{ + int status; + + hub->quiescing = 0; + status = usb_submit_urb(hub->urb, GFP_NOIO); + if (status < 0) + dev_err(&hub->intf->dev, "reactivate --> %d\n", status); + if (hub->has_indicators && blinkenlights) + schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +} + +#endif + static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -637,22 +667,14 @@ usb_set_intfdata (intf, NULL); - if (hub->urb) { - usb_kill_urb(hub->urb); - usb_free_urb(hub->urb); - hub->urb = NULL; - } + hub_quiesce(hub); + usb_free_urb(hub->urb); + hub->urb = NULL; spin_lock_irq(&hub_event_lock); list_del_init(&hub->event_list); spin_unlock_irq(&hub_event_lock); - /* assuming we used keventd, it must quiesce too */ - if (hub->has_indicators) - cancel_delayed_work (&hub->leds); - if (hub->has_indicators || hub->tt.hub) - flush_scheduled_work (); - if (hub->descriptor) { kfree(hub->descriptor); hub->descriptor = NULL; @@ -772,6 +794,7 @@ } } +/* caller has locked the hub and must own the device lock */ static int hub_reset(struct usb_hub *hub) { struct usb_device *hdev = hub->hdev; @@ -789,7 +812,7 @@ else return -1; - if (usb_reset_device(hdev)) + if (__usb_reset_device(hdev)) return -1; hub->urb->dev = hdev; @@ -801,6 +824,7 @@ return 0; } +/* caller has locked the hub */ /* FIXME! This routine should be subsumed into hub_reset */ static void hub_start_disconnect(struct usb_device *hdev) { @@ -832,12 +856,65 @@ udev->state = USB_STATE_NOTATTACHED; } +/* grab device/port lock, returning index of that port (zero based). + * protects the upstream link used by this device from concurrent + * tree operations like suspend, resume, reset, and disconnect, which + * apply to everything downstream of a given port. + */ +static int locktree(struct usb_device *udev) +{ + int t; + struct usb_device *hdev; + + if (!udev) + return -ENODEV; + + /* root hub is always the first lock in the series */ + hdev = udev->parent; + if (!hdev) { + down(&udev->serialize); + return 0; + } + + /* on the path from root to us, lock everything from + * top down, dropping parent locks when not needed + * + * NOTE: if disconnect were to ignore the locking, we'd need + * to get extra refcounts to everything since hdev->children + * and udev->parent could be invalidated while we work... + */ + t = locktree(hdev); + if (t < 0) + return t; + spin_lock_irq(&device_state_lock); + for (t = 0; t < hdev->maxchild; t++) { + if (hdev->children[t] == udev) { + /* everything is fail-fast once disconnect + * processing starts + */ + if (udev->state == USB_STATE_NOTATTACHED) + break; + + /* when everyone grabs locks top->bottom, + * non-overlapping work may be concurrent + */ + spin_unlock_irq(&device_state_lock); + down(&udev->serialize); + up(&hdev->serialize); + return t; + } + } + spin_unlock_irq(&device_state_lock); + up(&hdev->serialize); + return -ENODEV; +} + /** * usb_set_device_state - change a device's current state (usbcore-internal) * @udev: pointer to device whose state should be changed * @new_state: new state value to be stored * - * udev->state is _not_ protected by the udev->serialize semaphore. This + * udev->state is _not_ protected by the device lock. This * is so that devices can be marked as disconnected as soon as possible, * without having to wait for the semaphore to be released. Instead, * changes to the state must be protected by the device_state_lock spinlock. @@ -897,7 +974,7 @@ /** * usb_disconnect - disconnect a device (usbcore-internal) - * @pdev: pointer to device being disconnected + * @pdev: pointer to device being disconnected, into a locked hub * Context: !in_interrupt () * * Something got disconnected. Get rid of it, and all of its children. @@ -921,7 +998,8 @@ } /* mark the device as inactive, so any further urb submissions for - * this device will fail. + * this device (and any of its children) will fail immediately. + * this quiesces everyting except pending urbs. */ usb_set_device_state(udev, USB_STATE_NOTATTACHED); @@ -940,6 +1018,7 @@ /* deallocate hcd/hardware state ... nuking all pending urbs and * cleaning up all state associated with the current configuration + * so that the hardware is now fully quiesced. */ usb_disable_device(udev, 0); @@ -952,7 +1031,7 @@ usbfs_remove_device(udev); usb_remove_sysfs_dev_files(udev); - /* Avoid races with recursively_mark_NOTATTACHED() */ + /* Avoid races with recursively_mark_NOTATTACHED() and locktree() */ spin_lock_irq(&device_state_lock); *pdev = NULL; spin_unlock_irq(&device_state_lock); @@ -1016,6 +1095,10 @@ {} #endif +#ifdef CONFIG_USB_OTG +#include "otg_whitelist.h" +#endif + /** * usb_new_device - perform initial device setup (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) @@ -1065,6 +1148,79 @@ show_string(udev, "SerialNumber", udev->descriptor.iSerialNumber); +#ifdef CONFIG_USB_OTG + /* + * OTG-aware devices on OTG-capable root hubs may be able to use SRP, + * to wake us after we've powered off VBUS; and HNP, switching roles + * "host" to "peripheral". The OTG descriptor helps figure this out. + */ + if (!udev->bus->is_b_host + && udev->config + && udev->parent == udev->bus->root_hub) { + struct usb_otg_descriptor *desc = 0; + struct usb_bus *bus = udev->bus; + + /* descriptor may appear anywhere in config */ + if (__usb_get_extra_descriptor (udev->rawdescriptors[0], + udev->config[0].desc.wTotalLength, + USB_DT_OTG, (void **) &desc) == 0) { + if (desc->bmAttributes & USB_OTG_HNP) { + unsigned port; + struct usb_device *root = udev->parent; + + for (port = 0; port < root->maxchild; port++) { + if (root->children[port] == udev) + break; + } + port++; + + dev_info(&udev->dev, + "Dual-Role OTG device on %sHNP port\n", + (port == bus->otg_port) + ? "" : "non-"); + + /* enable HNP before suspend, it's simpler */ + if (port == bus->otg_port) + bus->b_hnp_enable = 1; + err = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + bus->b_hnp_enable + ? USB_DEVICE_B_HNP_ENABLE + : USB_DEVICE_A_ALT_HNP_SUPPORT, + 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + if (err < 0) { + /* OTG MESSAGE: report errors here, + * customize to match your product. + */ + dev_info(&udev->dev, + "can't set HNP mode; %d\n", + err); + bus->b_hnp_enable = 0; + } + } + } + } + + if (!is_targeted(udev)) { + + /* Maybe it can talk to us, though we can't talk to it. + * (Includes HNP test device.) + */ + if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { + static int __usb_suspend_device (struct usb_device *, + int port, u32 state); + err = __usb_suspend_device(udev, + udev->bus->otg_port - 1, + PM_SUSPEND_MEM); + if (err < 0) + dev_dbg(&udev->dev, "HNP fail, %d\n", err); + } + err = -ENODEV; + goto fail; + } +#endif + /* put device-specific files into sysfs */ err = device_add (&udev->dev); if (err) { @@ -1203,6 +1359,7 @@ if (status == -ENOTCONN || status == 0) { clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_RESET); + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); @@ -1226,9 +1383,11 @@ { int ret; - if (hdev->children[port]) + if (hdev->children[port]) { + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(hdev->children[port], USB_STATE_NOTATTACHED); + } ret = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_ENABLE); if (ret) dev_err(hubdev(hdev), "cannot disable port %d (err = %d)\n", @@ -1239,7 +1398,490 @@ #ifdef CONFIG_USB_SUSPEND - /* no USB_SUSPEND yet! */ +/* + * Selective port suspend reduces power; most suspended devices draw + * less than 500 uA. It's also used in OTG, along with remote wakeup. + * All devices below the suspended port are also suspended. + * + * Devices leave suspend state when the host wakes them up. Some devices + * also support "remote wakeup", where the device can activate the USB + * tree above them to deliver data, such as a keypress or packet. In + * some cases, this wakes the USB host. + */ +static int hub_port_suspend(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "suspend port %d\n", port); + + /* enable remote wakeup when appropriate; this lets the device + * wake up the upstream hub (including maybe the root hub). + * + * NOTE: OTG devices may issue remote wakeup (or SRP) even when + * we don't explicitly enable it here. + */ + if (udev->actconfig + // && FIXME (remote wakeup enabled on this bus) + // ... currently assuming it's always appropriate + && (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP) != 0) { + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) + dev_dbg(&udev->dev, + "won't remote wakeup, status %d\n", + status); + } + + /* see 7.1.7.6 */ + status = set_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(hubdev(hdev), + "can't suspend port %d, status %d\n", + port, status); + /* paranoia: "should not happen" */ + (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + /* device has up to 10 msec to fully suspend */ + dev_dbg(&udev->dev, "usb suspend\n"); + udev->state = USB_STATE_SUSPENDED; + msleep(10); + } + return status; +} + +/* + * Devices on USB hub ports have only one "suspend" state, corresponding + * to ACPI D2 (PM_SUSPEND_MEM), "may cause the device to lose some context". + * State transitions include: + * + * - suspend, resume ... when the VBUS power link stays live + * - suspend, disconnect ... VBUS lost + * + * Once VBUS drop breaks the circuit, the port it's using has to go through + * normal re-enumeration procedures, starting with enabling VBUS power. + * Other than re-initializing the hub (plug/unplug, except for root hubs), + * Linux (2.6) currently has NO mechanisms to initiate that: no khubd + * timer, no SRP, no requests through sysfs. + */ +static int __usb_suspend_device (struct usb_device *udev, int port, u32 state) +{ + int status; + + if (port < 0) + return port; + + /* NOTE: udev->serialize released on all real returns! */ + + if (state <= udev->dev.power.power_state + || state < PM_SUSPEND_MEM + || udev->state == USB_STATE_SUSPENDED + || udev->state == USB_STATE_NOTATTACHED) { + up(&udev->serialize); + return 0; + } + + /* suspend interface drivers; if this is a hub, it + * suspends the child devices + */ + if (udev->actconfig) { + int i; + + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (state <= intf->dev.power.power_state) + continue; + if (!intf->dev.driver) + continue; + driver = to_usb_driver(intf->dev.driver); + + if (driver->suspend) { + status = driver->suspend(intf, state); + if (intf->dev.power.power_state != state + || status) + dev_err(&intf->dev, + "suspend %d fail, code %d\n", + state, status); + } + + /* only drivers with suspend() can ever resume(); + * and after power loss, even they won't. + * bus_rescan_devices() can rebind drivers later. + * + * FIXME the PM core self-deadlocks when unbinding + * drivers during suspend/resume ... everything grabs + * dpm_sem (not a spinlock, ugh). we want to unbind, + * since we know every driver's probe/disconnect works + * even for drivers that can't suspend. + */ + if (!driver->suspend || state > PM_SUSPEND_MEM) { +#if 1 + dev_warn(&intf->dev, "resume is unsafe!\n"); +#else + down_write(&usb_bus_type.rwsem); + device_release_driver(&intf->dev); + up_write(&usb_bus_type.rwsem); +#endif + } + } + } + + /* + * FIXME this needs port power off call paths too, to help force + * USB into the "generic" PM model. At least for devices on + * ports that aren't using ganged switching (usually root hubs). + * + * NOTE: SRP-capable links should adopt more aggressive poweroff + * policies (when HNP doesn't apply) once we have mechanisms to + * turn power back on! (Likely not before 2.7...) + */ + if (state > PM_SUSPEND_MEM) { + dev_warn(&udev->dev, "no poweroff yet, suspending instead\n"); + state = PM_SUSPEND_MEM; + } + + /* "global suspend" of the HC-to-USB interface (root hub), or + * "selective suspend" of just one hub-device link. + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_suspend) + status = bus->op->hub_suspend (bus); + else + status = -EOPNOTSUPP; + } else + status = hub_port_suspend(udev->parent, port + 1); + + if (status == 0) + udev->dev.power.power_state = state; + up(&udev->serialize); + return status; +} + +/** + * usb_suspend_device - suspend a usb device + * @udev: device that's no longer in active use + * @state: PM_SUSPEND_MEM to suspend + * Context: must be able to sleep; device not locked + * + * Suspends a USB device that isn't in active use, conserving power. + * Devices may wake out of a suspend, if anything important happens, + * using the remote wakeup mechanism. They may also be taken out of + * suspend by the host, using usb_resume_device(). It's also routine + * to disconnect devices while they are suspended. + * + * Suspending OTG devices may trigger HNP, if that's been enabled + * between a pair of dual-role devices. That will change roles, such + * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. + * + * Returns 0 on success, else negative errno. + */ +int usb_suspend_device(struct usb_device *udev, u32 state) +{ + return __usb_suspend_device(udev, locktree(udev), state); +} + +/* + * hardware resume signaling is finished, either because of selective + * resume (by host) or remote wakeup (by device) ... now see what changed + * in the tree that's rooted at this device. + */ +static int finish_port_resume(struct usb_device *udev) +{ + int status; + u16 devstatus; + + /* caller owns udev->serialize */ + dev_dbg(&udev->dev, "usb resume\n"); + udev->dev.power.power_state = PM_SUSPEND_ON; + + /* usb ch9 identifies four variants of SUSPENDED, based on what + * state the device resumes to. Linux currently won't see the + * first two on the host side; they'd be inside hub_port_init() + * during many timeouts, but khubd can't suspend until later. + */ + udev->state = udev->actconfig + ? USB_STATE_CONFIGURED + : USB_STATE_ADDRESS; + + /* 10.5.4.5 says be sure devices in the tree are still there. + * For now let's assume the device didn't go crazy on resume, + * and device drivers will know about any resume quirks. + */ + status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); + if (status < 0) + dev_dbg(&udev->dev, + "gone after usb resume? status %d\n", + status); + else if (udev->actconfig) { + unsigned i; + + le16_to_cpus(&devstatus); + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) { + dev_dbg(&udev->dev, "disable remote " + "wakeup, status %d\n", status); + status = 0; + } + } + + /* resume interface drivers; if this is a hub, it + * resumes the child devices + */ + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (intf->dev.power.power_state == PM_SUSPEND_ON) + continue; + if (!intf->dev.driver) { + /* FIXME maybe force to alt 0 */ + continue; + } + driver = to_usb_driver(intf->dev.driver); + + /* bus_rescan_devices() may rebind drivers */ + if (!driver->resume) + continue; + + /* can we do better than just logging errors? */ + status = driver->resume(intf); + if (intf->dev.power.power_state != PM_SUSPEND_ON + || status) + dev_dbg(&intf->dev, + "resume fail, state %d code %d\n", + intf->dev.power.power_state, status); + } + status = 0; + + } else if (udev->devnum <= 0) { + dev_dbg(&udev->dev, "bogus resume!\n"); + status = -EINVAL; + } + return status; +} + +static int +hub_port_resume(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "resume port %d\n", port); + + /* see 7.1.7.7; affects power usage, but not budgeting */ + status = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "can't resume port %d, status %d\n", + port, status); + } else { + u16 devstatus; + u16 portchange; + + /* drive resume for at least 20 msec */ + dev_dbg(&udev->dev, "RESUME\n"); + msleep(25); + +#define LIVE_FLAGS ( USB_PORT_STAT_POWER \ + | USB_PORT_STAT_ENABLE \ + | USB_PORT_STAT_CONNECTION) + + /* Virtual root hubs can trigger on GET_PORT_STATUS to + * stop resume signaling. Then finish the resume + * sequence. + */ + devstatus = portchange = 0; + status = hub_port_status(hdev, port - 1, + &devstatus, &portchange); + if (status < 0 + || (devstatus & LIVE_FLAGS) != LIVE_FLAGS + || (devstatus & USB_PORT_STAT_SUSPEND) != 0 + ) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "port %d status %04x.%04x after resume, %d\n", + port, portchange, devstatus, status); + } else { + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + } + if (status < 0) + status = hub_port_disable(hdev, port); + + return status; +} + +static int hub_resume (struct usb_interface *intf); + +/** + * usb_resume_device - re-activate a suspended usb device + * @udev: device to re-activate + * Context: must be able to sleep; device not locked + * + * This will re-activate the suspended device, increasing power usage + * while letting drivers communicate again with its endpoints. + * USB resume explicitly guarantees that the power session between + * the host and the device is the same as it was when the device + * suspended. + * + * Returns 0 on success, else negative errno. + */ +int usb_resume_device(struct usb_device *udev) +{ + int port, status; + + port = locktree(udev); + if (port < 0) + return port; + + /* "global resume" of the HC-to-USB interface (root hub), or + * selective resume of one hub-to-device port + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_resume) + status = bus->op->hub_resume (bus); + else + status = -EOPNOTSUPP; + if (status == 0) { + /* TRSMRCY = 10 msec */ + msleep(10); + status = hub_resume (bus->root_hub + ->actconfig->interface[0]); + } + } else if (udev->state == USB_STATE_SUSPENDED) { + status = hub_port_resume(udev->parent, port + 1); + } else { + status = 0; + udev->dev.power.power_state = PM_SUSPEND_ON; + } + if (status < 0) { + dev_dbg(&udev->dev, "can't resume, status %d\n", + status); + } + + up(&udev->serialize); + + /* rebind drivers that had no suspend() */ + bus_rescan_devices(&usb_bus_type); + + return status; +} + +static int remote_wakeup(struct usb_device *udev) +{ + int status = 0; + + /* don't repeat RESUME sequence if this device + * was already woken up by some other task + */ + down(&udev->serialize); + if (udev->state == USB_STATE_SUSPENDED) { + dev_dbg(&udev->dev, "RESUME (wakeup)\n"); + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + up(&udev->serialize); + return status; +} + +static int hub_suspend(struct usb_interface *intf, u32 state) +{ + struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_device *hdev = hub->hdev; + unsigned port; + int status; + + /* stop khubd and related activity */ + hub_quiesce(hub); + + /* then suspend every port */ + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + + udev = hdev->children [port]; + if (!udev) + continue; + down(&udev->serialize); + status = __usb_suspend_device(udev, port, state); + if (status < 0) + dev_dbg(&intf->dev, "suspend port %d --> %d\n", + port, status); + } + + intf->dev.power.power_state = state; + return 0; +} + +static int hub_resume(struct usb_interface *intf) +{ + struct usb_device *hdev = interface_to_usbdev(intf); + struct usb_hub *hub = usb_get_intfdata (intf); + unsigned port; + int status; + + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + u16 portstat, portchange; + + udev = hdev->children [port]; + status = hub_port_status(hdev, port, &portstat, &portchange); + if (status == 0) { + if (portchange & USB_PORT_STAT_C_SUSPEND) { + clear_port_feature(hdev, port + 1, + USB_PORT_FEAT_C_SUSPEND); + portchange &= ~USB_PORT_STAT_C_SUSPEND; + } + + /* let khubd handle disconnects etc */ + if (portchange) + continue; + } + + if (!udev) + continue; + down (&udev->serialize); + if (portstat & USB_PORT_STAT_SUSPEND) + status = hub_port_resume(hdev, port + 1); + else { + status = finish_port_resume(udev); + if (status < 0) + status = hub_port_disable(hdev, port); + if (status < 0) + dev_dbg(&intf->dev, "resume port %d --> %d\n", + port, status); + } + up(&udev->serialize); + } + intf->dev.power.power_state = PM_SUSPEND_ON; + + hub_reactivate(hub); + return 0; +} #else /* !CONFIG_USB_SUSPEND */ @@ -1369,6 +2011,10 @@ hdev->bus->b_hnp_enable = 0; } + retval = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (retval < 0 && retval != -EPIPE) + dev_dbg(&udev->dev, "can't clear suspend; %d\n", retval); + /* Some low speed devices have problems with the quick delay, so */ /* be a bit pessimistic with those devices. RHbug #23670 */ if (oldspeed == USB_SPEED_LOW) @@ -1479,8 +2125,6 @@ != udev->descriptor.bMaxPacketSize0)) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - usb_endpoint_running(udev, 0, 1); - usb_endpoint_running(udev, 0, 0); udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0; udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0; } @@ -1574,6 +2218,7 @@ * a port enable-change occurs (often caused by EMI); * usb_reset_device() encounters changed descriptors (as from * a firmware download) + * caller already locked the hub */ static void hub_port_connect_change(struct usb_hub *hub, int port, u16 portstatus, u16 portchange) @@ -1596,6 +2241,12 @@ usb_disconnect(&hdev->children[port]); clear_bit(port, hub->change_bits); +#ifdef CONFIG_USB_OTG + /* during HNP, don't repeat the debounce */ + if (hdev->bus->is_b_host) + portchange &= ~USB_PORT_STAT_C_CONNECTION; +#endif + if (portchange & USB_PORT_STAT_C_CONNECTION) { status = hub_port_debounce(hdev, port); if (status < 0) { @@ -1780,7 +2431,8 @@ /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ - down(&hdev->serialize); + if (locktree(hdev) < 0) + break; if (hdev->state != USB_STATE_CONFIGURED || !hdev->actconfig || hub != usb_get_intfdata( @@ -2034,7 +2686,7 @@ } /** - * usb_reset_devce - perform a USB port reset to reinitialize a device + * usb_reset_device - perform a USB port reset to reinitialize a device * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) * * WARNING - don't reset any device unless drivers for all of its @@ -2123,7 +2775,7 @@ struct usb_interface *intf = udev->actconfig->interface[i]; struct usb_interface_descriptor *desc; - /* set_interface resets host side toggle and halt status even + /* set_interface resets host side toggle even * for altsetting zero. the interface may have no driver. */ desc = &intf->cur_altsetting->desc; diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h 2004-10-18 14:55:55 -07:00 +++ b/drivers/usb/core/hub.h 2004-10-18 14:55:55 -07:00 @@ -60,8 +60,8 @@ * See USB 2.0 spec Table 11-19 and Table 11-20 */ struct usb_port_status { - __u16 wPortStatus; - __u16 wPortChange; + __le16 wPortStatus; + __le16 wPortChange; } __attribute__ ((packed)); /* @@ -103,8 +103,8 @@ #define HUB_CHAR_PORTIND 0x0080 /* D7 */ struct usb_hub_status { - __u16 wHubStatus; - __u16 wHubChange; + __le16 wHubStatus; + __le16 wHubChange; } __attribute__ ((packed)); /* @@ -190,8 +190,8 @@ struct usb_device *hdev; struct urb *urb; /* for interrupt polling pipe */ - /* buffer for urb ... 1 bit each for hub and children, rounded up */ - char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8]; + /* buffer for urb ... with extra space in case of babble */ + char (*buffer)[8]; dma_addr_t buffer_dma; /* DMA address for buffer */ union { struct usb_hub_status hub; @@ -213,6 +213,8 @@ struct usb_tt tt; /* Transaction Translator */ u8 power_budget; /* in 2mA units; or zero */ + + unsigned quiescing:1; unsigned has_indicators:1; enum hub_led_mode indicator[USB_MAXCHILDREN]; diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c --- a/drivers/usb/core/inode.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/core/inode.c 2004-10-18 14:55:54 -07:00 @@ -345,30 +345,13 @@ return 0; } -static void d_unhash(struct dentry *dentry) -{ - dget(dentry); - spin_lock(&dcache_lock); - switch (atomic_read(&dentry->d_count)) { - default: - spin_unlock(&dcache_lock); - shrink_dcache_parent(dentry); - spin_lock(&dcache_lock); - if (atomic_read(&dentry->d_count) != 2) - break; - case 2: - __d_drop(dentry); - } - spin_unlock(&dcache_lock); -} - static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) { int error = -ENOTEMPTY; struct inode * inode = dentry->d_inode; down(&inode->i_sem); - d_unhash(dentry); + dentry_unhash(dentry); if (usbfs_empty(dentry)) { dentry->d_inode->i_nlink -= 2; dput(dentry); diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c 2004-10-18 14:56:20 -07:00 +++ b/drivers/usb/core/message.c 2004-10-18 14:56:20 -07:00 @@ -248,7 +248,7 @@ * unlink pending urbs so they won't rx/tx bad data. */ for (i = 0, found = 0; i < io->entries; i++) { - if (!io->urbs [i]) + if (!io->urbs [i] || !io->urbs [i]->dev) continue; if (found) { status = usb_unlink_urb (io->urbs [i]); @@ -337,7 +337,7 @@ if (io->entries <= 0) return io->entries; - io->count = 0; + io->count = io->entries; io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); if (!io->urbs) goto nomem; @@ -347,7 +347,7 @@ if (usb_pipein (pipe)) urb_flags |= URB_SHORT_NOT_OK; - for (i = 0; i < io->entries; i++, io->count = i) { + for (i = 0; i < io->entries; i++) { unsigned len; io->urbs [i] = usb_alloc_urb (0, mem_flags); @@ -477,24 +477,19 @@ /* fail any uncompleted urbs */ default: - spin_lock_irq (&io->lock); - io->count -= entries - i; - if (io->status == -EINPROGRESS) - io->status = retval; - if (io->count == 0) - complete (&io->complete); - spin_unlock_irq (&io->lock); - - io->urbs[i]->dev = NULL; + io->urbs [i]->dev = NULL; io->urbs [i]->status = retval; dev_dbg (&io->dev->dev, "%s, submit --> %d\n", __FUNCTION__, retval); usb_sg_cancel (io); } spin_lock_irq (&io->lock); - if (retval && io->status == -ECONNRESET) + if (retval && (io->status == 0 || io->status == -ECONNRESET)) io->status = retval; } + io->count -= entries - i; + if (io->count == 0) + complete (&io->complete); spin_unlock_irq (&io->lock); /* OK, yes, this could be packaged as non-blocking. @@ -577,8 +572,13 @@ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, HZ * USB_CTRL_GET_TIMEOUT); - if (!(result == 0 || result == -EPIPE)) - break; + if (result == 0 || result == -EPIPE) + continue; + if (result > 1 && ((u8 *)buf)[1] != type) { + result = -EPROTO; + continue; + } + break; } return result; } @@ -854,9 +854,8 @@ * the copy in usb-storage, for as long as we need two copies. */ - /* toggle was reset by the clear, then ep was reactivated */ + /* toggle was reset by the clear */ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); return 0; } @@ -870,9 +869,8 @@ * Deallocates hcd/hardware state for this endpoint ... and nukes all * pending urbs. * - * If the HCD hasn't registered a disable() function, this marks the - * endpoint as halted and sets its maxpacket size to 0 to prevent - * further submissions. + * If the HCD hasn't registered a disable() function, this sets the + * endpoint's maxpacket size to 0 to prevent further submissions. */ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) { @@ -881,13 +879,10 @@ else { unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - if (usb_endpoint_out(epaddr)) { - usb_endpoint_halt(dev, epnum, 1); + if (usb_endpoint_out(epaddr)) dev->epmaxpacketout[epnum] = 0; - } else { - usb_endpoint_halt(dev, epnum, 0); + else dev->epmaxpacketin[epnum] = 0; - } } } @@ -930,7 +925,6 @@ usb_disable_endpoint(dev, i + USB_DIR_IN); } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -966,9 +960,8 @@ * @dev: the device whose interface is being enabled * @epd: pointer to the endpoint descriptor * - * Marks the endpoint as running, resets its toggle, and stores - * its maxpacket value. For control endpoints, both the input - * and output sides are handled. + * Resets the endpoint toggle and stores its maxpacket value. + * For control endpoints, both the input and output sides are handled. */ void usb_enable_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *epd) @@ -980,12 +973,10 @@ USB_ENDPOINT_XFER_CONTROL); if (usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 1); usb_settoggle(dev, epnum, 1, 0); dev->epmaxpacketout[epnum] = maxsize; } if (!usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 0); usb_settoggle(dev, epnum, 0, 0); dev->epmaxpacketin[epnum] = maxsize; } @@ -1048,6 +1039,9 @@ int ret; int manual = 0; + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + iface = usb_ifnum_to_if(dev, interface); if (!iface) { dev_dbg(&dev->dev, "selecting invalid interface %d\n", @@ -1145,6 +1139,9 @@ int i, retval; struct usb_host_config *config; + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + /* caller must own dev->serialize (config won't change) * and the usb bus readlock (so driver bindings are stable); * so calls during probe() are fine @@ -1166,7 +1163,6 @@ } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { @@ -1195,7 +1191,7 @@ struct usb_interface_cache *intfc = altsetting_to_usb_interface_cache(intf->altsetting); - kref_put(&intfc->ref); + kref_put(&intfc->ref, usb_release_interface_cache); kfree(intf); } @@ -1257,6 +1253,9 @@ */ if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); + + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ diff -Nru a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/core/otg_whitelist.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,112 @@ +/* + * drivers/usb/core/otg_whitelist.h + * + * Copyright (C) 2004 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* + * This OTG Whitelist is the OTG "Targeted Peripheral List". It should + * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries.. + * + * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! + */ + +static struct usb_device_id whitelist_table [] = { + +/* hubs are optional in OTG, but very handy ... */ +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), }, + +#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */ +/* FIXME actually, printers are NOT supposed to use device classes; + * they're supposed to use interface classes... + */ +{ USB_DEVICE_INFO(7, 1, 1) }, +{ USB_DEVICE_INFO(7, 1, 2) }, +{ USB_DEVICE_INFO(7, 1, 3) }, +#endif + +#ifdef CONFIG_USB_CDCETHER +/* Linux-USB CDC Ethernet gadget */ +{ USB_DEVICE(0x0525, 0xa4a1), }, +/* Linux-USB CDC Ethernet + RNDIS gadget */ +{ USB_DEVICE(0x0525, 0xa4a2), }, +#endif + +#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE) +/* gadget zero, for testing */ +{ USB_DEVICE(0x0525, 0xa4a0), }, +#endif + +{ } /* Terminating entry */ +}; + +static int is_targeted(struct usb_device *dev) +{ + struct usb_device_id *id = whitelist_table; + + /* possible in developer configs only! */ + if (!dev->bus->otg_port) + return 1; + + /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */ + if (dev->descriptor.idVendor == 0x1a0a + && dev->descriptor.idProduct == 0xbadd) + return 0; + + /* NOTE: can't use usb_match_id() since interface caches + * aren't set up yet. this is cut/paste from that code. + */ + for (id = whitelist_table; id->match_flags; id++) { + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && + id->idVendor != dev->descriptor.idVendor) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && + id->idProduct != dev->descriptor.idProduct) + continue; + + /* No need to test id->bcdDevice_lo != 0, since 0 is never + greater than any unsigned number. */ + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && + (id->bcdDevice_lo > dev->descriptor.bcdDevice)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && + (id->bcdDevice_hi < dev->descriptor.bcdDevice)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && + (id->bDeviceClass != dev->descriptor.bDeviceClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && + (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) + continue; + + return 1; + } + + /* add other match criteria here ... */ + + + /* OTG MESSAGE: report errors here, customize to match your product */ + dev_err(&dev->dev, "device v%04x p%04x is not supported\n", + dev->descriptor.idVendor, + dev->descriptor.idProduct); +#ifdef CONFIG_USB_OTG_WHITELIST + return 0; +#else + return 1; +#endif +} + diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/core/urb.c 2004-10-18 14:56:33 -07:00 @@ -39,7 +39,7 @@ { if (urb) { memset(urb, 0, sizeof(*urb)); - kref_init(&urb->kref, urb_destroy); + kref_init(&urb->kref); spin_lock_init(&urb->lock); } } @@ -88,7 +88,7 @@ void usb_free_urb(struct urb *urb) { if (urb) - kref_put(&urb->kref); + kref_put(&urb->kref, urb_destroy); } /** @@ -255,13 +255,6 @@ if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) return -ENODEV; - - /* (actually HCDs may need to duplicate this, endpoint might yet - * stall due to queued bulk/intr transactions that complete after - * we check) - */ - if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out)) - return -EPIPE; /* FIXME there should be a sharable lock protecting us against * config/altsetting changes and disconnects, kicking in here. diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/usb/core/usb.c 2004-10-18 14:56:32 -07:00 @@ -93,6 +93,8 @@ if (!driver->probe) return error; + if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; id = usb_match_id (intf, driver->id_table); if (id) { diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h --- a/drivers/usb/core/usb.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/usb/core/usb.h 2004-10-18 14:56:17 -07:00 @@ -10,6 +10,7 @@ extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); +extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device (struct usb_device *dev, int skip_ep0); extern void usb_enable_endpoint (struct usb_device *dev, diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/gadget/Kconfig 2004-10-18 14:56:28 -07:00 @@ -135,6 +135,18 @@ depends on USB_GADGET_SA1100 default USB_GADGET +config USB_GADGET_LH7A40X + boolean "LH7A40X" + depends on ARCH_LH7A40X + help + This driver provides USB Device Controller driver for LH7A40x + +config USB_LH7A40X + tristate + depends on USB_GADGET_LH7A40X + default USB_GADGET + + config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" depends on USB && EXPERIMENTAL @@ -163,6 +175,41 @@ depends on USB_GADGET_DUMMY_HCD default USB_GADGET +config USB_GADGET_OMAP + boolean "OMAP USB Device Controller" + depends on ARCH_OMAP + select ISP1301_OMAP if MACH_OMAP_H2 + help + Many Texas Instruments OMAP processors have flexible full + speed USB device controllers, with support for up to 30 + endpoints (plus endpoint zero). This driver supports the + controller in the OMAP 1611, and should work with controllers + in other OMAP processors too, given minor tweaks. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "omap_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_OMAP + tristate + depends on USB_GADGET_OMAP + default USB_GADGET + +config USB_OTG + boolean "OTG Support" + depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD + help + The most notable feature of USB OTG is support for a + "Dual-Role" device, which can act as either a device + or a host. The initial role choice can be changed + later, when two dual-role devices talk to each other. + + Select this only if your OMAP board has a Mini-AB connector. + +config USB_OMAP_PROC + boolean "/proc/driver/udc file" + depends on USB_GADGET_OMAP + endchoice config USB_GADGET_DUALSPEED @@ -275,7 +322,7 @@ dynamically linked module called "gadgetfs". config USB_FILE_STORAGE - tristate "File-backed Storage Gadget (DEVELOPMENT)" + tristate "File-backed Storage Gadget" # we don't support the SA1100 because of its limitations depends on USB_GADGET_SA1100 = n help @@ -288,7 +335,7 @@ dynamically linked module called "g_file_storage". config USB_FILE_STORAGE_TEST - bool "File-backed Storage Gadget test version" + bool "File-backed Storage Gadget testing version" depends on USB_FILE_STORAGE default n help diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile --- a/drivers/usb/gadget/Makefile 2004-10-18 14:55:55 -07:00 +++ b/drivers/usb/gadget/Makefile 2004-10-18 14:55:55 -07:00 @@ -5,13 +5,15 @@ obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o +obj-$(CONFIG_USB_OMAP) += omap_udc.o +obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o # # USB gadget drivers # g_zero-objs := zero.o usbstring.o config.o epautoconf.o g_ether-objs := ether.o usbstring.o config.o epautoconf.o -g_serial-objs := serial.o usbstring.o +g_serial-objs := serial.o usbstring.o epautoconf.o gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o diff -Nru a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c --- a/drivers/usb/gadget/dummy_hcd.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/gadget/dummy_hcd.c 2004-10-18 14:55:54 -07:00 @@ -596,14 +596,13 @@ /* "function" sysfs attribute */ static ssize_t -show_function (struct device *_dev, char *buf) +show_function (struct device *dev, char *buf) { - struct dummy *dum = the_controller; + struct dummy *dum = gadget_dev_to_dummy (dev); - if (!dum->driver->function - || strlen (dum->driver->function) > PAGE_SIZE) + if (!dum->driver || !dum->driver->function) return 0; - return snprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); + return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); } DEVICE_ATTR (function, S_IRUGO, show_function, NULL); diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/gadget/ether.c 2004-10-18 14:57:04 -07:00 @@ -63,6 +63,7 @@ /* * Ethernet gadget driver -- with CDC and non-CDC options + * Builds on hardware support for a full duplex link. * * CDC Ethernet is the standard USB solution for sending Ethernet frames * using USB. Real hardware tends to use the same framing protocol but look @@ -242,6 +243,10 @@ #define DEV_CONFIG_SUBSET #endif +#ifdef CONFIG_USB_GADGET_LH7A40X +#define DEV_CONFIG_CDC +#endif + #ifdef CONFIG_USB_GADGET_SA1100 /* use non-CDC for backwards compatibility */ #define DEV_CONFIG_SUBSET @@ -855,7 +860,7 @@ static char ethaddr [2 * ETH_ALEN + 1]; #endif -/* static strings, in iso 8859/1 */ +/* static strings, in UTF-8 */ static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, product_desc, }, @@ -897,9 +902,9 @@ if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; -#define which_fn(t) (hs ? & hs_ ## t ## _function : & fs_ ## t ## _function) +#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) #else -#define which_fn(t) (& fs_ ## t ## _function) +#define which_fn(t) (fs_ ## t ## _function) #endif if (index >= device_desc.bNumConfigurations) @@ -911,14 +916,12 @@ */ if (device_desc.bNumConfigurations == 2 && index == 0) { config = &rndis_config; - function = (const struct usb_descriptor_header **) - which_fn (rndis); + function = which_fn (rndis); } else #endif { config = ð_config; - function = (const struct usb_descriptor_header **) - which_fn (eth); + function = which_fn (eth); } /* for now, don't advertise srp-only devices */ @@ -2329,6 +2332,8 @@ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); } else if (gadget_is_omap (gadget)) { device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else if (gadget_is_lh7a40x(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209); } else { /* can't assume CDC works. don't want to default to * anything less functional on CDC-capable hardware, diff -Nru a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c --- a/drivers/usb/gadget/file_storage.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/gadget/file_storage.c 2004-10-18 14:57:04 -07:00 @@ -46,17 +46,16 @@ * * Backing storage is provided by a regular file or a block device, specified * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. + * setting the optional "ro" module parameter. The gadget will indicate that + * it has removable media if the optional "removable" module parameter is set. * * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected * by the optional "transport" module parameter. It also supports the * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by - * the optional "protocol" module parameter. For testing purposes the - * gadget will indicate that it has removable media if the optional - * "removable" module parameter is set. In addition, the default Vendor ID, - * Product ID, and release number can be overridden. + * the optional "protocol" module parameter. In addition, the default + * Vendor ID, Product ID, and release number can be overridden. * * There is support for multiple logical units (LUNs), each of which has * its own backing file. The number of LUNs can be set using the optional @@ -79,13 +78,13 @@ * the files or block devices used for * backing storage * ro=b[,b...] Default false, booleans for read-only access + * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of * LUNs to support * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; * also 1 - 6) - * removable Default false, boolean for removable media * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID * release=0xRRRR Override the USB release number (bcdDevice) @@ -97,16 +96,16 @@ * boolean to permit the driver to halt * bulk endpoints * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file" and "ro" - * options are available; default values are used for everything else. + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", + * "removable", and "luns" options are available; default values are used + * for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun subdirectory of the - * gadget's sysfs directory. If CONFIG_USB_FILE_STORAGE_TEST and the - * "removable" option are both set, writing to these files will simulate - * ejecting/loading the medium (writing an empty line means eject) and - * adjusting a write-enable tab. Changes to the ro setting are not allowed - * when the medium is loaded. + * gadget's sysfs directory. If the "removable" option is set, writing to + * these files will simulate ejecting/loading the medium (writing an empty + * line means eject) and adjusting a write-enable tab. Changes to the ro + * setting are not allowed when the medium is loaded. * * This gadget driver is heavily based on "Gadget Zero" by David Brownell. */ @@ -178,7 +177,10 @@ * Bulk-only specification requires a stall. In such cases the driver * will halt the endpoint and set a flag indicating that it should clear * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. + * will permit everything to work correctly. Furthermore, although the + * specification allows the bulk-out endpoint to halt when the host sends + * too much data, implementing this would cause an unavoidable race. + * The driver will always use the "no-stall" approach for OUT transfers. * * One subtle point concerns sending status-stage responses for ep0 * requests. Some of these requests, such as device reset, can involve @@ -246,7 +248,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "21 March 2004" +#define DRIVER_VERSION "28 July 2004" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -371,14 +373,17 @@ module_param_array(ro, bool, mod_data.num_ros, S_IRUGO); MODULE_PARM_DESC(ro, "true to force read-only"); +module_param_named(luns, mod_data.nluns, uint, S_IRUGO); +MODULE_PARM_DESC(luns, "number of LUNs"); -/* In the non-TEST version, only the file and ro module parameters +module_param_named(removable, mod_data.removable, bool, S_IRUGO); +MODULE_PARM_DESC(removable, "true to simulate removable media"); + + +/* In the non-TEST version, only the module parameters listed above * are available. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST -module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -MODULE_PARM_DESC(luns, "number of LUNs"); - module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); @@ -386,9 +391,6 @@ MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " "8070, or SCSI)"); -module_param_named(removable, mod_data.removable, bool, S_IRUGO); -MODULE_PARM_DESC(removable, "true to simulate removable media"); - module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); MODULE_PARM_DESC(vendor, "USB Vendor ID"); @@ -525,11 +527,6 @@ * parts of the driver that aren't used in the non-TEST version. Even gcc * can recognize when a test of a constant expression yields a dead code * path. - * - * Also, in the non-TEST version, open_backing_file() is only used during - * initialization and the sysfs attribute store_xxx routines aren't used - * at all. We will define NORMALLY_INIT to mark them as __init so they - * don't occupy kernel code space unnecessarily. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -537,16 +534,12 @@ #define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) #define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) #define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) -#define backing_file_is_open(curlun) ((curlun)->filp != NULL) -#define NORMALLY_INIT #else #define transport_is_bbb() 1 #define transport_is_cbi() 0 #define protocol_is_scsi() 1 -#define backing_file_is_open(curlun) 1 -#define NORMALLY_INIT __init #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -567,6 +560,8 @@ struct device dev; }; +#define backing_file_is_open(curlun) ((curlun)->filp != NULL) + static inline struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); @@ -659,6 +654,7 @@ unsigned long atomic_bitflags; #define REGISTERED 0 #define CLEAR_BULK_HALTS 1 +#define SUSPENDED 2 struct usb_ep *bulk_in; struct usb_ep *bulk_out; @@ -1041,8 +1037,6 @@ function = fs_function; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); - if (len < 0) - return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len; } @@ -1172,9 +1166,10 @@ wakeup_thread(fsg); } + +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; @@ -1190,17 +1185,21 @@ bh->state = BUF_STATE_EMPTY; spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + /*-------------------------------------------------------------------------*/ /* Ep0 class-specific handlers. These always run in_irq. */ +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct usb_request *req = fsg->ep0req; static u8 cbi_reset_cmnd[6] = { SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; @@ -1238,9 +1237,13 @@ spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + static int class_setup_req(struct fsg_dev *fsg, const struct usb_ctrlrequest *ctrl) @@ -1465,8 +1468,8 @@ /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < ctrl->wLength - && (rc % gadget->ep0->maxpacket) == 0; + fsg->ep0req->zero = (rc < ctrl->wLength && + (rc % gadget->ep0->maxpacket) == 0); fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); @@ -2443,14 +2446,19 @@ rc = -EINTR; } - /* We haven't processed all the incoming data. If we are - * allowed to stall, halt the bulk-out endpoint and cancel - * any outstanding requests. */ + /* We haven't processed all the incoming data. Even though + * we may be allowed to stall, doing so would cause a race. + * The controller may already have ACK'ed all the remaining + * bulk-out packets, in which case the host wouldn't see a + * STALL. Not realizing the endpoint was halted, it wouldn't + * clear the halt -- leading to problems later on. */ +#if 0 else if (mod_data.can_stall) { fsg_set_halt(fsg, fsg->bulk_out); raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); rc = -EINTR; } +#endif /* We can't stall. Read in the excess data and throw it * all away. */ @@ -2513,7 +2521,7 @@ } else if (mod_data.transport_type == USB_PR_CB) { - /* Control-Bulk transport has no status stage! */ + /* Control-Bulk transport has no status phase! */ return 0; } else { // USB_PR_CBI @@ -2603,8 +2611,10 @@ fsg->residue = fsg->usb_amount_left = fsg->data_size; /* Conflicting data directions is a phase error */ - if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) - goto phase_error; + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { + fsg->phase_error = 1; + return -EINVAL; + } /* Verify the length of the command itself */ if (cmnd_size != fsg->cmnd_size) { @@ -2613,8 +2623,10 @@ * with cbw->Length == 12 (it should be 6). */ if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) cmnd_size = fsg->cmnd_size; - else - goto phase_error; + else { + fsg->phase_error = 1; + return -EINVAL; + } } /* Check that the LUN values are oonsistent */ @@ -2674,10 +2686,6 @@ } return 0; - -phase_error: - fsg->phase_error = 1; - return -EINVAL; } @@ -3424,8 +3432,7 @@ /* If the next two routines are called while the gadget is registered, * the caller must own fsg->filesem for writing. */ -static int NORMALLY_INIT open_backing_file(struct lun *curlun, - const char *filename) +static int open_backing_file(struct lun *curlun, const char *filename) { int ro; struct file *filp = NULL; @@ -3550,8 +3557,7 @@ } -ssize_t NORMALLY_INIT store_ro(struct device *dev, const char *buf, - size_t count) +ssize_t store_ro(struct device *dev, const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3575,8 +3581,7 @@ return rc; } -ssize_t NORMALLY_INIT store_file(struct device *dev, const char *buf, - size_t count) +ssize_t store_file(struct device *dev, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); @@ -3708,6 +3713,8 @@ mod_data.release = __constant_cpu_to_le16(0x0307); else if (gadget_is_omap(fsg->gadget)) mod_data.release = __constant_cpu_to_le16(0x0308); + else if (gadget_is_lh7a40x(gadget)) + mod_data.release = __constant_cpu_to_le16 (0x0309); else { WARN(fsg, "controller '%s' not recognized\n", fsg->gadget->name); @@ -3805,9 +3812,8 @@ goto out; } - /* Create the LUNs and open their backing files. We can't register - * the LUN devices until the gadget itself is registered, which - * doesn't happen until after fsg_bind() returns. */ + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); if (!fsg->luns) { rc = -ENOMEM; @@ -3825,6 +3831,15 @@ snprintf(curlun->dev.bus_id, BUS_ID_SIZE, "%s-lun%d", gadget->dev.bus_id, i); + if ((rc = device_register(&curlun->dev)) != 0) + INFO(fsg, "failed to register LUN%d: %d\n", i, rc); + else { + curlun->registered = 1; + curlun->dev.release = lun_release; + device_create_file(&curlun->dev, &dev_attr_ro); + device_create_file(&curlun->dev, &dev_attr_file); + } + if (file[i] && *file[i]) { if ((rc = open_backing_file(curlun, file[i])) != 0) goto out; @@ -3974,6 +3989,25 @@ /*-------------------------------------------------------------------------*/ +static void fsg_suspend(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "suspend\n"); + set_bit(SUSPENDED, &fsg->atomic_bitflags); +} + +static void fsg_resume(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "resume\n"); + clear_bit(SUSPENDED, &fsg->atomic_bitflags); +} + + +/*-------------------------------------------------------------------------*/ + static struct usb_gadget_driver fsg_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, @@ -3985,6 +4019,8 @@ .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, + .suspend = fsg_suspend, + .resume = fsg_resume, .driver = { .name = (char *) shortname, @@ -4024,8 +4060,6 @@ { int rc; struct fsg_dev *fsg; - int i; - struct lun *curlun; if ((rc = fsg_alloc()) != 0) return rc; @@ -4035,19 +4069,6 @@ return rc; } set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Register the LUN devices and their attribute files */ - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if ((rc = device_register(&curlun->dev)) != 0) - INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - else { - curlun->registered = 1; - curlun->dev.release = lun_release; - device_create_file(&curlun->dev, &dev_attr_ro); - device_create_file(&curlun->dev, &dev_attr_file); - } - } /* Tell the thread to start working */ complete(&fsg->thread_notifier); diff -Nru a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h --- a/drivers/usb/gadget/gadget_chips.h 2004-10-18 14:55:46 -07:00 +++ b/drivers/usb/gadget/gadget_chips.h 2004-10-18 14:55:46 -07:00 @@ -44,6 +44,12 @@ #define gadget_is_sa1100(g) 0 #endif +#ifdef CONFIG_USB_GADGET_LH7A40X +#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name) +#else +#define gadget_is_lh7a40x(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_MQ11XX #define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) #else diff -Nru a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c --- a/drivers/usb/gadget/inode.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/gadget/inode.c 2004-10-18 14:56:49 -07:00 @@ -1,7 +1,7 @@ /* * inode.c -- user mode filesystem api for usb gadget controllers * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell * Copyright (C) 2003 Agilent Technologies * * This program is free software; you can redistribute it and/or modify @@ -71,7 +71,7 @@ */ #define DRIVER_DESC "USB Gadget filesystem" -#define DRIVER_VERSION "18 Nov 2003" +#define DRIVER_VERSION "24 Aug 2004" static const char driver_desc [] = DRIVER_DESC; static const char shortname [] = "gadgetfs"; @@ -229,37 +229,12 @@ /*----------------------------------------------------------------------*/ /* most "how to use the hardware" policy choices are in userspace: - * mapping endpoint roles the driver needs to the capabilities that - * the usb controller exposes. + * mapping endpoint roles (which the driver needs) to the capabilities + * which the usb controller has. most of those capabilities are exposed + * implicitly, starting with the driver name and then endpoint names. */ -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -/* act (mostly) like a net2280 */ -#define CONFIG_USB_GADGET_NET2280 -#endif - -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define HIGHSPEED -#endif - -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx_udc" -/* earlier hardware doesn't have UDCCFR, races set_{config,interface} */ -#warning works best with pxa255 or newer -#endif - -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku_udc" -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define CHIP "omap_udc" -#endif - -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#endif +static const char *CHIP; /*----------------------------------------------------------------------*/ @@ -558,7 +533,7 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) { - struct kiocb_priv *priv = (void *) &iocb->private; + struct kiocb_priv *priv = iocb->private; struct ep_data *epdata; int value; @@ -577,10 +552,10 @@ return value; } -static long ep_aio_read_retry(struct kiocb *iocb) +static ssize_t ep_aio_read_retry(struct kiocb *iocb) { - struct kiocb_priv *priv = (void *) &iocb->private; - int status = priv->actual; + struct kiocb_priv *priv = iocb->private; + ssize_t status = priv->actual; /* we "retry" to get the right mm context for this: */ status = copy_to_user(priv->ubuf, priv->buf, priv->actual); @@ -589,6 +564,7 @@ else status = priv->actual; kfree(priv->buf); + kfree(priv); aio_put_req(iocb); return status; } @@ -596,7 +572,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) { struct kiocb *iocb = req->context; - struct kiocb_priv *priv = (void *) &iocb->private; + struct kiocb_priv *priv = iocb->private; struct ep_data *epdata = priv->epdata; /* lock against disconnect (and ideally, cancel) */ @@ -607,6 +583,8 @@ || unlikely(0 == req->actual) || unlikely(kiocbIsCancelled(iocb))) { kfree(req->buf); + kfree(priv); + iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ if (unlikely(kiocbIsCancelled(iocb))) aio_put_req(iocb); @@ -631,17 +609,33 @@ } static ssize_t -ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) +ep_aio_rwtail( + struct kiocb *iocb, + char *buf, + size_t len, + struct ep_data *epdata, + char __user *ubuf +) { struct kiocb_priv *priv = (void *) &iocb->private; struct usb_request *req; ssize_t value; - value = get_ready_ep(iocb->ki_filp->f_flags, epdata); - if (unlikely(value < 0)) { + priv = kmalloc(sizeof *priv, GFP_KERNEL); + if (!priv) { + value = -ENOMEM; +fail: kfree(buf); return value; } + iocb->private = priv; + priv->ubuf = ubuf; + + value = get_ready_ep(iocb->ki_filp->f_flags, epdata); + if (unlikely(value < 0)) { + kfree(priv); + goto fail; + } iocb->ki_cancel = ep_aio_cancel; get_ep(epdata); @@ -671,9 +665,10 @@ up(&epdata->lock); - if (unlikely(value)) + if (unlikely(value)) { + kfree(priv); put_ep(epdata); - else + } else value = -EIOCBQUEUED; return value; } @@ -681,7 +676,6 @@ static ssize_t ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) { - struct kiocb_priv *priv = (void *) &iocb->private; struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; @@ -691,8 +685,7 @@ if (unlikely(!buf)) return -ENOMEM; iocb->ki_retry = ep_aio_read_retry; - priv->ubuf = ubuf; - return ep_aio_rwtail(iocb, buf, len, epdata); + return ep_aio_rwtail(iocb, buf, len, epdata, ubuf); } static ssize_t @@ -710,7 +703,7 @@ kfree(buf); return -EFAULT; } - return ep_aio_rwtail(iocb, buf, len, epdata); + return ep_aio_rwtail(iocb, buf, len, epdata, NULL); } /*----------------------------------------------------------------------*/ @@ -718,6 +711,8 @@ /* used after endpoint configuration */ static struct file_operations ep_io_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ep_read, .write = ep_write, .ioctl = ep_ioctl, @@ -874,6 +869,8 @@ /* used before endpoint configuration */ static struct file_operations ep_config_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .open = ep_open, .write = ep_config, .release = ep_release, @@ -980,6 +977,18 @@ retval = usb_ep_queue (ep, req, GFP_ATOMIC); dev->state = STATE_CONNECTED; + /* assume that was SET_CONFIGURATION */ + if (dev->current_config) { + unsigned power; +#ifdef HIGHSPEED + if (dev->gadget->speed == USB_SPEED_HIGH) + power = dev->hs_config->bMaxPower; + else +#endif + power = dev->config->bMaxPower; + usb_gadget_vbus_draw(dev->gadget, 2 * power); + } + } else { /* collect OUT data */ if ((fd->f_flags & O_NONBLOCK) != 0 && !dev->setup_out_ready) { @@ -1230,6 +1239,8 @@ /* used after device configuration */ static struct file_operations ep0_io_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ep0_read, .write = ep0_write, .fasync = ep0_fasync, @@ -1406,19 +1417,25 @@ if (0 == (u8) ctrl->wValue) { value = 0; dev->current_config = 0; + usb_gadget_vbus_draw(gadget, 8 /* mA */ ); // user mode expected to disable endpoints } else { - u8 config; + u8 config, power; #ifdef HIGHSPEED - if (gadget->speed == USB_SPEED_HIGH) + if (gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; - else + power = dev->hs_config->bMaxPower; + } else #endif + { config = dev->config->bConfigurationValue; + power = dev->config->bMaxPower; + } if (config == (u8) ctrl->wValue) { value = 0; dev->current_config = config; + usb_gadget_vbus_draw(gadget, 2 * power); } } @@ -1636,8 +1653,8 @@ if (!dev) return -ESRCH; if (0 != strcmp (CHIP, gadget->name)) { - printk (KERN_ERR "%s expected " CHIP " controller not %s\n", - shortname, gadget->name); + printk (KERN_ERR "%s expected %s controller not %s\n", + shortname, CHIP, gadget->name); return -ENODEV; } @@ -1727,6 +1744,26 @@ /*----------------------------------------------------------------------*/ +static void gadgetfs_nop(struct usb_gadget *arg) { } + +static int gadgetfs_probe (struct usb_gadget *gadget) +{ + CHIP = gadget->name; + return -EISNAM; +} + +static struct usb_gadget_driver probe_driver = { + .speed = USB_SPEED_HIGH, + .bind = gadgetfs_probe, + .unbind = gadgetfs_nop, + .setup = (void *)gadgetfs_nop, + .disconnect = gadgetfs_nop, + .driver = { + .name = "nop", + }, +}; + + /* DEVICE INITIALIZATION * * fd = open ("/dev/gadget/$CHIP", O_RDWR) @@ -1763,6 +1800,7 @@ && config->bConfigurationValue != 0 && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; + /* FIXME if gadget->is_otg, _must_ include an otg descriptor */ /* FIXME check lengths: walk to end */ } @@ -1881,6 +1919,8 @@ static struct file_operations dev_init_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .open = dev_open, .write = dev_config, .fasync = ep0_fasync, @@ -1975,6 +2015,11 @@ if (the_device) return -ESRCH; + + /* fake probe to determine $CHIP */ + (void) usb_gadget_register_driver (&probe_driver); + if (!CHIP) + return -ENODEV; /* superblock */ sb->s_blocksize = PAGE_CACHE_SIZE; diff -Nru a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/gadget/lh7a40x_udc.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,2168 @@ +/* + * linux/drivers/usb/gadget/lh7a40x_udc.c + * Sharp LH7A40x on-chip full speed USB device controllers + * + * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID + * Copyright (C) 2004 Bo Henriksen, Nordic ID + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "lh7a40x_udc.h" + +//#define DEBUG printk +//#define DEBUG_EP0 printk +//#define DEBUG_SETUP printk + +#ifndef DEBUG_EP0 +# define DEBUG_EP0(fmt,args...) +#endif +#ifndef DEBUG_SETUP +# define DEBUG_SETUP(fmt,args...) +#endif +#ifndef DEBUG +# define NO_STATES +# define DEBUG(fmt,args...) +#endif + +#define DRIVER_DESC "LH7A40x USB Device Controller" +#define DRIVER_VERSION __DATE__ + +#ifndef _BIT /* FIXME - what happended to _BIT in 2.6.7bk18? */ +#define _BIT(x) (1<<(x)) +#endif + +struct lh7a40x_udc *the_controller; + +static const char driver_name[] = "lh7a40x_udc"; +static const char driver_desc[] = DRIVER_DESC; +static const char ep0name[] = "ep0-control"; + +/* + Local definintions. +*/ +#define UDC_PROC_FILE + +#ifndef NO_STATES +static char *state_names[] = { + "WAIT_FOR_SETUP", + "DATA_STATE_XMIT", + "DATA_STATE_NEED_ZLP", + "WAIT_FOR_OUT_STATUS", + "DATA_STATE_RECV" +}; +#endif + +/* + Local declarations. +*/ +static int lh7a40x_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *); +static int lh7a40x_ep_disable(struct usb_ep *ep); +static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, int); +static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *); +static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *, + int); +static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t, + unsigned); +static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, int); +static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); +static int lh7a40x_set_halt(struct usb_ep *ep, int); +static int lh7a40x_fifo_status(struct usb_ep *ep); +static int lh7a40x_fifo_status(struct usb_ep *ep); +static void lh7a40x_fifo_flush(struct usb_ep *ep); +static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep); +static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr); + +static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, + int status); +static void pio_irq_enable(int bEndpointAddress); +static void pio_irq_disable(int bEndpointAddress); +static void stop_activity(struct lh7a40x_udc *dev, + struct usb_gadget_driver *driver); +static void flush(struct lh7a40x_ep *ep); +static void udc_enable(struct lh7a40x_udc *dev); +static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address); + +static struct usb_ep_ops lh7a40x_ep_ops = { + .enable = lh7a40x_ep_enable, + .disable = lh7a40x_ep_disable, + + .alloc_request = lh7a40x_alloc_request, + .free_request = lh7a40x_free_request, + + .alloc_buffer = lh7a40x_alloc_buffer, + .free_buffer = lh7a40x_free_buffer, + + .queue = lh7a40x_queue, + .dequeue = lh7a40x_dequeue, + + .set_halt = lh7a40x_set_halt, + .fifo_status = lh7a40x_fifo_status, + .fifo_flush = lh7a40x_fifo_flush, +}; + +/* Inline code */ + +static __inline__ int write_packet(struct lh7a40x_ep *ep, + struct lh7a40x_request *req, int max) +{ + u8 *buf; + int length, count; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + buf = req->req.buf + req->req.actual; + prefetch(buf); + + length = req->req.length - req->req.actual; + length = min(length, max); + req->req.actual += length; + + DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo); + + count = length; + while (count--) { + *fifo = *buf++; + } + + return length; +} + +static __inline__ void usb_set_index(u32 ep) +{ + *(volatile u32 *)io_p2v(USB_INDEX) = ep; +} + +static __inline__ u32 usb_read(u32 port) +{ + return *(volatile u32 *)io_p2v(port); +} + +static __inline__ void usb_write(u32 val, u32 port) +{ + *(volatile u32 *)io_p2v(port) = val; +} + +static __inline__ void usb_set(u32 val, u32 port) +{ + volatile u32 *ioport = (volatile u32 *)io_p2v(port); + u32 after = (*ioport) | val; + *ioport = after; +} + +static __inline__ void usb_clear(u32 val, u32 port) +{ + volatile u32 *ioport = (volatile u32 *)io_p2v(port); + u32 after = (*ioport) & ~val; + *ioport = after; +} + +/*-------------------------------------------------------------------------*/ + +#define GPIO_PORTC_DR (0x80000E08) +#define GPIO_PORTC_DDR (0x80000E18) +#define GPIO_PORTC_PDR (0x80000E70) + +/* get port C pin data register */ +#define get_portc_pdr(bit) ((usb_read(GPIO_PORTC_PDR) & _BIT(bit)) != 0) +/* get port C data direction register */ +#define get_portc_ddr(bit) ((usb_read(GPIO_PORTC_DDR) & _BIT(bit)) != 0) +/* set port C data register */ +#define set_portc_dr(bit, val) (val ? usb_set(_BIT(bit), GPIO_PORTC_DR) : usb_clear(_BIT(bit), GPIO_PORTC_DR)) +/* set port C data direction register */ +#define set_portc_ddr(bit, val) (val ? usb_set(_BIT(bit), GPIO_PORTC_DDR) : usb_clear(_BIT(bit), GPIO_PORTC_DDR)) + +/* + * LPD7A404 GPIO's: + * Port C bit 1 = USB Port 1 Power Enable + * Port C bit 2 = USB Port 1 Data Carrier Detect + */ +#define is_usb_connected() get_portc_pdr(2) + +#ifdef UDC_PROC_FILE + +static const char proc_node_name[] = "driver/udc"; + +static int +udc_proc_read(char *page, char **start, off_t off, int count, + int *eof, void *_dev) +{ + char *buf = page; + struct lh7a40x_udc *dev = _dev; + char *next = buf; + unsigned size = count; + unsigned long flags; + int t; + + if (off != 0) + return 0; + + local_irq_save(flags); + + /* basic device status */ + t = scnprintf(next, size, + DRIVER_DESC "\n" + "%s version: %s\n" + "Gadget driver: %s\n" + "Host: %s\n\n", + driver_name, DRIVER_VERSION, + dev->driver ? dev->driver->driver.name : "(none)", + is_usb_connected()? "full speed" : "disconnected"); + size -= t; + next += t; + + t = scnprintf(next, size, + "GPIO:\n" + " Port C bit 1: %d, dir %d\n" + " Port C bit 2: %d, dir %d\n\n", + get_portc_pdr(1), get_portc_ddr(1), + get_portc_pdr(2), get_portc_ddr(2) + ); + size -= t; + next += t; + + t = scnprintf(next, size, + "DCP pullup: %d\n\n", + (usb_read(USB_PM) & PM_USB_DCP) != 0); + size -= t; + next += t; + + local_irq_restore(flags); + *eof = 1; + return count - size; +} + +#define create_proc_files() create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev) +#define remove_proc_files() remove_proc_entry(proc_node_name, NULL) + +#else /* !UDC_PROC_FILE */ + +#define create_proc_files() do {} while (0) +#define remove_proc_files() do {} while (0) + +#endif /* UDC_PROC_FILE */ + +/* + * udc_disable - disable USB device controller + */ +static void udc_disable(struct lh7a40x_udc *dev) +{ + DEBUG("%s, %p\n", __FUNCTION__, dev); + + udc_set_address(dev, 0); + + /* Disable interrupts */ + usb_write(0, USB_IN_INT_EN); + usb_write(0, USB_OUT_INT_EN); + usb_write(0, USB_INT_EN); + + /* Disable the USB */ + usb_write(0, USB_PM); + +#ifdef CONFIG_ARCH_LH7A404 + /* Disable USB power */ + set_portc_dr(1, 0); +#endif + + /* if hardware supports it, disconnect from usb */ + /* make_usb_disappear(); */ + + dev->ep0state = WAIT_FOR_SETUP; + dev->gadget.speed = USB_SPEED_UNKNOWN; + dev->usb_address = 0; +} + +/* + * udc_reinit - initialize software state + */ +static void udc_reinit(struct lh7a40x_udc *dev) +{ + u32 i; + + DEBUG("%s, %p\n", __FUNCTION__, dev); + + /* device/ep0 records init */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + dev->ep0state = WAIT_FOR_SETUP; + + /* basic endpoint records init */ + for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { + struct lh7a40x_ep *ep = &dev->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + + ep->desc = 0; + ep->stopped = 0; + INIT_LIST_HEAD(&ep->queue); + ep->pio_irqs = 0; + } + + /* the rest was statically initialized, and is read-only */ +} + +#define BYTES2MAXP(x) (x / 8) +#define MAXP2BYTES(x) (x * 8) + +/* until it's enabled, this UDC should be completely invisible + * to any USB host. + */ +static void udc_enable(struct lh7a40x_udc *dev) +{ + int ep; + + DEBUG("%s, %p\n", __FUNCTION__, dev); + + dev->gadget.speed = USB_SPEED_UNKNOWN; + +#ifdef CONFIG_ARCH_LH7A404 + /* Set Port C bit 1 & 2 as output */ + set_portc_ddr(1, 1); + set_portc_ddr(2, 1); + + /* Enable USB power */ + set_portc_dr(1, 0); +#endif + + /* + * C.f Chapter 18.1.3.1 Initializing the USB + */ + + /* Disable the USB */ + usb_clear(PM_USB_ENABLE, USB_PM); + + /* Reset APB & I/O sides of the USB */ + usb_set(USB_RESET_APB | USB_RESET_IO, USB_RESET); + mdelay(5); + usb_clear(USB_RESET_APB | USB_RESET_IO, USB_RESET); + + /* Set MAXP values for each */ + for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) { + struct lh7a40x_ep *ep_reg = &dev->ep[ep]; + u32 csr; + + usb_set_index(ep); + + switch (ep_reg->ep_type) { + case ep_bulk_in: + case ep_interrupt: + usb_clear(USB_IN_CSR2_USB_DMA_EN | USB_IN_CSR2_AUTO_SET, + ep_reg->csr2); + /* Fall through */ + case ep_control: + usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), + USB_IN_MAXP); + break; + case ep_bulk_out: + usb_clear(USB_OUT_CSR2_USB_DMA_EN | + USB_OUT_CSR2_AUTO_CLR, ep_reg->csr2); + usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), + USB_OUT_MAXP); + break; + } + + /* Read & Write CSR1, just in case */ + csr = usb_read(ep_reg->csr1); + usb_write(csr, ep_reg->csr1); + + flush(ep_reg); + } + + /* Disable interrupts */ + usb_write(0, USB_IN_INT_EN); + usb_write(0, USB_OUT_INT_EN); + usb_write(0, USB_INT_EN); + + /* Enable interrupts */ + usb_set(USB_IN_INT_EP0, USB_IN_INT_EN); + usb_set(USB_INT_RESET_INT | USB_INT_RESUME_INT, USB_INT_EN); + /* Dont enable rest of the interrupts */ + /* usb_set(USB_IN_INT_EP3 | USB_IN_INT_EP1 | USB_IN_INT_EP0, USB_IN_INT_EN); + usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); */ + + /* Enable SUSPEND */ + usb_set(PM_ENABLE_SUSPEND, USB_PM); + + /* Enable the USB */ + usb_set(PM_USB_ENABLE, USB_PM); + +#ifdef CONFIG_ARCH_LH7A404 + /* NOTE: DOES NOT WORK! */ + /* Let host detect UDC: + * Software must write a 0 to the PMR:DCP_CTRL bit to turn this + * transistor on and pull the USBDP pin HIGH. + */ + /* usb_clear(PM_USB_DCP, USB_PM); + usb_set(PM_USB_DCP, USB_PM); */ +#endif +} + +/* + Register entry point for the peripheral controller driver. +*/ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct lh7a40x_udc *dev = the_controller; + int retval; + + DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name); + + if (!driver + || driver->speed != USB_SPEED_FULL + || !driver->bind + || !driver->unbind || !driver->disconnect || !driver->setup) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + /* first hook up the driver ... */ + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + + device_add(&dev->gadget.dev); + retval = driver->bind(&dev->gadget); + if (retval) { + printk("%s: bind to driver %s --> error %d\n", dev->gadget.name, + driver->driver.name, retval); + device_del(&dev->gadget.dev); + + dev->driver = 0; + dev->gadget.dev.driver = 0; + return retval; + } + + /* ... then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + * NOTE: this shouldn't power up until later. + */ + printk("%s: registered gadget driver '%s'\n", dev->gadget.name, + driver->driver.name); + + udc_enable(dev); + + return 0; +} + +EXPORT_SYMBOL(usb_gadget_register_driver); + +/* + Unregister entry point for the peripheral controller driver. +*/ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct lh7a40x_udc *dev = the_controller; + unsigned long flags; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + dev->driver = 0; + stop_activity(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); + + driver->unbind(&dev->gadget); + device_del(&dev->gadget.dev); + + udc_disable(dev); + + DEBUG("unregistered gadget driver '%s'\n", driver->driver.name); + return 0; +} + +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +/*-------------------------------------------------------------------------*/ + +/** Write request to FIFO (max write == maxp size) + * Return: 0 = still running, 1 = completed, negative = errno + * NOTE: INDEX register must be set for EP + */ +static int write_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 max; + u32 csr; + + max = le16_to_cpu(ep->desc->wMaxPacketSize); + + csr = usb_read(ep->csr1); + DEBUG("CSR: %x %d\n", csr, csr & USB_IN_CSR1_FIFO_NOT_EMPTY); + + if (!(csr & USB_IN_CSR1_FIFO_NOT_EMPTY)) { + unsigned count; + int is_last, is_short; + + count = write_packet(ep, req, max); + usb_set(USB_IN_CSR1_IN_PKT_RDY, ep->csr1); + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = is_short = 1; + else { + if (likely(req->req.length != req->req.actual) + || req->req.zero) + is_last = 0; + else + is_last = 1; + /* interrupt/iso maxpacket may not fill the fifo */ + is_short = unlikely(max < ep_maxpacket(ep)); + } + + DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, + ep->ep.name, count, + is_last ? "/L" : "", is_short ? "/S" : "", + req->req.length - req->req.actual, req); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + if (list_empty(&ep->queue)) { + pio_irq_disable(ep_index(ep)); + } + return 1; + } + } else { + DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); + } + + return 0; +} + +/** Read to request from FIFO (max read == bytes in fifo) + * Return: 0 = still running, 1 = completed, negative = errno + * NOTE: INDEX register must be set for EP + */ +static int read_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 csr; + u8 *buf; + unsigned bufferspace, count, is_short; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + /* make sure there's a packet in the FIFO. */ + csr = usb_read(ep->csr1); + if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) { + DEBUG("%s: Packet NOT ready!\n", __FUNCTION__); + return -EINVAL; + } + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + bufferspace = req->req.length - req->req.actual; + + /* read all bytes from this packet */ + count = usb_read(USB_OUT_FIFO_WC1); + req->req.actual += min(count, bufferspace); + + is_short = (count < ep->ep.maxpacket); + DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", + ep->ep.name, csr, count, + is_short ? "/S" : "", req, req->req.actual, req->req.length); + + while (likely(count-- != 0)) { + u8 byte = (u8) (*fifo & 0xff); + + if (unlikely(bufferspace == 0)) { + /* this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + printk("%s overflow %d\n", ep->ep.name, count); + req->req.status = -EOVERFLOW; + } else { + *buf++ = byte; + bufferspace--; + } + } + + usb_clear(USB_OUT_CSR1_OUT_PKT_RDY, ep->csr1); + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); + + if (list_empty(&ep->queue)) + pio_irq_disable(ep_index(ep)); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +/* + * done - retire a request; caller blocked irqs + * INDEX register is preserved to keep same + */ +static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, int status) +{ + unsigned int stopped = ep->stopped; + u32 index; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + list_del_init(&req->queue); + + if (likely(req->req.status == -EINPROGRESS)) + req->req.status = status; + else + status = req->req.status; + + if (status && status != -ESHUTDOWN) + DEBUG("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + /* Read current index (completion may modify it) */ + index = usb_read(USB_INDEX); + + spin_unlock(&ep->dev->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&ep->dev->lock); + + /* Restore index */ + usb_set_index(index); + ep->stopped = stopped; +} + +/** Enable EP interrupt */ +static void pio_irq_enable(int ep) +{ + DEBUG("%s: %d\n", __FUNCTION__, ep); + + switch (ep) { + case 1: + usb_set(USB_IN_INT_EP1, USB_IN_INT_EN); + break; + case 2: + usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); + break; + case 3: + usb_set(USB_IN_INT_EP3, USB_IN_INT_EN); + break; + default: + DEBUG("Unknown endpoint: %d\n", ep); + break; + } +} + +/** Disable EP interrupt */ +static void pio_irq_disable(int ep) +{ + DEBUG("%s: %d\n", __FUNCTION__, ep); + + switch (ep) { + case 1: + usb_clear(USB_IN_INT_EP1, USB_IN_INT_EN); + break; + case 2: + usb_clear(USB_OUT_INT_EP2, USB_OUT_INT_EN); + break; + case 3: + usb_clear(USB_IN_INT_EP3, USB_IN_INT_EN); + break; + default: + DEBUG("Unknown endpoint: %d\n", ep); + break; + } +} + +/* + * nuke - dequeue ALL requests + */ +void nuke(struct lh7a40x_ep *ep, int status) +{ + struct lh7a40x_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + /* Flush FIFO */ + flush(ep); + + /* called with irqs blocked */ + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + done(ep, req, status); + } + + /* Disable IRQ if EP is enabled (has decriptor) */ + if (ep->desc) + pio_irq_disable(ep_index(ep)); +} + +/* +void nuke_all(struct lh7a40x_udc *dev) +{ + int n; + for(n=0; nep[n]; + usb_set_index(n); + nuke(ep, 0); + } +}*/ + +/* +static void flush_all(struct lh7a40x_udc *dev) +{ + int n; + for (n = 0; n < UDC_MAX_ENDPOINTS; n++) + { + struct lh7a40x_ep *ep = &dev->ep[n]; + flush(ep); + } +} +*/ + +/** Flush EP + * NOTE: INDEX register must be set before this call + */ +static void flush(struct lh7a40x_ep *ep) +{ + DEBUG("%s, %p\n", __FUNCTION__, ep); + + switch (ep->ep_type) { + case ep_control: + /* check, by implication c.f. 15.1.2.11 */ + break; + + case ep_bulk_in: + case ep_interrupt: + /* if(csr & USB_IN_CSR1_IN_PKT_RDY) */ + usb_set(USB_IN_CSR1_FIFO_FLUSH, ep->csr1); + break; + + case ep_bulk_out: + /* if(csr & USB_OUT_CSR1_OUT_PKT_RDY) */ + usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); + break; + } +} + +/** + * lh7a40x_in_epn - handle IN interrupt + */ +static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) +{ + u32 csr; + struct lh7a40x_ep *ep = &dev->ep[ep_idx]; + struct lh7a40x_request *req; + + usb_set_index(ep_idx); + + csr = usb_read(ep->csr1); + DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); + + if (csr & USB_IN_CSR1_SENT_STALL) { + DEBUG("USB_IN_CSR1_SENT_STALL\n"); + usb_set(USB_IN_CSR1_SENT_STALL /*|USB_IN_CSR1_SEND_STALL */ , + ep->csr1); + return; + } + + if (!ep->desc) { + DEBUG("%s: NO EP DESC\n", __FUNCTION__); + return; + } + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + + DEBUG("req: %p\n", req); + + if (!req) + return; + + write_fifo(ep, req); +} + +/* ********************************************************************************************* */ +/* Bulk OUT (recv) + */ + +static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) +{ + struct lh7a40x_ep *ep = &dev->ep[ep_idx]; + struct lh7a40x_request *req; + + DEBUG("%s: %d\n", __FUNCTION__, ep_idx); + + usb_set_index(ep_idx); + + if (ep->desc) { + u32 csr; + csr = usb_read(ep->csr1); + + while ((csr = + usb_read(ep-> + csr1)) & (USB_OUT_CSR1_OUT_PKT_RDY | + USB_OUT_CSR1_SENT_STALL)) { + DEBUG("%s: %x\n", __FUNCTION__, csr); + + if (csr & USB_OUT_CSR1_SENT_STALL) { + DEBUG("%s: stall sent, flush fifo\n", + __FUNCTION__); + /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ + flush(ep); + } else if (csr & USB_OUT_CSR1_OUT_PKT_RDY) { + if (list_empty(&ep->queue)) + req = 0; + else + req = + list_entry(ep->queue.next, + struct lh7a40x_request, + queue); + + if (!req) { + printk("%s: NULL REQ %d\n", + __FUNCTION__, ep_idx); + flush(ep); + break; + } else { + read_fifo(ep, req); + } + } + + } + + } else { + /* Throw packet away.. */ + printk("%s: No descriptor?!?\n", __FUNCTION__); + flush(ep); + } +} + +static void stop_activity(struct lh7a40x_udc *dev, + struct usb_gadget_driver *driver) +{ + int i; + + /* don't disconnect drivers more than once */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = 0; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { + struct lh7a40x_ep *ep = &dev->ep[i]; + ep->stopped = 1; + + usb_set_index(i); + nuke(ep, -ESHUTDOWN); + } + + /* report disconnect; the driver is already quiesced */ + if (driver) { + spin_unlock(&dev->lock); + driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } + + /* re-init driver-visible data structures */ + udc_reinit(dev); +} + +/** Handle USB RESET interrupt + */ +static void lh7a40x_reset_intr(struct lh7a40x_udc *dev) +{ +#if 0 /* def CONFIG_ARCH_LH7A404 */ + /* Does not work always... */ + + DEBUG("%s: %d\n", __FUNCTION__, dev->usb_address); + + if (!dev->usb_address) { + /*usb_set(USB_RESET_IO, USB_RESET); + mdelay(5); + usb_clear(USB_RESET_IO, USB_RESET); */ + return; + } + /* Put the USB controller into reset. */ + usb_set(USB_RESET_IO, USB_RESET); + + /* Set Device ID to 0 */ + udc_set_address(dev, 0); + + /* Let PLL2 settle down */ + mdelay(5); + + /* Release the USB controller from reset */ + usb_clear(USB_RESET_IO, USB_RESET); + + /* Re-enable UDC */ + udc_enable(dev); + +#endif + dev->gadget.speed = USB_SPEED_FULL; +} + +/* + * lh7a40x usb client interrupt handler. + */ +static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev, struct pt_regs *r) +{ + struct lh7a40x_udc *dev = _dev; + + DEBUG("\n\n"); + + spin_lock(&dev->lock); + + for (;;) { + u32 intr_in = usb_read(USB_IN_INT); + u32 intr_out = usb_read(USB_OUT_INT); + u32 intr_int = usb_read(USB_INT); + + /* Test also against enable bits.. (lh7a40x errata).. Sigh.. */ + u32 in_en = usb_read(USB_IN_INT_EN); + u32 out_en = usb_read(USB_OUT_INT_EN); + + if (!intr_out && !intr_in && !intr_int) + break; + + DEBUG("%s (on state %s)\n", __FUNCTION__, + state_names[dev->ep0state]); + DEBUG("intr_out = %x\n", intr_out); + DEBUG("intr_in = %x\n", intr_in); + DEBUG("intr_int = %x\n", intr_int); + + if (intr_in) { + usb_write(intr_in, USB_IN_INT); + + if ((intr_in & USB_IN_INT_EP1) + && (in_en & USB_IN_INT_EP1)) { + DEBUG("USB_IN_INT_EP1\n"); + lh7a40x_in_epn(dev, 1, intr_in); + } + if ((intr_in & USB_IN_INT_EP3) + && (in_en & USB_IN_INT_EP3)) { + DEBUG("USB_IN_INT_EP3\n"); + lh7a40x_in_epn(dev, 3, intr_in); + } + if (intr_in & USB_IN_INT_EP0) { + DEBUG("USB_IN_INT_EP0 (control)\n"); + lh7a40x_handle_ep0(dev, intr_in); + } + } + + if (intr_out) { + usb_write(intr_out, USB_OUT_INT); + + if ((intr_out & USB_OUT_INT_EP2) + && (out_en & USB_OUT_INT_EP2)) { + DEBUG("USB_OUT_INT_EP2\n"); + lh7a40x_out_epn(dev, 2, intr_out); + } + } + + if (intr_int) { + usb_write(intr_int, USB_INT); + + if (intr_int & USB_INT_RESET_INT) { + lh7a40x_reset_intr(dev); + } + + if (intr_int & USB_INT_RESUME_INT) { + DEBUG("USB resume\n"); + + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->resume + && is_usb_connected()) { + dev->driver->resume(&dev->gadget); + } + } + + if (intr_int & USB_INT_SUSPEND_INT) { + DEBUG("USB suspend%s\n", + is_usb_connected()? "" : "+disconnect"); + if (!is_usb_connected()) { + stop_activity(dev, dev->driver); + } else if (dev->gadget.speed != + USB_SPEED_UNKNOWN && dev->driver + && dev->driver->suspend) { + dev->driver->suspend(&dev->gadget); + } + } + + } + } + + spin_unlock(&dev->lock); + + return IRQ_HANDLED; +} + +static int lh7a40x_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct lh7a40x_ep *ep; + struct lh7a40x_udc *dev; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep || !desc || ep->desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress + || ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) { + DEBUG("%s, bad ep or descriptor\n", __FUNCTION__); + return -EINVAL; + } + + /* xfer types must match, except that interrupt ~= bulk */ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); + return -EINVAL; + } + + /* hardware _could_ do smaller, but driver doesn't */ + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep)) + || !desc->wMaxPacketSize) { + DEBUG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); + return -ERANGE; + } + + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + DEBUG("%s, bogus device state\n", __FUNCTION__); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&ep->dev->lock, flags); + + ep->stopped = 0; + ep->desc = desc; + ep->pio_irqs = 0; + ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + + /* Reset halt state (does flush) */ + lh7a40x_set_halt(_ep, 0); + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name); + return 0; +} + +/** Disable EP + * NOTE: Sets INDEX register + */ +static int lh7a40x_ep_disable(struct usb_ep *_ep) +{ + struct lh7a40x_ep *ep; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep || !ep->desc) { + DEBUG("%s, %s not enabled\n", __FUNCTION__, + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + spin_lock_irqsave(&ep->dev->lock, flags); + + usb_set_index(ep_index(ep)); + + /* Nuke all pending requests (does flush) */ + nuke(ep, -ESHUTDOWN); + + /* Disable ep IRQ */ + pio_irq_disable(ep_index(ep)); + + ep->desc = 0; + ep->stopped = 1; + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name); + return 0; +} + +static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, + int gfp_flags) +{ + struct lh7a40x_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + req = kmalloc(sizeof *req, gfp_flags); + if (!req) + return 0; + + memset(req, 0, sizeof *req); + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) +{ + struct lh7a40x_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + req = container_of(_req, struct lh7a40x_request, req); + WARN_ON(!list_empty(&req->queue)); + kfree(req); +} + +static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, + dma_addr_t * dma, int gfp_flags) +{ + char *retval; + + DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags); + + retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM)); + if (retval) + *dma = virt_to_bus(retval); + return retval; +} + +static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, + unsigned bytes) +{ + DEBUG("%s, %p\n", __FUNCTION__, ep); + kfree(buf); +} + +/** Queue one request + * Kickstart transfer if needed + * NOTE: Sets INDEX register + */ +static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, + int gfp_flags) +{ + struct lh7a40x_request *req; + struct lh7a40x_ep *ep; + struct lh7a40x_udc *dev; + unsigned long flags; + + DEBUG("\n\n\n%s, %p\n", __FUNCTION__, _ep); + + req = container_of(_req, struct lh7a40x_request, req); + if (unlikely + (!_req || !_req->complete || !_req->buf + || !list_empty(&req->queue))) { + DEBUG("%s, bad params\n", __FUNCTION__); + return -EINVAL; + } + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + + dev = ep->dev; + if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { + DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver); + return -ESHUTDOWN; + } + + DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, + _req->buf); + + spin_lock_irqsave(&dev->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* kickstart this i/o queue? */ + DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), + ep->stopped); + if (list_empty(&ep->queue) && likely(!ep->stopped)) { + u32 csr; + + if (unlikely(ep_index(ep) == 0)) { + /* EP0 */ + list_add_tail(&req->queue, &ep->queue); + lh7a40x_ep0_kick(dev, ep); + req = 0; + } else if (ep_is_in(ep)) { + /* EP1 & EP3 */ + usb_set_index(ep_index(ep)); + csr = usb_read(ep->csr1); + pio_irq_enable(ep_index(ep)); + if ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) == 0) { + if (write_fifo(ep, req) == 1) + req = 0; + } + } else { + /* EP2 */ + usb_set_index(ep_index(ep)); + csr = usb_read(ep->csr1); + pio_irq_enable(ep_index(ep)); + if (!(csr & USB_OUT_CSR1_FIFO_FULL)) { + if (read_fifo(ep, req) == 1) + req = 0; + } + } + } + + /* pio or dma irq handler advances the queue. */ + if (likely(req != 0)) + list_add_tail(&req->queue, &ep->queue); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* dequeue JUST ONE request */ +static int lh7a40x_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct lh7a40x_ep *ep; + struct lh7a40x_request *req; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep || ep->ep.name == ep0name) + return -EINVAL; + + spin_lock_irqsave(&ep->dev->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->dev->lock, flags); + return -EINVAL; + } + + done(ep, req, -ECONNRESET); + + spin_unlock_irqrestore(&ep->dev->lock, flags); + return 0; +} + +/** Halt specific EP + * Return 0 if success + * NOTE: Sets INDEX register to EP ! + */ +static int lh7a40x_set_halt(struct usb_ep *_ep, int value) +{ + struct lh7a40x_ep *ep; + unsigned long flags; + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + + usb_set_index(ep_index(ep)); + + DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value); + + spin_lock_irqsave(&ep->dev->lock, flags); + + if (ep_index(ep) == 0) { + /* EP0 */ + usb_set(EP0_SEND_STALL, ep->csr1); + } else if (ep_is_in(ep)) { + u32 csr = usb_read(ep->csr1); + if (value && ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) + || !list_empty(&ep->queue))) { + /* + * Attempts to halt IN endpoints will fail (returning -EAGAIN) + * if any transfer requests are still queued, or if the controller + * FIFO still holds bytes that the host hasn’t collected. + */ + spin_unlock_irqrestore(&ep->dev->lock, flags); + DEBUG + ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", + (csr & USB_IN_CSR1_FIFO_NOT_EMPTY), + !list_empty(&ep->queue)); + return -EAGAIN; + } + flush(ep); + if (value) + usb_set(USB_IN_CSR1_SEND_STALL, ep->csr1); + else { + usb_clear(USB_IN_CSR1_SEND_STALL, ep->csr1); + usb_set(USB_IN_CSR1_CLR_DATA_TOGGLE, ep->csr1); + } + + } else { + + flush(ep); + if (value) + usb_set(USB_OUT_CSR1_SEND_STALL, ep->csr1); + else { + usb_clear(USB_OUT_CSR1_SEND_STALL, ep->csr1); + usb_set(USB_OUT_CSR1_CLR_DATA_REG, ep->csr1); + } + } + + if (value) { + ep->stopped = 1; + } else { + ep->stopped = 0; + } + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); + + return 0; +} + +/** Return bytes in EP FIFO + * NOTE: Sets INDEX register to EP + */ +static int lh7a40x_fifo_status(struct usb_ep *_ep) +{ + u32 csr; + int count = 0; + struct lh7a40x_ep *ep; + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -ENODEV; + } + + DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep)); + + /* LPD can't report unclaimed bytes from IN fifos */ + if (ep_is_in(ep)) + return -EOPNOTSUPP; + + usb_set_index(ep_index(ep)); + + csr = usb_read(ep->csr1); + if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || + csr & USB_OUT_CSR1_OUT_PKT_RDY) { + count = usb_read(USB_OUT_FIFO_WC1); + } + + return count; +} + +/** Flush EP FIFO + * NOTE: Sets INDEX register to EP + */ +static void lh7a40x_fifo_flush(struct usb_ep *_ep) +{ + struct lh7a40x_ep *ep; + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return; + } + + usb_set_index(ep_index(ep)); + flush(ep); +} + +/****************************************************************/ +/* End Point 0 related functions */ +/****************************************************************/ + +/* return: 0 = still running, 1 = completed, negative = errno */ +static int write_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 max; + unsigned count; + int is_last; + + max = ep_maxpacket(ep); + + DEBUG_EP0("%s\n", __FUNCTION__); + + count = write_packet(ep, req, max); + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = 1; + else { + if (likely(req->req.length != req->req.actual) || req->req.zero) + is_last = 0; + else + is_last = 1; + } + + DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, + ep->ep.name, count, + is_last ? "/L" : "", req->req.length - req->req.actual, req); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + return 1; + } + + return 0; +} + +static __inline__ int lh7a40x_fifo_read(struct lh7a40x_ep *ep, + unsigned char *cp, int max) +{ + int bytes; + int count = usb_read(USB_OUT_FIFO_WC1); + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + if (count > max) + count = max; + bytes = count; + while (count--) + *cp++ = *fifo & 0xFF; + return bytes; +} + +static __inline__ void lh7a40x_fifo_write(struct lh7a40x_ep *ep, + unsigned char *cp, int count) +{ + volatile u32 *fifo = (volatile u32 *)ep->fifo; + DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count); + while (count--) + *fifo = *cp++; +} + +static int read_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 csr; + u8 *buf; + unsigned bufferspace, count, is_short; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + DEBUG_EP0("%s\n", __FUNCTION__); + + csr = usb_read(USB_EP0_CSR); + if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) + return 0; + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + bufferspace = req->req.length - req->req.actual; + + /* read all bytes from this packet */ + if (likely(csr & EP0_OUT_PKT_RDY)) { + count = usb_read(USB_OUT_FIFO_WC1); + req->req.actual += min(count, bufferspace); + } else /* zlp */ + count = 0; + + is_short = (count < ep->ep.maxpacket); + DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", + ep->ep.name, csr, count, + is_short ? "/S" : "", req, req->req.actual, req->req.length); + + while (likely(count-- != 0)) { + u8 byte = (u8) (*fifo & 0xff); + + if (unlikely(bufferspace == 0)) { + /* this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + DEBUG_EP0("%s overflow %d\n", ep->ep.name, + count); + req->req.status = -EOVERFLOW; + } else { + *buf++ = byte; + bufferspace--; + } + } + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +/** + * udc_set_address - set the USB address for this device + * @address: + * + * Called from control endpoint function after it decodes a set address setup packet. + */ +static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address) +{ + DEBUG_EP0("%s: %d\n", __FUNCTION__, address); + /* c.f. 15.1.2.2 Table 15-4 address will be used after DATA_END is set */ + dev->usb_address = address; + usb_set((address & USB_FA_FUNCTION_ADDR), USB_FA); + usb_set(USB_FA_ADDR_UPDATE | (address & USB_FA_FUNCTION_ADDR), USB_FA); + /* usb_read(USB_FA); */ +} + +/* + * DATA_STATE_RECV (OUT_PKT_RDY) + * - if error + * set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits + * - else + * set EP0_CLR_OUT bit + if last set EP0_DATA_END bit + */ +static void lh7a40x_ep0_out(struct lh7a40x_udc *dev, u32 csr) +{ + struct lh7a40x_request *req; + struct lh7a40x_ep *ep = &dev->ep[0]; + int ret; + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + + if (req) { + + if (req->req.length == 0) { + DEBUG_EP0("ZERO LENGTH OUT!\n"); + usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + return; + } + ret = read_fifo_ep0(ep, req); + if (ret) { + /* Done! */ + DEBUG_EP0("%s: finished, waiting for status\n", + __FUNCTION__); + + usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + } else { + /* Not done yet.. */ + DEBUG_EP0("%s: not finished\n", __FUNCTION__); + usb_set(EP0_CLR_OUT, USB_EP0_CSR); + } + } else { + DEBUG_EP0("NO REQ??!\n"); + } +} + +/* + * DATA_STATE_XMIT + */ +static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr) +{ + struct lh7a40x_request *req; + struct lh7a40x_ep *ep = &dev->ep[0]; + int ret, need_zlp = 0; + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + + if (!req) { + DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); + return 0; + } + + if (req->req.length == 0) { + + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + return 1; + } + + if (req->req.length - req->req.actual == EP0_PACKETSIZE) { + /* Next write will end with the packet size, */ + /* so we need Zero-length-packet */ + need_zlp = 1; + } + + ret = write_fifo_ep0(ep, req); + + if (ret == 1 && !need_zlp) { + /* Last packet */ + DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__); + + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + } else { + DEBUG_EP0("%s: not finished\n", __FUNCTION__); + usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR); + } + + if (need_zlp) { + DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__); + usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR); + dev->ep0state = DATA_STATE_NEED_ZLP; + } + + return 1; +} + +static int lh7a40x_handle_get_status(struct lh7a40x_udc *dev, + struct usb_ctrlrequest *ctrl) +{ + struct lh7a40x_ep *ep0 = &dev->ep[0]; + struct lh7a40x_ep *qep; + int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); + u16 val = 0; + + if (reqtype == USB_RECIP_INTERFACE) { + /* This is not supported. + * And according to the USB spec, this one does nothing.. + * Just return 0 + */ + DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); + } else if (reqtype == USB_RECIP_DEVICE) { + DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); + val |= (1 << 0); /* Self powered */ + /*val |= (1<<1); *//* Remote wakeup */ + } else if (reqtype == USB_RECIP_ENDPOINT) { + int ep_num = (ctrl->wIndex & ~USB_DIR_IN); + + DEBUG_SETUP + ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", + ep_num, ctrl->wLength); + + if (ctrl->wLength > 2 || ep_num > 3) + return -EOPNOTSUPP; + + qep = &dev->ep[ep_num]; + if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) + && ep_index(qep) != 0) { + return -EOPNOTSUPP; + } + + usb_set_index(ep_index(qep)); + + /* Return status on next IN token */ + switch (qep->ep_type) { + case ep_control: + val = + (usb_read(qep->csr1) & EP0_SEND_STALL) == + EP0_SEND_STALL; + break; + case ep_bulk_in: + case ep_interrupt: + val = + (usb_read(qep->csr1) & USB_IN_CSR1_SEND_STALL) == + USB_IN_CSR1_SEND_STALL; + break; + case ep_bulk_out: + val = + (usb_read(qep->csr1) & USB_OUT_CSR1_SEND_STALL) == + USB_OUT_CSR1_SEND_STALL; + break; + } + + /* Back to EP0 index */ + usb_set_index(0); + + DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, + ctrl->wIndex, val); + } else { + DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); + return -EOPNOTSUPP; + } + + /* Clear "out packet ready" */ + usb_set((EP0_CLR_OUT), USB_EP0_CSR); + /* Put status to FIFO */ + lh7a40x_fifo_write(ep0, (u8 *) & val, sizeof(val)); + /* Issue "In packet ready" */ + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + + return 0; +} + +/* + * WAIT_FOR_SETUP (OUT_PKT_RDY) + * - read data packet from EP0 FIFO + * - decode command + * - if error + * set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits + * - else + * set EP0_CLR_OUT | EP0_DATA_END bits + */ +static void lh7a40x_ep0_setup(struct lh7a40x_udc *dev, u32 csr) +{ + struct lh7a40x_ep *ep = &dev->ep[0]; + struct usb_ctrlrequest ctrl; + int i, bytes, is_in; + + DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr); + + /* Nuke all previous transfers */ + nuke(ep, -EPROTO); + + /* read control req from fifo (8 bytes) */ + bytes = lh7a40x_fifo_read(ep, (unsigned char *)&ctrl, 8); + + DEBUG_SETUP("Read CTRL REQ %d bytes\n", bytes); + DEBUG_SETUP("CTRL.bRequestType = %d (is_in %d)\n", ctrl.bRequestType, + ctrl.bRequestType == USB_DIR_IN); + DEBUG_SETUP("CTRL.bRequest = %d\n", ctrl.bRequest); + DEBUG_SETUP("CTRL.wLength = %d\n", ctrl.wLength); + DEBUG_SETUP("CTRL.wValue = %d (%d)\n", ctrl.wValue, ctrl.wValue >> 8); + DEBUG_SETUP("CTRL.wIndex = %d\n", ctrl.wIndex); + + /* Set direction of EP0 */ + if (likely(ctrl.bRequestType & USB_DIR_IN)) { + ep->bEndpointAddress |= USB_DIR_IN; + is_in = 1; + } else { + ep->bEndpointAddress &= ~USB_DIR_IN; + is_in = 0; + } + + dev->req_pending = 1; + + /* Handle some SETUP packets ourselves */ + switch (ctrl.bRequest) { + case USB_REQ_SET_ADDRESS: + if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + + DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); + udc_set_address(dev, ctrl.wValue); + usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); + return; + + case USB_REQ_GET_STATUS:{ + if (lh7a40x_handle_get_status(dev, &ctrl) == 0) + return; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { + struct lh7a40x_ep *qep; + int ep_num = (ctrl.wIndex & 0x0f); + + /* Support only HALT feature */ + if (ctrl.wValue != 0 || ctrl.wLength != 0 + || ep_num > 3 || ep_num < 1) + break; + + qep = &dev->ep[ep_num]; + if (ctrl.bRequest == USB_REQ_SET_FEATURE) { + DEBUG_SETUP("SET_FEATURE (%d)\n", + ep_num); + lh7a40x_set_halt(&qep->ep, 1); + } else { + DEBUG_SETUP("CLR_FEATURE (%d)\n", + ep_num); + lh7a40x_set_halt(&qep->ep, 0); + } + usb_set_index(0); + + /* Reply with a ZLP on next IN token */ + usb_set((EP0_CLR_OUT | EP0_DATA_END), + USB_EP0_CSR); + return; + } + break; + } + + default: + break; + } + + if (likely(dev->driver)) { + /* device-2-host (IN) or no data setup command, process immediately */ + spin_unlock(&dev->lock); + i = dev->driver->setup(&dev->gadget, &ctrl); + spin_lock(&dev->lock); + + if (i < 0) { + /* setup processing failed, force stall */ + DEBUG_SETUP + (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", + i); + usb_set_index(0); + usb_set((EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL), + USB_EP0_CSR); + + /* ep->stopped = 1; */ + dev->ep0state = WAIT_FOR_SETUP; + } + } +} + +/* + * DATA_STATE_NEED_ZLP + */ +static void lh7a40x_ep0_in_zlp(struct lh7a40x_udc *dev, u32 csr) +{ + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + /* c.f. Table 15-14 */ + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; +} + +/* + * handle ep0 interrupt + */ +static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr) +{ + struct lh7a40x_ep *ep = &dev->ep[0]; + u32 csr; + + /* Set index 0 */ + usb_set_index(0); + csr = usb_read(USB_EP0_CSR); + + DEBUG_EP0("%s: csr = %x\n", __FUNCTION__, csr); + + /* + * For overview of what we should be doing see c.f. Chapter 18.1.2.4 + * We will follow that outline here modified by our own global state + * indication which provides hints as to what we think should be + * happening.. + */ + + /* + * if SENT_STALL is set + * - clear the SENT_STALL bit + */ + if (csr & EP0_SENT_STALL) { + DEBUG_EP0("%s: EP0_SENT_STALL is set: %x\n", __FUNCTION__, csr); + usb_clear((EP0_SENT_STALL | EP0_SEND_STALL), USB_EP0_CSR); + nuke(ep, -ECONNABORTED); + dev->ep0state = WAIT_FOR_SETUP; + return; + } + + /* + * if a transfer is in progress && IN_PKT_RDY and OUT_PKT_RDY are clear + * - fill EP0 FIFO + * - if last packet + * - set IN_PKT_RDY | DATA_END + * - else + * set IN_PKT_RDY + */ + if (!(csr & (EP0_IN_PKT_RDY | EP0_OUT_PKT_RDY))) { + DEBUG_EP0("%s: IN_PKT_RDY and OUT_PKT_RDY are clear\n", + __FUNCTION__); + + switch (dev->ep0state) { + case DATA_STATE_XMIT: + DEBUG_EP0("continue with DATA_STATE_XMIT\n"); + lh7a40x_ep0_in(dev, csr); + return; + case DATA_STATE_NEED_ZLP: + DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); + lh7a40x_ep0_in_zlp(dev, csr); + return; + default: + /* Stall? */ + DEBUG_EP0("Odd state!! state = %s\n", + state_names[dev->ep0state]); + dev->ep0state = WAIT_FOR_SETUP; + /* nuke(ep, 0); */ + /* usb_set(EP0_SEND_STALL, ep->csr1); */ + break; + } + } + + /* + * if SETUP_END is set + * - abort the last transfer + * - set SERVICED_SETUP_END_BIT + */ + if (csr & EP0_SETUP_END) { + DEBUG_EP0("%s: EP0_SETUP_END is set: %x\n", __FUNCTION__, csr); + + usb_set(EP0_CLR_SETUP_END, USB_EP0_CSR); + + nuke(ep, 0); + dev->ep0state = WAIT_FOR_SETUP; + } + + /* + * if EP0_OUT_PKT_RDY is set + * - read data packet from EP0 FIFO + * - decode command + * - if error + * set SERVICED_OUT_PKT_RDY | DATA_END bits | SEND_STALL + * - else + * set SERVICED_OUT_PKT_RDY | DATA_END bits + */ + if (csr & EP0_OUT_PKT_RDY) { + + DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, + csr); + + switch (dev->ep0state) { + case WAIT_FOR_SETUP: + DEBUG_EP0("WAIT_FOR_SETUP\n"); + lh7a40x_ep0_setup(dev, csr); + break; + + case DATA_STATE_RECV: + DEBUG_EP0("DATA_STATE_RECV\n"); + lh7a40x_ep0_out(dev, csr); + break; + + default: + /* send stall? */ + DEBUG_EP0("strange state!! 2. send stall? state = %d\n", + dev->ep0state); + break; + } + } +} + +static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep) +{ + u32 csr; + + usb_set_index(0); + csr = usb_read(USB_EP0_CSR); + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + /* Clear "out packet ready" */ + usb_set(EP0_CLR_OUT, USB_EP0_CSR); + + if (ep_is_in(ep)) { + dev->ep0state = DATA_STATE_XMIT; + lh7a40x_ep0_in(dev, csr); + } else { + dev->ep0state = DATA_STATE_RECV; + lh7a40x_ep0_out(dev, csr); + } +} + +/* --------------------------------------------------------------------------- + * device-scoped parts of the api to the usb controller hardware + * --------------------------------------------------------------------------- + */ + +static int lh7a40x_udc_get_frame(struct usb_gadget *_gadget) +{ + u32 frame1 = usb_read(USB_FRM_NUM1); /* Least significant 8 bits */ + u32 frame2 = usb_read(USB_FRM_NUM2); /* Most significant 3 bits */ + DEBUG("%s, %p\n", __FUNCTION__, _gadget); + return ((frame2 & 0x07) << 8) | (frame1 & 0xff); +} + +static int lh7a40x_udc_wakeup(struct usb_gadget *_gadget) +{ + /* host may not have enabled remote wakeup */ + /*if ((UDCCS0 & UDCCS0_DRWF) == 0) + return -EHOSTUNREACH; + udc_set_mask_UDCCR(UDCCR_RSM); */ + return -ENOTSUPP; +} + +static const struct usb_gadget_ops lh7a40x_udc_ops = { + .get_frame = lh7a40x_udc_get_frame, + .wakeup = lh7a40x_udc_wakeup, + /* current versions must always be self-powered */ +}; + +static void nop_release(struct device *dev) +{ + DEBUG("%s %s\n", __FUNCTION__, dev->bus_id); +} + +static struct lh7a40x_udc memory = { + .usb_address = 0, + + .gadget = { + .ops = &lh7a40x_udc_ops, + .ep0 = &memory.ep[0].ep, + .name = driver_name, + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + /* control endpoint */ + .ep[0] = { + .ep = { + .name = ep0name, + .ops = &lh7a40x_ep_ops, + .maxpacket = EP0_PACKETSIZE, + }, + .dev = &memory, + + .bEndpointAddress = 0, + .bmAttributes = 0, + + .ep_type = ep_control, + .fifo = io_p2v(USB_EP0_FIFO), + .csr1 = USB_EP0_CSR, + .csr2 = USB_EP0_CSR, + }, + + /* first group of endpoints */ + .ep[1] = { + .ep = { + .name = "ep1in-bulk", + .ops = &lh7a40x_ep_ops, + .maxpacket = 64, + }, + .dev = &memory, + + .bEndpointAddress = USB_DIR_IN | 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + + .ep_type = ep_bulk_in, + .fifo = io_p2v(USB_EP1_FIFO), + .csr1 = USB_IN_CSR1, + .csr2 = USB_IN_CSR2, + }, + + .ep[2] = { + .ep = { + .name = "ep2out-bulk", + .ops = &lh7a40x_ep_ops, + .maxpacket = 64, + }, + .dev = &memory, + + .bEndpointAddress = 2, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + + .ep_type = ep_bulk_out, + .fifo = io_p2v(USB_EP2_FIFO), + .csr1 = USB_OUT_CSR1, + .csr2 = USB_OUT_CSR2, + }, + + .ep[3] = { + .ep = { + .name = "ep3in-int", + .ops = &lh7a40x_ep_ops, + .maxpacket = 64, + }, + .dev = &memory, + + .bEndpointAddress = USB_DIR_IN | 3, + .bmAttributes = USB_ENDPOINT_XFER_INT, + + .ep_type = ep_interrupt, + .fifo = io_p2v(USB_EP3_FIFO), + .csr1 = USB_IN_CSR1, + .csr2 = USB_IN_CSR2, + }, +}; + +/* + * probe - binds to the platform device + */ +static int lh7a40x_udc_probe(struct device *_dev) +{ + struct lh7a40x_udc *dev = &memory; + int retval; + + DEBUG("%s: %p\n", __FUNCTION__, _dev); + + spin_lock_init(&dev->lock); + dev->dev = _dev; + + device_initialize(&dev->gadget.dev); + dev->gadget.dev.parent = _dev; + + the_controller = dev; + dev_set_drvdata(_dev, dev); + + udc_disable(dev); + udc_reinit(dev); + + /* irq setup after old hardware state is cleaned up */ + retval = + request_irq(IRQ_USBINTR, lh7a40x_udc_irq, SA_INTERRUPT, driver_name, + dev); + if (retval != 0) { + DEBUG(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, + IRQ_USBINTR, retval); + return -EBUSY; + } + + create_proc_files(); + + return retval; +} + +static int lh7a40x_udc_remove(struct device *_dev) +{ + struct lh7a40x_udc *dev = _dev->driver_data; + + DEBUG("%s: %p\n", __FUNCTION__, dev); + + udc_disable(dev); + remove_proc_files(); + usb_gadget_unregister_driver(dev->driver); + + free_irq(IRQ_USBINTR, dev); + + dev_set_drvdata(_dev, 0); + + the_controller = 0; + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct device_driver udc_driver = { + .name = (char *)driver_name, + .bus = &platform_bus_type, + .probe = lh7a40x_udc_probe, + .remove = lh7a40x_udc_remove + /* FIXME power management support */ + /* .suspend = ... disable UDC */ + /* .resume = ... re-enable UDC */ +}; + +static int __init udc_init(void) +{ + DEBUG("%s: %s version %s\n", __FUNCTION__, driver_name, DRIVER_VERSION); + return driver_register(&udc_driver); +} + +static void __exit udc_exit(void) +{ + driver_unregister(&udc_driver); +} + +module_init(udc_init); +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Mikko Lahteenmaki, Bo Henriksen"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/gadget/lh7a40x_udc.h 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,261 @@ +/* + * linux/drivers/usb/gadget/lh7a40x_udc.h + * Sharp LH7A40x on-chip full speed USB device controllers + * + * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID + * Copyright (C) 2004 Bo Henriksen, Nordic ID + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __LH7A40X_H_ +#define __LH7A40X_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Memory map + */ + +#define USB_FA 0x80000200 // function address register +#define USB_PM 0x80000204 // power management register + +#define USB_IN_INT 0x80000208 // IN interrupt register bank (EP0-EP3) +#define USB_OUT_INT 0x80000210 // OUT interrupt register bank (EP2) +#define USB_INT 0x80000218 // interrupt register bank + +#define USB_IN_INT_EN 0x8000021C // IN interrupt enable register bank +#define USB_OUT_INT_EN 0x80000224 // OUT interrupt enable register bank +#define USB_INT_EN 0x8000022C // USB interrupt enable register bank + +#define USB_FRM_NUM1 0x80000230 // Frame number1 register +#define USB_FRM_NUM2 0x80000234 // Frame number2 register +#define USB_INDEX 0x80000238 // index register + +#define USB_IN_MAXP 0x80000240 // IN MAXP register +#define USB_IN_CSR1 0x80000244 // IN CSR1 register/EP0 CSR register +#define USB_EP0_CSR 0x80000244 // IN CSR1 register/EP0 CSR register +#define USB_IN_CSR2 0x80000248 // IN CSR2 register +#define USB_OUT_MAXP 0x8000024C // OUT MAXP register + +#define USB_OUT_CSR1 0x80000250 // OUT CSR1 register +#define USB_OUT_CSR2 0x80000254 // OUT CSR2 register +#define USB_OUT_FIFO_WC1 0x80000258 // OUT FIFO write count1 register +#define USB_OUT_FIFO_WC2 0x8000025C // OUT FIFO write count2 register + +#define USB_RESET 0x8000044C // USB reset register + +#define USB_EP0_FIFO 0x80000280 +#define USB_EP1_FIFO 0x80000284 +#define USB_EP2_FIFO 0x80000288 +#define USB_EP3_FIFO 0x8000028c + +/* + * USB reset register + */ +#define USB_RESET_APB (1<<1) //resets USB APB control side WRITE +#define USB_RESET_IO (1<<0) //resets USB IO side WRITE + +/* + * USB function address register + */ +#define USB_FA_ADDR_UPDATE (1<<7) +#define USB_FA_FUNCTION_ADDR (0x7F) + +/* + * Power Management register + */ +#define PM_USB_DCP (1<<5) +#define PM_USB_ENABLE (1<<4) +#define PM_USB_RESET (1<<3) +#define PM_UC_RESUME (1<<2) +#define PM_SUSPEND_MODE (1<<1) +#define PM_ENABLE_SUSPEND (1<<0) + +/* + * IN interrupt register + */ +#define USB_IN_INT_EP3 (1<<3) +#define USB_IN_INT_EP1 (1<<1) +#define USB_IN_INT_EP0 (1<<0) + +/* + * OUT interrupt register + */ +#define USB_OUT_INT_EP2 (1<<2) + +/* + * USB interrupt register + */ +#define USB_INT_RESET_INT (1<<2) +#define USB_INT_RESUME_INT (1<<1) +#define USB_INT_SUSPEND_INT (1<<0) + +/* + * USB interrupt enable register + */ +#define USB_INT_EN_USB_RESET_INTER (1<<2) +#define USB_INT_EN_RESUME_INTER (1<<1) +#define USB_INT_EN_SUSPEND_INTER (1<<0) + +/* + * INCSR1 register + */ +#define USB_IN_CSR1_CLR_DATA_TOGGLE (1<<6) +#define USB_IN_CSR1_SENT_STALL (1<<5) +#define USB_IN_CSR1_SEND_STALL (1<<4) +#define USB_IN_CSR1_FIFO_FLUSH (1<<3) +#define USB_IN_CSR1_FIFO_NOT_EMPTY (1<<1) +#define USB_IN_CSR1_IN_PKT_RDY (1<<0) + +/* + * INCSR2 register + */ +#define USB_IN_CSR2_AUTO_SET (1<<7) +#define USB_IN_CSR2_USB_DMA_EN (1<<4) + +/* + * OUT CSR1 register + */ +#define USB_OUT_CSR1_CLR_DATA_REG (1<<7) +#define USB_OUT_CSR1_SENT_STALL (1<<6) +#define USB_OUT_CSR1_SEND_STALL (1<<5) +#define USB_OUT_CSR1_FIFO_FLUSH (1<<4) +#define USB_OUT_CSR1_FIFO_FULL (1<<1) +#define USB_OUT_CSR1_OUT_PKT_RDY (1<<0) + +/* + * OUT CSR2 register + */ +#define USB_OUT_CSR2_AUTO_CLR (1<<7) +#define USB_OUT_CSR2_USB_DMA_EN (1<<4) + +/* + * EP0 CSR + */ +#define EP0_CLR_SETUP_END (1<<7) /* Clear "Setup Ends" Bit (w) */ +#define EP0_CLR_OUT (1<<6) /* Clear "Out packet ready" Bit (w) */ +#define EP0_SEND_STALL (1<<5) /* Send STALL Handshake (rw) */ +#define EP0_SETUP_END (1<<4) /* Setup Ends (r) */ + +#define EP0_DATA_END (1<<3) /* Data end (rw) */ +#define EP0_SENT_STALL (1<<2) /* Sent Stall Handshake (r) */ +#define EP0_IN_PKT_RDY (1<<1) /* In packet ready (rw) */ +#define EP0_OUT_PKT_RDY (1<<0) /* Out packet ready (r) */ + +/* general CSR */ +#define OUT_PKT_RDY (1<<0) +#define IN_PKT_RDY (1<<0) + +/* + * IN/OUT MAXP register + */ +#define USB_OUT_MAXP_MAXP (0xF) +#define USB_IN_MAXP_MAXP (0xF) + +// Max packet size +//#define EP0_PACKETSIZE 0x10 +#define EP0_PACKETSIZE 0x8 +#define EP0_MAXPACKETSIZE 0x10 + +#define UDC_MAX_ENDPOINTS 4 + +#define WAIT_FOR_SETUP 0 +#define DATA_STATE_XMIT 1 +#define DATA_STATE_NEED_ZLP 2 +#define WAIT_FOR_OUT_STATUS 3 +#define DATA_STATE_RECV 4 + +/* ********************************************************************************************* */ +/* IO + */ + +typedef enum ep_type { + ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt +} ep_type_t; + +struct lh7a40x_ep { + struct usb_ep ep; + struct lh7a40x_udc *dev; + + const struct usb_endpoint_descriptor *desc; + struct list_head queue; + unsigned long pio_irqs; + + u8 stopped; + u8 bEndpointAddress; + u8 bmAttributes; + + ep_type_t ep_type; + u32 fifo; + u32 csr1; + u32 csr2; +}; + +struct lh7a40x_request { + struct usb_request req; + struct list_head queue; +}; + +struct lh7a40x_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct device *dev; + spinlock_t lock; + + int ep0state; + struct lh7a40x_ep ep[UDC_MAX_ENDPOINTS]; + + unsigned char usb_address; + + unsigned req_pending:1, req_std:1, req_config:1; +}; + +extern struct lh7a40x_udc *the_controller; + +#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN) +#define ep_index(EP) ((EP)->bEndpointAddress&0xF) +#define ep_maxpacket(EP) ((EP)->ep.maxpacket) + +#endif diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/gadget/net2280.c 2004-10-18 14:55:54 -07:00 @@ -7,13 +7,9 @@ * * CODE STATUS HIGHLIGHTS * - * Used with a gadget driver like "zero.c" this enumerates fine to Windows - * or Linux hosts; handles disconnect, reconnect, and reset, for full or - * high speed operation; and passes USB-IF "chapter 9" tests. - * - * Handles standard stress loads from the Linux "usbtest" driver, with - * either DMA (default) or PIO (use_dma=n) used for ep-{a,b,c,d}. Testing - * with "ttcp" (and the "ether.c" driver) behaves nicely too. + * This driver should work well with most "gadget" drivers, including + * the File Storage, Serial, and Ethernet/RNDIS gadget drivers + * as well as Gadget Zero and Gadgetfs. * * DMA is enabled by default. Drivers using transfer queues might use * DMA chaining to remove IRQ latencies between transfers. (Except when @@ -257,7 +253,7 @@ return 0; } -static int handshake (u32 *ptr, u32 mask, u32 done, int usec) +static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -276,7 +272,7 @@ static struct usb_ep_ops net2280_ep_ops; -static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep) +static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) { u32 tmp; @@ -307,14 +303,16 @@ /* init to our chosen defaults, notably so that we NAK OUT * packets until the driver queues a read (+note erratum 0112) */ - writel ( (1 << SET_NAK_OUT_PACKETS_MODE) + tmp = (1 << SET_NAK_OUT_PACKETS_MODE) | (1 << SET_NAK_OUT_PACKETS) | (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_INTERRUPT_MODE) - | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - | (1 << CLEAR_ENDPOINT_TOGGLE) - | (1 << CLEAR_ENDPOINT_HALT) - , &ep->regs->ep_rsp); + | (1 << CLEAR_INTERRUPT_MODE); + + if (ep->num != 0) { + tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) + | (1 << CLEAR_ENDPOINT_HALT); + } + writel (tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ writel ( (1 << TIMEOUT) @@ -517,7 +515,7 @@ static void write_fifo (struct net2280_ep *ep, struct usb_request *req) { - struct net2280_ep_regs *regs = ep->regs; + struct net2280_ep_regs __iomem *regs = ep->regs; u8 *buf; u32 tmp; unsigned count, total; @@ -577,7 +575,8 @@ */ static void out_flush (struct net2280_ep *ep) { - u32 *statp, tmp; + u32 __iomem *statp; + u32 tmp; ASSERT_OUT_NAKING (ep); @@ -610,7 +609,7 @@ static int read_fifo (struct net2280_ep *ep, struct net2280_request *req) { - struct net2280_ep_regs *regs = ep->regs; + struct net2280_ep_regs __iomem *regs = ep->regs; u8 *buf = req->req.buf + req->req.actual; unsigned count, tmp, is_short; unsigned cleanup = 0, prevent = 0; @@ -678,7 +677,7 @@ } if (count) { tmp = readl (®s->ep_data); - cpu_to_le32s (&tmp); + /* LE conversion is implicit here: */ do { *buf++ = (u8) tmp; tmp >>= 8; @@ -737,12 +736,12 @@ /* erratum 0116 workaround part 2 (no AUTOSTART) */ | (1 << DMA_ENABLE); -static inline void spin_stop_dma (struct net2280_dma_regs *dma) +static inline void spin_stop_dma (struct net2280_dma_regs __iomem *dma) { handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50); } -static inline void stop_dma (struct net2280_dma_regs *dma) +static inline void stop_dma (struct net2280_dma_regs __iomem *dma) { writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl); spin_stop_dma (dma); @@ -750,7 +749,7 @@ static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) { - struct net2280_dma_regs *dma = ep->dma; + struct net2280_dma_regs __iomem *dma = ep->dma; writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION), &dma->dmacount); @@ -771,7 +770,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) { u32 tmp; - struct net2280_dma_regs *dma = ep->dma; + struct net2280_dma_regs __iomem *dma = ep->dma; /* FIXME can't use DMA for ZLPs */ @@ -1419,10 +1418,34 @@ return 0; } +static int net2280_pullup(struct usb_gadget *_gadget, int is_on) +{ + struct net2280 *dev; + u32 tmp; + unsigned long flags; + + if (!_gadget) + return -ENODEV; + dev = container_of (_gadget, struct net2280, gadget); + + spin_lock_irqsave (&dev->lock, flags); + tmp = readl (&dev->usb->usbctl); + dev->softconnect = (is_on != 0); + if (is_on) + tmp |= (1 << USB_DETECT_ENABLE); + else + tmp &= ~(1 << USB_DETECT_ENABLE); + writel (tmp, &dev->usb->usbctl); + spin_unlock_irqrestore (&dev->lock, flags); + + return 0; +} + static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, .wakeup = net2280_wakeup, .set_selfpowered = net2280_set_selfpowered, + .pullup = net2280_pullup, }; /*-------------------------------------------------------------------------*/ @@ -1807,8 +1830,6 @@ { u32 tmp; - /* force immediate bus disconnect, and synch through pci */ - writel (0, &dev->usb->usbctl); dev->gadget.speed = USB_SPEED_UNKNOWN; (void) readl (&dev->usb->usbctl); @@ -1902,10 +1923,8 @@ , &dev->usb->stdrsp); writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE) | (1 << SELF_POWERED_USB_DEVICE) - /* erratum 0102 workaround */ - | ((dev->chiprev == 0100) ? 0 : 1) << SUSPEND_IMMEDIATELY | (1 << REMOTE_WAKEUP_SUPPORT) - | (1 << USB_DETECT_ENABLE) + | (dev->softconnect << USB_DETECT_ENABLE) | (1 << SELF_POWERED_STATUS) , &dev->usb->usbctl); @@ -1957,6 +1976,7 @@ dev->ep [i].irqs = 0; /* hook up the driver ... */ + dev->softconnect = 1; driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; @@ -2028,6 +2048,8 @@ stop_activity (dev, driver); spin_unlock_irqrestore (&dev->lock, flags); + net2280_pullup (&dev->gadget, 0); + driver->unbind (&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -2492,15 +2514,23 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) { struct net2280_ep *ep; - u32 tmp, num, scratch; + u32 tmp, num, mask, scratch; /* after disconnect there's nothing else to do! */ tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); + mask = (1 << HIGH_SPEED) | (1 << FULL_SPEED); + + /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set. + * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and + * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT + * only indicates a change in the reset state). + */ if (stat & tmp) { writel (tmp, &dev->regs->irqstat1); - if (((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) != 0 - || (readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0 - ) && dev->gadget.speed != USB_SPEED_UNKNOWN) { + if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && + ((readl (&dev->usb->usbstat) & mask) == 0)) + || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0) + ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) { DEBUG (dev, "disconnect %s\n", dev->driver->driver.name); stop_activity (dev, dev->driver); @@ -2525,8 +2555,6 @@ if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) dev->driver->suspend (&dev->gadget); - /* we use SUSPEND_IMMEDIATELY */ - stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); } else { if (dev->driver->resume) dev->driver->resume (&dev->gadget); @@ -2553,7 +2581,7 @@ stat &= ~DMA_INTERRUPTS; scratch >>= 9; for (num = 0; scratch; num++) { - struct net2280_dma_regs *dma; + struct net2280_dma_regs __iomem *dma; tmp = 1 << num; if ((tmp & scratch) == 0) @@ -2722,7 +2750,7 @@ { struct net2280 *dev; unsigned long resource, len; - void *base = NULL; + void __iomem *base = NULL; int retval, i; char buf [8], *bufp; @@ -2780,14 +2808,15 @@ retval = -EFAULT; goto done; } - dev->regs = (struct net2280_regs *) base; - dev->usb = (struct net2280_usb_regs *) (base + 0x0080); - dev->pci = (struct net2280_pci_regs *) (base + 0x0100); - dev->dma = (struct net2280_dma_regs *) (base + 0x0180); - dev->dep = (struct net2280_dep_regs *) (base + 0x0200); - dev->epregs = (struct net2280_ep_regs *) (base + 0x0300); + dev->regs = (struct net2280_regs __iomem *) base; + dev->usb = (struct net2280_usb_regs __iomem *) (base + 0x0080); + dev->pci = (struct net2280_pci_regs __iomem *) (base + 0x0100); + dev->dma = (struct net2280_dma_regs __iomem *) (base + 0x0180); + dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200); + dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300); /* put into initial config, link up all endpoints */ + writel (0, &dev->usb->usbctl); usb_reset (dev); usb_reinit (dev); diff -Nru a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h --- a/drivers/usb/gadget/net2280.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/gadget/net2280.h 2004-10-18 14:56:49 -07:00 @@ -446,7 +446,7 @@ */ static inline u32 -get_idx_reg (struct net2280_regs *regs, u32 index) +get_idx_reg (struct net2280_regs __iomem *regs, u32 index) { writel (index, ®s->idxaddr); /* NOTE: synchs device/cpu memory views */ @@ -454,7 +454,7 @@ } static inline void -set_idx_reg (struct net2280_regs *regs, u32 index, u32 value) +set_idx_reg (struct net2280_regs __iomem *regs, u32 index, u32 value) { writel (index, ®s->idxaddr); writel (value, ®s->idxdata); @@ -507,8 +507,8 @@ struct net2280_ep { struct usb_ep ep; - struct net2280_ep_regs *regs; - struct net2280_dma_regs *dma; + struct net2280_ep_regs __iomem *regs; + struct net2280_dma_regs __iomem *dma; struct net2280_dma *dummy; dma_addr_t td_dma; /* of dummy */ struct net2280 *dev; @@ -539,7 +539,7 @@ /* count (<= 4) bytes in the next fifo write will be valid */ static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count) { - writeb (count, 2 + (u8 *) &ep->regs->ep_cfg); + writeb (count, 2 + (u8 __iomem *) &ep->regs->ep_cfg); } struct net2280_request { @@ -559,18 +559,19 @@ struct usb_gadget_driver *driver; unsigned enabled : 1, protocol_stall : 1, + softconnect : 1, got_irq : 1, region : 1; u16 chiprev; /* pci state used to access those endpoints */ struct pci_dev *pdev; - struct net2280_regs *regs; - struct net2280_usb_regs *usb; - struct net2280_pci_regs *pci; - struct net2280_dma_regs *dma; - struct net2280_dep_regs *dep; - struct net2280_ep_regs *epregs; + struct net2280_regs __iomem *regs; + struct net2280_usb_regs __iomem *usb; + struct net2280_pci_regs __iomem *pci; + struct net2280_dma_regs __iomem *dma; + struct net2280_dep_regs __iomem *dep; + struct net2280_ep_regs __iomem *epregs; struct pci_pool *requests; // statistics... diff -Nru a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/gadget/omap_udc.c 2004-10-18 14:57:22 -07:00 @@ -0,0 +1,2695 @@ +/* + * omap_udc.c -- for OMAP 1610 udc, with OTG support + * + * Copyright (C) 2004 Texas Instruments, Inc. + * Copyright (C) 2004 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#undef DEBUG +#undef VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "omap_udc.h" + +#undef USB_TRACE + +/* OUT-dma seems to be behaving */ +#define USE_DMA + +/* ISO too */ +#define USE_ISO + + +#define DRIVER_DESC "OMAP UDC driver" +#define DRIVER_VERSION "24 August 2004" + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + + +/* + * The OMAP UDC needs _very_ early endpoint setup: before enabling the + * D+ pullup to allow enumeration. That's too early for the gadget + * framework to use from usb_endpoint_enable(), which happens after + * enumeration as part of activating an interface. (But if we add an + * optional new "UDC not yet running" state to the gadget driver model, + * even just during driver binding, the endpoint autoconfig logic is the + * natural spot to manufacture new endpoints.) + * + * So instead of using endpoint enable calls to control the hardware setup, + * this driver defines a "fifo mode" parameter. It's used during driver + * initialization to choose among a set of pre-defined endpoint configs. + * See omap_udc_setup() for available modes, or to add others. That code + * lives in an init section, so use this driver as a module if you need + * to change the fifo mode after the kernel boots. + * + * Gadget drivers normally ignore endpoints they don't care about, and + * won't include them in configuration descriptors. That means only + * misbehaving hosts would even notice they exist. + */ +#ifdef USE_ISO +static unsigned fifo_mode = 3; +#else +static unsigned fifo_mode = 0; +#endif + +/* "modprobe omap_udc fifo_mode=42", or else as a kernel + * boot parameter "omap_udc:fifo_mode=42" + */ +module_param (fifo_mode, uint, 0); +MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)"); + + +#ifdef USE_DMA +static unsigned use_dma = 1; + +/* "modprobe omap_udc use_dma=y", or else as a kernel + * boot parameter "omap_udc:use_dma=y" + */ +module_param (use_dma, bool, 0); +MODULE_PARM_DESC (use_dma, "enable/disable DMA"); +#else /* !USE_DMA */ + +/* save a bit of code */ +#define use_dma 0 +#endif /* !USE_DMA */ + + +static const char driver_name [] = "omap_udc"; +static const char driver_desc [] = DRIVER_DESC; + +/*-------------------------------------------------------------------------*/ + +/* there's a notion of "current endpoint" for modifying endpoint + * state, and PIO access to its FIFO. + */ + +static void use_ep(struct omap_ep *ep, u16 select) +{ + u16 num = ep->bEndpointAddress & 0x0f; + + if (ep->bEndpointAddress & USB_DIR_IN) + num |= UDC_EP_DIR; + UDC_EP_NUM_REG = num | select; + /* when select, MUST deselect later !! */ +} + +static inline void deselect_ep(void) +{ + UDC_EP_NUM_REG &= ~UDC_EP_SEL; + /* 6 wait states before TX will happen */ +} + +static void dma_channel_claim(struct omap_ep *ep, unsigned preferred); + +/*-------------------------------------------------------------------------*/ + +static int omap_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + struct omap_udc *udc; + unsigned long flags; + u16 maxp; + + /* catch various bogus parameters */ + if (!_ep || !desc || ep->desc + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress + || ep->maxpacket < le16_to_cpu + (desc->wMaxPacketSize)) { + DBG("%s, bad ep or descriptor\n", __FUNCTION__); + return -EINVAL; + } + maxp = le16_to_cpu (desc->wMaxPacketSize); + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && maxp != ep->maxpacket) + || desc->wMaxPacketSize > ep->maxpacket + || !desc->wMaxPacketSize) { + DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); + return -ERANGE; + } + +#ifdef USE_ISO + if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC + && desc->bInterval != 1)) { + /* hardware wants period = 1; USB allows 2^(Interval-1) */ + DBG("%s, unsupported ISO period %dms\n", _ep->name, + 1 << (desc->bInterval - 1)); + return -EDOM; + } +#else + if (desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + DBG("%s, ISO nyet\n", _ep->name); + return -EDOM; + } +#endif + + /* xfer types must match, except that interrupt ~= bulk */ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + DBG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); + return -EINVAL; + } + + udc = ep->udc; + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { + DBG("%s, bogus device state\n", __FUNCTION__); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&udc->lock, flags); + + ep->desc = desc; + ep->irqs = 0; + ep->stopped = 0; + ep->ep.maxpacket = maxp; + + /* set endpoint to initial state */ + ep->dma_channel = 0; + ep->has_dma = 0; + ep->lch = -1; + use_ep(ep, UDC_EP_SEL); + UDC_CTRL_REG = UDC_RESET_EP; + ep->ackwait = 0; + deselect_ep(); + + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) + list_add(&ep->iso, &udc->iso); + + /* maybe assign a DMA channel to this endpoint */ + if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && !(ep->bEndpointAddress & USB_DIR_IN)) + /* FIXME ISO can dma, but prefers first channel. + * IN can dma, but lacks debugging. + */ + dma_channel_claim(ep, 0); + + /* PIO OUT may RX packets */ + if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC + && !ep->has_dma + && !(ep->bEndpointAddress & USB_DIR_IN)) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + + spin_unlock_irqrestore(&udc->lock, flags); + VDBG("%s enabled\n", _ep->name); + return 0; +} + +static void nuke(struct omap_ep *, int status); + +static int omap_ep_disable(struct usb_ep *_ep) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + unsigned long flags; + + if (!_ep || !ep->desc) { + DBG("%s, %s not enabled\n", __FUNCTION__, + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + spin_lock_irqsave(&ep->udc->lock, flags); + ep->desc = 0; + nuke (ep, -ESHUTDOWN); + ep->ep.maxpacket = ep->maxpacket; + ep->has_dma = 0; + UDC_CTRL_REG = UDC_SET_HALT; + list_del_init(&ep->iso); + + spin_unlock_irqrestore(&ep->udc->lock, flags); + + VDBG("%s disabled\n", _ep->name); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +omap_alloc_request(struct usb_ep *ep, int gfp_flags) +{ + struct omap_req *req; + + req = kmalloc(sizeof *req, gfp_flags); + if (req) { + memset (req, 0, sizeof *req); + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD (&req->queue); + } + return &req->req; +} + +static void +omap_free_request(struct usb_ep *ep, struct usb_request *_req) +{ + struct omap_req *req = container_of(_req, struct omap_req, req); + + if (_req) + kfree (req); +} + +/*-------------------------------------------------------------------------*/ + +static void * +omap_alloc_buffer( + struct usb_ep *_ep, + unsigned bytes, + dma_addr_t *dma, + int gfp_flags +) +{ + void *retval; + struct omap_ep *ep; + + ep = container_of(_ep, struct omap_ep, ep); + if (use_dma && ep->has_dma) { + static int warned; + if (!warned && bytes < PAGE_SIZE) { + dev_warn(ep->udc->gadget.dev.parent, + "using dma_alloc_coherent for " + "small allocations wastes memory\n"); + warned++; + } + return dma_alloc_coherent(ep->udc->gadget.dev.parent, + bytes, dma, gfp_flags); + } + + retval = kmalloc(bytes, gfp_flags); + if (retval) + *dma = virt_to_phys(retval); + return retval; +} + +static void omap_free_buffer( + struct usb_ep *_ep, + void *buf, + dma_addr_t dma, + unsigned bytes +) +{ + struct omap_ep *ep; + + ep = container_of(_ep, struct omap_ep, ep); + if (use_dma && _ep && ep->has_dma) + dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma); + else + kfree (buf); +} + +/*-------------------------------------------------------------------------*/ + +static void +done(struct omap_ep *ep, struct omap_req *req, int status) +{ + unsigned stopped = ep->stopped; + + list_del_init(&req->queue); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + if (use_dma && ep->has_dma) { + if (req->mapped) { + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } else + dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + } + +#ifndef USB_TRACE + if (status && status != -ESHUTDOWN) +#endif + VDBG("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + spin_unlock(&ep->udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&ep->udc->lock); + ep->stopped = stopped; +} + +/*-------------------------------------------------------------------------*/ + +#define FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) +#define FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL) + +#define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) +#define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) + +static inline int +write_packet(u8 *buf, struct omap_req *req, unsigned max) +{ + unsigned len; + u16 *wp; + + len = min(req->req.length - req->req.actual, max); + req->req.actual += len; + + max = len; + if (likely((((int)buf) & 1) == 0)) { + wp = (u16 *)buf; + while (max >= 2) { + UDC_DATA_REG = *wp++; + max -= 2; + } + buf = (u8 *)wp; + } + while (max--) + *(volatile u8 *)&UDC_DATA_REG = *buf++; + return len; +} + +// FIXME change r/w fifo calling convention + + +// return: 0 = still running, 1 = completed, negative = errno +static int write_fifo(struct omap_ep *ep, struct omap_req *req) +{ + u8 *buf; + unsigned count; + int is_last; + u16 ep_stat; + + buf = req->req.buf + req->req.actual; + prefetch(buf); + + /* PIO-IN isn't double buffered except for iso */ + ep_stat = UDC_STAT_FLG_REG; + if (ep_stat & FIFO_UNWRITABLE) + return 0; + + count = ep->ep.maxpacket; + count = write_packet(buf, req, count); + UDC_CTRL_REG = UDC_SET_FIFO_EN; + ep->ackwait = 1; + + /* last packet is often short (sometimes a zlp) */ + if (count != ep->ep.maxpacket) + is_last = 1; + else if (req->req.length == req->req.actual + && !req->req.zero) + is_last = 1; + else + is_last = 0; + + /* NOTE: requests complete when all IN data is in a + * FIFO (or sometimes later, if a zlp was needed). + * Use usb_ep_fifo_status() where needed. + */ + if (is_last) + done(ep, req, 0); + return is_last; +} + +static inline int +read_packet(u8 *buf, struct omap_req *req, unsigned avail) +{ + unsigned len; + u16 *wp; + + len = min(req->req.length - req->req.actual, avail); + req->req.actual += len; + avail = len; + + if (likely((((int)buf) & 1) == 0)) { + wp = (u16 *)buf; + while (avail >= 2) { + *wp++ = UDC_DATA_REG; + avail -= 2; + } + buf = (u8 *)wp; + } + while (avail--) + *buf++ = *(volatile u8 *)&UDC_DATA_REG; + return len; +} + +// return: 0 = still running, 1 = queue empty, negative = errno +static int read_fifo(struct omap_ep *ep, struct omap_req *req) +{ + u8 *buf; + unsigned count, avail; + int is_last; + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + + for (;;) { + u16 ep_stat = UDC_STAT_FLG_REG; + + is_last = 0; + if (ep_stat & FIFO_UNREADABLE) + break; + + if (ep_stat & (UDC_NON_ISO_FIFO_FULL|UDC_ISO_FIFO_FULL)) + avail = ep->ep.maxpacket; + else + avail = UDC_RXFSTAT_REG; + count = read_packet(buf, req, avail); + + // FIXME double buffered PIO OUT wasn't behaving... + + /* partial packet reads may not be errors */ + if (count < ep->ep.maxpacket) { + is_last = 1; + /* overflowed this request? flush extra data */ + if (count != avail) { + req->req.status = -EOVERFLOW; + avail -= count; + while (avail--) + (void) *(volatile u8 *)&UDC_DATA_REG; + } + } else if (req->req.length == req->req.actual) + is_last = 1; + else + is_last = 0; + + if (!ep->bEndpointAddress) + break; + if (!ep->double_buf) { + UDC_CTRL_REG = UDC_SET_FIFO_EN; + if (!is_last) + break; + } + + if (is_last) { + done(ep, req, 0); + if (list_empty(&ep->queue) || !ep->double_buf) + break; + req = container_of(ep->queue.next, + struct omap_req, queue); + is_last = 0; + } + } + return is_last; +} + +/*-------------------------------------------------------------------------*/ + +/* Each USB transfer request using DMA maps to one or more DMA transfers. + * When DMA completion isn't request completion, the UDC continues with + * the next DMA transfer for that USB transfer. + */ + +static void next_in_dma(struct omap_ep *ep, struct omap_req *req) +{ + u16 txdma_ctrl; + unsigned length = req->req.length - req->req.actual; + + /* measure length in either bytes or packets */ + if (length <= (UDC_TXN_TSC + 1)) { + txdma_ctrl = UDC_TXN_EOT | length; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + length, 1, OMAP_DMA_SYNC_ELEMENT); + } else { + length = max(length / ep->maxpacket, + (unsigned) UDC_TXN_TSC + 1); + txdma_ctrl = length; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + ep->ep.maxpacket, length, + OMAP_DMA_SYNC_ELEMENT); + length *= ep->maxpacket; + } + + omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + + omap_start_dma(ep->lch); + UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel); + UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl; + req->dma_bytes = length; +} + +static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) +{ + if (status == 0) { + req->req.actual += req->dma_bytes; + + /* return if this request needs to send data or zlp */ + if (req->req.actual < req->req.length) + return; + if (req->req.zero + && req->dma_bytes != 0 + && (req->req.actual % ep->maxpacket) == 0) + return; + } else { + u32 last; + + // FIXME this surely isn't #bytes transferred + last = (omap_readw(OMAP_DMA_CSSA_U(ep->lch)) << 16) + | omap_readw(OMAP_DMA_CSSA_L(ep->lch)); + req->req.actual = last - req->req.dma; + } + + /* tx completion */ + omap_stop_dma(ep->lch); + UDC_DMA_IRQ_EN_REG &= ~UDC_TX_DONE_IE(ep->dma_channel); + done(ep, req, status); +} + +static void next_out_dma(struct omap_ep *ep, struct omap_req *req) +{ + unsigned packets; + + /* NOTE: we filtered out "short reads" before, so we know + * the buffer has only whole numbers of packets. + */ + + /* set up this DMA transfer, enable the fifo, start */ + packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; + packets = min(packets, (unsigned)UDC_RXN_TC + 1); + req->dma_bytes = packets * ep->ep.maxpacket; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + ep->ep.maxpacket, packets, + OMAP_DMA_SYNC_ELEMENT); + omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + + UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); + UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel); + UDC_EP_NUM_REG = (ep->bEndpointAddress & 0xf); + UDC_CTRL_REG = UDC_SET_FIFO_EN; + + omap_start_dma(ep->lch); +} + +static void +finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) +{ + u16 count; + + /* FIXME must be a better way to see how much dma + * happened, even when it never got going... + */ + count = omap_readw(OMAP_DMA_CDAC(ep->lch)); + count -= 0xffff & (req->req.dma + req->req.actual); + count += req->req.actual; + if (count <= req->req.length) + req->req.actual = count; + + if (count != req->dma_bytes || status) + omap_stop_dma(ep->lch); + + /* if this wasn't short, request may need another transfer */ + else if (req->req.actual < req->req.length) + return; + + /* rx completion */ + UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel); + done(ep, req, status); +} + +static void dma_irq(struct omap_udc *udc, u16 irq_src) +{ + u16 dman_stat = UDC_DMAN_STAT_REG; + struct omap_ep *ep; + struct omap_req *req; + + /* IN dma: tx to host */ + if (irq_src & UDC_TXN_DONE) { + ep = &udc->ep[16 + UDC_DMA_TX_SRC(dman_stat)]; + ep->irqs++; + /* can see TXN_DONE after dma abort */ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + finish_in_dma(ep, req, 0); + } + UDC_IRQ_SRC_REG = UDC_TXN_DONE; + + if (!list_empty (&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + next_in_dma(ep, req); + } + } + + /* OUT dma: rx from host */ + if (irq_src & UDC_RXN_EOT) { + ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)]; + ep->irqs++; + /* can see RXN_EOT after dma abort */ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + finish_out_dma(ep, req, 0); + } + UDC_IRQ_SRC_REG = UDC_RXN_EOT; + + if (!list_empty (&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + next_out_dma(ep, req); + } + } + + if (irq_src & UDC_RXN_CNT) { + ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)]; + DBG("%s, RX_CNT irq?\n", ep->ep.name); + UDC_IRQ_SRC_REG = UDC_RXN_CNT; + } +} + +static void dma_error(int lch, u16 ch_status, void *data) +{ + struct omap_ep *ep = data; + + /* if ch_status & OMAP_DMA_DROP_IRQ ... */ + /* if ch_status & OMAP_DMA_TOUT_IRQ ... */ + ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status); + + /* complete current transfer ... */ +} + +static void dma_channel_claim(struct omap_ep *ep, unsigned channel) +{ + u16 reg; + int status, restart, is_in; + + is_in = ep->bEndpointAddress & USB_DIR_IN; + if (is_in) + reg = UDC_TXDMA_CFG_REG; + else + reg = UDC_RXDMA_CFG_REG; + reg |= 1 << 12; /* "pulse" activated */ + + ep->dma_channel = 0; + ep->lch = -1; + if (channel == 0 || channel > 3) { + if ((reg & 0x0f00) == 0) + channel = 3; + else if ((reg & 0x00f0) == 0) + channel = 2; + else if ((reg & 0x000f) == 0) /* preferred for ISO */ + channel = 1; + else { + status = -EMLINK; + goto just_restart; + } + } + reg |= (0x0f & ep->bEndpointAddress) << (4 * (channel - 1)); + ep->dma_channel = channel; + + if (is_in) { + status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel, + ep->ep.name, dma_error, ep, &ep->lch); + if (status == 0) { + UDC_TXDMA_CFG_REG = reg; + omap_set_dma_dest_params(ep->lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + } + } else { + status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel, + ep->ep.name, dma_error, ep, &ep->lch); + if (status == 0) { + UDC_RXDMA_CFG_REG = reg; + omap_set_dma_src_params(ep->lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + } + } + if (status) + ep->dma_channel = 0; + else { + ep->has_dma = 1; + omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); + + /* channel type P: hw synch (fifo) */ + omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch)); + } + +just_restart: + /* restart any queue, even if the claim failed */ + restart = !ep->stopped && !list_empty(&ep->queue); + + if (status) + DBG("%s no dma channel: %d%s\n", ep->ep.name, status, + restart ? " (restart)" : ""); + else + DBG("%s claimed %cxdma%d lch %d%s\n", ep->ep.name, + is_in ? 't' : 'r', + ep->dma_channel - 1, ep->lch, + restart ? " (restart)" : ""); + + if (restart) { + struct omap_req *req; + req = container_of(ep->queue.next, struct omap_req, queue); + if (ep->has_dma) + (is_in ? next_in_dma : next_out_dma)(ep, req); + else { + use_ep(ep, UDC_EP_SEL); + (is_in ? write_fifo : read_fifo)(ep, req); + deselect_ep(); + /* IN: 6 wait states before it'll tx */ + } + } +} + +static void dma_channel_release(struct omap_ep *ep) +{ + int shift = 4 * (ep->dma_channel - 1); + u16 mask = 0x0f << shift; + struct omap_req *req; + int active; + + /* abort any active usb transfer request */ + if (!list_empty(&ep->queue)) + req = container_of(ep->queue.next, struct omap_req, queue); + else + req = 0; + + active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0; + + DBG("%s release %s %cxdma%d %p\n", ep->ep.name, + active ? "active" : "idle", + (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', + ep->dma_channel - 1, req); + + /* wait till current packet DMA finishes, and fifo empties */ + if (ep->bEndpointAddress & USB_DIR_IN) { + UDC_TXDMA_CFG_REG &= ~mask; + + if (req) { + if (active) + udelay(50); + finish_in_dma(ep, req, -ECONNRESET); + if (UDC_TXDMA_CFG_REG & mask) + WARN("%s, SPIN abort TX dma\n", ep->ep.name); + } + + /* host may empty the fifo (or not...) */ + while (UDC_TXDMA_CFG_REG & mask) + udelay(10); + + } else { + UDC_RXDMA_CFG_REG &= ~mask; + + /* dma empties the fifo */ + while (active && (UDC_RXDMA_CFG_REG & mask)) + udelay(10); + omap_stop_dma(ep->lch); + if (req) + finish_out_dma(ep, req, -ECONNRESET); + } + omap_free_dma(ep->lch); + ep->dma_channel = 0; + ep->lch = -1; + /* has_dma still set, till endpoint is fully quiesced */ +} + + +/*-------------------------------------------------------------------------*/ + +static int +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + struct omap_req *req = container_of(_req, struct omap_req, req); + struct omap_udc *udc; + unsigned long flags; + int is_iso = 0; + + /* catch various bogus parameters */ + if (!_req || !req->req.complete || !req->req.buf + || !list_empty(&req->queue)) { + DBG("%s, bad params\n", __FUNCTION__); + return -EINVAL; + } + if (!_ep || (!ep->desc && ep->bEndpointAddress)) { + DBG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (req->req.length > ep->ep.maxpacket) + return -EMSGSIZE; + is_iso = 1; + } + + /* this isn't bogus, but OMAP DMA isn't the only hardware to + * have a hard time with partial packet reads... reject it. + */ + if (use_dma + && ep->has_dma + && ep->bEndpointAddress != 0 + && (ep->bEndpointAddress & USB_DIR_IN) == 0 + && (req->req.length % ep->ep.maxpacket) != 0) { + DBG("%s, no partial packet OUT reads\n", __FUNCTION__); + return -EMSGSIZE; + } + + udc = ep->udc; + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + if (use_dma && ep->has_dma) { + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single( + ep->udc->gadget.dev.parent, + req->req.buf, + req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device( + ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 0; + } + } + + VDBG("%s queue req %p, len %d buf %p\n", + ep->ep.name, _req, _req->length, _req->buf); + + spin_lock_irqsave(&udc->lock, flags); + + req->req.status = -EINPROGRESS; + req->req.actual = 0; + + /* maybe kickstart non-iso i/o queues */ + if (is_iso) + UDC_IRQ_EN_REG |= UDC_SOF_IE; + else if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) { + int is_in; + + if (ep->bEndpointAddress == 0) { + if (!udc->ep0_pending || !list_empty (&ep->queue)) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EL2HLT; + } + + /* empty DATA stage? */ + is_in = udc->ep0_in; + if (!req->req.length) { + + /* chip became CONFIGURED or ADDRESSED + * earlier; drivers may already have queued + * requests to non-control endpoints + */ + if (udc->ep0_set_config) { + u16 irq_en = UDC_IRQ_EN_REG; + + irq_en |= UDC_DS_CHG_IE | UDC_EP0_IE; + if (!udc->ep0_reset_config) + irq_en |= UDC_EPN_RX_IE + | UDC_EPN_TX_IE; + UDC_IRQ_EN_REG = irq_en; + } + + /* STATUS is reverse direction */ + UDC_EP_NUM_REG = is_in + ? UDC_EP_SEL + : (UDC_EP_SEL|UDC_EP_DIR); + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR; + + /* cleanup */ + udc->ep0_pending = 0; + done(ep, req, 0); + req = 0; + + /* non-empty DATA stage */ + } else if (is_in) { + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + } else { + if (udc->ep0_setup) + goto irq_wait; + UDC_EP_NUM_REG = UDC_EP_SEL; + } + } else { + is_in = ep->bEndpointAddress & USB_DIR_IN; + if (!ep->has_dma) + use_ep(ep, UDC_EP_SEL); + /* if ISO: SOF IRQs must be enabled/disabled! */ + } + + if (ep->has_dma) + (is_in ? next_in_dma : next_out_dma)(ep, req); + else if (req) { + if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) + req = 0; + deselect_ep(); + /* IN: 6 wait states before it'll tx */ + } + } + +irq_wait: + /* irq handler advances the queue */ + if (req != 0) + list_add_tail(&req->queue, &ep->queue); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + struct omap_req *req; + unsigned long flags; + + if (!_ep || !_req) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EINVAL; + } + + if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) { + int channel = ep->dma_channel; + + /* releasing the dma completion cancels the request, + * reclaiming the channel restarts the queue + */ + dma_channel_release(ep); + dma_channel_claim(ep, channel); + } else + done(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&ep->udc->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int omap_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + unsigned long flags; + int status = -EOPNOTSUPP; + + spin_lock_irqsave(&ep->udc->lock, flags); + + /* just use protocol stalls for ep0; real halts are annoying */ + if (ep->bEndpointAddress == 0) { + if (!ep->udc->ep0_pending) + status = -EINVAL; + else if (value) { + if (ep->udc->ep0_set_config) { + WARN("error changing config?\n"); + UDC_SYSCON2_REG = UDC_CLR_CFG; + } + UDC_SYSCON2_REG = UDC_STALL_CMD; + ep->udc->ep0_pending = 0; + status = 0; + } else /* NOP */ + status = 0; + + /* otherwise, all active non-ISO endpoints can halt */ + } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) { + + /* IN endpoints must already be idle */ + if ((ep->bEndpointAddress & USB_DIR_IN) + && !list_empty(&ep->queue)) { + status = -EAGAIN; + goto done; + } + + if (value) { + int channel; + + if (use_dma && ep->dma_channel + && !list_empty(&ep->queue)) { + channel = ep->dma_channel; + dma_channel_release(ep); + } else + channel = 0; + + use_ep(ep, UDC_EP_SEL); + if (UDC_STAT_FLG_REG & UDC_NON_ISO_FIFO_EMPTY) { + UDC_CTRL_REG = UDC_SET_HALT; + status = 0; + } else + status = -EAGAIN; + deselect_ep(); + + if (channel) + dma_channel_claim(ep, channel); + } else { + use_ep(ep, 0); + UDC_CTRL_REG = UDC_RESET_EP; + ep->ackwait = 0; + if (!(ep->bEndpointAddress & USB_DIR_IN)) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + } + } +done: + VDBG("%s %s halt stat %d\n", ep->ep.name, + value ? "set" : "clear", status); + + spin_unlock_irqrestore(&ep->udc->lock, flags); + return status; +} + +static struct usb_ep_ops omap_ep_ops = { + .enable = omap_ep_enable, + .disable = omap_ep_disable, + + .alloc_request = omap_alloc_request, + .free_request = omap_free_request, + + .alloc_buffer = omap_alloc_buffer, + .free_buffer = omap_free_buffer, + + .queue = omap_ep_queue, + .dequeue = omap_ep_dequeue, + + .set_halt = omap_ep_set_halt, + // fifo_status ... report bytes in fifo + // fifo_flush ... flush fifo +}; + +/*-------------------------------------------------------------------------*/ + +static int omap_get_frame(struct usb_gadget *gadget) +{ + u16 sof = UDC_SOF_REG; + return (sof & UDC_TS_OK) ? (sof & UDC_TS) : -EL2NSYNC; +} + +static int omap_wakeup(struct usb_gadget *gadget) +{ + struct omap_udc *udc; + unsigned long flags; + int retval = -EHOSTUNREACH; + + udc = container_of(gadget, struct omap_udc, gadget); + + spin_lock_irqsave(&udc->lock, flags); + if (udc->devstat & UDC_SUS) { + /* NOTE: OTG spec erratum says that OTG devices may + * issue wakeups without host enable. + */ + if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) { + DBG("remote wakeup...\n"); + UDC_SYSCON2_REG = UDC_RMT_WKP; + retval = 0; + } + + /* NOTE: non-OTG systems may use SRP TOO... */ + } else if (!(udc->devstat & UDC_ATT)) { + if (udc->transceiver) + retval = otg_start_srp(udc->transceiver); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return retval; +} + +static int +omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + struct omap_udc *udc; + unsigned long flags; + u16 syscon1; + + udc = container_of(gadget, struct omap_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + syscon1 = UDC_SYSCON1_REG; + if (is_selfpowered) + syscon1 |= UDC_SELF_PWR; + else + syscon1 &= ~UDC_SELF_PWR; + UDC_SYSCON1_REG = syscon1; + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int can_pullup(struct omap_udc *udc) +{ + return udc->driver && udc->softconnect && udc->vbus_active; +} + +static void pullup_enable(struct omap_udc *udc) +{ + UDC_SYSCON1_REG |= UDC_PULLUP_EN; +#ifndef CONFIG_USB_OTG + OTG_CTRL_REG |= OTG_BSESSVLD; +#endif + UDC_IRQ_EN_REG = UDC_DS_CHG_IE; +} + +static void pullup_disable(struct omap_udc *udc) +{ +#ifndef CONFIG_USB_OTG + OTG_CTRL_REG &= ~OTG_BSESSVLD; +#endif + UDC_IRQ_EN_REG = UDC_DS_CHG_IE; + UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; +} + +/* + * Called by whatever detects VBUS sessions: external transceiver + * driver, or maybe GPIO0 VBUS IRQ. + */ +static int omap_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct omap_udc *udc; + unsigned long flags; + + udc = container_of(gadget, struct omap_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + VDBG("VBUS %s\n", is_active ? "on" : "off"); + udc->vbus_active = (is_active != 0); + if (can_pullup(udc)) + pullup_enable(udc); + else + pullup_disable(udc); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + struct omap_udc *udc; + + udc = container_of(gadget, struct omap_udc, gadget); + if (udc->transceiver) + return otg_set_power(udc->transceiver, mA); + return -EOPNOTSUPP; +} + +static int omap_pullup(struct usb_gadget *gadget, int is_on) +{ + struct omap_udc *udc; + unsigned long flags; + + udc = container_of(gadget, struct omap_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + udc->softconnect = (is_on != 0); + if (can_pullup(udc)) + pullup_enable(udc); + else + pullup_disable(udc); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static struct usb_gadget_ops omap_gadget_ops = { + .get_frame = omap_get_frame, + .wakeup = omap_wakeup, + .set_selfpowered = omap_set_selfpowered, + .vbus_session = omap_vbus_session, + .vbus_draw = omap_vbus_draw, + .pullup = omap_pullup, +}; + +/*-------------------------------------------------------------------------*/ + +/* dequeue ALL requests; caller holds udc->lock */ +static void nuke(struct omap_ep *ep, int status) +{ + struct omap_req *req; + + ep->stopped = 1; + + if (use_dma && ep->dma_channel) + dma_channel_release(ep); + + use_ep(ep, 0); + UDC_CTRL_REG = UDC_CLR_EP; + if (ep->bEndpointAddress && ep->bmAttributes != USB_ENDPOINT_XFER_ISOC) + UDC_CTRL_REG = UDC_SET_HALT; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct omap_req, queue); + done(ep, req, status); + } +} + +/* caller holds udc->lock */ +static void udc_quiesce(struct omap_udc *udc) +{ + struct omap_ep *ep; + + udc->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc->ep[0], -ESHUTDOWN); + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) + nuke(ep, -ESHUTDOWN); +} + +/*-------------------------------------------------------------------------*/ + +static void update_otg(struct omap_udc *udc) +{ + u16 devstat; + + if (!udc->gadget.is_otg) + return; + + if (OTG_CTRL_REG & OTG_ID) + devstat = UDC_DEVSTAT_REG; + else + devstat = 0; + + udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE); + udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT); + udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT); + + /* Enable HNP early, avoiding races on suspend irq path. + * ASSUMES OTG state machine B_BUS_REQ input is true. + */ + if (udc->gadget.b_hnp_enable) + OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ) + & ~OTG_PULLUP; +} + +static void ep0_irq(struct omap_udc *udc, u16 irq_src) +{ + struct omap_ep *ep0 = &udc->ep[0]; + struct omap_req *req = 0; + + ep0->irqs++; + + /* Clear any pending requests and then scrub any rx/tx state + * before starting to handle the SETUP request. + */ + if (irq_src & UDC_SETUP) + nuke(ep0, 0); + + /* IN/OUT packets mean we're in the DATA or STATUS stage. + * This driver uses only uses protocol stalls (ep0 never halts), + * and if we got this far the gadget driver already had a + * chance to stall. Tries to be forgiving of host oddities. + * + * NOTE: the last chance gadget drivers have to stall control + * requests is during their request completion callback. + */ + if (!list_empty(&ep0->queue)) + req = container_of(ep0->queue.next, struct omap_req, queue); + + /* IN == TX to host */ + if (irq_src & UDC_EP0_TX) { + int stat; + + UDC_IRQ_SRC_REG = UDC_EP0_TX; + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + stat = UDC_STAT_FLG_REG; + if (stat & UDC_ACK) { + if (udc->ep0_in) { + /* write next IN packet from response, + * or set up the status stage. + */ + if (req) + stat = write_fifo(ep0, req); + UDC_EP_NUM_REG = UDC_EP_DIR; + if (!req && udc->ep0_pending) { + UDC_EP_NUM_REG = UDC_EP_SEL; + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = 0; + udc->ep0_pending = 0; + } /* else: 6 wait states before it'll tx */ + } else { + /* ack status stage of OUT transfer */ + UDC_EP_NUM_REG = UDC_EP_DIR; + if (req) + done(ep0, req, 0); + } + req = 0; + } else if (stat & UDC_STALL) { + UDC_CTRL_REG = UDC_CLR_HALT; + UDC_EP_NUM_REG = UDC_EP_DIR; + } else { + UDC_EP_NUM_REG = UDC_EP_DIR; + } + } + + /* OUT == RX from host */ + if (irq_src & UDC_EP0_RX) { + int stat; + + UDC_IRQ_SRC_REG = UDC_EP0_RX; + UDC_EP_NUM_REG = UDC_EP_SEL; + stat = UDC_STAT_FLG_REG; + if (stat & UDC_ACK) { + if (!udc->ep0_in) { + stat = 0; + /* read next OUT packet of request, maybe + * reactiviting the fifo; stall on errors. + */ + if (!req || (stat = read_fifo(ep0, req)) < 0) { + UDC_SYSCON2_REG = UDC_STALL_CMD; + udc->ep0_pending = 0; + stat = 0; + } else if (stat == 0) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = 0; + + /* activate status stage */ + if (stat == 1) { + done(ep0, req, 0); + /* that may have STALLed ep0... */ + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = UDC_EP_DIR; + udc->ep0_pending = 0; + } + } else { + /* ack status stage of IN transfer */ + UDC_EP_NUM_REG = 0; + if (req) + done(ep0, req, 0); + } + } else if (stat & UDC_STALL) { + UDC_CTRL_REG = UDC_CLR_HALT; + UDC_EP_NUM_REG = 0; + } else { + UDC_EP_NUM_REG = 0; + } + } + + /* SETUP starts all control transfers */ + if (irq_src & UDC_SETUP) { + union u { + u16 word[4]; + struct usb_ctrlrequest r; + } u; + int status = -EINVAL; + struct omap_ep *ep; + + /* read the (latest) SETUP message */ + do { + UDC_EP_NUM_REG = UDC_SETUP_SEL; + /* two bytes at a time */ + u.word[0] = UDC_DATA_REG; + u.word[1] = UDC_DATA_REG; + u.word[2] = UDC_DATA_REG; + u.word[3] = UDC_DATA_REG; + UDC_EP_NUM_REG = 0; + } while (UDC_IRQ_SRC_REG & UDC_SETUP); + le16_to_cpus (&u.r.wValue); + le16_to_cpus (&u.r.wIndex); + le16_to_cpus (&u.r.wLength); + + /* Delegate almost all control requests to the gadget driver, + * except for a handful of ch9 status/feature requests that + * hardware doesn't autodecode _and_ the gadget API hides. + */ + udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0; + udc->ep0_set_config = 0; + udc->ep0_pending = 1; + ep0->stopped = 0; + ep0->ackwait = 0; + switch (u.r.bRequest) { + case USB_REQ_SET_CONFIGURATION: + /* udc needs to know when ep != 0 is valid */ + if (u.r.bRequestType != USB_RECIP_DEVICE) + goto delegate; + if (u.r.wLength != 0) + goto do_stall; + udc->ep0_set_config = 1; + udc->ep0_reset_config = (u.r.wValue == 0); + VDBG("set config %d\n", u.r.wValue); + + /* update udc NOW since gadget driver may start + * queueing requests immediately; clear config + * later if it fails the request. + */ + if (udc->ep0_reset_config) + UDC_SYSCON2_REG = UDC_CLR_CFG; + else + UDC_SYSCON2_REG = UDC_DEV_CFG; + update_otg(udc); + goto delegate; + case USB_REQ_CLEAR_FEATURE: + /* clear endpoint halt */ + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wValue != USB_ENDPOINT_HALT + || u.r.wLength != 0) + goto do_stall; + ep = &udc->ep[u.r.wIndex & 0xf]; + if (ep != ep0) { + if (u.r.wIndex & USB_DIR_IN) + ep += 16; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC + || !ep->desc) + goto do_stall; + use_ep(ep, 0); + UDC_CTRL_REG = UDC_RESET_EP; + ep->ackwait = 0; + if (!(ep->bEndpointAddress & USB_DIR_IN)) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + } + VDBG("%s halt cleared by host\n", ep->name); + goto ep0out_status_stage; + case USB_REQ_SET_FEATURE: + /* set endpoint halt */ + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wValue != USB_ENDPOINT_HALT + || u.r.wLength != 0) + goto do_stall; + ep = &udc->ep[u.r.wIndex & 0xf]; + if (u.r.wIndex & USB_DIR_IN) + ep += 16; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC + || ep == ep0 || !ep->desc) + goto do_stall; + if (use_dma && ep->has_dma) { + /* this has rude side-effects (aborts) and + * can't really work if DMA-IN is active + */ + DBG("%s host set_halt, NYET \n", ep->name); + goto do_stall; + } + use_ep(ep, 0); + /* can't halt if fifo isn't empty... */ + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_HALT; + VDBG("%s halted by host\n", ep->name); +ep0out_status_stage: + status = 0; + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = UDC_EP_DIR; + udc->ep0_pending = 0; + break; + case USB_REQ_GET_STATUS: + /* return interface status. if we were pedantic, + * we'd detect non-existent interfaces, and stall. + */ + if (u.r.bRequestType + != (USB_DIR_IN|USB_RECIP_INTERFACE)) + goto delegate; + /* return two zero bytes */ + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + UDC_DATA_REG = 0; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = UDC_EP_DIR; + status = 0; + VDBG("GET_STATUS, interface %d\n", u.r.wIndex); + /* next, status stage */ + break; + default: +delegate: + /* activate the ep0out fifo right away */ + if (!udc->ep0_in && u.r.wLength) { + UDC_EP_NUM_REG = 0; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + } + + /* gadget drivers see class/vendor specific requests, + * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, + * and more + */ + VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, u.r.wLength); + + /* The gadget driver may return an error here, + * causing an immediate protocol stall. + * + * Else it must issue a response, either queueing a + * response buffer for the DATA stage, or halting ep0 + * (causing a protocol stall, not a real halt). A + * zero length buffer means no DATA stage. + * + * It's fine to issue that response after the setup() + * call returns, and this IRQ was handled. + */ + udc->ep0_setup = 1; + spin_unlock(&udc->lock); + status = udc->driver->setup (&udc->gadget, &u.r); + spin_lock(&udc->lock); + udc->ep0_setup = 0; + } + + if (status < 0) { +do_stall: + VDBG("req %02x.%02x protocol STALL; stat %d\n", + u.r.bRequestType, u.r.bRequest, status); + if (udc->ep0_set_config) { + if (udc->ep0_reset_config) + WARN("error resetting config?\n"); + else + UDC_SYSCON2_REG = UDC_CLR_CFG; + } + UDC_SYSCON2_REG = UDC_STALL_CMD; + udc->ep0_pending = 0; + } + } +} + +/*-------------------------------------------------------------------------*/ + +#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT) + +static void devstate_irq(struct omap_udc *udc, u16 irq_src) +{ + u16 devstat, change; + + devstat = UDC_DEVSTAT_REG; + change = devstat ^ udc->devstat; + udc->devstat = devstat; + + if (change & (UDC_USB_RESET|UDC_ATT)) { + udc_quiesce(udc); + + if (change & UDC_ATT) { + /* driver for any external transceiver will + * have called omap_vbus_session() already + */ + if (devstat & UDC_ATT) { + udc->gadget.speed = USB_SPEED_FULL; + VDBG("connect\n"); + if (!udc->transceiver) + pullup_enable(udc); + // if (driver->connect) call it + } else if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + udc->gadget.speed = USB_SPEED_UNKNOWN; + if (!udc->transceiver) + pullup_disable(udc); + DBG("disconnect, gadget %s\n", + udc->driver->driver.name); + if (udc->driver->disconnect) { + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + } + change &= ~UDC_ATT; + } + + if (change & UDC_USB_RESET) { + if (devstat & UDC_USB_RESET) { + VDBG("RESET=1\n"); + } else { + udc->gadget.speed = USB_SPEED_FULL; + INFO("USB reset done, gadget %s\n", + udc->driver->driver.name); + /* ep0 traffic is legal from now on */ + UDC_IRQ_EN_REG = UDC_DS_CHG_IE | UDC_EP0_IE; + } + change &= ~UDC_USB_RESET; + } + } + if (change & UDC_SUS) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + // FIXME tell isp1301 to suspend/resume (?) + if (devstat & UDC_SUS) { + VDBG("suspend\n"); + update_otg(udc); + /* HNP could be under way already */ + if (udc->gadget.speed == USB_SPEED_FULL + && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } else { + VDBG("resume\n"); + if (udc->gadget.speed == USB_SPEED_FULL + && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + } + change &= ~UDC_SUS; + } + if (change & OTG_FLAGS) { + update_otg(udc); + change &= ~OTG_FLAGS; + } + + change &= ~(UDC_CFG|UDC_DEF|UDC_ADD); + if (change) + VDBG("devstat %03x, ignore change %03x\n", + devstat, change); + + UDC_IRQ_SRC_REG = UDC_DS_CHG; +} + +static irqreturn_t +omap_udc_irq(int irq, void *_udc, struct pt_regs *r) +{ + struct omap_udc *udc = _udc; + u16 irq_src; + irqreturn_t status = IRQ_NONE; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + irq_src = UDC_IRQ_SRC_REG; + + /* Device state change (usb ch9 stuff) */ + if (irq_src & UDC_DS_CHG) { + devstate_irq(_udc, irq_src); + status = IRQ_HANDLED; + irq_src &= ~UDC_DS_CHG; + } + + /* EP0 control transfers */ + if (irq_src & (UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX)) { + ep0_irq(_udc, irq_src); + status = IRQ_HANDLED; + irq_src &= ~(UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX); + } + + /* DMA transfer completion */ + if (use_dma && (irq_src & (UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT))) { + dma_irq(_udc, irq_src); + status = IRQ_HANDLED; + irq_src &= ~(UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT); + } + + irq_src &= ~(UDC_SOF|UDC_EPN_TX|UDC_EPN_RX); + if (irq_src) + DBG("udc_irq, unhandled %03x\n", irq_src); + spin_unlock_irqrestore(&udc->lock, flags); + + return status; +} + +static irqreturn_t +omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r) +{ + u16 epn_stat, irq_src; + irqreturn_t status = IRQ_NONE; + struct omap_ep *ep; + int epnum; + struct omap_udc *udc = _dev; + struct omap_req *req; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + epn_stat = UDC_EPN_STAT_REG; + irq_src = UDC_IRQ_SRC_REG; + + /* handle OUT first, to avoid some wasteful NAKs */ + if (irq_src & UDC_EPN_RX) { + epnum = (epn_stat >> 8) & 0x0f; + UDC_IRQ_SRC_REG = UDC_EPN_RX; + status = IRQ_HANDLED; + ep = &udc->ep[epnum]; + ep->irqs++; + + if (!list_empty(&ep->queue)) { + UDC_EP_NUM_REG = epnum | UDC_EP_SEL; + if ((UDC_STAT_FLG_REG & UDC_ACK)) { + int stat; + req = container_of(ep->queue.next, + struct omap_req, queue); + stat = read_fifo(ep, req); + // FIXME double buffered PIO OUT should work + } + UDC_EP_NUM_REG = epnum; + } + } + + /* then IN transfers */ + if (irq_src & UDC_EPN_TX) { + epnum = epn_stat & 0x0f; + UDC_IRQ_SRC_REG = UDC_EPN_TX; + status = IRQ_HANDLED; + ep = &udc->ep[16 + epnum]; + ep->irqs++; + ep->ackwait = 0; + + if (!list_empty(&ep->queue)) { + UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL; + if ((UDC_STAT_FLG_REG & UDC_ACK)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + (void) write_fifo(ep, req); + } + UDC_EP_NUM_REG = epnum | UDC_EP_DIR; + /* 6 wait states before it'll tx */ + } + } + + spin_unlock_irqrestore(&udc->lock, flags); + return status; +} + +#ifdef USE_ISO +static irqreturn_t +omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r) +{ + struct omap_udc *udc = _dev; + struct omap_ep *ep; + int pending = 0; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + /* handle all non-DMA ISO transfers */ + list_for_each_entry (ep, &udc->iso, iso) { + u16 stat; + struct omap_req *req; + + if (ep->has_dma || list_empty(&ep->queue)) + continue; + req = list_entry(ep->queue.next, struct omap_req, queue); + + use_ep(ep, UDC_EP_SEL); + stat = UDC_STAT_FLG_REG; + + /* NOTE: like the other controller drivers, this isn't + * currently reporting lost or damaged frames. + */ + if (ep->bEndpointAddress & USB_DIR_IN) { + if (stat & UDC_MISS_IN) + /* done(ep, req, -EPROTO) */; + else + write_fifo(ep, req); + } else { + int status = 0; + + if (stat & UDC_NO_RXPACKET) + status = -EREMOTEIO; + else if (stat & UDC_ISO_ERR) + status = -EILSEQ; + else if (stat & UDC_DATA_FLUSH) + status = -ENOSR; + + if (status) + /* done(ep, req, status) */; + else + read_fifo(ep, req); + } + deselect_ep(); + /* 6 wait states before next EP */ + + ep->irqs++; + if (!list_empty(&ep->queue)) + pending = 1; + } + if (!pending) + UDC_IRQ_EN_REG &= ~UDC_SOF_IE; + UDC_IRQ_SRC_REG = UDC_SOF; + + spin_unlock_irqrestore(&udc->lock, flags); + return IRQ_HANDLED; +} +#endif + +/*-------------------------------------------------------------------------*/ + +static struct omap_udc *udc; + +int usb_gadget_register_driver (struct usb_gadget_driver *driver) +{ + int status = -ENODEV; + struct omap_ep *ep; + unsigned long flags; + + /* basic sanity tests */ + if (!udc) + return -ENODEV; + if (!driver + // FIXME if otg, check: driver->is_otg + || driver->speed < USB_SPEED_FULL + || !driver->bind + || !driver->unbind + || !driver->setup) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EBUSY; + } + + /* reset state */ + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + ep->irqs = 0; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) + continue; + use_ep(ep, 0); + UDC_CTRL_REG = UDC_SET_HALT; + } + udc->ep0_pending = 0; + udc->ep[0].irqs = 0; + udc->softconnect = 1; + + /* hook up the driver */ + driver->driver.bus = 0; + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + status = driver->bind (&udc->gadget); + if (status) { + DBG("bind to %s --> %d\n", driver->driver.name, status); + udc->gadget.dev.driver = 0; + udc->driver = 0; + goto done; + } + DBG("bound to driver %s\n", driver->driver.name); + + UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK; + + /* connect to bus through transceiver */ + if (udc->transceiver) { + status = otg_set_peripheral(udc->transceiver, &udc->gadget); + if (status < 0) { + ERR("can't bind to transceiver\n"); + driver->unbind (&udc->gadget); + udc->gadget.dev.driver = 0; + udc->driver = 0; + goto done; + } + } else { + if (can_pullup(udc)) + pullup_enable (udc); + else + pullup_disable (udc); + } + +done: + return status; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +{ + unsigned long flags; + int status = -ENODEV; + + if (!udc) + return -ENODEV; + if (!driver || driver != udc->driver) + return -EINVAL; + + if (udc->transceiver) + (void) otg_set_peripheral(udc->transceiver, 0); + else + pullup_disable(udc); + + spin_lock_irqsave(&udc->lock, flags); + udc_quiesce(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = 0; + udc->driver = 0; + + + DBG("unregistered driver '%s'\n", driver->driver.name); + return status; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_OMAP_PROC + +#include + +static const char proc_filename[] = "driver/udc"; + +#define FOURBITS "%s%s%s%s" +#define EIGHTBITS FOURBITS FOURBITS + +static void proc_ep_show(struct seq_file *s, struct omap_ep *ep) +{ + u16 stat_flg; + struct omap_req *req; + char buf[20]; + + use_ep(ep, 0); + + if (use_dma && ep->has_dma) + snprintf(buf, sizeof buf, "(%cxdma%d lch%d) ", + (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', + ep->dma_channel - 1, ep->lch); + else + buf[0] = 0; + + stat_flg = UDC_STAT_FLG_REG; + seq_printf(s, + "\n%s %sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n", + ep->name, buf, ep->irqs, stat_flg, + (stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "", + (stat_flg & UDC_MISS_IN) ? "miss_in " : "", + (stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "", + (stat_flg & UDC_ISO_ERR) ? "iso_err " : "", + (stat_flg & UDC_ISO_FIFO_EMPTY) ? "iso_fifo_empty " : "", + (stat_flg & UDC_ISO_FIFO_FULL) ? "iso_fifo_full " : "", + (stat_flg & UDC_EP_HALTED) ? "HALT " : "", + (stat_flg & UDC_STALL) ? "STALL " : "", + (stat_flg & UDC_NAK) ? "NAK " : "", + (stat_flg & UDC_ACK) ? "ACK " : "", + (stat_flg & UDC_FIFO_EN) ? "fifo_en " : "", + (stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "", + (stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : ""); + + if (list_empty (&ep->queue)) + seq_printf(s, "\t(queue empty)\n"); + else + list_for_each_entry (req, &ep->queue, queue) + seq_printf(s, "\treq %p len %d/%d buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); +} + +static char *trx_mode(unsigned m) +{ + switch (m) { + case 3: + case 0: return "6wire"; + case 1: return "4wire"; + case 2: return "3wire"; + default: return "unknown"; + } +} + +static int proc_udc_show(struct seq_file *s, void *_) +{ + u32 tmp; + struct omap_ep *ep; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + seq_printf(s, "%s, version: " DRIVER_VERSION +#ifdef USE_ISO + " (iso)" +#endif + "%s\n", + driver_desc, + use_dma ? " (dma)" : ""); + + tmp = UDC_REV_REG & 0xff; + seq_printf(s, + "UDC rev %d.%d, OTG rev %d.%d, fifo mode %d, gadget %s\n" + "hmc %d, transceiver %08x %s\n", + tmp >> 4, tmp & 0xf, + OTG_REV_REG >> 4, OTG_REV_REG & 0xf, + fifo_mode, + udc->driver ? udc->driver->driver.name : "(none)", + HMC, USB_TRANSCEIVER_CTRL_REG, + udc->transceiver ? udc->transceiver->label : ""); + + /* OTG controller registers */ + tmp = OTG_SYSCON_1_REG; + seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," + FOURBITS "\n", tmp, + trx_mode(USB2_TRX_MODE(tmp)), + trx_mode(USB1_TRX_MODE(tmp)), + trx_mode(USB0_TRX_MODE(tmp)), + (tmp & OTG_IDLE_EN) ? " !otg" : "", + (tmp & HST_IDLE_EN) ? " !host" : "", + (tmp & DEV_IDLE_EN) ? " !dev" : "", + (tmp & OTG_RESET_DONE) ? " reset_done" : " reset_active"); + tmp = OTG_SYSCON_2_REG; + seq_printf(s, "otg_syscon2 %08x%s" EIGHTBITS + " b_ase_brst=%d hmc=%d\n", tmp, + (tmp & OTG_EN) ? " otg_en" : "", + (tmp & USBX_SYNCHRO) ? " synchro" : "", + // much more SRP stuff + (tmp & SRP_DATA) ? " srp_data" : "", + (tmp & SRP_VBUS) ? " srp_vbus" : "", + (tmp & OTG_PADEN) ? " otg_paden" : "", + (tmp & HMC_PADEN) ? " hmc_paden" : "", + (tmp & UHOST_EN) ? " uhost_en" : "", + (tmp & HMC_TLLSPEED) ? " tllspeed" : "", + (tmp & HMC_TLLATTACH) ? " tllattach" : "", + B_ASE_BRST(tmp), + OTG_HMC(tmp)); + tmp = OTG_CTRL_REG; + seq_printf(s, "otg_ctrl %06x" EIGHTBITS EIGHTBITS "%s\n", tmp, + (tmp & OTG_ASESSVLD) ? " asess" : "", + (tmp & OTG_BSESSEND) ? " bsess_end" : "", + (tmp & OTG_BSESSVLD) ? " bsess" : "", + (tmp & OTG_VBUSVLD) ? " vbus" : "", + (tmp & OTG_ID) ? " id" : "", + (tmp & OTG_DRIVER_SEL) ? " DEVICE" : " HOST", + (tmp & OTG_A_SETB_HNPEN) ? " a_setb_hnpen" : "", + (tmp & OTG_A_BUSREQ) ? " a_bus" : "", + (tmp & OTG_B_HNPEN) ? " b_hnpen" : "", + (tmp & OTG_B_BUSREQ) ? " b_bus" : "", + (tmp & OTG_BUSDROP) ? " busdrop" : "", + (tmp & OTG_PULLDOWN) ? " down" : "", + (tmp & OTG_PULLUP) ? " up" : "", + (tmp & OTG_DRV_VBUS) ? " drv" : "", + (tmp & OTG_PD_VBUS) ? " pd_vb" : "", + (tmp & OTG_PU_VBUS) ? " pu_vb" : "", + (tmp & OTG_PU_ID) ? " pu_id" : "" + ); + tmp = OTG_IRQ_EN_REG; + seq_printf(s, "otg_irq_en %04x" "\n", tmp); + tmp = OTG_IRQ_SRC_REG; + seq_printf(s, "otg_irq_src %04x" "\n", tmp); + tmp = OTG_OUTCTRL_REG; + seq_printf(s, "otg_outctrl %04x" "\n", tmp); + tmp = OTG_TEST_REG; + seq_printf(s, "otg_test %04x" "\n", tmp); + + tmp = UDC_SYSCON1_REG; + seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp, + (tmp & UDC_CFG_LOCK) ? " cfg_lock" : "", + (tmp & UDC_DATA_ENDIAN) ? " data_endian" : "", + (tmp & UDC_DMA_ENDIAN) ? " dma_endian" : "", + (tmp & UDC_NAK_EN) ? " nak" : "", + (tmp & UDC_AUTODECODE_DIS) ? " autodecode_dis" : "", + (tmp & UDC_SELF_PWR) ? " self_pwr" : "", + (tmp & UDC_SOFF_DIS) ? " soff_dis" : "", + (tmp & UDC_PULLUP_EN) ? " PULLUP" : ""); + // syscon2 is write-only + + /* UDC controller registers */ + if (!(tmp & UDC_PULLUP_EN)) { + seq_printf(s, "(suspended)\n"); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; + } + + tmp = UDC_DEVSTAT_REG; + seq_printf(s, "devstat %04x" EIGHTBITS "%s%s\n", tmp, + (tmp & UDC_B_HNP_ENABLE) ? " b_hnp" : "", + (tmp & UDC_A_HNP_SUPPORT) ? " a_hnp" : "", + (tmp & UDC_A_ALT_HNP_SUPPORT) ? " a_alt_hnp" : "", + (tmp & UDC_R_WK_OK) ? " r_wk_ok" : "", + (tmp & UDC_USB_RESET) ? " usb_reset" : "", + (tmp & UDC_SUS) ? " SUS" : "", + (tmp & UDC_CFG) ? " CFG" : "", + (tmp & UDC_ADD) ? " ADD" : "", + (tmp & UDC_DEF) ? " DEF" : "", + (tmp & UDC_ATT) ? " ATT" : ""); + seq_printf(s, "sof %04x\n", UDC_SOF_REG); + tmp = UDC_IRQ_EN_REG; + seq_printf(s, "irq_en %04x" FOURBITS "%s\n", tmp, + (tmp & UDC_SOF_IE) ? " sof" : "", + (tmp & UDC_EPN_RX_IE) ? " epn_rx" : "", + (tmp & UDC_EPN_TX_IE) ? " epn_tx" : "", + (tmp & UDC_DS_CHG_IE) ? " ds_chg" : "", + (tmp & UDC_EP0_IE) ? " ep0" : ""); + tmp = UDC_IRQ_SRC_REG; + seq_printf(s, "irq_src %04x" EIGHTBITS "%s%s\n", tmp, + (tmp & UDC_TXN_DONE) ? " txn_done" : "", + (tmp & UDC_RXN_CNT) ? " rxn_cnt" : "", + (tmp & UDC_RXN_EOT) ? " rxn_eot" : "", + (tmp & UDC_SOF) ? " sof" : "", + (tmp & UDC_EPN_RX) ? " epn_rx" : "", + (tmp & UDC_EPN_TX) ? " epn_tx" : "", + (tmp & UDC_DS_CHG) ? " ds_chg" : "", + (tmp & UDC_SETUP) ? " setup" : "", + (tmp & UDC_EP0_RX) ? " ep0out" : "", + (tmp & UDC_EP0_TX) ? " ep0in" : ""); + if (use_dma) { + unsigned i; + + tmp = UDC_DMA_IRQ_EN_REG; + seq_printf(s, "dma_irq_en %04x%s" EIGHTBITS "\n", tmp, + (tmp & UDC_TX_DONE_IE(3)) ? " tx2_done" : "", + (tmp & UDC_RX_CNT_IE(3)) ? " rx2_cnt" : "", + (tmp & UDC_RX_EOT_IE(3)) ? " rx2_eot" : "", + + (tmp & UDC_TX_DONE_IE(2)) ? " tx1_done" : "", + (tmp & UDC_RX_CNT_IE(2)) ? " rx1_cnt" : "", + (tmp & UDC_RX_EOT_IE(2)) ? " rx1_eot" : "", + + (tmp & UDC_TX_DONE_IE(1)) ? " tx0_done" : "", + (tmp & UDC_RX_CNT_IE(1)) ? " rx0_cnt" : "", + (tmp & UDC_RX_EOT_IE(1)) ? " rx0_eot" : ""); + + tmp = UDC_RXDMA_CFG_REG; + seq_printf(s, "rxdma_cfg %04x\n", tmp); + if (tmp) { + for (i = 0; i < 3; i++) { + if ((tmp & (0x0f << (i * 4))) == 0) + continue; + seq_printf(s, "rxdma[%d] %04x\n", i, + UDC_RXDMA_REG(i + 1)); + } + } + tmp = UDC_TXDMA_CFG_REG; + seq_printf(s, "txdma_cfg %04x\n", tmp); + if (tmp) { + for (i = 0; i < 3; i++) { + if (!(tmp & (0x0f << (i * 4)))) + continue; + seq_printf(s, "txdma[%d] %04x\n", i, + UDC_TXDMA_REG(i + 1)); + } + } + } + + tmp = UDC_DEVSTAT_REG; + if (tmp & UDC_ATT) { + proc_ep_show(s, &udc->ep[0]); + if (tmp & UDC_ADD) { + list_for_each_entry (ep, &udc->gadget.ep_list, + ep.ep_list) { + if (ep->desc) + proc_ep_show(s, ep); + } + } + } + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static int proc_udc_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_udc_show, 0); +} + +static struct file_operations proc_ops = { + .open = proc_udc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_proc_file(void) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry (proc_filename, 0, NULL); + if (pde) + pde->proc_fops = &proc_ops; +} + +static void remove_proc_file(void) +{ + remove_proc_entry(proc_filename, 0); +} + +#else + +static inline void create_proc_file(void) {} +static inline void remove_proc_file(void) {} + +#endif + +/*-------------------------------------------------------------------------*/ + +/* Before this controller can enumerate, we need to pick an endpoint + * configuration, or "fifo_mode" That involves allocating 2KB of packet + * buffer space among the endpoints we'll be operating. + */ +static unsigned __init +omap_ep_setup(char *name, u8 addr, u8 type, + unsigned buf, unsigned maxp, int dbuf) +{ + struct omap_ep *ep; + u16 epn_rxtx = 0; + + /* OUT endpoints first, then IN */ + ep = &udc->ep[addr & 0xf]; + if (addr & USB_DIR_IN) + ep += 16; + + /* in case of ep init table bugs */ + BUG_ON(ep->name[0]); + + /* chip setup ... bit values are same for IN, OUT */ + if (type == USB_ENDPOINT_XFER_ISOC) { + switch (maxp) { + case 8: epn_rxtx = 0 << 12; break; + case 16: epn_rxtx = 1 << 12; break; + case 32: epn_rxtx = 2 << 12; break; + case 64: epn_rxtx = 3 << 12; break; + case 128: epn_rxtx = 4 << 12; break; + case 256: epn_rxtx = 5 << 12; break; + case 512: epn_rxtx = 6 << 12; break; + default: BUG(); + } + epn_rxtx |= UDC_EPN_RX_ISO; + dbuf = 1; + } else { + /* pio-out could potentially double-buffer, + * as can (should!) DMA-IN + */ + if (!use_dma || (addr & USB_DIR_IN)) + dbuf = 0; + + switch (maxp) { + case 8: epn_rxtx = 0 << 12; break; + case 16: epn_rxtx = 1 << 12; break; + case 32: epn_rxtx = 2 << 12; break; + case 64: epn_rxtx = 3 << 12; break; + default: BUG(); + } + if (dbuf && addr) + epn_rxtx |= UDC_EPN_RX_DB; + } + if (addr) + epn_rxtx |= UDC_EPN_RX_VALID; + BUG_ON(buf & 0x07); + epn_rxtx |= buf >> 3; + + DBG("%s addr %02x rxtx %04x maxp %d%s buf %d\n", + name, addr, epn_rxtx, maxp, dbuf ? "x2" : "", buf); + + if (addr & USB_DIR_IN) + UDC_EP_TX_REG(addr & 0xf) = epn_rxtx; + else + UDC_EP_RX_REG(addr) = epn_rxtx; + + /* next endpoint's buffer starts after this one's */ + buf += maxp; + if (dbuf) + buf += maxp; + BUG_ON(buf > 2048); + + /* set up driver data structures */ + BUG_ON(strlen(name) >= sizeof ep->name); + strlcpy(ep->name, name, sizeof ep->name); + INIT_LIST_HEAD(&ep->queue); + INIT_LIST_HEAD(&ep->iso); + ep->bEndpointAddress = addr; + ep->bmAttributes = type; + ep->double_buf = dbuf; + ep->udc = udc; + + ep->ep.name = ep->name; + ep->ep.ops = &omap_ep_ops; + ep->ep.maxpacket = ep->maxpacket = maxp; + list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list); + + return buf; +} + +static void omap_udc_release(struct device *dev) +{ + complete(udc->done); + kfree (udc); + udc = 0; +} + +static int __init +omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) +{ + unsigned tmp, buf; + + /* abolish any previous hardware state */ + UDC_SYSCON1_REG = 0; + UDC_IRQ_EN_REG = 0; + UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK; + UDC_DMA_IRQ_EN_REG = 0; + UDC_RXDMA_CFG_REG = 0; + UDC_TXDMA_CFG_REG = 0; + + /* UDC_PULLUP_EN gates the chip clock */ + // OTG_SYSCON_1_REG |= DEV_IDLE_EN; + + udc = kmalloc (sizeof *udc, SLAB_KERNEL); + if (!udc) + return -ENOMEM; + + memset(udc, 0, sizeof *udc); + spin_lock_init (&udc->lock); + + udc->gadget.ops = &omap_gadget_ops; + udc->gadget.ep0 = &udc->ep[0].ep; + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->iso); + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.name = driver_name; + + device_initialize(&udc->gadget.dev); + strcpy (udc->gadget.dev.bus_id, "gadget"); + udc->gadget.dev.release = omap_udc_release; + udc->gadget.dev.parent = &odev->dev; + if (use_dma) + udc->gadget.dev.dma_mask = odev->dev.dma_mask; + + udc->transceiver = xceiv; + + /* ep0 is special; put it right after the SETUP buffer */ + buf = omap_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, + 8 /* after SETUP */, 64 /* maxpacket */, 0); + list_del_init(&udc->ep[0].ep.ep_list); + + /* initially disable all non-ep0 endpoints */ + for (tmp = 1; tmp < 15; tmp++) { + UDC_EP_RX_REG(tmp) = 0; + UDC_EP_TX_REG(tmp) = 0; + } + +#define OMAP_BULK_EP(name,addr) \ + buf = omap_ep_setup(name "-bulk", addr, \ + USB_ENDPOINT_XFER_BULK, buf, 64, 1); +#define OMAP_INT_EP(name,addr, maxp) \ + buf = omap_ep_setup(name "-int", addr, \ + USB_ENDPOINT_XFER_INT, buf, maxp, 0); +#define OMAP_ISO_EP(name,addr, maxp) \ + buf = omap_ep_setup(name "-iso", addr, \ + USB_ENDPOINT_XFER_ISOC, buf, maxp, 1); + + switch (fifo_mode) { + case 0: + OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); + OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_INT_EP("ep3in", USB_DIR_IN | 3, 16); + break; + case 1: + OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); + OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_BULK_EP("ep3in", USB_DIR_IN | 3); + OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4); + + OMAP_BULK_EP("ep5in", USB_DIR_IN | 5); + OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); + OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); + OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6); + + OMAP_BULK_EP("ep7in", USB_DIR_IN | 7); + OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); + OMAP_BULK_EP("ep8in", USB_DIR_IN | 8); + OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8); + + OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); + OMAP_INT_EP("ep10out", USB_DIR_IN | 10, 16); + OMAP_INT_EP("ep11in", USB_DIR_IN | 9, 16); + OMAP_INT_EP("ep12out", USB_DIR_IN | 10, 16); + break; + +#ifdef USE_ISO + case 2: /* mixed iso/bulk */ + OMAP_ISO_EP("ep1in", USB_DIR_IN | 1, 256); + OMAP_ISO_EP("ep2out", USB_DIR_OUT | 2, 256); + OMAP_ISO_EP("ep3in", USB_DIR_IN | 3, 128); + OMAP_ISO_EP("ep4out", USB_DIR_OUT | 4, 128); + + OMAP_INT_EP("ep5in", USB_DIR_IN | 5, 16); + + OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); + OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); + OMAP_INT_EP("ep8in", USB_DIR_IN | 8, 16); + break; + case 3: /* mixed bulk/iso */ + OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); + OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_INT_EP("ep3in", USB_DIR_IN | 3, 16); + + OMAP_BULK_EP("ep4in", USB_DIR_IN | 4); + OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); + OMAP_INT_EP("ep6in", USB_DIR_IN | 6, 16); + + OMAP_ISO_EP("ep7in", USB_DIR_IN | 7, 256); + OMAP_ISO_EP("ep8out", USB_DIR_OUT | 8, 256); + OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); + break; +#endif + + /* add more modes as needed */ + + default: + ERR("unsupported fifo_mode #%d\n", fifo_mode); + return -ENODEV; + } + UDC_SYSCON1_REG = UDC_CFG_LOCK|UDC_SELF_PWR; + INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf); + return 0; +} + +static int __init omap_udc_probe(struct device *dev) +{ + struct platform_device *odev = to_platform_device(dev); + int status = -ENODEV; + int hmc; + struct otg_transceiver *xceiv = 0; + const char *type = 0; + struct omap_usb_config *config = dev->platform_data; + + /* NOTE: "knows" the order of the resources! */ + if (!request_mem_region(odev->resource[0].start, + odev->resource[0].end - odev->resource[0].start + 1, + driver_name)) { + DBG("request_mem_region failed\n"); + return -EBUSY; + } + + INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n", + UDC_REV_REG >> 4, UDC_REV_REG & 0xf, + OTG_REV_REG >> 4, OTG_REV_REG & 0xf, + config->otg ? "Mini-AB" : "B/Mini-B"); + + /* use the mode given to us by board init code */ + hmc = HMC; + switch (hmc) { + case 3: + case 11: + case 19: + case 25: + xceiv = otg_get_transceiver(); + if (!xceiv) { + DBG("external transceiver not registered!\n"); + goto cleanup0; + } + type = xceiv->label; + break; + case 0: /* POWERUP DEFAULT == 0 */ + case 4: + case 12: + case 20: + type = "INTEGRATED"; + break; + case 21: /* internal loopback */ + type = "(loopback)"; + break; + case 14: /* transceiverless */ + type = "(none)"; + break; + + default: + ERR("unrecognized UDC HMC mode %d\n", hmc); + return -ENODEV; + } + INFO("hmc mode %d, transceiver %s\n", hmc, type); + + /* a "gadget" abstracts/virtualizes the controller */ + status = omap_udc_setup(odev, xceiv); + if (status) { + goto cleanup0; + } + xceiv = 0; + // "udc" is now valid + pullup_disable(udc); + udc->gadget.is_otg = (config->otg != 0); + + /* USB general purpose IRQ: ep0, state changes, dma, etc */ + status = request_irq(odev->resource[1].start, omap_udc_irq, + SA_SAMPLE_RANDOM, driver_name, udc); + if (status != 0) { + ERR( "can't get irq %ld, err %d\n", + odev->resource[1].start, status); + goto cleanup1; + } + + /* USB "non-iso" IRQ (PIO for all but ep0) */ + status = request_irq(odev->resource[2].start, omap_udc_pio_irq, + SA_SAMPLE_RANDOM, "omap_udc pio", udc); + if (status != 0) { + ERR( "can't get irq %ld, err %d\n", + odev->resource[2].start, status); + goto cleanup2; + } +#ifdef USE_ISO + status = request_irq(odev->resource[3].start, omap_udc_iso_irq, + SA_INTERRUPT, "omap_udc iso", udc); + if (status != 0) { + ERR("can't get irq %ld, err %d\n", + odev->resource[3].start, status); + goto cleanup3; + } +#endif + + create_proc_file(); + device_add(&udc->gadget.dev); + return 0; + +#ifdef USE_ISO +cleanup3: + free_irq(odev->resource[2].start, udc); +#endif + +cleanup2: + free_irq(odev->resource[1].start, udc); + +cleanup1: + kfree (udc); + udc = 0; + +cleanup0: + if (xceiv) + put_device(xceiv->dev); + release_mem_region(odev->resource[0].start, + odev->resource[0].end - odev->resource[0].start + 1); + return status; +} + +static int __exit omap_udc_remove(struct device *dev) +{ + struct platform_device *odev = to_platform_device(dev); + DECLARE_COMPLETION(done); + + if (!udc) + return -ENODEV; + + udc->done = &done; + + pullup_disable(udc); + if (udc->transceiver) { + put_device(udc->transceiver->dev); + udc->transceiver = 0; + } + UDC_SYSCON1_REG = 0; + + remove_proc_file(); + +#ifdef USE_ISO + free_irq(odev->resource[3].start, udc); +#endif + free_irq(odev->resource[2].start, udc); + free_irq(odev->resource[1].start, udc); + + release_mem_region(odev->resource[0].start, + odev->resource[0].end - odev->resource[0].start + 1); + + device_unregister(&udc->gadget.dev); + wait_for_completion(&done); + + return 0; +} + +/* suspend/resume/wakeup from sysfs (echo > power/state) */ + +static int omap_udc_suspend(struct device *dev, u32 state, u32 level) +{ + if (level != 0) + return 0; + + DBG("suspend, state %d\n", state); + omap_pullup(&udc->gadget, 0); + udc->gadget.dev.power.power_state = 3; + udc->gadget.dev.parent->power.power_state = 3; + return 0; +} + +static int omap_udc_resume(struct device *dev, u32 level) +{ + if (level != 0) + return 0; + + DBG("resume + wakeup/SRP\n"); + udc->gadget.dev.parent->power.power_state = 0; + udc->gadget.dev.power.power_state = 0; + omap_pullup(&udc->gadget, 1); + + /* maybe the host would enumerate us if we nudged it */ + msleep(100); + return omap_wakeup(&udc->gadget); +} + +/*-------------------------------------------------------------------------*/ + +static struct device_driver udc_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = omap_udc_probe, + .remove = __exit_p(omap_udc_remove), + .suspend = omap_udc_suspend, + .resume = omap_udc_resume, +}; + +static int __init udc_init(void) +{ + /* should work on many OMAP systems with at most minor changes, + * but the 1510 doesn't have an OTG controller. + */ + if (cpu_is_omap1510()) { + DBG("no OMAP1510 support yet\n"); + return -ENODEV; + } + INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc, + use_dma ? " (dma)" : ""); + return driver_register(&udc_driver); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + diff -Nru a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/gadget/omap_udc.h 2004-10-18 14:57:23 -07:00 @@ -0,0 +1,199 @@ +/* + * omap_udc.h -- for omap 3.2 udc, with OTG support + * + * 2004 (C) Texas Instruments, Inc. + * 2004 (C) David Brownell + */ + +/* + * USB device/endpoint management registers + */ +#define UDC_REG(offset) __REG16(UDC_BASE + (offset)) + +#define UDC_REV_REG UDC_REG(0x0) /* Revision */ +#define UDC_EP_NUM_REG UDC_REG(0x4) /* Which endpoint */ +# define UDC_SETUP_SEL (1 << 6) +# define UDC_EP_SEL (1 << 5) +# define UDC_EP_DIR (1 << 4) + /* low 4 bits for endpoint number */ +#define UDC_DATA_REG UDC_REG(0x08) /* Endpoint FIFO */ +#define UDC_CTRL_REG UDC_REG(0x0C) /* Endpoint control */ +# define UDC_CLR_HALT (1 << 7) +# define UDC_SET_HALT (1 << 6) +# define UDC_SET_FIFO_EN (1 << 2) +# define UDC_CLR_EP (1 << 1) +# define UDC_RESET_EP (1 << 0) +#define UDC_STAT_FLG_REG UDC_REG(0x10) /* Endpoint status */ +# define UDC_NO_RXPACKET (1 << 15) +# define UDC_MISS_IN (1 << 14) +# define UDC_DATA_FLUSH (1 << 13) +# define UDC_ISO_ERR (1 << 12) +# define UDC_ISO_FIFO_EMPTY (1 << 9) +# define UDC_ISO_FIFO_FULL (1 << 8) +# define UDC_EP_HALTED (1 << 6) +# define UDC_STALL (1 << 5) +# define UDC_NAK (1 << 4) +# define UDC_ACK (1 << 3) +# define UDC_FIFO_EN (1 << 2) +# define UDC_NON_ISO_FIFO_EMPTY (1 << 1) +# define UDC_NON_ISO_FIFO_FULL (1 << 0) +#define UDC_RXFSTAT_REG UDC_REG(0x14) /* OUT bytecount */ +#define UDC_SYSCON1_REG UDC_REG(0x18) /* System config 1 */ +# define UDC_CFG_LOCK (1 << 8) +# define UDC_DATA_ENDIAN (1 << 7) +# define UDC_DMA_ENDIAN (1 << 6) +# define UDC_NAK_EN (1 << 4) +# define UDC_AUTODECODE_DIS (1 << 3) +# define UDC_SELF_PWR (1 << 2) +# define UDC_SOFF_DIS (1 << 1) +# define UDC_PULLUP_EN (1 << 0) +#define UDC_SYSCON2_REG UDC_REG(0x1C) /* System config 2 */ +# define UDC_RMT_WKP (1 << 6) +# define UDC_STALL_CMD (1 << 5) +# define UDC_DEV_CFG (1 << 3) +# define UDC_CLR_CFG (1 << 2) +#define UDC_DEVSTAT_REG UDC_REG(0x20) /* Device status */ +# define UDC_B_HNP_ENABLE (1 << 9) +# define UDC_A_HNP_SUPPORT (1 << 8) +# define UDC_A_ALT_HNP_SUPPORT (1 << 7) +# define UDC_R_WK_OK (1 << 6) +# define UDC_USB_RESET (1 << 5) +# define UDC_SUS (1 << 4) +# define UDC_CFG (1 << 3) +# define UDC_ADD (1 << 2) +# define UDC_DEF (1 << 1) +# define UDC_ATT (1 << 0) +#define UDC_SOF_REG UDC_REG(0x24) /* Start of frame */ +# define UDC_FT_LOCK (1 << 12) +# define UDC_TS_OK (1 << 11) +# define UDC_TS 0x03ff +#define UDC_IRQ_EN_REG UDC_REG(0x28) /* Interrupt enable */ +# define UDC_SOF_IE (1 << 7) +# define UDC_EPN_RX_IE (1 << 5) +# define UDC_EPN_TX_IE (1 << 4) +# define UDC_DS_CHG_IE (1 << 3) +# define UDC_EP0_IE (1 << 0) +#define UDC_DMA_IRQ_EN_REG UDC_REG(0x2C) /* DMA irq enable */ + /* rx/tx dma channels numbered 1-3 not 0-2 */ +# define UDC_TX_DONE_IE(n) (1 << (4 * (n) - 2)) +# define UDC_RX_CNT_IE(n) (1 << (4 * (n) - 3)) +# define UDC_RX_EOT_IE(n) (1 << (4 * (n) - 4)) +#define UDC_IRQ_SRC_REG UDC_REG(0x30) /* Interrupt source */ +# define UDC_TXN_DONE (1 << 10) +# define UDC_RXN_CNT (1 << 9) +# define UDC_RXN_EOT (1 << 8) +# define UDC_SOF (1 << 7) +# define UDC_EPN_RX (1 << 5) +# define UDC_EPN_TX (1 << 4) +# define UDC_DS_CHG (1 << 3) +# define UDC_SETUP (1 << 2) +# define UDC_EP0_RX (1 << 1) +# define UDC_EP0_TX (1 << 0) +# define UDC_IRQ_SRC_MASK 0x7bf +#define UDC_EPN_STAT_REG UDC_REG(0x34) /* EP irq status */ +#define UDC_DMAN_STAT_REG UDC_REG(0x38) /* DMA irq status */ +# define UDC_DMA_RX_SB (1 << 12) +# define UDC_DMA_RX_SRC(x) (((x)>>8) & 0xf) +# define UDC_DMA_TX_SRC(x) (((x)>>0) & 0xf) + + +/* DMA configuration registers: up to three channels in each direction. */ +#define UDC_RXDMA_CFG_REG UDC_REG(0x40) /* 3 eps for RX DMA */ +#define UDC_TXDMA_CFG_REG UDC_REG(0x44) /* 3 eps for TX DMA */ +#define UDC_DATA_DMA_REG UDC_REG(0x48) /* rx/tx fifo addr */ + +/* rx/tx dma control, numbering channels 1-3 not 0-2 */ +#define UDC_TXDMA_REG(chan) UDC_REG(0x50 - 4 + 4 * (chan)) +# define UDC_TXN_EOT (1 << 15) /* bytes vs packets */ +# define UDC_TXN_START (1 << 14) /* start transfer */ +# define UDC_TXN_TSC 0x03ff /* units in xfer */ +#define UDC_RXDMA_REG(chan) UDC_REG(0x60 - 4 + 4 * (chan)) +# define UDC_RXN_STOP (1 << 15) /* enable EOT irq */ +# define UDC_RXN_TC 0x00ff /* packets in xfer */ + + +/* + * Endpoint configuration registers (used before CFG_LOCK is set) + * UDC_EP_TX_REG(0) is unused + */ +#define UDC_EP_RX_REG(endpoint) UDC_REG(0x80 + (endpoint)*4) +# define UDC_EPN_RX_VALID (1 << 15) +# define UDC_EPN_RX_DB (1 << 14) + /* buffer size in bits 13, 12 */ +# define UDC_EPN_RX_ISO (1 << 11) + /* buffer pointer in low 11 bits */ +#define UDC_EP_TX_REG(endpoint) UDC_REG(0xc0 + (endpoint)*4) + /* same bitfields as in RX_REG */ + +/*-------------------------------------------------------------------------*/ + +struct omap_req { + struct usb_request req; + struct list_head queue; + unsigned dma_bytes; + unsigned mapped:1; +}; + +struct omap_ep { + struct usb_ep ep; + struct list_head queue; + unsigned long irqs; + struct list_head iso; + const struct usb_endpoint_descriptor *desc; + char name[14]; + u16 maxpacket; + u8 bEndpointAddress; + u8 bmAttributes; + unsigned double_buf:1; + unsigned stopped:1; + unsigned ackwait:1; + unsigned has_dma:1; + u8 dma_channel; + int lch; + struct omap_udc *udc; +}; + +struct omap_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + spinlock_t lock; + struct omap_ep ep[32]; + u16 devstat; + struct otg_transceiver *transceiver; + struct list_head iso; + unsigned softconnect:1; + unsigned vbus_active:1; + unsigned ep0_pending:1; + unsigned ep0_in:1; + unsigned ep0_set_config:1; + unsigned ep0_reset_config:1; + unsigned ep0_setup:1; + unsigned hmc:6; + + struct completion *done; +}; + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff) +#else +#define DBG(stuff...) do{}while(0) +#endif + +#ifdef VERBOSE +# define VDBG DBG +#else +# define VDBG(stuff...) do{}while(0) +#endif + +#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) +#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) +#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) + +/*-------------------------------------------------------------------------*/ + +// #define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f) +#define HMC_1610 (OTG_SYSCON_2_REG & 0x3f) +#define HMC HMC_1610 + diff -Nru a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c --- a/drivers/usb/gadget/pxa2xx_udc.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/gadget/pxa2xx_udc.c 2004-10-18 14:56:33 -07:00 @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -116,7 +117,7 @@ #ifdef USE_DMA static int use_dma = 1; -MODULE_PARM (use_dma, "i"); +module_param(use_dma, bool, 0); MODULE_PARM_DESC (use_dma, "true to use dma"); static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r); @@ -146,7 +147,7 @@ * ... so mode = 3 (or 7, 15, etc) does it for both */ static ushort fifo_mode = 0; -MODULE_PARM (fifo_mode, "h"); +module_param(fifo_mode, ushort, 0); MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode"); #endif @@ -1508,7 +1509,7 @@ /* caller must be able to sleep in order to cope * with startup transients. */ - schedule_timeout(HZ/10); + msleep(100); /* enable suspend/resume and reset irqs */ udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM); diff -Nru a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c --- a/drivers/usb/gadget/serial.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/gadget/serial.c 2004-10-18 14:56:49 -07:00 @@ -48,6 +48,8 @@ #include #include +#include "gadget_chips.h" + /* Wait Cond */ @@ -123,8 +125,8 @@ /* Defines */ -#define GS_VERSION_STR "v0.1" -#define GS_VERSION_NUM 0x0001 +#define GS_VERSION_STR "v1.0" +#define GS_VERSION_NUM 0x0100 #define GS_LONG_NAME "Gadget Serial" #define GS_SHORT_NAME "g_serial" @@ -173,164 +175,6 @@ #endif /* G_SERIAL_DEBUG */ -/* USB Controllers */ - -/* - * NetChip 2280, PCI based. - * - * This has half a dozen configurable endpoints, four with dedicated - * DMA channels to manage their FIFOs. It supports high speed. - * Those endpoints can be arranged in any desired configuration. - */ -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define EP0_MAXPACKET 64 -static const char EP_OUT_NAME[] = "ep-a"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME[] = "ep-b"; -#define EP_IN_NUM 2 -#define HIGHSPEED -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode); - -static inline void hw_optimize(struct usb_gadget *gadget) -{ - /* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets - * for highspeed bulk) because we're not using ep-c/ep-d. - */ - net2280_set_fifo_mode (gadget, 1); -} -#endif - - -/* - * Dummy_hcd, software-based loopback controller. - * - * This imitates the abilities of the NetChip 2280, so we will use - * the same configuration. - */ -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -#define CHIP "dummy" -#define EP0_MAXPACKET 64 -static const char EP_OUT_NAME[] = "ep-a"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME[] = "ep-b"; -#define EP_IN_NUM 2 -#define HIGHSPEED -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - - -/* - * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. - * - * This has fifteen fixed-function full speed endpoints, and it - * can support all USB transfer types. - * - * These supports three or four configurations, with fixed numbers. - * The hardware interprets SET_INTERFACE, net effect is that you - * can't use altsettings or reset the interfaces independently. - * So stick to a single interface. - */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx" -#define EP0_MAXPACKET 16 -static const char EP_OUT_NAME[] = "ep2out-bulk"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME[] = "ep1in-bulk"; -#define EP_IN_NUM 1 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define CHIP "omap" -#define EP0_MAXPACKET 64 -static const char EP_OUT_NAME [] = "ep2out-bulk"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME [] = "ep1in-bulk"; -#define EP_IN_NUM 1 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* supports remote wakeup, but this driver doesn't */ - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - - -/* - * SA-1100 UDC: widely used in first gen Linux-capable PDAs. - * - * This has only two fixed function endpoints, which can only - * be used for bulk (or interrupt) transfers. (Plus control.) - * - * Since it can't flush its TX fifos without disabling the UDC, - * the current configuration or altsettings can't change except - * in special situations. So this is a case of "choose it right - * during enumeration" ... - */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#define EP0_MAXPACKET 8 -static const char EP_OUT_NAME[] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2in-bulk"; -#define EP_IN_NUM 2 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - - -/* - * Toshiba TC86C001 ("Goku-S") UDC - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0116 -#define EP0_MAXPACKET 8 -static const char EP_OUT_NAME [] = "ep1-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2-bulk"; -#define EP_IN_NUM 2 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - -/* - * USB Controller Defaults - */ -#ifndef EP0_MAXPACKET -#error Configure some USB peripheral controller for g_serial! -#endif - -#ifndef SELFPOWER -/* default: say we rely on bus power */ -#define SELFPOWER 0 -/* else value must be USB_CONFIG_ATT_SELFPOWER */ -#endif - -#ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ -#endif /* Thanks to NetChip Technologies for donating this product ID. * @@ -449,11 +293,17 @@ static unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count); +/* external functions */ +extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode); + /* Globals */ static struct gs_dev *gs_device; +static const char *EP_IN_NAME; +static const char *EP_OUT_NAME; + static struct semaphore gs_open_close_sem[GS_NUM_PORTS]; static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE; @@ -483,7 +333,7 @@ /* gadget driver struct */ static struct usb_gadget_driver gs_gadget_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, @@ -510,8 +360,9 @@ #define GS_CONFIG_STR_ID 4 /* static strings, in iso 8859/1 */ +static char manufacturer[40]; static struct usb_string gs_strings[] = { - { GS_MANUFACTURER_STR_ID, UTS_SYSNAME " " UTS_RELEASE " with " CHIP }, + { GS_MANUFACTURER_STR_ID, manufacturer }, { GS_PRODUCT_STR_ID, GS_LONG_NAME }, { GS_SERIAL_STR_ID, "0" }, { GS_CONFIG_STR_ID, "Bulk" }, @@ -523,15 +374,13 @@ .strings = gs_strings, }; -static const struct usb_device_descriptor gs_device_desc = { +static struct usb_device_descriptor gs_device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .bMaxPacketSize0 = EP0_MAXPACKET, .idVendor = __constant_cpu_to_le16(GS_VENDOR_ID), .idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID), - .bcdDevice = __constant_cpu_to_le16(GS_VERSION_NUM), .iManufacturer = GS_MANUFACTURER_STR_ID, .iProduct = GS_PRODUCT_STR_ID, .iSerialNumber = GS_SERIAL_STR_ID, @@ -545,8 +394,8 @@ .bNumInterfaces = GS_NUM_INTERFACES, .bConfigurationValue = GS_BULK_CONFIG_ID, .iConfiguration = GS_CONFIG_STR_ID, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, }; static const struct usb_interface_descriptor gs_interface_desc = { @@ -557,46 +406,41 @@ .iInterface = GS_CONFIG_STR_ID, }; -static const struct usb_endpoint_descriptor gs_fullspeed_in_desc = { +static struct usb_endpoint_descriptor gs_fullspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), }; -static const struct usb_endpoint_descriptor gs_fullspeed_out_desc = { +static struct usb_endpoint_descriptor gs_fullspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM | USB_DIR_OUT, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), }; -static const struct usb_endpoint_descriptor gs_highspeed_in_desc = { +static struct usb_endpoint_descriptor gs_highspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static const struct usb_endpoint_descriptor gs_highspeed_out_desc = { +static struct usb_endpoint_descriptor gs_highspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -#ifdef HIGHSPEED -static const struct usb_qualifier_descriptor gs_qualifier_desc = { +#ifdef CONFIG_USB_GADGET_DUALSPEED +static struct usb_qualifier_descriptor gs_qualifier_desc = { .bLength = sizeof(struct usb_qualifier_descriptor), .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, /* assumes ep0 uses the same value for both speeds ... */ - .bMaxPacketSize0 = EP0_MAXPACKET, .bNumConfigurations = GS_NUM_CONFIGS, }; #endif @@ -608,17 +452,17 @@ MODULE_LICENSE("GPL"); #if G_SERIAL_DEBUG -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on, larger values for more messages"); #endif -MODULE_PARM(read_q_size, "i"); +module_param(read_q_size, int, 0); MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32"); -MODULE_PARM(write_q_size, "i"); +module_param(write_q_size, int, 0); MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32"); -MODULE_PARM(write_buf_size, "i"); +module_param(write_buf_size, int, 0); MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192"); module_init(gs_module_init); @@ -1416,18 +1260,81 @@ static int gs_bind(struct usb_gadget *gadget) { int ret; + struct usb_ep *ep; struct gs_dev *dev; + usb_ep_autoconfig_reset(gadget); + + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); + if (!ep) + goto autoconf_fail; + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + + /* device specific bcdDevice value in device descriptor */ + if (gadget_is_net2280(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0001); + } else if (gadget_is_pxa(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0002); + } else if (gadget_is_sh(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0003); + } else if (gadget_is_sa1100(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0004); + } else if (gadget_is_goku(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0005); + } else if (gadget_is_mq11xx(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0006); + } else if (gadget_is_omap(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0007); + } else if (gadget_is_lh7a40x(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0008); + } else { + printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", + gadget->name); + /* unrecognized, but safe unless bulk is REALLY quirky */ + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0099); + } + + gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; +#endif /* CONFIG_USB_GADGET_DUALSPEED */ + + usb_gadget_set_selfpowered(gadget); + gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; - set_gadget_data(gadget, dev); + snprintf (manufacturer, sizeof(manufacturer), + UTS_SYSNAME " " UTS_RELEASE " with %s", gadget->name); memset(dev, 0, sizeof(struct gs_dev)); dev->dev_gadget = gadget; spin_lock_init(&dev->dev_lock); INIT_LIST_HEAD(&dev->dev_req_list); + set_gadget_data(gadget, dev); if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) { printk(KERN_ERR "gs_bind: cannot allocate ports\n"); @@ -1450,6 +1357,10 @@ GS_LONG_NAME, GS_VERSION_STR); return 0; + +autoconf_fail: + printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name); + return -ENODEV; } /* @@ -1505,15 +1416,17 @@ memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; ret = min(ctrl->wLength, (u16)sizeof(struct usb_qualifier_descriptor)); memcpy(req->buf, &gs_qualifier_desc, ret); break; case USB_DT_OTHER_SPEED_CONFIG: -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: ret = gs_build_config_desc(req->buf, gadget->speed, ctrl->wValue >> 8, ctrl->wValue & 0xff); @@ -1677,7 +1590,9 @@ if (config != GS_BULK_CONFIG_ID) return -EINVAL; - hw_optimize(gadget); + /* device specific optimizations */ + if (gadget_is_net2280(gadget)) + net2280_set_fifo_mode(gadget, 1); gadget_for_each_ep(ep, gadget) { diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/gadget/zero.c 2004-10-18 14:56:29 -07:00 @@ -399,7 +399,7 @@ static char manufacturer [40]; static char serial [40]; -/* static strings, in iso 8859/1 */ +/* static strings, in UTF-8 */ static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, @@ -960,7 +960,8 @@ case USB_DT_STRING: /* wIndex == language code. * this driver only handles one language, you can - * add others even if they don't use iso8859/1 + * add string tables for other languages, using + * any UTF-8 characters */ value = usb_gadget_get_string (&stringtab, ctrl->wValue & 0xff, req->buf); @@ -1185,6 +1186,8 @@ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); } else if (gadget_is_omap (gadget)) { device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else if (gadget_is_lh7a40x(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209); } else { /* gadget zero is so simple (for now, no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. @@ -1229,6 +1232,12 @@ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif + + if (gadget->is_otg) { + otg_descriptor.bmAttributes |= USB_OTG_HNP, + source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } if (gadget->is_otg) { otg_descriptor.bmAttributes |= USB_OTG_HNP, diff -Nru a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig --- a/drivers/usb/host/Kconfig 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/host/Kconfig 2004-10-18 14:57:04 -07:00 @@ -52,6 +52,7 @@ config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB + select ISP1301_OMAP if MACH_OMAP_H2 ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/host/ehci-dbg.c 2004-10-18 14:56:49 -07:00 @@ -119,16 +119,16 @@ dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) { ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, - cpu_to_le32p (&qtd->hw_next), - cpu_to_le32p (&qtd->hw_alt_next), - cpu_to_le32p (&qtd->hw_token), - cpu_to_le32p (&qtd->hw_buf [0])); + le32_to_cpup (&qtd->hw_next), + le32_to_cpup (&qtd->hw_alt_next), + le32_to_cpup (&qtd->hw_token), + le32_to_cpup (&qtd->hw_buf [0])); if (qtd->hw_buf [1]) ehci_dbg (ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n", - cpu_to_le32p (&qtd->hw_buf [1]), - cpu_to_le32p (&qtd->hw_buf [2]), - cpu_to_le32p (&qtd->hw_buf [3]), - cpu_to_le32p (&qtd->hw_buf [4])); + le32_to_cpup (&qtd->hw_buf [1]), + le32_to_cpup (&qtd->hw_buf [2]), + le32_to_cpup (&qtd->hw_buf [3]), + le32_to_cpup (&qtd->hw_buf [4])); } static void __attribute__((__unused__)) @@ -331,14 +331,14 @@ default: tmp = '?'; break; \ }; tmp; }) -static inline char token_mark (u32 token) +static inline char token_mark (__le32 token) { - token = le32_to_cpu (token); - if (token & QTD_STS_ACTIVE) + __u32 v = le32_to_cpu (token); + if (v & QTD_STS_ACTIVE) return '*'; - if (token & QTD_STS_HALT) + if (v & QTD_STS_HALT) return '-'; - if (!IS_SHORT_READ (token)) + if (!IS_SHORT_READ (v)) return ' '; /* tries to advance through hw_alt_next */ return '/'; @@ -371,25 +371,25 @@ mark = '.'; /* use hw_qtd_next */ /* else alt_next points to some other qtd */ } - scratch = cpu_to_le32p (&qh->hw_info1); - hw_curr = (mark == '*') ? cpu_to_le32p (&qh->hw_current) : 0; + scratch = le32_to_cpup (&qh->hw_info1); + hw_curr = (mark == '*') ? le32_to_cpup (&qh->hw_current) : 0; temp = scnprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)", qh, scratch & 0x007f, speed_char (scratch), (scratch >> 8) & 0x000f, - scratch, cpu_to_le32p (&qh->hw_info2), - cpu_to_le32p (&qh->hw_token), mark, + scratch, le32_to_cpup (&qh->hw_info2), + le32_to_cpup (&qh->hw_token), mark, (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) ? "data1" : "data0", - (cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f); + (le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f); size -= temp; next += temp; /* hc may be modifying the list as we read it ... */ list_for_each (entry, &qh->qtd_list) { td = list_entry (entry, struct ehci_qtd, qtd_list); - scratch = cpu_to_le32p (&td->hw_token); + scratch = le32_to_cpup (&td->hw_token); mark = ' '; if (hw_curr == td->qtd_dma) mark = '*'; @@ -488,7 +488,8 @@ union ehci_shadow p, *seen; unsigned temp, size, seen_count; char *next; - unsigned i, tag; + unsigned i; + __le32 tag; if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) return 0; @@ -541,7 +542,7 @@ } /* show more info the first time around */ if (temp == seen_count && p.ptr) { - u32 scratch = cpu_to_le32p ( + u32 scratch = le32_to_cpup ( &p.qh->hw_info1); struct ehci_qtd *qtd; char *type = ""; diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/host/ehci-hcd.c 2004-10-18 14:56:33 -07:00 @@ -155,7 +155,7 @@ * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (u32 *ptr, u32 mask, u32 done, int usec) +static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -289,7 +289,7 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) { if (cap & (1 << 16)) { - int msec = 500; + int msec = 5000; struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller); /* request handoff to OS */ @@ -305,7 +305,10 @@ if (cap & (1 << 16)) { ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); - return 1; + // some BIOS versions seem buggy... + // return 1; + ehci_warn (ehci, "continuing after BIOS bug...\n"); + return 0; } ehci_dbg (ehci, "BIOS handoff succeeded\n"); } @@ -337,8 +340,8 @@ spin_lock_init (&ehci->lock); - ehci->caps = (struct ehci_caps *) hcd->regs; - ehci->regs = (struct ehci_regs *) (hcd->regs + + ehci->caps = hcd->regs; + ehci->regs = (hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase))); dbg_hcs_params (ehci, "reset"); dbg_hcc_params (ehci, "reset"); @@ -692,9 +695,18 @@ timer_action_done (ehci, TIMER_IO_WATCHDOG); if (ehci->reclaim_ready) end_unlink_async (ehci, regs); + + /* another CPU may drop ehci->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (ehci->scanning) + return; + ehci->scanning = 1; scan_async (ehci, regs); if (ehci->next_uframe != -1) scan_periodic (ehci, regs); + ehci->scanning = 0; /* the IO watchdog guards against hardware or driver bugs that * misplace IRQs, and should let us run completely without IRQs. diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c --- a/drivers/usb/host/ehci-hub.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/host/ehci-hub.c 2004-10-18 14:57:04 -07:00 @@ -146,8 +146,8 @@ #else -#define ehci_hub_suspend 0 -#define ehci_hub_resume 0 +#define ehci_hub_suspend NULL +#define ehci_hub_resume NULL #endif /* CONFIG_PM */ @@ -455,7 +455,7 @@ #endif dbg_port (ehci, "GetStatus", wIndex + 1, temp); // we "know" this alignment is good, caller used kmalloc()... - *((u32 *) buf) = cpu_to_le32 (status); + *((__le32 *) buf) = cpu_to_le32 (status); break; case SetHubFeature: switch (wValue) { diff -Nru a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c --- a/drivers/usb/host/ehci-mem.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/usb/host/ehci-mem.c 2004-10-18 14:57:03 -07:00 @@ -114,7 +114,7 @@ return qh; memset (qh, 0, sizeof *qh); - kref_init(&qh->kref, qh_destroy); + kref_init(&qh->kref); qh->ehci = ehci; qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); @@ -139,7 +139,7 @@ static inline void qh_put (struct ehci_qh *qh) { - kref_put(&qh->kref); + kref_put(&qh->kref, qh_destroy); } /*-------------------------------------------------------------------------*/ @@ -235,9 +235,9 @@ } /* Hardware periodic table */ - ehci->periodic = (u32 *) + ehci->periodic = (__le32 *) dma_alloc_coherent (ehci->hcd.self.controller, - ehci->periodic_size * sizeof (u32), + ehci->periodic_size * sizeof(__le32), &ehci->periodic_dma, 0); if (ehci->periodic == 0) { goto fail; diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/host/ehci-q.c 2004-10-18 14:56:49 -07:00 @@ -153,17 +153,9 @@ usb_pipein (urb->pipe) ? "in" : "out", token, urb->status); - /* stall indicates some recovery action is needed */ - if (urb->status == -EPIPE) { - int pipe = urb->pipe; - - if (!usb_pipecontrol (pipe)) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (pipe), - usb_pipeout (pipe)); - /* if async CSPLIT failed, try cleaning out the TT buffer */ - } else if (urb->dev->tt && !usb_pipeint (urb->pipe) + if (urb->status != -EPIPE + && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) && (!ehci_is_ARC(ehci) @@ -729,7 +721,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - u32 dma = QH_NEXT (qh->qh_dma); + __le32 dma = QH_NEXT (qh->qh_dma); struct ehci_qh *head; /* (re)start the async schedule? */ @@ -764,7 +756,7 @@ /*-------------------------------------------------------------------------*/ -#define QH_ADDR_MASK __constant_le32_to_cpu(0x7f) +#define QH_ADDR_MASK __constant_cpu_to_le32(0x7f) /* * For control/bulk/interrupt, return QH with these TDs appended. @@ -848,7 +840,7 @@ if (likely (qtd != 0)) { struct ehci_qtd *dummy; dma_addr_t dma; - u32 token; + __le32 token; /* to avoid racing the HC, use the dummy td instead of * the first td of our list (becomes new dummy). both diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/host/ehci-sched.c 2004-10-18 14:56:28 -07:00 @@ -44,7 +44,7 @@ * @tag: hardware tag for type of this record */ static union ehci_shadow * -periodic_next_shadow (union ehci_shadow *periodic, int tag) +periodic_next_shadow (union ehci_shadow *periodic, __le32 tag) { switch (tag) { case Q_TYPE_QH: @@ -64,7 +64,7 @@ static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) { union ehci_shadow *prev_p = &ehci->pshadow [frame]; - u32 *hw_p = &ehci->periodic [frame]; + __le32 *hw_p = &ehci->periodic [frame]; union ehci_shadow here = *prev_p; union ehci_shadow *next_p; @@ -98,7 +98,7 @@ static unsigned short periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) { - u32 *hw_p = &ehci->periodic [frame]; + __le32 *hw_p = &ehci->periodic [frame]; union ehci_shadow *q = &ehci->pshadow [frame]; unsigned usecs = 0; @@ -196,7 +196,7 @@ */ for (; frame < ehci->periodic_size; frame += period) { union ehci_shadow here; - u32 type; + __le32 type; here = ehci->pshadow [frame]; type = Q_NEXT_TYPE (ehci->periodic [frame]); @@ -403,7 +403,7 @@ unsigned frame, unsigned uframe, const struct ehci_qh *qh, - u32 *c_maskp + __le32 *c_maskp ) { int retval = -ENOSPC; @@ -412,7 +412,7 @@ goto done; if (!qh->c_usecs) { retval = 0; - *c_maskp = cpu_to_le32 (0); + *c_maskp = 0; goto done; } @@ -447,7 +447,7 @@ { int status; unsigned uframe; - u32 c_mask; + __le32 c_mask; unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ qh->hw_next = EHCI_LIST_END; @@ -1008,8 +1008,7 @@ uframe += period_uframes; } while (uframe < mod); - stream->splits = stream->raw_mask << (uframe & 7); - cpu_to_le32s (&stream->splits); + stream->splits = cpu_to_le32(stream->raw_mask << (uframe & 7)); return 1; } @@ -1812,7 +1811,7 @@ for (;;) { union ehci_shadow q, *q_p; - u32 type, *hw_p; + __le32 type, *hw_p; unsigned uframes; /* don't scan past the live uframe */ diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h --- a/drivers/usb/host/ehci.h 2004-10-18 14:56:50 -07:00 +++ b/drivers/usb/host/ehci.h 2004-10-18 14:56:50 -07:00 @@ -52,12 +52,13 @@ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; - int reclaim_ready : 1; + unsigned reclaim_ready : 1; + unsigned scanning : 1; /* periodic schedule support */ #define DEFAULT_I_TDPS 1024 /* some HCs can do less */ unsigned periodic_size; - u32 *periodic; /* hw periodic table */ + __le32 *periodic; /* hw periodic table */ dma_addr_t periodic_dma; unsigned i_thresh; /* uframes HC might cache */ @@ -70,9 +71,9 @@ /* glue to PCI and HCD framework */ struct usb_hcd hcd; - struct ehci_caps *caps; - struct ehci_regs *regs; - u32 hcs_params; /* cached register copy */ + struct ehci_caps __iomem *caps; + struct ehci_regs __iomem *regs; + __u32 hcs_params; /* cached register copy */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ @@ -272,9 +273,9 @@ */ struct ehci_qtd { /* first part defined by EHCI spec */ - u32 hw_next; /* see EHCI 3.5.1 */ - u32 hw_alt_next; /* see EHCI 3.5.2 */ - u32 hw_token; /* see EHCI 3.5.3 */ + __le32 hw_next; /* see EHCI 3.5.1 */ + __le32 hw_alt_next; /* see EHCI 3.5.2 */ + __le32 hw_token; /* see EHCI 3.5.3 */ #define QTD_TOGGLE (1 << 31) /* data toggle */ #define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) #define QTD_IOC (1 << 15) /* interrupt on complete */ @@ -288,8 +289,8 @@ #define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ #define QTD_STS_STS (1 << 1) /* split transaction state */ #define QTD_STS_PING (1 << 0) /* issue PING? */ - u32 hw_buf [5]; /* see EHCI 3.5.4 */ - u32 hw_buf_hi [5]; /* Appendix B */ + __le32 hw_buf [5]; /* see EHCI 3.5.4 */ + __le32 hw_buf_hi [5]; /* Appendix B */ /* the rest is HCD-private */ dma_addr_t qtd_dma; /* qtd address */ @@ -349,18 +350,18 @@ struct ehci_qh { /* first part defined by EHCI spec */ - u32 hw_next; /* see EHCI 3.6.1 */ - u32 hw_info1; /* see EHCI 3.6.2 */ + __le32 hw_next; /* see EHCI 3.6.1 */ + __le32 hw_info1; /* see EHCI 3.6.2 */ #define QH_HEAD 0x00008000 - u32 hw_info2; /* see EHCI 3.6.2 */ - u32 hw_current; /* qtd list - see EHCI 3.6.4 */ + __le32 hw_info2; /* see EHCI 3.6.2 */ + __le32 hw_current; /* qtd list - see EHCI 3.6.4 */ /* qtd overlay (hardware parts of a struct ehci_qtd) */ - u32 hw_qtd_next; - u32 hw_alt_next; - u32 hw_token; - u32 hw_buf [5]; - u32 hw_buf_hi [5]; + __le32 hw_qtd_next; + __le32 hw_alt_next; + __le32 hw_token; + __le32 hw_buf [5]; + __le32 hw_buf_hi [5]; /* the rest is HCD-private */ dma_addr_t qh_dma; /* address of qh */ @@ -396,7 +397,7 @@ struct ehci_iso_packet { /* These will be copied to iTD when scheduling */ u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ - u32 transaction; /* itd->hw_transaction[i] |= */ + __le32 transaction; /* itd->hw_transaction[i] |= */ u8 cross; /* buf crosses pages */ /* for full speed OUT splits */ u16 buf1; @@ -418,8 +419,8 @@ */ struct ehci_iso_stream { /* first two fields match QH, but info1 == 0 */ - u32 hw_next; - u32 hw_info1; + __le32 hw_next; + __le32 hw_info1; u32 refcount; u8 bEndpointAddress; @@ -433,7 +434,7 @@ unsigned long start; /* jiffies */ unsigned long rescheduled; int next_uframe; - u32 splits; + __le32 splits; /* the rest is derived from the endpoint descriptor, * trusting urb->interval == f(epdesc->bInterval) and @@ -446,12 +447,12 @@ unsigned bandwidth; /* This is used to initialize iTD's hw_bufp fields */ - u32 buf0; - u32 buf1; - u32 buf2; + __le32 buf0; + __le32 buf1; + __le32 buf2; /* this is used to initialize sITD's tt info */ - u32 address; + __le32 address; }; /*-------------------------------------------------------------------------*/ @@ -464,8 +465,8 @@ */ struct ehci_itd { /* first part defined by EHCI spec */ - u32 hw_next; /* see EHCI 3.3.1 */ - u32 hw_transaction [8]; /* see EHCI 3.3.2 */ + __le32 hw_next; /* see EHCI 3.3.1 */ + __le32 hw_transaction [8]; /* see EHCI 3.3.2 */ #define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ #define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */ #define EHCI_ISOC_BABBLE (1<<29) /* babble detected */ @@ -475,8 +476,8 @@ #define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE) - u32 hw_bufp [7]; /* see EHCI 3.3.3 */ - u32 hw_bufp_hi [7]; /* Appendix B */ + __le32 hw_bufp [7]; /* see EHCI 3.3.3 */ + __le32 hw_bufp_hi [7]; /* Appendix B */ /* the rest is HCD-private */ dma_addr_t itd_dma; /* for this itd */ @@ -503,11 +504,11 @@ */ struct ehci_sitd { /* first part defined by EHCI spec */ - u32 hw_next; + __le32 hw_next; /* uses bit field macros above - see EHCI 0.95 Table 3-8 */ - u32 hw_fullspeed_ep; /* EHCI table 3-9 */ - u32 hw_uframe; /* EHCI table 3-10 */ - u32 hw_results; /* EHCI table 3-11 */ + __le32 hw_fullspeed_ep; /* EHCI table 3-9 */ + __le32 hw_uframe; /* EHCI table 3-10 */ + __le32 hw_results; /* EHCI table 3-11 */ #define SITD_IOC (1 << 31) /* interrupt on completion */ #define SITD_PAGE (1 << 30) /* buffer 0/1 */ #define SITD_LENGTH(x) (0x3ff & ((x)>>16)) @@ -521,9 +522,9 @@ #define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE) - u32 hw_buf [2]; /* EHCI table 3-12 */ - u32 hw_backpointer; /* EHCI table 3-13 */ - u32 hw_buf_hi [2]; /* Appendix B */ + __le32 hw_buf [2]; /* EHCI table 3-12 */ + __le32 hw_backpointer; /* EHCI table 3-13 */ + __le32 hw_buf_hi [2]; /* Appendix B */ /* the rest is HCD-private */ dma_addr_t sitd_dma; @@ -548,8 +549,8 @@ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. */ struct ehci_fstn { - u32 hw_next; /* any periodic q entry */ - u32 hw_prev; /* qh or EHCI_LIST_END */ + __le32 hw_next; /* any periodic q entry */ + __le32 hw_prev; /* qh or EHCI_LIST_END */ /* the rest is HCD-private */ dma_addr_t fstn_dma; diff -Nru a/drivers/usb/host/hc_simple.c b/drivers/usb/host/hc_simple.c --- a/drivers/usb/host/hc_simple.c 2004-10-18 14:57:18 -07:00 +++ b/drivers/usb/host/hc_simple.c 2004-10-18 14:57:18 -07:00 @@ -146,11 +146,6 @@ if (!urb->dev || !urb->dev->bus || urb->hcpriv) return -EINVAL; - if (usb_endpoint_halted - (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) { - printk ("hci_submit_urb: endpoint_halted\n"); - return -EPIPE; - } hci = (hci_t *) urb->dev->bus->hcpriv; /* a request to the virtual root hub */ diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c --- a/drivers/usb/host/hc_sl811.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/host/hc_sl811.c 2004-10-18 14:56:49 -07:00 @@ -106,14 +106,14 @@ static int sofWaitCnt = 0; -MODULE_PARM (urb_debug, "i"); +module_param(urb_debug, int, 0); MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)"); -MODULE_PARM (base_addr, "i"); +module_param(base_addr, int, 0); MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000"); -MODULE_PARM (data_reg_addr, "i"); +module_param(data_reg_addr, int, 0); MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000"); -MODULE_PARM (irq, "i"); +module_param(irq, int, 0); MODULE_PARM_DESC (irq, "IRQ 34 (default)"); static int hc_reset (hci_t * hci); diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c --- a/drivers/usb/host/ohci-dbg.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/usb/host/ohci-dbg.c 2004-10-18 14:56:50 -07:00 @@ -131,7 +131,7 @@ static void ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) { - struct ohci_regs *regs = controller->regs; + struct ohci_regs __iomem *regs = controller->regs; u32 temp; temp = ohci_readl (®s->revision) & 0xff; @@ -336,7 +336,7 @@ ohci_dump_ed (const struct ohci_hcd *ohci, const char *label, const struct ed *ed, int verbose) { - u32 tmp = ed->hwINFO; + __le32 tmp = ed->hwINFO; char *type = ""; ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n", @@ -359,7 +359,7 @@ type, 0x007f & le32_to_cpu (tmp)); ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s\n", - tmp = le32_to_cpup (&ed->hwHeadP), + le32_to_cpup (&ed->hwHeadP), (ed->hwHeadP & ED_C) ? data1 : data0, (ed->hwHeadP & ED_H) ? " HALT" : "", le32_to_cpup (&ed->hwTailP), @@ -415,8 +415,8 @@ /* dump a snapshot of the bulk or control schedule */ while (ed) { - u32 info = ed->hwINFO; - u32 scratch = cpu_to_le32p (&ed->hwINFO); + __le32 info = ed->hwINFO; + u32 scratch = le32_to_cpup (&ed->hwINFO); struct list_head *entry; struct td *td; @@ -439,7 +439,7 @@ u32 cbp, be; td = list_entry (entry, struct td, td_list); - scratch = cpu_to_le32p (&td->hwINFO); + scratch = le32_to_cpup (&td->hwINFO); cbp = le32_to_cpup (&td->hwCBP); be = le32_to_cpup (&td->hwBE); temp = scnprintf (buf, size, @@ -541,8 +541,8 @@ /* show more info the first time around */ if (temp == seen_count) { - u32 info = ed->hwINFO; - u32 scratch = cpu_to_le32p (&ed->hwINFO); + __le32 info = ed->hwINFO; + u32 scratch = le32_to_cpup (&ed->hwINFO); struct list_head *entry; unsigned qlen = 0; @@ -599,7 +599,7 @@ struct usb_bus *bus; struct usb_hcd *hcd; struct ohci_hcd *ohci; - struct ohci_regs *regs; + struct ohci_regs __iomem *regs; unsigned long flags; unsigned temp, size; char *next; diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/host/ohci-hcd.c 2004-10-18 14:55:54 -07:00 @@ -97,6 +97,7 @@ #include #include /* for in_interrupt () */ #include +#include #include "../core/hcd.h" #include #include /* needed by ohci-mem.c when no PCI */ @@ -593,7 +594,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct ohci_regs *regs = ohci->regs; + struct ohci_regs __iomem *regs = ohci->regs; int ints; /* we can eliminate a (slow) ohci_readl() @@ -693,7 +694,7 @@ /* must not be called from interrupt context */ -#ifdef CONFIG_PM +#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) static void mark_children_gone (struct usb_device *dev) { diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c --- a/drivers/usb/host/ohci-hub.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/usb/host/ohci-hub.c 2004-10-18 14:55:55 -07:00 @@ -435,6 +435,89 @@ /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_OTG + +static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + u32 status; + + if (!port) + return -EINVAL; + port--; + + /* start port reset before HNP protocol times out */ + status = ohci_readl(&ohci->regs->roothub.portstatus [port]); + if (!(status & RH_PS_CCS)) + return -ENODEV; + + /* khubd will finish the reset later */ + writel(RH_PS_PRS, &ohci->regs->roothub.portstatus [port]); + return 0; +} + +static void start_hnp(struct ohci_hcd *ohci); + +#else + +#define ohci_start_port_reset NULL + +#endif + +/*-------------------------------------------------------------------------*/ + + +/* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling, + * not necessarily continuous ... to guard against resume signaling. + * The short timeout is safe for non-root hubs, and is backward-compatible + * with earlier Linux hosts. + */ +#ifdef CONFIG_USB_SUSPEND +#define PORT_RESET_MSEC 50 +#else +#define PORT_RESET_MSEC 10 +#endif + +/* this timer value might be vendor-specific ... */ +#define PORT_RESET_HW_MSEC 10 + +/* wrap-aware logic stolen from */ +#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) + +/* called from some task, normally khubd */ +static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) +{ + u32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; + u32 temp; + u16 now = readl(&ohci->regs->fmnumber); + u16 reset_done = now + PORT_RESET_MSEC; + + /* build a "continuous enough" reset signal, with up to + * 3msec gap between pulses. scheduler HZ==100 must work; + * this might need to be deadline-scheduled. + */ + do { + /* spin until any current reset finishes */ + for (;;) { + temp = ohci_readl (portstat); + if (!(temp & RH_PS_PRS)) + break; + udelay (500); + } + + if (!(temp & RH_PS_CCS)) + break; + if (temp & RH_PS_PRSC) + writel (RH_PS_PRSC, portstat); + + /* start the next reset, sleep till it's probably done */ + writel (RH_PS_PRS, portstat); + msleep(PORT_RESET_HW_MSEC); + now = readl(&ohci->regs->fmnumber); + } while (tick_before(now, reset_done)); + /* caller synchronizes using PRSC */ +} + static int ohci_hub_control ( struct usb_hcd *hcd, u16 typeReq, @@ -503,14 +586,14 @@ break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - *(u32 *) buf = cpu_to_le32 (temp); + *(__le32 *) buf = cpu_to_le32 (temp); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); - *(u32 *) buf = cpu_to_le32 (temp); + *(__le32 *) buf = cpu_to_le32 (temp); #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ @@ -533,6 +616,12 @@ wIndex--; switch (wValue) { case USB_PORT_FEAT_SUSPEND: +#ifdef CONFIG_USB_OTG + if (ohci->hcd.self.otg_port == (wIndex + 1) + && ohci->hcd.self.b_hnp_enable) + start_hnp(ohci); + else +#endif writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [wIndex]); break; @@ -541,10 +630,7 @@ &ohci->regs->roothub.portstatus [wIndex]); break; case USB_PORT_FEAT_RESET: - temp = ohci_readl (&ohci->regs->roothub.portstatus [wIndex]); - if (temp & RH_PS_CCS) - writel (RH_PS_PRS, - &ohci->regs->roothub.portstatus [wIndex]); + root_port_reset (ohci, wIndex); break; default: goto error; diff -Nru a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c --- a/drivers/usb/host/ohci-omap.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/usb/host/ohci-omap.c 2004-10-18 14:56:48 -07:00 @@ -2,27 +2,30 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2000-2004 David Brownell * (C) Copyright 2002 Hewlett-Packard Company * * OMAP Bus Glue * * Written by Christopher Hoover - * Based on fragments of previous driver by Rusell King et al. + * Based on fragments of previous driver by Russell King et al. * * Modified for OMAP from ohci-sa1111.c by Tony Lindgren * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc. * * This file is licenced under the GPL. */ - + #include #include +#include -#include #include #include #include +#include +#include +#include #include "ohci-omap.h" @@ -34,122 +37,53 @@ extern int ocpi_enable(void); /* - * Use the first port only by default. Override with hmc_mode option. - * - * NOTE: Many OMAP-1510 Innovators supposedly have bad wiring for the USB ports - * 1 & 2, so only port 0 will work. To use the OHCI on the first port, use - * the Innovator USB client cable with a client-to-client connector and modify - * either the cable or the hub to feed 5V VBUS back to Innovator. VBUS should - * be the red lead in the cable. - * - * To mount USB hard disk as root, see the patch for do_mounts.c that tries - * remounting the root, and use root=0801 if your root is on sda1. Does not - * work with devfs. - */ -static int default_hmc_mode = 16; -static int hmc_mode = 1234; - -/* - * Set the USB host pin multiplexing and the selected HMC mode - */ -static int omap_usb_set_hmc_mode(int hmc_mode) -{ - unsigned int val; - - switch (hmc_mode) { - case 0: - /* 0: function, 1: disabled, 2: disabled */ - omap_cfg_reg(W4_USB_PUEN); - omap_cfg_reg(R18_1510_USB_GPIO0); - break; - case 4: - /* 0: function 1: host 2: host */ - omap_cfg_reg(usb1_speed); - omap_cfg_reg(usb1_susp); - omap_cfg_reg(usb1_seo); - omap_cfg_reg(usb1_txen); - omap_cfg_reg(usb1_txd); - omap_cfg_reg(usb1_vp); - omap_cfg_reg(usb1_vm); - omap_cfg_reg(usb1_rcv); - omap_cfg_reg(usb2_susp); - omap_cfg_reg(usb2_seo); - omap_cfg_reg(usb2_txen); - omap_cfg_reg(usb2_txd); - omap_cfg_reg(usb2_vp); - omap_cfg_reg(usb2_vm); - omap_cfg_reg(usb2_rcv); - break; - case 16: - /* 0: host, 1: disabled, 2: disabled */ - omap_cfg_reg(W9_USB0_TXEN); - omap_cfg_reg(AA9_USB0_VP); - omap_cfg_reg(Y5_USB0_RCV); - omap_cfg_reg(R9_USB0_VM); - omap_cfg_reg(V6_USB0_TXD); - omap_cfg_reg(W5_USB0_SE0); - break; - default: - printk("Unknown USB host configuration: %i\n", hmc_mode); - return -ENODEV; - } - - /* Write the selected HMC mode */ - val = readl(MOD_CONF_CTRL_0) & ~HMC_CLEAR; - val |= (hmc_mode << 1); - writel(val, MOD_CONF_CTRL_0); - - return 0; -} - -/* * OHCI clock initialization for OMAP-1510 and 1610 */ static int omap_ohci_clock_power(int on) { if (on) { - if (cpu_is_omap_1510()) { + if (cpu_is_omap1510()) { /* Use DPLL, not APLL */ - writel(readl(ULPD_APLL_CTRL_REG) & ~APLL_NDPLL_SWITCH, - ULPD_APLL_CTRL_REG); + omap_writel(omap_readl(ULPD_APLL_CTRL) & ~APLL_NDPLL_SWITCH, + ULPD_APLL_CTRL); /* Enable DPLL */ - writel(readl(ULPD_DPLL_CTRL_REG) | DPLL_PLL_ENABLE, - ULPD_DPLL_CTRL_REG); + omap_writel(omap_readl(ULPD_DPLL_CTRL) | DPLL_PLL_ENABLE, + ULPD_DPLL_CTRL); /* Software request for USB 48MHz clock */ - writel(readl(ULPD_SOFT_REQ_REG) | SOFT_REQ_REG_REQ, - ULPD_SOFT_REQ_REG); + omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_REQ_REG_REQ, + ULPD_SOFT_REQ); - while (!(readl(ULPD_DPLL_CTRL_REG) & DPLL_LOCK)); + while (!(omap_readl(ULPD_DPLL_CTRL) & DPLL_LOCK)); } - if (cpu_is_omap_1610()) { + if (cpu_is_omap16xx()) { /* Enable OHCI */ - writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_OTG_REQ, - ULPD_SOFT_REQ_REG); + omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_OTG_REQ, + ULPD_SOFT_REQ); /* USB host clock request if not using OTG */ - writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_REQ, - ULPD_SOFT_REQ_REG); + omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_REQ, + ULPD_SOFT_REQ); - writel(readl(ULPD_STATUS_REQ_REG) | USB_HOST_DPLL_REQ, - ULPD_STATUS_REQ_REG); + omap_writel(omap_readl(ULPD_STATUS_REQ) | USB_HOST_DPLL_REQ, + ULPD_STATUS_REQ); } /* Enable 48MHz clock to USB */ - writel(readl(ULPD_CLOCK_CTRL_REG) | USB_MCLK_EN, - ULPD_CLOCK_CTRL_REG); + omap_writel(omap_readl(ULPD_CLOCK_CTRL) | USB_MCLK_EN, + ULPD_CLOCK_CTRL); - writel(readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK), + omap_writel(omap_readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK), ARM_IDLECT2); - writel(readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN, + omap_writel(omap_readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN, MOD_CONF_CTRL_0); } else { /* Disable 48MHz clock to USB */ - writel(readl(ULPD_CLOCK_CTRL_REG) & ~USB_MCLK_EN, - ULPD_CLOCK_CTRL_REG); + omap_writel(omap_readl(ULPD_CLOCK_CTRL) & ~USB_MCLK_EN, + ULPD_CLOCK_CTRL); /* FIXME: The DPLL stays on for now */ } @@ -163,13 +97,19 @@ static int omap_ohci_transceiver_power(int on) { if (on) { - if (omap_is_innovator()) - writel(readl(OMAP1510_FPGA_HOST_CTRL) | 0x20, - OMAP1510_FPGA_HOST_CTRL); + if (machine_is_omap_innovator() && cpu_is_omap1510()) + fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) | 0x20, + INNOVATOR_FPGA_CAM_USB_CONTROL); + else if (machine_is_omap_osk()) { + /* FIXME: GPIO1 -> 1 on the TPS65010 I2C chip */ + } } else { - if (omap_is_innovator()) - writel(readl(OMAP1510_FPGA_HOST_CTRL) & ~0x20, - OMAP1510_FPGA_HOST_CTRL); + if (machine_is_omap_innovator() && cpu_is_omap1510()) + fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) & ~0x20, + INNOVATOR_FPGA_CAM_USB_CONTROL); + else if (machine_is_omap_osk()) { + /* FIXME: GPIO1 -> 0 on the TPS65010 I2C chip */ + } } return 0; @@ -181,10 +121,10 @@ static int omap_1510_local_bus_power(int on) { if (on) { - writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); + omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); udelay(200); } else { - writel(0, OMAP1510_LB_MMU_CTL); + omap_writel(0, OMAP1510_LB_MMU_CTL); } return 0; @@ -193,8 +133,8 @@ /* * OMAP-1510 specific Local Bus initialization * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. - * See also arch/mach-omap/memory.h for __virt_to_bus() and - * __bus_to_virt() which need to match with the physical + * See also arch/mach-omap/memory.h for __virt_to_dma() and + * __dma_to_virt() which need to match with the physical * Local Bus address below. */ static int omap_1510_local_bus_init(void) @@ -202,125 +142,115 @@ unsigned int tlb; unsigned long lbaddr, physaddr; - writel((readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, + omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, OMAP1510_LB_CLOCK_DIV); /* Configure the Local Bus MMU table */ for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) { lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; physaddr = tlb * 0x00100000 + PHYS_OFFSET; - writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); - writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, + omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); + omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, OMAP1510_LB_MMU_CAM_L); - writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); - writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); - writel(tlb << 4, OMAP1510_LB_MMU_LCK); - writel(0x1, OMAP1510_LB_MMU_LD_TLB); + omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); + omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); + omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK); + omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB); } /* Enable the walking table */ - writel(readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); + omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); udelay(200); return 0; } -/* - * OMAP-1610 specific hardware initialization - * - * Intended to configure OMAP-1610 USB host and OTG ports depending on - * the HMC mode selected. - * - * FIXME: Currently only supports alternate ping group 2 mode, should - * be easy to modify for other configurations once there is some - * hardware to test with. - */ -static int omap_1610_usb_init(int mode) -{ - u_int val = 0; - - /* Configure the OMAP transceiver settings */ - val |= (1 << 8); /* CONF_USB2_UNI TRM p 15-205*/ - val |= (4 << 4); /* TRM p 5-59, p 15-157 (1224) */ - - //val |= (1 << 3); /* Isolate integrated transceiver from port 0 */ - val |= (1 << 2); /* Disable pulldown on integrated transceiver DM */ - val |= (1 << 1); /* Disable pulldown on integraded transceiver DP */ - - writel(val, USB_TRANSCEIVER_CTRL); - - /* Set the USB0_TRX_MODE */ - val = 0; - val &= ~OTG_IDLE_EN; - val &= ~DEV_IDLE_EN; - val &= ~(7 << 16); /* Clear USB0_TRX_MODE */ - val |= (3 << 16); /* 0 or 3, 6-wire DAT/SE0, TRM p 15-159 */ - writel(val, OTG_SYSCON_1); - - /* - * Control via OTG, see TRM p 15-163 - */ - val = 0; - //val |= 1; /* REVISIT: Enable OTG = 1 */ +#ifdef CONFIG_USB_OTG - /* Control via OTG */ - val &= ~HMC_PADEN; - val &= ~OTG_PADEN; - val |= UHOST_EN; - - val &= ~0x3f; /* Clear HMC mode */ - val |= mode; /* Set HMC mode */ - val &= ~(7 << 16); /* Clear ASE0_BRST */ - val |= (4 << 16); /* Must be 4 */ - val |= USBX_SYNCHRO; /* Must be set */ - val |= SRP_VBUS; - writel(val, OTG_SYSCON_2); +static void start_hnp(struct ohci_hcd *ohci) +{ + const unsigned port = ohci->hcd.self.otg_port - 1; + unsigned long flags; - /* Enable OTG idle */ - //writel(readl(OTG_SYSCON_1) | OTG_IDLE_EN, OTG_SYSCON_1); + otg_start_hnp(ohci->transceiver); - return 0; + local_irq_save(flags); + ohci->transceiver->state = OTG_STATE_A_SUSPEND; + writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]); + OTG_CTRL_REG &= ~OTG_A_BUSREQ; + local_irq_restore(flags); } +#endif + /*-------------------------------------------------------------------------*/ -static void omap_start_hc(struct omap_dev *dev) +static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) { - printk(KERN_DEBUG __FILE__ - ": starting OMAP OHCI USB Controller\n"); + struct omap_usb_config *config = pdev->dev.platform_data; + int need_transceiver = (config->otg != 0); - /* - * Set the HMC mode for the USB ports - */ -#if 0 - /* See note about the Innovator wiring above */ - if (omap_is_innovator()) - hmc_mode = 4; /* 0: function 1: host 2: host */ -#endif + dev_dbg(&pdev->dev, "starting USB Controller\n"); + + if (config->otg) { + ohci->hcd.self.otg_port = config->otg; + /* default/minimum OTG power budget: 8 mA */ + ohci->power_budget = 8; + } - if (cpu_is_omap_1610()) + /* boards can use OTG transceivers in non-OTG modes */ + need_transceiver = need_transceiver + || machine_is_omap_h2(); + + if (cpu_is_omap16xx()) ocpi_enable(); - omap_usb_set_hmc_mode(hmc_mode); +#ifdef CONFIG_ARCH_OMAP_OTG + if (need_transceiver) { + ohci->transceiver = otg_get_transceiver(); + if (ohci->transceiver) { + int status = otg_set_host(ohci->transceiver, + &ohci->hcd.self); + dev_dbg(&pdev->dev, "init %s transceiver, status %d\n", + ohci->transceiver->label, status); + if (status) { + if (ohci->transceiver) + put_device(ohci->transceiver->dev); + return status; + } + } else { + dev_err(&pdev->dev, "can't find transceiver\n"); + return -ENODEV; + } + } +#endif + + if (machine_is_omap_osk()) { + omap_request_gpio(9); + omap_set_gpio_direction(9, 1); + omap_set_gpio_dataout(9, 1); + } omap_ohci_clock_power(1); + omap_ohci_transceiver_power(1); - if (cpu_is_omap_1510()) { + if (cpu_is_omap1510()) { omap_1510_local_bus_power(1); omap_1510_local_bus_init(); } - if (cpu_is_omap_1610()) - omap_1610_usb_init(hmc_mode); + /* board init will have already handled HMC and mux setup. + * any external transceiver should already be initialized + * too, so all configured ports use the right signaling now. + */ - //omap_enable_device(dev); + return 0; } -static void omap_stop_hc(struct omap_dev *dev) +static void omap_stop_hc(struct platform_device *pdev) { - printk(KERN_DEBUG __FILE__ - ": stopping OMAP OHCI USB Controller\n"); + dev_dbg(&pdev->dev, "stopping USB Controller\n"); /* * FIXME: Put the USB host controller into reset. @@ -336,16 +266,7 @@ /*-------------------------------------------------------------------------*/ -static irqreturn_t usb_hcd_omap_hcim_irq (int irq, void *__hcd, struct pt_regs * r) -{ - struct usb_hcd *hcd = __hcd; - - return usb_hcd_irq(irq, hcd, r); -} - -/*-------------------------------------------------------------------------*/ - -void usb_hcd_omap_remove (struct usb_hcd *, struct omap_dev *); +void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ @@ -358,59 +279,71 @@ * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. - * - * Store this function in the HCD's struct pci_driver as probe(). */ int usb_hcd_omap_probe (const struct hc_driver *driver, - struct usb_hcd **hcd_out, - struct omap_dev *dev) + struct platform_device *pdev) { int retval; struct usb_hcd *hcd = 0; + struct ohci_hcd *ohci; - if (!request_mem_region(dev->res.start, - dev->res.end - dev->res.start + 1, hcd_name)) { - dbg("request_mem_region failed"); - return -EBUSY; + if (pdev->num_resources != 2) { + printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", + pdev->num_resources); + return -ENODEV; + } + + if (pdev->resource[0].flags != IORESOURCE_MEM + || pdev->resource[1].flags != IORESOURCE_IRQ) { + printk(KERN_ERR "hcd probe: invalid resource type\n"); + return -ENODEV; } - omap_start_hc(dev); + if (!request_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1, hcd_name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + return -EBUSY; + } hcd = driver->hcd_alloc (); if (hcd == NULL){ - dbg ("hcd_alloc failed"); + dev_dbg(&pdev->dev, "hcd_alloc failed\n"); retval = -ENOMEM; goto err1; } + dev_set_drvdata(&pdev->dev, hcd); + ohci = hcd_to_ohci(hcd); hcd->driver = (struct hc_driver *) driver; hcd->description = driver->description; - hcd->irq = dev->irq[0]; - hcd->regs = dev->mapbase; - hcd->self.controller = &dev->dev; + hcd->irq = pdev->resource[1].start; + hcd->regs = (void *)pdev->resource[0].start; + hcd->self.controller = &pdev->dev; + + retval = omap_start_hc(ohci, pdev); + if (retval < 0) + goto err2; retval = hcd_buffer_create (hcd); if (retval != 0) { - dbg ("pool alloc fail"); + dev_dbg(&pdev->dev, "pool alloc fail\n"); goto err1; } - retval = request_irq (hcd->irq, - usb_hcd_omap_hcim_irq, + retval = request_irq (hcd->irq, usb_hcd_irq, SA_INTERRUPT, hcd->description, hcd); if (retval != 0) { - dbg("request_irq failed"); + dev_dbg(&pdev->dev, "request_irq failed\n"); retval = -EBUSY; goto err2; } - info ("%s (OMAP) at 0x%p, irq %d\n", - hcd->description, hcd->regs, hcd->irq); + dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); usb_bus_init (&hcd->self); hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = (void *) hcd; - hcd->self.bus_name = "omap"; + hcd->self.bus_name = pdev->dev.bus_id; hcd->product_desc = "OMAP OHCI"; INIT_LIST_HEAD (&hcd->dev_list); @@ -418,11 +351,10 @@ if ((retval = driver->start (hcd)) < 0) { - usb_hcd_omap_remove(hcd, dev); + usb_hcd_omap_remove(hcd, pdev); return retval; } - *hcd_out = hcd; return 0; err2: @@ -430,10 +362,12 @@ if (hcd) driver->hcd_free(hcd); err1: - omap_stop_hc(dev); + omap_stop_hc(pdev); - release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + dev_set_drvdata(&pdev->dev, 0); return retval; } @@ -451,24 +385,27 @@ * context, normally "rmmod", "apmd", or something similar. * */ -void usb_hcd_omap_remove (struct usb_hcd *hcd, struct omap_dev *dev) +void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) { void *base; - info ("remove: %s, state %x", hcd->self.bus_name, hcd->state); + dev_info(&pdev->dev, "remove: state %x\n", hcd->state); if (in_interrupt ()) BUG (); hcd->state = USB_STATE_QUIESCING; - dbg ("%s: roothub graceful disconnect", hcd->self.bus_name); + dev_dbg(&pdev->dev, "roothub graceful disconnect\n"); usb_disconnect (&hcd->self.root_hub); hcd->driver->stop (hcd); hcd_buffer_destroy (hcd); hcd->state = USB_STATE_HALT; + if (machine_is_omap_osk()) + omap_free_gpio(9); + free_irq (hcd->irq, hcd); usb_deregister_bus (&hcd->self); @@ -476,9 +413,10 @@ base = hcd->regs; hcd->driver->hcd_free (hcd); - omap_stop_hc(dev); + omap_stop_hc(pdev); - release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); } /*-------------------------------------------------------------------------*/ @@ -486,11 +424,13 @@ static int __devinit ohci_omap_start (struct usb_hcd *hcd) { + struct omap_usb_config *config; struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - ohci->hcca = dma_alloc_consistent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma); + config = hcd->self.controller->platform_data; + ohci->hcca = dma_alloc_coherent (hcd->self.controller, + sizeof *ohci->hcca, &ohci->hcca_dma, 0); if (!ohci->hcca) return -ENOMEM; @@ -500,6 +440,10 @@ return ret; } ohci->regs = hcd->regs; + + if (config->otg || config->rwc) + writel(OHCI_CTRL_RWC, &ohci->regs->control); + if (hc_reset (ohci) < 0) { ohci_stop (hcd); return -ENODEV; @@ -510,6 +454,9 @@ ohci_stop (hcd); return -EBUSY; } + if (ohci->power_budget) + hub_set_power_budget(ohci->hcd.self.root_hub, + ohci->power_budget); create_debug_files (ohci); #ifdef DEBUG @@ -533,10 +480,6 @@ * basic lifecycle operations */ .start = ohci_omap_start, -#ifdef CONFIG_PM - /* suspend: ohci_omap_suspend, -- tbd */ - /* resume: ohci_omap_resume, -- tbd */ -#endif .stop = ohci_stop, /* @@ -566,104 +509,130 @@ .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ -static int ohci_hcd_omap_drv_probe(struct omap_dev *dev) +static int ohci_hcd_omap_drv_probe(struct device *dev) { - struct usb_hcd *hcd = NULL; - int ret; - - if (usb_disabled()) - return -ENODEV; + return usb_hcd_omap_probe(&ohci_omap_hc_driver, + to_platform_device(dev)); +} - ret = usb_hcd_omap_probe(&ohci_omap_hc_driver, &hcd, dev); +static int ohci_hcd_omap_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci (hcd); - if (ret == 0) - omap_set_drvdata(dev, hcd); + usb_hcd_omap_remove(hcd, pdev); + if (ohci->transceiver) { + (void) otg_set_host(ohci->transceiver, 0); + put_device(ohci->transceiver->dev); + } + dev_set_drvdata(dev, NULL); - return ret; + return 0; } -static int ohci_hcd_omap_drv_remove(struct omap_dev *dev) +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) + +/* states match PCI usage, always suspending the root hub except that + * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset). + */ + +static int ohci_omap_suspend(struct device *dev, u32 state, u32 level) { - struct usb_hcd *hcd = omap_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); + int status = -EINVAL; - usb_hcd_omap_remove(hcd, dev); + if (state <= dev->power.power_state) + return 0; - omap_set_drvdata(dev, NULL); + dev_dbg(dev, "suspend to %d\n", state); + down(&ohci->hcd.self.root_hub->serialize); + status = ohci_hub_suspend(&ohci->hcd); + if (status == 0) { + if (state >= 4) { + /* power off + reset */ + OTG_SYSCON_2_REG &= ~UHOST_EN; + ohci->hcd.self.root_hub->state = USB_STATE_SUSPENDED; + state = 4; + } + ohci->hcd.state = HCD_STATE_SUSPENDED; + dev->power.power_state = state; + } + up(&ohci->hcd.self.root_hub->serialize); + return status; +} - return 0; +static int ohci_omap_resume(struct device *dev, u32 level) +{ + struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); + int status = 0; + + switch (dev->power.power_state) { + case 0: + break; + case 4: + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + OTG_SYSCON_2_REG |= UHOST_EN; + /* FALLTHROUGH */ + default: + dev_dbg(dev, "resume from %d\n", dev->power.power_state); +#ifdef CONFIG_USB_SUSPEND + /* get extra cleanup even if remote wakeup isn't in use */ + status = usb_resume_device(ohci->hcd.self.root_hub); +#else + down(&ohci->hcd.self.root_hub->serialize); + status = ohci_hub_resume(&ohci->hcd); + up(&ohci->hcd.self.root_hub->serialize); +#endif + if (status == 0) + dev->power.power_state = 0; + break; + } + return status; } +#endif + +/*-------------------------------------------------------------------------*/ + /* * Driver definition to register with the OMAP bus */ -static struct omap_driver ohci_hcd_omap_driver = { - .drv = { - .name = OMAP_OHCI_NAME, - }, - .devid = OMAP_OCP_DEVID_USB, - .busid = OMAP_BUS_OCP, - .clocks = 0, +static struct device_driver ohci_hcd_omap_driver = { + .name = "ohci", + .bus = &platform_bus_type, .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, -}; - -/* Any dma_mask must be set for OHCI to work */ -static u64 omap_dmamask = 0xffffffffUL; - -/* - * Device definition to match the driver above - */ -static struct omap_dev ohci_hcd_omap_device = { - .name = OMAP_OHCI_NAME, - .devid = OMAP_OCP_DEVID_USB, - .busid = OMAP_BUS_OCP, - .mapbase = (void *)OMAP_OHCI_BASE, - .dma_mask = &omap_dmamask, /* Needed only for OHCI */ - .res = { - .start = OMAP_OHCI_BASE, - .end = OMAP_OHCI_BASE + OMAP_OHCI_SIZE, - }, - .irq = { - INT_USB_HHC_1, - }, +#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) + .suspend = ohci_omap_suspend, + .resume = ohci_omap_resume, +#endif }; static int __init ohci_hcd_omap_init (void) { - int ret; - - dbg (DRIVER_INFO " (OMAP)"); - dbg ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - if (hmc_mode < 0 || hmc_mode > 25) - hmc_mode = default_hmc_mode; - - /* Register the driver with OMAP bus */ - ret = omap_driver_register(&ohci_hcd_omap_driver); - if (ret != 0) + printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name); + if (usb_disabled()) return -ENODEV; - /* Register the device with OMAP bus */ - ret = omap_device_register(&ohci_hcd_omap_device); - if (ret != 0) { - omap_driver_unregister(&ohci_hcd_omap_driver); - return -ENODEV; - } + pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name, + sizeof (struct ed), sizeof (struct td)); - return ret; + return driver_register(&ohci_hcd_omap_driver); } -MODULE_PARM(hmc_mode, "hmc_mode"); - static void __exit ohci_hcd_omap_cleanup (void) { - omap_device_unregister(&ohci_hcd_omap_device); - omap_driver_unregister(&ohci_hcd_omap_driver); + driver_unregister(&ohci_hcd_omap_driver); } module_init (ohci_hcd_omap_init); diff -Nru a/drivers/usb/host/ohci-omap.h b/drivers/usb/host/ohci-omap.h --- a/drivers/usb/host/ohci-omap.h 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,57 +0,0 @@ -/* - * linux/drivers/usb/host/ohci-omap.h - * - * OMAP OHCI USB controller specific defines - */ - -/* OMAP USB OHCI common defines */ -#define OMAP_OHCI_NAME "omap-ohci" -#define OMAP_OHCI_BASE 0xfffba000 -#define OMAP_OHCI_SIZE 4096 - -#define HMC_CLEAR (0x3f << 1) -#define APLL_NDPLL_SWITCH 0x0001 -#define DPLL_PLL_ENABLE 0x0010 -#define DPLL_LOCK 0x0001 -#define SOFT_REQ_REG_REQ 0x0001 -#define USB_MCLK_EN 0x0010 -#define USB_HOST_HHC_UHOST_EN 0x00000200 -#define SOFT_USB_OTG_REQ (1 << 8) -#define SOFT_USB_REQ (1 << 3) -#define STATUS_REQ_REG 0xfffe0840 -#define USB_HOST_DPLL_REQ (1 << 8) -#define SOFT_DPLL_REQ (1 << 0) - -/* OMAP-1510 USB OHCI defines */ -#define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */ -#define OMAP1510_LB_CLOCK_DIV 0xfffec10c -#define OMAP1510_LB_MMU_CTL 0xfffec208 -#define OMAP1510_LB_MMU_LCK 0xfffec224 -#define OMAP1510_LB_MMU_LD_TLB 0xfffec228 -#define OMAP1510_LB_MMU_CAM_H 0xfffec22c -#define OMAP1510_LB_MMU_CAM_L 0xfffec230 -#define OMAP1510_LB_MMU_RAM_H 0xfffec234 -#define OMAP1510_LB_MMU_RAM_L 0xfffec238 - -/* OMAP-1610 USB OHCI defines */ -#define USB_TRANSCEIVER_CTRL 0xfffe1064 -#define OTG_REV 0xfffb0400 - -#define OTG_SYSCON_1 0xfffb0404 -#define OTG_IDLE_EN (1 << 15) -#define DEV_IDLE_EN (1 << 13) - -#define OTG_SYSCON_2 0xfffb0408 -#define OTG_CTRL 0xfffb040c -#define OTG_IRQ_EN 0xfffb0410 -#define OTG_IRQ_SRC 0xfffb0414 - -#define OTG_EN (1 << 31) -#define USBX_SYNCHRO (1 << 30) -#define SRP_VBUS (1 << 12) -#define OTG_PADEN (1 << 10) -#define HMC_PADEN (1 << 9) -#define UHOST_EN (1 << 8) - -/* Hardware specific defines */ -#define OMAP1510_FPGA_HOST_CTRL 0xe800020c diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c --- a/drivers/usb/host/ohci-pci.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/usb/host/ohci-pci.c 2004-10-18 14:56:48 -07:00 @@ -242,6 +242,7 @@ .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ @@ -276,7 +277,7 @@ if (usb_disabled()) return -ENODEV; - printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name, + pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); return pci_module_init (&ohci_pci_driver); } diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/host/ohci-q.c 2004-10-18 14:57:04 -07:00 @@ -136,7 +136,7 @@ for (i = ed->branch; i < NUM_INTS; i += ed->interval) { struct ed **prev = &ohci->periodic [i]; - u32 *prev_p = &ohci->hcca->int_table [i]; + __le32 *prev_p = &ohci->hcca->int_table [i]; struct ed *here = *prev; /* sorting each branch by period (slow before fast) @@ -156,7 +156,7 @@ ed->hwNextED = *prev_p; wmb (); *prev = ed; - *prev_p = cpu_to_le32p (&ed->dma); + *prev_p = cpu_to_le32(ed->dma); wmb(); } ohci->load [i] += ed->load; @@ -257,7 +257,7 @@ for (i = ed->branch; i < NUM_INTS; i += ed->interval) { struct ed *temp; struct ed **prev = &ohci->periodic [i]; - u32 *prev_p = &ohci->hcca->int_table [i]; + __le32 *prev_p = &ohci->hcca->int_table [i]; while (*prev && (temp = *prev) != ed) { prev_p = &temp->hwNextED; @@ -427,20 +427,21 @@ */ if (ed->state == ED_IDLE) { u32 info; + __le32 hw_info; info = usb_pipedevice (pipe); info |= (ep >> 1) << 7; info |= usb_maxpacket (udev, pipe, is_out) << 16; - info = cpu_to_le32 (info); + hw_info = cpu_to_le32 (info); if (udev->speed == USB_SPEED_LOW) - info |= ED_LOWSPEED; + hw_info |= ED_LOWSPEED; /* only control transfers store pids in tds */ if (type != PIPE_CONTROL) { - info |= is_out ? ED_OUT : ED_IN; + hw_info |= is_out ? ED_OUT : ED_IN; if (type != PIPE_BULK) { /* periodic transfers... */ if (type == PIPE_ISOCHRONOUS) - info |= ED_ISO; + hw_info |= ED_ISO; else if (interval > 32) /* iso can be bigger */ interval = 32; ed->interval = interval; @@ -451,7 +452,7 @@ / 1000; } } - ed->hwINFO = info; + ed->hwINFO = hw_info; } done: @@ -751,12 +752,6 @@ cc = TD_CC_GET (tdINFO); - /* control endpoints only have soft stalls */ - if (type != PIPE_CONTROL && cc == TD_CC_STALL) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)); - /* update packet status if needed (short is normally ok) */ if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) @@ -795,7 +790,7 @@ struct urb *urb = td->urb; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; - u32 toggle = ed->hwHeadP & ED_C; + __le32 toggle = ed->hwHeadP & ED_C; /* clear ed halt; this is the td that caused it, but keep it inactive * until its urb->complete() has a chance to clean up. @@ -810,7 +805,7 @@ */ while (tmp != &ed->td_list) { struct td *next; - u32 info; + __le32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -906,9 +901,6 @@ /*-------------------------------------------------------------------------*/ -/* wrap-aware logic stolen from */ -#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) - /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) @@ -919,7 +911,7 @@ for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) { struct list_head *entry, *tmp; int completed, modified; - u32 *prev; + __le32 *prev; /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs @@ -937,7 +929,7 @@ td = list_entry (ed->td_list.next, struct td, td_list); - head = cpu_to_le32 (ed->hwHeadP) & TD_MASK; + head = le32_to_cpu (ed->hwHeadP) & TD_MASK; /* INTR_WDH may need to clean up first */ if (td->td_dma != head) @@ -968,7 +960,7 @@ struct td *td; struct urb *urb; urb_priv_t *urb_priv; - u32 savebits; + __le32 savebits; td = list_entry (entry, struct td, td_list); urb = td->urb; diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h --- a/drivers/usb/host/ohci.h 2004-10-18 14:57:05 -07:00 +++ b/drivers/usb/host/ohci.h 2004-10-18 14:57:05 -07:00 @@ -16,7 +16,7 @@ */ struct ed { /* first fields are hardware-specified, le32 */ - __u32 hwINFO; /* endpoint config bitmap */ + __le32 hwINFO; /* endpoint config bitmap */ /* info bits defined by hcd */ #define ED_DEQUEUE __constant_cpu_to_le32(1 << 27) /* info bits defined by the hardware */ @@ -25,11 +25,11 @@ #define ED_LOWSPEED __constant_cpu_to_le32(1 << 13) #define ED_OUT __constant_cpu_to_le32(0x01 << 11) #define ED_IN __constant_cpu_to_le32(0x02 << 11) - __u32 hwTailP; /* tail of TD list */ - __u32 hwHeadP; /* head of TD list (hc r/w) */ + __le32 hwTailP; /* tail of TD list */ + __le32 hwHeadP; /* head of TD list (hc r/w) */ #define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */ #define ED_H __constant_cpu_to_le32(0x01) /* halted */ - __u32 hwNextED; /* next ED in list */ + __le32 hwNextED; /* next ED in list */ /* rest are purely for the driver's use */ dma_addr_t dma; /* addr of ED */ @@ -71,7 +71,7 @@ */ struct td { /* first fields are hardware-specified, le32 */ - __u32 hwINFO; /* transfer info bitmask */ + __le32 hwINFO; /* transfer info bitmask */ /* hwINFO bits for both general and iso tds: */ #define TD_CC 0xf0000000 /* condition code */ @@ -100,13 +100,13 @@ /* (no hwINFO #defines yet for iso tds) */ - __u32 hwCBP; /* Current Buffer Pointer (or 0) */ - __u32 hwNextTD; /* Next TD Pointer */ - __u32 hwBE; /* Memory Buffer End Pointer */ + __le32 hwCBP; /* Current Buffer Pointer (or 0) */ + __le32 hwNextTD; /* Next TD Pointer */ + __le32 hwBE; /* Memory Buffer End Pointer */ /* PSW is only for ISO */ #define MAXPSW 1 /* hardware allows 8 */ - __u16 hwPSW [MAXPSW]; + __le16 hwPSW [MAXPSW]; /* rest are purely for the driver's use */ __u8 index; @@ -171,16 +171,16 @@ */ struct ohci_hcca { #define NUM_INTS 32 - __u32 int_table [NUM_INTS]; /* periodic schedule */ + __le32 int_table [NUM_INTS]; /* periodic schedule */ /* * OHCI defines u16 frame_no, followed by u16 zero pad. * Since some processors can't do 16 bit bus accesses, * portable access must be a 32 bit byteswapped access. */ - u32 frame_no; /* current frame number */ + __le32 frame_no; /* current frame number */ #define OHCI_FRAME_NO(hccap) ((u16)le32_to_cpup(&(hccap)->frame_no)) - __u32 done_head; /* info returned for an interrupt */ + __le32 done_head; /* info returned for an interrupt */ u8 reserved_for_hc [116]; u8 what [4]; /* spec only identifies 252 bytes :) */ } __attribute__ ((aligned(256))); @@ -343,7 +343,7 @@ /* * I/O memory used to communicate with the HC (dma-consistent) */ - struct ohci_regs *regs; + struct ohci_regs __iomem *regs; /* * main memory used to communicate with the HC (dma-consistent). @@ -360,6 +360,13 @@ struct ed *periodic [NUM_INTS]; /* shadow int_table */ /* + * OTG controllers and transceivers need software interaction; + * other external transceivers should be software-transparent + */ + struct otg_transceiver *transceiver; + unsigned power_budget; + + /* * memory management for queue data structures */ struct dma_pool *td_cache; @@ -443,7 +450,7 @@ #else /* Standard version of ohci_readl uses standard, platform * specific implementation. */ -static inline unsigned int ohci_readl (void* regs) +static inline unsigned int ohci_readl (void __iomem * regs) { return readl (regs); } diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/usb/host/uhci-hcd.c 2004-10-18 14:57:03 -07:00 @@ -82,7 +82,7 @@ #else static int debug = 0; #endif -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level"); static char *errbuf; #define ERRBUF_LEN (32 * 1024) @@ -232,7 +232,7 @@ /* * Inserts a td into qh list at the top. */ -static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 breadth) +static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth) { struct list_head *tmp, *head; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -376,7 +376,7 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct uhci_qh *pqh; - u32 newlink; + __le32 newlink; unsigned int age; if (!qh) @@ -1120,10 +1120,6 @@ td_error: ret = uhci_map_status(status, uhci_packetout(td_token(td))); - if (ret == -EPIPE) - /* endpoint has stalled - mark it halted */ - usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td))); err: /* @@ -1344,7 +1340,7 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) { - int ret = -EINVAL; + int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; struct urb *eurb; @@ -1352,7 +1348,8 @@ spin_lock_irqsave(&uhci->schedule_lock, flags); - if (urb->status != -EINPROGRESS) /* URB already unlinked! */ + ret = urb->status; + if (ret != -EINPROGRESS) /* URB already unlinked! */ goto out; eurb = uhci_find_urb_ep(uhci, urb); @@ -1637,13 +1634,6 @@ if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); - /* Check if the URB timed out */ - if (u->timeout && u->status == -EINPROGRESS && - time_after_eq(jiffies, up->inserttime + u->timeout)) { - u->status = -ETIMEDOUT; - list_move_tail(&up->urb_list, &list); - } - spin_unlock(&u->lock); } spin_unlock_irqrestore(&uhci->schedule_lock, flags); @@ -2258,7 +2248,8 @@ irq = 7; /* Only place we don't use the frame list routines */ - uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle); + uhci->fl->frame[i] = UHCI_PTR_QH | + cpu_to_le32(uhci->skelqh[irq]->dma_handle); } /* diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/host/uhci-hcd.h 2004-10-18 14:56:49 -07:00 @@ -80,7 +80,7 @@ #define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ struct uhci_frame_list { - u32 frame[UHCI_NUMFRAMES]; + __le32 frame[UHCI_NUMFRAMES]; void *frame_cpu[UHCI_NUMFRAMES]; @@ -105,8 +105,8 @@ */ struct uhci_qh { /* Hardware fields */ - u32 link; /* Next queue */ - u32 element; /* Queue element pointer */ + __le32 link; /* Next queue */ + __le32 element; /* Queue element pointer */ /* Software fields */ dma_addr_t dma_handle; @@ -185,10 +185,10 @@ */ struct uhci_td { /* Hardware fields */ - u32 link; - u32 status; - u32 token; - u32 buffer; + __le32 link; + __le32 status; + __le32 token; + __le32 buffer; /* Software fields */ dma_addr_t dma_handle; diff -Nru a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c --- a/drivers/usb/host/uhci-hub.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/host/uhci-hub.c 2004-10-18 14:55:54 -07:00 @@ -82,7 +82,7 @@ */ case GetHubStatus: - *(__u32 *)buf = cpu_to_le32(0); + *(__le32 *)buf = cpu_to_le32(0); OK(4); /* hub power */ case GetPortStatus: if (!wIndex || wIndex > uhci->rh_numports) @@ -126,8 +126,8 @@ dev_dbg(uhci_dev(uhci), "port %d portsc %04x\n", wIndex, status); - *(__u16 *)buf = cpu_to_le16(wPortStatus); - *(__u16 *)(buf + 2) = cpu_to_le16(wPortChange); + *(__le16 *)buf = cpu_to_le16(wPortStatus); + *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); OK(4); case SetHubFeature: /* We don't implement these */ case ClearHubFeature: diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c --- a/drivers/usb/image/microtek.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/usb/image/microtek.c 2004-10-18 14:57:05 -07:00 @@ -214,8 +214,8 @@ #ifdef MTS_DO_DEBUG static inline void mts_debug_dump(struct mts_desc* desc) { - MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n", - (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], + MTS_DEBUG("desc at 0x%x: toggle = %02x%02x\n", + (int)desc, (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] ); MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n", diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/input/aiptek.c 2004-10-18 14:56:49 -07:00 @@ -494,9 +494,9 @@ } else { input_regs(inputdev, regs); - x = le16_to_cpu(get_unaligned((__u16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__u16 *) (data + 3))); - z = le16_to_cpu(get_unaligned((__u16 *) (data + 6))); + x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); + y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); + z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); p = (data[5] & 0x01) != 0 ? 1 : 0; dv = (data[5] & 0x02) != 0 ? 1 : 0; @@ -573,8 +573,8 @@ aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { input_regs(inputdev, regs); - x = le16_to_cpu(get_unaligned((__u16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__u16 *) (data + 3))); + x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); + y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); jitterable = data[5] & 0x1c; @@ -632,7 +632,7 @@ pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; macro = data[3]; - z = le16_to_cpu(get_unaligned((__u16 *) (data + 4))); + z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); if (dv != 0) { input_regs(inputdev, regs); @@ -729,7 +729,7 @@ * hat switches (which just so happen to be the macroKeys.) */ else if (data[0] == 6) { - macro = le16_to_cpu(get_unaligned((__u16 *) (data + 1))); + macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); input_regs(inputdev, regs); if (macro > 0) { @@ -930,7 +930,7 @@ buf[0], buf[1], buf[2]); ret = -EIO; } else { - ret = le16_to_cpu(get_unaligned((__u16 *) (buf + 1))); + ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1))); } kfree(buf); return ret; @@ -2289,9 +2289,9 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(programmableDelay, "i"); +module_param(programmableDelay, int, 0); MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming"); -MODULE_PARM(jitterDelay, "i"); +module_param(jitterDelay, int, 0); MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay"); module_init(aiptek_init); diff -Nru a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c --- a/drivers/usb/input/ati_remote.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/usb/input/ati_remote.c 2004-10-18 14:56:48 -07:00 @@ -112,11 +112,11 @@ #define ATI_INPUTNUM 1 /* Which input device to register as */ static unsigned long channel_mask = 0; -module_param(channel_mask, ulong, 444); +module_param(channel_mask, ulong, 0444); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); static int debug = 0; -module_param(debug, int, 444); +module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/input/hid-core.c 2004-10-18 14:56:33 -07:00 @@ -219,17 +219,13 @@ dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); return -1; } - usages = parser->local.usage_index; + + if (!(usages = max_t(int, parser->local.usage_index, parser->global.report_count))) + return 0; /* Ignore padding fields */ offset = report->size; report->size += parser->global.report_size * parser->global.report_count; - if (usages < parser->global.report_count) - usages = parser->global.report_count; - - if (usages == 0) - return 0; /* ignore padding fields */ - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) return 0; @@ -609,16 +605,16 @@ case 2: if ((end - start) < 2) return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__u16*)start)); - start = (__u8 *)((__u16 *)start + 1); + item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); + start = (__u8 *)((__le16 *)start + 1); return start; case 3: item->size++; if ((end - start) < 4) return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__u32*)start)); - start = (__u8 *)((__u32 *)start + 1); + item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); + start = (__u8 *)((__le32 *)start + 1); return start; } @@ -760,15 +756,15 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1); + return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1 << n) - 1); } static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) { report += (offset >> 5) << 2; offset &= 31; - put_unaligned((get_unaligned((__u64*)report) + put_unaligned((get_unaligned((__le64*)report) & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) - | cpu_to_le64((__u64)value << offset), (__u64*)report); + | cpu_to_le64((__u64)value << offset), (__le64*)report); } /* @@ -923,20 +919,22 @@ int status; switch (urb->status) { - case 0: /* success */ - hid_input_report(HID_INPUT_REPORT, urb, regs); - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dbg("nonzero status in input irq %d", urb->status); + case 0: /* success */ + hid_input_report(HID_INPUT_REPORT, urb, regs); + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + return; + case -ETIMEDOUT: /* NAK */ + break; + default: /* error */ + warn("input irq status %d received", urb->status); } - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, SLAB_ATOMIC); if (status) - err ("can't resubmit intr, %s-%s/input%d, status %d", + err("can't resubmit intr, %s-%s/input%d, status %d", hid->dev->bus->bus_name, hid->dev->devpath, hid->ifnum, status); } @@ -1137,23 +1135,31 @@ struct hid_device *hid = urb->context; unsigned long flags; - if (urb->status) - warn("output irq status %d received", urb->status); + switch (urb->status) { + case 0: /* success */ + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + break; + default: /* error */ + warn("output irq status %d received", urb->status); + } spin_lock_irqsave(&hid->outlock, flags); hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); if (hid->outhead != hid->outtail) { - hid_submit_out(hid); + if (hid_submit_out(hid)) { + clear_bit(HID_OUT_RUNNING, &hid->iofl);; + wake_up(&hid->wait); + } spin_unlock_irqrestore(&hid->outlock, flags); return; } clear_bit(HID_OUT_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); - wake_up(&hid->wait); } @@ -1166,26 +1172,34 @@ struct hid_device *hid = urb->context; unsigned long flags; - if (urb->status) - warn("ctrl urb status %d received", urb->status); - spin_lock_irqsave(&hid->ctrllock, flags); - if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + switch (urb->status) { + case 0: /* success */ + if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) + hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + case -EPIPE: /* report not available */ + break; + default: /* error */ + warn("ctrl urb status %d received", urb->status); + } hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->ctrlhead != hid->ctrltail) { - hid_submit_ctrl(hid); + if (hid_submit_ctrl(hid)) { + clear_bit(HID_CTRL_RUNNING, &hid->iofl); + wake_up(&hid->wait); + } spin_unlock_irqrestore(&hid->ctrllock, flags); return; } clear_bit(HID_CTRL_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); - wake_up(&hid->wait); } @@ -1211,7 +1225,8 @@ hid->outhead = head; if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) - hid_submit_out(hid); + if (hid_submit_out(hid)) + clear_bit(HID_OUT_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->outlock, flags); return; @@ -1230,7 +1245,8 @@ hid->ctrlhead = head; if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) - hid_submit_ctrl(hid); + if (hid_submit_ctrl(hid)) + clear_bit(HID_CTRL_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->ctrllock, flags); } @@ -1282,7 +1298,7 @@ void hid_close(struct hid_device *hid) { if (!--hid->open) - usb_unlink_urb(hid->urbin); + usb_kill_urb(hid->urbin); } /* @@ -1439,6 +1455,11 @@ #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 +#define USB_VENDOR_ID_CODEMERCS 0x07c0 +#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 + + static struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1453,20 +1474,20 @@ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, @@ -1619,11 +1640,17 @@ struct usb_endpoint_descriptor *endpoint; int pipe; + int interval; endpoint = &interface->endpoint[n].desc; if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ continue; + /* handle potential highspeed HID correctly */ + interval = endpoint->bInterval; + if (dev->speed == USB_SPEED_HIGH) + interval = 1 << (interval - 1); + if (endpoint->bEndpointAddress & USB_DIR_IN) { int len; @@ -1636,9 +1663,9 @@ if (len > HID_BUFFER_SIZE) len = HID_BUFFER_SIZE; usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len, - hid_irq_in, hid, endpoint->bInterval); + hid_irq_in, hid, interval); hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); } else { if (hid->urbout) continue; @@ -1646,9 +1673,9 @@ goto fail; pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress); usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, - hid_irq_out, hid, 1); + hid_irq_out, hid, interval); hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + hid->urbout->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); } } @@ -1698,8 +1725,7 @@ hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP - | URB_NO_SETUP_DMA_MAP); + hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_ASYNC_UNLINK); return hid; @@ -1725,9 +1751,9 @@ return; usb_set_intfdata(intf, NULL); - usb_unlink_urb(hid->urbin); - usb_unlink_urb(hid->urbout); - usb_unlink_urb(hid->urbctrl); + usb_kill_urb(hid->urbin); + usb_kill_urb(hid->urbout); + usb_kill_urb(hid->urbctrl); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); @@ -1835,8 +1861,8 @@ static void __exit hid_exit(void) { - hiddev_exit(); usb_deregister(&hid_driver); + hiddev_exit(); } module_init(hid_init); diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c --- a/drivers/usb/input/hiddev.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/input/hiddev.c 2004-10-18 14:56:29 -07:00 @@ -223,16 +223,6 @@ return retval < 0 ? retval : 0; } -/* - * De-allocate a hiddev structure - */ -static struct usb_class_driver hiddev_class; -static void hiddev_cleanup(struct hiddev *hiddev) -{ - hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; - usb_deregister_dev(hiddev->hid->intf, &hiddev_class); - kfree(hiddev); -} /* * release file op @@ -253,7 +243,7 @@ if (list->hiddev->exist) hid_close(list->hiddev->hid); else - hiddev_cleanup(list->hiddev); + kfree(list->hiddev); } kfree(list); @@ -636,16 +626,19 @@ goto inval; field = report->field[uref->field_index]; - if (uref->usage_index >= field->maxusage) - goto inval; - if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi->num_values >= HID_MAX_USAGES || - uref->usage_index >= field->maxusage || - (uref->usage_index + uref_multi->num_values) >= field->maxusage) + if (cmd == HIDIOCGCOLLECTIONINDEX) { + if (uref->usage_index >= field->maxusage) goto inval; + } else if (uref->usage_index >= field->report_count) + goto inval; + + else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && + (uref_multi->num_values >= HID_MAX_MULTI_USAGES || + uref->usage_index + uref_multi->num_values >= field->report_count || + uref->usage_index + uref_multi->num_values < uref->usage_index)) + goto inval; } - } switch (cmd) { case HIDIOCGUSAGE: @@ -795,17 +788,21 @@ * This is where hid.c calls us to disconnect a hiddev device from the * corresponding hid device (usually because the usb device has disconnected) */ +static struct usb_class_driver hiddev_class; void hiddev_disconnect(struct hid_device *hid) { struct hiddev *hiddev = hid->hiddev; hiddev->exist = 0; + hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; + usb_deregister_dev(hiddev->hid->intf, &hiddev_class); + if (hiddev->open) { hid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { - hiddev_cleanup(hiddev); + kfree(hiddev); } } diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- a/drivers/usb/input/kbtab.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/input/kbtab.c 2004-10-18 14:55:54 -07:00 @@ -26,10 +26,9 @@ #define USB_VENDOR_ID_KBGEAR 0x084e -static int kb_pressure_click = 0x10; -MODULE_PARM (kb_pressure_click,"i"); -MODULE_PARM_DESC(kb_pressure_click, - "pressure threshold for clicks"); +static int kb_pressure_click = 0x10; +module_param(kb_pressure_click, int, 0); +MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); struct kbtab { signed char *data; @@ -67,8 +66,8 @@ goto exit; } - kbtab->x = le16_to_cpu(get_unaligned((u16 *) &data[1])); - kbtab->y = le16_to_cpu(get_unaligned((u16 *) &data[3])); + kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1])); + kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3])); kbtab->pressure = (data[5]); diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/input/wacom.c 2004-10-18 14:55:54 -07:00 @@ -285,8 +285,8 @@ input_regs(dev, regs); input_report_key(dev, BTN_TOOL_PEN, 1); - input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((u16 *) &data[1]))); - input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((u16 *) &data[3]))); + input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((__le16 *) &data[1]))); + input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((__le16 *) &data[3]))); input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127); input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20)); input_report_key(dev, BTN_STYLUS, (data[5] & 0x40)); @@ -329,8 +329,8 @@ if (data[0] != 2) dbg("wacom_graphire_irq: received unknown report #%d", data[0]); - x = le16_to_cpu(*(u16 *) &data[2]); - y = le16_to_cpu(*(u16 *) &data[4]); + x = le16_to_cpu(*(__le16 *) &data[2]); + y = le16_to_cpu(*(__le16 *) &data[4]); input_regs(dev, regs); @@ -367,7 +367,7 @@ input_report_abs(dev, ABS_Y, y); } - input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(u16 *) &data[6])); + input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); input_report_key(dev, BTN_TOUCH, data[1] & 0x01); input_report_key(dev, BTN_STYLUS, data[1] & 0x02); input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); @@ -456,8 +456,8 @@ goto exit; } - input_report_abs(dev, ABS_X, be16_to_cpu(*(u16 *) &data[2])); - input_report_abs(dev, ABS_Y, be16_to_cpu(*(u16 *) &data[4])); + input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2])); + input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4])); input_report_abs(dev, ABS_DISTANCE, data[9]); if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */ diff -Nru a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig --- a/drivers/usb/media/Kconfig 2004-10-18 14:55:53 -07:00 +++ b/drivers/usb/media/Kconfig 2004-10-18 14:55:53 -07:00 @@ -106,46 +106,6 @@ To compile this driver as a module, choose M here: the module will be called ov511. -config USB_PWC - tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV - ---help--- - Say Y or M here if you want to use one of these Philips & OEM - webcams: - * Philips PCA645, PCA646 - * Philips PCVC675, PCVC680, PCVC690 - * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 - * Askey VC010 - * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' - and 'Orbit'/'Sphere' - * Samsung MPC-C10, MPC-C30 - * Creative Webcam 5, Pro Ex - * SOTEC Afina Eye - * Visionite VCS-UC300, VCS-UM100 - - The PCA635, PCVC665 and PCVC720/20 are not supported by this driver - and never will be, but the 665 and 720/20 are supported by other - drivers. - - This driver has an optional plugin (called PWCX), which is - distributed as a binary module only. It contains code that allow you - to use higher resolutions and framerates but may not be distributed - as source. But even without this plugin you can these cams for most - applications. - - See for more information and - installation instructions. - - The built-in microphone is enabled by selecting USB Audio support. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Character Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called pwc. - config USB_SE401 tristate "USB SE401 Camera support" depends on USB && VIDEO_DEV @@ -163,11 +123,11 @@ module will be called se401. config USB_SN9C102 - tristate "USB SN9C10[12] PC Camera Controller support (EXPERIMENTAL)" - depends on USB && VIDEO_DEV && EXPERIMENTAL + tristate "USB SN9C10[12] PC Camera Controller support" + depends on USB && VIDEO_DEV ---help--- - Say Y here if you want support for cameras based on SN9C101 and - SN9C102 PC Camera Controllers. + Say Y here if you want support for cameras based on SONiX SN9C101 + or SN9C102 PC Camera Controllers. See for more informations. diff -Nru a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile --- a/drivers/usb/media/Makefile 2004-10-18 14:55:46 -07:00 +++ b/drivers/usb/media/Makefile 2004-10-18 14:55:46 -07:00 @@ -2,15 +2,13 @@ # Makefile for USB Media drivers # -pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o -sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o sn9c102_pas202bcb.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o obj-$(CONFIG_USB_OV511) += ov511.o -obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_SN9C102) += sn9c102.o obj-$(CONFIG_USB_STV680) += stv680.o diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c --- a/drivers/usb/media/dabusb.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/media/dabusb.c 2004-10-18 14:56:33 -07:00 @@ -61,7 +61,7 @@ static dabusb_t dabusb[NRDABUSB]; static int buffers = 256; -extern struct usb_driver dabusb_driver; +static struct usb_driver dabusb_driver; /*-------------------------------------------------------------------*/ @@ -868,7 +868,7 @@ MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM (buffers, "i"); +module_param(buffers, int, 0); MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); module_init (dabusb_init); diff -Nru a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c --- a/drivers/usb/media/dsbr100.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/media/dsbr100.c 2004-10-18 14:56:28 -07:00 @@ -107,7 +107,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file); static int radio_nr = -1; -MODULE_PARM(radio_nr, "i"); +module_param(radio_nr, int, 0); /* Data for one (physical) device */ typedef struct { diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c --- a/drivers/usb/media/ibmcam.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/usb/media/ibmcam.c 2004-10-18 14:56:27 -07:00 @@ -124,38 +124,38 @@ /* Settings for camera model 3 */ static int init_model3_input = 0; -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -MODULE_PARM(flags, "i"); +module_param(flags, int, 0); MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames"); -MODULE_PARM(framerate, "i"); +module_param(framerate, int, 0); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); -MODULE_PARM(lighting, "i"); +module_param(lighting, int, 0); MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); -MODULE_PARM(sharpness, "i"); +module_param(sharpness, int, 0); MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); -MODULE_PARM(size, "i"); +module_param(size, int, 0); MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)"); -MODULE_PARM(init_brightness, "i"); +module_param(init_brightness, int, 0); MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_contrast, "i"); +module_param(init_contrast, int, 0); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -MODULE_PARM(init_color, "i"); +module_param(init_color, int, 0); MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_hue, "i"); +module_param(init_hue, int, 0); MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -MODULE_PARM(hue_correction, "i"); +module_param(hue_correction, int, 0); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); -MODULE_PARM(init_model2_rg2, "i"); +module_param(init_model2_rg2, int, 0); MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)"); -MODULE_PARM(init_model2_sat, "i"); +module_param(init_model2_sat, int, 0); MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)"); -MODULE_PARM(init_model2_yb, "i"); +module_param(init_model2_yb, int, 0); MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); /* 01.01.08 - Added for RCA video in support -LO */ -MODULE_PARM(init_model3_input, "i"); +module_param(init_model3_input, int, 0); MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA"); MODULE_AUTHOR ("Dmitri"); diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c --- a/drivers/usb/media/konicawc.c 2004-10-18 14:55:53 -07:00 +++ b/drivers/usb/media/konicawc.c 2004-10-18 14:55:53 -07:00 @@ -68,7 +68,7 @@ /* Some default values for initial camera settings, can be set by modprobe */ -static enum frame_sizes size; +static int size; static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */ static int brightness = MAX_BRIGHTNESS/2; static int contrast = MAX_CONTRAST/2; @@ -362,8 +362,8 @@ else if (!urb->status && !cam->last_data_urb->status) len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); - resubmit_urb(uvd, urb); resubmit_urb(uvd, cam->last_data_urb); + resubmit_urb(uvd, urb); cam->last_data_urb = NULL; uvd->stats.urb_length = len; uvd->stats.data_count += len; @@ -928,23 +928,23 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Simon Evans "); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_PARM(speed, "i"); +module_param(speed, int, 0); MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)"); -MODULE_PARM(size, "i"); +module_param(size, int, 0); MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240"); -MODULE_PARM(brightness, "i"); +module_param(brightness, int, 0); MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108"); -MODULE_PARM(contrast, "i"); +module_param(contrast, int, 0); MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108"); -MODULE_PARM(saturation, "i"); +module_param(saturation, int, 0); MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108"); -MODULE_PARM(sharpness, "i"); +module_param(sharpness, int, 0); MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108"); -MODULE_PARM(whitebal, "i"); +module_param(whitebal, int, 0); MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363"); #ifdef CONFIG_USB_DEBUG -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); #endif diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c --- a/drivers/usb/media/ov511.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/media/ov511.c 2004-10-18 14:56:28 -07:00 @@ -119,78 +119,79 @@ static int mirror; static int ov518_color; -MODULE_PARM(autobright, "i"); +module_param(autobright, int, 0); MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); -MODULE_PARM(autogain, "i"); +module_param(autogain, int, 0); MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); -MODULE_PARM(autoexp, "i"); +module_param(autoexp, int, 0); MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); -MODULE_PARM(snapshot, "i"); +module_param(snapshot, int, 0); MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); -MODULE_PARM(cams, "i"); +module_param(cams, int, 0); MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); -MODULE_PARM(compress, "i"); +module_param(compress, int, 0); MODULE_PARM_DESC(compress, "Turn on compression"); -MODULE_PARM(testpat, "i"); +module_param(testpat, int, 0); MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)"); -MODULE_PARM(dumppix, "i"); +module_param(dumppix, int, 0); MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); -MODULE_PARM(led, "i"); +module_param(led, int, 0); MODULE_PARM_DESC(led, "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); -MODULE_PARM(dump_bridge, "i"); +module_param(dump_bridge, int, 0); MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); -MODULE_PARM(dump_sensor, "i"); +module_param(dump_sensor, int, 0); MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); -MODULE_PARM(printph, "i"); +module_param(printph, int, 0); MODULE_PARM_DESC(printph, "Print frame start/end headers"); -MODULE_PARM(phy, "i"); +module_param(phy, int, 0); MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); -MODULE_PARM(phuv, "i"); +module_param(phuv, int, 0); MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); -MODULE_PARM(pvy, "i"); +module_param(pvy, int, 0); MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); -MODULE_PARM(pvuv, "i"); +module_param(pvuv, int, 0); MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); -MODULE_PARM(qhy, "i"); +module_param(qhy, int, 0); MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); -MODULE_PARM(qhuv, "i"); +module_param(qhuv, int, 0); MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); -MODULE_PARM(qvy, "i"); +module_param(qvy, int, 0); MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); -MODULE_PARM(qvuv, "i"); +module_param(qvuv, int, 0); MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); -MODULE_PARM(lightfreq, "i"); +module_param(lightfreq, int, 0); MODULE_PARM_DESC(lightfreq, "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); -MODULE_PARM(bandingfilter, "i"); +module_param(bandingfilter, int, 0); MODULE_PARM_DESC(bandingfilter, "Enable banding filter (to reduce effects of fluorescent lighting)"); -MODULE_PARM(clockdiv, "i"); +module_param(clockdiv, int, 0); MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); -MODULE_PARM(packetsize, "i"); +module_param(packetsize, int, 0); MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); -MODULE_PARM(framedrop, "i"); +module_param(framedrop, int, 0); MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); -MODULE_PARM(fastset, "i"); +module_param(fastset, int, 0); MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); -MODULE_PARM(force_palette, "i"); +module_param(force_palette, int, 0); MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); -MODULE_PARM(backlight, "i"); +module_param(backlight, int, 0); MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); -MODULE_PARM(unit_video, "1-" __MODULE_STRING(OV511_MAX_UNIT_VIDEO) "i"); +static int num_uv; +module_param_array(unit_video, int, num_uv, 0); MODULE_PARM_DESC(unit_video, "Force use of specific minor number(s). 0 is not allowed."); -MODULE_PARM(remove_zeros, "i"); +module_param(remove_zeros, int, 0); MODULE_PARM_DESC(remove_zeros, "Remove zero-padding from uncompressed incoming data"); -MODULE_PARM(mirror, "i"); +module_param(mirror, int, 0); MODULE_PARM_DESC(mirror, "Reverse image horizontally"); -MODULE_PARM(ov518_color, "i"); +module_param(ov518_color, int, 0); MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); MODULE_AUTHOR(DRIVER_AUTHOR); @@ -472,7 +473,7 @@ down(&ov->cbuf_lock); - *((u32 *)ov->cbuf) = __cpu_to_le32(val); + *((__le32 *)ov->cbuf) = __cpu_to_le32(val); rc = usb_control_msg(ov->dev, usb_sndctrlpipe(ov->dev, 0), @@ -1169,7 +1170,7 @@ return -EIO; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && @@ -1182,7 +1183,7 @@ if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); /* Dummy read to sync I2C */ if (i2c_r(ov, 0x00) < 0) return -EIO; @@ -4947,7 +4948,7 @@ return -1; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); i = 0; success = 0; diff -Nru a/drivers/usb/media/pwc-ctrl.c b/drivers/usb/media/pwc-ctrl.c --- a/drivers/usb/media/pwc-ctrl.c 2004-10-18 14:57:04 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,1644 +0,0 @@ -/* Driver for Philips webcam - Functions that send various control messages to the webcam, including - video modes. - (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - Changes - 2001/08/03 Alvarado Added methods for changing white balance and - red/green gains - */ - -/* Control functions for the cam; brightness, contrast, video mode, etc. */ - -#ifdef __KERNEL__ -#include -#endif -#include -#include - -#include "pwc.h" -#include "pwc-ioctl.h" -#include "pwc-uncompress.h" - -/* Request types: video */ -#define SET_LUM_CTL 0x01 -#define GET_LUM_CTL 0x02 -#define SET_CHROM_CTL 0x03 -#define GET_CHROM_CTL 0x04 -#define SET_STATUS_CTL 0x05 -#define GET_STATUS_CTL 0x06 -#define SET_EP_STREAM_CTL 0x07 -#define GET_EP_STREAM_CTL 0x08 -#define SET_MPT_CTL 0x0D -#define GET_MPT_CTL 0x0E - -/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ -#define AGC_MODE_FORMATTER 0x2000 -#define PRESET_AGC_FORMATTER 0x2100 -#define SHUTTER_MODE_FORMATTER 0x2200 -#define PRESET_SHUTTER_FORMATTER 0x2300 -#define PRESET_CONTOUR_FORMATTER 0x2400 -#define AUTO_CONTOUR_FORMATTER 0x2500 -#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 -#define CONTRAST_FORMATTER 0x2700 -#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 -#define FLICKERLESS_MODE_FORMATTER 0x2900 -#define AE_CONTROL_SPEED 0x2A00 -#define BRIGHTNESS_FORMATTER 0x2B00 -#define GAMMA_FORMATTER 0x2C00 - -/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ -#define WB_MODE_FORMATTER 0x1000 -#define AWB_CONTROL_SPEED_FORMATTER 0x1100 -#define AWB_CONTROL_DELAY_FORMATTER 0x1200 -#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 -#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 -#define COLOUR_MODE_FORMATTER 0x1500 -#define SATURATION_MODE_FORMATTER1 0x1600 -#define SATURATION_MODE_FORMATTER2 0x1700 - -/* Selectors for the Status controls [GS]ET_STATUS_CTL */ -#define SAVE_USER_DEFAULTS_FORMATTER 0x0200 -#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 -#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 -#define READ_AGC_FORMATTER 0x0500 -#define READ_SHUTTER_FORMATTER 0x0600 -#define READ_RED_GAIN_FORMATTER 0x0700 -#define READ_BLUE_GAIN_FORMATTER 0x0800 -#define SENSOR_TYPE_FORMATTER1 0x0C00 -#define READ_RAW_Y_MEAN_FORMATTER 0x3100 -#define SET_POWER_SAVE_MODE_FORMATTER 0x3200 -#define MIRROR_IMAGE_FORMATTER 0x3300 -#define LED_FORMATTER 0x3400 -#define SENSOR_TYPE_FORMATTER2 0x3700 - -/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ -#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 - -/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ -#define PT_RELATIVE_CONTROL_FORMATTER 0x01 -#define PT_RESET_CONTROL_FORMATTER 0x02 -#define PT_STATUS_FORMATTER 0x03 - -static char *size2name[PSZ_MAX] = -{ - "subQCIF", - "QSIF", - "QCIF", - "SIF", - "CIF", - "VGA", -}; - -/********/ - -/* Entries for the Nala (645/646) camera; the Nala doesn't have compression - preferences, so you either get compressed or non-compressed streams. - - An alternate value of 0 means this mode is not available at all. - */ - -struct Nala_table_entry { - char alternate; /* USB alternate setting */ - int compressed; /* Compressed yes/no */ - - unsigned char mode[3]; /* precomputed mode table */ -}; - -static struct Nala_table_entry Nala_table[PSZ_MAX][8] = -{ -#include "pwc_nala.h" -}; - -/* This tables contains entries for the 675/680/690 (Timon) camera, with - 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface - number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: - 6 different resolutions subqcif, qsif, qcif, sif, cif, vga - 6 framerates: 5, 10, 15, 20, 25, 30 - 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode - will be chosen (unless the decompressor is absent). Sometimes there are only - 1 or 2 compressed modes available; in that case entries are duplicated. -*/ -struct Timon_table_entry -{ - char alternate; /* USB alternate interface */ - unsigned short packetsize; /* Normal packet size */ - unsigned short bandlength; /* Bandlength when decompressing */ - unsigned char mode[13]; /* precomputed mode settings for cam */ -}; - -static struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = -{ -#include "pwc_timon.h" -}; - -/* Entries for the Kiara (730/740/750) camera */ - -struct Kiara_table_entry -{ - char alternate; /* USB alternate interface */ - unsigned short packetsize; /* Normal packet size */ - unsigned short bandlength; /* Bandlength when decompressing */ - unsigned char mode[12]; /* precomputed mode settings for cam */ -}; - -static struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = -{ -#include "pwc_kiara.h" -}; - - -/****************************************************************************/ - - -#define SendControlMsg(request, value, buflen) \ - usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ - request, \ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ - value, \ - pdev->vcinterface, \ - &buf, buflen, HZ / 2) - -#define RecvControlMsg(request, value, buflen) \ - usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ - request, \ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ - value, \ - pdev->vcinterface, \ - &buf, buflen, HZ / 2) - - -#if PWC_DEBUG -void pwc_hexdump(void *p, int len) -{ - int i; - unsigned char *s; - char buf[100], *d; - - s = (unsigned char *)p; - d = buf; - *d = '\0'; - Debug("Doing hexdump @ %p, %d bytes.\n", p, len); - for (i = 0; i < len; i++) { - d += sprintf(d, "%02X ", *s++); - if ((i & 0xF) == 0xF) { - Debug("%s\n", buf); - d = buf; - *d = '\0'; - } - } - if ((i & 0xF) != 0) - Debug("%s\n", buf); -} -#endif - -static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) -{ - return usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - SET_EP_STREAM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - VIDEO_OUTPUT_CONTROL_FORMATTER, - index, - buf, buflen, HZ); -} - - - -static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) -{ - unsigned char buf[3]; - int ret, fps; - struct Nala_table_entry *pEntry; - int frames2frames[31] = - { /* closest match of framerate */ - 0, 0, 0, 0, 4, /* 0-4 */ - 5, 5, 7, 7, 10, /* 5-9 */ - 10, 10, 12, 12, 15, /* 10-14 */ - 15, 15, 15, 20, 20, /* 15-19 */ - 20, 20, 20, 24, 24, /* 20-24 */ - 24, 24, 24, 24, 24, /* 25-29 */ - 24 /* 30 */ - }; - int frames2table[31] = - { 0, 0, 0, 0, 0, /* 0-4 */ - 1, 1, 1, 2, 2, /* 5-9 */ - 3, 3, 4, 4, 4, /* 10-14 */ - 5, 5, 5, 5, 5, /* 15-19 */ - 6, 6, 6, 6, 7, /* 20-24 */ - 7, 7, 7, 7, 7, /* 25-29 */ - 7 /* 30 */ - }; - - if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) - return -EINVAL; - frames = frames2frames[frames]; - fps = frames2table[frames]; - pEntry = &Nala_table[size][fps]; - if (pEntry->alternate == 0) - return -EINVAL; - - if (pEntry->compressed && pdev->decompressor == NULL) - return -ENOENT; /* Not supported. */ - - memcpy(buf, pEntry->mode, 3); - ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); - if (ret < 0) { - Debug("Failed to send video command... %d\n", ret); - return ret; - } - if (pEntry->compressed && pdev->decompressor != 0 && pdev->vpalette != VIDEO_PALETTE_RAW) - pdev->decompressor->init(pdev->type, pdev->release, buf, pdev->decompress_data); - - pdev->cmd_len = 3; - memcpy(pdev->cmd_buf, buf, 3); - - /* Set various parameters */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->valternate = pEntry->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; - if (pEntry->compressed) { - if (pdev->release < 5) { /* 4 fold compression */ - pdev->vbandlength = 528; - pdev->frame_size /= 4; - } - else { - pdev->vbandlength = 704; - pdev->frame_size /= 3; - } - } - else - pdev->vbandlength = 0; - return 0; -} - - -static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) -{ - unsigned char buf[13]; - struct Timon_table_entry *pChoose; - int ret, fps; - - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) - return -EINVAL; - fps = (frames / 5) - 1; - - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - */ - pChoose = NULL; - if (pdev->decompressor == NULL) { -#if PWC_DEBUG - Debug("Trying to find uncompressed mode.\n"); -#endif - pChoose = &Timon_table[size][fps][0]; - } - else { - while (compression <= 3) { - pChoose = &Timon_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } - } - if (pChoose == NULL || pChoose->alternate == 0) - return -ENOENT; /* Not supported. */ - - memcpy(buf, pChoose->mode, 13); - if (snapshot) - buf[0] |= 0x80; - ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); - if (ret < 0) - return ret; - - if (pChoose->bandlength > 0 && pdev->decompressor != 0 && pdev->vpalette != VIDEO_PALETTE_RAW) - pdev->decompressor->init(pdev->type, pdev->release, buf, pdev->decompress_data); - - pdev->cmd_len = 13; - memcpy(pdev->cmd_buf, buf, 13); - - /* Set various parameters */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; - pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->vbandlength = pChoose->bandlength; - if (pChoose->bandlength > 0) - pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; - else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - return 0; -} - - -static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) -{ - struct Kiara_table_entry *pChoose = NULL; - int fps, ret; - unsigned char buf[12]; - struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; - - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) - return -EINVAL; - fps = (frames / 5) - 1; - - /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ - if (size == PSZ_VGA && frames == 5 && snapshot) - { - /* Only available in case the raw palette is selected or - we have the decompressor available. This mode is - only available in compressed form - */ - if (pdev->vpalette == VIDEO_PALETTE_RAW || pdev->decompressor != NULL) - { - Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); - pChoose = &RawEntry; - } - else - { - Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); - } - } - else - { - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - Skip this step when using RAW modes. - */ - if (pdev->decompressor == NULL && pdev->vpalette != VIDEO_PALETTE_RAW) { -#if PWC_DEBUG - Debug("Trying to find uncompressed mode.\n"); -#endif - pChoose = &Kiara_table[size][fps][0]; - } - else { - while (compression <= 3) { - pChoose = &Kiara_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } - } - } - if (pChoose == NULL || pChoose->alternate == 0) - return -ENOENT; /* Not supported. */ - - /* usb_control_msg won't take staticly allocated arrays as argument?? */ - memcpy(buf, pChoose->mode, 12); - if (snapshot) - buf[0] |= 0x80; - - /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ - ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); - if (ret < 0) - return ret; - - if (pChoose->bandlength > 0 && pdev->decompressor != 0 && pdev->vpalette != VIDEO_PALETTE_RAW) - pdev->decompressor->init(pdev->type, pdev->release, buf, pdev->decompress_data); - - pdev->cmd_len = 12; - memcpy(pdev->cmd_buf, buf, 12); - /* All set and go */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; - pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->vbandlength = pChoose->bandlength; - if (pdev->vbandlength > 0) - pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; - else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - return 0; -} - - - -/** - @pdev: device structure - @width: viewport width - @height: viewport height - @frame: framerate, in fps - @compression: preferred compression ratio - @snapshot: snapshot mode or streaming - */ -int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) -{ - int ret, size; - - Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); - size = pwc_decode_size(pdev, width, height); - if (size < 0) { - Debug("Could not find suitable size.\n"); - return -ERANGE; - } - Debug("decode_size = %d.\n", size); - - ret = -EINVAL; - switch(pdev->type) { - case 645: - case 646: - ret = set_video_mode_Nala(pdev, size, frames); - break; - - case 675: - case 680: - case 690: - ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); - break; - - case 720: - case 730: - case 740: - case 750: - ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); - break; - } - if (ret < 0) { - if (ret == -ENOENT) - Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); - else { - Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); - } - return ret; - } - pdev->view.x = width; - pdev->view.y = height; - pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; - pwc_set_image_buffer_size(pdev); - Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); - return 0; -} - - -void pwc_set_image_buffer_size(struct pwc_device *pdev) -{ - int i, factor = 0, filler = 0; - - /* for PALETTE_YUV420P */ - switch(pdev->vpalette) - { - case VIDEO_PALETTE_YUV420P: - factor = 6; - filler = 128; - break; - case VIDEO_PALETTE_RAW: - factor = 6; /* can be uncompressed YUV420P */ - filler = 0; - break; - } - - /* Set sizes in bytes */ - pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; - pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; - - /* Align offset, or you'll get some very weird results in - YUV420 mode... x must be multiple of 4 (to get the Y's in - place), and y even (or you'll mixup U & V). This is less of a - problem for YUV420P. - */ - pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; - pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; - - /* Fill buffers with gray or black */ - for (i = 0; i < MAX_IMAGES; i++) { - if (pdev->image_ptr[i] != NULL) - memset(pdev->image_ptr[i], filler, pdev->view.size); - } -} - - - -/* BRIGHTNESS */ - -int pwc_get_brightness(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); - if (ret < 0) - return ret; - return buf << 9; -} - -int pwc_set_brightness(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 9) & 0x7f; - return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); -} - -/* CONTRAST */ - -int pwc_get_contrast(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); - if (ret < 0) - return ret; - return buf << 10; -} - -int pwc_set_contrast(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 10) & 0x3f; - return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); -} - -/* GAMMA */ - -int pwc_get_gamma(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); - if (ret < 0) - return ret; - return buf << 11; -} - -int pwc_set_gamma(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 11) & 0x1f; - return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); -} - - -/* SATURATION */ - -int pwc_get_saturation(struct pwc_device *pdev) -{ - char buf; - int ret; - - if (pdev->type < 675) - return -1; - ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); - if (ret < 0) - return ret; - return 32768 + buf * 327; -} - -int pwc_set_saturation(struct pwc_device *pdev, int value) -{ - char buf; - - if (pdev->type < 675) - return -EINVAL; - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* saturation ranges from -100 to +100 */ - buf = (value - 32768) / 327; - return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); -} - -/* AGC */ - -static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) -{ - char buf; - int ret; - - if (mode) - buf = 0x0; /* auto */ - else - buf = 0xff; /* fixed */ - - ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); - - if (!mode && ret >= 0) { - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 10) & 0x3F; - ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); - } - if (ret < 0) - return ret; - return 0; -} - -static inline int pwc_get_agc(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); - if (ret < 0) - return ret; - - if (buf != 0) { /* fixed */ - ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); - if (ret < 0) - return ret; - if (buf > 0x3F) - buf = 0x3F; - *value = (buf << 10); - } - else { /* auto */ - ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); - if (ret < 0) - return ret; - /* Gah... this value ranges from 0x00 ... 0x9F */ - if (buf > 0x9F) - buf = 0x9F; - *value = -(48 + buf * 409); - } - - return 0; -} - -static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) -{ - char buf[2]; - int speed, ret; - - - if (mode) - buf[0] = 0x0; /* auto */ - else - buf[0] = 0xff; /* fixed */ - - ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); - - if (!mode && ret >= 0) { - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - switch(pdev->type) { - case 675: - case 680: - case 690: - /* speed ranges from 0x0 to 0x290 (656) */ - speed = (value / 100); - buf[1] = speed >> 8; - buf[0] = speed & 0xff; - break; - case 720: - case 730: - case 740: - case 750: - /* speed seems to range from 0x0 to 0xff */ - buf[1] = 0; - buf[0] = value >> 8; - break; - } - - ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); - } - return ret; -} - - -/* POWER */ - -int pwc_camera_power(struct pwc_device *pdev, int power) -{ - char buf; - - if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) - return 0; /* Not supported by Nala or Timon < release 6 */ - - if (power) - buf = 0x00; /* active */ - else - buf = 0xFF; /* power save */ - return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); -} - - - -/* private calls */ - -static inline int pwc_restore_user(struct pwc_device *pdev) -{ - char buf; /* dummy */ - return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); -} - -static inline int pwc_save_user(struct pwc_device *pdev) -{ - char buf; /* dummy */ - return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); -} - -static inline int pwc_restore_factory(struct pwc_device *pdev) -{ - char buf; /* dummy */ - return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); -} - - /* ************************************************* */ - /* Patch by Alvarado: (not in the original version */ - - /* - * the camera recognizes modes from 0 to 4: - * - * 00: indoor (incandescant lighting) - * 01: outdoor (sunlight) - * 02: fluorescent lighting - * 03: manual - * 04: auto - */ -static inline int pwc_set_awb(struct pwc_device *pdev, int mode) -{ - char buf; - int ret; - - if (mode < 0) - mode = 0; - - if (mode > 4) - mode = 4; - - buf = mode & 0x07; /* just the lowest three bits */ - - ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); - - if (ret < 0) - return ret; - return 0; -} - -static inline int pwc_get_awb(struct pwc_device *pdev) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); - - if (ret < 0) - return ret; - return buf; -} - -static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) -{ - unsigned char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* only the msb is considered */ - buf = value >> 8; - return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); -} - -static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value) -{ - unsigned char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* only the msb is considered */ - buf = value >> 8; - return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); -} - -static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -/* The following two functions are different, since they only read the - internal red/blue gains, which may be different from the manual - gains set or read above. - */ -static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - -static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) -{ - unsigned char buf; - - /* useful range is 0x01..0x20 */ - buf = speed / 0x7f0; - return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); -} - -static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf * 0x7f0; - return 0; -} - - -static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) -{ - unsigned char buf; - - /* useful range is 0x01..0x3F */ - buf = (delay >> 10); - return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); -} - -static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 10; - return 0; -} - - -int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) -{ - unsigned char buf[2]; - - if (pdev->type < 730) - return 0; - on_value /= 100; - off_value /= 100; - if (on_value < 0) - on_value = 0; - if (on_value > 0xff) - on_value = 0xff; - if (off_value < 0) - off_value = 0; - if (off_value > 0xff) - off_value = 0xff; - - buf[0] = on_value; - buf[1] = off_value; - - return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); -} - -int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) -{ - unsigned char buf[2]; - int ret; - - if (pdev->type < 730) { - *on_value = -1; - *off_value = -1; - return 0; - } - - ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); - if (ret < 0) - return ret; - *on_value = buf[0] * 100; - *off_value = buf[1] * 100; - return 0; -} - -static inline int pwc_set_contour(struct pwc_device *pdev, int contour) -{ - unsigned char buf; - int ret; - - if (contour < 0) - buf = 0xff; /* auto contour on */ - else - buf = 0x0; /* auto contour off */ - ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - - if (contour < 0) - return 0; - if (contour > 0xffff) - contour = 0xffff; - - buf = (contour >> 10); /* contour preset is [0..3f] */ - ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - return 0; -} - -static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - - if (buf == 0) { - /* auto mode off, query current preset value */ - ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - *contour = buf << 10; - } - else - *contour = -1; - return 0; -} - - -static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) -{ - unsigned char buf; - - if (backlight) - buf = 0xff; - else - buf = 0x0; - return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); -} - -static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) -{ - int ret; - unsigned char buf; - - ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); - if (ret < 0) - return ret; - *backlight = buf; - return 0; -} - - -static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) -{ - unsigned char buf; - - if (flicker) - buf = 0xff; - else - buf = 0x0; - return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); -} - -static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) -{ - int ret; - unsigned char buf; - - ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); - if (ret < 0) - return ret; - *flicker = buf; - return 0; -} - - -static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) -{ - unsigned char buf; - - if (noise < 0) - noise = 0; - if (noise > 3) - noise = 3; - buf = noise; - return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); -} - -static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) -{ - int ret; - unsigned char buf; - - ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); - if (ret < 0) - return ret; - *noise = buf; - return 0; -} - -int pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - unsigned char buf; - - buf = flags & 0x03; // only lower two bits are currently used - return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); -} - -static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - unsigned char buf[4]; - - /* set new relative angle; angles are expressed in degrees * 100, - but cam as .5 degree resolution, hence devide by 200. Also - the angle must be multiplied by 64 before it's send to - the cam (??) - */ - pan = 64 * pan / 100; - tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ - buf[0] = pan & 0xFF; - buf[1] = (pan >> 8) & 0xFF; - buf[2] = tilt & 0xFF; - buf[3] = (tilt >> 8) & 0xFF; - return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); -} - -static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) -{ - int ret; - unsigned char buf[5]; - - ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); - if (ret < 0) - return ret; - status->status = buf[0] & 0x7; // 3 bits are used for reporting - status->time_pan = (buf[1] << 8) + buf[2]; - status->time_tilt = (buf[3] << 8) + buf[4]; - return 0; -} - - -int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) -{ - unsigned char buf; - int ret = -1, request; - - if (pdev->type < 675) - request = SENSOR_TYPE_FORMATTER1; - else if (pdev->type < 730) - return -1; /* The Vesta series doesn't have this call */ - else - request = SENSOR_TYPE_FORMATTER2; - - ret = RecvControlMsg(GET_STATUS_CTL, request, 1); - if (ret < 0) - return ret; - if (pdev->type < 675) - *sensor = buf | 0x100; - else - *sensor = buf; - return 0; -} - - - /* End of Add-Ons */ - /* ************************************************* */ - -/* Linux 2.5.something and 2.6 pass direct pointers to arguments of - ioctl() calls. With 2.4, you have to do tedious copy_from_user() - and copy_to_user() calls. With these macros we circumvent this, - and let me maintain only one source file. The functionality is - exactly the same otherwise. - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - -/* define local variable for arg */ -#define ARG_DEF(ARG_type, ARG_name)\ - ARG_type *ARG_name = arg; -/* copy arg to local variable */ -#define ARG_IN(ARG_name) /* nothing */ -/* argument itself (referenced) */ -#define ARGR(ARG_name) (*ARG_name) -/* argument address */ -#define ARGA(ARG_name) ARG_name -/* copy local variable to arg */ -#define ARG_OUT(ARG_name) /* nothing */ - -#else - -#define ARG_DEF(ARG_type, ARG_name)\ - ARG_type ARG_name; -#define ARG_IN(ARG_name)\ - if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\ - ret = -EFAULT;\ - break;\ - } -#define ARGR(ARG_name) ARG_name -#define ARGA(ARG_name) &ARG_name -#define ARG_OUT(ARG_name)\ - if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\ - ret = -EFAULT;\ - break;\ - } - -#endif - -int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) -{ - int ret = 0; - - switch(cmd) { - case VIDIOCPWCRUSER: - { - if (pwc_restore_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSUSER: - { - if (pwc_save_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCFACTORY: - { - if (pwc_restore_factory(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSCQUAL: - { - ARG_DEF(int, qual) - - ARG_IN(qual) - if (ARGR(qual) < 0 || ARGR(qual) > 3) - ret = -EINVAL; - else - ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); - if (ret >= 0) - pdev->vcompression = ARGR(qual); - break; - } - - case VIDIOCPWCGCQUAL: - { - ARG_DEF(int, qual) - - ARGR(qual) = pdev->vcompression; - ARG_OUT(qual) - break; - } - - case VIDIOCPWCPROBE: - { - ARG_DEF(struct pwc_probe, probe) - - strcpy(ARGR(probe).name, pdev->vdev->name); - ARGR(probe).type = pdev->type; - ARG_OUT(probe) - break; - } - - case VIDIOCPWCGSERIAL: - { - ARG_DEF(struct pwc_serial, serial) - - strcpy(ARGR(serial).serial, pdev->serial); - ARG_OUT(serial) - break; - } - - case VIDIOCPWCSAGC: - { - ARG_DEF(int, agc) - - ARG_IN(agc) - if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) - ret = -EINVAL; - break; - } - - case VIDIOCPWCGAGC: - { - ARG_DEF(int, agc) - - if (pwc_get_agc(pdev, ARGA(agc))) - ret = -EINVAL; - ARG_OUT(agc) - break; - } - - case VIDIOCPWCSSHUTTER: - { - ARG_DEF(int, shutter_speed) - - ARG_IN(shutter_speed) - ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); - break; - } - - case VIDIOCPWCSAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - - ARG_IN(wb) - ret = pwc_set_awb(pdev, ARGR(wb).mode); - if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { - pwc_set_red_gain(pdev, ARGR(wb).manual_red); - pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); - } - break; - } - - case VIDIOCPWCGAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - - memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); - ARGR(wb).mode = pwc_get_awb(pdev); - if (ARGR(wb).mode < 0) - ret = -EINVAL; - else { - if (ARGR(wb).mode == PWC_WB_MANUAL) { - ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); - if (ret < 0) - break; - ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); - if (ret < 0) - break; - } - if (ARGR(wb).mode == PWC_WB_AUTO) { - ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); - if (ret < 0) - break; - ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); - if (ret < 0) - break; - } - } - ARG_OUT(wb) - break; - } - - case VIDIOCPWCSAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - if (ARGR(wbs).control_speed > 0) { - ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); - } - if (ARGR(wbs).control_delay > 0) { - ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); - } - break; - } - - case VIDIOCPWCGAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); - if (ret < 0) - break; - ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); - if (ret < 0) - break; - ARG_OUT(wbs) - break; - } - - case VIDIOCPWCSLED: - { - ARG_DEF(struct pwc_leds, leds) - - ARG_IN(leds) - ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); - break; - } - - - case VIDIOCPWCGLED: - { - ARG_DEF(struct pwc_leds, leds) - - ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); - ARG_OUT(leds) - break; - } - - case VIDIOCPWCSCONTOUR: - { - ARG_DEF(int, contour) - - ARG_IN(contour) - ret = pwc_set_contour(pdev, ARGR(contour)); - break; - } - - case VIDIOCPWCGCONTOUR: - { - ARG_DEF(int, contour) - - ret = pwc_get_contour(pdev, ARGA(contour)); - ARG_OUT(contour) - break; - } - - case VIDIOCPWCSBACKLIGHT: - { - ARG_DEF(int, backlight) - - ARG_IN(backlight) - ret = pwc_set_backlight(pdev, ARGR(backlight)); - break; - } - - case VIDIOCPWCGBACKLIGHT: - { - ARG_DEF(int, backlight) - - ret = pwc_get_backlight(pdev, ARGA(backlight)); - ARG_OUT(backlight) - break; - } - - case VIDIOCPWCSFLICKER: - { - ARG_DEF(int, flicker) - - ARG_IN(flicker) - ret = pwc_set_flicker(pdev, ARGR(flicker)); - break; - } - - case VIDIOCPWCGFLICKER: - { - ARG_DEF(int, flicker) - - ret = pwc_get_flicker(pdev, ARGA(flicker)); - ARG_OUT(flicker) - break; - } - - case VIDIOCPWCSDYNNOISE: - { - ARG_DEF(int, dynnoise) - - ARG_IN(dynnoise) - ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); - break; - } - - case VIDIOCPWCGDYNNOISE: - { - ARG_DEF(int, dynnoise) - - ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); - ARG_OUT(dynnoise); - break; - } - - case VIDIOCPWCGREALSIZE: - { - ARG_DEF(struct pwc_imagesize, size) - - ARGR(size).width = pdev->image.x; - ARGR(size).height = pdev->image.y; - ARG_OUT(size) - break; - } - - case VIDIOCPWCMPTRESET: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(int, flags) - - ARG_IN(flags) - ret = pwc_mpt_reset(pdev, ARGR(flags)); - if (ret >= 0) - { - pdev->pan_angle = 0; - pdev->tilt_angle = 0; - } - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGRANGE: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_range, range) - - ARGR(range) = pdev->angle_range; - ARG_OUT(range) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSANGLE: - { - int new_pan, new_tilt; - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARG_IN(angles) - /* The camera can only set relative angles, so - do some calculations when getting an absolute angle . - */ - if (ARGR(angles).absolute) - { - new_pan = ARGR(angles).pan; - new_tilt = ARGR(angles).tilt; - } - else - { - new_pan = pdev->pan_angle + ARGR(angles).pan; - new_tilt = pdev->tilt_angle + ARGR(angles).tilt; - } - /* check absolute ranges */ - if (new_pan < pdev->angle_range.pan_min || - new_pan > pdev->angle_range.pan_max || - new_tilt < pdev->angle_range.tilt_min || - new_tilt > pdev->angle_range.tilt_max) - { - ret = -ERANGE; - } - else - { - /* go to relative range, check again */ - new_pan -= pdev->pan_angle; - new_tilt -= pdev->tilt_angle; - /* angles are specified in degrees * 100, thus the limit = 36000 */ - if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000) - ret = -ERANGE; - } - if (ret == 0) /* no errors so far */ - { - ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); - if (ret >= 0) - { - pdev->pan_angle += new_pan; - pdev->tilt_angle += new_tilt; - } - if (ret == -EPIPE) /* stall -> out of range */ - ret = -ERANGE; - } - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGANGLE: - { - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARGR(angles).absolute = 1; - ARGR(angles).pan = pdev->pan_angle; - ARGR(angles).tilt = pdev->tilt_angle; - ARG_OUT(angles) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSTATUS: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_status, status) - - ret = pwc_mpt_get_status(pdev, ARGA(status)); - ARG_OUT(status) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCGVIDCMD: - { - ARG_DEF(struct pwc_video_command, cmd); - - ARGR(cmd).type = pdev->type; - ARGR(cmd).release = pdev->release; - ARGR(cmd).command_len = pdev->cmd_len; - memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); - ARGR(cmd).bandlength = pdev->vbandlength; - ARGR(cmd).frame_size = pdev->frame_size; - ARG_OUT(cmd) - break; - } - - default: - ret = -ENOIOCTLCMD; - break; - } - - if (ret > 0) - return 0; - return ret; -} - - - diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c --- a/drivers/usb/media/pwc-if.c 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,2193 +0,0 @@ -/* Linux driver for Philips webcam - USB and Video4Linux interface part. - (C) 1999-2004 Nemosoft Unv. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/* - This code forms the interface between the USB layers and the Philips - specific stuff. Some adanved stuff of the driver falls under an - NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and - is thus not distributed in source form. The binary pwcx.o module - contains the code that falls under the NDA. - - In case you're wondering: 'pwc' stands for "Philips WebCam", but - I really didn't want to type 'philips_web_cam' every time (I'm lazy as - any Linux kernel hacker, but I don't like uncomprehensible abbreviations - without explanation). - - Oh yes, convention: to disctinguish between all the various pointers to - device-structures, I use these names for the pointer variables: - udev: struct usb_device * - vdev: struct video_device * - pdev: struct pwc_devive * -*/ - -/* Contributors: - - Alvarado: adding whitebalance code - - Alistar Moire: QuickCam 3000 Pro device/product ID - - Tony Hoyle: Creative Labs Webcam 5 device/product ID - - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged - - Jk Fang: Sotec Afina Eye ID - - Xavier Roche: QuickCam Pro 4000 ID - - Jens Knudsen: QuickCam Zoom ID - - J. Debert: QuickCam for Notebooks ID -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pwc.h" -#include "pwc-ioctl.h" -#include "pwc-uncompress.h" - -/* Function prototypes and driver templates */ - -/* hotplug device table support */ -static struct usb_device_id pwc_device_table [] = { - { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ - { USB_DEVICE(0x0471, 0x0303) }, - { USB_DEVICE(0x0471, 0x0304) }, - { USB_DEVICE(0x0471, 0x0307) }, - { USB_DEVICE(0x0471, 0x0308) }, - { USB_DEVICE(0x0471, 0x030C) }, - { USB_DEVICE(0x0471, 0x0310) }, - { USB_DEVICE(0x0471, 0x0311) }, - { USB_DEVICE(0x0471, 0x0312) }, - { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ - { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ - { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ - { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ - { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ - { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ - { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ - { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ - { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ - { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ - { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ - { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ - { USB_DEVICE(0x055D, 0x9001) }, - { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ - { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ - { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ - { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ - { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ - { USB_DEVICE(0x0d81, 0x1900) }, - { } -}; -MODULE_DEVICE_TABLE(usb, pwc_device_table); - -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); -static void usb_pwc_disconnect(struct usb_interface *intf); - -static struct usb_driver pwc_driver = { - .owner = THIS_MODULE, - .name = "Philips webcam", /* name */ - .id_table = pwc_device_table, - .probe = usb_pwc_probe, /* probe() */ - .disconnect = usb_pwc_disconnect, /* disconnect() */ -}; - -#define MAX_DEV_HINTS 20 -#define MAX_ISOC_ERRORS 20 - -static int default_size = PSZ_QCIF; -static int default_fps = 10; -static int default_fbufs = 3; /* Default number of frame buffers */ -static int default_mbufs = 2; /* Default number of mmap() buffers */ - int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; -static int power_save = 0; -static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ - int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ -static struct { - int type; - char serial_number[30]; - int device_node; - struct pwc_device *pdev; -} device_hint[MAX_DEV_HINTS]; - -/***/ - -static int pwc_video_open(struct inode *inode, struct file *file); -static int pwc_video_close(struct inode *inode, struct file *file); -static ssize_t pwc_video_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); -static unsigned int pwc_video_poll(struct file *file, poll_table *wait); -static int pwc_video_ioctl(struct inode *inode, struct file *file, - unsigned int ioctlnr, unsigned long arg); -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); - -static struct file_operations pwc_fops = { - .owner = THIS_MODULE, - .open = pwc_video_open, - .release = pwc_video_close, - .read = pwc_video_read, - .poll = pwc_video_poll, - .mmap = pwc_video_mmap, - .ioctl = pwc_video_ioctl, - .llseek = no_llseek, -}; -static struct video_device pwc_template = { - .owner = THIS_MODULE, - .name = "Philips Webcam", /* Filled in later */ - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_PWC, - .release = video_device_release, - .fops = &pwc_fops, - .minor = -1, -}; - -/***************************************************************************/ - -/* Okay, this is some magic that I worked out and the reasoning behind it... - - The biggest problem with any USB device is of course: "what to do - when the user unplugs the device while it is in use by an application?" - We have several options: - 1) Curse them with the 7 plagues when they do (requires divine intervention) - 2) Tell them not to (won't work: they'll do it anyway) - 3) Oops the kernel (this will have a negative effect on a user's uptime) - 4) Do something sensible. - - Of course, we go for option 4. - - It happens that this device will be linked to two times, once from - usb_device and once from the video_device in their respective 'private' - pointers. This is done when the device is probed() and all initialization - succeeded. The pwc_device struct links back to both structures. - - When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register it as a V4L device, but - unfortunately I can't free the memory since the struct is still in use - by the file descriptor. This free-ing is then deferend until the first - opportunity. Crude, but it works. - - A small 'advantage' is that if a user unplugs the cam and plugs it back - in, it should get assigned the same video device minor, but unfortunately - it's non-trivial to re-link the cam back to the video device... (that - would surely be magic! :)) -*/ - -/***************************************************************************/ -/* Private functions */ - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void * rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr; - - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} - - - - -static int pwc_allocate_buffers(struct pwc_device *pdev) -{ - int i; - void *kbuf; - - Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); - - if (pdev == NULL) - return -ENXIO; - -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("allocate_buffers(): magic failed.\n"); - return -ENXIO; - } -#endif - /* Allocate Isochronuous pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (pdev->sbuf[i].data == NULL) { - kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); - if (kbuf == NULL) { - Err("Failed to allocate iso buffer %d.\n", i); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); - pdev->sbuf[i].data = kbuf; - memset(kbuf, 0, ISO_BUFFER_SIZE); - } - } - - /* Allocate frame buffer structure */ - if (pdev->fbuf == NULL) { - kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); - if (kbuf == NULL) { - Err("Failed to allocate frame buffer structure.\n"); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); - pdev->fbuf = kbuf; - memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); - } - /* create frame buffers, and make circular ring */ - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data == NULL) { - kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ - if (kbuf == NULL) { - Err("Failed to allocate frame buffer %d.\n", i); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); - pdev->fbuf[i].data = kbuf; - memset(kbuf, 128, PWC_FRAME_SIZE); - } - } - - /* Allocate decompressor table space */ - kbuf = NULL; - if (pdev->decompressor != NULL) { - kbuf = kmalloc(pdev->decompressor->table_size, GFP_KERNEL); - if (kbuf == NULL) { - Err("Failed to allocate decompress table.\n"); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated decompress table %p.\n", kbuf); - } - pdev->decompress_data = kbuf; - - /* Allocate image buffer; double buffer for mmap() */ - kbuf = rvmalloc(default_mbufs * pdev->len_per_image); - if (kbuf == NULL) { - Err("Failed to allocate image buffer(s).\n"); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); - pdev->image_data = kbuf; - for (i = 0; i < default_mbufs; i++) - pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; - for (; i < MAX_IMAGES; i++) - pdev->image_ptr[i] = NULL; - - kbuf = NULL; - - Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); - return 0; -} - -static void pwc_free_buffers(struct pwc_device *pdev) -{ - int i; - - Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); - - if (pdev == NULL) - return; -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("free_buffers(): magic failed.\n"); - return; - } -#endif - - /* Release Iso-pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) - if (pdev->sbuf[i].data != NULL) { - Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); - kfree(pdev->sbuf[i].data); - pdev->sbuf[i].data = NULL; - } - - /* The same for frame buffers */ - if (pdev->fbuf != NULL) { - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data != NULL) { - Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); - vfree(pdev->fbuf[i].data); - pdev->fbuf[i].data = NULL; - } - } - kfree(pdev->fbuf); - pdev->fbuf = NULL; - } - - /* Intermediate decompression buffer & tables */ - if (pdev->decompress_data != NULL) { - Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); - kfree(pdev->decompress_data); - pdev->decompress_data = NULL; - } - pdev->decompressor = NULL; - - /* Release image buffers */ - if (pdev->image_data != NULL) { - Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); - rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); - } - pdev->image_data = NULL; - - Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); -} - -/* The frame & image buffer mess. - - Yes, this is a mess. Well, it used to be simple, but alas... In this - module, 3 buffers schemes are used to get the data from the USB bus to - the user program. The first scheme involves the ISO buffers (called thus - since they transport ISO data from the USB controller), and not really - interesting. Suffices to say the data from this buffer is quickly - gathered in an interrupt handler (pwc_isoc_handler) and placed into the - frame buffer. - - The frame buffer is the second scheme, and is the central element here. - It collects the data from a single frame from the camera (hence, the - name). Frames are delimited by the USB camera with a short USB packet, - so that's easy to detect. The frame buffers form a list that is filled - by the camera+USB controller and drained by the user process through - either read() or mmap(). - - The image buffer is the third scheme, in which frames are decompressed - and converted into planar format. For mmap() there is more than - one image buffer available. - - The frame buffers provide the image buffering. In case the user process - is a bit slow, this introduces lag and some undesired side-effects. - The problem arises when the frame buffer is full. I used to drop the last - frame, which makes the data in the queue stale very quickly. But dropping - the frame at the head of the queue proved to be a litte bit more difficult. - I tried a circular linked scheme, but this introduced more problems than - it solved. - - Because filling and draining are completely asynchronous processes, this - requires some fiddling with pointers and mutexes. - - Eventually, I came up with a system with 2 lists: an 'empty' frame list - and a 'full' frame list: - * Initially, all frame buffers but one are on the 'empty' list; the one - remaining buffer is our initial fill frame. - * If a frame is needed for filling, we try to take it from the 'empty' - list, unless that list is empty, in which case we take the buffer at - the head of the 'full' list. - * When our fill buffer has been filled, it is appended to the 'full' - list. - * If a frame is needed by read() or mmap(), it is taken from the head of - the 'full' list, handled, and then appended to the 'empty' list. If no - buffer is present on the 'full' list, we wait. - The advantage is that the buffer that is currently being decompressed/ - converted, is on neither list, and thus not in our way (any other scheme - I tried had the problem of old data lingering in the queue). - - Whatever strategy you choose, it always remains a tradeoff: with more - frame buffers the chances of a missed frame are reduced. On the other - hand, on slower machines it introduces lag because the queue will - always be full. - */ - -/** - \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. - */ -static inline int pwc_next_fill_frame(struct pwc_device *pdev) -{ - int ret; - unsigned long flags; - - ret = 0; - spin_lock_irqsave(&pdev->ptrlock, flags); - if (pdev->fill_frame != NULL) { - /* append to 'full' list */ - if (pdev->full_frames == NULL) { - pdev->full_frames = pdev->fill_frame; - pdev->full_frames_tail = pdev->full_frames; - } - else { - pdev->full_frames_tail->next = pdev->fill_frame; - pdev->full_frames_tail = pdev->fill_frame; - } - } - if (pdev->empty_frames != NULL) { - /* We have empty frames available. That's easy */ - pdev->fill_frame = pdev->empty_frames; - pdev->empty_frames = pdev->empty_frames->next; - } - else { - /* Hmm. Take it from the full list */ -#if PWC_DEBUG - /* sanity check */ - if (pdev->full_frames == NULL) { - Err("Neither empty or full frames available!\n"); - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return -EINVAL; - } -#endif - pdev->fill_frame = pdev->full_frames; - pdev->full_frames = pdev->full_frames->next; - ret = 1; - } - pdev->fill_frame->next = NULL; -#if PWC_DEBUG - Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); - pdev->fill_frame->sequence = pdev->sequence++; -#endif - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; -} - - -/** - \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. - - If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. - */ -static void pwc_reset_buffers(struct pwc_device *pdev) -{ - int i; - unsigned long flags; - - spin_lock_irqsave(&pdev->ptrlock, flags); - pdev->full_frames = NULL; - pdev->full_frames_tail = NULL; - for (i = 0; i < default_fbufs; i++) { - pdev->fbuf[i].filled = 0; - if (i > 0) - pdev->fbuf[i].next = &pdev->fbuf[i - 1]; - else - pdev->fbuf->next = NULL; - } - pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; - pdev->empty_frames_tail = pdev->fbuf; - pdev->read_frame = NULL; - pdev->fill_frame = pdev->empty_frames; - pdev->empty_frames = pdev->empty_frames->next; - - pdev->image_read_pos = 0; - pdev->fill_image = 0; - spin_unlock_irqrestore(&pdev->ptrlock, flags); -} - - -/** - \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. - */ -static int pwc_handle_frame(struct pwc_device *pdev) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&pdev->ptrlock, flags); - /* First grab our read_frame; this is removed from all lists, so - we can release the lock after this without problems */ - if (pdev->read_frame != NULL) { - /* This can't theoretically happen */ - Err("Huh? Read frame still in use?\n"); - } - else { - if (pdev->full_frames == NULL) { - Err("Woops. No frames ready.\n"); - } - else { - pdev->read_frame = pdev->full_frames; - pdev->full_frames = pdev->full_frames->next; - pdev->read_frame->next = NULL; - } - - if (pdev->read_frame != NULL) { -#if PWC_DEBUG - Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); -#endif - /* Decompression is a lenghty process, so it's outside of the lock. - This gives the isoc_handler the opportunity to fill more frames - in the mean time. - */ - spin_unlock_irqrestore(&pdev->ptrlock, flags); - ret = pwc_decompress(pdev); - spin_lock_irqsave(&pdev->ptrlock, flags); - - /* We're done with read_buffer, tack it to the end of the empty buffer list */ - if (pdev->empty_frames == NULL) { - pdev->empty_frames = pdev->read_frame; - pdev->empty_frames_tail = pdev->empty_frames; - } - else { - pdev->empty_frames_tail->next = pdev->read_frame; - pdev->empty_frames_tail = pdev->read_frame; - } - pdev->read_frame = NULL; - } - } - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; -} - -/** - \brief Advance pointers of image buffer (after each user request) -*/ -static inline void pwc_next_image(struct pwc_device *pdev) -{ - pdev->image_used[pdev->fill_image] = 0; - pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; -} - - -/* This gets called for the Isochronous pipe (video). This is done in - * interrupt time, so it has to be fast, not crash, and not stall. Neat. - */ -static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) -{ - struct pwc_device *pdev; - int i, fst, flen; - int awake; - struct pwc_frame_buf *fbuf; - unsigned char *fillptr = NULL; - unsigned char *iso_buf = NULL; - - awake = 0; - pdev = (struct pwc_device *)urb->context; - if (pdev == NULL) { - Err("isoc_handler() called with NULL device?!\n"); - return; - } -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("isoc_handler() called with bad magic!\n"); - return; - } -#endif - if (urb->status == -ENOENT || urb->status == -ECONNRESET) { - Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); - return; - } - if (urb->status != -EINPROGRESS && urb->status != 0) { - const char *errmsg; - - errmsg = "Unknown"; - switch(urb->status) { - case -ENOSR: errmsg = "Buffer error (overrun)"; break; - case -EPIPE: errmsg = "Stalled (device not responding)"; break; - case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; - case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; - case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; - case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; - } - Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); - /* Give up after a number of contiguous errors on the USB bus. - Appearantly something is wrong so we simulate an unplug event. - */ - if (++pdev->visoc_errors > MAX_ISOC_ERRORS) - { - Info("Too many ISOC errors, bailing out.\n"); - pdev->error_status = EIO; - awake = 1; - wake_up_interruptible(&pdev->frameq); - } - goto handler_end; // ugly, but practical - } - - fbuf = pdev->fill_frame; - if (fbuf == NULL) { - Err("pwc_isoc_handler without valid fill frame.\n"); - awake = 1; - goto handler_end; - } - else { - fillptr = fbuf->data + fbuf->filled; - } - - /* Reset ISOC error counter. We did get here, after all. */ - pdev->visoc_errors = 0; - - /* vsync: 0 = don't copy data - 1 = sync-hunt - 2 = synched - */ - /* Compact data */ - for (i = 0; i < urb->number_of_packets; i++) { - fst = urb->iso_frame_desc[i].status; - flen = urb->iso_frame_desc[i].actual_length; - iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (fst == 0) { - if (flen > 0) { /* if valid data... */ - if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ - pdev->vsync = 2; - - /* ...copy data to frame buffer, if possible */ - if (flen + fbuf->filled > pdev->frame_total_size) { - Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); - pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ - pdev->vframes_error++; - } - else { - memmove(fillptr, iso_buf, flen); - fillptr += flen; - } - } - fbuf->filled += flen; - } /* ..flen > 0 */ - - if (flen < pdev->vlast_packet_size) { - /* Shorter packet... We probably have the end of an image-frame; - wake up read() process and let select()/poll() do something. - Decompression is done in user time over there. - */ - if (pdev->vsync == 2) { - /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus - frames on the USB wire after an exposure change. This conditition is - however detected in the cam and a bit is set in the header. - */ - if (pdev->type == 730) { - unsigned char *ptr = (unsigned char *)fbuf->data; - - if (ptr[1] == 1 && ptr[0] & 0x10) { -#if PWC_DEBUG - Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); -#endif - pdev->drop_frames += 2; - pdev->vframes_error++; - } - if ((ptr[0] ^ pdev->vmirror) & 0x01) { - if (ptr[0] & 0x01) - Info("Snapshot button pressed.\n"); - else - Info("Snapshot button released.\n"); - } - if ((ptr[0] ^ pdev->vmirror) & 0x02) { - if (ptr[0] & 0x02) - Info("Image is mirrored.\n"); - else - Info("Image is normal.\n"); - } - pdev->vmirror = ptr[0] & 0x03; - /* Sometimes the trailer of the 730 is still sent as a 4 byte packet - after a short frame; this condition is filtered out specifically. A 4 byte - frame doesn't make sense anyway. - So we get either this sequence: - drop_bit set -> 4 byte frame -> short frame -> good frame - Or this one: - drop_bit set -> short frame -> good frame - So we drop either 3 or 2 frames in all! - */ - if (fbuf->filled == 4) - pdev->drop_frames++; - } - - /* In case we were instructed to drop the frame, do so silently. - The buffer pointers are not updated either (but the counters are reset below). - */ - if (pdev->drop_frames > 0) - pdev->drop_frames--; - else { - /* Check for underflow first */ - if (fbuf->filled < pdev->frame_total_size) { - Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); - pdev->vframes_error++; - } - else { - /* Send only once per EOF */ - awake = 1; /* delay wake_ups */ - - /* Find our next frame to fill. This will always succeed, since we - * nick a frame from either empty or full list, but if we had to - * take it from the full list, it means a frame got dropped. - */ - if (pwc_next_fill_frame(pdev)) { - pdev->vframes_dumped++; - if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { - if (pdev->vframes_dumped < 20) - Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); - if (pdev->vframes_dumped == 20) - Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); - } - } - fbuf = pdev->fill_frame; - } - } /* !drop_frames */ - pdev->vframe_count++; - } - fbuf->filled = 0; - fillptr = fbuf->data; - pdev->vsync = 1; - } /* .. flen < last_packet_size */ - pdev->vlast_packet_size = flen; - } /* ..status == 0 */ -#if PWC_DEBUG - /* This is normally not interesting to the user, unless you are really debugging something */ - else { - static int iso_error = 0; - iso_error++; - if (iso_error < 20) - Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); - } -#endif - } - -handler_end: - if (awake) - wake_up_interruptible(&pdev->frameq); - - urb->dev = pdev->udev; - i = usb_submit_urb(urb, GFP_ATOMIC); - if (i != 0) - Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); -} - - -static int pwc_isoc_init(struct pwc_device *pdev) -{ - struct usb_device *udev; - struct urb *urb; - int i, j, ret; - - struct usb_interface *intf; - struct usb_host_interface *idesc = NULL; - - if (pdev == NULL) - return -EFAULT; - if (pdev->iso_init) - return 0; - pdev->vsync = 0; - udev = pdev->udev; - - /* Get the current alternate interface, adjust packet size */ - if (!udev->actconfig) - return -EFAULT; - intf = usb_ifnum_to_if(udev, 0); - if (intf) - idesc = usb_altnum_to_altsetting(intf, pdev->valternate); - if (!idesc) - return -EFAULT; - - /* Search video endpoint */ - pdev->vmax_packet_size = -1; - for (i = 0; i < idesc->desc.bNumEndpoints; i++) - if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { - pdev->vmax_packet_size = idesc->endpoint[i].desc.wMaxPacketSize; - break; - } - - if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { - Err("Failed to find packet size for video endpoint in current alternate setting.\n"); - return -ENFILE; /* Odd error, that should be noticable */ - } - - /* Set alternate interface */ - ret = 0; - Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); - ret = usb_set_interface(pdev->udev, 0, pdev->valternate); - if (ret < 0) - return ret; - - for (i = 0; i < MAX_ISO_BUFS; i++) { - urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); - if (urb == NULL) { - Err("Failed to allocate urb %d\n", i); - ret = -ENOMEM; - break; - } - pdev->sbuf[i].urb = urb; - Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); - } - if (ret) { - /* De-allocate in reverse order */ - while (i >= 0) { - if (pdev->sbuf[i].urb != NULL) - usb_free_urb(pdev->sbuf[i].urb); - pdev->sbuf[i].urb = NULL; - i--; - } - return ret; - } - - /* init URB structure */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - urb = pdev->sbuf[i].urb; - - urb->interval = 1; // devik - urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = pdev->sbuf[i].data; - urb->transfer_buffer_length = ISO_BUFFER_SIZE; - urb->complete = pwc_isoc_handler; - urb->context = pdev; - urb->start_frame = 0; - urb->number_of_packets = ISO_FRAMES_PER_DESC; - for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; - urb->iso_frame_desc[j].length = pdev->vmax_packet_size; - } - } - - /* link */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); - if (ret) - Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); - else - Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); - } - - /* All is done... */ - pdev->iso_init = 1; - Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); - return 0; -} - -static void pwc_isoc_cleanup(struct pwc_device *pdev) -{ - int i; - - Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); - if (pdev == NULL) - return; - - /* Unlinking ISOC buffers one by one */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - struct urb *urb; - - urb = pdev->sbuf[i].urb; - if (urb != 0) { - if (pdev->iso_init) { - Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); - usb_unlink_urb(urb); - } - Trace(TRACE_MEMORY, "Freeing URB\n"); - usb_free_urb(urb); - pdev->sbuf[i].urb = NULL; - } - } - - /* Stop camera, but only if we are sure the camera is still there (unplug - is signalled by EPIPE) - */ - if (pdev->error_status && pdev->error_status != EPIPE) { - Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); - usb_set_interface(pdev->udev, 0, 0); - } - - pdev->iso_init = 0; - Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); -} - -int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) -{ - int ret, start; - - /* Stop isoc stuff */ - pwc_isoc_cleanup(pdev); - /* Reset parameters */ - pwc_reset_buffers(pdev); - /* Try to set video mode... */ - start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); - if (ret) { - Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); - /* That failed... restore old mode (we know that worked) */ - start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - if (start) { - Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); - } - } - if (start == 0) - { - if (pwc_isoc_init(pdev) < 0) - { - Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); - ret = -EAGAIN; /* let's try again, who knows if it works a second time */ - } - } - pdev->drop_frames++; /* try to avoid garbage during switch */ - return ret; /* Return original error code */ -} - - -/***************************************************************************/ -/* Video4Linux functions */ - -static int pwc_video_open(struct inode *inode, struct file *file) -{ - int i; - struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev; - - Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); - - pdev = (struct pwc_device *)vdev->priv; - if (pdev == NULL) - BUG(); - if (pdev->vopen) - return -EBUSY; - - down(&pdev->modlock); - if (!pdev->usb_init) { - Trace(TRACE_OPEN, "Doing first time initialization.\n"); - pdev->usb_init = 1; - - if (pwc_trace & TRACE_OPEN) - { - /* Query sensor type */ - const char *sensor_type = NULL; - int ret; - - ret = pwc_get_cmos_sensor(pdev, &i); - if (ret >= 0) - { - switch(i) { - case 0x00: sensor_type = "Hyundai CMOS sensor"; break; - case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; - case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; - case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; - case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; - case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; - case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; - case 0x40: sensor_type = "UPA 1021 sensor"; break; - case 0x100: sensor_type = "VGA sensor"; break; - case 0x101: sensor_type = "PAL MR sensor"; break; - default: sensor_type = "unknown type of sensor"; break; - } - } - if (sensor_type != NULL) - Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); - } - } - - /* Turn on camera */ - if (power_save) { - i = pwc_camera_power(pdev, 1); - if (i < 0) - Info("Failed to restore power to the camera! (%d)\n", i); - } - /* Set LED on/off time */ - if (pwc_set_leds(pdev, led_on, led_off) < 0) - Info("Failed to set LED on/off time.\n"); - - /* Find our decompressor, if any */ - pdev->decompressor = pwc_find_decompressor(pdev->type); -#if PWC_DEBUG - Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor); -#endif - pwc_construct(pdev); /* set min/max sizes correct */ - - /* So far, so good. Allocate memory. */ - i = pwc_allocate_buffers(pdev); - if (i < 0) { - Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); - up(&pdev->modlock); - return i; - } - - /* Reset buffers & parameters */ - pwc_reset_buffers(pdev); - for (i = 0; i < default_mbufs; i++) - pdev->image_used[i] = 0; - pdev->vframe_count = 0; - pdev->vframes_dumped = 0; - pdev->vframes_error = 0; - pdev->visoc_errors = 0; - pdev->error_status = 0; -#if PWC_DEBUG - pdev->sequence = 0; -#endif - pwc_construct(pdev); /* set min/max sizes correct */ - - /* Set some defaults */ - pdev->vsnapshot = 0; - - /* Start iso pipe for video; first try the last used video size - (or the default one); if that fails try QCIF/10 or QSIF/10; - it that fails too, give up. - */ - i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); - if (i) { - Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); - if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) - i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); - else - i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); - } - if (i) { - Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); - up(&pdev->modlock); - return i; - } - - i = pwc_isoc_init(pdev); - if (i) { - Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); - up(&pdev->modlock); - return i; - } - - pdev->vopen++; - file->private_data = vdev; - /* lock decompressor; this has a small race condition, since we - could in theory unload pwcx.o between pwc_find_decompressor() - above and this call. I doubt it's ever going to be a problem. - */ - if (pdev->decompressor != NULL) - pdev->decompressor->lock(); - up(&pdev->modlock); - Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); - return 0; -} - -/* Note that all cleanup is done in the reverse order as in _open */ -static int pwc_video_close(struct inode *inode, struct file *file) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - int i; - - Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); - - pdev = (struct pwc_device *)vdev->priv; - if (pdev->vopen == 0) - Info("video_close() called on closed device?\n"); - - /* Dump statistics, but only if a reasonable amount of frames were - processed (to prevent endless log-entries in case of snap-shot - programs) - */ - if (pdev->vframe_count > 20) - Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); - - if (pdev->decompressor != NULL) { - pdev->decompressor->exit(); - pdev->decompressor->unlock(); - pdev->decompressor = NULL; - } - - pwc_isoc_cleanup(pdev); - pwc_free_buffers(pdev); - - /* Turn off LEDS and power down camera, but only when not unplugged */ - if (pdev->error_status != EPIPE) { - /* Turn LEDs off */ - if (pwc_set_leds(pdev, 0, 0) < 0) - Info("Failed to set LED on/off time.\n"); - if (power_save) { - i = pwc_camera_power(pdev, 0); - if (i < 0) - Err("Failed to power down camera (%d)\n", i); - } - } - pdev->vopen = 0; - Trace(TRACE_OPEN, "<< video_close()\n"); - return 0; -} - -/* - * FIXME: what about two parallel reads ???? - * ANSWER: Not supported. You can't open the device more than once, - despite what the V4L1 interface says. First, I don't see - the need, second there's no mechanism of alerting the - 2nd/3rd/... process of events like changing image size. - And I don't see the point of blocking that for the - 2nd/3rd/... process. - In multi-threaded environments reading parallel from any - device is tricky anyhow. - */ - -static ssize_t pwc_video_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - int noblock = file->f_flags & O_NONBLOCK; - DECLARE_WAITQUEUE(wait, current); - int bytes_to_read; - - Trace(TRACE_READ, "video_read(0x%p, %p, %zd) called.\n", vdev, buf, count); - if (vdev == NULL) - return -EFAULT; - pdev = vdev->priv; - if (pdev == NULL) - return -EFAULT; - if (pdev->error_status) - return -pdev->error_status; /* Something happened, report what. */ - - /* In case we're doing partial reads, we don't have to wait for a frame */ - if (pdev->image_read_pos == 0) { - /* Do wait queueing according to the (doc)book */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - /* Check for unplugged/etc. here */ - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status ; - } - if (noblock) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -EWOULDBLOCK; - } - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - /* Decompress and release frame */ - if (pwc_handle_frame(pdev)) - return -EFAULT; - } - - Trace(TRACE_READ, "Copying data to user space.\n"); - if (pdev->vpalette == VIDEO_PALETTE_RAW) - bytes_to_read = pdev->frame_size; - else - bytes_to_read = pdev->view.size; - - /* copy bytes to user space; we allow for partial reads */ - if (count + pdev->image_read_pos > bytes_to_read) - count = bytes_to_read - pdev->image_read_pos; - if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) - return -EFAULT; - pdev->image_read_pos += count; - if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ - pdev->image_read_pos = 0; - pwc_next_image(pdev); - } - return count; -} - -static unsigned int pwc_video_poll(struct file *file, poll_table *wait) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - - if (vdev == NULL) - return -EFAULT; - pdev = vdev->priv; - if (pdev == NULL) - return -EFAULT; - - poll_wait(file, &pdev->frameq, wait); - if (pdev->error_status) - return POLLERR; - if (pdev->full_frames != NULL) /* we have frames waiting */ - return (POLLIN | POLLRDNORM); - - return 0; -} - -static int pwc_video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - DECLARE_WAITQUEUE(wait, current); - - if (vdev == NULL) - return -EFAULT; - pdev = vdev->priv; - if (pdev == NULL) - return -EFAULT; - - switch (cmd) { - /* Query cabapilities */ - case VIDIOCGCAP: - { - struct video_capability *caps = arg; - - strcpy(caps->name, vdev->name); - caps->type = VID_TYPE_CAPTURE; - caps->channels = 1; - caps->audios = 1; - caps->minwidth = pdev->view_min.x; - caps->minheight = pdev->view_min.y; - caps->maxwidth = pdev->view_max.x; - caps->maxheight = pdev->view_max.y; - break; - } - - /* Channel functions (simulate 1 channel) */ - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Webcam"); - return 0; - } - - case VIDIOCSCHAN: - { - /* The spec says the argument is an integer, but - the bttv driver uses a video_channel arg, which - makes sense becasue it also has the norm flag. - */ - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - - - /* Picture functions; contrast etc. */ - case VIDIOCGPICT: - { - struct video_picture *p = arg; - int val; - - val = pwc_get_brightness(pdev); - if (val >= 0) - p->brightness = val; - else - p->brightness = 0xffff; - val = pwc_get_contrast(pdev); - if (val >= 0) - p->contrast = val; - else - p->contrast = 0xffff; - /* Gamma, Whiteness, what's the difference? :) */ - val = pwc_get_gamma(pdev); - if (val >= 0) - p->whiteness = val; - else - p->whiteness = 0xffff; - val = pwc_get_saturation(pdev); - if (val >= 0) - p->colour = val; - else - p->colour = 0xffff; - p->depth = 24; - p->palette = pdev->vpalette; - p->hue = 0xFFFF; /* N/A */ - break; - } - - case VIDIOCSPICT: - { - struct video_picture *p = arg; - /* - * FIXME: Suppose we are mid read - ANSWER: No problem: the firmware of the camera - can handle brightness/contrast/etc - changes at _any_ time, and the palette - is used exactly once in the uncompress - routine. - */ - pwc_set_brightness(pdev, p->brightness); - pwc_set_contrast(pdev, p->contrast); - pwc_set_gamma(pdev, p->whiteness); - pwc_set_saturation(pdev, p->colour); - if (p->palette && p->palette != pdev->vpalette) { - switch (p->palette) { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - pdev->vpalette = p->palette; - return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - break; - default: - return -EINVAL; - break; - } - } - break; - } - - /* Window/size parameters */ - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; - vw->y = 0; - vw->width = pdev->view.x; - vw->height = pdev->view.y; - vw->chromakey = 0; - vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | - (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); - break; - } - - case VIDIOCSWIN: - { - struct video_window *vw = arg; - int fps, snapshot, ret; - - fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; - snapshot = vw->flags & PWC_FPS_SNAPSHOT; - if (fps == 0) - fps = pdev->vframes; - if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) - return 0; - ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); - if (ret) - return ret; - break; - } - - /* We don't have overlay support (yet) */ - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - memset(vb,0,sizeof(*vb)); - break; - } - - /* mmap() functions */ - case VIDIOCGMBUF: - { - /* Tell the user program how much memory is needed for a mmap() */ - struct video_mbuf *vm = arg; - int i; - - memset(vm, 0, sizeof(*vm)); - vm->size = default_mbufs * pdev->len_per_image; - vm->frames = default_mbufs; /* double buffering should be enough for most applications */ - for (i = 0; i < default_mbufs; i++) - vm->offsets[i] = i * pdev->len_per_image; - break; - } - - case VIDIOCMCAPTURE: - { - /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ - struct video_mmap *vm = arg; - - Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); - if (vm->frame < 0 || vm->frame >= default_mbufs) - return -EINVAL; - - /* xawtv is nasty. It probes the available palettes - by setting a very small image size and trying - various palettes... The driver doesn't support - such small images, so I'm working around it. - */ - if (vm->format) - { - switch (vm->format) - { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - break; - default: - return -EINVAL; - break; - } - } - - if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && - (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { - int ret; - - Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); - ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - if (ret) - return ret; - } /* ... size mismatch */ - - /* FIXME: should we lock here? */ - if (pdev->image_used[vm->frame]) - return -EBUSY; /* buffer wasn't available. Bummer */ - pdev->image_used[vm->frame] = 1; - - /* Okay, we're done here. In the SYNC call we wait until a - frame comes available, then expand image into the given - buffer. - In contrast to the CPiA cam the Philips cams deliver a - constant stream, almost like a grabber card. Also, - we have separate buffers for the rawdata and the image, - meaning we can nearly always expand into the requested buffer. - */ - Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); - break; - } - - case VIDIOCSYNC: - { - /* The doc says: "Whenever a buffer is used it should - call VIDIOCSYNC to free this frame up and continue." - - The only odd thing about this whole procedure is - that MCAPTURE flags the buffer as "in use", and - SYNC immediately unmarks it, while it isn't - after SYNC that you know that the buffer actually - got filled! So you better not start a CAPTURE in - the same frame immediately (use double buffering). - This is not a problem for this cam, since it has - extra intermediate buffers, but a hardware - grabber card will then overwrite the buffer - you're working on. - */ - int *mbuf = arg; - int ret; - - Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); - - /* bounds check */ - if (*mbuf < 0 || *mbuf >= default_mbufs) - return -EINVAL; - /* check if this buffer was requested anyway */ - if (pdev->image_used[*mbuf] == 0) - return -EINVAL; - - /* Add ourselves to the frame wait-queue. - - FIXME: needs auditing for safety. - QUESTION: In what respect? I think that using the - frameq is safe now. - */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status; - } - - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - /* The frame is ready. Expand in the image buffer - requested by the user. I don't care if you - mmap() 5 buffers and request data in this order: - buffer 4 2 3 0 1 2 3 0 4 3 1 . . . - Grabber hardware may not be so forgiving. - */ - Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); - pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ - /* Decompress, etc */ - ret = pwc_handle_frame(pdev); - pdev->image_used[*mbuf] = 0; - if (ret) - return -EFAULT; - break; - } - - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - - strcpy(v->name, "Microphone"); - v->audio = -1; /* unknown audio minor */ - v->flags = 0; - v->mode = VIDEO_SOUND_MONO; - v->volume = 0; - v->bass = 0; - v->treble = 0; - v->balance = 0x8000; - v->step = 1; - break; - } - - case VIDIOCSAUDIO: - { - /* Dummy: nothing can be set */ - break; - } - - case VIDIOCGUNIT: - { - struct video_unit *vu = arg; - - vu->video = pdev->vdev->minor & 0x3F; - vu->audio = -1; /* not known yet */ - vu->vbi = -1; - vu->radio = -1; - vu->teletext = -1; - break; - } - default: - return pwc_ioctl(pdev, cmd, arg); - } /* ..switch */ - return 0; -} - -static int pwc_video_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); -} - - -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - - Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); - pdev = vdev->priv; - - pos = (unsigned long)pdev->image_data; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return 0; -} - -/***************************************************************************/ -/* USB functions */ - -/* This function gets called when a new device is plugged in or the usb core - * is loaded. - */ - -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct pwc_device *pdev = NULL; - int vendor_id, product_id, type_id; - int i, hint; - int features = 0; - int video_nr = -1; /* default: use next available device */ - char serial_number[30], *name; - - /* Check if we can handle this device */ - Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", - udev->descriptor.idVendor, udev->descriptor.idProduct, - intf->altsetting->desc.bInterfaceNumber); - - /* the interfaces are probed one by one. We are only interested in the - video interface (0) now. - Interface 1 is the Audio Control, and interface 2 Audio itself. - */ - if (intf->altsetting->desc.bInterfaceNumber > 0) - return -ENODEV; - - vendor_id = udev->descriptor.idVendor; - product_id = udev->descriptor.idProduct; - - if (vendor_id == 0x0471) { - switch (product_id) { - case 0x0302: - Info("Philips PCA645VC USB webcam detected.\n"); - name = "Philips 645 webcam"; - type_id = 645; - break; - case 0x0303: - Info("Philips PCA646VC USB webcam detected.\n"); - name = "Philips 646 webcam"; - type_id = 646; - break; - case 0x0304: - Info("Askey VC010 type 2 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 646; - break; - case 0x0307: - Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); - name = "Philips 675 webcam"; - type_id = 675; - break; - case 0x0308: - Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); - name = "Philips 680 webcam"; - type_id = 680; - break; - case 0x030C: - Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); - name = "Philips 690 webcam"; - type_id = 690; - break; - case 0x0310: - Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); - name = "Philips 730 webcam"; - type_id = 730; - break; - case 0x0311: - Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); - name = "Philips 740 webcam"; - type_id = 740; - break; - case 0x0312: - Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); - name = "Philips 750 webcam"; - type_id = 750; - break; - case 0x0313: - Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); - name = "Philips 720K/40 webcam"; - type_id = 720; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x069A) { - switch(product_id) { - case 0x0001: - Info("Askey VC010 type 1 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 645; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x046d) { - switch(product_id) { - case 0x08b0: - Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); - name = "Logitech QuickCam Pro 3000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b1: - Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); - name = "Logitech QuickCam Notebook Pro"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b2: - Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); - name = "Logitech QuickCam Pro 4000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b3: - Info("Logitech QuickCam Zoom USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - break; - case 0x08B4: - Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b5: - Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); - name = "Logitech QuickCam Orbit"; - type_id = 740; /* CCD sensor */ - features |= FEATURE_MOTOR_PANTILT; - break; - case 0x08b6: - case 0x08b7: - case 0x08b8: - Info("Logitech QuickCam detected (reserved ID).\n"); - name = "Logitech QuickCam (res.)"; - type_id = 730; /* Assuming CMOS */ - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x055d) { - /* I don't know the difference between the C10 and the C30; - I suppose the difference is the sensor, but both cameras - work equally well with a type_id of 675 - */ - switch(product_id) { - case 0x9000: - Info("Samsung MPC-C10 USB webcam detected.\n"); - name = "Samsung MPC-C10"; - type_id = 675; - break; - case 0x9001: - Info("Samsung MPC-C30 USB webcam detected.\n"); - name = "Samsung MPC-C30"; - type_id = 675; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x041e) { - switch(product_id) { - case 0x400c: - Info("Creative Labs Webcam 5 detected.\n"); - name = "Creative Labs Webcam 5"; - type_id = 730; - break; - case 0x4011: - Info("Creative Labs Webcam Pro Ex detected.\n"); - name = "Creative Labs Webcam Pro Ex"; - type_id = 740; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x04cc) { - switch(product_id) { - case 0x8116: - Info("Sotec Afina Eye USB webcam detected.\n"); - name = "Sotec Afina Eye"; - type_id = 730; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x06be) { - switch(product_id) { - case 0x8116: - /* Basicly the same as the Sotec Afina Eye */ - Info("AME CU-001 USB webcam detected.\n"); - name = "AME CU-001"; - type_id = 730; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x06be) { - switch(product_id) { - case 0x8116: - /* This is essentially the same cam as the Sotec Afina Eye */ - Info("AME Co. Afina Eye USB webcam detected.\n"); - name = "AME Co. Afina Eye"; - type_id = 750; - break; - default: - return -ENODEV; - break; - } - - } - else if (vendor_id == 0x0d81) { - switch(product_id) { - case 0x1900: - Info("Visionite VCS-UC300 USB webcam detected.\n"); - name = "Visionite VCS-UC300"; - type_id = 740; /* CCD sensor */ - break; - case 0x1910: - Info("Visionite VCS-UM100 USB webcam detected.\n"); - name = "Visionite VCS-UM100"; - type_id = 730; /* CMOS sensor */ - break; - default: - return -ENODEV; - break; - } - } - else - return -ENODEV; /* Not any of the know types; but the list keeps growing. */ - - memset(serial_number, 0, 30); - usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); - Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); - - if (udev->descriptor.bNumConfigurations > 1) - Info("Warning: more than 1 configuration available.\n"); - - /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ - pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); - if (pdev == NULL) { - Err("Oops, could not allocate memory for pwc_device.\n"); - return -ENOMEM; - } - memset(pdev, 0, sizeof(struct pwc_device)); - pdev->type = type_id; - pdev->vsize = default_size; - pdev->vframes = default_fps; - strcpy(pdev->serial, serial_number); - pdev->features = features; - if (vendor_id == 0x046D && product_id == 0x08B5) - { - /* Logitech QuickCam Orbit - The ranges have been determined experimentally; they may differ from cam to cam. - Also, the exact ranges left-right and up-down are different for my cam - */ - pdev->angle_range.pan_min = -7000; - pdev->angle_range.pan_max = 7000; - pdev->angle_range.tilt_min = -3000; - pdev->angle_range.tilt_max = 2500; - } - - init_MUTEX(&pdev->modlock); - pdev->ptrlock = SPIN_LOCK_UNLOCKED; - - pdev->udev = udev; - init_waitqueue_head(&pdev->frameq); - pdev->vcompression = pwc_preferred_compression; - - /* Allocate video_device structure */ - pdev->vdev = video_device_alloc(); - if (pdev->vdev == 0) - { - Err("Err, cannot allocate video_device struture. Failing probe."); - kfree(pdev); - return -ENOMEM; - } - memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - strcpy(pdev->vdev->name, name); - pdev->vdev->owner = THIS_MODULE; - video_set_drvdata(pdev->vdev, pdev); - - pdev->release = udev->descriptor.bcdDevice; - Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); - - /* Now search device_hint[] table for a match, so we can hint a node number. */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) { - if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && - (device_hint[hint].pdev == NULL)) { - /* so far, so good... try serial number */ - if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { - /* match! */ - video_nr = device_hint[hint].device_node; - Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); - break; - } - } - } - - pdev->vdev->release = video_device_release; - i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); - if (i < 0) { - Err("Failed to register as video device (%d).\n", i); - video_device_release(pdev->vdev); /* Drip... drip... drip... */ - kfree(pdev); /* Oops, no memory leaks please */ - return -EIO; - } - else { - Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); - } - - /* occupy slot */ - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = pdev; - - Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); - usb_set_intfdata (intf, pdev); - return 0; -} - -/* The user janked out the cable... */ -static void usb_pwc_disconnect(struct usb_interface *intf) -{ - struct pwc_device *pdev; - int hint; - - lock_kernel(); - pdev = usb_get_intfdata (intf); - usb_set_intfdata (intf, NULL); - if (pdev == NULL) { - Err("pwc_disconnect() Called without private pointer.\n"); - goto disconnect_out; - } - if (pdev->udev == NULL) { - Err("pwc_disconnect() already called for %p\n", pdev); - goto disconnect_out; - } - if (pdev->udev != interface_to_usbdev(intf)) { - Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); - goto disconnect_out; - } -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); - goto disconnect_out; - } -#endif - - /* We got unplugged; this is signalled by an EPIPE error code */ - if (pdev->vopen) { - Info("Disconnected while webcam is in use!\n"); - pdev->error_status = EPIPE; - } - - /* Alert waiting processes */ - wake_up_interruptible(&pdev->frameq); - /* Wait until device is closed */ - while (pdev->vopen) - schedule(); - /* Device is now closed, so we can safely unregister it */ - Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); - video_unregister_device(pdev->vdev); - - /* Free memory (don't set pdev to 0 just yet) */ - kfree(pdev); - -disconnect_out: - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - - unlock_kernel(); -} - - -/* *grunt* We have to do atoi ourselves :-( */ -static int pwc_atoi(const char *s) -{ - int k = 0; - - k = 0; - while (*s != '\0' && *s >= '0' && *s <= '9') { - k = 10 * k + (*s - '0'); - s++; - } - return k; -} - - -/* - * Initialization code & module stuff - */ - -static char *size = NULL; -static int fps = 0; -static int fbufs = 0; -static int mbufs = 0; -static int trace = -1; -static int compression = -1; -static int leds[2] = { -1, -1 }; -static char *dev_hint[MAX_DEV_HINTS] = { }; - -MODULE_PARM(size, "s"); -MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); -MODULE_PARM(fps, "i"); -MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); -MODULE_PARM(fbufs, "i"); -MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); -MODULE_PARM(mbufs, "i"); -MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); -MODULE_PARM(trace, "i"); -MODULE_PARM_DESC(trace, "For debugging purposes"); -MODULE_PARM(power_save, "i"); -MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); -MODULE_PARM(compression, "i"); -MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); -MODULE_PARM(leds, "2i"); -MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); -MODULE_PARM(dev_hint, "0-20s"); -MODULE_PARM_DESC(dev_hint, "Device node hints"); - -MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); -MODULE_AUTHOR("Nemosoft Unv. "); -MODULE_LICENSE("GPL"); - -static int __init usb_pwc_init(void) -{ - int i, sz; - char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; - - Info("Philips webcam module version " PWC_VERSION " loaded.\n"); - Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); - Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); - Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); - - if (fps) { - if (fps < 4 || fps > 30) { - Err("Framerate out of bounds (4-30).\n"); - return -EINVAL; - } - default_fps = fps; - Info("Default framerate set to %d.\n", default_fps); - } - - if (size) { - /* string; try matching with array */ - for (sz = 0; sz < PSZ_MAX; sz++) { - if (!strcmp(sizenames[sz], size)) { /* Found! */ - default_size = sz; - break; - } - } - if (sz == PSZ_MAX) { - Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); - return -EINVAL; - } - Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); - } - if (mbufs) { - if (mbufs < 1 || mbufs > MAX_IMAGES) { - Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); - return -EINVAL; - } - default_mbufs = mbufs; - Info("Number of image buffers set to %d.\n", default_mbufs); - } - if (fbufs) { - if (fbufs < 2 || fbufs > MAX_FRAMES) { - Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); - return -EINVAL; - } - default_fbufs = fbufs; - Info("Number of frame buffers set to %d.\n", default_fbufs); - } - if (trace >= 0) { - Info("Trace options: 0x%04x\n", trace); - pwc_trace = trace; - } - if (compression >= 0) { - if (compression > 3) { - Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); - return -EINVAL; - } - pwc_preferred_compression = compression; - Info("Preferred compression set to %d.\n", pwc_preferred_compression); - } - if (power_save) - Info("Enabling power save on open/close.\n"); - if (leds[0] >= 0) - led_on = leds[0]; - if (leds[1] >= 0) - led_off = leds[1]; - - /* Big device node whoopla. Basicly, it allows you to assign a - device node (/dev/videoX) to a camera, based on its type - & serial number. The format is [type[.serialnumber]:]node. - - Any camera that isn't matched by these rules gets the next - available free device node. - */ - for (i = 0; i < MAX_DEV_HINTS; i++) { - char *s, *colon, *dot; - - /* This loop also initializes the array */ - device_hint[i].pdev = NULL; - s = dev_hint[i]; - if (s != NULL && *s != '\0') { - device_hint[i].type = -1; /* wildcard */ - strcpy(device_hint[i].serial_number, "*"); - - /* parse string: chop at ':' & '/' */ - colon = dot = s; - while (*colon != '\0' && *colon != ':') - colon++; - while (*dot != '\0' && *dot != '.') - dot++; - /* Few sanity checks */ - if (*dot != '\0' && dot > colon) { - Err("Malformed camera hint: the colon must be after the dot.\n"); - return -EINVAL; - } - - if (*colon == '\0') { - /* No colon */ - if (*dot != '\0') { - Err("Malformed camera hint: no colon + device node given.\n"); - return -EINVAL; - } - else { - /* No type or serial number specified, just a number. */ - device_hint[i].device_node = pwc_atoi(s); - } - } - else { - /* There's a colon, so we have at least a type and a device node */ - device_hint[i].type = pwc_atoi(s); - device_hint[i].device_node = pwc_atoi(colon + 1); - if (*dot != '\0') { - /* There's a serial number as well */ - int k; - - dot++; - k = 0; - while (*dot != ':' && k < 29) { - device_hint[i].serial_number[k++] = *dot; - dot++; - } - device_hint[i].serial_number[k] = '\0'; - } - } -#if PWC_DEBUG - Debug("device_hint[%d]:\n", i); - Debug(" type : %d\n", device_hint[i].type); - Debug(" serial# : %s\n", device_hint[i].serial_number); - Debug(" node : %d\n", device_hint[i].device_node); -#endif - } - else - device_hint[i].type = 0; /* not filled */ - } /* ..for MAX_DEV_HINTS */ - - Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); - return usb_register(&pwc_driver); -} - -static void __exit usb_pwc_exit(void) -{ - Trace(TRACE_MODULE, "Deregistering driver.\n"); - usb_deregister(&pwc_driver); - Info("Philips webcam module removed.\n"); -} - -module_init(usb_pwc_init); -module_exit(usb_pwc_exit); - diff -Nru a/drivers/usb/media/pwc-ioctl.h b/drivers/usb/media/pwc-ioctl.h --- a/drivers/usb/media/pwc-ioctl.h 2004-10-18 14:56:29 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,279 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. webcam@smcc.demon.nl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is pwc-ioctl.h belonging to PWC 8.12.1 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - - - /* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 - - -/* structure for transfering x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) - -#endif diff -Nru a/drivers/usb/media/pwc-misc.c b/drivers/usb/media/pwc-misc.c --- a/drivers/usb/media/pwc-misc.c 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,146 +0,0 @@ -/* Linux driver for Philips webcam - Various miscellaneous functions and tables. - (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -#include "pwc.h" - -struct pwc_coord pwc_image_sizes[PSZ_MAX] = -{ - { 128, 96, 0 }, - { 160, 120, 0 }, - { 176, 144, 0 }, - { 320, 240, 0 }, - { 352, 288, 0 }, - { 640, 480, 0 }, -}; - -/* x,y -> PSZ_ */ -int pwc_decode_size(struct pwc_device *pdev, int width, int height) -{ - int i, find; - - /* Make sure we don't go beyond our max size. - NB: we have different limits for RAW and normal modes. In case - you don't have the decompressor loaded or use RAW mode, - the maximum viewable size is smaller. - */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) - { - if (width > pdev->abs_max.x || height > pdev->abs_max.y) - { - Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); - return -1; - } - } - else - { - if (width > pdev->view_max.x || height > pdev->view_max.y) - { - Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n"); - return -1; - } - } - - /* Find the largest size supported by the camera that fits into the - requested size. - */ - find = -1; - for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1 << i)) { - if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) - find = i; - } - } - return find; -} - -/* initialize variables depending on type and decompressor*/ -void pwc_construct(struct pwc_device *pdev) -{ - switch(pdev->type) { - case 645: - case 646: - pdev->view_min.x = 128; - pdev->view_min.y = 96; - pdev->view_max.x = 352; - pdev->view_max.y = 288; - pdev->abs_max.x = 352; - pdev->abs_max.y = 288; - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; - pdev->vcinterface = 2; - pdev->vendpoint = 4; - pdev->frame_header_size = 0; - pdev->frame_trailer_size = 0; - break; - case 675: - case 680: - case 690: - pdev->view_min.x = 128; - pdev->view_min.y = 96; - /* Anthill bug #38: PWC always reports max size, even without PWCX */ - if (pdev->decompressor != NULL) { - pdev->view_max.x = 640; - pdev->view_max.y = 480; - } - else { - pdev->view_max.x = 352; - pdev->view_max.y = 288; - } - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; - pdev->vcinterface = 3; - pdev->vendpoint = 4; - pdev->frame_header_size = 0; - pdev->frame_trailer_size = 0; - break; - case 720: - case 730: - case 740: - case 750: - pdev->view_min.x = 160; - pdev->view_min.y = 120; - /* Anthill bug #38: PWC always reports max size, even without PWCX */ - if (pdev->decompressor != NULL) { - pdev->view_max.x = 640; - pdev->view_max.y = 480; - } - else { - /* We use CIF, not SIF since some tools really need CIF. So we cheat a bit. */ - pdev->view_max.x = 352; - pdev->view_max.y = 288; - } - pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; - pdev->vcinterface = 3; - pdev->vendpoint = 5; - pdev->frame_header_size = TOUCAM_HEADER_SIZE; - pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; - break; - } - pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ - pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; - pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; - /* length of image, in YUV format; always allocate enough memory. */ - pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2; -} - - diff -Nru a/drivers/usb/media/pwc-uncompress.c b/drivers/usb/media/pwc-uncompress.c --- a/drivers/usb/media/pwc-uncompress.c 2004-10-18 14:56:32 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,180 +0,0 @@ -/* Linux driver for Philips webcam - Decompression frontend. - (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/* - This is where the decompression routines register and unregister - themselves. It also has a decompressor wrapper function. -*/ - -#include -#include -// #include - -#include "pwc.h" -#include "pwc-uncompress.h" - - -/* This contains a list of all registered decompressors */ -static LIST_HEAD(pwc_decompressor_list); - -/* Should the pwc_decompress structure ever change, we increase the - version number so that we don't get nasty surprises, or can - dynamically adjust our structure. - */ -const int pwc_decompressor_version = PWC_MAJOR; - -/* Add decompressor to list, ignoring duplicates */ -void pwc_register_decompressor(struct pwc_decompressor *pwcd) -{ - if (pwc_find_decompressor(pwcd->type) == NULL) { - Trace(TRACE_PWCX, "Adding decompressor for model %d.\n", pwcd->type); - list_add_tail(&pwcd->pwcd_list, &pwc_decompressor_list); - } -} - -/* Remove decompressor from list */ -void pwc_unregister_decompressor(int type) -{ - struct pwc_decompressor *find; - - find = pwc_find_decompressor(type); - if (find != NULL) { - Trace(TRACE_PWCX, "Removing decompressor for model %d.\n", type); - list_del(&find->pwcd_list); - } -} - -/* Find decompressor in list */ -struct pwc_decompressor *pwc_find_decompressor(int type) -{ - struct list_head *tmp; - struct pwc_decompressor *pwcd; - - list_for_each(tmp, &pwc_decompressor_list) { - pwcd = list_entry(tmp, struct pwc_decompressor, pwcd_list); - if (pwcd->type == type) - return pwcd; - } - return NULL; -} - - - -int pwc_decompress(struct pwc_device *pdev) -{ - struct pwc_frame_buf *fbuf; - int n, line, col, stride; - void *yuv, *image; - u16 *src; - u16 *dsty, *dstu, *dstv; - - if (pdev == NULL) - return -EFAULT; -#if defined(__KERNEL__) && defined(PWC_MAGIC) - if (pdev->magic != PWC_MAGIC) { - Err("pwc_decompress(): magic failed.\n"); - return -EFAULT; - } -#endif - - fbuf = pdev->read_frame; - if (fbuf == NULL) - return -EFAULT; - image = pdev->image_ptr[pdev->fill_image]; - if (!image) - return -EFAULT; - - yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ - - /* Raw format; that's easy... */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) - { - memcpy(image, yuv, pdev->frame_size); - return 0; - } - - if (pdev->vbandlength == 0) { - /* Uncompressed mode. We copy the data into the output buffer, - using the viewport size (which may be larger than the image - size). Unfortunately we have to do a bit of byte stuffing - to get the desired output format/size. - */ - /* - * We do some byte shuffling here to go from the - * native format to YUV420P. - */ - src = (u16 *)yuv; - n = pdev->view.x * pdev->view.y; - - /* offset in Y plane */ - stride = pdev->view.x * pdev->offset.y + pdev->offset.x; - dsty = (u16 *)(image + stride); - - /* offsets in U/V planes */ - stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; - dstu = (u16 *)(image + n + stride); - dstv = (u16 *)(image + n + n / 4 + stride); - - /* increment after each line */ - stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ - - for (line = 0; line < pdev->image.y; line++) { - for (col = 0; col < pdev->image.x; col += 4) { - *dsty++ = *src++; - *dsty++ = *src++; - if (line & 1) - *dstv++ = *src++; - else - *dstu++ = *src++; - } - dsty += stride; - if (line & 1) - dstv += (stride >> 1); - else - dstu += (stride >> 1); - } - } - else { - /* Compressed; the decompressor routines will write the data - in planar format immediately. - */ - int flags; - - flags = PWCX_FLAG_PLANAR; - if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) - flags |= PWCX_FLAG_BAYER; - - if (pdev->decompressor) - pdev->decompressor->decompress( - &pdev->image, &pdev->view, &pdev->offset, - yuv, image, - flags, - pdev->decompress_data, pdev->vbandlength); - else - return -ENXIO; /* No such device or address: missing decompressor */ - } - return 0; -} - -/* Make sure these functions are available for the decompressor plugin - both when this code is compiled into the kernel or as as module. - */ - -EXPORT_SYMBOL_NOVERS(pwc_decompressor_version); -EXPORT_SYMBOL(pwc_register_decompressor); -EXPORT_SYMBOL(pwc_unregister_decompressor); diff -Nru a/drivers/usb/media/pwc-uncompress.h b/drivers/usb/media/pwc-uncompress.h --- a/drivers/usb/media/pwc-uncompress.h 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,84 +0,0 @@ -/* (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This file is the bridge between the kernel module and the plugin; it - describes the structures and datatypes used in both modules. Any - significant change should be reflected by increasing the - pwc_decompressor_version major number. - */ -#ifndef PWC_UNCOMPRESS_H -#define PWC_UNCOMPRESS_H - -#include -#include -#include - -#include "pwc-ioctl.h" - -/* from pwc-dec.h */ -#define PWCX_FLAG_PLANAR 0x0001 -/* */ - - -#ifdef __cplusplus -extern "C" { -#endif - -/* The decompressor structure. - Every type of decompressor registers itself with the main module. - When a device is opened, it looks up the correct compressor, and - uses that when a compressed video mode is requested. - */ -struct pwc_decompressor -{ - int type; /* type of camera (645, 680, etc) */ - int table_size; /* memory needed */ - - void (* init)(int type, int release, void *buffer, void *table); /* Initialization routine; should be called after each set_video_mode */ - void (* exit)(void); /* Cleanup routine */ - void (* decompress)(struct pwc_coord *image, struct pwc_coord *view, - struct pwc_coord *offset, - void *src, void *dst, int flags, - void *table, int bandlength); - void (* lock)(void); /* make sure module cannot be unloaded */ - void (* unlock)(void); /* release lock on module */ - - struct list_head pwcd_list; -}; - - -/* Our structure version number. Is set to the version number major */ -extern const int pwc_decompressor_version; - -/* Adds decompressor to list, based on its 'type' field (which matches the 'type' field in pwc_device; ignores any double requests */ -extern void pwc_register_decompressor(struct pwc_decompressor *pwcd); -/* Removes decompressor, based on the type number */ -extern void pwc_unregister_decompressor(int type); -/* Returns pointer to decompressor struct, or NULL if it doesn't exist */ -extern struct pwc_decompressor *pwc_find_decompressor(int type); - -#ifdef CONFIG_USB_PWCX -/* If the decompressor is compiled in, we must call these manually */ -extern int usb_pwcx_init(void); -extern void usb_pwcx_exit(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff -Nru a/drivers/usb/media/pwc.h b/drivers/usb/media/pwc.h --- a/drivers/usb/media/pwc.h 2004-10-18 14:56:33 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,271 +0,0 @@ -/* (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef PWC_H -#define PWC_H - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pwc-uncompress.h" -#include "pwc-ioctl.h" - -/* Defines and structures for the Philips webcam */ -/* Used for checking memory corruption/pointer validation */ -#define PWC_MAGIC 0x89DC10ABUL -#undef PWC_MAGIC - -/* Turn some debugging options on/off */ -#define PWC_DEBUG 0 - -/* Trace certain actions in the driver */ -#define TRACE_MODULE 0x0001 -#define TRACE_PROBE 0x0002 -#define TRACE_OPEN 0x0004 -#define TRACE_READ 0x0008 -#define TRACE_MEMORY 0x0010 -#define TRACE_FLOW 0x0020 -#define TRACE_SIZE 0x0040 -#define TRACE_PWCX 0x0080 -#define TRACE_SEQUENCE 0x1000 - -#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) -#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) -#define Info(A...) printk(KERN_INFO PWC_NAME " " A) -#define Err(A...) printk(KERN_ERR PWC_NAME " " A) - - -/* Defines for ToUCam cameras */ -#define TOUCAM_HEADER_SIZE 8 -#define TOUCAM_TRAILER_SIZE 4 - -#define FEATURE_MOTOR_PANTILT 0x0001 - -/* Version block */ -#define PWC_MAJOR 9 -#define PWC_MINOR 0 -#define PWC_VERSION "9.0.1" -#define PWC_NAME "pwc" - -/* Turn certain features on/off */ -#define PWC_INT_PIPE 0 - -/* Ignore errors in the first N frames, to allow for startup delays */ -#define FRAME_LOWMARK 5 - -/* Size and number of buffers for the ISO pipe. */ -#define MAX_ISO_BUFS 2 -#define ISO_FRAMES_PER_DESC 10 -#define ISO_MAX_FRAME_SIZE 960 -#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) - -/* Frame buffers: contains compressed or uncompressed video data. */ -#define MAX_FRAMES 5 -/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ -#define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) - -/* Absolute maximum number of buffers available for mmap() */ -#define MAX_IMAGES 10 - -/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ -struct pwc_iso_buf -{ - void *data; - int length; - int read; - struct urb *urb; -}; - -/* intermediate buffers with raw data from the USB cam */ -struct pwc_frame_buf -{ - void *data; - volatile int filled; /* number of bytes filled */ - struct pwc_frame_buf *next; /* list */ -#if PWC_DEBUG - int sequence; /* Sequence number */ -#endif -}; - -struct pwc_device -{ - struct video_device *vdev; -#ifdef PWC_MAGIC - int magic; -#endif - /* Pointer to our usb_device */ - struct usb_device *udev; - - int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ - int release; /* release number */ - int features; /* feature bits */ - char serial[30]; /* serial number (string) */ - int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ - int usb_init; /* set when the cam has been initialized over USB */ - - /*** Video data ***/ - int vopen; /* flag */ - int vendpoint; /* video isoc endpoint */ - int vcinterface; /* video control interface */ - int valternate; /* alternate interface needed */ - int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ - int vpalette; /* palette: 420P, RAW or RGBBAYER */ - int vframe_count; /* received frames */ - int vframes_dumped; /* counter for dumped frames */ - int vframes_error; /* frames received in error */ - int vmax_packet_size; /* USB maxpacket size */ - int vlast_packet_size; /* for frame synchronisation */ - int visoc_errors; /* number of contiguous ISOC errors */ - int vcompression; /* desired compression factor */ - int vbandlength; /* compressed band length; 0 is uncompressed */ - char vsnapshot; /* snapshot mode */ - char vsync; /* used by isoc handler */ - char vmirror; /* for ToUCaM series */ - - int cmd_len; - unsigned char cmd_buf[13]; - - /* The image acquisition requires 3 to 4 steps: - 1. data is gathered in short packets from the USB controller - 2. data is synchronized and packed into a frame buffer - 3a. in case data is compressed, decompress it directly into image buffer - 3b. in case data is uncompressed, copy into image buffer with viewport - 4. data is transferred to the user process - - Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... - We have in effect a back-to-back-double-buffer system. - */ - /* 1: isoc */ - struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; - char iso_init; - - /* 2: frame */ - struct pwc_frame_buf *fbuf; /* all frames */ - struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ - struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ - struct pwc_frame_buf *fill_frame; /* frame currently being filled */ - struct pwc_frame_buf *read_frame; /* frame currently read by user process */ - int frame_header_size, frame_trailer_size; - int frame_size; - int frame_total_size; /* including header & trailer */ - int drop_frames; -#if PWC_DEBUG - int sequence; /* Debugging aid */ -#endif - - /* 3: decompression */ - struct pwc_decompressor *decompressor; /* function block with decompression routines */ - void *decompress_data; /* private data for decompression engine */ - - /* 4: image */ - /* We have an 'image' and a 'view', where 'image' is the fixed-size image - as delivered by the camera, and 'view' is the size requested by the - program. The camera image is centered in this viewport, laced with - a gray or black border. view_min <= image <= view <= view_max; - */ - int image_mask; /* bitmask of supported sizes */ - struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ - struct pwc_coord abs_max; /* maximum supported size with compression */ - struct pwc_coord image, view; /* image and viewport size */ - struct pwc_coord offset; /* offset within the viewport */ - - void *image_data; /* total buffer, which is subdivided into ... */ - void *image_ptr[MAX_IMAGES]; /* ...several images... */ - int fill_image; /* ...which are rotated. */ - int len_per_image; /* length per image */ - int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ - int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ - - struct semaphore modlock; /* to prevent races in video_open(), etc */ - spinlock_t ptrlock; /* for manipulating the buffer pointers */ - - /*** motorized pan/tilt feature */ - struct pwc_mpt_range angle_range; - int pan_angle; /* in degrees * 100 */ - int tilt_angle; /* absolute angle; 0,0 is home position */ - - /*** Misc. data ***/ - wait_queue_head_t frameq; /* When waiting for a frame to finish... */ -#if PWC_INT_PIPE - void *usb_int_handler; /* for the interrupt endpoint */ -#endif -}; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Global variables */ -extern int pwc_trace; -extern int pwc_preferred_compression; - -/** functions in pwc-if.c */ -int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); - -/** Functions in pwc-misc.c */ -/* sizes in pixels */ -extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; - -int pwc_decode_size(struct pwc_device *pdev, int width, int height); -void pwc_construct(struct pwc_device *pdev); - -/** Functions in pwc-ctrl.c */ -/* Request a certain video mode. Returns < 0 if not possible */ -extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); -/* Calculate the number of bytes per image (not frame) */ -extern void pwc_set_image_buffer_size(struct pwc_device *pdev); - -/* Various controls; should be obvious. Value 0..65535, or < 0 on error */ -extern int pwc_get_brightness(struct pwc_device *pdev); -extern int pwc_set_brightness(struct pwc_device *pdev, int value); -extern int pwc_get_contrast(struct pwc_device *pdev); -extern int pwc_set_contrast(struct pwc_device *pdev, int value); -extern int pwc_get_gamma(struct pwc_device *pdev); -extern int pwc_set_gamma(struct pwc_device *pdev, int value); -extern int pwc_get_saturation(struct pwc_device *pdev); -extern int pwc_set_saturation(struct pwc_device *pdev, int value); -extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); -extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); -extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); - -/* Power down or up the camera; not supported by all models */ -extern int pwc_camera_power(struct pwc_device *pdev, int power); - -/* Private ioctl()s; see pwc-ioctl.h */ -extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); - - -/** pwc-uncompress.c */ -/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ -extern int pwc_decompress(struct pwc_device *pdev); - -#ifdef __cplusplus -} -#endif - - -#endif diff -Nru a/drivers/usb/media/pwc_kiara.h b/drivers/usb/media/pwc_kiara.h --- a/drivers/usb/media/pwc_kiara.h 2004-10-18 14:56:28 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,270 +0,0 @@ - /* SQCIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* QSIF */ - { - /* 5 fps */ - { - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - }, - /* 10 fps */ - { - {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - }, - /* 15 fps */ - { - {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, - {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, - {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, - {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, - }, - /* 20 fps */ - { - {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, - {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, - {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, - {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, - }, - /* 25 fps */ - { - {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, - {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, - {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, - {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, - }, - /* 30 fps */ - { - {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, - {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, - {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, - {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, - }, - }, - /* QCIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* SIF */ - { - /* 5 fps */ - { - {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, - {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, - {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, - {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, - }, - /* 10 fps */ - { - {0, }, - {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, - {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, - {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, - }, - /* 15 fps */ - { - {0, }, - {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, - {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, - {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, - }, - /* 20 fps */ - { - {0, }, - {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, - {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, - {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, - }, - /* 25 fps */ - { - {0, }, - {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, - {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, - {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, - }, - /* 30 fps */ - { - {0, }, - {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, - {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, - {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, - }, - }, - /* CIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* VGA */ - { - /* 5 fps */ - { - {0, }, - {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, - {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, - {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, - }, - /* 10 fps */ - { - {0, }, - {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, - {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, - {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, - }, - /* 15 fps */ - { - {0, }, - {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, - {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, - {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, diff -Nru a/drivers/usb/media/pwc_nala.h b/drivers/usb/media/pwc_nala.h --- a/drivers/usb/media/pwc_nala.h 2004-10-18 14:56:20 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,66 +0,0 @@ - /* SQCIF */ - { - {0, 0, {0x04, 0x01, 0x03}}, - {8, 0, {0x05, 0x01, 0x03}}, - {7, 0, {0x08, 0x01, 0x03}}, - {7, 0, {0x0A, 0x01, 0x03}}, - {6, 0, {0x0C, 0x01, 0x03}}, - {5, 0, {0x0F, 0x01, 0x03}}, - {4, 0, {0x14, 0x01, 0x03}}, - {3, 0, {0x18, 0x01, 0x03}}, - }, - /* QSIF */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, - /* QCIF */ - { - {0, 0, {0x04, 0x01, 0x02}}, - {8, 0, {0x05, 0x01, 0x02}}, - {7, 0, {0x08, 0x01, 0x02}}, - {6, 0, {0x0A, 0x01, 0x02}}, - {5, 0, {0x0C, 0x01, 0x02}}, - {4, 0, {0x0F, 0x01, 0x02}}, - {1, 0, {0x14, 0x01, 0x02}}, - {1, 0, {0x18, 0x01, 0x02}}, - }, - /* SIF */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, - /* CIF */ - { - {4, 0, {0x04, 0x01, 0x01}}, - {7, 1, {0x05, 0x03, 0x01}}, - {6, 1, {0x08, 0x03, 0x01}}, - {4, 1, {0x0A, 0x03, 0x01}}, - {3, 1, {0x0C, 0x03, 0x01}}, - {2, 1, {0x0F, 0x03, 0x01}}, - {0}, - {0}, - }, - /* VGA */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, diff -Nru a/drivers/usb/media/pwc_timon.h b/drivers/usb/media/pwc_timon.h --- a/drivers/usb/media/pwc_timon.h 2004-10-18 14:56:49 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,270 +0,0 @@ - /* SQCIF */ - { - /* 5 fps */ - { - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - }, - /* 10 fps */ - { - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - }, - /* 15 fps */ - { - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - }, - /* 20 fps */ - { - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - }, - /* 25 fps */ - { - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - }, - /* 30 fps */ - { - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - }, - }, - /* QSIF */ - { - /* 5 fps */ - { - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - }, - /* 10 fps */ - { - {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - }, - /* 15 fps */ - { - {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, - {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - }, - /* 20 fps */ - { - {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, - {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, - }, - /* 25 fps */ - { - {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, - {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, - {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, - {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, - {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, - }, - }, - /* QCIF */ - { - /* 5 fps */ - { - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - }, - /* 10 fps */ - { - {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, - {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, - }, - /* 15 fps */ - { - {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, - {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, - }, - /* 20 fps */ - { - {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, - {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, - {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, - }, - /* 25 fps */ - { - {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, - {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, - {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, - {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, - {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, - }, - }, - /* SIF */ - { - /* 5 fps */ - { - {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, - {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, - {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, - {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, - {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, - {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, - {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, - {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, - {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, - {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, - }, - /* 25 fps */ - { - {0, }, - {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, - {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, - {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, - {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, - {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, - }, - }, - /* CIF */ - { - /* 5 fps */ - { - {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, - {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, - {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, - {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, - {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, - {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, - {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, - {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, - {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, - {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, - }, - /* 25 fps */ - { - {0, }, - {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, - {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, - {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, - {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, - {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, - }, - }, - /* VGA */ - { - /* 5 fps */ - { - {0, }, - {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, - {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, - {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, - {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, - {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, - {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, - {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c --- a/drivers/usb/media/se401.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/media/se401.c 2004-10-18 14:56:28 -07:00 @@ -53,9 +53,9 @@ MODULE_AUTHOR("Jeroen Vreeken "); MODULE_DESCRIPTION("SE401 USB Camera Driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(flickerless, "i"); +module_param(flickerless, int, 0); MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); -MODULE_PARM(video_nr, "i"); +module_param(video_nr, int, 0); static struct usb_driver se401_driver; diff -Nru a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h --- a/drivers/usb/media/sn9c102.h 2004-10-18 14:56:31 -07:00 +++ b/drivers/usb/media/sn9c102.h 2004-10-18 14:56:31 -07:00 @@ -31,6 +31,7 @@ #include #include #include +#include #include "sn9c102_sensor.h" @@ -39,6 +40,7 @@ #define SN9C102_DEBUG #define SN9C102_DEBUG_LEVEL 2 #define SN9C102_MAX_DEVICES 64 +#define SN9C102_PRESERVE_IMGSCALE 0 #define SN9C102_MAX_FRAMES 32 #define SN9C102_URBS 2 #define SN9C102_ISO_PACKETS 7 @@ -51,8 +53,8 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.01-beta" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) +#define SN9C102_MODULE_VERSION "1:1.08" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 8) SN9C102_ID_TABLE; SN9C102_SENSOR_TABLE; diff -Nru a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c --- a/drivers/usb/media/sn9c102_core.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/media/sn9c102_core.c 2004-10-18 14:55:54 -07:00 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -83,7 +84,7 @@ /*****************************************************************************/ -typedef char sn9c102_sof_header_t[7]; +typedef char sn9c102_sof_header_t[12]; typedef char sn9c102_eof_header_t[4]; static sn9c102_sof_header_t sn9c102_sof_header[] = { @@ -91,8 +92,6 @@ {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, }; -/* Number of random bytes that complete the SOF above headers */ -#define SN9C102_SOFLEN 5 static sn9c102_eof_header_t sn9c102_eof_header[] = { {0x00, 0x00, 0x00, 0x00}, @@ -237,9 +236,6 @@ u8* buff = cam->control_buffer; int res; - if (index == 0x18) - value = (value & 0xcf) | (cam->reg[0x18] & 0x30); - *buff = value; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, @@ -443,14 +439,15 @@ static void* sn9c102_find_sof_header(void* mem, size_t len) { - size_t soflen=sizeof(sn9c102_sof_header_t), SOFLEN=SN9C102_SOFLEN, i; + size_t soflen = sizeof(sn9c102_sof_header_t), i; u8 j, n = sizeof(sn9c102_sof_header) / soflen; - for (i = 0; (len >= soflen+SOFLEN) && (i <= len-soflen-SOFLEN); i++) + for (i = 0; (len >= soflen) && (i <= len - soflen); i++) for (j = 0; j < n; j++) - if (!memcmp(mem + i, sn9c102_sof_header[j], soflen)) + /* It's enough to compare 7 bytes */ + if (!memcmp(mem + i, sn9c102_sof_header[j], 7)) /* Skips the header */ - return mem + i + soflen + SOFLEN; + return mem + i + soflen; return NULL; } @@ -517,10 +514,12 @@ PDBGG("Isochrnous frame: length %u, #%u i", len, i) - /* NOTE: It is probably correct to assume that SOF and EOF + /* + NOTE: It is probably correct to assume that SOF and EOF headers do not occur between two consecutive packets, but who knows..Whatever is the truth, this assumption - doesn't introduce bugs. */ + doesn't introduce bugs. + */ redo: sof = sn9c102_find_sof_header(pos, len); @@ -764,9 +763,11 @@ return (u8)val; } -/* NOTE 1: being inside one of the following methods implies that the v4l +/* + NOTE 1: being inside one of the following methods implies that the v4l device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long */ + NOTE 2: buffers are PAGE_SIZE long +*/ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) { @@ -1019,24 +1020,6 @@ static ssize_t -sn9c102_store_redblue(struct class_device* cd, const char* buf, size_t len) -{ - ssize_t res = 0; - u8 value; - ssize_t count; - - value = sn9c102_strtou8(buf, len, &count); - if (!count) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, "0x10", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); - - return res; -} - - -static ssize_t sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) { ssize_t res = 0; @@ -1062,7 +1045,6 @@ sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(redblue, S_IWUGO, NULL, sn9c102_store_redblue); static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); @@ -1072,7 +1054,6 @@ video_device_create_file(v4ldev, &class_device_attr_reg); video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_redblue); video_device_create_file(v4ldev, &class_device_attr_green); if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); @@ -1118,10 +1099,6 @@ ae_endy = v_size / 2; int err = 0; - /* These are a sort of stroboscopic signal for some sensors */ - err += sn9c102_write_reg(cam, h_size, 0x1a); - err += sn9c102_write_reg(cam, v_size, 0x1b); - err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); err += sn9c102_write_reg(cam, h_size, 0x15); @@ -1134,8 +1111,7 @@ return -EIO; PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " - "%u %u %u %u %u %u", h_start, v_start, h_size, v_size, ho_size, - vo_size) + "%u %u %u %u", h_start, v_start, h_size, v_size) return 0; } @@ -1229,7 +1205,10 @@ struct sn9c102_device* cam; int err = 0; - /* This the only safe way to prevent race conditions with disconnect */ + /* + This is the only safe way to prevent race conditions with + disconnect + */ if (!down_read_trylock(&sn9c102_disconnect)) return -ERESTARTSYS; @@ -1727,6 +1706,12 @@ return -EINVAL; } + /* Preserve R,G or B origin */ + rect->left = (s->_rect.left & 1L) ? + rect->left | 1L : rect->left & ~1L; + rect->top = (s->_rect.top & 1L) ? + rect->top | 1L : rect->top & ~1L; + if (rect->width < 16) rect->width = 16; if (rect->height < 16) @@ -1747,13 +1732,15 @@ rect->width &= ~15L; rect->height &= ~15L; - { /* calculate the scaling factor */ + if (SN9C102_PRESERVE_IMGSCALE) { + /* Calculate the actual scaling factor */ u32 a, b; a = rect->width * rect->height; b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : - ((a / b) > 4 ? 4 : (a / b)))) : 1; - } + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; + } else + scale = 1; if (cam->stream == STREAM_ON) { cam->stream = STREAM_INTERRUPT; @@ -1879,12 +1866,12 @@ memcpy(&rect, &(s->_rect), sizeof(rect)); - { /* calculate the scaling factor */ + { /* calculate the actual scaling factor */ u32 a, b; a = rect.width * rect.height; b = pix->width * pix->height; - scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : - ((a / b) > 4 ? 4 : (a / b)))) : 1; + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; } rect.width = scale * pix->width; @@ -1895,13 +1882,21 @@ if (rect.height < 16) rect.height = 16; if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left+bounds->width - rect.left; + rect.width = bounds->left + bounds->width - rect.left; if (rect.height > bounds->top + bounds->height - rect.top) rect.height = bounds->top + bounds->height - rect.top; rect.width &= ~15L; rect.height &= ~15L; + { /* adjust the scaling factor */ + u32 a, b; + a = rect.width * rect.height; + b = pix->width * pix->height; + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; + } + pix->width = rect.width / scale; pix->height = rect.height / scale; @@ -2119,7 +2114,7 @@ spin_lock_irqsave(&cam->queue_lock, lock_flags); f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); - list_del(&cam->outqueue); + list_del(cam->outqueue.next); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); f->state = F_UNUSED; diff -Nru a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c --- a/drivers/usb/media/sn9c102_pas106b.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/media/sn9c102_pas106b.c 2004-10-18 14:55:54 -07:00 @@ -40,13 +40,12 @@ err += sn9c102_i2c_write(cam, 0x02, 0x0c); err += sn9c102_i2c_write(cam, 0x03, 0x12); err += sn9c102_i2c_write(cam, 0x04, 0x05); - err += sn9c102_i2c_write(cam, 0x05, 0x22); - err += sn9c102_i2c_write(cam, 0x06, 0xac); - err += sn9c102_i2c_write(cam, 0x07, 0x00); + err += sn9c102_i2c_write(cam, 0x05, 0x5a); + err += sn9c102_i2c_write(cam, 0x06, 0x88); + err += sn9c102_i2c_write(cam, 0x07, 0x80); err += sn9c102_i2c_write(cam, 0x08, 0x01); - err += sn9c102_i2c_write(cam, 0x0a, 0x00); + err += sn9c102_i2c_write(cam, 0x0a, 0x01); err += sn9c102_i2c_write(cam, 0x0b, 0x00); - err += sn9c102_i2c_write(cam, 0x0d, 0x00); err += sn9c102_i2c_write(cam, 0x10, 0x06); err += sn9c102_i2c_write(cam, 0x11, 0x06); err += sn9c102_i2c_write(cam, 0x12, 0x00); @@ -64,11 +63,30 @@ { switch (ctrl->id) { case V4L2_CID_RED_BALANCE: - return (ctrl->value = sn9c102_i2c_read(cam, 0x0c))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; case V4L2_CID_BLUE_BALANCE: - return (ctrl->value = sn9c102_i2c_read(cam, 0x09))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_GAIN: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; case V4L2_CID_BRIGHTNESS: - return (ctrl->value = sn9c102_i2c_read(cam, 0x0e))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_CONTRAST: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) + return -EIO; + ctrl->value &= 0x07; + return 0; default: return -EINVAL; } @@ -87,9 +105,15 @@ case V4L2_CID_BLUE_BALANCE: err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f); break; - case V4L2_CID_BRIGHTNESS: + case V4L2_CID_GAIN: err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f); break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x0d, 0x1f-(ctrl->value & 0x1f)); + break; + case V4L2_CID_CONTRAST: + err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03); + break; default: return -EINVAL; } @@ -130,7 +154,7 @@ .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x03, + .default_value = 0x04, .flags = 0, }, { @@ -140,7 +164,17 @@ .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x02, + .default_value = 0x06, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0d, .flags = 0, }, { @@ -150,7 +184,17 @@ .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x06, + .default_value = 0x1f, + .flags = 0, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "contrast", + .minimum = 0x00, + .maximum = 0x07, + .step = 0x01, + .default_value = 0x00, /* 0x00~0x03 have same effect */ .flags = 0, }, }, @@ -185,11 +229,13 @@ int r0 = 0, r1 = 0, err = 0; unsigned int pid = 0; - /* Minimal initialization to enable the I2C communication - NOTE: do NOT change the values! */ + /* + Minimal initialization to enable the I2C communication + NOTE: do NOT change the values! + */ err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ - err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 48 MHz */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ if (err) return -EIO; diff -Nru a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/media/sn9c102_pas202bcb.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,238 @@ +/*************************************************************************** + * Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera * + * Controllers * + * * + * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * + * * + * http://cadu.homelinux.com:8080/ * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor pas202bcb; + + +static int pas202bcb_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x20, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); + + err += sn9c102_i2c_write(cam, 0x02, 0x0c); + err += sn9c102_i2c_write(cam, 0x03, 0x40); + err += sn9c102_i2c_write(cam, 0x04, 0x07); + err += sn9c102_i2c_write(cam, 0x05, 0x25); + err += sn9c102_i2c_write(cam, 0x0d, 0x2c); + err += sn9c102_i2c_write(cam, 0x0e, 0x01); + err += sn9c102_i2c_write(cam, 0x0f, 0xa9); + err += sn9c102_i2c_write(cam, 0x08, 0x01); + err += sn9c102_i2c_write(cam, 0x0b, 0x01); + err += sn9c102_i2c_write(cam, 0x13, 0x63); + err += sn9c102_i2c_write(cam, 0x15, 0x70); + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + msleep(400); + + return err; +} + + +static int pas202bcb_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_BLUE_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_GAIN: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_BRIGHTNESS: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + default: + return -EINVAL; + } +} + + +static int pas202bcb_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f); + break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f)); + break; + default: + return -EINVAL; + } + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + return err; +} + + +static int pas202bcb_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &pas202bcb; + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static struct sn9c102_sensor pas202bcb = { + .name = "PAS202BCB", + .maintainer = "Carlos Eduardo Medaglia Dyonisio " + "", + .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .slave_read_id = 0x40, + .slave_write_id = 0x40, + .init = &pas202bcb_init, + .qctrl = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x05, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0c, + .flags = 0, + }, + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x0f, + .flags = 0, + }, + }, + .get_ctrl = &pas202bcb_get_ctrl, + .set_ctrl = &pas202bcb_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &pas202bcb_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + } +}; + + +int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) +{ + int r0 = 0, r1 = 0, err = 0; + unsigned int pid = 0; + + /* + * Minimal initialization to enable the I2C communication + * NOTE: do NOT change the values! + */ + err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ + err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ + if (err) + return -EIO; + + r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); + r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); + + if (r0 < 0 || r1 < 0) + return -EIO; + + pid = (r0 << 4) | ((r1 & 0xf0) >> 4); + if (pid != 0x017) + return -ENODEV; + + sn9c102_attach_sensor(cam, &pas202bcb); + + return 0; +} diff -Nru a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h --- a/drivers/usb/media/sn9c102_sensor.h 2004-10-18 14:56:27 -07:00 +++ b/drivers/usb/media/sn9c102_sensor.h 2004-10-18 14:56:27 -07:00 @@ -33,7 +33,8 @@ /*****************************************************************************/ -/* OVERVIEW. +/* + OVERVIEW. This is a small interface that allows you to add support for any CCD/CMOS image sensors connected to the SN9C10X bridges. The entire API is documented below. In the most general case, to support a sensor there are three steps @@ -48,26 +49,33 @@ "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do NOT need to touch the source code of the core module for the things to work properly, unless you find bugs or flaws in it. Finally, do not forget to - read the V4L2 API for completeness. */ + read the V4L2 API for completeness. +*/ /*****************************************************************************/ - -/* Probing functions: on success, you must attach the sensor to the camera + +/* + Probing functions: on success, you must attach the sensor to the camera by calling sn9c102_attach_sensor() provided below. To enable the I2C communication, you might need to perform a really basic initialization of the SN9C10X chip by using the write function declared ahead. - Functions must return 0 on success, the appropriate error otherwise. */ + Functions must return 0 on success, the appropriate error otherwise. +*/ extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); +extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); -/* Add the above entries to this table. Be sure to add the entry in the right +/* + Add the above entries to this table. Be sure to add the entry in the right place, since, on failure, the next probing routine is called according to - the order of the list below, from top to bottom */ + the order of the list below, from top to bottom. +*/ #define SN9C102_SENSOR_TABLE \ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ - &sn9c102_probe_pas106b, /* strong detection based on SENSOR vid/pid */\ + &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ + &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ NULL, \ @@ -81,28 +89,29 @@ /* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/ #define SN9C102_ID_TABLE \ static const struct usb_device_id sn9c102_id_table[] = { \ - { USB_DEVICE(0xc45, 0x6001), }, \ + { USB_DEVICE(0xc45, 0x6001), }, /* TAS5110C1B */ \ { USB_DEVICE(0xc45, 0x6005), }, /* TAS5110C1B */ \ { USB_DEVICE(0xc45, 0x6009), }, /* PAS106B */ \ { USB_DEVICE(0xc45, 0x600d), }, /* PAS106B */ \ { USB_DEVICE(0xc45, 0x6024), }, \ - { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B Maybe also TAS5110C1B */\ - { USB_DEVICE(0xc45, 0x6028), }, /* Maybe PAS202B */ \ - { USB_DEVICE(0xc45, 0x6029), }, \ - { USB_DEVICE(0xc45, 0x602a), }, /* Maybe HV7131[D|E1] */ \ - { USB_DEVICE(0xc45, 0x602c), }, /* Maybe OV7620 */ \ - { USB_DEVICE(0xc45, 0x6030), }, /* Maybe MI03 */ \ - { USB_DEVICE(0xc45, 0x8001), }, \ + { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ + { USB_DEVICE(0xc45, 0x6028), }, /* PAS202BCB */ \ + { USB_DEVICE(0xc45, 0x6029), }, /* PAS106B */ \ + { USB_DEVICE(0xc45, 0x602a), }, /* HV7131[D|E1] */ \ + { USB_DEVICE(0xc45, 0x602c), }, /* OV7620 */ \ + { USB_DEVICE(0xc45, 0x6030), }, /* MI03 */ \ { } \ }; /*****************************************************************************/ -/* Read/write routines: they always return -1 on error, 0 or the read value +/* + Read/write routines: they always return -1 on error, 0 or the read value otherwise. NOTE that a real read operation is not supported by the SN9C10X chip for some of its registers. To work around this problem, a pseudo-read call is provided instead: it returns the last successfully written value - on the register (0 if it has never been written), the usual -1 on error. */ + on the register (0 if it has never been written), the usual -1 on error. +*/ /* The "try" I2C I/O versions are used when probing the sensor */ extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, @@ -110,10 +119,12 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, u8 address); -/* This must be used if and only if the sensor doesn't implement the standard - I2C protocol, like the TASC sensors. There a number of good reasons why you - must use the single-byte versions of this function: do not abuse. It writes - n bytes, from data0 to datan, (registers 0x09 - 0x09+n of SN9C10X chip) */ +/* + This must be used if and only if the sensor doesn't implement the standard + I2C protocol. There a number of good reasons why you must use the + single-byte versions of this function: do not abuse. It writes n bytes, + from data0 to datan, (registers 0x09 - 0x09+n of SN9C10X chip). +*/ extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, struct sn9c102_sensor* sensor, u8 n, u8 data0, u8 data1, u8 data2, u8 data3, @@ -127,12 +138,14 @@ extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); -/* NOTE: there are no debugging functions here. To uniform the output you must +/* + NOTE: there are no debugging functions here. To uniform the output you must use the dev_info()/dev_warn()/dev_err() macros defined in device.h, already included here, the argument being the struct device 'dev' of the sensor structure. Do NOT use these macros before the sensor is attached or the kernel will crash! However you should not need to notify the user about - common errors or other messages, since this is done by the master module. */ + common errors or other messages, since this is done by the master module. +*/ /*****************************************************************************/ @@ -150,24 +163,31 @@ char name[32], /* sensor name */ maintainer[64]; /* name of the mantainer */ - /* These sensor capabilities must be provided if the SN9C10X controller + /* + These sensor capabilities must be provided if the SN9C10X controller needs to communicate through the sensor serial interface by using - at least one of the i2c functions available */ + at least one of the i2c functions available. + */ enum sn9c102_i2c_frequency frequency; enum sn9c102_i2c_interface interface; - /* These identifiers must be provided if the image sensor implements + /* + These identifiers must be provided if the image sensor implements the standard I2C protocol. TASC sensors don't, although they have a serial interface: so this is a case where the "raw" I2C version - could be helpful. */ + could be helpful. + */ u8 slave_read_id, slave_write_id; /* reg. 0x09 */ - /* NOTE: Where not noted,most of the functions below are not mandatory. + /* + NOTE: Where not noted,most of the functions below are not mandatory. Set to null if you do not implement them. If implemented, - they must return 0 on success, the proper error otherwise. */ + they must return 0 on success, the proper error otherwise. + */ int (*init)(struct sn9c102_device* cam); - /* This function is called after the sensor has been attached. + /* + This function is called after the sensor has been attached. It should be used to initialize the sensor only, but may also configure part of the SN9C10X chip if necessary. You don't need to setup picture settings like brightness, contrast, etc.. here, if @@ -177,23 +197,29 @@ specified in the v4l2_queryctrl list of supported controls; Same suggestions apply for other settings, _if_ the corresponding methods are present; if not, the initialization must configure the - sensor according to the default configuration structures below. */ + sensor according to the default configuration structures below. + */ struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; - /* Optional list of default controls, defined as indicated in the - V4L2 API. Menu type controls are not handled by this interface. */ + /* + Optional list of default controls, defined as indicated in the + V4L2 API. Menu type controls are not handled by this interface. + */ int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); int (*set_ctrl)(struct sn9c102_device* cam, const struct v4l2_control* ctrl); - /* You must implement at least the set_ctrl method if you have defined + /* + You must implement at least the set_ctrl method if you have defined the list above. The returned value must follow the V4L2 specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER are not supported by this driver, so do not implement them. Also, - passed values are NOT checked to see if they are out of bounds. */ + passed values are NOT checked to see if they are out of bounds. + */ struct v4l2_cropcap cropcap; - /* Think the image sensor as a grid of R,G,B monochromatic pixels + /* + Think the image sensor as a grid of R,G,B monochromatic pixels disposed according to a particular Bayer pattern, which describes the complete array of pixels, from (0,0) to (xmax, ymax). We will use this coordinate system from now on. It is assumed the sensor @@ -221,11 +247,13 @@ NOTE: once you have defined the bounds of the active window (struct cropcap.bounds) you must not change them.anymore. Only 'bounds' and 'defrect' fields are mandatory, other fields - will be ignored. */ + will be ignored. + */ int (*set_crop)(struct sn9c102_device* cam, const struct v4l2_rect* rect); - /* To be called on VIDIOC_C_SETCROP. The core module always calls a + /* + To be called on VIDIOC_C_SETCROP. The core module always calls a default routine which configures the appropriate SN9C10X regs (also scaling), but you may need to override/adjust specific stuff. 'rect' contains width and height values that are multiple of 16: in @@ -237,10 +265,12 @@ frame after each HSYNC or VSYNC, so that the image starts with real RGB data (see regs 0x12,0x13) (having set H_SIZE and, V_SIZE you don't have to care about blank pixels or blank - lines at the end of each line or frame). */ + lines at the end of each line or frame). + */ struct v4l2_pix_format pix_format; - /* What you have to define here are: initial 'width' and 'height' of + /* + What you have to define here are: initial 'width' and 'height' of the target rectangle, the bayer 'pixelformat' and 'priv' which we'll be used to indicate the number of bits per pixel, 8 or 9. Nothing more. @@ -249,20 +279,27 @@ suggest 1/1. NOTE 2: as said above, you have to program the SN9C10X chip to get rid of any blank pixels, so that the output of the sensor - matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). */ + matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). + */ const struct device* dev; - /* This is the argument for dev_err(), dev_info() and dev_warn(). It + /* + This is the argument for dev_err(), dev_info() and dev_warn(). It is used for debugging purposes. You must not access the struct - before the sensor is attached. */ + before the sensor is attached. + */ const struct usb_device* usbdev; - /* Points to the usb_device struct after the sensor is attached. - Do not touch unless you know what you are doing. */ + /* + Points to the usb_device struct after the sensor is attached. + Do not touch unless you know what you are doing. + */ - /* Do NOT write to the data below, it's READ ONLY. It is used by the + /* + Do NOT write to the data below, it's READ ONLY. It is used by the core module to store successfully updated values of the above - settings, for rollbacks..etc..in case of errors during atomic I/O */ + settings, for rollbacks..etc..in case of errors during atomic I/O + */ struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; struct v4l2_rect _rect; }; diff -Nru a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c --- a/drivers/usb/media/sn9c102_tas5110c1b.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/usb/media/sn9c102_tas5110c1b.c 2004-10-18 14:55:46 -07:00 @@ -33,15 +33,33 @@ err += sn9c102_write_reg(cam, 0x44, 0x01); err += sn9c102_write_reg(cam, 0x00, 0x10); err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x0a, 0x14); err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x06, 0x18); - err += sn9c102_write_reg(cam, 0xcb, 0x19); + err += sn9c102_write_reg(cam, 0xfb, 0x19); + + err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0, + 0x80, 0, 0); return err; } +static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_GAIN: + return sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, + 0x02, 0x20, + 0xff - (ctrl->value & 0xff), + 0, 0); + default: + return -EINVAL; + } +} + + static int tas5110c1b_set_crop(struct sn9c102_device* cam, const struct v4l2_rect* rect) { @@ -53,6 +71,11 @@ err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); + /* Don't change ! */ + err += sn9c102_write_reg(cam, 0x14, 0x1a); + err += sn9c102_write_reg(cam, 0x0a, 0x1b); + err += sn9c102_write_reg(cam, 0xfb, 0x19); + return err; } @@ -60,7 +83,22 @@ static struct sn9c102_sensor tas5110c1b = { .name = "TAS5110C1B", .maintainer = "Luca Risolia ", + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_3WIRES, .init = &tas5110c1b_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x48, + .flags = 0, + }, + }, + .set_ctrl = &tas5110c1b_set_ctrl, .cropcap = { .bounds = { .left = 0, @@ -90,8 +128,9 @@ /* This sensor has no identifiers, so let's attach it anyway */ sn9c102_attach_sensor(cam, &tas5110c1b); - /* At the moment, only devices whose PID is 0x6005 have this sensor */ - if (tas5110c1b.usbdev->descriptor.idProduct != 0x6005) + /* At the moment, sensor detection is based on USB pid/vid */ + if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 && + tas5110c1b.usbdev->descriptor.idProduct != 0x6005) return -ENODEV; return 0; diff -Nru a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c --- a/drivers/usb/media/sn9c102_tas5130d1b.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/usb/media/sn9c102_tas5130d1b.c 2004-10-18 14:56:32 -07:00 @@ -37,38 +37,45 @@ err += sn9c102_write_reg(cam, 0x00, 0x14); err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x07, 0x18); - err += sn9c102_write_reg(cam, 0x33, 0x19); err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40, 0x47, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, - 0xa9, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, - 0x49, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, - 0x6c, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, - 0x08, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x20, - 0x00, 0, 0); - - err += sn9c102_write_reg(cam, 0x63, 0x19); return err; } +static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_GAIN: + return sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, + 0x02, 0x20, + 0xff - (ctrl->value & 0xff), + 0, 0); + default: + return -EINVAL; + } +} + + static int tas5130d1b_set_crop(struct sn9c102_device* cam, const struct v4l2_rect* rect) { struct sn9c102_sensor* s = &tas5130d1b; - int err = 0; u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; + int err = 0; err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); + /* Do NOT change! */ + err += sn9c102_write_reg(cam, 0x1d, 0x1a); + err += sn9c102_write_reg(cam, 0x10, 0x1b); + err += sn9c102_write_reg(cam, 0xf3, 0x19); + return err; } @@ -79,6 +86,19 @@ .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, .init = &tas5130d1b_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + }, + .set_ctrl = &tas5130d1b_set_ctrl, .cropcap = { .bounds = { .left = 0, @@ -108,13 +128,9 @@ /* This sensor has no identifiers, so let's attach it anyway */ sn9c102_attach_sensor(cam, &tas5130d1b); - /* At the moment, only devices whose PID is 0x6025 have this sensor */ + /* At the moment, sensor detection is based on USB pid/vid */ if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025) return -ENODEV; - dev_info(tas5130d1b.dev, "TAS5130D1B detected, but the support for it " - "is disabled at the moment - needs further " - "testing -\n"); - - return -ENODEV; + return 0; } diff -Nru a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c --- a/drivers/usb/media/stv680.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/usb/media/stv680.c 2004-10-18 14:56:48 -07:00 @@ -93,11 +93,11 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); -MODULE_PARM (debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC (debug, "Debug enabled or not"); -MODULE_PARM (swapRGB_on, "i"); +module_param(swapRGB_on, int, 0); MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); -MODULE_PARM (video_nr, "i"); +module_param(video_nr, int, 0); /******************************************************************** * @@ -704,7 +704,6 @@ usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr), stv680->sbuf[i].data, stv680->rawbufsize, stv680_video_irq, stv680); - urb->timeout = PENCAM_TIMEOUT * 2; stv680->urb[i] = urb; err = usb_submit_urb (stv680->urb[i], GFP_KERNEL); if (err) diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c --- a/drivers/usb/media/ultracam.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/usb/media/ultracam.c 2004-10-18 14:56:17 -07:00 @@ -60,9 +60,9 @@ static int init_hue = 128; static int hue_correction = 128; -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -MODULE_PARM(flags, "i"); +module_param(flags, int, 0); MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, " "1=B/W, " @@ -71,18 +71,18 @@ "4=test pattern, " "5=separate frames, " "6=clean frames"); -MODULE_PARM(framerate, "i"); +module_param(framerate, int, 0); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); -MODULE_PARM(init_brightness, "i"); +module_param(init_brightness, int, 0); MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_contrast, "i"); +module_param(init_contrast, int, 0); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -MODULE_PARM(init_color, "i"); +module_param(init_color, int, 0); MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_hue, "i"); +module_param(init_hue, int, 0); MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -MODULE_PARM(hue_correction, "i"); +module_param(hue_correction, int, 0); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); /* diff -Nru a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c --- a/drivers/usb/media/usbvideo.c 2004-10-18 14:57:05 -07:00 +++ b/drivers/usb/media/usbvideo.c 2004-10-18 14:57:05 -07:00 @@ -34,7 +34,7 @@ #endif static int video_nr = -1; -MODULE_PARM(video_nr, "i"); +module_param(video_nr, int, 0); /* * Local prototypes. diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c --- a/drivers/usb/misc/auerswald.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/misc/auerswald.c 2004-10-18 14:56:28 -07:00 @@ -269,7 +269,7 @@ /* Forwards */ static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs); static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp); -extern struct usb_driver auerswald_driver; +static struct usb_driver auerswald_driver; /*-------------------------------------------------------------------*/ @@ -1037,7 +1037,8 @@ /* now extract the information */ channelid = cp->intbufp[2]; - bytecount = le16_to_cpup (&cp->intbufp[3]); + bytecount = (unsigned char)cp->intbufp[3]; + bytecount |= (unsigned char)cp->intbufp[4] << 8; /* check the channel id */ if (channelid >= AUH_TYPESIZE) { @@ -1930,7 +1931,7 @@ struct usb_device *usbdev = interface_to_usbdev(intf); pauerswald_t cp = NULL; unsigned int u = 0; - char *pbuf; + __le16 *pbuf; int ret; dbg ("probe: vendor id 0x%x, device id 0x%x", @@ -1976,8 +1977,7 @@ dbg ("Version is %X", cp->version); /* allow some time to settle the device */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/3); + msleep(334); /* Try to get a suitable textual description of the device */ /* Device name:*/ @@ -2003,7 +2003,7 @@ info("device is a %s", cp->dev_desc); /* get the maximum allowed control transfer length */ - pbuf = (char *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */ + pbuf = (__le16 *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */ if (!pbuf) { err( "out of memory"); goto pfail; diff -Nru a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c --- a/drivers/usb/misc/legousbtower.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/misc/legousbtower.c 2004-10-18 14:56:29 -07:00 @@ -71,6 +71,8 @@ * - make device locking interruptible * 2004-04-30 - 0.95 Juergen Stuber * - check for valid udev on resubmitting and unlinking urbs + * 2004-08-03 - 0.96 Juergen Stuber + * - move reset into open to clean out spurious data */ #include @@ -98,12 +100,12 @@ /* Version Information */ -#define DRIVER_VERSION "v0.95" +#define DRIVER_VERSION "v0.96" #define DRIVER_AUTHOR "Juergen Stuber " #define DRIVER_DESC "LEGO USB Tower Driver" /* Module parameters */ -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); /* The defaults are chosen to work with the latest versions of leJOS and NQC. @@ -113,8 +115,8 @@ * In this case read_buffer_size should exceed the maximal packet length * (417 for datalog uploads), and packet_timeout should be set. */ -static size_t read_buffer_size = 480; -MODULE_PARM(read_buffer_size, "i"); +static int read_buffer_size = 480; +module_param(read_buffer_size, int, 0); MODULE_PARM_DESC(read_buffer_size, "Read buffer size"); /* Some legacy software likes to send packets in one piece. @@ -123,8 +125,8 @@ * A problem with long writes is that the following read may time out * if the software is not prepared to wait long enough. */ -static size_t write_buffer_size = 480; -MODULE_PARM(write_buffer_size, "i"); +static int write_buffer_size = 480; +module_param(write_buffer_size, int, 0); MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); /* Some legacy software expects reads to contain whole LASM packets. @@ -138,7 +140,7 @@ * Set it to 0 to disable. */ static int packet_timeout = 50; -MODULE_PARM(packet_timeout, "i"); +module_param(packet_timeout, int, 0); MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms"); /* Some legacy software expects blocking reads to time out. @@ -146,7 +148,7 @@ * Set it to 0 to disable. */ static int read_timeout = 200; -MODULE_PARM(read_timeout, "i"); +module_param(read_timeout, int, 0); MODULE_PARM_DESC(read_timeout, "Read timeout in ms"); /* As of kernel version 2.6.4 ehci-hcd uses an @@ -159,11 +161,11 @@ * or set to 0 to use the standard interval from the endpoint descriptors. */ static int interrupt_in_interval = 2; -MODULE_PARM(interrupt_in_interval, "i"); +module_param(interrupt_in_interval, int, 0); MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms"); static int interrupt_out_interval = 8; -MODULE_PARM(interrupt_out_interval, "i"); +module_param(interrupt_out_interval, int, 0); MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms"); /* Define these values to match your device */ @@ -175,18 +177,18 @@ #define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD struct tower_reset_reply { - __u16 size; /* little-endian */ + __le16 size; /* little-endian */ __u8 err_code; __u8 spare; } __attribute__ ((packed)); struct tower_get_version_reply { - __u16 size; /* little-endian */ + __le16 size; /* little-endian */ __u8 err_code; __u8 spare; __u8 major; __u8 minor; - __u16 build_no; /* little-endian */ + __le16 build_no; /* little-endian */ } __attribute__ ((packed)); @@ -341,6 +343,8 @@ int subminor; int retval = 0; struct usb_interface *interface; + struct tower_reset_reply reset_reply; + int result; dbg(2, "%s: enter", __FUNCTION__); @@ -378,6 +382,22 @@ } dev->open_count = 1; + /* reset the tower */ + result = usb_control_msg (dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + LEGO_USB_TOWER_REQUEST_RESET, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &reset_reply, + sizeof(reset_reply), + HZ); + if (result < 0) { + err("LEGO USB Tower reset control request failed"); + retval = result; + goto unlock_exit; + } + /* initialize in direction */ dev->read_buffer_length = 0; dev->read_packet_length = 0; @@ -694,7 +714,7 @@ } /* write the data into interrupt_out_buffer from userspace */ - bytes_to_write = min(count, write_buffer_size); + bytes_to_write = min_t(int, count, write_buffer_size); dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __FUNCTION__, count, bytes_to_write); if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) { @@ -828,7 +848,6 @@ struct lego_usb_tower *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor* endpoint; - struct tower_reset_reply reset_reply; struct tower_get_version_reply get_version_reply; int i; int retval = -ENOMEM; @@ -950,22 +969,6 @@ /* let the user know what node this device is now attached to */ info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor); - - /* reset the tower */ - result = usb_control_msg (udev, - usb_rcvctrlpipe(udev, 0), - LEGO_USB_TOWER_REQUEST_RESET, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - &reset_reply, - sizeof(reset_reply), - HZ); - if (result < 0) { - err("LEGO USB Tower reset control request failed"); - retval = result; - goto error; - } /* get the firmware version and log it */ result = usb_control_msg (udev, diff -Nru a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c --- a/drivers/usb/misc/phidgetservo.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/usb/misc/phidgetservo.c 2004-10-18 14:56:48 -07:00 @@ -12,8 +12,6 @@ * controllers available at: http://www.phidgets.com/ * * Note that the driver takes input as: degrees.minutes - * -23 < degrees < 203 - * 0 < minutes < 59 * * CAUTION: Generally you should use 0 < degrees < 180 as anything else * is probably beyond the range of your servo and may damage it. @@ -21,6 +19,10 @@ * Jun 16, 2004: Sean Young * - cleanups * - was using memory after kfree() + * Aug 8, 2004: Sean Young + * - set the highest angle as high as the hardware allows, there are + * some odd servos out there + * */ #include @@ -87,6 +89,9 @@ int retval; unsigned char *buffer; + if (degrees < -23 || degrees > 362) + return -EINVAL; + buffer = kmalloc(6, GFP_KERNEL); if (!buffer) { dev_err(&servo->udev->dev, "%s - out of memory\n", @@ -157,6 +162,9 @@ int retval; unsigned char *buffer; + if (degrees < -23 || degrees > 278) + return -EINVAL; + buffer = kmalloc(2, GFP_KERNEL); if (!buffer) { dev_err(&servo->udev->dev, "%s - out of memory\n", @@ -212,10 +220,8 @@ return -EINVAL; \ } \ \ - if (degrees < -23 || degrees > (180 + 23) || \ - minutes < 0 || minutes > 59) { \ + if (minutes < 0 || minutes > 59) \ return -EINVAL; \ - } \ \ if (servo->type & SERVO_VERSION_30) \ retval = change_position_v30 (servo, value, degrees, \ diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c --- a/drivers/usb/misc/tiglusb.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/misc/tiglusb.c 2004-10-18 14:55:54 -07:00 @@ -560,7 +560,7 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE (DRIVER_LICENSE); -MODULE_PARM (timeout, "i"); +module_param(timeout, int, 0); MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)"); /* --------------------------------------------------------------------- */ diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/misc/usbtest.c 2004-10-18 14:57:04 -07:00 @@ -1054,8 +1054,7 @@ urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size); if (!urb) return -ENOMEM; - if (async) - urb->transfer_flags |= URB_ASYNC_UNLINK; + urb->transfer_flags |= URB_ASYNC_UNLINK; urb->context = &completion; urb->complete = unlink1_callback; @@ -1074,17 +1073,20 @@ * hcd states and code paths, even with little other system load. */ msleep (jiffies % (2 * INTERRUPT_RATE)); + if (async) { retry: - retval = usb_unlink_urb (urb); - if (retval == -EBUSY || retval == -EIDRM) { - /* we can't unlink urbs while they're completing. - * or if they've completed, and we haven't resubmitted. - * "normal" drivers would prevent resubmission, but - * since we're testing unlink paths, we can't. - */ - dev_dbg (&dev->intf->dev, "unlink retry\n"); - goto retry; - } + retval = usb_unlink_urb (urb); + if (retval == -EBUSY || retval == -EIDRM) { + /* we can't unlink urbs while they're completing. + * or if they've completed, and we haven't resubmitted. + * "normal" drivers would prevent resubmission, but + * since we're testing unlink paths, we can't. + */ + dev_dbg (&dev->intf->dev, "unlink retry\n"); + goto retry; + } + } else + usb_kill_urb (urb); if (!(retval == 0 || retval == -EINPROGRESS)) { dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval); return retval; @@ -1095,9 +1097,10 @@ simple_free_urb (urb); if (async) - return (retval != -ECONNRESET) ? -ECONNRESET : 0; + return (retval == -ECONNRESET) ? 0 : retval - 1000; else - return (retval != -ENOENT) ? -ENOENT : 0; + return (retval == -ENOENT || retval == -EPERM) ? + 0 : retval - 2000; } static int unlink_simple (struct usbtest_dev *dev, int pipe, int len) diff -Nru a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c --- a/drivers/usb/net/catc.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/net/catc.c 2004-10-18 14:56:29 -07:00 @@ -242,7 +242,7 @@ do { if(!catc->is_f5u011) { - pkt_len = le16_to_cpup((u16*)pkt_start); + pkt_len = le16_to_cpup((__le16*)pkt_start); if (pkt_len > urb->actual_length) { catc->stats.rx_length_errors++; catc->stats.rx_errors++; @@ -303,7 +303,7 @@ else if (data[1] & 0x20) linksts = LinkBad; } else { - hasdata = (unsigned int)(be16_to_cpup((u16*)data) & 0x0fff); + hasdata = (unsigned int)(be16_to_cpup((__be16*)data) & 0x0fff); if (data[0] == 0x90) linksts = LinkGood; else if (data[0] == 0xA0) diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c --- a/drivers/usb/net/kaweth.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/usb/net/kaweth.c 2004-10-18 14:56:48 -07:00 @@ -203,7 +203,7 @@ __u8 reserved2; eth_addr_t hw_addr; __u32 statistics_mask; - __u16 segment_size; + __le16 segment_size; __u16 max_multicast_filters; __u8 reserved3; } __attribute__ ((packed)); @@ -588,7 +588,7 @@ int count = urb->actual_length; int count2 = urb->transfer_buffer_length; - __u16 pkt_len = le16_to_cpup((u16 *)kaweth->rx_buf); + __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf); struct sk_buff *skb; @@ -668,7 +668,7 @@ INTBUFFERSIZE, int_callback, kaweth, - HZ/4); + 8); kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -763,7 +763,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) { struct kaweth_device *kaweth = net->priv; - u16 *private_header; + __le16 *private_header; int res; @@ -794,7 +794,7 @@ } } - private_header = (u16 *)__skb_push(skb, 2); + private_header = (__le16 *)__skb_push(skb, 2); *private_header = cpu_to_le16(skb->len-2); kaweth->tx_skb = skb; diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/net/pegasus.c 2004-10-18 14:57:04 -07:00 @@ -78,8 +78,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(loopback, "i"); -MODULE_PARM(mii_mode, "i"); +module_param(loopback, bool, 0); +module_param(mii_mode, bool, 0); MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0"); @@ -286,7 +286,7 @@ { int i; __u8 data[4] = { phy, 0, 0, indx }; - __u16 regdi; + __le16 regdi; set_register(pegasus, PhyCtrl, 0); set_registers(pegasus, PhyAddr, sizeof (data), data); @@ -347,7 +347,7 @@ { int i; __u8 tmp; - __u16 retdatai; + __le16 retdatai; set_register(pegasus, EpromCtrl, 0); set_register(pegasus, EpromOffset, index); @@ -417,7 +417,7 @@ for (i = 0; i < 3; i++) { read_eprom_word(pegasus, i, &w16); - ((__u16 *) id)[i] = cpu_to_le16p(&w16); + ((__le16 *) id)[i] = cpu_to_le16p(&w16); } } @@ -581,7 +581,7 @@ if (!count) goto goon; - rx_status = le32_to_cpu(*(int *) (urb->transfer_buffer + count - 4)); + rx_status = le32_to_cpu(*(__le32 *) (urb->transfer_buffer + count - 4)); if (rx_status & 0x000e0000) { dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000); pegasus->stats.rx_errors++; @@ -594,7 +594,7 @@ goto goon; } if (pegasus->chip == 0x8513) { - pkt_len = le32_to_cpu(*(int *)urb->transfer_buffer); + pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer); pkt_len &= 0x0fff; pegasus->rx_skb->data += 2; } else { @@ -774,7 +774,7 @@ netif_stop_queue(net); - ((__u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); + ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); memcpy(pegasus->tx_buff + 2, skb->data, skb->len); usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb, usb_sndbulkpipe(pegasus->usb, 2), diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/net/rtl8150.c 2004-10-18 14:56:33 -07:00 @@ -160,7 +160,7 @@ spinlock_t rx_pool_lock; struct usb_ctrlrequest dr; int intr_interval; - u16 rx_creg; + __le16 rx_creg; u8 *intr_buff; u8 phy; }; @@ -265,7 +265,7 @@ if (i < MII_TIMEOUT) { get_registers(dev, PHYDAT, 2, data); - *reg = le16_to_cpup(data); + *reg = data[0] | (data[1] << 8); return 0; } else return 1; @@ -450,7 +450,7 @@ goto goon; res = urb->actual_length; - rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4)); + rx_stat = le16_to_cpu(*(__le16 *)(urb->transfer_buffer + res - 4)); pkt_len = res - 4; skb_put(dev->rx_skb, pkt_len); diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/usb/net/usbnet.c 2004-10-18 14:56:32 -07:00 @@ -166,7 +166,7 @@ #define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000) // between wakeups -#define UNLINK_TIMEOUT_JIFFIES ((3 /*ms*/ * HZ)/1000) +#define UNLINK_TIMEOUT_MS 3 /*-------------------------------------------------------------------------*/ @@ -268,7 +268,7 @@ /* use ethtool to change the level for any given device */ static int msg_level = 1; -MODULE_PARM (msg_level, "i"); +module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); @@ -937,8 +937,8 @@ u8 iMACAddress; u32 bmEthernetStatistics; - u16 wMaxSegmentSize; - u16 wNumberMCFilters; + __le16 wMaxSegmentSize; + __le16 wNumberMCFilters; u8 bNumberPowerFilters; } __attribute__ ((packed)); @@ -1074,7 +1074,7 @@ info->u->bLength); goto bad_desc; } - dev->net->mtu = cpu_to_le16p ( + dev->net->mtu = le16_to_cpup ( &info->ether->wMaxSegmentSize) - ETH_HLEN; /* because of Zaurus, we may be ignoring the host @@ -2591,8 +2591,7 @@ while (skb_queue_len (&dev->rxq) && skb_queue_len (&dev->txq) && skb_queue_len (&dev->done)) { - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (UNLINK_TIMEOUT_JIFFIES); + msleep(UNLINK_TIMEOUT_MS); devdbg (dev, "waited for %d urb completions", temp); } dev->wait = NULL; diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c --- a/drivers/usb/serial/cyberjack.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/usb/serial/cyberjack.c 2004-10-18 14:57:03 -07:00 @@ -44,7 +44,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.0" +#define DRIVER_VERSION "v1.01" #define DRIVER_AUTHOR "Matthias Bruestle" #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" @@ -111,6 +111,7 @@ static int cyberjack_startup (struct usb_serial *serial) { struct cyberjack_private *priv; + int i; dbg("%s", __FUNCTION__); @@ -128,6 +129,16 @@ init_waitqueue_head(&serial->port[0]->write_wait); + for (i = 0; i < serial->num_ports; ++i) { + int result; + serial->port[i]->interrupt_in_urb->dev = serial->dev; + result = usb_submit_urb(serial->port[i]->interrupt_in_urb, + GFP_KERNEL); + if (result) + err(" usb_submit_urb(read int) failed"); + dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); + } + return( 0 ); } @@ -138,6 +149,7 @@ dbg("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { + usb_unlink_urb (serial->port[i]->interrupt_in_urb); /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); @@ -168,17 +180,6 @@ priv->wrsent = 0; spin_unlock_irqrestore(&priv->lock, flags); - /* shutdown any bulk reads that might be going on */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) - err(" usb_submit_urb(read int) failed"); - dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); - return result; } @@ -190,11 +191,6 @@ /* shutdown any bulk reads that might be going on */ usb_unlink_urb (port->write_urb); usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - dbg("%s - usb_clear_halt", __FUNCTION__ ); - usb_clear_halt(port->serial->dev, port->write_urb->pipe); - usb_clear_halt(port->serial->dev, port->read_urb->pipe); - usb_clear_halt(port->serial->dev, port->interrupt_in_urb->pipe); } } @@ -376,6 +372,10 @@ } tty = port->tty; + if (!tty) { + dbg("%s - ignoring since device not open\n", __FUNCTION__); + return; + } if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ diff -Nru a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c --- a/drivers/usb/serial/digi_acceleport.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/serial/digi_acceleport.c 2004-10-18 14:56:29 -07:00 @@ -624,14 +624,7 @@ wake_up_interruptible( &port->write_wait ); /* wake up line discipline */ - if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup ) - (tty->ldisc.write_wakeup)(tty); - - /* wake up other tty processes */ - wake_up_interruptible( &tty->write_wait ); - /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ - + tty_wakeup(tty); } @@ -1553,13 +1546,17 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count ); + /* if disconnected, just clear flags */ + if (!usb_get_intfdata(port->serial->interface)) + goto exit; + /* do cleanup only after final close on this port */ spin_lock_irqsave( &priv->dp_port_lock, flags ); priv->dp_in_close = 1; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); /* tell line discipline to process only XON/XOFF */ - tty->closing = 1; + tty->closing = 1; /* wait for output to drain */ if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) { @@ -1569,8 +1566,7 @@ /* flush driver and line discipline buffers */ if( tty->driver->flush_buffer ) tty->driver->flush_buffer( tty ); - if( tty->ldisc.flush_buffer ) - tty->ldisc.flush_buffer( tty ); + tty_ldisc_flush(tty); if (port->serial->dev) { /* wait for transmit idle */ @@ -1624,6 +1620,7 @@ tty->closing = 0; +exit: spin_lock_irqsave( &priv->dp_port_lock, flags ); priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c --- a/drivers/usb/serial/empeg.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/serial/empeg.c 2004-10-18 14:57:04 -07:00 @@ -516,11 +516,7 @@ */ port->tty->low_latency = 1; - /* Notify the tty driver that the termios have changed. */ - port->tty->ldisc.set_termios(port->tty, NULL); - return; - } diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/serial/ftdi_sio.c 2004-10-18 14:56:49 -07:00 @@ -17,6 +17,11 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (21/Jul/2004) Ian Abbott + * Incorporated Steven Turner's code to add support for the FT2232C chip. + * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have + * fixed a couple of things. + * * (27/May/2004) Ian Abbott * Improved throttling code, mostly stolen from the WhiteHEAT driver. * @@ -259,7 +264,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.0" +#define DRIVER_VERSION "v1.4.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -489,11 +494,18 @@ }; +static struct usb_device_id id_table_FT2232C[] = { + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { } /* Terminating entry */ +}; + + static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, @@ -621,6 +633,8 @@ __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ + __u16 interface; /* FT2232C port interface (0 for FT232/245) */ + int force_baud; /* if non-zero, force the baud rate to this value */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ }; @@ -637,6 +651,7 @@ static int ftdi_SIO_startup (struct usb_serial *serial); static int ftdi_8U232AM_startup (struct usb_serial *serial); static int ftdi_FT232BM_startup (struct usb_serial *serial); +static int ftdi_FT2232C_startup (struct usb_serial *serial); static int ftdi_USB_UIRT_startup (struct usb_serial *serial); static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); @@ -739,6 +754,32 @@ .shutdown = ftdi_shutdown, }; +static struct usb_serial_device_type ftdi_FT2232C_device = { + .owner = THIS_MODULE, + .name = "FTDI FT2232C Compatible", + .id_table = id_table_FT2232C, + .num_interrupt_in = 0, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ftdi_open, + .close = ftdi_close, + .throttle = ftdi_throttle, + .unthrottle = ftdi_unthrottle, + .write = ftdi_write, + .write_room = ftdi_write_room, + .chars_in_buffer = ftdi_chars_in_buffer, + .read_bulk_callback = ftdi_read_bulk_callback, + .write_bulk_callback = ftdi_write_bulk_callback, + .tiocmget = ftdi_tiocmget, + .tiocmset = ftdi_tiocmset, + .ioctl = ftdi_ioctl, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .attach = ftdi_FT2232C_startup, + .shutdown = ftdi_shutdown, +}; + static struct usb_serial_device_type ftdi_USB_UIRT_device = { .owner = THIS_MODULE, .name = "USB-UIRT Infrared Tranceiver", @@ -866,7 +907,7 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -896,7 +937,7 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -909,6 +950,7 @@ static int change_speed(struct usb_serial_port *port) { + struct ftdi_private *priv = usb_get_serial_port_data(port); char *buf; __u16 urb_value; __u16 urb_index; @@ -922,6 +964,9 @@ urb_index_value = get_ftdi_divisor(port); urb_value = (__u16)urb_index_value; urb_index = (__u16)(urb_index_value >> 16); + if (priv->interface) { /* FT2232C */ + urb_index = (__u16)((urb_index << 8) | priv->interface); + } rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1015,7 +1060,12 @@ } break; case FT232BM: /* FT232BM chip */ - chip_name = "FT232BM"; + case FT2232C: /* FT2232C chip */ + if (priv->chip_type == FT2232C) { + chip_name = "FT2232C"; + } else { + chip_name = "FT232BM"; + } if (baud <= 3000000) { div_value = ftdi_232bm_baud_to_divisor(baud); } else { @@ -1231,6 +1281,35 @@ return (0); } /* ftdi_FT232BM_startup */ +/* Startup for the FT2232C chip */ +/* Called from usbserial:serial_probe */ +static int ftdi_FT2232C_startup (struct usb_serial *serial) +{ /* ftdi_FT2232C_startup */ + struct ftdi_private *priv; + int err; + int inter; + + dbg("%s",__FUNCTION__); + err = ftdi_common_startup(serial); + if (err){ + return (err); + } + + priv = usb_get_serial_port_data(serial->port[0]); + priv->chip_type = FT2232C; + inter = serial->interface->altsetting->desc.bInterfaceNumber; + + if (inter) { + priv->interface = INTERFACE_B; + } + else { + priv->interface = INTERFACE_A; + } + priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */ + + return (0); +} /* ftdi_FT2232C_startup */ + /* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ /* Called from usbserial:serial_probe */ static int ftdi_USB_UIRT_startup (struct usb_serial *serial) @@ -1323,7 +1402,7 @@ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, - 0, buf, 0, WDR_TIMEOUT); + priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change port->tty->termios - this would loose speed settings, etc. @@ -1373,6 +1452,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) { /* ftdi_close */ unsigned int c_cflag = port->tty->termios->c_cflag; + struct ftdi_private *priv = usb_get_serial_port_data(port); char buf[1]; dbg("%s", __FUNCTION__); @@ -1383,7 +1463,8 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, buf, 0, WDR_TIMEOUT) < 0) { + 0, priv->interface, buf, 0, + WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); } @@ -1796,7 +1877,7 @@ if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); } @@ -1875,7 +1956,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, 100) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); } @@ -1886,7 +1967,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s error from disable flowcontrol urb", __FUNCTION__); } @@ -1903,6 +1984,13 @@ if (change_speed(port)) { err("%s urb failed to set baurdrate", __FUNCTION__); } + /* Ensure RTS and DTR are raised */ + else if (set_dtr(port, HIGH) < 0){ + err("%s Error from DTR HIGH urb", __FUNCTION__); + } + else if (set_rts(port, HIGH) < 0){ + err("%s Error from RTS HIGH urb", __FUNCTION__); + } } /* Set flow control */ @@ -1913,7 +2001,7 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0 , FTDI_SIO_RTS_CTS_HS, + 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to rts/cts flow control"); } @@ -1939,7 +2027,8 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - urb_value , FTDI_SIO_XON_XOFF_HS, + urb_value , (FTDI_SIO_XON_XOFF_HS + | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to xon/xoff flow control"); } @@ -1951,7 +2040,7 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to clear flow control"); } @@ -1985,13 +2074,14 @@ break; case FT8U232AM: case FT232BM: + case FT2232C: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 2, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2206,6 +2296,9 @@ retval = usb_serial_register(&ftdi_FT232BM_device); if (retval) goto failed_FT232BM_register; + retval = usb_serial_register(&ftdi_FT2232C_device); + if (retval) + goto failed_FT2232C_register; retval = usb_serial_register(&ftdi_USB_UIRT_device); if (retval) goto failed_USB_UIRT_register; @@ -2223,6 +2316,8 @@ failed_HE_TIRA1_register: usb_serial_deregister(&ftdi_USB_UIRT_device); failed_USB_UIRT_register: + usb_serial_deregister(&ftdi_FT2232C_device); +failed_FT2232C_register: usb_serial_deregister(&ftdi_FT232BM_device); failed_FT232BM_register: usb_serial_deregister(&ftdi_8U232AM_device); @@ -2241,6 +2336,7 @@ usb_deregister (&ftdi_driver); usb_serial_deregister (&ftdi_HE_TIRA1_device); usb_serial_deregister (&ftdi_USB_UIRT_device); + usb_serial_deregister (&ftdi_FT2232C_device); usb_serial_deregister (&ftdi_FT232BM_device); usb_serial_deregister (&ftdi_8U232AM_device); usb_serial_deregister (&ftdi_SIO_device); diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h 2004-10-18 14:56:50 -07:00 +++ b/drivers/usb/serial/ftdi_sio.h 2004-10-18 14:56:50 -07:00 @@ -26,6 +26,7 @@ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ +#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ @@ -234,6 +235,21 @@ #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ +/* Port interface code for FT2232C */ +#define INTERFACE_A 1 +#define INTERFACE_B 2 + + +/* + * BmRequestType: 1100 0000b + * bRequest: FTDI_E2_READ + * wValue: 0 + * wIndex: Address of word to read + * wLength: 2 + * Data: Will return a word of data from E2Address + * + */ + /* Port Identifier Table */ #define PIT_DEFAULT 0 /* SIOA */ #define PIT_SIOA 1 /* SIOA */ @@ -333,6 +349,7 @@ SIO = 1, FT8U232AM = 2, FT232BM = 3, + FT2232C = 4, } ftdi_chip_type_t; typedef enum { diff -Nru a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c --- a/drivers/usb/serial/io_edgeport.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/serial/io_edgeport.c 2004-10-18 14:55:54 -07:00 @@ -479,7 +479,7 @@ static void load_application_firmware (struct edgeport_serial *edge_serial); -static void unicode_to_ascii (char *string, short *unicode, int unicode_size); +static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size); @@ -504,7 +504,7 @@ __u32 BootNewVer; __u8 BootMajorVersion; __u8 BootMinorVersion; - __u16 BootBuildNumber; + __le16 BootBuildNumber; __u8 *BootImage; __u32 BootSize; struct edge_firmware_image_record *record; @@ -653,7 +653,7 @@ memset (product_info, 0, sizeof(struct edgeport_product_info)); - product_info->ProductId = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_GENERATION_2); + product_info->ProductId = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_80251_NETCHIP); product_info->NumPorts = edge_serial->manuf_descriptor.NumPorts; product_info->ProdInfoVer = 0; @@ -669,7 +669,7 @@ memcpy(product_info->ManufactureDescDate, edge_serial->manuf_descriptor.DescDate, sizeof(edge_serial->manuf_descriptor.DescDate)); // check if this is 2nd generation hardware - if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_GENERATION_2) { + if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_80251_NETCHIP) { product_info->FirmwareMajorVersion = OperationalCodeImageVersion_GEN2.MajorVersion; product_info->FirmwareMinorVersion = OperationalCodeImageVersion_GEN2.MinorVersion; product_info->FirmwareBuildNumber = cpu_to_le16(OperationalCodeImageVersion_GEN2.BuildNumber); @@ -900,12 +900,7 @@ if (tty && edge_port->open) { /* let the tty driver wakeup if it has a special write_wakeup function */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - (tty->ldisc.write_wakeup)(tty); - } - - /* tell the tty driver that something has changed */ - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } // Release the Write URB @@ -1389,7 +1384,7 @@ // to bother queueing a write. If it's too small, say a few bytes, // it's better to wait for more credits so we can do a larger // write. - if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) { + if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE)) { dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits ); return; } @@ -2747,7 +2742,7 @@ * ASCII range, but it's only for debugging... * NOTE: expects the unicode in LE format ****************************************************************************/ -static void unicode_to_ascii (char *string, short *unicode, int unicode_size) +static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size) { int i; for (i = 0; i < unicode_size; ++i) { @@ -3007,9 +3002,6 @@ static int __init edgeport_init(void) { int retval; - retval = usb_serial_register(&edgeport_1port_device); - if (retval) - goto failed_1port_device_register; retval = usb_serial_register(&edgeport_2port_device); if (retval) goto failed_2port_device_register; @@ -3031,8 +3023,6 @@ failed_4port_device_register: usb_serial_deregister(&edgeport_2port_device); failed_2port_device_register: - usb_serial_deregister(&edgeport_1port_device); -failed_1port_device_register: return retval; } @@ -3045,7 +3035,6 @@ static void __exit edgeport_exit (void) { usb_deregister (&io_driver); - usb_serial_deregister (&edgeport_1port_device); usb_serial_deregister (&edgeport_2port_device); usb_serial_deregister (&edgeport_4port_device); usb_serial_deregister (&edgeport_8port_device); diff -Nru a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h --- a/drivers/usb/serial/io_edgeport.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/serial/io_edgeport.h 2004-10-18 14:56:33 -07:00 @@ -107,11 +107,11 @@ __u8 BootMajorVersion; /* Boot Firmware version: xx. */ __u8 BootMinorVersion; /* yy. */ - __u16 BootBuildNumber; /* zzzz (LE format) */ + __le16 BootBuildNumber; /* zzzz (LE format) */ __u8 FirmwareMajorVersion; /* Operational Firmware version:xx. */ __u8 FirmwareMinorVersion; /* yy. */ - __u16 FirmwareBuildNumber; /* zzzz (LE format) */ + __le16 FirmwareBuildNumber; /* zzzz (LE format) */ __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ __u8 Unused1[1]; /* Available */ diff -Nru a/drivers/usb/serial/io_fw_down.h b/drivers/usb/serial/io_fw_down.h --- a/drivers/usb/serial/io_fw_down.h 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/serial/io_fw_down.h 2004-10-18 14:57:04 -07:00 @@ -17,7 +17,7 @@ unsigned short Addr; unsigned short Len; unsigned char Data[0]; - } __attribute ((packed)); + } __attribute__ ((packed)); struct edge_firmware_version_info { unsigned char MajorVersion; @@ -36,11 +36,11 @@ // Segment #1, Start Address 00ff0000, Length 6 0xff,0x00,0x00,0x00,0x06,0x00, - 0x02, 0x00, 0x80, 0x02, 0x49, 0x39, + 0x02, 0x00, 0x80, 0x02, 0x44, 0xb0, // Segment #2, Start Address 00ff000b, Length 3 0xff,0x00,0x0b,0x00,0x03,0x00, - 0x02, 0x44, 0x1a, + 0x02, 0x44, 0x72, // Segment #3, Start Address 00ff0013, Length 3 0xff,0x00,0x13,0x00,0x03,0x00, @@ -72,11 +72,11 @@ // Segment #10, Start Address 00ff004b, Length 3 0xff,0x00,0x4b,0x00,0x03,0x00, - 0x02, 0x70, 0xd4, + 0x02, 0x6e, 0xc4, // Segment #11, Start Address 00ff0053, Length 3 0xff,0x00,0x53,0x00,0x03,0x00, - 0x02, 0x77, 0x9d, + 0x02, 0x75, 0x8d, // Segment #12, Start Address 00ff007b, Length 3 0xff,0x00,0x7b,0x00,0x03,0x00, @@ -86,657 +86,745 @@ 0xff,0x00,0x80,0x00,0x07,0x00, 0x7e, 0x14, 0x00, 0x00, 0x02, 0x40, 0x51, -// Segment #14, Start Address 00ff4000, Length 15920 -0xff,0x00,0x00,0x40,0x30,0x3e, +// Segment #14, Start Address 00ff3000, Length 2178 +0xff,0x00,0x00,0x30,0x82,0x08, + 0x12, 0x37, 0x28, 0x12, 0x30, 0x3e, 0x12, 0x30, 0x54, 0x12, 0x30, 0xe5, 0x12, 0x31, 0x68, 0x12, + 0x35, 0x20, 0x12, 0x38, 0x58, 0x12, 0x31, 0x15, 0x12, 0x31, 0x40, 0x12, 0x30, 0xa0, 0x80, 0xe0, + 0xe5, 0x23, 0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, 0x09, 0xb1, 0x01, 0xcf, 0xb4, 0x00, 0x02, 0x80, + 0x05, 0x14, 0x19, 0xb1, 0x01, 0xcf, 0xa5, 0x0b, 0xbe, 0x31, 0x2f, 0x78, 0xeb, 0x22, 0xc2, 0xaf, + 0x7e, 0xb3, 0x3f, 0xf1, 0xb4, 0x01, 0x0a, 0xc0, 0xf1, 0x75, 0xf1, 0x02, 0x12, 0x70, 0xef, 0xd0, + 0xf1, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, 0x60, 0x43, 0x7e, 0x07, 0x01, 0xe1, 0xbe, 0x04, + 0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, + 0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, 0x04, 0x0a, 0x32, 0x09, 0x53, 0x67, 0x8e, 0x5e, + 0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, 0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, + 0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, + 0xc2, 0xaf, 0x7e, 0x20, 0x00, 0x7e, 0x30, 0x01, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x32, 0x01, + 0x8f, 0xbe, 0x34, 0x00, 0x00, 0x68, 0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, 0x21, 0xca, + 0x19, 0x49, 0x22, 0x30, 0xd5, 0x99, 0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, + 0x78, 0xd6, 0xd2, 0xaf, 0x22, 0x46, 0x0f, 0x49, 0x67, 0x4c, 0xbf, 0x50, 0x17, 0x53, 0x6f, 0x56, + 0xc7, 0x5a, 0x1f, 0x5d, 0x77, 0xc2, 0xaf, 0xe5, 0x32, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, + 0x07, 0xca, 0xb8, 0x12, 0x31, 0x02, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, + 0xaf, 0x22, 0xca, 0x28, 0x12, 0x67, 0xab, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, 0xb2, 0x67, + 0x8e, 0xf4, 0x52, 0x32, 0x22, 0xc2, 0xaf, 0xe5, 0x34, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, + 0x07, 0xca, 0xb8, 0x12, 0x31, 0x32, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, + 0xaf, 0x22, 0xca, 0x28, 0x0a, 0x22, 0x09, 0x42, 0x00, 0x3e, 0x12, 0x69, 0xc2, 0xda, 0x28, 0x22, + 0xc2, 0xaf, 0xe5, 0x35, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, + 0x5d, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x7e, + 0x40, 0x00, 0x12, 0x6c, 0x5b, 0xda, 0x28, 0x22, 0xc2, 0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, + 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, 0x85, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, + 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x31, 0x90, 0x89, 0x24, + 0x31, 0xa0, 0x32, 0x10, 0x32, 0x80, 0x32, 0xf0, 0x33, 0x60, 0x33, 0xd0, 0x34, 0x40, 0x34, 0xb0, + 0x7e, 0x27, 0x01, 0x8f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x49, 0x30, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0x9f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x9f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xcf, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xcf, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x18, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xcf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x91, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x4c, 0x88, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa1, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa1, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd0, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd0, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x19, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd0, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x93, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x4f, 0xe0, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa3, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa3, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd1, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd1, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1a, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd1, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x95, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x53, 0x38, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa5, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa5, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd2, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd2, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1b, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd2, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x97, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x56, 0x90, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa7, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa7, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd3, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd3, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1c, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd3, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x99, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x59, 0xe8, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa9, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa9, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd4, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd4, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1d, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd4, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x9b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x5d, 0x40, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xab, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xab, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd5, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd5, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1e, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd5, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x9d, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x60, 0x98, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xad, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xad, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd6, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd6, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1f, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd6, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0xc2, 0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x35, + 0x3d, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, + 0x0a, 0x2b, 0x49, 0x22, 0x35, 0x48, 0x89, 0x24, 0x35, 0x58, 0x35, 0x92, 0x35, 0xcc, 0x36, 0x06, + 0x36, 0x40, 0x36, 0x7a, 0x36, 0xb4, 0x36, 0xee, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 0x14, + 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x49, 0x30, + 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, + 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x20, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, + 0xf1, 0x22, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, + 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4c, 0x88, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, + 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, + 0x21, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x82, 0x00, + 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, + 0x12, 0x12, 0x4f, 0xe0, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, + 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x22, 0xc0, 0xf1, 0x75, 0xf1, 0x01, + 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, + 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x53, 0x38, 0x7d, 0x21, + 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, + 0x12, 0x7c, 0x15, 0xc2, 0x23, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, + 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x56, 0x90, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, + 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x24, 0xc0, + 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x59, 0xe8, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, + 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x25, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, + 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, + 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5d, 0x40, 0x7d, 0x21, 0xda, 0x19, + 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, + 0x15, 0xc2, 0x26, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, + 0x87, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, + 0x19, 0x7d, 0x12, 0x12, 0x60, 0x98, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, + 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x27, 0xc0, 0xf1, 0x75, + 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0xc2, 0xaf, 0xe5, 0x33, 0x60, 0x14, 0x7e, 0x20, + 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x37, 0x45, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, + 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x37, 0x50, 0x89, 0x24, + 0x37, 0x60, 0x37, 0x7f, 0x37, 0x9e, 0x37, 0xbd, 0x37, 0xdc, 0x37, 0xfb, 0x38, 0x1a, 0x38, 0x39, + 0x7e, 0x24, 0x80, 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x48, 0x1b, 0xda, 0x19, 0x10, 0x04, 0x02, + 0x80, 0x0c, 0xd2, 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, + 0x24, 0x81, 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4b, 0x73, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, + 0x0c, 0xd2, 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, + 0x82, 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4e, 0xcb, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, + 0xd2, 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x83, + 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x52, 0x23, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, + 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x84, 0x00, + 0xca, 0x19, 0x7d, 0x12, 0x12, 0x55, 0x7b, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, + 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x85, 0x00, 0xca, + 0x19, 0x7d, 0x12, 0x12, 0x58, 0xd3, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, 0xc0, + 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x86, 0x00, 0xca, 0x19, + 0x7d, 0x12, 0x12, 0x5c, 0x2b, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, 0xc0, 0xf1, + 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x87, 0x00, 0xca, 0x19, 0x7d, + 0x12, 0x12, 0x5f, 0x83, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, 0xc0, 0xf1, 0x75, + 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0xc2, 0xaf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0xa9, + 0x32, 0xf2, 0x1a, 0x7e, 0x07, 0x01, 0xe1, 0xbe, 0x04, 0x00, 0x00, 0x78, 0x10, 0xe5, 0xf5, 0x33, + 0x82, 0xe7, 0x40, 0x09, 0x85, 0x31, 0x31, 0x12, 0x7c, 0x15, 0x75, 0xf6, 0x00, 0xd0, 0xf1, 0xd2, + 0xaf, 0x22, + +// Segment #15, Start Address 00ff4000, Length 15381 +0xff,0x00,0x00,0x40,0x15,0x3c, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x14, 0x7f, 0xf8, 0x7e, 0x24, 0x00, 0xfe, 0x7d, 0x31, 0x0b, 0x1a, - 0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x6a, 0x7e, 0xf8, 0x00, 0x59, 0xd2, - 0x04, 0xc2, 0x94, 0xd2, 0x95, 0x7e, 0xf4, 0x40, 0x2c, 0x02, 0x40, 0x7c, 0x12, 0x7f, 0x3f, 0xf5, - 0x2e, 0x7a, 0xa1, 0x2d, 0x7a, 0x11, 0x58, 0x12, 0x77, 0xda, 0x12, 0x40, 0xdc, 0x7e, 0xb3, 0x3f, - 0xf1, 0x60, 0x03, 0x12, 0x43, 0x68, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x7f, 0xd2, 0xaf, 0x02, 0x44, - 0x06, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x5f, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xa9, + 0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x6a, 0x7e, 0xf8, 0x00, 0x6f, 0xd2, + 0x04, 0xc2, 0x94, 0xd2, 0x95, 0x7e, 0xf4, 0x40, 0x2c, 0x02, 0x40, 0x7c, 0x12, 0x7d, 0x30, 0xf5, + 0x2f, 0x7a, 0xa1, 0x30, 0x7a, 0x11, 0x6e, 0x12, 0x75, 0xca, 0x12, 0x40, 0xdc, 0x7e, 0xb3, 0x3f, + 0xf1, 0x60, 0x03, 0x12, 0x43, 0xd4, 0x75, 0xf1, 0x00, 0x12, 0x76, 0x6f, 0xd2, 0xaf, 0x02, 0x30, + 0x00, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x5f, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xa9, 0x25, 0x87, 0x03, 0xa9, 0xd5, 0x87, 0xd2, 0x93, 0x89, 0x08, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x78, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xc2, 0x93, 0x89, 0x08, 0x7e, 0x08, 0x00, 0x20, - 0x7e, 0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x8e, 0x02, 0x7e, 0x4b, 0x7e, 0x08, - 0x01, 0x59, 0x7e, 0x44, 0x28, 0x7c, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xa0, 0x02, 0x7e, 0x4b, - 0x7e, 0x08, 0x00, 0x59, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xb2, 0x02, - 0x7e, 0x4b, 0x75, 0x57, 0x20, 0x75, 0x56, 0x30, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x54, 0x58, 0x75, - 0x55, 0x08, 0x75, 0x51, 0x08, 0x75, 0x53, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, - 0x00, 0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x42, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, + 0x7e, 0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x8e, 0x02, 0x7c, 0x30, 0x7e, 0x08, + 0x01, 0x6f, 0x7e, 0x44, 0x28, 0x7c, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xa0, 0x02, 0x7c, 0x30, + 0x7e, 0x08, 0x00, 0x6f, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xb2, 0x02, + 0x7c, 0x30, 0x75, 0x6d, 0x20, 0x75, 0x6c, 0x30, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x6a, 0x58, 0x75, + 0x6b, 0x08, 0x75, 0x67, 0x08, 0x75, 0x69, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, + 0x00, 0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x58, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, 0xb8, 0x7f, 0x75, 0xb3, 0x07, 0x75, 0xb2, 0x07, 0xd2, 0xa9, 0x22, 0xd2, 0x92, 0xe4, 0xd5, 0xe0, - 0xfd, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2e, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, - 0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x72, 0x0b, 0x20, - 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, 0xb0, + 0xfd, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2f, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, + 0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x7e, 0x0b, 0x20, + 0xbe, 0x21, 0x2f, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0x10, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x80, 0x19, 0xb0, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x02, 0x19, 0xa0, 0x00, 0x04, 0x19, 0xb0, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb0, 0x00, 0x0c, - 0x74, 0x07, 0x20, 0x68, 0x02, 0x74, 0x0f, 0x19, 0xb0, 0x00, 0x04, 0x30, 0x6b, 0x17, 0x74, 0xbf, - 0x19, 0xb0, 0x00, 0x0c, 0x74, 0x28, 0x20, 0x68, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, 0x74, - 0x03, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, 0x00, - 0x10, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, 0x00, - 0x10, 0x54, 0x08, 0x19, 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, 0xb2, - 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x41, 0x99, 0x89, 0x24, 0x41, 0xa9, 0x41, 0xc6, 0x41, 0xe3, 0x42, - 0x00, 0x42, 0x1d, 0x42, 0x3a, 0x42, 0x57, 0x42, 0x74, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x08, 0x7e, - 0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x6d, 0x00, 0x7a, 0x07, 0x01, - 0x79, 0x7a, 0x07, 0x01, 0x89, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, - 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7b, 0x7a, 0x07, - 0x01, 0x8b, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, - 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, 0x22, - 0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x0b, 0x7e, 0x04, 0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, - 0x01, 0x6f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7f, 0x7a, 0x07, 0x01, 0x8f, 0x22, 0xc2, 0x14, 0xc2, - 0x1c, 0xc2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x6d, - 0x00, 0x7a, 0x07, 0x01, 0x81, 0x7a, 0x07, 0x01, 0x91, 0x22, 0xc2, 0x15, 0xc2, 0x1d, 0xc2, 0x0d, - 0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, 0x7a, 0x07, 0x01, 0x73, 0x6d, 0x00, 0x7a, 0x07, - 0x01, 0x83, 0x7a, 0x07, 0x01, 0x93, 0x22, 0xc2, 0x16, 0xc2, 0x1e, 0xc2, 0x0e, 0x7e, 0x04, 0x21, - 0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x85, 0x7a, - 0x07, 0x01, 0x95, 0x22, 0xc2, 0x17, 0xc2, 0x1f, 0xc2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, - 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x87, 0x7a, 0x07, 0x01, 0x97, - 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x42, 0x9c, 0x89, 0x24, 0x42, 0xac, 0x42, 0xc3, - 0x42, 0xda, 0x42, 0xf1, 0x43, 0x08, 0x43, 0x1f, 0x43, 0x36, 0x43, 0x4d, 0x30, 0x40, 0x07, 0x20, - 0x58, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, 0x50, 0x04, 0xc2, 0x28, 0x80, 0x02, - 0xd2, 0x28, 0x22, 0x30, 0x41, 0x07, 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, 0x07, - 0x20, 0x51, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x42, 0x07, 0x20, 0x5a, 0x04, - 0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, 0x07, 0x20, 0x52, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 0x2a, - 0x22, 0x30, 0x43, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, 0x4b, 0x07, 0x20, 0x53, - 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x44, 0x07, 0x20, 0x5c, 0x04, 0xc2, 0x2c, - 0x80, 0x0c, 0x30, 0x4c, 0x07, 0x20, 0x54, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, 0x30, - 0x45, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x55, 0x04, 0xc2, - 0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x46, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, 0x0c, - 0x30, 0x4e, 0x07, 0x20, 0x56, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, 0x47, 0x07, - 0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x57, 0x04, 0xc2, 0x2f, 0x80, - 0x02, 0xd2, 0x2f, 0x22, 0x43, 0xcc, 0x43, 0x79, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, 0x0a, - 0x5b, 0x49, 0x55, 0x43, 0x64, 0x99, 0x54, 0xd3, 0x22, 0xa9, 0xc5, 0x87, 0x12, 0x43, 0xd7, 0x7e, - 0x04, 0x05, 0xcd, 0x7a, 0x07, 0x01, 0xc1, 0x7a, 0x07, 0x01, 0xc3, 0x7e, 0x04, 0x01, 0xcd, 0x7a, - 0x07, 0x01, 0xc7, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x04, 0x76, 0xbd, 0x7a, 0x05, 0x4b, 0x75, 0xf1, - 0x01, 0x75, 0xe1, 0x1f, 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x75, 0xf1, 0x02, 0x75, 0xe1, 0x03, - 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x43, 0xa2, 0x1c, 0x12, 0x40, 0xeb, 0x7e, 0x20, 0x00, 0x12, - 0x41, 0x8e, 0x0b, 0x20, 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0xa9, 0xd5, 0x87, 0x12, - 0x43, 0xd7, 0xd2, 0x92, 0xc2, 0xa8, 0x22, 0x75, 0xa3, 0x00, 0x53, 0xa2, 0x03, 0x75, 0xc1, 0x00, - 0x53, 0xc0, 0x03, 0x7e, 0x00, 0x05, 0x7a, 0x01, 0xf1, 0x43, 0xf4, 0x80, 0x43, 0xe4, 0x80, 0xe5, - 0xf2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xf2, 0xe5, 0xe2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xe2, 0x75, - 0xe1, 0x10, 0xa5, 0xd8, 0xe1, 0x22, 0x12, 0x44, 0x76, 0x12, 0x44, 0x8c, 0x12, 0x45, 0x27, 0x12, - 0x45, 0x57, 0x12, 0x49, 0x0f, 0x12, 0x44, 0xd8, 0x80, 0xec, 0xca, 0x09, 0x12, 0x44, 0x58, 0x10, - 0x01, 0x12, 0xd5, 0x51, 0x1e, 0x63, 0x53, 0x01, 0x7e, 0x00, 0x54, 0x2e, 0x01, 0x53, 0xa5, 0xe6, - 0xf5, 0x51, 0x80, 0x12, 0x20, 0x02, 0x1e, 0x75, 0x53, 0x00, 0x85, 0x54, 0x51, 0xd2, 0x02, 0x74, - 0x00, 0x80, 0x0d, 0x30, 0x02, 0x0f, 0xc2, 0x02, 0x7e, 0x00, 0x56, 0x2e, 0x01, 0x53, 0xa5, 0xe6, - 0x53, 0x90, 0xcf, 0x42, 0x90, 0xda, 0x09, 0x32, 0xe5, 0x23, 0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, - 0x09, 0xb1, 0x01, 0xb9, 0xb4, 0x00, 0x02, 0x80, 0x05, 0x14, 0x19, 0xb1, 0x01, 0xb9, 0xa5, 0x0a, - 0xbe, 0x21, 0x2e, 0x78, 0xeb, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, 0x3f, 0xf1, 0xb4, 0x01, 0x0a, 0xc0, - 0xf1, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xff, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, - 0x60, 0x43, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, - 0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, 0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, - 0x04, 0x0a, 0x32, 0x09, 0x53, 0x6a, 0x93, 0x5e, 0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, - 0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, 0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, - 0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x26, 0x60, 0x36, 0x7e, 0x20, - 0x00, 0x7e, 0x30, 0x01, 0xe5, 0x26, 0xa5, 0x5b, 0x68, 0x21, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, - 0x32, 0x01, 0x79, 0xbe, 0x34, 0x00, 0x00, 0x68, 0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, - 0x21, 0xca, 0x19, 0x49, 0x22, 0x45, 0x17, 0x99, 0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, - 0x21, 0x2e, 0x78, 0xd0, 0xd2, 0xaf, 0x22, 0x4a, 0x98, 0x4d, 0xcd, 0x51, 0x02, 0x54, 0x37, 0x57, - 0x6c, 0x5a, 0xa1, 0x5d, 0xd6, 0x61, 0x0b, 0xc2, 0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, - 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x44, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, - 0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x12, 0x6a, 0xac, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, - 0xb2, 0x6a, 0x93, 0xf4, 0x52, 0x24, 0x22, 0xc2, 0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, 0x00, - 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x74, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, - 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x45, 0x7f, 0x89, 0x24, 0x45, - 0x8f, 0x45, 0xff, 0x46, 0x6f, 0x46, 0xdf, 0x47, 0x4f, 0x47, 0xbf, 0x48, 0x2f, 0x48, 0x9f, 0x7e, - 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4d, - 0x96, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x89, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x89, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xb9, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xb9, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x18, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xb9, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x50, - 0xcb, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x8b, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8b, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xba, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xba, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x19, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xba, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x54, - 0x00, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x8d, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8d, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbb, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbb, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1a, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbb, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x57, - 0x35, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x8f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbc, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbc, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1b, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbc, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x81, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5a, - 0x6a, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x91, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x91, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbd, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbd, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1c, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbd, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5d, - 0x9f, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x93, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x93, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbe, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbe, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1d, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbe, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x60, - 0xd4, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x95, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x95, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbf, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbf, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1e, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x87, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x64, - 0x09, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x97, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x97, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xc0, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xc0, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1f, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xc0, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0xc2, - 0xaf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0xa9, 0x32, 0xf2, 0x1a, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, - 0x00, 0x00, 0x78, 0x10, 0xe5, 0xf5, 0x33, 0x82, 0xe7, 0x40, 0x09, 0x85, 0x31, 0x2f, 0x12, 0x7e, - 0x30, 0x75, 0xf6, 0x00, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, - 0xf0, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xd2, 0x01, 0x75, 0x2f, 0x89, 0x12, 0x7e, 0x30, 0x7e, - 0x14, 0x80, 0x00, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xd8, 0x20, 0x70, 0x5a, - 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xf0, 0x20, 0x71, 0x4b, 0xa5, - 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x08, 0xa5, 0x0a, 0x09, 0xb1, 0x00, - 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x20, 0x20, 0x72, 0x30, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, - 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x38, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, - 0x4a, 0x50, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x68, 0xa5, 0x0a, - 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x80, 0x30, 0x04, 0x0c, 0xc2, 0x04, 0xc0, - 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, - 0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x75, 0x2f, 0x80, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x81, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x66, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x82, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x83, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x66, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x84, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x85, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x67, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x86, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x87, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x67, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x10, 0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, - 0x08, 0x22, 0x75, 0x2f, 0xa0, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, - 0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, - 0x03, 0x12, 0x4d, 0x96, 0x30, 0x30, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x08, 0x22, 0x30, 0xe6, 0x02, - 0xd2, 0x60, 0x7e, 0x37, 0x01, 0x79, 0x7e, 0x27, 0x01, 0x99, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, - 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, - 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, - 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x60, 0xc4, 0x22, 0xc2, - 0x60, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, - 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x99, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x99, 0x7e, 0x37, 0x01, - 0x79, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, - 0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, - 0x59, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x0d, 0xcd, - 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x09, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, - 0x59, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4b, 0x0b, 0x22, 0xd2, 0x08, 0x7e, - 0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x75, 0x2f, 0x94, 0x12, 0x7e, - 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, - 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, - 0x7e, 0x27, 0x01, 0xa9, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, - 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, - 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, - 0x00, 0x00, 0x2e, 0x27, 0x01, 0xa9, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, - 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, - 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0x80, 0x7f, 0x7a, 0x51, - 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x00, 0x00, 0x2e, 0x67, - 0x01, 0xa9, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, - 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, - 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, - 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, - 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, - 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, - 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, - 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, - 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, - 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, - 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, - 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, - 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4c, 0x6f, 0x75, - 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, - 0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0xda, - 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4c, 0x6f, 0xda, 0xb8, 0x02, - 0x4d, 0x96, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, - 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, - 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, - 0x50, 0x80, 0x02, 0xc2, 0x50, 0x12, 0x42, 0xac, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, - 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, - 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, - 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, - 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4c, 0xc3, 0x75, - 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x09, 0x01, - 0x22, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x75, 0x2f, 0xa1, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x81, - 0x00, 0x80, 0x06, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, - 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x50, 0xcb, 0x30, 0x31, 0x06, 0x20, 0xe6, 0x4f, 0xd2, - 0x09, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x61, 0x7e, 0x37, 0x01, 0x7b, 0x7e, 0x27, 0x01, 0x9b, 0x9d, - 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, 0x37, 0x01, 0x7b, 0x7e, - 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, - 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, - 0x10, 0x61, 0xc4, 0x22, 0xc2, 0x61, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, - 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9b, 0x28, 0x04, 0x7e, 0x27, - 0x01, 0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, - 0x7a, 0x37, 0x01, 0x7b, 0x7e, 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, - 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, - 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0x9e, 0x44, 0x11, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x0d, 0xcd, 0x7d, 0x24, - 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5b, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4e, - 0x40, 0x22, 0xd2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, - 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, - 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xab, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, - 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, - 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, - 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, 0x01, 0xab, 0x1b, 0x38, 0x20, 0x0b, 0x35, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, - 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, - 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, - 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, - 0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xab, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, - 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, - 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, - 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, - 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, - 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, - 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, - 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, - 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, - 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, - 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, - 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, - 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, - 0xe7, 0x02, 0x4f, 0xa4, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, - 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, - 0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, - 0x4f, 0xa4, 0xda, 0xb8, 0x02, 0x50, 0xcb, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, - 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, - 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, - 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x12, 0x42, 0xc3, 0x02, 0x65, 0x9c, - 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, - 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, - 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, - 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, - 0x22, 0x02, 0x4f, 0xf8, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, - 0x30, 0x22, 0x10, 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x75, 0x2f, 0xa2, 0x12, - 0x7e, 0x30, 0x7e, 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, - 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x54, 0x00, 0x30, 0x32, - 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0a, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x62, 0x7e, 0x37, 0x01, 0x7d, - 0x7e, 0x27, 0x01, 0x9d, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, - 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xcc, - 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, - 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x62, 0xc4, 0x22, 0xc2, 0x62, 0x2d, 0x23, 0x68, 0x78, 0x6d, - 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, - 0x9d, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x9d, 0x32, 0x7d, 0x02, 0x2e, - 0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, - 0x42, 0xbe, 0x44, 0x15, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, - 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x15, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, - 0x34, 0x11, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5d, 0x12, 0x68, 0x34, 0xbe, 0x25, - 0x20, 0x78, 0x03, 0x02, 0x51, 0x75, 0x22, 0xd2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, - 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, - 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, - 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xad, 0x2e, 0x24, - 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, - 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, - 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xad, - 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, - 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, - 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, - 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, - 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x02, 0x00, 0x2e, 0x67, 0x01, 0xad, 0x9e, 0x24, 0x00, 0x02, - 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, - 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, - 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, - 0x23, 0x23, 0x44, 0x02, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, - 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, - 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, - 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, - 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, - 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, - 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, - 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, - 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, - 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x52, 0xd9, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, - 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, - 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, - 0x68, 0x07, 0xca, 0xb8, 0x12, 0x52, 0xd9, 0xda, 0xb8, 0x02, 0x54, 0x00, 0x09, 0xb1, 0x00, 0x18, - 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, - 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, - 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x12, - 0x42, 0xda, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, - 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, - 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, - 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, - 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x53, 0x2d, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, - 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, - 0x22, 0x75, 0x2f, 0xa3, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, + 0x74, 0x07, 0xa9, 0x20, 0x30, 0x0b, 0xa9, 0x35, 0x30, 0x05, 0xbe, 0x20, 0x01, 0x28, 0x02, 0x74, + 0x0f, 0x19, 0xb0, 0x00, 0x04, 0xa9, 0x33, 0x30, 0x18, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x74, + 0x28, 0xa9, 0x20, 0x30, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, 0x74, 0x03, 0x19, 0xb0, 0x00, + 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, 0x00, 0x10, 0x22, 0x7e, 0x04, + 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, 0x00, 0x10, 0x54, 0x08, 0x19, + 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, + 0x22, 0x41, 0xa5, 0x89, 0x24, 0x41, 0xb5, 0x41, 0xd4, 0x41, 0xf3, 0x42, 0x12, 0x42, 0x31, 0x42, + 0x50, 0x42, 0x6f, 0x42, 0x8e, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x20, 0xc2, 0x08, 0x7e, 0x04, 0x09, + 0xe3, 0x7a, 0x07, 0x01, 0x6f, 0x7a, 0x07, 0x01, 0x7f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x8f, 0x7a, + 0x07, 0x01, 0x9f, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x21, 0xc2, 0x09, 0x7e, 0x04, 0x0d, 0xe3, + 0x7a, 0x07, 0x01, 0x71, 0x7a, 0x07, 0x01, 0x81, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x91, 0x7a, 0x07, + 0x01, 0xa1, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x22, 0xc2, 0x0a, 0x7e, 0x04, 0x11, 0xe3, 0x7a, + 0x07, 0x01, 0x73, 0x7a, 0x07, 0x01, 0x83, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x93, 0x7a, 0x07, 0x01, + 0xa3, 0x22, 0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x23, 0xc2, 0x0b, 0x7e, 0x04, 0x15, 0xe3, 0x7a, 0x07, + 0x01, 0x75, 0x7a, 0x07, 0x01, 0x85, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x95, 0x7a, 0x07, 0x01, 0xa5, + 0x22, 0xc2, 0x14, 0xc2, 0x1c, 0xc2, 0x24, 0xc2, 0x0c, 0x7e, 0x04, 0x19, 0xe3, 0x7a, 0x07, 0x01, + 0x77, 0x7a, 0x07, 0x01, 0x87, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x97, 0x7a, 0x07, 0x01, 0xa7, 0x22, + 0xc2, 0x15, 0xc2, 0x1d, 0xc2, 0x25, 0xc2, 0x0d, 0x7e, 0x04, 0x1d, 0xe3, 0x7a, 0x07, 0x01, 0x79, + 0x7a, 0x07, 0x01, 0x89, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x99, 0x7a, 0x07, 0x01, 0xa9, 0x22, 0xc2, + 0x16, 0xc2, 0x1e, 0xc2, 0x26, 0xc2, 0x0e, 0x7e, 0x04, 0x21, 0xe3, 0x7a, 0x07, 0x01, 0x7b, 0x7a, + 0x07, 0x01, 0x8b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x9b, 0x7a, 0x07, 0x01, 0xab, 0x22, 0xc2, 0x17, + 0xc2, 0x1f, 0xc2, 0x27, 0xc2, 0x0f, 0x7e, 0x04, 0x25, 0xe3, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, + 0x01, 0x8d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x9d, 0x7a, 0x07, 0x01, 0xad, 0x22, 0x7c, 0xb2, 0x23, + 0x0a, 0x2b, 0x49, 0x22, 0x42, 0xb8, 0x89, 0x24, 0x42, 0xc8, 0x42, 0xe9, 0x43, 0x0a, 0x43, 0x2b, + 0x43, 0x4c, 0x43, 0x6d, 0x43, 0x8e, 0x43, 0xaf, 0x30, 0x50, 0x07, 0x20, 0x68, 0x04, 0xc2, 0x28, + 0x80, 0x16, 0x30, 0x40, 0x07, 0x20, 0x60, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, + 0x58, 0x04, 0xc2, 0x28, 0x80, 0x02, 0xd2, 0x28, 0x22, 0x30, 0x51, 0x07, 0x20, 0x69, 0x04, 0xc2, + 0x29, 0x80, 0x16, 0x30, 0x41, 0x07, 0x20, 0x61, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, 0x07, + 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x52, 0x07, 0x20, 0x6a, 0x04, + 0xc2, 0x2a, 0x80, 0x16, 0x30, 0x42, 0x07, 0x20, 0x62, 0x04, 0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, + 0x07, 0x20, 0x5a, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 0x2a, 0x22, 0x30, 0x53, 0x07, 0x20, 0x6b, + 0x04, 0xc2, 0x2b, 0x80, 0x16, 0x30, 0x43, 0x07, 0x20, 0x63, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, + 0x4b, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x54, 0x07, 0x20, + 0x6c, 0x04, 0xc2, 0x2c, 0x80, 0x16, 0x30, 0x44, 0x07, 0x20, 0x64, 0x04, 0xc2, 0x2c, 0x80, 0x0c, + 0x30, 0x4c, 0x07, 0x20, 0x5c, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, 0x30, 0x55, 0x07, + 0x20, 0x6d, 0x04, 0xc2, 0x2d, 0x80, 0x16, 0x30, 0x45, 0x07, 0x20, 0x65, 0x04, 0xc2, 0x2d, 0x80, + 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x56, + 0x07, 0x20, 0x6e, 0x04, 0xc2, 0x2e, 0x80, 0x16, 0x30, 0x46, 0x07, 0x20, 0x66, 0x04, 0xc2, 0x2e, + 0x80, 0x0c, 0x30, 0x4e, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, + 0x57, 0x07, 0x20, 0x6f, 0x04, 0xc2, 0x2f, 0x80, 0x16, 0x30, 0x47, 0x07, 0x20, 0x67, 0x04, 0xc2, + 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x02, 0xd2, 0x2f, 0x22, + 0x44, 0x38, 0x43, 0xe5, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, 0x0a, 0x5b, 0x49, 0x55, 0x43, + 0xd0, 0x99, 0x54, 0xd3, 0x22, 0xa9, 0xc5, 0x87, 0x12, 0x44, 0x43, 0x7e, 0x04, 0x05, 0xe3, 0x7a, + 0x07, 0x01, 0xd7, 0x7a, 0x07, 0x01, 0xd9, 0x7e, 0x04, 0x01, 0xe3, 0x7a, 0x07, 0x01, 0xdd, 0x7a, + 0x07, 0x01, 0xdf, 0x7e, 0x04, 0x74, 0xad, 0x7a, 0x05, 0x61, 0x75, 0xf1, 0x01, 0x75, 0xe1, 0x1f, + 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x75, 0xf1, 0x02, 0x75, 0xe1, 0x03, 0x75, 0xe4, 0x04, 0x75, + 0xf4, 0x04, 0x43, 0xa2, 0x1c, 0x12, 0x40, 0xeb, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x9a, 0x0b, 0x20, + 0xbe, 0x21, 0x2f, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0xa9, 0xd5, 0x87, 0x12, 0x44, 0x43, 0xd2, 0x92, + 0xc2, 0xa8, 0x22, 0x75, 0xa3, 0x00, 0x53, 0xa2, 0x03, 0x75, 0xc1, 0x00, 0x53, 0xc0, 0x03, 0x7e, + 0x00, 0x05, 0x7a, 0x01, 0xf1, 0x43, 0xf4, 0x80, 0x43, 0xe4, 0x80, 0xe5, 0xf2, 0x54, 0x7f, 0x44, + 0x08, 0xf5, 0xf2, 0xe5, 0xe2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xe2, 0x75, 0xe1, 0x10, 0xa5, 0xd8, + 0xe1, 0x22, 0xca, 0x09, 0x12, 0x30, 0x20, 0x10, 0x01, 0x12, 0xd5, 0x67, 0x1e, 0x63, 0x69, 0x01, + 0x7e, 0x00, 0x6a, 0x2e, 0x01, 0x69, 0xa5, 0xe6, 0xf5, 0x67, 0x80, 0x12, 0x20, 0x02, 0x1e, 0x75, + 0x69, 0x00, 0x85, 0x6a, 0x67, 0xd2, 0x02, 0x74, 0x00, 0x80, 0x0d, 0x30, 0x02, 0x0f, 0xc2, 0x02, + 0x7e, 0x00, 0x6c, 0x2e, 0x01, 0x69, 0xa5, 0xe6, 0x53, 0x90, 0xcf, 0x42, 0x90, 0xda, 0x09, 0x32, + 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, 0xf0, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xd2, 0x01, + 0x75, 0x31, 0x89, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x80, 0x00, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, + 0x03, 0x02, 0x45, 0x4f, 0x20, 0x78, 0x5a, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, + 0x02, 0x45, 0x67, 0x20, 0x79, 0x4b, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, + 0x45, 0x7f, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, 0x97, 0x20, 0x7a, + 0x30, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, 0xaf, 0xa5, 0x0a, 0x09, + 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, 0xc7, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, + 0xe0, 0x03, 0x02, 0x45, 0xdf, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, + 0xf7, 0x30, 0x04, 0x0c, 0xc2, 0x04, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, + 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, 0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x75, + 0x31, 0x80, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, + 0x2b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x81, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0x6b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, + 0x31, 0x82, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, + 0xab, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x83, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0xeb, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, + 0x31, 0x84, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, + 0x2b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x85, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, 0x6b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, + 0x31, 0x86, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, + 0xab, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x87, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, 0xeb, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x10, + 0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x75, 0x31, 0xa0, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x49, 0x30, 0x20, 0xe6, 0x03, 0xd2, 0x08, + 0x22, 0x30, 0x30, 0x49, 0xd2, 0x70, 0x7e, 0x37, 0x01, 0x8f, 0x7e, 0x27, 0x01, 0xaf, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x48, 0x7a, 0x05, 0x48, 0x7a, 0x37, 0x01, 0x8f, 0x7e, 0x37, + 0x01, 0x6f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x6f, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x70, 0xc4, 0x22, 0xc2, 0x70, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x8f, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xaf, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xaf, 0x7e, 0x37, 0x01, 0x8f, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x48, 0x7a, 0x05, 0x48, 0x7a, + 0x37, 0x01, 0x8f, 0x7e, 0x37, 0x01, 0x6f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x6f, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x0d, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x09, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x6f, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x46, 0x7f, + 0x22, 0xd2, 0x08, 0x7e, 0x04, 0x09, 0xe3, 0x7a, 0x07, 0x01, 0x6f, 0x7a, 0x07, 0x01, 0x7f, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xbf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x00, 0x00, 0x2e, 0x27, 0x01, 0xbf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x30, 0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x00, 0x00, 0x2e, 0x67, 0x01, 0xbf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, + 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, + 0x02, 0x47, 0xe3, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, + 0xd2, 0x10, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x47, + 0xe3, 0xda, 0xb8, 0x02, 0x49, 0x30, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x68, 0x80, 0x02, 0xc2, 0x68, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x60, 0x80, 0x02, + 0xc2, 0x60, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0x12, + 0x42, 0xc8, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x48, 0x35, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x09, 0x01, 0x22, 0x20, 0x29, 0x03, 0xd2, 0x09, + 0x22, 0x75, 0x31, 0xa1, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x81, 0x00, 0x80, 0x06, 0x20, 0x29, 0x03, + 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, + 0x12, 0x4c, 0x88, 0x20, 0xe6, 0x03, 0xd2, 0x09, 0x22, 0x30, 0x31, 0x49, 0xd2, 0x71, 0x7e, 0x37, + 0x01, 0x91, 0x7e, 0x27, 0x01, 0xb1, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x4a, 0x7a, + 0x05, 0x4a, 0x7a, 0x37, 0x01, 0x91, 0x7e, 0x37, 0x01, 0x71, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x11, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x71, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x71, 0xc4, 0x22, 0xc2, 0x71, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x91, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xb1, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xb1, 0x7e, 0x37, 0x01, 0x91, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x4a, 0x7a, 0x05, 0x4a, 0x7a, 0x37, 0x01, 0x91, 0x7e, 0x37, 0x01, 0x71, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x71, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x11, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x0d, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x71, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x49, 0xd7, 0x22, 0xd2, 0x09, 0x7e, 0x04, 0x0d, 0xe3, 0x7a, + 0x07, 0x01, 0x71, 0x7a, 0x07, 0x01, 0x81, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc1, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, + 0x01, 0xc1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xc1, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4b, 0x3b, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4b, 0x3b, 0xda, 0xb8, 0x02, 0x4c, 0x88, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x69, 0x80, 0x02, 0xc2, 0x69, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x61, 0x80, 0x02, 0xc2, 0x61, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0x12, 0x42, 0xe9, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4b, + 0x8d, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, + 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x75, 0x31, 0xa2, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x4f, 0xe0, 0x20, 0xe6, 0x03, 0xd2, 0x0a, + 0x22, 0x30, 0x32, 0x49, 0xd2, 0x72, 0x7e, 0x37, 0x01, 0x93, 0x7e, 0x27, 0x01, 0xb3, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x4c, 0x7a, 0x05, 0x4c, 0x7a, 0x37, 0x01, 0x93, 0x7e, 0x37, + 0x01, 0x73, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x73, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x72, 0xc4, 0x22, 0xc2, 0x72, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x93, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xb3, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xb3, 0x7e, 0x37, 0x01, 0x93, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x4c, 0x7a, 0x05, 0x4c, 0x7a, + 0x37, 0x01, 0x93, 0x7e, 0x37, 0x01, 0x73, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x73, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x15, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x11, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x73, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4d, 0x2f, + 0x22, 0xd2, 0x0a, 0x7e, 0x04, 0x11, 0xe3, 0x7a, 0x07, 0x01, 0x73, 0x7a, 0x07, 0x01, 0x83, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc3, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xc3, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x02, 0x00, 0x2e, 0x67, 0x01, 0xc3, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x02, 0x7a, 0x69, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, + 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, + 0x02, 0x4e, 0x93, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, + 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4e, + 0x93, 0xda, 0xb8, 0x02, 0x4f, 0xe0, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x6a, 0x80, 0x02, 0xc2, 0x6a, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x62, 0x80, 0x02, + 0xc2, 0x62, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0x12, + 0x43, 0x0a, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4e, 0xe5, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, + 0x22, 0x75, 0x31, 0xa3, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, 0xd2, 0x0b, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, - 0x12, 0x57, 0x35, 0x30, 0x33, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0b, 0x22, 0x30, 0xe6, 0x02, 0xd2, - 0x63, 0x7e, 0x37, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x9f, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, - 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, 0x5f, 0x7d, 0x43, 0x2d, - 0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5f, 0x75, 0x2f, 0x94, 0x12, 0x7e, - 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x63, 0xc4, 0x22, 0xc2, 0x63, - 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, - 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9f, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9f, 0x7e, 0x37, 0x01, 0x7f, - 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, - 0x01, 0x5f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5f, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x19, 0xcd, 0x9d, - 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x15, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5f, - 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x54, 0xaa, 0x22, 0xd2, 0x0b, 0x7e, 0x04, - 0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, 0x01, 0x6f, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, - 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, - 0x27, 0x01, 0xaf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, - 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, - 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x03, - 0x00, 0x2e, 0x27, 0x01, 0xaf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, - 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, - 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, - 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, - 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, - 0xaf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, - 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, - 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, - 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, - 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, - 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, - 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, - 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, - 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, - 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, - 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, - 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, - 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x56, 0x0e, 0x75, 0x2f, - 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, - 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, - 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x56, 0x0e, 0xda, 0xb8, 0x02, 0x57, - 0x35, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, - 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, - 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, - 0x80, 0x02, 0xc2, 0x53, 0x12, 0x42, 0xf1, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, - 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, - 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, - 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, - 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x56, 0x62, 0x75, 0x2f, - 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0c, 0x01, 0x22, - 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x2f, 0xa4, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x84, 0x00, - 0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, - 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5a, 0x6a, 0x30, 0x34, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0c, - 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x64, 0x7e, 0x37, 0x01, 0x81, 0x7e, 0x27, 0x01, 0xa1, 0x9d, 0x32, - 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, - 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x61, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, - 0x64, 0xc4, 0x22, 0xc2, 0x64, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, - 0x81, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa1, 0x28, 0x04, 0x7e, 0x27, 0x01, - 0xa1, 0x7e, 0x37, 0x01, 0x81, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, - 0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, - 0x13, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, - 0x9e, 0x44, 0x1d, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x19, 0xcd, 0x7d, 0x24, 0x2d, - 0x43, 0x7a, 0x47, 0x01, 0x61, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x57, 0xdf, - 0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, - 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, - 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb1, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, - 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, - 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, - 0x01, 0xc9, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, 0xb1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, - 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, - 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x12, 0x53, 0x38, 0x20, 0xe6, 0x03, 0xd2, 0x0b, 0x22, 0x30, 0x33, 0x49, 0xd2, 0x73, 0x7e, 0x37, + 0x01, 0x95, 0x7e, 0x27, 0x01, 0xb5, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x4e, 0x7a, + 0x05, 0x4e, 0x7a, 0x37, 0x01, 0x95, 0x7e, 0x37, 0x01, 0x75, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x19, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x75, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x73, 0xc4, 0x22, 0xc2, 0x73, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x95, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xb5, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xb5, 0x7e, 0x37, 0x01, 0x95, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x4e, 0x7a, 0x05, 0x4e, 0x7a, 0x37, 0x01, 0x95, 0x7e, 0x37, 0x01, 0x75, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x19, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x75, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x19, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x15, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x75, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x50, 0x87, 0x22, 0xd2, 0x0b, 0x7e, 0x04, 0x15, 0xe3, 0x7a, + 0x07, 0x01, 0x75, 0x7a, 0x07, 0x01, 0x85, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc5, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x03, 0x00, 0x2e, 0x27, + 0x01, 0xc5, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, 0xc5, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x51, 0xeb, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x51, 0xeb, 0xda, 0xb8, 0x02, 0x53, 0x38, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6b, 0x80, 0x02, 0xc2, 0x6b, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x63, 0x80, 0x02, 0xc2, 0x63, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0x12, 0x43, 0x2b, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x52, + 0x3d, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, + 0x0c, 0x01, 0x22, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x31, 0xa4, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x84, 0x00, 0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x56, 0x90, 0x20, 0xe6, 0x03, 0xd2, 0x0c, + 0x22, 0x30, 0x34, 0x49, 0xd2, 0x74, 0x7e, 0x37, 0x01, 0x97, 0x7e, 0x27, 0x01, 0xb7, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x50, 0x7a, 0x05, 0x50, 0x7a, 0x37, 0x01, 0x97, 0x7e, 0x37, + 0x01, 0x77, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x77, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x74, 0xc4, 0x22, 0xc2, 0x74, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x97, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xb7, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xb7, 0x7e, 0x37, 0x01, 0x97, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x50, 0x7a, 0x05, 0x50, 0x7a, + 0x37, 0x01, 0x97, 0x7e, 0x37, 0x01, 0x77, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x77, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x1d, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x19, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x77, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x53, 0xdf, + 0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x19, 0xe3, 0x7a, 0x07, 0x01, 0x77, 0x7a, 0x07, 0x01, 0x87, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, 0xc7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x14, 0x22, - 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, - 0x04, 0x00, 0x2e, 0x67, 0x01, 0xb1, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, - 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, - 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x04, 0x00, 0x2e, 0x67, 0x01, 0xc7, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x04, 0x7a, 0x69, - 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, - 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, - 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, - 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, - 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, - 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, - 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, - 0x02, 0x59, 0x43, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0x02, 0x55, 0x43, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, - 0xd2, 0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x59, - 0x43, 0xda, 0xb8, 0x02, 0x5a, 0x6a, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, - 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, - 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, - 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x12, 0x43, 0x08, 0x02, 0x65, 0x9c, 0x75, - 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, - 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, - 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, - 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, - 0x02, 0x59, 0x97, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, - 0x22, 0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x75, 0x2f, 0xa5, 0x12, 0x7e, - 0x30, 0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5d, 0x9f, 0x30, 0x35, 0x06, - 0x20, 0xe6, 0x4f, 0xd2, 0x0d, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x65, 0x7e, 0x37, 0x01, 0x83, 0x7e, - 0x27, 0x01, 0xa3, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3c, 0x7a, 0x05, 0x3c, 0x7a, - 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x21, 0xcc, 0x38, - 0x68, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0x12, 0x68, 0x34, 0x10, 0x65, 0xc4, 0x22, 0xc2, 0x65, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, - 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa3, - 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa3, 0x7e, 0x37, 0x01, 0x83, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, - 0x3c, 0x7a, 0x05, 0x3c, 0x7a, 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, - 0xbe, 0x44, 0x21, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, - 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x21, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, - 0x1d, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x63, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, - 0x78, 0x03, 0x02, 0x5b, 0x14, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, - 0x7a, 0x07, 0x01, 0x73, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, - 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, - 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb3, 0x2e, 0x24, 0x00, - 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, - 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, - 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, 0x01, 0xb3, 0x1b, - 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, - 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, - 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, - 0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, - 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, 0x01, 0xb3, 0x9e, 0x24, 0x00, 0x02, 0x40, - 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, - 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, - 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, - 0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, - 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, - 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, - 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, - 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, - 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, - 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, - 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, - 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, - 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5c, 0x78, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, + 0xd2, 0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x55, + 0x43, 0xda, 0xb8, 0x02, 0x56, 0x90, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x6c, 0x80, 0x02, 0xc2, 0x6c, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x64, 0x80, 0x02, + 0xc2, 0x64, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0x12, + 0x43, 0x4c, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x55, 0x95, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, + 0x22, 0x75, 0x31, 0xa5, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, + 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, + 0x12, 0x59, 0xe8, 0x20, 0xe6, 0x03, 0xd2, 0x0d, 0x22, 0x30, 0x35, 0x49, 0xd2, 0x75, 0x7e, 0x37, + 0x01, 0x99, 0x7e, 0x27, 0x01, 0xb9, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x52, 0x7a, + 0x05, 0x52, 0x7a, 0x37, 0x01, 0x99, 0x7e, 0x37, 0x01, 0x79, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x21, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x79, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x75, 0xc4, 0x22, 0xc2, 0x75, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x99, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xb9, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xb9, 0x7e, 0x37, 0x01, 0x99, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x52, 0x7a, 0x05, 0x52, 0x7a, 0x37, 0x01, 0x99, 0x7e, 0x37, 0x01, 0x79, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x21, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x79, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x21, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x1d, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x79, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x57, 0x37, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x1d, 0xe3, 0x7a, + 0x07, 0x01, 0x79, 0x7a, 0x07, 0x01, 0x89, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc9, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, + 0x01, 0xc9, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, - 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, - 0x07, 0xca, 0xb8, 0x12, 0x5c, 0x78, 0xda, 0xb8, 0x02, 0x5d, 0x9f, 0x09, 0xb1, 0x00, 0x18, 0x7e, - 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, - 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, - 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, 0x02, 0xc2, 0x55, 0x12, 0x43, - 0x1f, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, - 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, - 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, - 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, - 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5c, 0xcc, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, - 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0e, 0x01, 0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, - 0x75, 0x2f, 0xa6, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x86, 0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, - 0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, - 0x60, 0xd4, 0x30, 0x36, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0e, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x66, - 0x7e, 0x37, 0x01, 0x85, 0x7e, 0x27, 0x01, 0xa5, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, - 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, - 0xbe, 0x44, 0x25, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x65, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x66, 0xc4, 0x22, 0xc2, 0x66, 0x2d, - 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x68, - 0x6a, 0xbe, 0x27, 0x01, 0xa5, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa5, 0x7e, 0x37, 0x01, 0x85, 0x9d, - 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, - 0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x65, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, - 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x25, 0xcd, 0x9d, 0x24, - 0x12, 0x68, 0x34, 0x7e, 0x34, 0x21, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x65, 0x12, - 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5e, 0x49, 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x21, - 0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, - 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, - 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, - 0x01, 0xb5, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, - 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, - 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x06, 0x00, - 0x2e, 0x27, 0x01, 0xb5, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, - 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, - 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, - 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, - 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x06, 0x00, 0x2e, 0x67, 0x01, 0xb5, - 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, - 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, - 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, - 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, - 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, - 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, - 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, - 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, - 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, - 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, - 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, - 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, - 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5f, 0xad, 0x75, 0x2f, 0x99, - 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, - 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, - 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5f, 0xad, 0xda, 0xb8, 0x02, 0x60, 0xd4, - 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, - 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, - 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, - 0x02, 0xc2, 0x56, 0x12, 0x43, 0x36, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, - 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, - 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, - 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, - 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x60, 0x01, 0x75, 0x2f, 0x95, - 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, - 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x75, 0x2f, 0xa7, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x87, 0x00, 0x80, - 0x06, 0x20, 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, - 0xda, 0xb8, 0x68, 0x03, 0x12, 0x64, 0x09, 0x30, 0x37, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0f, 0x22, - 0x30, 0xe6, 0x02, 0xd2, 0x67, 0x7e, 0x37, 0x01, 0x87, 0x7e, 0x27, 0x01, 0xa7, 0x9d, 0x32, 0x40, - 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, 0x87, 0x7e, 0x37, 0x01, - 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x67, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x67, - 0xc4, 0x22, 0xc2, 0x67, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x87, - 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa7, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa7, - 0x7e, 0x37, 0x01, 0x87, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, - 0x01, 0x87, 0x7e, 0x37, 0x01, 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x13, - 0x7a, 0x47, 0x01, 0x67, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, - 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, - 0x44, 0x29, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x25, 0xcd, 0x7d, 0x24, 0x2d, 0x43, - 0x7a, 0x47, 0x01, 0x67, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x61, 0x7e, 0x22, - 0xd2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x75, 0x2f, - 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, - 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, - 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, - 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, - 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, - 0xc9, 0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, 0x01, 0xb7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, - 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, - 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, - 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, - 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x07, - 0x00, 0x2e, 0x67, 0x01, 0xb7, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, - 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, - 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, - 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, - 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, - 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, - 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, - 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, - 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, - 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, - 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, - 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, - 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, - 0x62, 0xe2, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, - 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, - 0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x62, 0xe2, - 0xda, 0xb8, 0x02, 0x64, 0x09, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, - 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, - 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, - 0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x12, 0x43, 0x4d, 0x02, 0x65, 0x9c, 0x75, 0x2f, - 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, - 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, - 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, - 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, - 0x63, 0x36, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, - 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, - 0x20, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, - 0xd2, 0x50, 0x80, 0x02, 0xc2, 0x50, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, - 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, - 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x02, - 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, - 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, - 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, - 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, - 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, - 0x53, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, - 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, - 0x50, 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, - 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, - 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, - 0x02, 0xc2, 0x55, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, - 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, - 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 0x02, 0xc2, 0x56, 0x02, 0x65, 0x88, 0x7c, - 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, - 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, - 0x57, 0x80, 0x02, 0xc2, 0x57, 0x02, 0x65, 0x88, 0x54, 0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, - 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0x22, 0xca, 0x19, 0x5e, 0x20, - 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, - 0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, 0x64, 0x00, 0x02, 0x02, 0x65, 0xe7, 0xca, - 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, - 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, - 0x7e, 0x64, 0x00, 0x03, 0x02, 0x65, 0xe7, 0xd2, 0x04, 0x7e, 0x27, 0x01, 0xcb, 0x2d, 0x26, 0xbe, - 0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7e, 0x79, 0xa0, - 0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, 0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, - 0x01, 0xcb, 0x7e, 0x25, 0x30, 0x2d, 0x26, 0x7a, 0x25, 0x30, 0x7a, 0x07, 0x01, 0xc9, 0xda, 0x19, - 0xc2, 0xd7, 0x22, 0x75, 0x2f, 0x9a, 0x12, 0x7e, 0x30, 0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, - 0x01, 0xcd, 0x80, 0xd7, 0x4d, 0x42, 0x4a, 0xae, 0x4b, 0xa8, 0x4d, 0x7b, 0x49, 0x4f, 0x49, 0x4f, - 0x4c, 0xa7, 0x49, 0x4f, 0x4d, 0xbf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x4d, 0xc6, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x50, 0x77, 0x4d, 0xe3, 0x4e, 0xdd, 0x50, 0xb0, 0x49, 0x4f, 0x49, 0x4f, - 0x4f, 0xdc, 0x49, 0x4f, 0x50, 0xf4, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x50, 0xfb, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x53, 0xac, 0x51, 0x18, 0x52, 0x12, 0x53, 0xe5, 0x49, 0x4f, 0x49, 0x4f, - 0x53, 0x11, 0x49, 0x4f, 0x54, 0x29, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x54, 0x30, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x56, 0xe1, 0x54, 0x4d, 0x55, 0x47, 0x57, 0x1a, 0x49, 0x4f, 0x49, 0x4f, - 0x56, 0x46, 0x49, 0x4f, 0x57, 0x5e, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x57, 0x65, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x16, 0x57, 0x82, 0x58, 0x7c, 0x5a, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x59, 0x7b, 0x49, 0x4f, 0x5a, 0x93, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x9a, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5d, 0x4b, 0x5a, 0xb7, 0x5b, 0xb1, 0x5d, 0x84, 0x49, 0x4f, 0x49, 0x4f, - 0x5c, 0xb0, 0x49, 0x4f, 0x5d, 0xc8, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5d, 0xcf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x60, 0x80, 0x5d, 0xec, 0x5e, 0xe6, 0x60, 0xb9, 0x49, 0x4f, 0x49, 0x4f, - 0x5f, 0xe5, 0x49, 0x4f, 0x60, 0xfd, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x61, 0x04, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x63, 0xb5, 0x61, 0x21, 0x62, 0x1b, 0x63, 0xee, 0x49, 0x4f, 0x49, 0x4f, - 0x63, 0x1a, 0x49, 0x4f, 0x64, 0x32, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x64, 0x39, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0xca, 0x29, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x10, 0x9c, 0xb5, - 0xa4, 0x2e, 0x54, 0x68, 0x51, 0x89, 0x54, 0x7e, 0x39, 0x00, 0x7a, 0x19, 0x00, 0x0b, 0x34, 0x80, - 0xe9, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, - 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, - 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, - 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, 0x01, 0xc9, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x58, 0x9b, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x58, 0x9b, 0xda, 0xb8, 0x02, 0x59, 0xe8, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6d, 0x80, 0x02, 0xc2, 0x6d, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x65, 0x80, 0x02, 0xc2, 0x65, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0x12, 0x43, 0x6d, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x58, + 0xed, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, + 0x0e, 0x01, 0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x75, 0x31, 0xa6, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x86, 0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5d, 0x40, 0x20, 0xe6, 0x03, 0xd2, 0x0e, + 0x22, 0x30, 0x36, 0x49, 0xd2, 0x76, 0x7e, 0x37, 0x01, 0x9b, 0x7e, 0x27, 0x01, 0xbb, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x54, 0x7a, 0x05, 0x54, 0x7a, 0x37, 0x01, 0x9b, 0x7e, 0x37, + 0x01, 0x7b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x7b, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x76, 0xc4, 0x22, 0xc2, 0x76, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x9b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xbb, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xbb, 0x7e, 0x37, 0x01, 0x9b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x54, 0x7a, 0x05, 0x54, 0x7a, + 0x37, 0x01, 0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x7b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x25, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x21, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x7b, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5a, 0x8f, + 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x21, 0xe3, 0x7a, 0x07, 0x01, 0x7b, 0x7a, 0x07, 0x01, 0x8b, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xcb, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x06, 0x00, 0x2e, 0x27, 0x01, 0xcb, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x06, 0x00, 0x2e, 0x67, 0x01, 0xcb, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, + 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, + 0x02, 0x5b, 0xf3, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, + 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5b, + 0xf3, 0xda, 0xb8, 0x02, 0x5d, 0x40, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x6e, 0x80, 0x02, 0xc2, 0x6e, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x66, 0x80, 0x02, + 0xc2, 0x66, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0x12, + 0x43, 0x8e, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5c, 0x45, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, 0x2f, 0x03, 0xd2, 0x0f, + 0x22, 0x75, 0x31, 0xa7, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x87, 0x00, 0x80, 0x06, 0x20, 0x2f, 0x03, + 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, + 0x12, 0x60, 0x98, 0x20, 0xe6, 0x03, 0xd2, 0x0f, 0x22, 0x30, 0x37, 0x49, 0xd2, 0x77, 0x7e, 0x37, + 0x01, 0x9d, 0x7e, 0x27, 0x01, 0xbd, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x56, 0x7a, + 0x05, 0x56, 0x7a, 0x37, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x29, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x7d, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x77, 0xc4, 0x22, 0xc2, 0x77, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x9d, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xbd, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xbd, 0x7e, 0x37, 0x01, 0x9d, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x56, 0x7a, 0x05, 0x56, 0x7a, 0x37, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x7d, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x29, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x25, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x7d, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5d, 0xe7, 0x22, 0xd2, 0x0f, 0x7e, 0x04, 0x25, 0xe3, 0x7a, + 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xcd, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, + 0x01, 0xcd, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x07, 0x00, 0x2e, 0x67, 0x01, 0xcd, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5f, 0x4b, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5f, 0x4b, 0xda, 0xb8, 0x02, 0x60, 0x98, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6f, 0x80, 0x02, 0xc2, 0x6f, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x67, 0x80, 0x02, 0xc2, 0x67, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0x12, 0x43, 0xaf, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5f, + 0x9d, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x7c, + 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, + 0x68, 0x04, 0xd2, 0x68, 0x80, 0x02, 0xc2, 0x68, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, + 0x60, 0x80, 0x02, 0xc2, 0x60, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, + 0xc2, 0x58, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, + 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x69, 0x80, 0x02, 0xc2, 0x69, 0xa5, 0xfd, + 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x61, 0x80, 0x02, 0xc2, 0x61, 0xa5, 0xfd, 0x5e, 0x50, 0x80, + 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, + 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6a, + 0x80, 0x02, 0xc2, 0x6a, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x62, 0x80, 0x02, 0xc2, + 0x62, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0x02, 0x62, + 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, + 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6b, 0x80, 0x02, 0xc2, 0x6b, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, + 0x04, 0xd2, 0x63, 0x80, 0x02, 0xc2, 0x63, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5b, + 0x80, 0x02, 0xc2, 0x5b, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, + 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6c, 0x80, 0x02, 0xc2, 0x6c, + 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x64, 0x80, 0x02, 0xc2, 0x64, 0xa5, 0xfd, 0x5e, + 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, + 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, + 0xd2, 0x6d, 0x80, 0x02, 0xc2, 0x6d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x65, 0x80, + 0x02, 0xc2, 0x65, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, + 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, + 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6e, 0x80, 0x02, 0xc2, 0x6e, 0xa5, 0xfd, 0x5e, 0x50, + 0x20, 0x68, 0x04, 0xd2, 0x66, 0x80, 0x02, 0xc2, 0x66, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, + 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, + 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6f, 0x80, 0x02, + 0xc2, 0x6f, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x67, 0x80, 0x02, 0xc2, 0x67, 0xa5, + 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0x02, 0x62, 0x7f, 0x54, + 0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, + 0x7c, 0x15, 0x22, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xe3, 0xca, 0x79, + 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, + 0x64, 0x00, 0x02, 0x02, 0x62, 0xde, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, + 0xe3, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, + 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, 0x7e, 0x64, 0x00, 0x03, 0x02, 0x62, 0xde, 0xd2, 0x04, + 0x7e, 0x27, 0x01, 0xe1, 0x2d, 0x26, 0xbe, 0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xdf, + 0x7e, 0x44, 0x05, 0xe3, 0x7e, 0x79, 0xa0, 0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, + 0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, 0x01, 0xe1, 0x7e, 0x25, 0x46, 0x2d, 0x26, 0x7a, 0x25, + 0x46, 0x7a, 0x07, 0x01, 0xdf, 0xda, 0x19, 0xc2, 0xd7, 0x22, 0x75, 0x31, 0x9a, 0x12, 0x7c, 0x15, + 0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd7, 0x48, 0xb6, 0x46, 0x25, 0x47, + 0x1c, 0x49, 0x15, 0x44, 0xc6, 0x44, 0xc6, 0x48, 0x1b, 0x44, 0xc6, 0x49, 0x59, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x49, 0x60, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x4c, 0x0e, 0x49, 0x7d, 0x4a, + 0x74, 0x4c, 0x6d, 0x44, 0xc6, 0x44, 0xc6, 0x4b, 0x73, 0x44, 0xc6, 0x4c, 0xb1, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x4c, 0xb8, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x4f, 0x66, 0x4c, 0xd5, 0x4d, + 0xcc, 0x4f, 0xc5, 0x44, 0xc6, 0x44, 0xc6, 0x4e, 0xcb, 0x44, 0xc6, 0x50, 0x09, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x50, 0x10, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x52, 0xbe, 0x50, 0x2d, 0x51, + 0x24, 0x53, 0x1d, 0x44, 0xc6, 0x44, 0xc6, 0x52, 0x23, 0x44, 0xc6, 0x53, 0x61, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x53, 0x68, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x56, 0x16, 0x53, 0x85, 0x54, + 0x7c, 0x56, 0x75, 0x44, 0xc6, 0x44, 0xc6, 0x55, 0x7b, 0x44, 0xc6, 0x56, 0xb9, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x56, 0xc0, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x59, 0x6e, 0x56, 0xdd, 0x57, + 0xd4, 0x59, 0xcd, 0x44, 0xc6, 0x44, 0xc6, 0x58, 0xd3, 0x44, 0xc6, 0x5a, 0x11, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x5a, 0x18, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x5c, 0xc6, 0x5a, 0x35, 0x5b, + 0x2c, 0x5d, 0x25, 0x44, 0xc6, 0x44, 0xc6, 0x5c, 0x2b, 0x44, 0xc6, 0x5d, 0x69, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x5d, 0x70, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x60, 0x1e, 0x5d, 0x8d, 0x5e, + 0x84, 0x60, 0x7d, 0x44, 0xc6, 0x44, 0xc6, 0x5f, 0x83, 0x44, 0xc6, 0x60, 0xc1, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x60, 0xc8, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0xca, 0x29, 0x1e, 0x50, 0x40, + 0x0d, 0x7e, 0x54, 0x0b, 0x10, 0x9c, 0xb5, 0xa4, 0x2e, 0x54, 0x65, 0x48, 0x89, 0x54, 0x7e, 0x39, + 0x00, 0x7a, 0x19, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, @@ -744,12 +832,12 @@ 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, - 0x35, 0xda, 0x29, 0x22, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x1c, 0x9c, 0xb5, 0xa4, 0x2e, - 0x54, 0x69, 0x1f, 0x89, 0x54, 0x7e, 0x19, 0x00, 0x7a, 0x39, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x7e, - 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, - 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, - 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, - 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, + 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, + 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, + 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, + 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0xda, 0x29, 0x22, 0x1e, 0x50, 0x40, 0x0d, 0x7e, + 0x54, 0x0b, 0x1c, 0x9c, 0xb5, 0xa4, 0x2e, 0x54, 0x66, 0x16, 0x89, 0x54, 0x7e, 0x19, 0x00, 0x7a, + 0x39, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, @@ -765,157 +853,176 @@ 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, - 0x00, 0x0b, 0x35, 0x22, 0x6a, 0x9b, 0x6c, 0x4f, 0x6c, 0x67, 0x6c, 0x82, 0x6d, 0x1d, 0x6d, 0xb5, - 0x6d, 0xd0, 0x6e, 0x62, 0x6d, 0xeb, 0x6e, 0x2c, 0x7c, 0xb3, 0xbe, 0xb0, 0x09, 0x28, 0x14, 0x75, - 0x2f, 0x09, 0x12, 0x7e, 0x30, 0x75, 0x57, 0x10, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x43, 0xe1, 0xc0, - 0xd0, 0xf1, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x6a, 0x54, 0x0b, 0x58, - 0x50, 0x89, 0x54, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x2f, 0xb0, 0x12, 0x7e, - 0x30, 0x0a, 0x22, 0x09, 0xb2, 0x6a, 0x93, 0x42, 0x24, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, - 0x3b, 0x49, 0x33, 0x6a, 0xb7, 0x89, 0x34, 0x6a, 0xc7, 0x6a, 0xf5, 0x6b, 0x23, 0x6b, 0x51, 0x6b, - 0x7f, 0x6b, 0xad, 0x6b, 0xdb, 0x6c, 0x09, 0x12, 0x41, 0xa9, 0xd2, 0x28, 0xd2, 0x08, 0xc2, 0x40, - 0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x7e, 0x04, 0x00, 0x20, - 0x7a, 0x07, 0x01, 0x99, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xa9, 0x12, 0x41, 0x16, 0x12, - 0x64, 0x40, 0x02, 0x6c, 0x37, 0x12, 0x41, 0xc6, 0xd2, 0x29, 0xd2, 0x09, 0xc2, 0x41, 0xc2, 0x49, - 0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xba, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, - 0x01, 0x9b, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xab, 0x12, 0x41, 0x16, 0x12, 0x64, 0x69, - 0x02, 0x6c, 0x37, 0x12, 0x41, 0xe3, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, 0xc2, 0x4a, 0xc2, 0x3a, - 0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9d, - 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xad, 0x12, 0x41, 0x16, 0x12, 0x64, 0x92, 0x02, 0x6c, - 0x37, 0x12, 0x42, 0x00, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, 0xc2, 0x3b, 0xc2, 0x33, - 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9f, 0x7e, 0x04, - 0x00, 0x38, 0x7a, 0x07, 0x01, 0xaf, 0x12, 0x41, 0x16, 0x12, 0x64, 0xbb, 0x02, 0x6c, 0x37, 0x12, - 0x42, 0x1d, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, 0xc2, 0x34, 0x6d, 0x00, - 0x7a, 0x03, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa1, 0x7e, 0x04, 0x00, 0x38, - 0x7a, 0x07, 0x01, 0xb1, 0x12, 0x41, 0x16, 0x12, 0x64, 0xe4, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x3a, - 0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, 0x6d, 0x00, 0x7a, 0x03, - 0x01, 0xbe, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, - 0x01, 0xb3, 0x12, 0x41, 0x16, 0x12, 0x65, 0x0d, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x57, 0xd2, 0x2e, - 0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbf, - 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb5, - 0x12, 0x41, 0x16, 0x12, 0x65, 0x36, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x74, 0xd2, 0x2f, 0xd2, 0x0f, - 0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x7e, 0x04, - 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa7, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb7, 0x12, 0x41, - 0x16, 0x12, 0x65, 0x5f, 0x02, 0x6c, 0x37, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, 0x0f, 0x12, 0x65, 0xbf, - 0x40, 0x0c, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xc2, 0xd7, 0x22, 0x75, - 0x2f, 0xb1, 0x12, 0x7e, 0x30, 0x0a, 0x52, 0x23, 0x6d, 0x00, 0x59, 0x05, 0x00, 0x32, 0x12, 0x41, - 0x72, 0x12, 0x41, 0x8e, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb2, 0x12, 0x7e, 0x30, 0x0a, 0x22, 0x09, - 0xb2, 0x6a, 0x93, 0x42, 0x23, 0x7e, 0xb0, 0x9c, 0x19, 0xb2, 0x01, 0xb9, 0x12, 0x45, 0x74, 0xd0, - 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, - 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, - 0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, - 0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, - 0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, 0xb8, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, - 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0x3e, 0x20, - 0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x20, 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, - 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, 0x59, 0x46, 0x01, 0xa9, 0x09, 0xb0, 0x00, 0x10, 0x44, - 0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x11, 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, - 0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, 0x46, 0x01, 0xa9, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, - 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, - 0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x04, 0x44, 0x80, 0x80, 0x02, 0x54, 0x7f, - 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x02, 0x80, 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, - 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, - 0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xda, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x10, 0xa5, - 0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x04, 0xa5, - 0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x29, 0x42, 0x26, - 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x15, 0xa5, 0xee, 0x52, 0x29, 0x7c, 0x74, - 0x5e, 0x70, 0x02, 0x78, 0x0a, 0x52, 0x26, 0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0x99, 0x12, - 0x42, 0x91, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, - 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, - 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, - 0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb5, 0x12, 0x7e, - 0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, - 0x0c, 0xe5, 0x58, 0xb4, 0x07, 0x23, 0x09, 0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, - 0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, - 0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb6, 0x12, - 0x7e, 0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe5, 0x58, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, - 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, - 0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, - 0xa8, 0x22, 0x75, 0x2f, 0xb4, 0x12, 0x7e, 0x30, 0x7a, 0x21, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, - 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0xb0, 0x01, 0x7e, 0xa0, 0xc8, 0x7c, 0x64, 0x12, 0x65, 0xbf, 0xc0, - 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xd0, 0xa8, 0x22, 0x6e, 0x9c, 0x6e, 0xe3, - 0x6f, 0x2a, 0x6f, 0x71, 0x6f, 0xb8, 0x6f, 0xff, 0x70, 0x46, 0x70, 0x8d, 0x75, 0x2f, 0x55, 0x12, - 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, - 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x69, 0x7e, 0x27, 0x01, 0x79, 0x2d, 0x23, 0x7e, 0x09, - 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x0d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, - 0x78, 0xec, 0x7a, 0x17, 0x01, 0x69, 0x7a, 0x27, 0x01, 0x79, 0x02, 0x4a, 0x98, 0x7e, 0x14, 0x09, - 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x01, 0x12, 0x7e, 0x30, 0x7a, - 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6b, 0x7e, - 0x27, 0x01, 0x7b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, - 0x14, 0x11, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6b, 0x7a, 0x27, 0x01, - 0x7b, 0x02, 0x4d, 0xcd, 0x7e, 0x14, 0x0d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, - 0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, - 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6d, 0x7e, 0x27, 0x01, 0x7d, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, - 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x15, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, - 0x7a, 0x17, 0x01, 0x6d, 0x7a, 0x27, 0x01, 0x7d, 0x02, 0x51, 0x02, 0x7e, 0x14, 0x11, 0xcd, 0x80, - 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x03, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, - 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6f, 0x7e, 0x27, 0x01, - 0x7f, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x19, - 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6f, 0x7a, 0x27, 0x01, 0x7f, 0x02, - 0x54, 0x37, 0x7e, 0x14, 0x15, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, - 0x04, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, - 0x7e, 0x17, 0x01, 0x71, 0x7e, 0x27, 0x01, 0x81, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, - 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, - 0x01, 0x71, 0x7a, 0x27, 0x01, 0x81, 0x02, 0x57, 0x6c, 0x7e, 0x14, 0x19, 0xcd, 0x80, 0xeb, 0x75, - 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x05, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, - 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x73, 0x7e, 0x27, 0x01, 0x83, 0x2d, - 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x21, 0xcc, 0x38, - 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x73, 0x7a, 0x27, 0x01, 0x83, 0x02, 0x5a, 0xa1, - 0x7e, 0x14, 0x1d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x06, 0x12, - 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, - 0x01, 0x75, 0x7e, 0x27, 0x01, 0x85, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, - 0x0b, 0x14, 0xbe, 0x14, 0x25, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x75, - 0x7a, 0x27, 0x01, 0x85, 0x02, 0x5d, 0xd6, 0x7e, 0x14, 0x21, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, - 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, - 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x77, 0x7e, 0x27, 0x01, 0x87, 0x2d, 0x23, 0x7e, - 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x29, 0xcc, 0x38, 0x0f, 0x1b, - 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x77, 0x7a, 0x27, 0x01, 0x87, 0x02, 0x61, 0x0b, 0x7e, 0x14, - 0x25, 0xcd, 0x80, 0xeb, 0xca, 0xb8, 0xc0, 0xf1, 0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0xe5, 0xc0, - 0x54, 0x03, 0x68, 0x05, 0x12, 0x77, 0xdd, 0x80, 0xf5, 0x30, 0xc2, 0x08, 0x75, 0xf1, 0x01, 0x12, - 0x71, 0xe9, 0x80, 0x14, 0x30, 0xc3, 0x08, 0x75, 0xf1, 0x01, 0x12, 0x71, 0x0d, 0x80, 0x09, 0x30, - 0xc4, 0x06, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xf9, 0xd0, 0xf1, 0xda, 0xb8, 0x32, 0x75, 0x2f, 0x10, - 0x12, 0x7e, 0x30, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x5c, 0xe5, - 0xe5, 0x54, 0xc0, 0x68, 0x4f, 0xe5, 0xe6, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xc5, 0x2d, 0x35, 0xbe, - 0x34, 0x04, 0x00, 0x38, 0x4a, 0x7a, 0x37, 0x01, 0xc5, 0x7e, 0x37, 0x01, 0xc3, 0x7d, 0x43, 0x2d, - 0x45, 0xbe, 0x44, 0x09, 0xcc, 0x38, 0x40, 0x7a, 0x47, 0x01, 0xc3, 0x75, 0x2f, 0x11, 0x12, 0x7e, - 0x30, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x73, 0xc8, 0xa9, 0x21, 0xe5, 0x1f, 0xa9, 0xd4, + 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, + 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, + 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, + 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x22, 0x67, 0x96, 0x69, 0x63, 0x69, + 0x7b, 0x6a, 0x49, 0x6a, 0xe4, 0x6b, 0x8e, 0x6b, 0xa9, 0x6c, 0x3b, 0x6b, 0xc4, 0x6c, 0x05, 0x69, + 0x96, 0x69, 0xaa, 0x7c, 0xb3, 0xbe, 0xb0, 0x0b, 0x28, 0x14, 0x75, 0x31, 0x09, 0x12, 0x7c, 0x15, + 0x75, 0x6d, 0x10, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x22, 0xc0, 0xa8, + 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x67, 0x4b, 0x0b, 0x58, 0x50, 0x89, 0x54, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x31, 0xb0, 0x12, 0x7c, 0x15, 0x0a, 0x32, 0x09, 0xb3, + 0x67, 0x8e, 0x42, 0x32, 0x19, 0x43, 0x00, 0x36, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x3b, + 0x49, 0x33, 0x67, 0xcb, 0x0a, 0x22, 0x09, 0x32, 0x00, 0x36, 0x09, 0xb2, 0x67, 0x8e, 0xa5, 0xbb, + 0x00, 0x05, 0xf4, 0x52, 0x33, 0x80, 0x02, 0x42, 0x33, 0x89, 0x34, 0x67, 0xdb, 0x68, 0x09, 0x68, + 0x37, 0x68, 0x65, 0x68, 0x93, 0x68, 0xc1, 0x68, 0xef, 0x69, 0x1d, 0x12, 0x41, 0xb5, 0xd2, 0x28, + 0xd2, 0x08, 0xc2, 0x40, 0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xcf, + 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xaf, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xbf, + 0x12, 0x41, 0x16, 0x12, 0x60, 0xcf, 0x02, 0x69, 0x4b, 0x12, 0x41, 0xd4, 0xd2, 0x29, 0xd2, 0x09, + 0xc2, 0x41, 0xc2, 0x49, 0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd0, 0x7e, 0x04, + 0x00, 0x20, 0x7a, 0x07, 0x01, 0xb1, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc1, 0x12, 0x41, + 0x16, 0x12, 0x61, 0x05, 0x02, 0x69, 0x4b, 0x12, 0x41, 0xf3, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, + 0xc2, 0x4a, 0xc2, 0x3a, 0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd1, 0x7e, 0x04, 0x00, 0x20, + 0x7a, 0x07, 0x01, 0xb3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc3, 0x12, 0x41, 0x16, 0x12, + 0x61, 0x3b, 0x02, 0x69, 0x4b, 0x12, 0x42, 0x12, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, + 0xc2, 0x3b, 0xc2, 0x33, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd2, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, + 0x01, 0xb5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc5, 0x12, 0x41, 0x16, 0x12, 0x61, 0x71, + 0x02, 0x69, 0x4b, 0x12, 0x42, 0x31, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, + 0xc2, 0x34, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd3, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xb7, + 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc7, 0x12, 0x41, 0x16, 0x12, 0x61, 0xa7, 0x02, 0x69, + 0x4b, 0x12, 0x42, 0x50, 0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, + 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd4, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xb9, 0x7e, 0x04, + 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc9, 0x12, 0x41, 0x16, 0x12, 0x61, 0xdd, 0x02, 0x69, 0x4b, 0x12, + 0x42, 0x6f, 0xd2, 0x2e, 0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, + 0x7a, 0x03, 0x01, 0xd5, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x38, + 0x7a, 0x07, 0x01, 0xcb, 0x12, 0x41, 0x16, 0x12, 0x62, 0x13, 0x02, 0x69, 0x4b, 0x12, 0x42, 0x8e, + 0xd2, 0x2f, 0xd2, 0x0f, 0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, + 0x01, 0xd6, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, + 0x01, 0xcd, 0x12, 0x41, 0x16, 0x12, 0x62, 0x49, 0x02, 0x69, 0x4b, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, + 0x0f, 0x12, 0x62, 0xb6, 0x40, 0x0c, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, + 0xc2, 0xd7, 0x22, 0x75, 0x31, 0xb1, 0x12, 0x7c, 0x15, 0x0a, 0x52, 0x23, 0x6d, 0x00, 0x59, 0x05, + 0x00, 0x48, 0x12, 0x41, 0x7e, 0x12, 0x41, 0x9a, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb2, 0x12, 0x7c, + 0x15, 0x0a, 0x22, 0x09, 0xb2, 0x67, 0x8e, 0x42, 0x23, 0x7e, 0xb0, 0x9c, 0x19, 0xb2, 0x01, 0xcf, + 0x12, 0x31, 0x85, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb7, 0x12, 0x7c, 0x15, 0x0a, 0x22, 0x09, 0xb2, + 0x67, 0x8e, 0x42, 0x24, 0x12, 0x35, 0x3d, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb9, 0x12, 0x7c, 0x15, + 0x0a, 0x32, 0x09, 0xb3, 0x67, 0x8e, 0x42, 0x34, 0x19, 0x43, 0x00, 0x3e, 0x12, 0x69, 0xc2, 0xd0, + 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x0b, 0x7c, 0xb4, 0x20, 0xe0, 0x04, 0x6d, 0x33, 0x80, 0x04, + 0x49, 0x30, 0x01, 0x8f, 0x7e, 0xa0, 0xd8, 0xa5, 0xef, 0xca, 0x0b, 0xca, 0x29, 0x12, 0x62, 0xb6, + 0xda, 0x29, 0xda, 0x0b, 0x40, 0x62, 0x75, 0x31, 0xba, 0x12, 0x7c, 0x15, 0x7c, 0xb4, 0x30, 0xe0, + 0x1e, 0x6d, 0x33, 0x59, 0x30, 0x01, 0x8f, 0x7e, 0x34, 0x09, 0xe3, 0x0a, 0x82, 0x7e, 0x94, 0x04, + 0x00, 0xad, 0x89, 0x2d, 0x39, 0x59, 0x30, 0x01, 0x6f, 0x59, 0x30, 0x01, 0x7f, 0x7c, 0xb4, 0x30, + 0xe1, 0x10, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0xb0, 0x00, 0x08, 0x44, 0x04, 0x19, 0xb0, + 0x00, 0x08, 0x0a, 0x02, 0x09, 0xb0, 0x67, 0x8e, 0x42, 0x21, 0xf4, 0x52, 0x34, 0x7c, 0xb2, 0x23, + 0x0a, 0x0b, 0xca, 0x19, 0x49, 0x00, 0x30, 0xd5, 0x99, 0x04, 0xda, 0x19, 0xc0, 0xf1, 0x75, 0xf1, + 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0xc2, 0xd7, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, + 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, + 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, 0x00, 0x10, + 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, 0x5e, 0x70, + 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, 0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, 0xb8, 0x74, + 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, + 0x62, 0x09, 0xb6, 0x67, 0x8e, 0x3e, 0x20, 0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x20, + 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, 0x59, 0x46, + 0x01, 0xbf, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x11, + 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, 0x46, 0x01, + 0xbf, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x0a, 0x62, 0x09, 0xb6, + 0x67, 0x8e, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, 0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xa5, 0xee, 0x52, + 0x26, 0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0xaf, 0xda, 0x28, 0x09, 0x30, 0x00, 0x0c, 0x74, + 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x0c, + 0x44, 0x80, 0xca, 0xb8, 0xa5, 0xed, 0x42, 0x2a, 0xda, 0xb8, 0x80, 0x0a, 0x54, 0x7f, 0xca, 0xb8, + 0xa5, 0xee, 0x52, 0x2a, 0xda, 0xb8, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x02, 0x80, + 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x02, + 0x68, 0x10, 0xa5, 0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0xaf, + 0x80, 0x04, 0xa5, 0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, + 0x29, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0xaf, 0x80, 0x0b, 0xa5, 0xee, 0x52, + 0x29, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x78, 0x00, 0x12, 0x42, 0xad, 0xd0, 0xa8, 0x22, 0x7e, 0x04, + 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, + 0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, + 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, + 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb5, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, + 0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, 0x0c, 0xe5, 0x6e, 0xb4, 0x07, 0x23, 0x09, + 0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, 0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, + 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, 0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, + 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb6, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x80, 0x00, 0x4c, + 0x02, 0xe5, 0x6e, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, + 0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, + 0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb4, 0x12, 0x7c, + 0x15, 0x7a, 0x21, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x41, 0x31, 0x12, 0x7c, 0x15, 0x0a, 0x32, 0x09, + 0xb3, 0x67, 0x8e, 0x42, 0x35, 0x12, 0x6c, 0x5b, 0xd0, 0xa8, 0x22, 0x7e, 0xb0, 0x01, 0x7e, 0xa0, + 0xc8, 0x7c, 0x64, 0x12, 0x62, 0xb6, 0x40, 0x13, 0x0a, 0x32, 0x09, 0xb3, 0x67, 0x8e, 0xf4, 0x52, + 0x35, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x6c, 0x8c, 0x6c, 0xd3, + 0x6d, 0x1a, 0x6d, 0x61, 0x6d, 0xa8, 0x6d, 0xef, 0x6e, 0x36, 0x6e, 0x7d, 0x75, 0x31, 0x55, 0x12, + 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, + 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x8f, 0x2d, 0x23, 0x7e, 0x09, + 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x0d, 0xe2, 0x38, 0x0f, 0x1b, 0x34, + 0x78, 0xec, 0x7a, 0x17, 0x01, 0x7f, 0x7a, 0x27, 0x01, 0x8f, 0x02, 0x46, 0x0f, 0x7e, 0x14, 0x09, + 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x01, 0x12, 0x7c, 0x15, 0x7a, + 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x81, 0x7e, + 0x27, 0x01, 0x91, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, + 0x14, 0x11, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x81, 0x7a, 0x27, 0x01, + 0x91, 0x02, 0x49, 0x67, 0x7e, 0x14, 0x0d, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, + 0x75, 0x31, 0x02, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x83, 0x7e, 0x27, 0x01, 0x93, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, + 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x15, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, + 0x7a, 0x17, 0x01, 0x83, 0x7a, 0x27, 0x01, 0x93, 0x02, 0x4c, 0xbf, 0x7e, 0x14, 0x11, 0xe3, 0x80, + 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x03, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, + 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x85, 0x7e, 0x27, 0x01, + 0x95, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x19, + 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x85, 0x7a, 0x27, 0x01, 0x95, 0x02, + 0x50, 0x17, 0x7e, 0x14, 0x15, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, + 0x04, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, + 0x7e, 0x17, 0x01, 0x87, 0x7e, 0x27, 0x01, 0x97, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, + 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1d, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, + 0x01, 0x87, 0x7a, 0x27, 0x01, 0x97, 0x02, 0x53, 0x6f, 0x7e, 0x14, 0x19, 0xe3, 0x80, 0xeb, 0x75, + 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x05, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, + 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x89, 0x7e, 0x27, 0x01, 0x99, 0x2d, + 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x21, 0xe2, 0x38, + 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x89, 0x7a, 0x27, 0x01, 0x99, 0x02, 0x56, 0xc7, + 0x7e, 0x14, 0x1d, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x06, 0x12, + 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, + 0x01, 0x8b, 0x7e, 0x27, 0x01, 0x9b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, + 0x0b, 0x14, 0xbe, 0x14, 0x25, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x8b, + 0x7a, 0x27, 0x01, 0x9b, 0x02, 0x5a, 0x1f, 0x7e, 0x14, 0x21, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, + 0x12, 0x7c, 0x15, 0x75, 0x31, 0x07, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, + 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x8d, 0x7e, 0x27, 0x01, 0x9d, 0x2d, 0x23, 0x7e, + 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x29, 0xe2, 0x38, 0x0f, 0x1b, + 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x8d, 0x7a, 0x27, 0x01, 0x9d, 0x02, 0x5d, 0x77, 0x7e, 0x14, + 0x25, 0xe3, 0x80, 0xeb, 0xca, 0xb8, 0xc0, 0xf1, 0x75, 0x31, 0x02, 0x12, 0x7c, 0x15, 0xe5, 0xc0, + 0x54, 0x03, 0x68, 0x05, 0x12, 0x75, 0xcd, 0x80, 0xf5, 0x30, 0xc2, 0x08, 0x75, 0xf1, 0x01, 0x12, + 0x6f, 0xd9, 0x80, 0x14, 0x30, 0xc3, 0x08, 0x75, 0xf1, 0x01, 0x12, 0x6e, 0xfd, 0x80, 0x09, 0x30, + 0xc4, 0x06, 0x75, 0xf1, 0x02, 0x12, 0x70, 0xe9, 0xd0, 0xf1, 0xda, 0xb8, 0x32, 0x75, 0x31, 0x10, + 0x12, 0x7c, 0x15, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x5c, 0xe5, + 0xe5, 0x54, 0xc0, 0x68, 0x4f, 0xe5, 0xe6, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xdb, 0x2d, 0x35, 0xbe, + 0x34, 0x04, 0x00, 0x38, 0x4a, 0x7a, 0x37, 0x01, 0xdb, 0x7e, 0x37, 0x01, 0xd9, 0x7d, 0x43, 0x2d, + 0x45, 0xbe, 0x44, 0x09, 0xe2, 0x38, 0x40, 0x7a, 0x47, 0x01, 0xd9, 0x75, 0x31, 0x11, 0x12, 0x7c, + 0x15, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x71, 0xb8, 0xa9, 0x21, 0xe5, 0x1f, 0xa9, 0xd4, 0xe4, 0xa9, 0x24, 0xe4, 0xfc, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x3b, 0xe5, 0xe5, 0x54, 0xc0, 0x78, - 0xb4, 0x12, 0x76, 0x6a, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x80, 0x29, 0x80, 0x58, 0x75, - 0x2f, 0x16, 0x12, 0x7e, 0x30, 0x80, 0xed, 0x75, 0x2f, 0x12, 0x12, 0x7e, 0x30, 0x7a, 0xb1, 0x2f, - 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x09, 0xcd, 0x9d, 0x54, 0x12, 0x73, 0xc8, 0x7e, 0x34, 0x05, 0xcd, - 0x7d, 0x54, 0x2d, 0x43, 0x80, 0xa1, 0xe5, 0xe5, 0x54, 0x03, 0x78, 0x12, 0x75, 0x2f, 0x13, 0x12, - 0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xe9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe9, 0x80, 0xa7, 0x75, 0x2f, - 0x14, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xed, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xed, 0xa9, 0xd7, - 0xe4, 0xa9, 0x27, 0xe4, 0xfc, 0x80, 0x9d, 0x75, 0x2f, 0x15, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, - 0xf1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf1, 0x80, 0xe5, 0x75, 0x2f, 0x18, 0x12, 0x7e, 0x30, 0xca, + 0xb4, 0x12, 0x74, 0x5a, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x80, 0x29, 0x80, 0x58, 0x75, + 0x31, 0x16, 0x12, 0x7c, 0x15, 0x80, 0xed, 0x75, 0x31, 0x12, 0x12, 0x7c, 0x15, 0x7a, 0xb1, 0x31, + 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x09, 0xe3, 0x9d, 0x54, 0x12, 0x71, 0xb8, 0x7e, 0x34, 0x05, 0xe3, + 0x7d, 0x54, 0x2d, 0x43, 0x80, 0xa1, 0xe5, 0xe5, 0x54, 0x03, 0x78, 0x12, 0x75, 0x31, 0x13, 0x12, + 0x7c, 0x15, 0x7e, 0x0f, 0x29, 0xff, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xff, 0x80, 0xa7, 0x75, 0x31, + 0x14, 0x12, 0x7c, 0x15, 0x7e, 0x0f, 0x2a, 0x03, 0x0b, 0x0c, 0x7a, 0x0f, 0x2a, 0x03, 0xa9, 0xd7, + 0xe4, 0xa9, 0x27, 0xe4, 0xfc, 0x80, 0x9d, 0x75, 0x31, 0x15, 0x12, 0x7c, 0x15, 0x7e, 0x0f, 0x2a, + 0x07, 0x0b, 0x0c, 0x7a, 0x0f, 0x2a, 0x07, 0x80, 0xe5, 0x75, 0x31, 0x18, 0x12, 0x7c, 0x15, 0xca, 0x09, 0xca, 0x39, 0xca, 0x2b, 0xc2, 0xc2, 0xa9, 0x21, 0xf2, 0x52, 0xe5, 0xf5, 0x33, 0x82, 0xe7, - 0x40, 0x44, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x54, 0x00, 0x40, 0x9d, 0x35, 0x40, 0x43, 0x7a, 0x37, - 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc7, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x52, - 0x7a, 0x47, 0x01, 0xc7, 0x7d, 0x45, 0x12, 0x75, 0x26, 0xa9, 0x20, 0xf5, 0x22, 0x75, 0x2f, 0x19, - 0x12, 0x7e, 0x30, 0x7a, 0x91, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x81, 0xf7, 0x7a, 0x91, 0xf6, 0xe5, + 0x40, 0x44, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x54, 0x00, 0x40, 0x9d, 0x35, 0x40, 0x43, 0x7a, 0x37, + 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdd, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x52, + 0x7a, 0x47, 0x01, 0xdd, 0x7d, 0x45, 0x12, 0x73, 0x16, 0xa9, 0x20, 0xf5, 0x22, 0x75, 0x31, 0x19, + 0x12, 0x7c, 0x15, 0x7a, 0x91, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x81, 0xf7, 0x7a, 0x91, 0xf6, 0xe5, 0xf5, 0x33, 0x82, 0xe7, 0x50, 0xbc, 0xda, 0x2b, 0xda, 0x39, 0xda, 0x09, 0x22, 0x80, 0x41, 0x80, - 0x64, 0x2d, 0x53, 0x6d, 0x33, 0x70, 0xb7, 0x7e, 0x04, 0x01, 0xcd, 0x7a, 0x07, 0x01, 0xc9, 0x7a, - 0x07, 0x01, 0xc7, 0xa9, 0x32, 0xf2, 0xdf, 0x85, 0x30, 0x2f, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x00, - 0x80, 0xd4, 0xca, 0x59, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x54, 0x12, 0x75, 0x26, 0x7e, 0x34, 0x01, - 0xcd, 0x7d, 0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc7, 0x12, 0x75, 0x26, 0xda, 0x49, 0x80, 0x99, - 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x0f, 0x29, 0xd9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xd9, - 0x80, 0x9d, 0x7e, 0x0f, 0x29, 0xe1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe1, 0xa9, 0xd7, 0xf4, 0xa9, - 0x27, 0xf4, 0xfc, 0x80, 0x8a, 0x7e, 0x0f, 0x29, 0xdd, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xdd, 0x80, - 0xeb, 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x2f, 0x29, 0xf9, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, - 0xf9, 0x80, 0x34, 0x7e, 0x2f, 0x2a, 0x01, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x01, 0xa9, 0xd7, 0xf4, - 0xa9, 0x27, 0xf4, 0xfc, 0x80, 0x21, 0x7e, 0x2f, 0x29, 0xfd, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, 0xfd, - 0x80, 0xeb, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x2f, 0x28, 0x12, 0x7e, 0x30, 0xca, + 0x64, 0x2d, 0x53, 0x6d, 0x33, 0x70, 0xb7, 0x7e, 0x04, 0x01, 0xe3, 0x7a, 0x07, 0x01, 0xdf, 0x7a, + 0x07, 0x01, 0xdd, 0xa9, 0x32, 0xf2, 0xdf, 0x85, 0x30, 0x31, 0x12, 0x7c, 0x15, 0x75, 0xf6, 0x00, + 0x80, 0xd4, 0xca, 0x59, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x54, 0x12, 0x73, 0x16, 0x7e, 0x34, 0x01, + 0xe3, 0x7d, 0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdd, 0x12, 0x73, 0x16, 0xda, 0x49, 0x80, 0x99, + 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x0f, 0x29, 0xef, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xef, + 0x80, 0x9d, 0x7e, 0x0f, 0x29, 0xf7, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf7, 0xa9, 0xd7, 0xf4, 0xa9, + 0x27, 0xf4, 0xfc, 0x80, 0x8a, 0x7e, 0x0f, 0x29, 0xf3, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf3, 0x80, + 0xeb, 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x2f, 0x2a, 0x0f, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, + 0x0f, 0x80, 0x34, 0x7e, 0x2f, 0x2a, 0x17, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x17, 0xa9, 0xd7, 0xf4, + 0xa9, 0x27, 0xf4, 0xfc, 0x80, 0x21, 0x7e, 0x2f, 0x2a, 0x13, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x13, + 0x80, 0xeb, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x31, 0x28, 0x12, 0x7c, 0x15, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xc2, 0xc4, 0xa9, 0x21, 0xf2, 0xb6, 0xe5, 0xf5, 0x33, 0x72, 0xe7, - 0x40, 0xe0, 0x7e, 0x0d, 0x30, 0x7e, 0x1d, 0x34, 0x7e, 0x2d, 0x38, 0x7e, 0x3d, 0x3c, 0x7e, 0x85, - 0x40, 0x7d, 0x90, 0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, + 0x40, 0xe0, 0x7e, 0x0d, 0x46, 0x7e, 0x1d, 0x4a, 0x7e, 0x2d, 0x4e, 0x7e, 0x3d, 0x52, 0x7e, 0x85, + 0x56, 0x7d, 0x90, 0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, 0x97, 0x4d, 0x98, 0x68, 0x72, 0x7a, 0x11, 0xf3, 0x7a, 0x01, 0xf3, 0x7a, 0x31, 0xf3, 0x7a, 0x21, 0xf3, 0x7a, 0x51, 0xf3, 0x7a, 0x41, 0xf3, 0x7a, 0x71, 0xf3, 0x7a, 0x61, 0xf3, 0x7a, 0x91, 0xf3, - 0x7a, 0x81, 0xf3, 0x30, 0x73, 0x1a, 0x7a, 0xb1, 0xf3, 0x7a, 0xa1, 0xf3, 0x7a, 0xd1, 0xf3, 0x7a, + 0x7a, 0x81, 0xf3, 0x30, 0x7b, 0x1a, 0x7a, 0xb1, 0xf3, 0x7a, 0xa1, 0xf3, 0x7a, 0xd1, 0xf3, 0x7a, 0xc1, 0xf3, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, 0x7d, 0x78, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, - 0xa9, 0x30, 0xf5, 0x03, 0x02, 0x72, 0xe6, 0x75, 0x2f, 0x29, 0x12, 0x7e, 0x30, 0x20, 0x73, 0x0b, - 0x75, 0x2f, 0x0a, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x0a, 0x80, 0x09, 0x75, 0x2f, 0x12, 0x12, 0x7e, - 0x30, 0x75, 0xf6, 0x12, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x30, 0x7a, 0x0d, 0x34, 0x7a, 0x0d, - 0x38, 0x7a, 0x0d, 0x3c, 0x7a, 0x05, 0x40, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x1e, 0xb0, - 0x40, 0x0c, 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x75, 0x0b, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0xa1, + 0xa9, 0x30, 0xf5, 0x03, 0x02, 0x70, 0xd6, 0x75, 0x31, 0x29, 0x12, 0x7c, 0x15, 0x20, 0x7b, 0x0b, + 0x75, 0x31, 0x0a, 0x12, 0x7c, 0x15, 0x75, 0xf6, 0x0a, 0x80, 0x09, 0x75, 0x31, 0x12, 0x12, 0x7c, + 0x15, 0x75, 0xf6, 0x12, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x46, 0x7a, 0x0d, 0x4a, 0x7a, 0x0d, + 0x4e, 0x7a, 0x0d, 0x52, 0x7a, 0x05, 0x56, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x1e, 0xb0, + 0x40, 0x0c, 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x72, 0xfb, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0xa1, 0xe3, 0x7a, 0x39, 0xa0, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, @@ -937,7 +1044,7 @@ 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x22, 0x1e, 0xb0, 0x40, 0x0c, - 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x76, 0x69, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0x39, 0xa0, 0x7a, + 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x74, 0x59, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0x39, 0xa0, 0x7a, 0xa1, 0xf3, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, @@ -958,144 +1065,144 @@ 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, - 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x22, 0xc2, 0xaf, 0x7e, 0x37, 0x01, 0xc5, - 0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xc1, 0x7e, 0x54, 0x09, 0xcd, 0x9d, 0x50, 0xbd, 0x35, - 0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x4b, 0x99, 0x64, 0xda, 0x39, 0x7e, 0x07, 0x01, - 0xc5, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xc5, 0x2e, 0x37, 0x01, 0xc1, 0x7a, 0x37, 0x01, 0xc1, 0xbe, - 0x34, 0x09, 0xcc, 0x28, 0xc7, 0x7e, 0x34, 0x05, 0xcd, 0x7a, 0x37, 0x01, 0xc1, 0x80, 0xbd, 0xd2, - 0xaf, 0x22, 0x75, 0x2f, 0x53, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, 0x80, 0x11, 0x75, 0x2f, 0x51, - 0x12, 0x7e, 0x30, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, 0x7c, 0xb2, - 0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x6e, 0x8c, 0x7c, 0xb2, 0x54, 0x78, - 0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x4d, 0x7a, 0x25, - 0x4f, 0x7e, 0x64, 0x77, 0x47, 0x7a, 0x65, 0x4b, 0x89, 0x24, 0x02, 0x77, 0x55, 0x7e, 0x64, 0x76, - 0xbd, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, 0x19, 0xca, - 0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x4d, 0x7e, 0x64, - 0x77, 0x33, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x76, 0xb2, 0x7a, - 0x65, 0x4b, 0x22, 0x75, 0x2f, 0x52, 0x12, 0x7e, 0x30, 0x7e, 0x21, 0x4d, 0x7e, 0x09, 0x30, 0x0b, - 0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x2f, 0x54, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, - 0x7e, 0x25, 0x4f, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x77, 0xd1, 0x30, 0xe6, - 0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, 0x6a, 0x68, - 0x20, 0xe3, 0x04, 0x7e, 0x44, 0x77, 0xd9, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, 0x39, 0xda, - 0x09, 0x7e, 0x64, 0x76, 0xbd, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x4d, 0xf5, 0x4f, - 0x7e, 0x64, 0x77, 0x96, 0x80, 0x99, 0x7e, 0x15, 0x4d, 0xe5, 0x4f, 0x80, 0xc4, 0xc0, 0xd0, 0xc0, - 0xd1, 0xc0, 0xe0, 0xca, 0x19, 0xa9, 0x20, 0xdf, 0x12, 0xa9, 0x21, 0xdf, 0x1b, 0x75, 0x2f, 0x01, - 0x12, 0x7e, 0x30, 0x53, 0xdf, 0xf7, 0x12, 0x40, 0xdc, 0x80, 0x0d, 0x75, 0x2f, 0xfe, 0x12, 0x7e, - 0x30, 0x7e, 0x14, 0x00, 0x53, 0x02, 0x40, 0x51, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, - 0x32, 0x03, 0xa5, 0xcb, 0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x02, 0x78, 0x52, 0xca, 0x0b, 0xca, + 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x22, 0xc2, 0xaf, 0x7e, 0x37, 0x01, 0xdb, + 0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xd7, 0x7e, 0x54, 0x09, 0xe3, 0x9d, 0x50, 0xbd, 0x35, + 0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x61, 0x99, 0x64, 0xda, 0x39, 0x7e, 0x07, 0x01, + 0xdb, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xdb, 0x2e, 0x37, 0x01, 0xd7, 0x7a, 0x37, 0x01, 0xd7, 0xbe, + 0x34, 0x09, 0xe2, 0x28, 0xc7, 0x7e, 0x34, 0x05, 0xe3, 0x7a, 0x37, 0x01, 0xd7, 0x80, 0xbd, 0xd2, + 0xaf, 0x22, 0x75, 0x31, 0x53, 0x12, 0x7c, 0x15, 0x7e, 0x15, 0x63, 0x80, 0x11, 0x75, 0x31, 0x51, + 0x12, 0x7c, 0x15, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, 0x7c, 0xb2, + 0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x6c, 0x7c, 0x7c, 0xb2, 0x54, 0x78, + 0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x63, 0x7a, 0x25, + 0x65, 0x7e, 0x64, 0x75, 0x37, 0x7a, 0x65, 0x61, 0x89, 0x24, 0x02, 0x75, 0x45, 0x7e, 0x64, 0x74, + 0xad, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, 0x19, 0xca, + 0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x63, 0x7e, 0x64, + 0x75, 0x23, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x74, 0xa2, 0x7a, + 0x65, 0x61, 0x22, 0x75, 0x31, 0x52, 0x12, 0x7c, 0x15, 0x7e, 0x21, 0x63, 0x7e, 0x09, 0x30, 0x0b, + 0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x31, 0x54, 0x12, 0x7c, 0x15, 0x7e, 0x15, 0x63, + 0x7e, 0x25, 0x65, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x75, 0xc1, 0x30, 0xe6, + 0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, 0x67, 0x63, + 0x20, 0xe3, 0x04, 0x7e, 0x44, 0x75, 0xc9, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, 0x39, 0xda, + 0x09, 0x7e, 0x64, 0x74, 0xad, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x63, 0xf5, 0x65, + 0x7e, 0x64, 0x75, 0x86, 0x80, 0x99, 0x7e, 0x15, 0x63, 0xe5, 0x65, 0x80, 0xc4, 0xc0, 0xd0, 0xc0, + 0xd1, 0xc0, 0xe0, 0xca, 0x19, 0xa9, 0x20, 0xdf, 0x12, 0xa9, 0x21, 0xdf, 0x1b, 0x75, 0x31, 0x01, + 0x12, 0x7c, 0x15, 0x53, 0xdf, 0xf7, 0x12, 0x40, 0xdc, 0x80, 0x0d, 0x75, 0x31, 0xfe, 0x12, 0x7c, + 0x15, 0x7e, 0x14, 0x00, 0x53, 0x02, 0x40, 0x51, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, + 0x32, 0x03, 0xa5, 0xcb, 0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x02, 0x76, 0x42, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0xc0, - 0xf1, 0x7e, 0xb3, 0x2a, 0x1d, 0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, - 0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x78, - 0xcd, 0x80, 0x14, 0x30, 0xc1, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x78, 0xcd, 0x80, 0x09, 0x30, 0xc0, - 0x06, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, + 0xf1, 0x7e, 0xb3, 0x2a, 0x33, 0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, + 0x75, 0xf1, 0x00, 0x12, 0x76, 0x2c, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x76, + 0xbd, 0x80, 0x14, 0x30, 0xc1, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x76, 0xbd, 0x80, 0x09, 0x30, 0xc0, + 0x06, 0x75, 0xf1, 0x00, 0x12, 0x76, 0x2c, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0xc2, 0xc0, 0x7e, 0xb3, - 0x2a, 0x1d, 0xb4, 0x02, 0x07, 0x12, 0x78, 0x5e, 0x02, 0x78, 0x52, 0x22, 0xb4, 0x01, 0xfc, 0x02, - 0x78, 0x98, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2a, 0x1d, 0x7a, 0x03, 0x2a, 0x1e, 0x22, 0x7e, 0xb3, - 0x2a, 0x15, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, - 0x05, 0x0c, 0x75, 0x2f, 0x71, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xf5, 0x8f, 0x22, 0x75, - 0xf6, 0x00, 0x22, 0xbe, 0x57, 0x2a, 0x1b, 0x28, 0x04, 0x7e, 0x57, 0x2a, 0x1b, 0x7a, 0x0f, 0x2a, - 0x20, 0x7a, 0x57, 0x2a, 0x24, 0x02, 0x78, 0x98, 0x7e, 0xef, 0x2a, 0x20, 0x7e, 0xf7, 0x2a, 0x24, - 0x7e, 0x07, 0x2a, 0x24, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, - 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x2a, 0x20, 0x7a, - 0xf7, 0x2a, 0x24, 0x75, 0x2f, 0x06, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, - 0x2f, 0x03, 0x12, 0x7e, 0x30, 0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, - 0xd7, 0xf4, 0xa9, 0x27, 0xf4, 0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x79, 0x44, 0x7e, - 0xb3, 0x2a, 0x1e, 0xb4, 0x02, 0x0f, 0xa9, 0xd4, 0xe4, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x2a, 0x1e, - 0x7a, 0xb3, 0x2a, 0x1d, 0x22, 0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, 0x7c, 0x32, 0x7e, 0x13, 0x2a, - 0x1f, 0x2c, 0x21, 0x7a, 0x23, 0x2a, 0x1f, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x2a, 0x26, 0xe5, 0xe3, - 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, 0x75, 0x2f, 0x70, 0x12, 0x7e, - 0x30, 0x7e, 0xb3, 0x2a, 0x1f, 0x7e, 0xa3, 0x2a, 0x1c, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x79, 0xdb, - 0x22, 0x02, 0x7d, 0x44, 0xe5, 0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, 0xe2, 0x7e, 0x01, 0xe3, 0x7e, - 0x11, 0xe3, 0x7e, 0x31, 0xe3, 0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, 0x7e, 0x41, 0xe3, 0x7e, 0x71, - 0xe3, 0x7e, 0x61, 0xe3, 0x7a, 0x0f, 0x2a, 0x15, 0x7a, 0x1f, 0x2a, 0x19, 0x75, 0x2f, 0x04, 0x12, - 0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x21, - 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x31, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, 0x2f, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, - 0x7e, 0x30, 0xa9, 0xd4, 0xe4, 0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, 0x12, 0x79, 0xaf, 0x22, 0x6d, - 0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x2a, 0x24, 0x7a, 0x03, 0x2a, 0x1f, 0x7e, 0xb3, 0x2a, - 0x15, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x2a, 0x1e, 0x7a, 0x33, 0x2a, 0x1d, 0xbe, 0x07, 0x2a, 0x1b, - 0x68, 0x09, 0x22, 0x7a, 0x33, 0x2a, 0x1e, 0x7a, 0x23, 0x2a, 0x1d, 0x7e, 0xb3, 0x2a, 0x15, 0x54, - 0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, - 0x30, 0xe4, 0x03, 0x02, 0x7d, 0x44, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, - 0x90, 0x7a, 0x07, 0x75, 0x84, 0xff, 0x73, 0x02, 0x7b, 0x5b, 0x02, 0x7a, 0x4f, 0x02, 0x7b, 0xf8, - 0x02, 0x7c, 0x13, 0x02, 0x7a, 0xf4, 0x02, 0x7a, 0xb5, 0x02, 0x7c, 0x2c, 0x02, 0x7c, 0x2c, 0x02, - 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, - 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x35, 0x02, 0x7c, 0xe9, 0x02, 0x7c, 0x32, - 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x7e, - 0xb3, 0x2a, 0x16, 0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, 0x56, 0x7c, 0x0b, 0x7e, 0x13, - 0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x72, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, - 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x4e, 0x40, 0x35, 0x02, 0x78, 0x83, - 0xb4, 0x08, 0x10, 0x75, 0x2f, 0x74, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf1, 0xf5, 0xf3, 0x75, - 0xf6, 0x01, 0x22, 0xb4, 0x00, 0x1c, 0x75, 0x2f, 0x75, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf2, - 0x30, 0xe0, 0x05, 0x75, 0xf3, 0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, 0x75, 0xf3, 0x00, 0x75, 0xf6, - 0x02, 0x22, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x00, 0x35, 0x75, 0x2f, 0x76, 0x12, - 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, - 0x09, 0xe5, 0xe1, 0x30, 0xe7, 0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, 0xe1, 0x30, 0xe6, 0x04, 0x74, - 0x01, 0x80, 0x02, 0x74, 0x00, 0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, - 0x22, 0x02, 0x7d, 0x44, 0xc0, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x42, 0xf1, 0x7e, 0xb3, - 0x2a, 0x18, 0xb4, 0x00, 0x45, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x01, 0x24, 0x75, 0x2f, 0x77, 0x12, - 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x78, 0x05, 0x53, 0xe1, 0x3f, 0x80, 0x37, 0x7e, - 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, 0x53, 0xe1, 0xbf, 0x80, 0x26, - 0xb4, 0x03, 0x17, 0x75, 0x2f, 0x78, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, - 0x43, 0xe1, 0x80, 0x80, 0x11, 0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x75, - 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x22, 0xd0, 0xf1, 0x02, 0x78, 0x7f, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, - 0x09, 0x23, 0x75, 0x2f, 0x79, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xbe, 0xb3, 0x3f, 0xf1, - 0x68, 0x11, 0xca, 0xb8, 0xc0, 0xf1, 0x12, 0x43, 0x68, 0xd0, 0xf1, 0xda, 0xb8, 0x50, 0x76, 0x7a, - 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x2f, 0x7a, 0x12, 0x7e, 0x30, 0x80, 0x62, - 0xb4, 0x03, 0x19, 0x75, 0x2f, 0x7b, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x55, - 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, 0x75, - 0x2f, 0x7c, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, 0xf2, - 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, - 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x73, 0x12, 0x7e, - 0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x7a, - 0x40, 0x03, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0b, 0xf6, 0x75, - 0x2f, 0x7d, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0x7e, 0xa3, 0x2a, 0x1a, 0x4c, 0xab, 0x78, - 0xe4, 0x80, 0xdf, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0a, 0xdb, 0x75, 0x2f, 0x7e, 0x12, 0x7e, 0x30, - 0x7e, 0xb3, 0x2a, 0x18, 0x70, 0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0x02, 0x7d, 0x44, 0x02, - 0x7d, 0x44, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x04, 0x20, 0x75, 0x2f, 0xc3, 0x12, - 0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x18, 0x2a, 0x26, 0x7a, 0x1c, - 0x00, 0x00, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0x02, 0x7c, 0xe3, 0xb4, 0x06, 0x3a, 0x75, - 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, - 0xd7, 0x2a, 0x17, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0x75, - 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7e, - 0x75, 0xd0, 0x87, 0xd0, 0xa8, 0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, - 0x87, 0x12, 0x78, 0x7f, 0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, - 0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, 0x7e, 0x57, 0x2a, 0x17, 0x4d, - 0x55, 0x68, 0x05, 0xa9, 0xd2, 0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, 0x80, 0x16, 0xb4, 0x07, 0x16, - 0xc2, 0xaf, 0x7e, 0x07, 0x2a, 0x19, 0x7e, 0x17, 0x2a, 0x17, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, - 0xca, 0x28, 0x32, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x03, 0x15, - 0x75, 0x2f, 0xc2, 0x12, 0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x57, - 0x2a, 0x1b, 0x02, 0x78, 0x83, 0xb4, 0x05, 0x39, 0x75, 0x2f, 0xc0, 0x12, 0x7e, 0x30, 0xc0, 0xa8, - 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, - 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2a, 0x17, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0xd0, 0x87, - 0xd0, 0xa8, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x2a, 0x1b, 0x02, 0x78, - 0x83, 0x02, 0x7d, 0x44, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x43, 0xe1, 0xc0, 0x22, 0xc0, 0xa8, - 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x19, 0x7e, 0x08, 0x2a, 0x26, - 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x7e, 0x3c, 0xda, 0x59, 0xda, 0x0b, 0xd0, - 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, - 0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x2b, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, - 0x7f, 0x61, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0xbd, 0x74, - 0x78, 0x11, 0x75, 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x12, 0x7e, 0x75, 0x40, 0x06, 0xd0, 0x87, 0xd0, - 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, - 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0xc2, - 0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, 0x34, 0x7f, 0xcc, 0x7e, 0x1b, - 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, - 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, - 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, - 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, - 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, + 0x2a, 0x33, 0xb4, 0x02, 0x07, 0x12, 0x76, 0x4e, 0x02, 0x76, 0x42, 0x22, 0xb4, 0x01, 0xfc, 0x02, + 0x76, 0x88, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2a, 0x33, 0x7a, 0x03, 0x2a, 0x34, 0x22, 0x7e, 0xb3, + 0x2a, 0x2b, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, + 0x05, 0x0c, 0x75, 0x31, 0x71, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0xf5, 0x8f, 0x22, 0x75, + 0xf6, 0x00, 0x22, 0xbe, 0x57, 0x2a, 0x31, 0x28, 0x04, 0x7e, 0x57, 0x2a, 0x31, 0x7a, 0x0f, 0x2a, + 0x36, 0x7a, 0x57, 0x2a, 0x3a, 0x02, 0x76, 0x88, 0x7e, 0xef, 0x2a, 0x36, 0x7e, 0xf7, 0x2a, 0x3a, + 0x7e, 0x07, 0x2a, 0x3a, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, + 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x2a, 0x36, 0x7a, + 0xf7, 0x2a, 0x3a, 0x75, 0x31, 0x06, 0x12, 0x7c, 0x15, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, + 0x31, 0x03, 0x12, 0x7c, 0x15, 0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, + 0xd7, 0xf4, 0xa9, 0x27, 0xf4, 0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x77, 0x29, 0x7e, + 0xb3, 0x2a, 0x34, 0xb4, 0x02, 0x04, 0xa9, 0xd4, 0xe4, 0x22, 0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, + 0x7c, 0x32, 0x7e, 0x13, 0x2a, 0x35, 0x2c, 0x21, 0x7a, 0x23, 0x2a, 0x35, 0x7e, 0x00, 0x00, 0x2e, + 0x04, 0x2a, 0x3c, 0xe5, 0xe3, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, + 0x75, 0x31, 0x70, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x35, 0x7e, 0xa3, 0x2a, 0x32, 0xbc, 0xab, + 0x78, 0x03, 0x12, 0x77, 0xc0, 0x22, 0x02, 0x7b, 0x29, 0xe5, 0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, + 0xe2, 0x7e, 0x01, 0xe3, 0x7e, 0x11, 0xe3, 0x7e, 0x31, 0xe3, 0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, + 0x7e, 0x41, 0xe3, 0x7e, 0x71, 0xe3, 0x7e, 0x61, 0xe3, 0x7a, 0x0f, 0x2a, 0x2b, 0x7a, 0x1f, 0x2a, + 0x2f, 0x75, 0x31, 0x04, 0x12, 0x7c, 0x15, 0x7a, 0x01, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x11, 0x31, + 0x12, 0x7c, 0x15, 0x7a, 0x21, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x31, 0x31, 0x12, 0x7c, 0x15, 0x7a, + 0x41, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, + 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xa9, 0xd4, 0xe4, 0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, + 0x12, 0x77, 0x94, 0x22, 0x6d, 0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x2a, 0x3a, 0x7a, 0x03, + 0x2a, 0x35, 0x7e, 0xb3, 0x2a, 0x2b, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x2a, 0x34, 0x7a, 0x33, 0x2a, + 0x33, 0xbe, 0x07, 0x2a, 0x31, 0x68, 0x09, 0x22, 0x7a, 0x33, 0x2a, 0x34, 0x7a, 0x23, 0x2a, 0x33, + 0x7e, 0xb3, 0x2a, 0x2b, 0x54, 0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, + 0xd2, 0xe4, 0x30, 0xe5, 0x06, 0x30, 0xe4, 0x03, 0x02, 0x7b, 0x29, 0x54, 0x3e, 0xf5, 0xf0, 0x03, + 0x54, 0x1f, 0xc3, 0x25, 0xf0, 0x90, 0x77, 0xec, 0x75, 0x84, 0xff, 0x73, 0x02, 0x79, 0x40, 0x02, + 0x78, 0x34, 0x02, 0x79, 0xdd, 0x02, 0x79, 0xf8, 0x02, 0x78, 0xd9, 0x02, 0x78, 0x9a, 0x02, 0x7a, + 0x11, 0x02, 0x7a, 0x11, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, + 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x1a, 0x02, + 0x7a, 0xce, 0x02, 0x7a, 0x17, 0x02, 0x7a, 0x17, 0x02, 0x7a, 0x17, 0x02, 0x7a, 0x17, 0x02, 0x7a, + 0x17, 0x02, 0x7a, 0x17, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x2a, 0x2d, 0x60, + 0x56, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x2e, 0x7e, 0x17, 0x2a, 0x2f, 0x75, 0x31, 0x72, 0x12, 0x7c, + 0x15, 0x7a, 0x01, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x11, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x7b, 0x33, + 0x40, 0x35, 0x02, 0x76, 0x73, 0xb4, 0x08, 0x10, 0x75, 0x31, 0x74, 0x12, 0x7c, 0x15, 0x7e, 0xb3, + 0x3f, 0xf1, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0xb4, 0x00, 0x1c, 0x75, 0x31, 0x75, 0x12, 0x7c, + 0x15, 0x7e, 0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x05, 0x75, 0xf3, 0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, + 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x7b, 0x29, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x00, + 0x35, 0x75, 0x31, 0x76, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x30, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, + 0xb3, 0x2a, 0x30, 0x20, 0xe7, 0x09, 0xe5, 0xe1, 0x30, 0xe7, 0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, + 0xe1, 0x30, 0xe6, 0x04, 0x74, 0x01, 0x80, 0x02, 0x74, 0x00, 0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, + 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x7b, 0x29, 0xc0, 0xf1, 0x7e, 0xb3, 0x2a, 0x30, 0x54, + 0x0f, 0x42, 0xf1, 0x7e, 0xb3, 0x2a, 0x2e, 0xb4, 0x00, 0x45, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x01, + 0x24, 0x75, 0x31, 0x77, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x30, 0x54, 0x0f, 0x78, 0x05, 0x53, + 0xe1, 0x3f, 0x80, 0x37, 0x7e, 0xb3, 0x2a, 0x30, 0x20, 0xe7, 0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, + 0x53, 0xe1, 0xbf, 0x80, 0x26, 0xb4, 0x03, 0x17, 0x75, 0x31, 0x78, 0x12, 0x7c, 0x15, 0x7e, 0xb3, + 0x2a, 0x30, 0x20, 0xe7, 0x05, 0x43, 0xe1, 0x80, 0x80, 0x11, 0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, + 0xe1, 0xc0, 0xd0, 0xf1, 0x75, 0x31, 0x07, 0x12, 0x7c, 0x15, 0x22, 0xd0, 0xf1, 0x02, 0x76, 0x6f, + 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x09, 0x23, 0x75, 0x31, 0x79, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, + 0x2e, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x11, 0xca, 0xb8, 0xc0, 0xf1, 0x12, 0x43, 0xd4, 0xd0, 0xf1, + 0xda, 0xb8, 0x50, 0x76, 0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x31, 0x7a, + 0x12, 0x7c, 0x15, 0x80, 0x62, 0xb4, 0x03, 0x19, 0x75, 0x31, 0x7b, 0x12, 0x7c, 0x15, 0x7e, 0xb3, + 0x2a, 0x2e, 0xb4, 0x01, 0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, + 0x46, 0xb4, 0x01, 0x19, 0x75, 0x31, 0x7c, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0xb4, 0x01, + 0x39, 0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, + 0x7e, 0xb3, 0x2a, 0x2d, 0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x2e, 0x7e, 0x17, 0x2a, 0x2f, + 0x75, 0x31, 0x73, 0x12, 0x7c, 0x15, 0x7a, 0x01, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x11, 0x31, 0x12, + 0x7c, 0x15, 0x12, 0x7b, 0x5f, 0x40, 0x03, 0x02, 0x76, 0x6f, 0x02, 0x7b, 0x29, 0x7e, 0xb3, 0x2a, + 0x2c, 0xb4, 0x0b, 0xf6, 0x75, 0x31, 0x7d, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0x7e, 0xa3, + 0x2a, 0x30, 0x4c, 0xab, 0x78, 0xe4, 0x80, 0xdf, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x0a, 0xdb, 0x75, + 0x31, 0x7e, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0x70, 0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, + 0x22, 0x02, 0x7b, 0x29, 0x02, 0x7b, 0x29, 0x02, 0x7b, 0x29, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x04, + 0x20, 0x75, 0x31, 0xc3, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x2d, 0x7e, + 0x18, 0x2a, 0x3c, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, 0x2a, 0x31, 0x12, 0x7c, 0x21, 0x02, 0x7a, + 0xc8, 0xb4, 0x06, 0x3a, 0x75, 0x31, 0xc1, 0x12, 0x7c, 0x15, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, + 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x2a, 0x2d, 0x7e, 0x78, 0x2a, 0x3c, 0x7a, 0x7c, 0x00, 0x00, + 0x7e, 0x77, 0x2a, 0x31, 0x75, 0x31, 0xc1, 0x12, 0x7c, 0x15, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, + 0xa9, 0xd5, 0x87, 0x12, 0x7c, 0x5a, 0xd0, 0x87, 0xd0, 0xa8, 0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, + 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x76, 0x6f, 0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, + 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, + 0x7e, 0x57, 0x2a, 0x2d, 0x4d, 0x55, 0x68, 0x05, 0xa9, 0xd2, 0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, + 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x2a, 0x2f, 0x7e, 0x17, 0x2a, 0x2d, 0xc0, + 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x76, 0x6f, 0x02, 0x7b, 0x29, 0x7e, 0xb3, + 0x2a, 0x2c, 0xb4, 0x03, 0x15, 0x75, 0x31, 0xc2, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x00, 0x01, 0x7e, + 0x17, 0x2a, 0x2d, 0x7e, 0x57, 0x2a, 0x31, 0x02, 0x76, 0x73, 0xb4, 0x05, 0x39, 0x75, 0x31, 0xc0, + 0x12, 0x7c, 0x15, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x7e, 0x08, 0x2a, 0x3c, + 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2a, 0x2d, 0x7e, 0x47, 0x2a, 0x31, + 0x12, 0x7c, 0x21, 0xd0, 0x87, 0xd0, 0xa8, 0x7e, 0x08, 0x2a, 0x3c, 0x7a, 0x0c, 0x00, 0x00, 0x7e, + 0x57, 0x2a, 0x31, 0x02, 0x76, 0x73, 0x02, 0x7b, 0x29, 0x75, 0x31, 0x07, 0x12, 0x7c, 0x15, 0x43, + 0xe1, 0xc0, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7b, 0x9e, 0x40, + 0x19, 0x7e, 0x08, 0x2a, 0x3c, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x7c, 0x21, + 0xda, 0x59, 0xda, 0x0b, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, + 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7b, 0x9e, 0x40, 0x2b, 0x7e, 0x58, 0x00, + 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, 0x2a, 0x3c, 0x7a, 0x7c, 0x00, 0x00, 0x7e, + 0x77, 0x2a, 0x31, 0xbd, 0x74, 0x78, 0x11, 0x75, 0x31, 0xc1, 0x12, 0x7c, 0x15, 0x12, 0x7c, 0x5a, + 0x40, 0x06, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, + 0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, + 0x87, 0x7e, 0x34, 0x7f, 0xc2, 0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, + 0x34, 0x7f, 0xcc, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, + 0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, + 0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, + 0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, + 0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, + 0xff, 0xc3, 0x22, 0xd3, 0x22, -// Segment #15, Start Address 00ff7fc6, Length 4 +// Segment #16, Start Address 00ff7fc6, Length 4 0xff,0x00,0xc6,0x7f,0x04,0x00, - 0x01, 0x0c, 0x03, 0x00, + 0x01, 0x10, 0x04, 0x00, -// Segment #16, Start Address 00ff7e30, Length 315 -0xff,0x00,0x30,0x7e,0x3b,0x01, - 0xca, 0x08, 0x7e, 0x01, 0x2f, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, +// Segment #17, Start Address 00ff7c15, Length 330 +0xff,0x00,0x15,0x7c,0x4a,0x01, + 0xca, 0x08, 0x7e, 0x01, 0x31, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, 0x0b, 0xc0, 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 0xfc, 0x7c, 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 0x44, 0x00, 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 0xfa, 0x7f, 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, - 0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x7e, 0x9f, + 0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x7c, 0x84, 0xda, 0x79, 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x43, 0x90, 0x30, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, @@ -1104,16 +1211,17 @@ 0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2c, 0x6d, 0x00, 0x7c, 0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, 0x16, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x03, 0x63, 0x90, 0x30, 0x4d, 0x77, 0x78, 0x93, 0xc2, - 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, - 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x04, 0x00, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, - 0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, 0xfe, 0x0b, 0x1a, 0x00, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, - 0x51, 0x23, 0x7e, 0x18, 0x7f, 0x15, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, - 0x08, 0xa5, 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, + 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x42, 0x08, 0x06, 0x04, 0x02, 0x04, 0x00, + 0x02, 0x01, 0x04, 0x01, 0x02, 0x82, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x04, 0x02, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x02, 0x02, 0x08, 0x02, 0x04, 0x20, 0x04, 0x7e, 0x18, 0x7f, 0xbd, 0x7a, + 0x1c, 0x00, 0xfe, 0x0b, 0x1a, 0x00, 0x5e, 0x10, 0x1f, 0xbe, 0x10, 0x1a, 0x38, 0x1a, 0x0a, 0x51, + 0x23, 0x7e, 0x18, 0x7c, 0xfa, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, + 0xa5, 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, }; static struct edge_firmware_version_info IMAGE_VERSION_NAME = { - 1, 12, 3 }; // Major, Minor, Build + 1, 16, 4 }; // Major, Minor, Build #undef IMAGE_VERSION_NAME diff -Nru a/drivers/usb/serial/io_fw_down3.h b/drivers/usb/serial/io_fw_down3.h --- a/drivers/usb/serial/io_fw_down3.h 2004-10-18 14:56:50 -07:00 +++ b/drivers/usb/serial/io_fw_down3.h 2004-10-18 14:56:50 -07:00 @@ -1,11 +1,11 @@ //************************************************************** //* Edgeport Binary Image (for TI based products) -//* Generated by TIBin2C v1.00 +//* Generated by TIBin2C v2.00 (watchport) //* Copyright (C) 2001 Inside Out Networks, All rights reserved. //************************************************************** -static int IMAGE_SIZE = 12166; +static int IMAGE_SIZE = 12749; struct EDGE_FIRMWARE_VERSION_INFO { @@ -16,7 +16,7 @@ static struct EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = { - 4, 1, 0 // Major, Minor, Build + 4, 10, 0 // Major, Minor, Build }; @@ -27,20 +27,20 @@ // WORD Length; // BYTE CheckSum; // }; -0x83, 0x2f, -0x33, +0xca, 0x31, +0xa8, -0x02, 0x24, 0x84, 0x02, 0x1f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x45, -0x8c, 0x85, 0x46, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, -0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x44, -0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x44, 0x75, -0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x92, 0xe5, 0x81, -0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x1a, 0xe6, 0xf0, 0x08, 0xa3, 0xd9, -0xfa, 0x74, 0x08, 0x25, 0x44, 0xf8, 0x05, 0x44, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x44, -0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x44, 0x00, 0x80, 0xef, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0x86, -0x81, 0xe5, 0x44, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, -0x78, 0x92, 0xe5, 0x81, 0x04, 0xc3, 0x98, 0xf9, 0xe0, 0xf6, 0x08, 0xa3, 0xd9, 0xfa, 0xd0, 0x07, +0x02, 0x26, 0xfe, 0x02, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x3f, +0x8c, 0x85, 0x40, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, +0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x3e, +0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x3e, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x3e, 0x75, +0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x8c, 0xe5, 0x81, +0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x94, 0xe6, 0xf0, 0x08, 0xa3, 0xd9, +0xfa, 0x74, 0x08, 0x25, 0x3e, 0xf8, 0x05, 0x3e, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x3e, +0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x3e, 0x00, 0x80, 0xef, 0xe5, 0x3e, 0x24, 0x10, 0xf8, 0x86, +0x81, 0xe5, 0x3e, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, +0x78, 0x8c, 0xe5, 0x81, 0x04, 0xc3, 0x98, 0xf9, 0xe0, 0xf6, 0x08, 0xa3, 0xd9, 0xfa, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x30, 0x01, 0x4d, 0x30, 0xb4, 0x48, 0x10, 0x00, 0x45, 0x90, 0xff, 0x08, 0xe0, 0x54, 0x20, 0xf8, 0x90, 0xff, 0x48, 0xe0, 0x54, 0x20, 0xf9, @@ -50,747 +50,783 @@ 0xa3, 0xe0, 0xcb, 0xf0, 0x6b, 0x60, 0x02, 0x7e, 0x04, 0x22, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0xff, 0x93, 0x74, 0x01, 0xf0, 0xe5, 0x81, 0x94, 0xfd, 0x40, 0x03, -0x02, 0x11, 0x1a, 0x85, 0x47, 0x8d, 0x85, 0x48, 0x8b, 0x74, 0xae, 0xf5, 0x82, 0x74, 0xfa, 0xf5, +0x02, 0x11, 0x94, 0x85, 0x41, 0x8d, 0x85, 0x42, 0x8b, 0x74, 0xaf, 0xf5, 0x82, 0x74, 0xfa, 0xf5, 0x83, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x4a, 0xe0, 0x30, 0xe7, 0x2c, 0x90, 0xff, 0x4e, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, -0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, -0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, +0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x27, +0x8d, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, 0xa3, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x52, 0xe0, 0x30, 0xe7, 0x2c, -0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, -0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, -0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, -0x20, 0x02, 0x03, 0x30, 0x01, 0x7b, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x14, -0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, 0x7e, -0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x22, 0x12, 0x00, 0xc9, 0xee, 0x64, -0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, 0x02, -0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x22, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, 0x22, -0x7c, 0x0a, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, -0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, 0x80, -0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, 0xd2, -0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, 0x60, -0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x43, 0x60, -0x13, 0x14, 0xf5, 0x43, 0x70, 0x0e, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x10, 0x95, -0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, -0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x90, -0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb5, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, -0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, 0x01, -0x7f, 0x08, 0x8e, 0x34, 0x8f, 0x35, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 0xff, -0xea, 0x90, 0xfa, 0xb9, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x18, 0x49, 0x78, 0x24, 0x7c, 0x00, 0x7d, -0x00, 0x12, 0x19, 0x6c, 0x7e, 0x00, 0x7f, 0x05, 0x12, 0x13, 0x8f, 0xe4, 0xf5, 0x53, 0xe5, 0x53, -0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x18, 0x2a, 0xe4, 0x12, 0x13, 0xfb, 0x05, 0x53, 0x04, 0x12, -0x18, 0x1b, 0x80, 0xea, 0x12, 0x18, 0x49, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, 0xc0, -0x70, 0x03, 0x02, 0x08, 0xb8, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, -0xfe, 0x54, 0x0f, 0xf5, 0x53, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, 0x90, -0xff, 0x01, 0xe0, 0x12, 0x15, 0x0f, 0x03, 0x55, 0x00, 0x04, 0x28, 0x01, 0x05, 0x2f, 0x03, 0x05, -0xf6, 0x05, 0x06, 0x38, 0x06, 0x07, 0x9a, 0x08, 0x07, 0xe2, 0x09, 0x08, 0x3e, 0x0a, 0x08, 0x7e, -0x0b, 0x00, 0x00, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, -0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x02, 0x45, 0x34, -0x60, 0x03, 0x02, 0x0e, 0xac, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, 0x02, -0x60, 0x03, 0x02, 0x0e, 0xac, 0xee, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0x2a, 0x74, 0x01, -0x12, 0x13, 0xfb, 0x78, 0x6d, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x18, 0x2a, 0x74, 0x02, 0x12, 0x13, -0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb5, 0xe0, 0x60, -0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, -0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x60, -0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x53, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, -0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, 0x80, 0x19, 0x15, 0x53, 0x30, -0x0a, 0x0b, 0x12, 0x18, 0xbd, 0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x80, 0x09, 0x12, 0x18, 0xcb, -0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0x60, 0x05, 0x74, 0x01, -0x12, 0x13, 0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, -0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, -0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, -0xac, 0x78, 0x6d, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, -0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb5, 0xe0, -0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, -0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, 0xb9, 0xe0, 0x70, -0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x07, -0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, 0x54, -0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x53, 0x24, 0xfe, 0x60, 0x1b, -0x04, 0x70, 0x2e, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, -0x80, 0x1f, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, 0x80, 0x16, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, -0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2a, 0xce, 0x80, 0x07, 0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2a, -0xce, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, -0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, -0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, -0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, -0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, -0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x78, 0x6d, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, -0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, -0x30, 0xe0, 0x07, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0a, 0xe5, -0x53, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, -0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xff, -0x12, 0x2f, 0x3b, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, -0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x19, 0x7a, 0x02, 0x19, 0x3e, -0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, -0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x44, 0x08, -0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, -0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, -0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x03, 0x02, 0x0e, 0xac, -0x90, 0xfa, 0xba, 0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x2c, 0x01, 0x80, 0x03, -0x53, 0x2c, 0xfe, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x35, 0x45, 0x34, 0x70, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, -0xac, 0x90, 0xfa, 0xb9, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, -0x75, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xed, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, -0x49, 0x12, 0x19, 0x73, 0x7d, 0x03, 0x12, 0x0e, 0xf3, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, -0xb0, 0x90, 0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, -0x04, 0xae, 0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x18, 0x49, 0x90, 0xf9, 0x65, 0xe0, 0x30, -0xe4, 0x0d, 0x12, 0x19, 0x73, 0x7d, 0x14, 0x12, 0x0e, 0xf3, 0x60, 0x10, 0x02, 0x0e, 0xac, 0x12, -0x19, 0x73, 0x7d, 0x04, 0x12, 0x0f, 0x47, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, 0xb0, 0x90, -0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, 0x04, 0xae, -0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x19, 0x73, 0x7d, 0x05, 0x12, 0x0f, 0x47, 0x60, 0x03, -0x02, 0x0e, 0xac, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x12, 0x18, 0x90, 0x7d, 0x01, 0x12, 0x23, -0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xba, 0xe0, 0x90, -0xfa, 0xb1, 0xf0, 0xe4, 0xf5, 0x52, 0x90, 0xfa, 0xb1, 0xe0, 0xff, 0xe5, 0x52, 0xc3, 0x9f, 0x50, -0x24, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0xff, 0xfd, 0x90, 0xfa, 0xb3, 0xe4, 0x8d, 0xf0, 0x12, -0x14, 0x2f, 0x90, 0xfa, 0xb2, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0e, -0xac, 0x05, 0x52, 0x80, 0xd1, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0x24, 0xfe, 0xff, 0x90, 0xfa, -0xb2, 0xf0, 0xfd, 0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0x7a, 0xf9, 0x79, 0x6e, 0x7b, -0x01, 0x8b, 0x2d, 0x8a, 0x2e, 0x89, 0x2f, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x18, -0x90, 0x12, 0x23, 0xee, 0x8f, 0x52, 0x05, 0x52, 0x05, 0x52, 0x12, 0x18, 0x2a, 0xe5, 0x52, 0x12, -0x13, 0xfb, 0x12, 0x18, 0x2a, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x14, 0x0d, 0xaf, 0x52, 0x7e, -0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x50, 0x02, 0x80, 0x04, 0xae, 0x34, 0xaf, 0x35, -0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, -0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, -0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, -0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, -0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x00, 0x75, 0x2f, 0x29, 0x02, -0x0f, 0x2f, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, -0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, 0x90, 0xfa, 0xba, -0xe0, 0x94, 0x01, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, -0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0e, -0xac, 0x90, 0xfa, 0xba, 0xe0, 0xf5, 0x29, 0xe5, 0x29, 0x70, 0x08, 0x43, 0x2c, 0x01, 0x53, 0x2c, -0xfd, 0x80, 0x06, 0x53, 0x2c, 0xfe, 0x43, 0x2c, 0x02, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, -0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, -0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, -0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, -0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x7f, 0x01, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, -0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, -0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, -0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, -0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xff, 0x01, 0x12, 0x19, 0x8a, 0xef, 0x12, -0x13, 0xfb, 0x90, 0xfa, 0xb5, 0x12, 0x19, 0x8a, 0x90, 0x00, 0x01, 0xef, 0x12, 0x14, 0x0d, 0x90, -0x00, 0x02, 0xe4, 0x12, 0x14, 0x0d, 0x74, 0x03, 0x12, 0x18, 0x1b, 0x90, 0xfa, 0xb9, 0xe0, 0xff, -0xa3, 0xe0, 0x85, 0x2f, 0x82, 0x85, 0x2e, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, -0xe0, 0x12, 0x15, 0x0f, 0x09, 0x3d, 0x02, 0x09, 0x5f, 0x04, 0x09, 0x81, 0x05, 0x09, 0xad, 0x06, -0x09, 0xcb, 0x07, 0x09, 0xe9, 0x08, 0x0a, 0x07, 0x09, 0x0a, 0x25, 0x0b, 0x0a, 0xda, 0x80, 0x0c, -0xfa, 0x81, 0x0d, 0x1c, 0x82, 0x0b, 0x21, 0x83, 0x0b, 0x6a, 0x84, 0x0b, 0x89, 0x85, 0x0b, 0xc5, -0x86, 0x0c, 0x07, 0x87, 0x0c, 0x95, 0x88, 0x0c, 0xd0, 0x89, 0x0a, 0x43, 0x92, 0x0a, 0x43, 0x93, -0x0d, 0xcf, 0xc0, 0x0e, 0x00, 0xc1, 0x0e, 0x11, 0xc2, 0x00, 0x00, 0x0e, 0x9b, 0xe5, 0x2c, 0x20, -0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, -0xfd, 0x7c, 0x00, 0x7f, 0x07, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, 0xc0, 0xe5, -0x2c, 0x20, 0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, -0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, -0xc0, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x19, 0x99, 0x50, 0x06, 0xe5, 0x35, -0x45, 0x34, 0x70, 0x05, 0x7f, 0x02, 0x02, 0x2e, 0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x24, 0xfe, 0x24, -0xfd, 0x50, 0x02, 0x80, 0x03, 0x02, 0x2f, 0x28, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, -0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, -0x00, 0x7f, 0x08, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, -0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, -0x09, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, -0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, -0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, -0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x10, 0x9c, -0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, -0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x10, 0x9c, 0x7f, 0x07, -0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x56, 0x12, 0x18, 0xd9, 0x70, 0x4a, 0x90, 0xff, 0x02, -0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, 0x80, 0x12, 0xe5, 0x52, 0xb4, -0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x52, 0x12, -0x17, 0x8b, 0x12, 0x19, 0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x05, -0x12, 0x2f, 0x76, 0x80, 0x06, 0x85, 0x2a, 0x30, 0x85, 0x2b, 0x31, 0x75, 0x2d, 0x01, 0x75, 0x2e, -0xf9, 0x75, 0x2f, 0x71, 0x02, 0x29, 0x2d, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x12, 0x18, -0xd9, 0x60, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x19, 0x99, 0x40, 0x05, 0x7f, 0x03, 0x02, -0x2e, 0xa5, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, -0x80, 0x12, 0xe5, 0x52, 0xb4, 0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, -0xf0, 0x04, 0xf5, 0x52, 0x12, 0x17, 0x8b, 0x02, 0x2f, 0x28, 0x12, 0x19, 0xa3, 0x12, 0x27, 0x19, -0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x78, -0x6e, 0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, -0xe4, 0x12, 0x14, 0x0d, 0x90, 0xfa, 0xb6, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x82, 0xe6, 0xfc, -0x08, 0xe6, 0x8c, 0x83, 0x12, 0x18, 0xa3, 0xef, 0xf0, 0x12, 0x2f, 0x80, 0xe4, 0xff, 0x02, 0x2e, -0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, -0x70, 0x06, 0xa3, 0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, -0xba, 0xe0, 0x42, 0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, 0x70, -0x06, 0xa3, 0xe0, 0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xba, -0xe0, 0x42, 0xb0, 0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x49, 0x90, 0xfa, 0xb5, -0xe0, 0xb4, 0x01, 0x0a, 0x12, 0x18, 0x2a, 0xe5, 0x90, 0x12, 0x13, 0xfb, 0x80, 0x08, 0x12, 0x18, -0x2a, 0xe5, 0xb0, 0x12, 0x13, 0xfb, 0x02, 0x0f, 0x2f, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x30, -0x12, 0x18, 0x53, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, -0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x19, 0xad, 0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb6, -0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x04, 0x12, 0x19, 0xb4, 0xf0, -0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x36, 0x12, 0x18, 0x53, 0x60, -0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, -0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, -0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, -0xdf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x46, 0x04, 0x60, 0x03, 0x02, -0x0c, 0x90, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x04, 0xf0, 0x90, -0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x6a, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x61, 0x90, -0xff, 0xa4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x53, 0x30, 0x95, 0x09, -0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x47, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, -0x80, 0x3e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x04, 0xf0, 0x90, -0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x2a, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x21, 0x90, -0xff, 0xb4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x13, 0x30, 0x93, 0x09, -0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfd, 0xf0, -0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, -0xe0, 0x60, 0x09, 0x90, 0xff, 0xa2, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa2, 0xe0, -0x54, 0xbf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb2, 0xe0, 0x44, -0x40, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, -0x12, 0x18, 0x49, 0x12, 0x18, 0x5b, 0x60, 0x0f, 0x04, 0x70, 0x16, 0x90, 0xff, 0xa4, 0xe0, 0x12, -0x18, 0x2a, 0x12, 0x13, 0xfb, 0x80, 0x0a, 0x90, 0xff, 0xb4, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, -0xfb, 0x75, 0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x12, -0x19, 0x46, 0x7f, 0x03, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0xff, -0x7e, 0x00, 0x12, 0x2d, 0xee, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, 0xe4, 0xf5, 0x54, 0xf5, -0x55, 0x90, 0xfa, 0xbb, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, 0xb3, 0xf0, 0xa3, 0x74, -0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, 0xb8, 0xf0, 0xd3, 0x94, -0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, -0xd6, 0xe5, 0x23, 0x45, 0x22, 0x70, 0x73, 0x12, 0x18, 0x62, 0x90, 0xfa, 0xbb, 0x12, 0x19, 0x65, -0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, 0xfa, 0xb8, 0x74, 0x40, -0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, 0xd6, 0xe5, 0x23, -0x45, 0x22, 0x70, 0x46, 0x12, 0x18, 0x62, 0x80, 0xd1, 0x75, 0x52, 0x02, 0x90, 0xfa, 0xbb, 0xe4, -0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb3, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, 0xf0, 0x7b, 0x00, 0x7a, -0x00, 0x79, 0x52, 0x90, 0xfa, 0xbc, 0xe0, 0xf5, 0x50, 0x7d, 0x0f, 0x7c, 0x00, 0x12, 0x26, 0x25, -0x75, 0x22, 0x00, 0x8f, 0x23, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, 0x40, 0xf5, 0x41, -0x7d, 0x01, 0x12, 0x23, 0xee, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0xaf, 0x23, 0x02, 0x2e, 0xa5, 0x90, -0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x62, -0xf0, 0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0f, -0x90, 0xf9, 0x61, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x2e, 0xa5, -0x12, 0x19, 0xa3, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x2e, -0xa5, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, -0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, -0x12, 0x19, 0xad, 0x12, 0x0e, 0xfe, 0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, -0x44, 0x10, 0x12, 0x0e, 0xfe, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, -0x19, 0xad, 0xf0, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, -0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, -0x92, 0x80, 0x23, 0x12, 0x19, 0xb4, 0x12, 0x0f, 0x1e, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, -0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x1e, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, -0xd2, 0x92, 0x12, 0x19, 0xb4, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x07, -0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x2f, 0x76, 0x22, -0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, -0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0xab, -0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x22, 0xaa, 0x54, 0xa9, 0x55, 0x7b, 0xff, 0x90, 0xfa, 0xb3, 0xe0, -0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xb8, 0xe0, 0xf5, 0x50, 0x12, 0x26, 0x25, 0x75, 0x22, 0x00, -0x8f, 0x23, 0x22, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, 0xef, 0x22, 0xf0, 0x7f, -0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x12, -0x23, 0xee, 0x8f, 0x52, 0x7e, 0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x22, 0xf0, 0x7f, -0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x75, -0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x02, 0x2f, 0x3b, -0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, -0xef, 0x22, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb0, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, -0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, -0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, 0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, -0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, 0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, -0x04, 0xc0, 0x05, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, -0x0f, 0xfe, 0x7f, 0x00, 0x7e, 0x00, 0xe5, 0x49, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x19, 0xe0, 0x54, -0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, -0x49, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, -0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, -0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, -0x12, 0x10, 0x95, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, -0x4a, 0x75, 0xa8, 0x88, 0xec, 0x70, 0x02, 0x7c, 0x3f, 0x8c, 0x43, 0x22, 0xe5, 0x44, 0x24, 0x08, -0xf8, 0x76, 0x00, 0x12, 0x10, 0xec, 0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, -0xc0, 0x06, 0x7c, 0xff, 0x12, 0x0f, 0xfe, 0xe5, 0x49, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x19, 0xe0, -0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x49, 0x80, 0x07, -0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, 0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, -0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, -0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, -0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, 0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, -0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, 0xee, 0x12, 0x10, 0x95, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, -0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, 0x43, 0x00, 0x85, 0x4a, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, -0xc0, 0x83, 0xc3, 0xe5, 0x49, 0x24, 0xe8, 0x50, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf4, 0xef, 0x60, -0x31, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x0f, -0xfe, 0xd0, 0x04, 0x43, 0x07, 0x80, 0xe5, 0x49, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x19, 0xf5, 0x82, -0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, 0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x49, 0x12, -0x10, 0x95, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x02, 0x11, 0x1a, 0xc0, 0x04, 0x7c, 0x20, -0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, 0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, -0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, 0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, -0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, 0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, -0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, 0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, -0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, 0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, -0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0xd2, 0xb0, 0xd2, -0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, -0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, -0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x48, 0x8e, -0x47, 0x22, 0xc3, 0xef, 0x94, 0xbc, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, -0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x46, 0x8e, 0x45, 0x22, 0xef, -0x70, 0x01, 0x22, 0xc0, 0x00, 0xe5, 0x44, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x44, 0x24, 0x08, -0xf8, 0xc6, 0x54, 0x7f, 0xf6, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x10, 0xec, 0x80, +0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x25, +0xb4, 0x02, 0x22, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x27, +0x8d, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, +0x80, 0x03, 0x02, 0x02, 0x62, 0x74, 0x15, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x20, 0x04, +0xf1, 0x20, 0x02, 0x03, 0x30, 0x01, 0xeb, 0x74, 0x18, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, +0x14, 0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, +0x7e, 0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x33, 0x12, 0x00, 0xc9, 0xee, +0x64, 0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, +0x02, 0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x33, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, +0x33, 0x7c, 0x0a, 0x74, 0x18, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, +0xa3, 0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, +0x80, 0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, +0xd2, 0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, +0x60, 0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x3d, +0x60, 0x13, 0x14, 0xf5, 0x3d, 0x70, 0x0e, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11, +0x0f, 0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, +0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, +0x90, 0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, +0xec, 0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, +0x01, 0x7f, 0x08, 0x8e, 0x3b, 0x8f, 0x3c, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, +0xff, 0xea, 0x90, 0xfa, 0xba, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x1c, 0x30, 0xe4, 0xf5, 0x4d, 0xe5, +0x4d, 0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x1c, 0x11, 0xe4, 0x12, 0x1a, 0x38, 0x05, 0x4d, 0x04, +0x12, 0x1c, 0x02, 0x80, 0xea, 0x12, 0x1c, 0x30, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, +0xc0, 0x70, 0x03, 0x02, 0x08, 0xc5, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, +0xe0, 0xfe, 0x54, 0x0f, 0xf5, 0x4d, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, +0x90, 0xff, 0x01, 0xe0, 0x12, 0x1b, 0x4c, 0x03, 0x56, 0x00, 0x04, 0x29, 0x01, 0x05, 0x3c, 0x03, +0x06, 0x03, 0x05, 0x06, 0x45, 0x06, 0x07, 0xa7, 0x08, 0x07, 0xef, 0x09, 0x08, 0x4b, 0x0a, 0x08, +0x8b, 0x0b, 0x00, 0x00, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x64, 0x02, 0x45, +0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, +0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xee, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0x11, 0x74, +0x01, 0x12, 0x1a, 0x38, 0x78, 0x67, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x1c, 0x11, 0x74, 0x02, 0x12, +0x1a, 0x38, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb6, 0xe0, +0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0f, +0x26, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb6, 0xe0, 0xff, +0x60, 0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0xb2, 0x40, 0x03, 0x02, 0x0f, +0x26, 0xe5, 0x4d, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x1c, 0x0e, 0x12, 0x1a, +0x38, 0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x1c, 0x0e, 0x12, 0x1a, 0x38, 0x80, 0x19, 0x15, 0x4d, +0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0x12, 0x1c, 0x0c, 0x12, 0x1a, 0x38, 0x80, 0x09, 0x12, 0x1c, +0xb3, 0x12, 0x1c, 0x0c, 0x12, 0x1a, 0x38, 0x12, 0x1c, 0x11, 0x12, 0x19, 0xf2, 0x60, 0x05, 0x74, +0x01, 0x12, 0x1a, 0x38, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, +0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x14, 0x60, 0x2d, +0x14, 0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x04, +0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, +0x0f, 0x26, 0x78, 0x67, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, +0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb6, +0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb6, 0xe0, 0xd3, +0x94, 0x01, 0x40, 0x03, 0x02, 0x0f, 0x26, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xfa, 0xba, 0xe0, +0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0xb2, 0x40, 0x03, 0x02, 0x0f, +0x26, 0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, +0x07, 0xe5, 0x4d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x4d, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, +0x54, 0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x4d, 0x24, 0xfe, 0x60, +0x20, 0x24, 0xfb, 0x60, 0x34, 0x24, 0x06, 0x70, 0x35, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, +0xfd, 0x7f, 0x03, 0x12, 0x2d, 0xa8, 0x80, 0x26, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2d, 0xa8, 0x80, +0x1d, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2d, 0xa8, 0x80, 0x0e, +0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2d, 0xa8, 0x80, 0x05, 0x7f, 0x87, 0x12, 0x31, 0x32, 0x15, 0x4d, +0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, 0x09, 0x12, 0x1c, +0xb3, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, +0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, +0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, +0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, +0x60, 0x03, 0x02, 0x0f, 0x26, 0x78, 0x67, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, 0x02, 0x31, 0xb1, +0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, 0x07, +0xe5, 0x4d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x0a, 0xe5, 0x4d, 0xd3, 0x94, +0x01, 0x40, 0x03, 0x02, 0x0f, 0x26, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xfa, 0xba, 0xe0, 0x70, +0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x12, 0x31, 0x82, +0x40, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, +0xe5, 0x4d, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x1d, 0x64, 0x02, 0x1d, 0x2f, 0xe5, 0x35, 0x20, +0xe1, 0x03, 0x02, 0x0f, 0x26, 0x15, 0x4d, 0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0xf5, 0x83, 0xe0, +0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x1c, 0xb3, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0xe4, 0xff, +0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, +0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, +0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xbb, +0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x35, 0x01, 0x80, 0x03, 0x53, 0x35, 0xfe, +0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, +0x3b, 0x70, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xba, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, 0x75, 0x24, 0x02, +0x60, 0x03, 0x02, 0x0f, 0x26, 0xed, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0x30, 0x12, 0x1d, +0x5d, 0x7d, 0x03, 0x12, 0x0f, 0x6d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0x2a, 0x90, 0xfa, +0xb3, 0xe0, 0xfd, 0xa3, 0x12, 0x1c, 0x7b, 0x12, 0x0f, 0x89, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, +0xaf, 0x3c, 0x02, 0x0f, 0xba, 0x12, 0x1c, 0x30, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe4, 0x0d, 0x12, +0x1d, 0x5d, 0x7d, 0x14, 0x12, 0x0f, 0x6d, 0x60, 0x10, 0x02, 0x0f, 0x26, 0x12, 0x1d, 0x5d, 0x7d, +0x04, 0x12, 0x0f, 0xc1, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0x2a, 0x90, 0xfa, 0xb3, 0xe0, +0xfd, 0xa3, 0x12, 0x1c, 0x7b, 0x12, 0x0f, 0x89, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c, +0x02, 0x0f, 0xba, 0x12, 0x1d, 0x5d, 0x7d, 0x05, 0x12, 0x0f, 0xc1, 0x60, 0x03, 0x02, 0x0f, 0x26, +0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x12, 0x1c, 0x78, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, +0xb4, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xbb, 0xe0, 0x90, 0xfa, 0xb2, 0xf0, +0xe4, 0xf5, 0x4c, 0x90, 0xfa, 0xb2, 0xe0, 0xff, 0xe5, 0x4c, 0xc3, 0x9f, 0x50, 0x24, 0x12, 0x1c, +0x72, 0x12, 0x0f, 0xcc, 0xff, 0xfd, 0x90, 0xfa, 0xb4, 0xe4, 0x8d, 0xf0, 0x12, 0x1a, 0x6c, 0x90, +0xfa, 0xb3, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0f, 0x26, 0x05, 0x4c, +0x80, 0xd1, 0x12, 0x1c, 0x72, 0x12, 0x0f, 0xcc, 0x24, 0xfe, 0xff, 0x90, 0xfa, 0xb3, 0xf0, 0xfd, +0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x1a, 0x6c, 0x7a, 0xf9, 0x79, 0x6f, 0x7b, 0x01, 0x8b, 0x36, +0x8a, 0x37, 0x89, 0x38, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x1c, 0x78, 0x12, 0x25, +0xd7, 0x8f, 0x4c, 0x05, 0x4c, 0x05, 0x4c, 0x12, 0x1c, 0x11, 0xe5, 0x4c, 0x12, 0x1a, 0x38, 0x12, +0x1c, 0x11, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x1a, 0x4a, 0xaf, 0x4c, 0x7e, 0x00, 0xc3, 0xef, +0x95, 0x3c, 0xee, 0x95, 0x3b, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c, 0x8e, 0x39, 0x8f, +0x3a, 0x02, 0x2c, 0x07, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, +0x3c, 0x64, 0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, +0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, +0x12, 0x1c, 0xc9, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, +0x02, 0x0f, 0x26, 0x75, 0x36, 0x00, 0x75, 0x37, 0x00, 0x75, 0x38, 0x32, 0x02, 0x0f, 0xa9, 0xe5, +0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, +0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xd3, 0x90, 0xfa, 0xbb, 0xe0, 0x94, 0x01, +0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x60, 0x03, +0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xbb, 0xe0, 0xf5, 0x32, 0xe5, 0x32, 0x70, 0x08, 0x43, 0x35, 0x01, 0x53, 0x35, 0xfd, 0x80, 0x06, +0x53, 0x35, 0xfe, 0x43, 0x35, 0x02, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe7, 0x03, +0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x64, 0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, +0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, +0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x7f, 0x01, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, +0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xd3, 0x90, 0xfa, 0xbb, +0xe0, 0x94, 0x00, 0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, +0xc9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, +0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xff, 0x01, 0x12, 0x1d, 0x74, 0xef, 0x12, 0x1a, 0x38, 0x90, +0xfa, 0xb6, 0x12, 0x1d, 0x74, 0x90, 0x00, 0x01, 0xef, 0x12, 0x1a, 0x4a, 0x90, 0x00, 0x02, 0xe4, +0x12, 0x1a, 0x4a, 0x74, 0x03, 0x12, 0x1c, 0x02, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0xa3, 0xe0, 0x85, +0x38, 0x82, 0x85, 0x37, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, 0xe0, 0x12, 0x1b, +0x4c, 0x09, 0x4a, 0x02, 0x09, 0x6c, 0x04, 0x09, 0x8e, 0x05, 0x09, 0xba, 0x06, 0x09, 0xd8, 0x07, +0x09, 0xf6, 0x08, 0x0a, 0x14, 0x09, 0x0a, 0x32, 0x0b, 0x0a, 0xe7, 0x80, 0x0d, 0x6f, 0x81, 0x0d, +0xa0, 0x82, 0x0b, 0x2e, 0x83, 0x0b, 0x77, 0x84, 0x0b, 0x96, 0x85, 0x0b, 0xdb, 0x86, 0x0c, 0x26, +0x87, 0x0c, 0xb7, 0x88, 0x0d, 0x42, 0x89, 0x0a, 0x50, 0x92, 0x0a, 0x50, 0x93, 0x0e, 0x53, 0xc0, +0x0e, 0x7f, 0xc1, 0x0e, 0x90, 0xc2, 0x00, 0x00, 0x0f, 0x15, 0xe5, 0x35, 0x20, 0xe7, 0x05, 0x7f, +0x05, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, +0x7f, 0x07, 0x02, 0x11, 0x16, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0x18, 0xe5, 0x35, 0x20, 0xe7, +0x05, 0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, +0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x11, 0x16, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0x18, 0xe5, 0x35, +0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1d, 0x92, 0x50, 0x06, 0xe5, 0x3c, 0x45, 0x3b, 0x70, +0x05, 0x7f, 0x02, 0x02, 0x30, 0xec, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfe, 0x24, 0xfd, 0x50, 0x02, +0x80, 0x03, 0x02, 0x31, 0x6f, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, +0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x08, +0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, +0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x09, 0x02, 0x11, +0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, +0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, 0x11, 0x16, 0x7f, +0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, +0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, +0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, +0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, +0xe5, 0x35, 0x30, 0xe7, 0x56, 0x12, 0x1c, 0xc9, 0x70, 0x4a, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x4c, +0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12, 0xe5, 0x4c, 0xb4, 0x83, 0x05, 0x75, +0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x4c, 0x12, 0x1b, 0x72, 0x12, +0x1d, 0x8b, 0x12, 0x25, 0x39, 0x12, 0x1c, 0xd9, 0x12, 0x1a, 0x0b, 0x60, 0x05, 0x12, 0x31, 0xbd, +0x80, 0x06, 0x85, 0x33, 0x39, 0x85, 0x34, 0x3a, 0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75, 0x38, +0x72, 0x02, 0x2c, 0x07, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f, 0x18, 0x12, 0x1c, 0xc9, 0x60, 0x05, +0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x1d, 0x92, 0x40, 0x05, 0x7f, 0x03, 0x02, 0x30, 0xec, 0x90, +0xff, 0x02, 0xe0, 0xf5, 0x4c, 0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12, 0xe5, +0x4c, 0xb4, 0x83, 0x05, 0x75, 0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04, 0xf5, +0x4c, 0x12, 0x1b, 0x72, 0x02, 0x31, 0x6f, 0x12, 0x1d, 0x9c, 0x12, 0x2a, 0x06, 0x12, 0x1c, 0x83, +0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x78, 0x68, 0x12, 0x1b, +0x28, 0x90, 0x00, 0x02, 0x12, 0x1a, 0x0b, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, 0xe4, 0x12, 0x1a, +0x4a, 0x90, 0xfa, 0xb7, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x7c, 0xe6, 0xfc, 0x08, 0xe6, 0x8c, +0x83, 0x12, 0x1c, 0x8b, 0xef, 0xf0, 0x12, 0x31, 0xc7, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x90, 0xfa, +0xb6, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06, 0xa3, +0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, 0xbb, 0xe0, 0x42, +0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06, 0xa3, 0xe0, +0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xbb, 0xe0, 0x42, 0xb0, +0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0x30, 0x90, 0xfa, 0xb6, 0xe0, 0xb4, 0x01, +0x0a, 0x12, 0x1c, 0x11, 0xe5, 0x90, 0x12, 0x1a, 0x38, 0x80, 0x08, 0x12, 0x1c, 0x11, 0xe5, 0xb0, +0x12, 0x1a, 0x38, 0x02, 0x0f, 0xa9, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x24, 0x12, 0x12, 0x1c, 0x41, +0x20, 0xe1, 0x33, 0x12, 0x1c, 0xd0, 0xef, 0x24, 0xfc, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa, +0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x1d, 0xa6, +0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0, +0x80, 0x04, 0x12, 0x1d, 0xad, 0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x90, 0xfa, 0xb6, 0xe0, 0xff, +0x24, 0x12, 0x12, 0x1c, 0x41, 0x20, 0xe1, 0x39, 0x12, 0x1c, 0xd0, 0xef, 0x24, 0xfc, 0x60, 0x1b, +0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, +0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb7, 0xe0, 0x60, +0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xdf, +0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x12, 0x1c, 0xc1, 0x60, 0x4d, 0x04, 0x60, +0x03, 0x02, 0x0c, 0xb2, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x0f, 0x90, 0xff, 0xa4, 0x12, 0x1c, 0x3a, +0x30, 0xe1, 0x6f, 0x12, 0x1d, 0x7c, 0x02, 0x0c, 0xb2, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfb, 0x12, +0x1c, 0x3d, 0xfe, 0x30, 0xe1, 0x5c, 0x30, 0xe2, 0x11, 0x30, 0xb4, 0x05, 0x12, 0x1d, 0x7c, 0x80, +0x51, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x48, 0x30, 0x95, 0x05, 0x12, 0x1d, 0x7c, +0x80, 0x40, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x37, 0x90, 0xfa, 0xb7, 0xe0, 0x60, +0x12, 0x90, 0xff, 0xb4, 0x12, 0x1c, 0x3a, 0x30, 0xe1, 0x28, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, +0xf0, 0x80, 0x1f, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfb, 0x12, 0x1c, 0x3d, 0x30, 0xe1, 0x13, 0x30, +0x93, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, +0xfd, 0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfc, +0x60, 0x40, 0x04, 0x70, 0x78, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xa2, 0xe0, 0x44, +0x40, 0xf0, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x65, 0xd2, 0x03, 0xa3, 0xe0, 0x54, 0xdf, 0xf0, 0x90, +0xff, 0xa3, 0xef, 0x54, 0x7f, 0xf0, 0x80, 0x55, 0x30, 0x03, 0x0e, 0x90, 0xff, 0xa3, 0xe0, 0x44, +0x80, 0xf0, 0xc2, 0x03, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, +0x80, 0x3b, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xb2, 0xe0, 0x44, 0x40, 0xf0, 0xa3, +0xe0, 0xff, 0x30, 0xe7, 0x28, 0xd2, 0x04, 0xa3, 0xe0, 0x54, 0xdf, 0xf0, 0x90, 0xff, 0xb3, 0xef, +0x54, 0x7f, 0xf0, 0x80, 0x18, 0x30, 0x04, 0x0e, 0x90, 0xff, 0xb3, 0xe0, 0x44, 0x80, 0xf0, 0xc2, +0x04, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02, +0x30, 0xec, 0x12, 0x1c, 0x30, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfc, 0x60, 0x0f, 0x04, 0x70, 0x16, +0x90, 0xff, 0xa6, 0xe0, 0x12, 0x1c, 0x11, 0x12, 0x1a, 0x38, 0x80, 0x0a, 0x90, 0xff, 0xb6, 0xe0, +0x12, 0x1c, 0x11, 0x12, 0x1a, 0x38, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02, 0x2c, 0x07, 0xe4, +0xff, 0x12, 0x30, 0xec, 0x12, 0x1d, 0x37, 0x7f, 0x03, 0x12, 0x12, 0x19, 0x90, 0xf9, 0x15, 0xe0, +0x30, 0xe4, 0x08, 0x90, 0xff, 0x93, 0x74, 0x80, 0xf0, 0x80, 0x10, 0x90, 0xff, 0xfc, 0xe0, 0x54, +0x7f, 0xf0, 0x7f, 0xff, 0x7e, 0x00, 0x12, 0x30, 0x16, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, +0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x90, 0xfa, 0xbc, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, +0xb4, 0xf0, 0xa3, 0x74, 0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, +0xb9, 0xf0, 0xd3, 0x94, 0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbd, 0xe0, 0x90, 0xfa, +0xb9, 0xf0, 0x12, 0x0f, 0x50, 0xe5, 0x31, 0x45, 0x30, 0x70, 0x73, 0x12, 0x1c, 0x4a, 0x90, 0xfa, +0xbc, 0x12, 0x1d, 0x56, 0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, +0xfa, 0xb9, 0x74, 0x40, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbd, 0xe0, 0x90, 0xfa, 0xb9, 0xf0, 0x12, +0x0f, 0x50, 0xe5, 0x31, 0x45, 0x30, 0x70, 0x46, 0x12, 0x1c, 0x4a, 0x80, 0xd1, 0x75, 0x4c, 0x02, +0x90, 0xfa, 0xbc, 0xe4, 0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb4, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, +0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0x90, 0xfa, 0xbd, 0xe0, 0xf5, 0x4a, 0x7d, 0x0f, 0x7c, +0x00, 0x12, 0x28, 0x9f, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0xe4, +0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xaf, 0x31, +0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x64, 0xf0, +0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb7, 0xe0, 0x54, 0x0f, 0x90, +0xf9, 0x63, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, +0x1d, 0x9c, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x30, 0xec, +0x12, 0x1c, 0xd0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, +0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, 0x12, 0x1d, 0xa6, 0x12, 0x0f, 0x78, +0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x78, 0xff, +0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, 0x1d, 0xa6, 0xf0, 0x90, 0xfa, 0xb7, +0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, +0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, 0x92, 0x80, 0x23, 0x12, 0x1d, 0xad, +0x12, 0x0f, 0x98, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, +0x0f, 0x98, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, 0xd2, 0x92, 0x12, 0x1d, 0xad, 0xf0, +0xe4, 0xff, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x07, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f, +0x18, 0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x31, 0xbd, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, +0x90, 0xfa, 0xb4, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, +0xfa, 0xb4, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x22, +0xaa, 0x4e, 0xa9, 0x4f, 0x7b, 0xff, 0x90, 0xfa, 0xb4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, +0xb9, 0xe0, 0xf5, 0x4a, 0x12, 0x28, 0x9f, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x22, 0x12, 0x22, 0xa0, +0x7e, 0x00, 0x8e, 0x30, 0x8f, 0x31, 0xef, 0x22, 0xf0, 0x7f, 0x01, 0x12, 0x12, 0x19, 0x90, 0xff, +0xa6, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x54, 0xa0, 0x22, 0x12, 0x25, 0xd7, 0x8f, 0x4c, 0x7e, 0x00, +0xc3, 0xef, 0x95, 0x3c, 0xee, 0x95, 0x3b, 0x22, 0xf0, 0x7f, 0x01, 0x12, 0x12, 0x19, 0x90, 0xff, +0xb6, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x54, 0xa0, 0x22, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02, +0x2c, 0x07, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x02, 0x31, 0x82, 0x8e, 0x39, 0x8f, 0x3a, 0x02, 0x2c, +0x07, 0x12, 0x22, 0xa0, 0x7e, 0x00, 0x8e, 0x30, 0x8f, 0x31, 0xef, 0x22, 0x7d, 0x01, 0x12, 0x25, +0xd7, 0x90, 0xfa, 0xb1, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, 0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, +0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, 0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, +0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, 0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, +0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 0xc0, 0x05, 0xe5, 0x3e, 0x24, +0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, 0x10, 0x78, 0x7f, 0x00, 0x7e, 0x00, +0xe5, 0x43, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, +0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, 0x43, 0x80, 0x07, 0xa3, 0xa3, 0xa3, +0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, +0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, +0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x12, 0x11, 0x0f, 0xd0, 0x05, 0xd0, +0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, 0x44, 0x75, 0xa8, 0x88, 0xec, 0x70, +0x02, 0x7c, 0x3f, 0x8c, 0x3d, 0x22, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11, 0x66, +0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 0xc0, 0x06, 0x7c, 0xff, 0x12, 0x10, +0x78, 0xe5, 0x43, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, +0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x43, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, +0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, +0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, +0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, 0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, +0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, 0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, +0xee, 0x12, 0x11, 0x0f, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, +0x3d, 0x00, 0x85, 0x44, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc3, 0xe5, 0x43, 0x24, +0xe8, 0x50, 0x05, 0x12, 0x11, 0x66, 0x80, 0xf4, 0xef, 0x60, 0x31, 0x90, 0x30, 0x54, 0xe4, 0x93, +0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x10, 0x78, 0xd0, 0x04, 0x43, 0x07, 0x80, +0xe5, 0x43, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x1b, 0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, +0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x43, 0x12, 0x11, 0x0f, 0xd0, 0x83, 0xd0, 0x82, +0xd0, 0xf0, 0x22, 0x02, 0x11, 0x94, 0xc0, 0x04, 0x7c, 0x20, 0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, +0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, 0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, +0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, 0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, +0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, 0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, +0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, +0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, +0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0xd2, 0xb0, 0xd2, 0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, +0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, +0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, 0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, +0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x42, 0x8e, 0x41, 0x22, 0xc3, 0xef, 0x94, 0xbc, +0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, +0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x40, 0x8e, 0x3f, 0x22, 0xef, 0x70, 0x01, 0x22, 0xc0, 0x00, 0xc0, +0xa8, 0xc2, 0xaf, 0xe5, 0x3e, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0xc6, +0x54, 0x7f, 0xf6, 0xd0, 0xa8, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x11, 0x66, 0x80, 0xf4, 0xc0, 0x00, 0x7f, 0x01, 0xef, 0x24, 0x08, 0xf8, 0xe6, 0x60, 0x09, 0x0f, 0xbf, 0x08, 0xf5, -0x12, 0x10, 0xec, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, -0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0xa0, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, +0x12, 0x11, 0x66, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, +0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0x9a, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0xc0, 0x82, 0xc0, 0x83, 0xa3, 0xa3, 0xe4, 0x78, -0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x0e, 0xf5, 0x82, -0xe5, 0xf0, 0x34, 0x2e, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, +0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x36, 0xf5, 0x82, +0xe5, 0xf0, 0x34, 0x30, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, 0x82, 0xec, 0xf0, 0xa3, 0xee, 0xf0, 0xed, 0x24, 0x08, 0xf8, 0xef, 0x44, 0x80, 0xf6, 0xd0, 0x04, -0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x44, 0x00, 0x75, 0x49, +0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x3e, 0x00, 0x75, 0x43, 0x00, 0x7a, 0x08, 0x79, 0x18, 0x78, 0x08, 0x76, 0x00, 0x77, 0x00, 0x08, 0x09, 0xda, 0xf8, 0x90, -0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, +0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x30, 0x54, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, 0x04, 0xf0, 0x78, 0x08, 0x74, 0x80, 0x44, 0x7f, 0xf6, 0x74, 0x01, 0x44, 0x10, 0xf5, 0x89, 0x75, -0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x91, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, -0xe5, 0x49, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x19, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, +0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x8b, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, +0xe5, 0x43, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, 0x08, 0xe0, 0x54, 0x7f, 0xfa, 0x7b, 0x00, 0xe6, 0x54, 0x7f, 0xb5, 0x02, 0x02, 0x7b, 0xff, 0x08, -0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x11, 0xc1, 0xad, 0x07, 0xaf, 0x02, -0x12, 0x11, 0xd8, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x10, 0xec, 0x80, 0xc1, 0xe7, -0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, -0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, -0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, -0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08, 0xdf, -0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c, 0x80, -0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10, 0x80, -0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33, 0x89, -0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, -0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0x0d, -0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0, 0xed, -0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, -0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde, 0xe8, -0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, -0xf0, 0xef, 0x60, 0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, -0x50, 0xb9, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, -0x23, 0x90, 0x13, 0x0f, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, -0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, -0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, -0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, -0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, -0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xf8, 0xbb, 0x01, -0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0x22, 0x50, 0x06, -0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0x22, 0xc5, -0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, -0x83, 0xe0, 0x38, 0xf0, 0x22, 0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, -0x82, 0x70, 0x02, 0x15, 0x83, 0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22, 0xbb, 0x01, 0x10, 0xe5, 0x82, -0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0, 0xa3, 0xe0, 0x22, 0x50, 0x09, -0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe, 0x0a, 0xe9, 0x25, 0x82, 0xf8, -0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83, 0xe9, 0x93, 0xf5, 0xf0, 0xa3, -0xe9, 0x93, 0x22, 0xbb, 0x01, 0x0a, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, -0x50, 0x06, 0xf7, 0x09, 0xa7, 0xf0, 0x19, 0x22, 0xbb, 0xfe, 0x06, 0xf3, 0xe5, 0xf0, 0x09, 0xf3, -0x19, 0x22, 0xf8, 0xbb, 0x01, 0x11, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, -0xe8, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x08, 0xa6, -0xf0, 0x22, 0xbb, 0xfe, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0xe5, 0xf0, 0x08, 0xf2, 0x22, 0xa4, -0x25, 0x82, 0xf5, 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xfa, -0x08, 0xe6, 0xf9, 0x22, 0xeb, 0xf6, 0x08, 0xea, 0xf6, 0x08, 0xe9, 0xf6, 0x22, 0xe0, 0xfb, 0xa3, -0xe0, 0xfa, 0xa3, 0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, -0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, -0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, -0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, -0xff, 0xf9, 0x74, 0x02, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, 0x00, -0x7a, 0x00, 0x79, 0x37, 0x75, 0x40, 0x00, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0xe5, 0x37, -0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x37, 0x64, 0x07, 0x60, 0x0b, 0xe5, 0x37, 0x64, 0x06, -0x60, 0x05, 0xe5, 0x37, 0xb4, 0x14, 0x1b, 0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0xe5, -0x37, 0xb4, 0x07, 0x08, 0x90, 0xf9, 0x65, 0x74, 0x02, 0xf0, 0x80, 0x06, 0x90, 0xf9, 0x65, 0x74, -0x01, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x17, 0x71, 0x90, 0xff, -0xf5, 0xe5, 0x37, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, -0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x12, 0x17, 0x71, 0xe5, 0x37, 0x30, 0xe7, -0x02, 0xd2, 0x02, 0xe4, 0xf5, 0x2c, 0xf5, 0x2a, 0xf5, 0x2b, 0xf5, 0x29, 0x12, 0x19, 0x92, 0x12, -0x18, 0x49, 0x12, 0x19, 0x6c, 0x90, 0xf9, 0x66, 0x12, 0x15, 0x06, 0x90, 0xf9, 0x6b, 0x12, 0x15, -0x06, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81, 0x74, -0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0x12, -0x18, 0xbf, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x37, 0x12, 0x18, 0xcd, 0xf5, 0x83, 0xe4, 0xf0, 0x05, -0x37, 0xe5, 0x37, 0xb4, 0x07, 0xe7, 0x78, 0x80, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x2f, 0x06, -0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x2f, 0x13, 0xe4, 0x93, 0xff, 0x08, -0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x18, 0xaf, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0, 0x08, -0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0, 0x9f, -0x78, 0x81, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x18, 0x41, 0xce, 0xc3, 0x13, 0xce, 0x13, -0xd8, 0xf9, 0xff, 0xed, 0x12, 0x19, 0x07, 0xef, 0xf0, 0xed, 0x12, 0x19, 0x2d, 0xe4, 0xf5, 0x37, -0xe5, 0x37, 0x90, 0x2f, 0x00, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xe5, 0x37, 0x25, 0xe0, 0x24, -0x07, 0xf5, 0x82, 0xe4, 0x34, 0x2f, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7, 0x53, -0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xaf, 0x12, 0x19, 0x15, 0x24, 0x47, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12, 0x19, -0x07, 0xef, 0xf0, 0x12, 0x18, 0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, -0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x19, 0x2d, 0xe9, -0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, -0x02, 0x17, 0x46, 0x78, 0x7e, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xf9, 0x12, 0x19, 0x15, 0x24, -0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, -0x12, 0x19, 0x1a, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x18, -0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, 0x24, 0x05, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5, 0x37, 0x64, 0x04, 0x60, 0x03, 0x02, 0x16, -0x70, 0x90, 0x2f, 0x05, 0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0x12, 0x18, 0xf7, 0xe4, 0xf0, 0x90, -0x2f, 0x04, 0x93, 0xff, 0xf6, 0x12, 0x18, 0xad, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05, 0xf0, -0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, -0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, -0x2f, 0xe5, 0x52, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, -0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0x74, 0x11, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, -0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x06, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, -0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0xab, 0x2d, -0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, -0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, -0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x04, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, -0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x05, 0xe0, -0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, -0x35, 0x2e, 0xf5, 0x2e, 0x22, 0xf5, 0x83, 0xe0, 0x54, 0x08, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, -0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3, 0x78, 0x81, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, -0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22, 0x75, 0x2d, 0x01, 0x75, 0x2e, 0xf9, 0x75, -0x2f, 0x6e, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xfa, 0xb5, 0xe0, 0x24, -0xfc, 0x22, 0x90, 0xfa, 0xb8, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xbc, 0xe0, 0x9f, 0xf0, -0x90, 0xfa, 0xbb, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xb3, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, -0x25, 0x55, 0xf5, 0x55, 0xee, 0x35, 0x54, 0xf5, 0x54, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb0, -0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x22, 0x78, 0x82, 0xe6, 0xfe, 0x08, -0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, -0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x53, 0x75, -0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0xe5, 0x53, 0x75, 0xf0, 0x08, -0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22, -0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x75, 0x2a, 0x00, 0x8f, 0x2b, 0x90, 0xf9, 0x6b, -0x12, 0x14, 0xfd, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, -0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08, 0xa4, -0x22, 0x74, 0xae, 0x25, 0x36, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, -0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90, 0xff, -0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff, 0xfc, -0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x6d, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x65, -0xf0, 0x22, 0x12, 0x14, 0xdf, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xf9, -0x79, 0x6e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, -0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x66, 0x02, -0x14, 0xfd, 0x75, 0x30, 0x01, 0x75, 0x31, 0x09, 0x22, 0xd3, 0xe5, 0x35, 0x94, 0x08, 0xe5, 0x34, -0x94, 0x01, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x90, 0xfa, 0xb6, 0xf0, 0x22, 0x90, 0xff, 0xa4, -0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xef, 0x22, 0x8f, 0x38, 0x12, 0x27, 0x19, -0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xe0, 0xfd, -0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x12, 0x20, 0x7c, 0x24, -0x07, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x12, 0x20, 0xbe, 0x24, 0x09, 0x12, 0x20, 0x25, 0xef, 0xf0, -0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x20, 0x2f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, -0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, 0x82, 0xe0, 0x33, 0xd0, -0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xe0, 0xfc, 0xa3, 0xe0, -0xfd, 0xec, 0xff, 0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xef, 0xf0, 0xed, -0x12, 0x20, 0xbe, 0x24, 0x07, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, -0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x20, 0x69, 0xa3, 0xe0, -0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, -0x2f, 0x4d, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x12, 0x20, 0xae, 0x24, 0x06, 0x12, 0x20, 0x25, -0xe0, 0x60, 0x03, 0x43, 0x07, 0x04, 0x53, 0x07, 0xfc, 0x78, 0x86, 0x12, 0x20, 0x96, 0x24, 0x04, -0x12, 0x20, 0x25, 0xe0, 0x42, 0x07, 0x43, 0x07, 0x80, 0x12, 0x20, 0xa6, 0xf5, 0x82, 0x8a, 0x83, -0xa3, 0xa3, 0xef, 0xf0, 0x12, 0x20, 0xbe, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x8d, 0x82, -0x8c, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, -0x03, 0x43, 0x07, 0x20, 0xec, 0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, -0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, 0x4c, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x42, -0x12, 0x20, 0xae, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, 0x60, 0x31, 0x14, 0x60, 0x29, 0x14, -0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, 0x38, 0xb4, 0x03, 0x0d, 0x30, 0x95, -0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, 0x43, 0x07, -0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53, 0x07, 0xfd, -0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x20, 0x94, 0x24, 0x04, 0x12, 0x20, 0x25, 0xef, 0xf0, 0x8d, -0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, -0x4a, 0xee, 0x30, 0xe1, 0x43, 0x08, 0x12, 0x20, 0xb0, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, -0x60, 0x2c, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, -0x38, 0xb4, 0x03, 0x0d, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x1f, 0x43, 0x07, 0x80, 0x80, -0x1a, 0x30, 0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x12, 0x43, 0x07, 0x80, 0x80, 0x0d, 0x53, 0x07, -0x7f, 0x80, 0x08, 0x43, 0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x86, 0x12, 0x20, 0x65, -0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, -0xec, 0x30, 0xe3, 0x05, 0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, -0x43, 0x07, 0x10, 0x80, 0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, -0x03, 0x53, 0x07, 0xf7, 0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, -0xed, 0x30, 0xe6, 0x05, 0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, -0x43, 0x07, 0x02, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x78, 0x84, 0x12, 0x20, 0x65, 0xa3, 0xef, 0xf0, -0x12, 0x2f, 0x80, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x8e, 0xef, 0xf6, 0x12, 0x27, 0x19, -0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0xfd, 0x12, 0x20, 0x53, 0x90, -0x00, 0x0a, 0x12, 0x20, 0x78, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x14, -0x0d, 0x12, 0x20, 0x70, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x59, 0x12, 0x20, -0x7c, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xf5, 0x5a, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, -0xf5, 0x5b, 0xe5, 0x59, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x8e, 0xf6, 0xd3, 0x94, 0x00, -0x40, 0x06, 0xe5, 0x5a, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x8e, 0xe6, 0x12, 0x20, 0x52, 0x90, 0x00, -0x0c, 0xef, 0x12, 0x14, 0x0d, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, -0xff, 0x53, 0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x59, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, -0x5a, 0x20, 0xe5, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, 0x20, 0xe7, 0x03, 0x43, -0x07, 0x02, 0xe5, 0x59, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x59, 0x30, 0xe2, 0x03, 0x43, -0x07, 0x20, 0xe5, 0x59, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x59, 0x30, 0xe1, 0x03, -0x43, 0x07, 0x80, 0xe5, 0x59, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x59, 0x30, 0xe6, 0x03, -0x43, 0x06, 0x08, 0xe5, 0x5a, 0x20, 0xe4, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, -0x20, 0xe7, 0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, -0x8f, 0xf0, 0x12, 0x14, 0xb2, 0xe5, 0x5b, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, -0x12, 0x20, 0x52, 0x90, 0x00, 0x08, 0xef, 0x12, 0x14, 0x0d, 0x80, 0x0a, 0x12, 0x20, 0x53, 0x90, -0x00, 0x08, 0xe4, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x03, 0x12, 0x20, 0x52, 0x90, 0x00, 0x07, -0xef, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x14, -0x0d, 0x90, 0x00, 0x07, 0x12, 0x13, 0xce, 0x70, 0x13, 0x12, 0x20, 0x53, 0xe9, 0x24, 0x09, 0xf9, -0xe4, 0x3a, 0xfa, 0x12, 0x13, 0xb5, 0xff, 0xc3, 0x13, 0x12, 0x13, 0xfb, 0x12, 0x20, 0x94, 0x24, -0x08, 0x12, 0x20, 0x25, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x20, -0x25, 0xe0, 0xfd, 0xee, 0xed, 0x12, 0x20, 0x52, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x14, -0xb2, 0x12, 0x2f, 0x80, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, 0x90, 0xfa, -0xe2, 0xe0, 0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, -0xfa, 0xd6, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xff, 0x7e, 0x00, -0x90, 0xfa, 0xd2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, -0x12, 0x14, 0x5b, 0xff, 0x90, 0xfa, 0xd4, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, -0x01, 0x8e, 0x56, 0x8f, 0x57, 0x74, 0x0a, 0x25, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, -0x90, 0xfa, 0xd7, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd5, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, -0xff, 0x90, 0xfa, 0xd9, 0xf0, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0x90, 0xfa, 0xd2, 0xe0, 0x94, -0x00, 0x50, 0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, 0x60, 0x03, 0xe0, 0xff, -0x22, 0x12, 0x2a, 0x80, 0x90, 0xfa, 0xd2, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, -0xfa, 0xd6, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, -0xfa, 0xd9, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, -0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, 0x2a, 0x80, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x58, -0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7f, 0x00, 0x22, 0xaa, 0x56, 0xa9, -0x57, 0x7b, 0x01, 0x90, 0xfa, 0xd4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xd9, 0xe0, 0xf5, -0x50, 0x12, 0x26, 0x25, 0x90, 0xfa, 0xd8, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, -0xfe, 0x60, 0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x1e, 0xed, 0x24, 0x06, 0x60, 0x03, 0x02, 0x1f, -0x35, 0x78, 0x77, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, -0x74, 0x33, 0x90, 0xfa, 0x90, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xae, 0x74, 0x01, 0xf0, -0x22, 0x78, 0x78, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, -0x74, 0x43, 0x90, 0xfa, 0x92, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, -0x22, 0x90, 0xfa, 0x9c, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x1f, 0x35, 0x90, 0xff, 0xa6, 0xe0, -0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, -0x90, 0xff, 0xa6, 0x12, 0x20, 0x83, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, -0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x57, 0x90, 0xfa, -0xca, 0xe0, 0xff, 0x74, 0x34, 0x90, 0xfa, 0x94, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa6, -0xe0, 0xa3, 0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, -0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x20, 0x83, 0x90, -0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, -0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, -0x96, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, -0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, -0x06, 0xc0, 0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc8, 0xf0, 0x90, 0xff, 0x92, 0xe4, -0xf0, 0xef, 0x12, 0x15, 0x0f, 0x1f, 0xed, 0x26, 0x1f, 0xed, 0x2e, 0x1f, 0x90, 0x30, 0x1f, 0x90, -0x32, 0x1f, 0x9e, 0x38, 0x1f, 0xb0, 0x3a, 0x1f, 0xe2, 0x3e, 0x1f, 0xcd, 0x44, 0x1f, 0xc2, 0x46, -0x1f, 0xd8, 0x50, 0x1f, 0xd8, 0x52, 0x1f, 0xd8, 0x54, 0x1f, 0xd8, 0x56, 0x00, 0x00, 0x1f, 0xf2, -0x90, 0xfa, 0xc8, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x10, 0x9c, 0x80, 0x62, 0x7c, 0x00, -0x7d, 0x01, 0x7f, 0x03, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, -0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x02, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, -0x80, 0x3e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x10, 0x9c, 0x80, 0x33, 0x7c, 0x00, 0x7d, -0x01, 0x7f, 0x06, 0x12, 0x10, 0x9c, 0x80, 0x28, 0x90, 0xfa, 0xc8, 0xe0, 0xff, 0x12, 0x1e, 0x4a, -0x80, 0x1e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x10, 0x9c, 0x80, 0x13, 0x12, 0x25, 0x13, -0x80, 0x0e, 0x90, 0xfa, 0xc8, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x29, 0xda, -0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, -0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x82, 0xe6, 0xfe, 0x08, -0xe6, 0x24, 0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x78, 0x82, 0xe6, -0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0x22, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, -0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, 0xff, 0x7a, 0x2f, 0x79, 0x52, 0x7e, 0x00, 0x7f, 0x0a, 0x02, -0x13, 0x8f, 0xff, 0x90, 0xf9, 0x6b, 0x02, 0x14, 0xfd, 0x90, 0xf9, 0x66, 0x12, 0x14, 0xfd, 0x90, -0x00, 0x04, 0x02, 0x13, 0xce, 0xe6, 0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, -0x78, 0x84, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xed, 0x12, 0x14, 0x0d, 0x8f, 0x82, 0x8e, 0x83, -0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, -0xf0, 0x4e, 0xf0, 0x22, 0x78, 0x84, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, 0x83, 0x22, 0xa6, 0x07, -0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x22, 0x78, 0x84, 0xe6, 0xfa, 0x08, 0xe6, 0xfb, 0x22, 0x78, 0x86, -0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, -0x8a, 0x83, 0xe5, 0x82, 0x22, 0x8b, 0x38, 0x8a, 0x39, 0x89, 0x3a, 0x8d, 0x3b, 0x90, 0xfa, 0xce, -0xe4, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe0, -0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xcd, 0xe0, 0x65, -0x3b, 0x60, 0x46, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x21, -0x54, 0x90, 0xfa, 0xcd, 0xe0, 0xff, 0x90, 0xfa, 0xd0, 0xe4, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0x12, -0x21, 0x54, 0x90, 0xfa, 0xd0, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xce, 0xcf, 0xf0, 0xa3, 0xef, -0xf0, 0x90, 0xfa, 0xcd, 0xe0, 0xa3, 0x75, 0xf0, 0x00, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xce, 0xe4, -0x75, 0xf0, 0x04, 0x12, 0x14, 0x2f, 0x02, 0x20, 0xd6, 0x90, 0xfa, 0xcf, 0xe0, 0x24, 0x01, 0xff, -0x90, 0xfa, 0xce, 0xe0, 0x34, 0x00, 0xab, 0x38, 0xaa, 0x39, 0xa9, 0x3a, 0x8f, 0xf0, 0x12, 0x14, -0x93, 0x7f, 0x00, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe4, 0x75, 0xf0, -0x01, 0x12, 0x14, 0x2f, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x8f, 0x68, -0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xfb, -0xf0, 0x44, 0x02, 0xf0, 0x08, 0x12, 0x20, 0x65, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x20, 0x7c, -0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x78, 0x82, 0xe6, 0xfe, 0x08, 0xe6, 0xff, -0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x68, 0x24, 0xfe, 0x44, 0x20, 0xfc, -0x4d, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, -0x82, 0x8e, 0x83, 0xa3, 0x74, 0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, -0x05, 0x12, 0x20, 0x25, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x95, 0x25, 0x68, 0xf5, 0x82, -0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, -0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, -0x25, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x68, 0xf8, 0x74, 0x04, 0x46, -0xf6, 0x7f, 0x00, 0x22, 0x8b, 0x62, 0x8a, 0x63, 0x89, 0x64, 0x12, 0x2a, 0x62, 0x90, 0xfa, 0xbf, -0x12, 0x15, 0x06, 0xaa, 0x63, 0xa9, 0x64, 0x90, 0xfa, 0xc2, 0x12, 0x15, 0x06, 0x90, 0xfa, 0xc3, -0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xc2, 0x12, 0x14, 0xfd, 0xe9, 0x24, 0x01, -0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc5, 0x12, 0x15, 0x06, 0xab, 0x62, 0xaa, 0x63, 0xa9, 0x64, -0x12, 0x2a, 0x6e, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x88, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, -0xff, 0x78, 0x88, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xbf, 0x12, 0x2a, 0x43, 0xff, 0x78, -0x89, 0xf6, 0x90, 0xfa, 0xc2, 0x12, 0x2a, 0x43, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x89, 0xf6, 0x12, -0x2a, 0x40, 0x5e, 0x4f, 0xff, 0x78, 0x89, 0xf6, 0x12, 0x2a, 0x49, 0x75, 0xf0, 0x02, 0x12, 0x14, -0x2f, 0x90, 0xfa, 0xc3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0xab, 0x62, 0xaa, 0x63, 0xa9, -0x64, 0x90, 0x00, 0x04, 0x12, 0x13, 0xce, 0x30, 0xe4, 0x03, 0x12, 0x2a, 0x58, 0x78, 0x88, 0x06, -0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x22, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x90, 0xfa, -0xbe, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbd, 0xf0, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x26, -0x14, 0x70, 0x70, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x22, 0x14, 0x80, -0x62, 0x12, 0x2a, 0x79, 0x12, 0x1d, 0x5e, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0x80, 0x55, 0x90, 0xfa, -0xbe, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e, 0x12, -0x29, 0x85, 0x80, 0x3f, 0xe5, 0x5e, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5d, 0xfa, 0x7b, 0x01, 0xc0, -0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xfd, 0x90, -0x00, 0x08, 0x12, 0x14, 0x5b, 0xf5, 0x41, 0x85, 0xf0, 0x40, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, -0x12, 0x23, 0xee, 0x90, 0xfa, 0xbd, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa, 0xbe, -0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbe, 0xe0, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x02, 0x12, 0x14, 0x0d, -0x90, 0xfa, 0xbd, 0xe0, 0xff, 0x22, 0x12, 0x0f, 0x89, 0x7f, 0x02, 0x12, 0x11, 0x9f, 0x78, 0x6d, -0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2, 0xb1, 0xd2, 0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, -0x7a, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, -0x78, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, -0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40, 0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, -0xe3, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff, 0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, -0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7a, -0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x78, -0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x15, -0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe3, 0xe0, 0xf5, 0xa8, 0x02, 0x10, 0x0c, 0x8b, 0x3c, -0x8a, 0x3d, 0x89, 0x3e, 0x8d, 0x3f, 0xe5, 0x3f, 0x70, 0x03, 0xaf, 0x3f, 0x22, 0x12, 0x2a, 0xa8, -0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x40, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x2e, 0xd4, 0x50, 0xf2, -0x12, 0x24, 0x7b, 0x40, 0x0b, 0x7f, 0x00, 0x22, 0x12, 0x2a, 0xc7, 0x12, 0x24, 0x7b, 0x50, 0xf8, -0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5, 0x3f, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, -0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0, 0xf5, 0x42, 0xe5, 0x3f, 0x14, 0xff, 0xe5, 0x42, 0xc3, -0x9f, 0x50, 0x2a, 0x12, 0x2e, 0xbd, 0x40, 0x03, 0xaf, 0x42, 0x22, 0xc3, 0xe5, 0x3f, 0x95, 0x42, -0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2a, 0xba, 0x05, 0x42, -0x74, 0x01, 0x25, 0x3e, 0xf5, 0x3e, 0xe4, 0x35, 0x3d, 0xf5, 0x3d, 0x80, 0xcc, 0x12, 0x2e, 0xbd, -0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xba, 0xaf, 0x3f, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x41, -0xf0, 0x02, 0x2e, 0xd4, 0x75, 0xa8, 0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x91, -0x02, 0x24, 0xce, 0x02, 0x2e, 0x88, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, -0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, -0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, -0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x28, -0xcb, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, -0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, -0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, -0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, -0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x36, 0x12, 0x19, 0x21, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x36, 0x24, -0x03, 0xff, 0x12, 0x2d, 0x4f, 0x12, 0x19, 0x21, 0xe4, 0xf0, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, -0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x36, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x90, 0x12, 0x19, -0x62, 0x60, 0x2c, 0x12, 0x29, 0xda, 0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, -0x90, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x36, 0x90, 0xfa, 0x9c, -0x12, 0x14, 0xdf, 0xe0, 0xa3, 0x30, 0xe6, 0x33, 0x12, 0x19, 0x21, 0x74, 0x04, 0xf0, 0x22, 0x75, -0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x19, 0x62, 0x60, 0x16, 0x12, 0x29, 0xda, 0xef, -0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, -0xf0, 0x22, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, -0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, -0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xfb, 0x0f, 0x12, 0x18, 0x19, 0x80, -0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x31, 0x9d, 0xf5, 0x31, 0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0xd3, -0xe5, 0x31, 0x94, 0x00, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, -0x12, 0x19, 0x3e, 0x12, 0x19, 0x92, 0x12, 0x19, 0x8c, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x1e, -0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x13, 0xce, 0xff, 0x24, 0xfc, -0x60, 0x03, 0x04, 0x70, 0x1f, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x10, 0x9c, 0x12, 0x19, -0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, -0xff, 0x12, 0x2f, 0x6a, 0x22, 0x8b, 0x4b, 0x8a, 0x4c, 0x89, 0x4d, 0x8c, 0x4e, 0x8d, 0x4f, 0xd2, -0x00, 0x12, 0x2a, 0xa8, 0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x4e, 0x90, 0xff, 0xf1, 0xf0, 0x12, -0x2e, 0xd4, 0x50, 0xf2, 0x12, 0x26, 0x9a, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xc7, 0x12, -0x26, 0x9a, 0x50, 0xf8, 0xe4, 0xf5, 0x51, 0xe5, 0x50, 0x14, 0xff, 0xe5, 0x51, 0xc3, 0x9f, 0x50, -0x17, 0x12, 0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x05, 0x51, 0x74, 0x01, 0x25, 0x4d, 0xf5, -0x4d, 0xe4, 0x35, 0x4c, 0xf5, 0x4c, 0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, -0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x7f, 0x00, 0x22, 0xab, 0x4b, 0xaa, 0x4c, 0xa9, 0x4d, -0x12, 0x13, 0xb5, 0x90, 0xff, 0xf1, 0xf0, 0x02, 0x2e, 0xd4, 0x90, 0xff, 0xf1, 0xe5, 0x4f, 0xf0, -0x02, 0x2e, 0xd4, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, 0xfa, -0xcb, 0xe4, 0x75, 0xf0, 0x09, 0x12, 0x14, 0x2f, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, -0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x12, -0x23, 0xee, 0x90, 0xff, 0xf7, 0xe5, 0x37, 0x12, 0x26, 0xfe, 0x90, 0xff, 0xf6, 0xe5, 0x37, 0xf0, -0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x06, 0x12, 0x26, 0xfe, 0xe5, 0x37, 0x30, 0xe0, 0x07, -0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0, 0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, -0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, -0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x15, 0x6b, 0xa8, 0x6b, 0xa6, 0x07, 0x30, -0x08, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x6b, 0xe6, 0xff, 0xb4, 0x03, 0x0f, -0x78, 0x82, 0x76, 0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, -0x82, 0x76, 0xff, 0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x86, 0x76, 0xfa, -0x08, 0x76, 0x9a, 0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x20, 0xb7, 0x7b, -0x01, 0x7a, 0xff, 0x79, 0x48, 0x78, 0x6e, 0x12, 0x14, 0xf4, 0xa8, 0x6b, 0xe6, 0x24, 0xfd, 0x75, -0xf0, 0x08, 0xa4, 0xff, 0xae, 0xf0, 0x78, 0x70, 0x12, 0x20, 0xb7, 0x79, 0x08, 0x78, 0x71, 0x12, -0x14, 0xf4, 0x78, 0x73, 0xef, 0x12, 0x20, 0xb7, 0x05, 0x6b, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, -0xab, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe2, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, -0x79, 0xcb, 0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7e, 0x00, 0x90, 0xfa, -0xe0, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x52, -0x09, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe0, 0xe0, 0x70, 0x04, -0xa3, 0xe0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x65, -0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe2, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x65, 0xe0, -0x54, 0xef, 0xf0, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x90, 0xff, 0x93, 0x74, 0x2a, -0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90, 0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, -0xe0, 0x44, 0x90, 0xf0, 0x12, 0x27, 0x8b, 0x12, 0x15, 0x35, 0x12, 0x2d, 0xa5, 0x7e, 0x07, 0x7f, -0xd0, 0x12, 0x11, 0x68, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0x82, 0xe4, 0x78, 0x7d, 0xf6, 0x78, -0x7d, 0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x74, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x7d, -0x06, 0x80, 0xec, 0x7f, 0x03, 0x12, 0x2c, 0x5b, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe4, 0x05, 0x7f, -0x04, 0x12, 0x2c, 0x5b, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, -0xe0, 0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x90, 0xef, 0xf6, 0x12, 0x27, -0x19, 0x12, 0x20, 0x59, 0x30, 0xe0, 0x25, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x7f, 0xf0, 0x78, 0x71, -0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02, 0xe4, -0x12, 0x14, 0x0d, 0x80, 0xe9, 0x12, 0x20, 0x2d, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x20, 0x59, 0x30, -0xe1, 0x1e, 0x12, 0x20, 0x1b, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x2f, 0x15, 0x78, 0x6e, 0x12, 0x14, -0xeb, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x14, 0x0d, 0x12, 0x20, 0x1b, 0xe0, 0x44, 0x80, 0xf0, -0x12, 0x2f, 0x80, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x03, 0x6e, 0x01, 0xff, 0x48, -0x03, 0x71, 0x01, 0xff, 0x08, 0x02, 0x6c, 0x00, 0x00, 0x44, 0xfa, 0x94, 0x00, 0x00, 0x00, 0x00, -0x44, 0xfa, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xae, 0x00, 0x00, 0x42, 0xfa, 0x7a, 0x00, -0x00, 0x42, 0xfa, 0x78, 0x00, 0x00, 0x42, 0xf9, 0x69, 0xff, 0xff, 0x42, 0xfa, 0x76, 0x00, 0x00, -0x43, 0xf9, 0x16, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x63, 0x20, 0x41, 0xf9, 0x64, 0x20, 0x41, 0xf9, -0x61, 0x00, 0x41, 0xf9, 0x62, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf9, 0x65, -0x00, 0x41, 0xf9, 0x15, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, 0x19, 0x82, -0xe5, 0x31, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x31, 0x94, -0x08, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x11, 0x7f, 0x08, 0xef, 0xe5, 0x31, 0x94, 0x08, 0xf5, 0x31, -0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0x80, 0x05, 0xaf, 0x31, 0x12, 0x19, 0x92, 0xe4, 0xfe, 0xee, -0xc3, 0x9f, 0x50, 0x19, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, -0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed, 0xf0, 0x0e, 0x12, 0x18, 0x19, 0x80, 0xe2, 0xef, 0x54, 0x7f, -0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b, 0x5f, 0x8a, 0x60, 0x89, 0x61, 0x12, 0x2a, 0x6e, 0x70, 0x05, -0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab, 0x5f, 0xaa, 0x60, 0xa9, 0x61, 0x12, 0x2a, 0x62, 0x90, 0xfa, -0xc5, 0x12, 0x15, 0x06, 0xe5, 0x61, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x60, 0xfa, 0x90, 0xfa, 0xbf, -0x12, 0x15, 0x06, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x78, 0x91, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, 0xff, -0x78, 0x91, 0xe6, 0xc3, 0x9f, 0x50, 0x12, 0x12, 0x2a, 0x40, 0xff, 0x12, 0x2a, 0x49, 0x12, 0x2a, -0x5c, 0x78, 0x91, 0x06, 0x12, 0x2a, 0x58, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x2f, -0x06, 0xe4, 0x93, 0xff, 0x78, 0x7a, 0xf6, 0x54, 0x0f, 0x12, 0x19, 0x07, 0xe0, 0x08, 0x76, 0x00, -0x08, 0xf6, 0x18, 0x12, 0x18, 0x42, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x7b, -0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee, 0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, -0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00, 0x22, 0x78, 0x7b, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, -0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, -0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0x00, 0x03, 0x12, 0x13, 0xce, 0x54, 0xf0, 0x24, 0xa0, 0x22, -0x90, 0xfa, 0xc5, 0x12, 0x14, 0xfd, 0x02, 0x13, 0xb5, 0x90, 0xfa, 0xbf, 0x12, 0x14, 0xfd, 0xef, -0x12, 0x13, 0xfb, 0x90, 0xfa, 0xc6, 0xe4, 0x22, 0x90, 0xfa, 0xc0, 0xe4, 0x75, 0xf0, 0x01, 0x02, -0x14, 0x2f, 0x90, 0x00, 0x08, 0x12, 0x14, 0x5b, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, -0x05, 0x12, 0x13, 0xce, 0x90, 0xfa, 0xbd, 0xf0, 0x22, 0xab, 0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x22, -0x90, 0xfa, 0xd9, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, -0xd2, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xd4, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, 0x25, 0x57, -0xf5, 0x57, 0xee, 0x35, 0x56, 0xf5, 0x56, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, -0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe2, 0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x3c, -0xaa, 0x3d, 0xa9, 0x3e, 0x02, 0x13, 0xfb, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x6a, -0xed, 0x70, 0x0f, 0xe5, 0x6a, 0xb4, 0x03, 0x05, 0x7f, 0x01, 0x02, 0x2e, 0xeb, 0x7f, 0x02, 0x02, -0x2e, 0xeb, 0xaf, 0x6a, 0x12, 0x27, 0x19, 0x74, 0x74, 0x25, 0x6a, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, -0xd2, 0x09, 0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x6a, 0xb4, -0x03, 0x07, 0x7f, 0x81, 0x12, 0x2e, 0xeb, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x2e, 0xeb, 0x30, 0x09, -0x07, 0x12, 0x18, 0x9b, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x22, 0x12, 0x0f, 0x89, 0x90, -0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0, 0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, -0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13, 0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x2c, 0x80, -0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0d, 0x12, 0x19, 0x3e, 0x53, 0x2c, 0x7f, 0x90, -0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0, 0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0x9f, -0x12, 0x19, 0x46, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, 0x8a, 0x12, 0x20, 0x9e, 0x30, 0xe1, -0x07, 0x7f, 0x13, 0x12, 0x2e, 0xa5, 0x80, 0x34, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, 0x16, -0x78, 0x8a, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07, 0x90, -0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x04, 0xf0, 0x78, 0x8a, -0xe6, 0xff, 0x12, 0x20, 0x59, 0xfd, 0x12, 0x2d, 0x21, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, -0x0f, 0x89, 0x78, 0x8f, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x27, 0x19, 0x90, 0xf9, 0x66, 0x12, 0x14, -0xfd, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, -0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x20, 0x4b, 0x12, 0x2f, 0x80, 0x78, -0x8f, 0xe6, 0xff, 0x12, 0x19, 0xbb, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, -0x8b, 0xef, 0xf6, 0x12, 0x2e, 0x4c, 0x12, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, -0x16, 0x78, 0x8b, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, -0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x14, 0xf0, 0xe0, 0x70, 0x02, -0xd2, 0xb3, 0x02, 0x10, 0x0c, 0x8f, 0x69, 0x12, 0x27, 0x19, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x3f, -0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, -0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0x74, -0x74, 0x25, 0x69, 0xf8, 0x74, 0xfb, 0x56, 0xf6, 0x7f, 0x00, 0x22, 0x8f, 0x37, 0xc2, 0x08, 0x12, -0x27, 0x19, 0x12, 0x20, 0x38, 0x78, 0x84, 0x12, 0x20, 0x1d, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x20, -0x70, 0x12, 0x20, 0x21, 0xe0, 0x20, 0xe0, 0xf6, 0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, -0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0xaf, 0x37, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, -0x89, 0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x24, 0x06, 0x12, 0x20, 0x23, 0xe0, 0xfd, 0x12, 0x20, -0x53, 0x90, 0x00, 0x03, 0x12, 0x20, 0x78, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x04, -0x12, 0x14, 0x0d, 0x12, 0x2f, 0x80, 0x7d, 0x02, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, -0xae, 0x05, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x35, -0xe4, 0x95, 0x34, 0x40, 0x02, 0xae, 0x35, 0xee, 0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, -0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, 0x12, 0x14, 0x0d, 0xaf, 0x06, 0x12, 0x2f, 0x6a, -0x22, 0x12, 0x0f, 0x89, 0x78, 0x8c, 0x12, 0x20, 0x9e, 0x30, 0xe2, 0x07, 0x7f, 0x13, 0x12, 0x2e, -0xa5, 0x80, 0x1b, 0x78, 0x8c, 0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x20, 0xe1, 0x07, 0x7f, 0x12, 0x12, -0x2e, 0xa5, 0x80, 0x0a, 0x78, 0x8c, 0xe6, 0xff, 0x12, 0x21, 0x6e, 0x12, 0x2e, 0xa5, 0x02, 0x10, -0x0c, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, 0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, -0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, 0x74, 0x74, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, -0x74, 0x95, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, -0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, 0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, -0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x80, 0xf0, 0x74, -0x74, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, 0x64, -0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, -0xc3, 0xe5, 0x31, 0x9f, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x05, 0x12, 0x25, 0x9c, 0x80, 0x03, 0x12, -0x2f, 0x76, 0x02, 0x10, 0x0c, 0x90, 0xff, 0xfc, 0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, -0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, 0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, -0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0x80, 0xef, 0x22, 0x12, 0x0f, 0x89, 0x78, -0x6c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, 0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, -0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x11, 0x9f, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x8e, 0x65, -0x8f, 0x66, 0xe5, 0x66, 0x15, 0x66, 0xae, 0x65, 0x70, 0x02, 0x15, 0x65, 0xd3, 0x94, 0x00, 0xee, -0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, 0x12, 0x0f, 0x62, 0x80, 0xe5, 0x22, 0x11, 0x1a, -0x2b, 0x1c, 0x23, 0x56, 0x2f, 0x5c, 0x2d, 0xcc, 0x2d, 0x7a, 0x2e, 0x6b, 0x2c, 0x8e, 0x2b, 0x66, -0x2b, 0xec, 0x2c, 0xf1, 0x2e, 0x2d, 0x1b, 0xe6, 0x2b, 0xaf, 0x28, 0x67, 0x0e, 0x12, 0x0f, 0x89, -0x78, 0x8d, 0x12, 0x20, 0x9e, 0x20, 0xe2, 0x07, 0x7f, 0x11, 0x12, 0x2e, 0xa5, 0x80, 0x0a, 0x78, -0x8d, 0xe6, 0xff, 0x12, 0x2c, 0x25, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x8f, 0x67, 0x12, 0x2c, -0x25, 0xaf, 0x67, 0x12, 0x27, 0x19, 0x12, 0x20, 0x38, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x67, -0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x67, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, -0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x05, 0x12, 0x29, 0x2d, 0x80, 0x06, 0x12, -0x19, 0x7a, 0x12, 0x19, 0x82, 0x02, 0x10, 0x0c, 0x12, 0x27, 0xfb, 0x12, 0x12, 0x3b, 0x90, 0xf8, -0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x11, 0xd8, 0x12, 0x26, 0xa3, 0x12, 0x12, 0x77, -0x12, 0x10, 0xfa, 0x80, 0xe3, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0xe4, 0xf5, 0x2a, 0xf5, -0x2b, 0xef, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, 0xff, 0x12, 0x2f, 0x6a, 0x22, 0x90, 0xff, 0xf0, -0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, -0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, -0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, -0x18, 0xad, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, 0x18, 0xf7, 0xe0, 0x54, 0xdf, 0xf0, 0x22, -0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, -0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x84, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, -0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, 0x34, 0x30, 0x85, 0x35, 0x31, 0x90, 0xff, -0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x2f, -0x00, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, 0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, -0x38, 0x28, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x89, 0x7f, -0x02, 0x12, 0x10, 0x18, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x12, -0x18, 0x49, 0x12, 0x29, 0x2d, 0x22, 0x12, 0x19, 0x82, 0x12, 0x19, 0x3e, 0x12, 0x19, 0x7a, 0x22, -0xc2, 0x08, 0x22, +0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x12, 0x41, 0xad, 0x07, 0xaf, 0x02, +0x12, 0x12, 0x58, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x11, 0x66, 0x80, 0xc1, 0x8f, +0x24, 0x12, 0x2a, 0x06, 0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, +0x21, 0xf3, 0xe0, 0xfd, 0x12, 0x22, 0x8a, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x21, 0xf3, 0xed, 0xf0, +0x12, 0x22, 0x56, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xe0, 0xff, 0x12, 0x22, 0x99, 0x24, 0x09, 0x12, +0x21, 0xf3, 0xef, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x22, 0x09, 0xc0, +0x83, 0xc0, 0x82, 0xa3, 0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, +0x82, 0xe0, 0x33, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x80, 0x12, 0x22, 0x09, +0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0xff, 0x12, 0x22, 0x8a, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x21, +0xf3, 0xef, 0xf0, 0xed, 0x12, 0x22, 0x99, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xed, 0xf0, 0x12, 0x21, +0xfb, 0xe0, 0xff, 0x30, 0xe7, 0x19, 0x12, 0x22, 0x6e, 0x12, 0x21, 0xf3, 0xe0, 0x60, 0x09, 0x12, +0x21, 0xfb, 0xef, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x12, 0x21, 0xfb, 0xef, 0x54, 0xfd, 0xf0, 0x78, +0x7e, 0x12, 0x22, 0x09, 0xa3, 0xa3, 0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, +0xfd, 0x12, 0x22, 0x43, 0xa3, 0xe0, 0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, +0x05, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x31, 0x94, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x78, 0x80, +0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x24, 0x06, 0x12, 0x21, 0xf3, 0xe0, 0x60, 0x03, 0x43, 0x07, +0x04, 0x53, 0x07, 0xfc, 0x78, 0x80, 0x12, 0x22, 0x7a, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0x42, +0x07, 0x43, 0x07, 0x80, 0x12, 0x22, 0x8a, 0xf5, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xef, 0xf0, 0x12, +0x22, 0x99, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0xff, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xe0, +0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, 0x03, 0x43, 0x07, 0x20, 0xec, +0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, 0x12, 0x21, 0xfb, 0xe0, 0xfe, +0x54, 0x03, 0x60, 0x73, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x69, 0x78, 0x80, 0x12, 0x22, 0x6f, +0x12, 0x21, 0xf3, 0xe0, 0x12, 0x1b, 0x4c, 0x14, 0xa6, 0x00, 0x14, 0xda, 0x01, 0x14, 0xdf, 0x03, +0x14, 0xda, 0x05, 0x14, 0xdf, 0x07, 0x14, 0xda, 0x09, 0x14, 0xdf, 0x0b, 0x14, 0xda, 0x0d, 0x14, +0xdf, 0x0f, 0x00, 0x00, 0x14, 0xe7, 0xe5, 0x24, 0x64, 0x03, 0x70, 0x21, 0x90, 0xf9, 0x15, 0xe0, +0x30, 0xe2, 0x0d, 0x30, 0xb4, 0x05, 0x43, 0x07, 0x02, 0x80, 0x2c, 0x53, 0x07, 0xfd, 0x80, 0x27, +0x30, 0x95, 0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, +0x43, 0x07, 0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53, +0x07, 0xfd, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x22, 0x78, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xef, +0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x12, 0x21, 0xfb, 0xe0, 0xfe, 0x54, +0x03, 0x70, 0x03, 0x02, 0x15, 0xd7, 0xee, 0x20, 0xe1, 0x03, 0x02, 0x15, 0xd4, 0x12, 0x22, 0x6e, +0x12, 0x21, 0xf3, 0xe0, 0x12, 0x1b, 0x4c, 0x15, 0x36, 0x00, 0x15, 0x6c, 0x01, 0x15, 0x6c, 0x03, +0x15, 0xa0, 0x05, 0x15, 0xa0, 0x07, 0x15, 0x86, 0x09, 0x15, 0x86, 0x0b, 0x15, 0xba, 0x0d, 0x15, +0xba, 0x0f, 0x00, 0x00, 0x15, 0xd7, 0xe5, 0x24, 0x64, 0x03, 0x70, 0x23, 0x90, 0xf9, 0x15, 0xe0, +0x30, 0xe2, 0x0f, 0x30, 0xb1, 0x06, 0x53, 0x07, 0x7f, 0x02, 0x15, 0xd7, 0x43, 0x07, 0x80, 0x02, +0x15, 0xd7, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x7d, 0x43, 0x07, 0x80, 0x80, 0x78, 0x30, +0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x70, 0x43, 0x07, 0x80, 0x80, 0x6b, 0xe5, 0x24, 0xb4, 0x03, +0x09, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xdf, +0xf0, 0x53, 0x07, 0x7f, 0x80, 0x51, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x44, +0x10, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x20, 0xf0, 0x53, 0x07, 0x7f, 0x80, 0x37, +0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0xff, +0x9e, 0xe0, 0x54, 0xdf, 0xf0, 0x43, 0x07, 0x80, 0x80, 0x1d, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, +0xff, 0x9e, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x20, 0xf0, 0x43, +0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x80, 0x12, 0x22, 0x3f, 0xe0, 0xfc, 0xa3, 0xe0, +0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, 0xec, 0x30, 0xe3, 0x05, +0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x10, 0x80, +0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, 0x03, 0x53, 0x07, 0xf7, +0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, 0xed, 0x30, 0xe6, 0x05, +0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, 0x43, 0x07, 0x02, 0x80, +0x03, 0x53, 0x07, 0xfd, 0x78, 0x7e, 0x12, 0x22, 0x3f, 0xa3, 0xef, 0xf0, 0x12, 0x31, 0xc7, 0x7f, +0x00, 0x22, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, 0xff, 0xf9, 0x74, +0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcc, 0xe4, 0xfd, 0x12, 0x22, 0xa0, 0x90, 0xfa, 0xcc, +0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0x12, 0x18, 0xe2, 0xe5, 0x23, 0x30, 0xe7, 0x02, 0xd2, +0x02, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x24, 0x90, 0xfa, 0xcc, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, +0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, +0x00, 0x7a, 0x00, 0x79, 0x23, 0x75, 0x2d, 0x00, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0xe5, +0x23, 0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x23, 0x64, 0x07, 0x60, 0x1e, 0xe5, 0x23, 0x64, +0x06, 0x60, 0x18, 0xe5, 0x23, 0x64, 0x14, 0x60, 0x12, 0xe5, 0x23, 0x64, 0x41, 0x60, 0x0c, 0xe5, +0x23, 0x64, 0x1a, 0x70, 0x46, 0xe5, 0x24, 0x64, 0x02, 0x70, 0x40, 0xe5, 0x23, 0xb4, 0x07, 0x16, +0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x02, 0xf0, 0xa3, +0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1e, 0xe5, 0x23, 0xb4, 0x41, 0x12, 0x90, 0xf9, 0x15, 0xe0, 0x44, +0x06, 0xf0, 0xa3, 0xe0, 0x44, 0x06, 0xf0, 0xd2, 0xb1, 0xd2, 0xb4, 0x80, 0x07, 0x90, 0xf9, 0x15, +0xe0, 0x44, 0x01, 0xf0, 0x90, 0xf9, 0x16, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x23, 0x64, 0x42, 0x60, +0x05, 0xe5, 0x23, 0xb4, 0x43, 0x0c, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x80, 0xf0, 0xa3, 0xe0, 0x44, +0x80, 0xf0, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x18, 0xe2, 0x90, 0xff, +0xf5, 0xe5, 0x23, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x33, 0xf5, 0x34, 0xf5, 0x32, 0x12, 0x1d, 0x84, +0x12, 0x1c, 0x30, 0x12, 0x1d, 0x8b, 0x90, 0xf9, 0x67, 0x12, 0x1b, 0x43, 0x90, 0xf9, 0x6c, 0x12, +0x1b, 0x43, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81, +0x74, 0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x23, 0xe5, 0x23, +0x12, 0x1c, 0xa7, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x23, 0x12, 0x1c, 0xb5, 0xf5, 0x83, 0xe4, 0xf0, +0x05, 0x23, 0xe5, 0x23, 0xb4, 0x07, 0xe7, 0x78, 0x7a, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x31, +0x4d, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x31, 0x5a, 0xe4, 0x93, 0xff, +0x08, 0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x1c, 0x97, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0, +0x08, 0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0, +0x9f, 0x78, 0x7b, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x1c, 0x28, 0xce, 0xc3, 0x13, 0xce, +0x13, 0xd8, 0xf9, 0xff, 0xed, 0x12, 0x1c, 0xf8, 0xef, 0xf0, 0xed, 0x12, 0x1d, 0x1e, 0xe4, 0xf5, +0x23, 0xe5, 0x23, 0x90, 0x31, 0x47, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xe5, 0x23, 0x25, 0xe0, +0x24, 0x4e, 0xf5, 0x82, 0xe4, 0x34, 0x31, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7, +0x53, 0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1c, 0x97, 0x12, 0x1d, 0x06, 0x24, 0x47, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0x12, 0x1c, 0x18, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12, +0x1c, 0xf8, 0xef, 0xf0, 0x12, 0x1c, 0x1f, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d, +0x0b, 0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x1d, 0x1e, +0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, +0xf0, 0x02, 0x18, 0xb7, 0x78, 0x78, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1c, 0xea, 0x12, 0x1d, 0x06, +0x24, 0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x1c, 0x18, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, +0xf9, 0x12, 0x1d, 0x0b, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12, +0x1c, 0x1f, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d, 0x0b, 0x24, 0x05, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x23, 0xe5, 0x23, 0x64, 0x04, 0x60, 0x03, 0x02, +0x17, 0xe1, 0x90, 0x31, 0x4c, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0x12, 0x1c, 0xe8, 0xe4, 0xf0, +0x90, 0x31, 0x4b, 0x93, 0xff, 0xf6, 0x12, 0x1c, 0x95, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05, +0xf0, 0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12, +0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x25, 0xd7, 0xe7, 0x09, 0xf6, 0x08, +0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, 0x82, 0x8c, 0x83, +0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x78, +0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, 0x09, 0xf0, 0xa3, +0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x58, +0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c, 0x80, 0xd2, 0x80, 0xfa, +0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10, 0x80, 0xa6, 0x80, 0xea, +0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33, 0x89, 0x82, 0x8a, 0x83, +0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, +0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0x0d, 0x89, 0x82, 0x8a, +0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0, 0xed, 0xfb, 0x22, 0x89, +0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xf0, +0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde, 0xe8, 0x80, 0xdb, 0x89, +0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, 0xf0, 0xef, 0x60, +0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xb9, 0xf5, +0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, 0x23, 0x90, 0x19, +0x4c, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, +0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, +0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8, +0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82, +0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, +0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, +0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, +0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0x22, 0xc5, 0xf0, 0xf8, 0xa3, +0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xe0, 0x38, +0xf0, 0x22, 0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, +0x15, 0x83, 0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22, 0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, +0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0, 0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, +0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe, 0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, +0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83, 0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22, +0xbb, 0x01, 0x0a, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x06, 0xf7, +0x09, 0xa7, 0xf0, 0x19, 0x22, 0xbb, 0xfe, 0x06, 0xf3, 0xe5, 0xf0, 0x09, 0xf3, 0x19, 0x22, 0xf8, +0xbb, 0x01, 0x11, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0xe5, +0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x08, 0xa6, 0xf0, 0x22, 0xbb, +0xfe, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0xe5, 0xf0, 0x08, 0xf2, 0x22, 0xa4, 0x25, 0x82, 0xf5, +0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xfa, 0x08, 0xe6, 0xf9, +0x22, 0xeb, 0xf6, 0x08, 0xea, 0xf6, 0x08, 0xe9, 0xf6, 0x22, 0xe0, 0xfb, 0xa3, 0xe0, 0xfa, 0xa3, +0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, 0x83, 0xd0, 0x82, +0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, +0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, +0x80, 0xdf, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0xe5, 0x4c, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, +0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0x74, 0x11, 0x12, +0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x06, +0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, +0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0xe4, 0x12, 0x1a, 0x38, 0x04, 0x25, +0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0xe4, 0x12, 0x1a, +0x38, 0x04, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x04, 0xe0, 0xab, +0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, +0x37, 0xf5, 0x37, 0x90, 0xff, 0x05, 0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, +0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x22, 0xf5, 0x83, 0xe0, 0x54, +0x08, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3, +0x78, 0x7b, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, 0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22, +0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75, 0x38, 0x6f, 0x22, 0xe0, 0x44, 0x04, 0xf0, 0x74, 0x12, +0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xe0, 0x22, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, +0x00, 0xc3, 0x90, 0xfa, 0xbd, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xbc, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, +0xb4, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0xef, 0x25, 0x4f, 0xf5, 0x4f, 0xee, 0x35, 0x4e, 0xf5, +0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb1, 0x90, 0xfa, 0xb4, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, +0xf5, 0x2e, 0x22, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4, +0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x4d, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0x22, 0xe5, 0x4d, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff, +0x22, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22, +0x90, 0xfa, 0xbb, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x22, 0x75, 0x33, 0x00, 0x8f, 0x34, 0x90, 0xf9, +0x6c, 0x12, 0x1b, 0x3a, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, +0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08, +0xa4, 0x22, 0x74, 0xaf, 0x25, 0x22, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0, +0x08, 0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90, +0xff, 0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff, +0xfc, 0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x67, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74, +0x65, 0xf0, 0x22, 0x12, 0x1b, 0x1c, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a, +0xfa, 0x79, 0xb4, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0, +0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x67, 0x02, 0x1b, 0x3a, 0x90, 0xff, 0xa4, 0xe0, +0x44, 0x02, 0xf0, 0x22, 0x75, 0x39, 0x01, 0x75, 0x3a, 0x09, 0x22, 0x7b, 0x01, 0x7a, 0xf9, 0x79, +0x6f, 0x22, 0xd3, 0xe5, 0x3c, 0x94, 0x08, 0xe5, 0x3b, 0x94, 0x01, 0x22, 0x90, 0xfa, 0xbb, 0xe0, +0xff, 0x90, 0xfa, 0xb7, 0xf0, 0x22, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4, +0xe0, 0x54, 0xef, 0x22, 0x12, 0x10, 0x03, 0x78, 0x88, 0xef, 0xf6, 0x12, 0x2a, 0x06, 0x12, 0x22, +0x4a, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x21, 0xf3, 0xe0, 0xfd, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x0a, +0x12, 0x22, 0x52, 0x24, 0x0a, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x1a, 0x4a, 0x12, +0x22, 0x4a, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x53, 0x12, 0x22, 0x56, 0x24, +0x04, 0x12, 0x21, 0xf3, 0xe0, 0xf5, 0x54, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xf5, 0x55, +0xe5, 0x53, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x88, 0xf6, 0xd3, 0x94, 0x00, 0x40, 0x06, +0xe5, 0x54, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x88, 0xe6, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x0c, 0xef, +0x12, 0x1a, 0x4a, 0x78, 0x80, 0x12, 0x22, 0x09, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x53, +0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x53, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, 0x54, 0x20, +0xe5, 0x0e, 0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7, 0x03, 0x43, 0x07, 0x02, +0xe5, 0x53, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x53, 0x30, 0xe2, 0x03, 0x43, 0x07, 0x20, +0xe5, 0x53, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x53, 0x30, 0xe1, 0x03, 0x43, 0x07, +0x80, 0xe5, 0x53, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x53, 0x30, 0xe6, 0x03, 0x43, 0x06, +0x08, 0xe5, 0x54, 0x20, 0xe4, 0x0e, 0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7, +0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, 0x8f, 0xf0, +0x12, 0x1a, 0xef, 0xe5, 0x55, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, 0x12, 0x22, +0x2c, 0x90, 0x00, 0x08, 0xef, 0x12, 0x1a, 0x4a, 0x80, 0x0a, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x08, +0xe4, 0x12, 0x1a, 0x4a, 0xe5, 0x55, 0x54, 0x03, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x07, 0xef, 0x12, +0x1a, 0x4a, 0xe5, 0x55, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x1a, 0x4a, 0x90, +0x00, 0x07, 0x12, 0x1a, 0x0b, 0x70, 0x13, 0x12, 0x22, 0x2d, 0xe9, 0x24, 0x09, 0xf9, 0xe4, 0x3a, +0xfa, 0x12, 0x19, 0xf2, 0xff, 0xc3, 0x13, 0x12, 0x1a, 0x38, 0x12, 0x22, 0x78, 0x24, 0x08, 0x12, +0x21, 0xf3, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xe0, +0xfd, 0xee, 0xed, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0xef, 0x12, +0x31, 0xc7, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2f, 0x18, 0x02, 0x10, 0x86, 0x90, 0xfa, 0xe3, 0xe0, +0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, 0xfa, 0xd7, +0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0xff, 0x7e, 0x00, 0x90, 0xfa, +0xd3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, 0x12, 0x1a, +0x98, 0xff, 0x90, 0xfa, 0xd5, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, 0x01, 0x8e, +0x50, 0x8f, 0x51, 0x74, 0x0a, 0x25, 0x51, 0xf5, 0x51, 0xe4, 0x35, 0x50, 0xf5, 0x50, 0x90, 0xfa, +0xd8, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd6, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, 0xff, 0x90, +0xfa, 0xda, 0xf0, 0xc3, 0x90, 0xfa, 0xd4, 0xe0, 0x9f, 0x90, 0xfa, 0xd3, 0xe0, 0x94, 0x00, 0x50, +0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xda, 0xf0, 0x12, 0x1f, 0xfb, 0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, +0x2d, 0x5a, 0x90, 0xfa, 0xd3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, 0xfa, 0xd7, +0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, 0xfa, 0xda, +0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd4, 0xe0, 0x90, 0xfa, 0xda, 0xf0, 0x12, 0x1f, 0xfb, 0x60, 0x03, +0xe0, 0xff, 0x22, 0x12, 0x2d, 0x5a, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, +0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x7f, 0x00, 0x22, 0xaa, 0x50, 0xa9, 0x51, 0x7b, +0x01, 0x90, 0xfa, 0xd5, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xda, 0xe0, 0xf5, 0x4a, 0x12, +0x28, 0x9f, 0x90, 0xfa, 0xd9, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, 0xfe, 0x60, +0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x20, 0xbb, 0x24, 0x06, 0x60, 0x03, 0x02, 0x21, 0x03, 0x78, +0x71, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x33, +0x90, 0xfa, 0x91, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, 0x22, 0x78, +0x72, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x43, +0x90, 0xfa, 0x93, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xb0, 0x74, 0x01, 0xf0, 0x22, 0x90, +0xfa, 0x9d, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x21, 0x03, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, +0xca, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, +0xa6, 0x12, 0x22, 0x5d, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xca, 0xf0, 0x80, 0xe6, 0x90, 0xfa, +0xcb, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x2c, 0xb4, 0xef, 0x70, 0x57, 0x90, 0xfa, 0xcb, 0xe0, +0xff, 0x74, 0x34, 0x90, 0xfa, 0x95, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa7, 0xe0, 0xa3, +0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xca, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xca, +0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x22, 0x5d, 0x90, 0xff, 0xb6, +0xe0, 0x90, 0xfa, 0xca, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xcb, 0xe0, 0xff, 0x74, 0x44, 0xfe, 0x12, +0x2c, 0xb4, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xcb, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, 0x97, 0xf0, +0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, +0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, +0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc9, 0xf0, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0xef, +0x12, 0x1b, 0x4c, 0x21, 0xbb, 0x26, 0x21, 0xbb, 0x2e, 0x21, 0x5e, 0x30, 0x21, 0x5e, 0x32, 0x21, +0x6c, 0x38, 0x21, 0x7e, 0x3a, 0x21, 0xb0, 0x3e, 0x21, 0x9b, 0x44, 0x21, 0x90, 0x46, 0x21, 0xa6, +0x50, 0x21, 0xa6, 0x52, 0x21, 0xa6, 0x54, 0x21, 0xa6, 0x56, 0x00, 0x00, 0x21, 0xc0, 0x90, 0xfa, +0xc9, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x11, 0x16, 0x80, 0x62, 0x7c, 0x00, 0x7d, 0x01, +0x7f, 0x03, 0x12, 0x11, 0x16, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, 0x7c, 0x00, +0x7d, 0x01, 0x7f, 0x02, 0x12, 0x11, 0x16, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x3e, +0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x11, 0x16, 0x80, 0x33, 0x7c, 0x00, 0x7d, 0x01, 0x7f, +0x06, 0x12, 0x11, 0x16, 0x80, 0x28, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x12, 0x20, 0x18, 0x80, 0x1e, +0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x11, 0x16, 0x80, 0x13, 0x12, 0x27, 0x8d, 0x80, 0x0e, +0x90, 0xfa, 0xc9, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x2c, 0xb4, 0xd0, 0x07, +0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, +0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0x24, +0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x74, 0x12, 0x25, 0x24, 0xf5, +0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0x22, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, +0x83, 0x22, 0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, +0xff, 0x7a, 0x31, 0x79, 0x99, 0x7e, 0x00, 0x7f, 0x0a, 0x02, 0x19, 0xcc, 0xff, 0x90, 0xf9, 0x6c, +0x02, 0x1b, 0x3a, 0x90, 0xf9, 0x67, 0x12, 0x1b, 0x3a, 0x90, 0x00, 0x04, 0x02, 0x1a, 0x0b, 0xe6, +0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, 0x78, 0x7e, 0xe6, 0xfe, 0x08, 0xe6, +0xff, 0x22, 0xed, 0x12, 0x1a, 0x4a, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90, +0xfa, 0xcb, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, 0xf0, 0x4e, 0xf0, 0x22, 0x08, 0xe6, +0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x24, 0x09, 0x22, 0x78, 0x7e, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, +0x83, 0x22, 0xa6, 0x07, 0xe6, 0x24, 0x6e, 0xf8, 0xe6, 0x22, 0x78, 0x7e, 0xe6, 0xfa, 0x08, 0xe6, +0xfb, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, 0x8a, 0x83, 0xe5, 0x82, 0x22, +0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0x8d, 0x28, 0x90, 0xfa, 0xcf, 0xe4, 0xf0, 0xa3, 0x74, 0x02, +0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xce, 0x90, 0xfa, 0xcf, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, +0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xce, 0xe0, 0x65, 0x28, 0x60, 0x46, 0xa3, 0xe0, +0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x23, 0x2f, 0x90, 0xfa, 0xce, 0xe0, +0xff, 0x90, 0xfa, 0xd1, 0xe4, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0x12, 0x23, 0x2f, 0x90, 0xfa, 0xd1, +0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xcf, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xfa, 0xce, 0xe0, +0xa3, 0x75, 0xf0, 0x00, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x04, 0x12, 0x1a, +0x6c, 0x02, 0x22, 0xb1, 0x90, 0xfa, 0xd0, 0xe0, 0x24, 0x01, 0xff, 0x90, 0xfa, 0xcf, 0xe0, 0x34, +0x00, 0xab, 0x25, 0xaa, 0x26, 0xa9, 0x27, 0x8f, 0xf0, 0x12, 0x1a, 0xd0, 0x7f, 0x00, 0x22, 0x7b, +0x01, 0x7a, 0xfa, 0x79, 0xce, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1a, 0x6c, 0x85, +0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x25, 0xd7, 0x8f, 0x62, 0x12, 0x2a, 0x06, 0x12, 0x22, +0x4a, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x21, 0xf3, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x02, 0xf0, 0x08, +0x12, 0x22, 0x3f, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x22, 0x56, 0x24, 0x0b, 0x12, 0x21, 0xf3, +0xe0, 0x44, 0x01, 0xf0, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, +0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x62, 0x24, 0xfe, 0x44, 0x20, 0xfc, 0x4d, 0xf0, 0xe5, 0x82, 0x24, +0x04, 0x12, 0x21, 0xf3, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0x74, +0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x05, 0x12, 0x21, 0xf3, 0xc0, +0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x96, 0x25, 0x62, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, +0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, +0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0x44, 0x80, 0xf0, +0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x62, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, +0x10, 0x03, 0x7f, 0x02, 0x12, 0x12, 0x19, 0x78, 0x67, 0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2, +0xb1, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe7, 0x07, 0x90, 0xff, 0x9e, 0xe4, 0xf0, 0x80, 0x36, 0xd2, +0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7c, +0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x7a, +0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40, +0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, 0xe4, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff, +0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87, +0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7c, 0xe0, +0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x7a, 0xe0, +0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x17, 0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe4, 0xe0, +0xf5, 0xa8, 0x02, 0x10, 0x86, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x12, 0x2d, 0x3c, 0x90, 0xfa, +0xc0, 0x12, 0x1b, 0x43, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0x43, 0x90, 0xfa, +0xc4, 0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0x3a, 0xe9, 0x24, +0x01, 0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x43, 0xab, 0x5c, 0xaa, 0x5d, 0xa9, +0x5e, 0x12, 0x2d, 0x48, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x82, 0xf6, 0x90, 0xfa, 0xbe, +0xe0, 0xff, 0x78, 0x82, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xc0, 0x12, 0x2d, 0x1d, 0xff, +0x78, 0x83, 0xf6, 0x90, 0xfa, 0xc3, 0x12, 0x2d, 0x1d, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x83, 0xf6, +0x12, 0x2d, 0x1a, 0x5e, 0x4f, 0xff, 0x78, 0x83, 0xf6, 0x12, 0x2d, 0x23, 0x75, 0xf0, 0x02, 0x12, +0x1a, 0x6c, 0x90, 0xfa, 0xc4, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x1a, 0x6c, 0xab, 0x5c, 0xaa, 0x5d, +0xa9, 0x5e, 0x90, 0x00, 0x04, 0x12, 0x1a, 0x0b, 0x30, 0xe4, 0x03, 0x12, 0x2d, 0x32, 0x78, 0x82, +0x06, 0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbf, 0xf0, 0x22, 0x8b, 0x56, 0x8a, 0x57, 0x89, 0x58, 0x90, +0xfa, 0xbf, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x12, 0x19, 0xf2, 0x24, 0x6e, 0x60, +0x26, 0x14, 0x70, 0x70, 0x12, 0x2d, 0x09, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x24, 0x95, +0x80, 0x62, 0x12, 0x2d, 0x53, 0x12, 0x1f, 0x2c, 0x90, 0xfa, 0xbf, 0xef, 0xf0, 0x80, 0x55, 0x90, +0xfa, 0xbf, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2d, 0x09, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e, +0x12, 0x2c, 0x5f, 0x80, 0x3f, 0xe5, 0x58, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x57, 0xfa, 0x7b, 0x01, +0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2d, 0x53, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0xfd, +0x90, 0x00, 0x08, 0x12, 0x1a, 0x98, 0xf5, 0x2e, 0x85, 0xf0, 0x2d, 0xd0, 0x01, 0xd0, 0x02, 0xd0, +0x03, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa, +0xbf, 0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbf, 0xe0, 0x12, 0x2d, 0x53, 0x90, 0x00, 0x02, 0x12, 0x1a, +0x4a, 0x90, 0xfa, 0xbe, 0xe0, 0xff, 0x22, 0x8b, 0x29, 0x8a, 0x2a, 0x89, 0x2b, 0x8d, 0x2c, 0xe5, +0x2c, 0x70, 0x03, 0xaf, 0x2c, 0x22, 0x12, 0x2d, 0x82, 0x70, 0x16, 0x12, 0x2d, 0xa1, 0xe5, 0x2d, +0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0x1b, 0x50, 0xf2, 0x12, 0x26, 0x64, 0x40, 0x0b, 0x7f, 0x00, +0x22, 0x12, 0x2d, 0xa1, 0x12, 0x26, 0x64, 0x50, 0xf8, 0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5, +0x2c, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0, +0xf5, 0x2f, 0xe5, 0x2c, 0x14, 0xff, 0xe5, 0x2f, 0xc3, 0x9f, 0x50, 0x2a, 0x12, 0x31, 0x04, 0x40, +0x03, 0xaf, 0x2f, 0x22, 0xc3, 0xe5, 0x2c, 0x95, 0x2f, 0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0, +0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2d, 0x94, 0x05, 0x2f, 0x74, 0x01, 0x25, 0x2b, 0xf5, 0x2b, 0xe4, +0x35, 0x2a, 0xf5, 0x2a, 0x80, 0xcc, 0x12, 0x31, 0x04, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2d, +0x94, 0xaf, 0x2c, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x2e, 0xf0, 0x02, 0x31, 0x1b, 0x12, 0x10, 0x03, +0x78, 0x84, 0x12, 0x22, 0x82, 0x30, 0xe1, 0x08, 0x7f, 0x13, 0x12, 0x30, 0xec, 0x02, 0x26, 0xfb, +0x78, 0x84, 0xe6, 0xf9, 0x24, 0x12, 0x12, 0x21, 0xff, 0xe0, 0xff, 0x30, 0xe7, 0x40, 0x54, 0x03, +0x60, 0x1e, 0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x44, 0x04, +0xf0, 0x80, 0x46, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x39, +0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x80, +0x28, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1b, 0xef, 0x54, +0x03, 0x60, 0x14, 0xe9, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07, +0x90, 0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x17, 0xe0, 0x04, 0xf0, 0xaf, +0x01, 0x12, 0x22, 0x33, 0xfd, 0x12, 0x2f, 0x49, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x75, 0xa8, +0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x8b, 0x02, 0x27, 0x48, 0x02, 0x30, 0xcf, +0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, +0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, +0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, +0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x2b, 0x4c, 0xe4, 0x7e, 0x01, 0x93, 0x60, +0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, +0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, +0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, +0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x22, +0x12, 0x1d, 0x12, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x22, 0x24, 0x03, 0xff, 0x12, 0x2f, 0x77, 0x12, +0x1d, 0x12, 0xe4, 0xf0, 0x05, 0x22, 0xe5, 0x22, 0xc3, 0x94, 0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x22, +0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x91, 0x12, 0x1d, 0x53, 0x60, 0x2c, 0x12, 0x2c, 0xb4, +0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x91, 0x12, 0x1b, 0x1c, 0xe4, 0xf0, +0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x22, 0x90, 0xfa, 0x9d, 0x12, 0x1b, 0x1c, 0xe0, 0xa3, 0x30, +0xe6, 0x33, 0x12, 0x1d, 0x12, 0x74, 0x04, 0xf0, 0x22, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, +0x95, 0x12, 0x1d, 0x53, 0x60, 0x16, 0x12, 0x2c, 0xb4, 0xef, 0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5, +0x22, 0x90, 0xfa, 0x95, 0x12, 0x1b, 0x1c, 0xe4, 0xf0, 0xa3, 0xf0, 0x22, 0x05, 0x22, 0xe5, 0x22, +0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef, +0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12, +0x1c, 0x11, 0x12, 0x1a, 0x38, 0x0f, 0x12, 0x1c, 0x00, 0x80, 0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x3a, +0x9d, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5, 0x39, 0xd3, 0xe5, 0x3a, 0x94, 0x00, 0xe5, 0x39, +0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, 0x12, 0x1d, 0x2f, 0x12, 0x1d, 0x84, +0x12, 0x1d, 0x76, 0x12, 0x19, 0xf2, 0x24, 0x6e, 0x60, 0x1e, 0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70, +0x2d, 0x90, 0x00, 0x01, 0x12, 0x1a, 0x0b, 0xff, 0x24, 0xfc, 0x60, 0x03, 0x04, 0x70, 0x1f, 0xef, +0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x11, 0x16, 0x12, 0x1d, 0x8b, 0x12, 0x25, 0x39, 0x12, 0x1c, +0xd9, 0x12, 0x1a, 0x0b, 0x60, 0x03, 0x02, 0x31, 0xbd, 0xe4, 0xff, 0x12, 0x31, 0xb1, 0x22, 0x8b, +0x45, 0x8a, 0x46, 0x89, 0x47, 0x8c, 0x48, 0x8d, 0x49, 0xd2, 0x00, 0x12, 0x2d, 0x82, 0x70, 0x16, +0x12, 0x2d, 0xa1, 0xe5, 0x48, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0x1b, 0x50, 0xf2, 0x12, 0x29, +0x14, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2d, 0xa1, 0x12, 0x29, 0x14, 0x50, 0xf8, 0xe4, 0xf5, +0x4b, 0xe5, 0x4a, 0x14, 0xff, 0xe5, 0x4b, 0xc3, 0x9f, 0x50, 0x17, 0x12, 0x29, 0x04, 0x40, 0x03, +0x7f, 0x18, 0x22, 0x05, 0x4b, 0x74, 0x01, 0x25, 0x47, 0xf5, 0x47, 0xe4, 0x35, 0x46, 0xf5, 0x46, +0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x29, 0x04, 0x40, 0x03, 0x7f, 0x18, +0x22, 0x7f, 0x00, 0x22, 0xab, 0x45, 0xaa, 0x46, 0xa9, 0x47, 0x12, 0x19, 0xf2, 0x90, 0xff, 0xf1, +0xf0, 0x02, 0x31, 0x1b, 0x90, 0xff, 0xf1, 0xe5, 0x49, 0xf0, 0x02, 0x31, 0x1b, 0x7b, 0x01, 0x7a, +0xfa, 0x79, 0xcc, 0xe4, 0xfd, 0x12, 0x22, 0xa0, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x09, 0x12, +0x1a, 0x6c, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12, +0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xff, 0xf7, 0xe5, +0x23, 0x12, 0x29, 0x78, 0x90, 0xff, 0xf6, 0xe5, 0x23, 0xf0, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, +0x74, 0x06, 0x12, 0x29, 0x78, 0xe5, 0x23, 0x30, 0xe0, 0x07, 0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0, +0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, +0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, +0x02, 0x25, 0xd7, 0x90, 0xff, 0x93, 0x74, 0x2a, 0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90, +0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, 0xe0, 0x44, 0x90, 0xf0, 0xe4, 0x90, 0xf9, 0x15, +0xf0, 0xa3, 0xf0, 0x12, 0x2a, 0x78, 0x12, 0x16, 0x42, 0x12, 0x2f, 0xcd, 0x7e, 0x07, 0x7f, 0xd0, +0x12, 0x11, 0xe2, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0xfc, 0xe4, 0x78, 0x77, 0xf6, 0x78, 0x77, +0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x6e, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x77, 0x06, +0x80, 0xec, 0x7f, 0x03, 0x12, 0x2e, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x20, 0xe4, 0x05, 0x7f, 0x04, +0x12, 0x2e, 0xb3, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, 0xe0, +0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x15, 0x65, 0xa8, 0x65, 0xa6, 0x07, 0x30, 0x08, 0x05, 0x12, +0x11, 0x66, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x65, 0xe6, 0xff, 0xb4, 0x03, 0x0f, 0x78, 0x7c, 0x76, +0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, 0x7c, 0x76, 0xff, +0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x80, 0x76, 0xfa, 0x08, 0x76, 0x9b, +0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x22, 0x92, 0x7b, 0x01, 0x7a, 0xff, +0x79, 0x48, 0x78, 0x68, 0x12, 0x1b, 0x31, 0xa8, 0x65, 0xe6, 0x24, 0xfd, 0x75, 0xf0, 0x08, 0xa4, +0xff, 0xae, 0xf0, 0x78, 0x6a, 0x12, 0x22, 0x92, 0x79, 0x08, 0x78, 0x6b, 0x12, 0x1b, 0x31, 0x78, +0x6d, 0xef, 0x12, 0x22, 0x92, 0x05, 0x65, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xab, 0xf0, 0xe0, +0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcc, 0xe4, +0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x7e, 0x00, 0x90, 0xfa, 0xe1, 0xee, 0xf0, +0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcc, 0xe0, 0xb4, 0x52, 0x09, 0x90, 0xf9, +0x15, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe1, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, +0x01, 0x70, 0x10, 0x90, 0xfa, 0xcc, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x10, +0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe3, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x54, 0xef, 0xf0, +0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x12, 0x10, 0x03, 0x78, 0x8a, 0xef, 0xf6, 0x12, +0x2a, 0x06, 0x12, 0x22, 0x33, 0x30, 0xe0, 0x25, 0x12, 0x22, 0x07, 0xe0, 0x54, 0x7f, 0xf0, 0x78, +0x6b, 0x12, 0x1b, 0x28, 0x90, 0x00, 0x02, 0x12, 0x1a, 0x0b, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02, +0xe4, 0x12, 0x1a, 0x4a, 0x80, 0xe9, 0x12, 0x22, 0x07, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x22, 0x33, +0x30, 0xe1, 0x1e, 0x12, 0x21, 0xe9, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x31, 0x5c, 0x78, 0x68, 0x12, +0x1b, 0x28, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x1a, 0x4a, 0x12, 0x21, 0xe9, 0xe0, 0x44, 0x80, +0xf0, 0x12, 0x31, 0xc7, 0xe4, 0xff, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x03, 0x68, 0x01, 0xff, +0x48, 0x03, 0x6b, 0x01, 0xff, 0x08, 0x02, 0x66, 0x00, 0x00, 0x44, 0xfa, 0x95, 0x00, 0x00, 0x00, +0x00, 0x44, 0xfa, 0x91, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xaf, 0x00, 0x00, 0x42, 0xfa, 0x7b, +0x00, 0x00, 0x42, 0xfa, 0x79, 0x00, 0x00, 0x42, 0xf9, 0x6a, 0xff, 0xff, 0x42, 0xfa, 0x77, 0x00, +0x00, 0x43, 0xf9, 0x18, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x65, 0x20, 0x41, 0xf9, 0x66, 0x20, 0x41, +0xf9, 0x63, 0x00, 0x41, 0xf9, 0x64, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf9, +0x15, 0x00, 0x00, 0x41, 0xf9, 0x17, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, +0x10, 0x03, 0x78, 0x85, 0xef, 0xf6, 0x12, 0x30, 0x93, 0x12, 0x30, 0xec, 0x78, 0x85, 0xe6, 0xff, +0x24, 0x12, 0x12, 0x21, 0xff, 0xe0, 0xfe, 0x30, 0xe7, 0x16, 0xef, 0xb4, 0x03, 0x09, 0x90, 0xff, +0x9e, 0xe0, 0x54, 0xfa, 0xf0, 0x80, 0x22, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf5, 0xf0, 0x80, 0x19, +0xee, 0x54, 0x03, 0x60, 0x14, 0xef, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, +0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x17, 0xe0, 0x14, 0xf0, 0xe0, +0x70, 0x02, 0xd2, 0xb3, 0x02, 0x10, 0x86, 0x12, 0x1d, 0x6c, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, +0xe5, 0x39, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x3a, 0x94, 0x08, 0xe5, 0x39, 0x94, 0x00, 0x40, +0x11, 0x7f, 0x08, 0xef, 0xe5, 0x3a, 0x94, 0x08, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5, 0x39, +0x80, 0x05, 0xaf, 0x3a, 0x12, 0x1d, 0x84, 0xe4, 0xfe, 0xee, 0xc3, 0x9f, 0x50, 0x19, 0x12, 0x1c, +0x11, 0x12, 0x19, 0xf2, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed, +0xf0, 0x0e, 0x12, 0x1c, 0x00, 0x80, 0xe2, 0xef, 0x54, 0x7f, 0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b, +0x59, 0x8a, 0x5a, 0x89, 0x5b, 0x12, 0x2d, 0x48, 0x70, 0x05, 0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab, +0x59, 0xaa, 0x5a, 0xa9, 0x5b, 0x12, 0x2d, 0x3c, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x43, 0xe5, 0x5b, +0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5a, 0xfa, 0x90, 0xfa, 0xc0, 0x12, 0x1b, 0x43, 0xe4, 0x90, 0xfa, +0xbf, 0xf0, 0x78, 0x8b, 0xf6, 0x90, 0xfa, 0xbe, 0xe0, 0xff, 0x78, 0x8b, 0xe6, 0xc3, 0x9f, 0x50, +0x12, 0x12, 0x2d, 0x1a, 0xff, 0x12, 0x2d, 0x23, 0x12, 0x2d, 0x36, 0x78, 0x8b, 0x06, 0x12, 0x2d, +0x32, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x31, 0x4d, 0xe4, 0x93, 0xff, 0x78, 0x74, +0xf6, 0x54, 0x0f, 0x12, 0x1c, 0xf8, 0xe0, 0x08, 0x76, 0x00, 0x08, 0xf6, 0x18, 0x12, 0x1c, 0x29, +0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x75, 0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee, +0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, 0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00, +0x22, 0x78, 0x75, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, +0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58, 0x90, +0x00, 0x03, 0x12, 0x1a, 0x0b, 0x54, 0xf0, 0x24, 0xa0, 0x22, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x3a, +0x02, 0x19, 0xf2, 0x90, 0xfa, 0xc0, 0x12, 0x1b, 0x3a, 0xef, 0x12, 0x1a, 0x38, 0x90, 0xfa, 0xc7, +0xe4, 0x22, 0x90, 0xfa, 0xc1, 0xe4, 0x75, 0xf0, 0x01, 0x02, 0x1a, 0x6c, 0x90, 0x00, 0x08, 0x12, +0x1a, 0x98, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0x90, 0xfa, +0xbe, 0xf0, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58, 0x22, 0x90, 0xfa, 0xda, 0xe0, 0xff, 0x7e, +0x00, 0xc3, 0x90, 0xfa, 0xd4, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xd3, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, +0xd5, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0xef, 0x25, 0x51, 0xf5, 0x51, 0xee, 0x35, 0x50, 0xf5, +0x50, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe3, +0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x29, 0xaa, 0x2a, 0xa9, 0x2b, 0x02, 0x1a, +0x38, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x64, 0xed, 0x70, 0x0f, 0xe5, 0x64, 0xb4, +0x03, 0x05, 0x7f, 0x01, 0x02, 0x31, 0x32, 0x7f, 0x02, 0x02, 0x31, 0x32, 0xaf, 0x64, 0x12, 0x2a, +0x06, 0x74, 0x6e, 0x25, 0x64, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, 0xd2, 0x09, 0x12, 0x1c, 0x83, 0xe0, +0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x64, 0xb4, 0x03, 0x07, 0x7f, 0x81, 0x12, 0x31, +0x32, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x31, 0x32, 0x30, 0x09, 0x07, 0x12, 0x1c, 0x83, 0xe0, 0x44, +0x80, 0xf0, 0x12, 0x31, 0xc7, 0x22, 0x12, 0x10, 0x03, 0x90, 0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0, +0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13, +0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x35, 0x80, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01, +0xf0, 0x80, 0x0d, 0x12, 0x1d, 0x2f, 0x53, 0x35, 0x7f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0, +0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0xb0, 0x12, 0x1d, 0x37, 0x02, 0x10, 0x86, +0x12, 0x10, 0x03, 0x78, 0x89, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x2a, 0x06, 0x90, 0xf9, 0x67, 0x12, +0x1b, 0x3a, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x80, 0xe6, 0xfe, 0x08, +0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x22, 0x25, 0x12, 0x31, 0xc7, +0x78, 0x89, 0xe6, 0xff, 0x12, 0x13, 0x3f, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x8f, 0x63, 0x12, +0x2a, 0x06, 0x12, 0x22, 0x07, 0xe0, 0x54, 0x3f, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x21, 0xf3, +0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, 0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x21, 0xf3, +0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x63, 0xf8, 0x74, 0xfb, 0x56, 0xf6, +0x7f, 0x00, 0x22, 0x8f, 0x23, 0xc2, 0x08, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x12, 0x78, 0x7e, 0x12, +0x21, 0xeb, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x22, 0x4a, 0x12, 0x21, 0xef, 0xe0, 0x20, 0xe0, 0xf6, +0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x31, 0xc7, +0xaf, 0x23, 0x12, 0x13, 0x3f, 0x22, 0x12, 0x10, 0x03, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x4a, 0x24, +0x06, 0x12, 0x21, 0xf1, 0xe0, 0xfd, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x03, 0x12, 0x22, 0x52, 0x24, +0x05, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x00, 0x04, 0x12, 0x1a, 0x4a, 0x12, 0x31, 0xc7, 0x7d, 0x02, +0xe4, 0xff, 0x12, 0x2f, 0x18, 0x02, 0x10, 0x86, 0xae, 0x05, 0x12, 0x1c, 0xde, 0xef, 0x12, 0x1a, +0x4a, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x3c, 0xe4, 0x95, 0x3b, 0x40, 0x02, 0xae, 0x3c, 0xee, +0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, 0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, +0x12, 0x1a, 0x4a, 0xaf, 0x06, 0x12, 0x31, 0xb1, 0x22, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, +0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, 0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, +0x74, 0x6e, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, 0x74, 0x96, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, +0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, 0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, +0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, +0x12, 0x21, 0xf3, 0xe0, 0x44, 0x80, 0xf0, 0x74, 0x6e, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, +0x00, 0x22, 0x12, 0x10, 0x03, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60, +0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, 0xc3, 0xe5, 0x3a, 0x9f, 0xe5, 0x39, 0x94, 0x00, +0x40, 0x05, 0x12, 0x28, 0x16, 0x80, 0x03, 0x12, 0x31, 0xbd, 0x02, 0x10, 0x86, 0x90, 0xff, 0xfc, +0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, 0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, +0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, 0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, +0xf0, 0x80, 0xef, 0x22, 0x12, 0x10, 0x03, 0x78, 0x66, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, +0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x12, 0x19, +0x12, 0x1d, 0x46, 0x02, 0x10, 0x86, 0x8e, 0x5f, 0x8f, 0x60, 0xe5, 0x60, 0x15, 0x60, 0xae, 0x5f, +0x70, 0x02, 0x15, 0x5f, 0xd3, 0x94, 0x00, 0xee, 0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, +0x12, 0x0f, 0xdc, 0x80, 0xe5, 0x22, 0x11, 0x94, 0x2d, 0xf6, 0x23, 0xef, 0x31, 0xa3, 0x2f, 0xf4, +0x2f, 0xa2, 0x30, 0xb2, 0x2e, 0xe6, 0x26, 0x6d, 0x2b, 0xaf, 0x30, 0x55, 0x30, 0x74, 0x1d, 0xb4, +0x2e, 0x40, 0x2a, 0xe8, 0x0e, 0x12, 0x10, 0x03, 0x78, 0x86, 0x12, 0x22, 0x82, 0x20, 0xe1, 0x07, +0x7f, 0x12, 0x12, 0x30, 0xec, 0x80, 0x0a, 0x78, 0x86, 0xe6, 0xff, 0x12, 0x23, 0x49, 0x12, 0x30, +0xec, 0x02, 0x10, 0x86, 0x12, 0x10, 0x03, 0x78, 0x87, 0x12, 0x22, 0x82, 0x20, 0xe2, 0x07, 0x7f, +0x11, 0x12, 0x30, 0xec, 0x80, 0x0a, 0x78, 0x87, 0xe6, 0xff, 0x12, 0x2e, 0x7d, 0x12, 0x30, 0xec, +0x02, 0x10, 0x86, 0x8f, 0x61, 0x12, 0x2e, 0x7d, 0xaf, 0x61, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x12, +0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x61, 0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x61, 0x12, 0x13, +0x3f, 0x22, 0x12, 0x10, 0x03, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60, +0x05, 0x12, 0x2c, 0x07, 0x80, 0x06, 0x12, 0x1d, 0x64, 0x12, 0x1d, 0x6c, 0x02, 0x10, 0x86, 0x12, +0x29, 0x93, 0x12, 0x12, 0xbb, 0x90, 0xf8, 0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x12, +0x58, 0x12, 0x29, 0x1d, 0x12, 0x12, 0xf7, 0x12, 0x11, 0x74, 0x80, 0xe3, 0x12, 0x1c, 0xde, 0xef, +0x12, 0x1a, 0x4a, 0xe4, 0xf5, 0x33, 0xf5, 0x34, 0xef, 0x60, 0x03, 0x02, 0x31, 0xbd, 0xe4, 0xff, +0x12, 0x31, 0xb1, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, +0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, +0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, +0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, 0x1c, 0x95, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, +0x1c, 0xe8, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, +0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x7e, 0x12, 0x22, +0x09, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, +0x3b, 0x39, 0x85, 0x3c, 0x3a, 0x90, 0xff, 0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, +0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x31, 0x47, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, +0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, 0x28, 0x38, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x12, 0x10, 0x03, 0x7f, 0x02, 0x12, 0x10, 0x92, 0x12, 0x1d, 0x46, 0x02, 0x10, +0x86, 0x75, 0x39, 0x00, 0x8f, 0x3a, 0x12, 0x1c, 0x30, 0x12, 0x2c, 0x07, 0x22, 0x12, 0x1d, 0x6c, +0x12, 0x1d, 0x2f, 0x12, 0x1d, 0x64, 0x22, 0xc2, 0x08, 0x22, }; #undef IMAGE_VERSION_NAME diff -Nru a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h --- a/drivers/usb/serial/io_tables.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/serial/io_tables.h 2004-10-18 14:56:33 -07:00 @@ -14,22 +14,12 @@ #ifndef IO_TABLES_H #define IO_TABLES_H -static struct usb_device_id edgeport_1port_id_table [] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) }, - { } -}; - static struct usb_device_id edgeport_2port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) }, { } }; @@ -41,12 +31,9 @@ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) }, { } }; @@ -54,9 +41,9 @@ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, { } }; @@ -69,7 +56,6 @@ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, @@ -77,50 +63,17 @@ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, id_table_combined); - -static struct usb_serial_device_type edgeport_1port_device = { - .owner = THIS_MODULE, - .name = "Edgeport 1 port adapter", - .short_name = "edgeport_1", - .id_table = edgeport_1port_id_table, - .num_interrupt_in = 1, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .shutdown = edge_shutdown, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, -}; static struct usb_serial_device_type edgeport_2port_device = { .owner = THIS_MODULE, diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- a/drivers/usb/serial/io_ti.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/serial/io_ti.c 2004-10-18 14:57:04 -07:00 @@ -124,15 +124,11 @@ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, { } }; @@ -143,15 +139,11 @@ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, { } }; @@ -278,7 +270,7 @@ { int status = 0; __u8 read_length; - __u16 be_start_address; + __be16 be_start_address; dbg ("%s - @ %x for %d", __FUNCTION__, start_address, length); @@ -395,7 +387,7 @@ { int status = 0; int write_length; - __u16 be_start_address; + __be16 be_start_address; /* We can only send a maximum of 1 aligned byte page at a time */ @@ -1804,12 +1796,7 @@ tty = port->tty; if (tty) { /* let the tty driver wakeup if it has a special write_wakeup function */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - (tty->ldisc.write_wakeup)(tty); - } - - /* tell the tty driver that something has changed */ - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } diff -Nru a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h --- a/drivers/usb/serial/io_usbvend.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/serial/io_usbvend.h 2004-10-18 14:56:49 -07:00 @@ -18,14 +18,6 @@ #if !defined(_USBVEND_H) #define _USBVEND_H -#ifndef __KERNEL__ -#include "ionprag.h" /* Extra I/O Networks pragmas */ - -#include - -#include "iondef.h" /* Standard I/O Networks definitions */ -#endif - /************************************************************************ * * D e f i n e s / T y p e d e f s @@ -37,6 +29,7 @@ // #define USB_VENDOR_ID_ION 0x1608 // Our VID +#define USB_VENDOR_ID_TI 0x0451 // TI VID // // Definitions of USB product IDs (PID) @@ -48,36 +41,41 @@ // ION-device OEM IDs #define ION_OEM_ID_ION 0 // 00h Inside Out Networks -#define ION_OEM_ID_NLYNX 1 // 01h NLynx Systems +#define ION_OEM_ID_NLYNX 1 // 01h NLynx Systems #define ION_OEM_ID_GENERIC 2 // 02h Generic OEM #define ION_OEM_ID_MAC 3 // 03h Mac Version #define ION_OEM_ID_MEGAWOLF 4 // 04h Lupusb OEM Mac version (MegaWolf) #define ION_OEM_ID_MULTITECH 5 // 05h Multitech Rapidports +#define ION_OEM_ID_AGILENT 6 // 06h AGILENT board - -// ION-device Device IDs -// Product IDs - assigned to match middle digit of serial number +// ION-device Device IDs +// Product IDs - assigned to match middle digit of serial number (No longer true) -// The ION_DEVICE_ID_GENERATION_2 bit (0x20) will be ORed into the existing edgeport -// PIDs to identify 80251+Netchip hardware. This will guarantee that if a second -// generation edgeport device is plugged into a PC with an older (pre 2.0) driver, -// it will not enumerate. +#define ION_DEVICE_ID_80251_NETCHIP 0x020 // This bit is set in the PID if this edgeport hardware$ + // is based on the 80251+Netchip. -#define ION_DEVICE_ID_GENERATION_2 0x020 // This bit is set in the PID if this edgeport hardware - // is based on the 80251+Netchip. +#define ION_DEVICE_ID_GENERATION_1 0x00 // Value for 930 based edgeports +#define ION_DEVICE_ID_GENERATION_2 0x01 // Value for 80251+Netchip. +#define ION_DEVICE_ID_GENERATION_3 0x02 // Value for Texas Instruments TUSB5052 chip +#define ION_DEVICE_ID_GENERATION_4 0x03 // Watchport Family of products +#define ION_GENERATION_MASK 0x03 + +#define ION_DEVICE_ID_HUB_MASK 0x0080 // This bit in the PID designates a HUB device + // for example 8C would be a 421 4 port hub + // and 8D would be a 2 port embedded hub -#define EDGEPORT_DEVICE_ID_MASK 0x3df // Not including GEN_2 bit +#define EDGEPORT_DEVICE_ID_MASK 0x0ff // Not including OEM or GENERATION fields #define ION_DEVICE_ID_UNCONFIGURED_EDGE_DEVICE 0x000 // In manufacturing only #define ION_DEVICE_ID_EDGEPORT_4 0x001 // Edgeport/4 RS232 -// ION_DEVICE_ID_HUBPORT_7 0x002 // Hubport/7 (Placeholder, not used by software) +#define ION_DEVICE_ID_EDGEPORT_8R 0x002 // Edgeport with RJ45 no Ring #define ION_DEVICE_ID_RAPIDPORT_4 0x003 // Rapidport/4 #define ION_DEVICE_ID_EDGEPORT_4T 0x004 // Edgeport/4 RS232 for Telxon (aka "Fleetport") #define ION_DEVICE_ID_EDGEPORT_2 0x005 // Edgeport/2 RS232 #define ION_DEVICE_ID_EDGEPORT_4I 0x006 // Edgeport/4 RS422 #define ION_DEVICE_ID_EDGEPORT_2I 0x007 // Edgeport/2 RS422/RS485 -// ION_DEVICE_ID_HUBPORT_4 0x008 // Hubport/4 (Placeholder, not used by software) +#define ION_DEVICE_ID_EDGEPORT_8RR 0x008 // Edgeport with RJ45 with Data and RTS/CTS only // ION_DEVICE_ID_EDGEPORT_8_HANDBUILT 0x009 // Hand-built Edgeport/8 (Placeholder, used in middle digit of serial number only!) // ION_DEVICE_ID_MULTIMODEM_4X56 0x00A // MultiTech version of RP/4 (Placeholder, used in middle digit of serial number only!) #define ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT 0x00B // Edgeport/(4)21 Parallel port (USS720) @@ -90,41 +88,134 @@ #define ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU 0x012 // Half of an Edgeport/16 (the kind with 2 EP/8s) #define ION_DEVICE_ID_EDGEPORT_COMPATIBLE 0x013 // Edgeport Compatible, for NCR, Axiohm etc. testing #define ION_DEVICE_ID_EDGEPORT_8I 0x014 // Edgeport/8 RS422 (single-CPU) +#define ION_DEVICE_ID_EDGEPORT_1 0x015 // Edgeport/1 RS232 +#define ION_DEVICE_ID_EPOS44 0x016 // Half of an EPOS/44 (TIUMP BASED) +#define ION_DEVICE_ID_EDGEPORT_42 0x017 // Edgeport/42 +#define ION_DEVICE_ID_EDGEPORT_412_8 0x018 // Edgeport/412 8 port part +#define ION_DEVICE_ID_EDGEPORT_412_4 0x019 // Edgeport/412 4 port part +#define ION_DEVICE_ID_EDGEPORT_22I 0x01A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 + +// Compact Form factor TI based devices 2c, 21c, 22c, 221c +#define ION_DEVICE_ID_EDGEPORT_2C 0x01B // Edgeport/2c is a TI based Edgeport/2 - Small I2c +#define ION_DEVICE_ID_EDGEPORT_221C 0x01C // Edgeport/221c is a TI based Edgeport/2 with lucent chip and + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_EDGEPORT_22C 0x01D // Edgeport/22c is a TI based Edgeport/2 with + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_EDGEPORT_21C 0x01E // Edgeport/21c is a TI based Edgeport/2 with lucent chip + // Small I2C + + +/* + * DANGER DANGER The 0x20 bit was used to indicate a 8251/netchip GEN 2 device. + * Since the MAC, Linux, and Optimal drivers still used the old code + * I suggest that you skip the 0x20 bit when creating new PIDs + */ + + +// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) +#define ION_DEVICE_ID_TI3410_EDGEPORT_1 0x040 // Edgeport/1 RS232 +#define ION_DEVICE_ID_TI3410_EDGEPORT_1I 0x041 // Edgeport/1i- RS422 model + +// Ti based software switchable RS232/RS422/RS485 devices +#define ION_DEVICE_ID_EDGEPORT_4S 0x042 // Edgeport/4s - software switchable model +#define ION_DEVICE_ID_EDGEPORT_8S 0x043 // Edgeport/8s - software switchable model + +// Usb to Ethernet dongle +#define ION_DEVICE_ID_EDGEPORT_E 0x0E0 // Edgeport/E Usb to Ethernet + +// Edgeport TI based devices +#define ION_DEVICE_ID_TI_EDGEPORT_4 0x0201 // Edgeport/4 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_2 0x0205 // Edgeport/2 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_4I 0x0206 // Edgeport/4i RS422 +#define ION_DEVICE_ID_TI_EDGEPORT_2I 0x0207 // Edgeport/2i RS422/RS485 +#define ION_DEVICE_ID_TI_EDGEPORT_421 0x020C // Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) +#define ION_DEVICE_ID_TI_EDGEPORT_21 0x020D // Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) +#define ION_DEVICE_ID_TI_EDGEPORT_8 0x020F // Edgeport/8 (single-CPU) +#define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 // Edgeport/1 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 // Edgeport/42 4 hub 2 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_22I 0x021A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_2C 0x021B // Edgeport/2c RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_221C 0x021C // Edgeport/221c is a TI based Edgeport/2 with lucent chip and + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_TI_EDGEPORT_22C 0x021D // Edgeport/22c is a TI based Edgeport/2 with + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_TI_EDGEPORT_21C 0x021E // Edgeport/21c is a TI based Edgeport/2 with lucent chip + +// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) +#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1 0x240 // Edgeport/1 RS232 +#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I 0x241 // Edgeport/1i- RS422 model + +// Ti based software switchable RS232/RS422/RS485 devices +#define ION_DEVICE_ID_TI_EDGEPORT_4S 0x242 // Edgeport/4s - software switchable model +#define ION_DEVICE_ID_IT_EDGEPORT_8S 0x243 // Edgeport/8s - software switchable model + + +/************************************************************************ + * + * Generation 4 devices + * + ************************************************************************/ + +// Watchport based on 3410 both 1-wire and binary products (16K I2C) +#define ION_DEVICE_ID_WP_UNSERIALIZED 0x300 // Watchport based on 3410 both 1-wire and binary products +#define ION_DEVICE_ID_WP_PROXIMITY 0x301 // Watchport/P Discontinued +#define ION_DEVICE_ID_WP_MOTION 0x302 // Watchport/M +#define ION_DEVICE_ID_WP_MOISTURE 0x303 // Watchport/W +#define ION_DEVICE_ID_WP_TEMPERATURE 0x304 // Watchport/T +#define ION_DEVICE_ID_WP_HUMIDITY 0x305 // Watchport/H + +#define ION_DEVICE_ID_WP_POWER 0x306 // Watchport +#define ION_DEVICE_ID_WP_LIGHT 0x307 // Watchport +#define ION_DEVICE_ID_WP_RADIATION 0x308 // Watchport +#define ION_DEVICE_ID_WP_ACCELERATION 0x309 // Watchport/A +#define ION_DEVICE_ID_WP_DISTANCE 0x30A // Watchport/D Discontinued +#define ION_DEVICE_ID_WP_PROX_DIST 0x30B // Watchport/D uses distance sensor + // Default to /P function + +#define ION_DEVICE_ID_PLUS_PWR_HP4CD 0x30C // 5052 Plus Power HubPort/4CD+ (for Dell) +#define ION_DEVICE_ID_PLUS_PWR_HP4C 0x30D // 5052 Plus Power HubPort/4C+ +#define ION_DEVICE_ID_PLUS_PWR_PCI 0x30E // 3410 Plus Power PCI Host Controller 4 port + + +// +// Definitions for AXIOHM USB product IDs +// +#define USB_VENDOR_ID_AXIOHM 0x05D9 // Axiohm VID + +#define AXIOHM_DEVICE_ID_MASK 0xffff +#define AXIOHM_DEVICE_ID_EPIC_A758 0xA758 +#define AXIOHM_DEVICE_ID_EPIC_A794 0xA794 +#define AXIOHM_DEVICE_ID_EPIC_A225 0xA225 + + +// +// Definitions for NCR USB product IDs +// +#define USB_VENDOR_ID_NCR 0x0404 // NCR VID + +#define NCR_DEVICE_ID_MASK 0xffff +#define NCR_DEVICE_ID_EPIC_0202 0x0202 +#define NCR_DEVICE_ID_EPIC_0203 0x0203 +#define NCR_DEVICE_ID_EPIC_0310 0x0310 +#define NCR_DEVICE_ID_EPIC_0311 0x0311 +#define NCR_DEVICE_ID_EPIC_0312 0x0312 + + +// +// Definitions for SYMBOL USB product IDs +// +#define USB_VENDOR_ID_SYMBOL 0x05E0 // Symbol VID +#define SYMBOL_DEVICE_ID_MASK 0xffff +#define SYMBOL_DEVICE_ID_KEYFOB 0x0700 + + +// +// Definitions for other product IDs #define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device -// BlackBox OEM devices -#define ION_DEVICE_ID_BB_EDGEPORT_4 0x001 // Edgeport/4 RS232 -#define ION_DEVICE_ID_BB_EDGEPORT_4T 0x004 // Edgeport/4 RS232 for Telxon (aka "Fleetport") -#define ION_DEVICE_ID_BB_EDGEPORT_2 0x005 // Edgeport/2 RS232 -#define ION_DEVICE_ID_BB_EDGEPORT_4I 0x006 // Edgeport/4 RS422 -#define ION_DEVICE_ID_BB_EDGEPORT_2I 0x007 // Edgeport/2 RS422/RS485 -#define ION_DEVICE_ID_BB_EDGEPORT_421 0x00C // Edgeport/421 Hub+RS232+Parallel -#define ION_DEVICE_ID_BB_EDGEPORT_21 0x00D // Edgeport/21 RS232+Parallel -#define ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU 0x00E // Half of an Edgeport/8 (the kind with 2 EP/4s on 1 PCB) -#define ION_DEVICE_ID_BB_EDGEPORT_8 0x00F // Edgeport/8 (single-CPU) -#define ION_DEVICE_ID_BB_EDGEPORT_2_DIN 0x010 // Edgeport/2 RS232 with Apple DIN connector -#define ION_DEVICE_ID_BB_EDGEPORT_4_DIN 0x011 // Edgeport/4 RS232 with Apple DIN connector -#define ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU 0x012 // Half of an Edgeport/16 (the kind with 2 EP/8s) -#define ION_DEVICE_ID_BB_EDGEPORT_8I 0x014 // Edgeport/8 RS422 (single-CPU) - - -/* Edgeport TI based devices */ -#define ION_DEVICE_ID_TI_EDGEPORT_4 0x0201 /* Edgeport/4 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_2 0x0205 /* Edgeport/2 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_4I 0x0206 /* Edgeport/4i RS422 */ -#define ION_DEVICE_ID_TI_EDGEPORT_2I 0x0207 /* Edgeport/2i RS422/RS485 */ -#define ION_DEVICE_ID_TI_EDGEPORT_421 0x020C /* Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) */ -#define ION_DEVICE_ID_TI_EDGEPORT_21 0x020D /* Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) */ -#define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 /* Edgeport/1 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 /* Edgeport/42 4 hub 2 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_22 0x021A /* Edgeport/22 Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_2C 0x021B /* Edgeport/2c RS232 */ - -#define ION_DEVICE_ID_TI_EDGEPORT_421_BOOT 0x0240 /* Edgeport/421 in boot mode */ -#define ION_DEVICE_ID_TI_EDGEPORT_421_DOWN 0x0241 /* Edgeport/421 in download mode first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */ -#define ION_DEVICE_ID_TI_EDGEPORT_21_BOOT 0x0242 /* Edgeport/21 in boot mode */ -#define ION_DEVICE_ID_TI_EDGEPORT_21_DOWN 0x0243 /*Edgeport/42 in download mode: first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */ +#define GENERATION_ID_FROM_USB_PRODUCT_ID( ProductId ) \ + ( (__u16) ((ProductId >> 8) & (ION_GENERATION_MASK)) ) #define MAKE_USB_PRODUCT_ID( OemId, DeviceId ) \ ( (__u16) (((OemId) << 10) || (DeviceId)) ) @@ -143,7 +234,7 @@ // TxCredits value below which driver won't bother sending (to prevent too many small writes). // Send only if above 25% -#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit) (max(((InitialCredit) / 4), EDGE_FW_BULK_MAX_PACKET_SIZE)) +#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit, MaxPacketSize) (max( ((InitialCredit) / 4), (MaxPacketSize) )) #define EDGE_FW_BULK_MAX_PACKET_SIZE 64 // Max Packet Size for Bulk In Endpoint (EP1) #define EDGE_FW_BULK_READ_BUFFER_SIZE 1024 // Size to use for Bulk reads @@ -158,8 +249,8 @@ // Definitions of I/O Networks vendor-specific requests // for default endpoint // -// bmRequestType = 00100000 Set vendor-specific, to device -// bmRequestType = 10100000 Get vendor-specific, to device +// bmRequestType = 01000000 Set vendor-specific, to device +// bmRequestType = 11000000 Get vendor-specific, to device // // These are the definitions for the bRequest field for the // above bmRequestTypes. @@ -184,11 +275,87 @@ #define USB_REQUEST_ION_ENABLE_SUSPEND 9 // Enable/Disable suspend feature // (wValue != 0: Enable; wValue = 0: Disable) +#define USB_REQUEST_ION_SEND_IOSP 10 // Send an IOSP command to the edgeport over the control pipe +#define USB_REQUEST_ION_RECV_IOSP 11 // Receive an IOSP command from the edgeport over the control pipe + + +#define USB_REQUEST_ION_DIS_INT_TIMER 0x80 // Sent to Axiohm to enable/ disable + // interrupt token timer + // wValue = 1, enable (default) + // wValue = 0, disable // // Define parameter values for our vendor-specific commands // +// +// Edgeport Compatiblity Descriptor +// +// This descriptor is only returned by Edgeport-compatible devices +// supporting the EPiC spec. True ION devices do not return this +// descriptor, but instead return STALL on receipt of the +// GET_EPIC_DESC command. The driver interprets a STALL to mean that +// this is a "real" Edgeport. +// + +struct edge_compatibility_bits +{ + // This __u32 defines which Vendor-specific commands/functionality + // the device supports on the default EP0 pipe. + + __u32 VendEnableSuspend : 1; // 0001 Set if device supports ION_ENABLE_SUSPEND + __u32 VendUnused : 31; // Available for future expansion, must be 0 + + // This __u32 defines which IOSP commands are supported over the + // bulk pipe EP1. + + // xxxx Set if device supports: + __u32 IOSPOpen : 1; // 0001 OPEN / OPEN_RSP (Currently must be 1) + __u32 IOSPClose : 1; // 0002 CLOSE + __u32 IOSPChase : 1; // 0004 CHASE / CHASE_RSP + __u32 IOSPSetRxFlow : 1; // 0008 SET_RX_FLOW + __u32 IOSPSetTxFlow : 1; // 0010 SET_TX_FLOW + __u32 IOSPSetXChar : 1; // 0020 SET_XON_CHAR/SET_XOFF_CHAR + __u32 IOSPRxCheck : 1; // 0040 RX_CHECK_REQ/RX_CHECK_RSP + __u32 IOSPSetClrBreak : 1; // 0080 SET_BREAK/CLEAR_BREAK + __u32 IOSPWriteMCR : 1; // 0100 MCR register writes (set/clr DTR/RTS) + __u32 IOSPWriteLCR : 1; // 0200 LCR register writes (wordlen/stop/parity) + __u32 IOSPSetBaudRate : 1; // 0400 setting Baud rate (writes to LCR.80h and DLL/DLM register) + __u32 IOSPDisableIntPipe : 1; // 0800 Do not use the interrupt pipe for TxCredits or RxButesAvailable + __u32 IOSPRxDataAvail : 1; // 1000 Return status of RX Fifo (Data available in Fifo) + __u32 IOSPTxPurge : 1; // 2000 Purge TXBuffer and/or Fifo in Edgeport hardware + __u32 IOSPUnused : 18; // Available for future expansion, must be 0 + + // This __u32 defines which 'general' features are supported + + __u32 TrueEdgeport : 1; // 0001 Set if device is a 'real' Edgeport + // (Used only by driver, NEVER set by an EPiC device) + __u32 GenUnused : 31; // Available for future expansion, must be 0 + +}; + +struct edge_compatibility_descriptor +{ + __u8 Length; // Descriptor Length (per USB spec) + __u8 DescType; // Descriptor Type (per USB spec, =DEVICE type) + __u8 EpicVer; // Version of EPiC spec supported + // (Currently must be 1) + __u8 NumPorts; // Number of serial ports supported + __u8 iDownloadFile; // Index of string containing download code filename + // 0=no download, FF=download compiled into driver. + __u8 Unused[ 3 ]; // Available for future expansion, must be 0 + // (Currently must be 0). + __u8 MajorVersion; // Firmware version: xx. + __u8 MinorVersion; // yy. + __le16 BuildNumber; // zzzz (LE format) + + // The following structure contains __u32s, with each bit + // specifying whether the EPiC device supports the given + // command or functionality. + + struct edge_compatibility_bits Supports; + +}; // Values for iDownloadFile #define EDGE_DOWNLOAD_FILE_NONE 0 // No download requested @@ -272,30 +439,30 @@ __u8 NumPorts; // F08 Number of ports __u8 DescDate[3]; // F09 MM/DD/YY when descriptor template was compiler, - // so host can track changes to USB-only descriptors. + // so host can track changes to USB-only descriptors. __u8 SerNumLength; // F0C USB string descriptor len __u8 SerNumDescType; // F0D USB descriptor type (=STRING type) - __u16 SerialNumber[MAX_SERIALNUMBER_LEN]; // F0E "01-01-000100" Unicode Serial Number + __le16 SerialNumber[MAX_SERIALNUMBER_LEN]; // F0E "01-01-000100" Unicode Serial Number __u8 AssemblyNumLength; // F26 USB string descriptor len __u8 AssemblyNumDescType; // F27 USB descriptor type (=STRING type) - __u16 AssemblyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F28 "350-1000-01-A " assembly number + __le16 AssemblyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F28 "350-1000-01-A " assembly number __u8 OemAssyNumLength; // F44 USB string descriptor len __u8 OemAssyNumDescType; // F45 USB descriptor type (=STRING type) - __u16 OemAssyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F46 "xxxxxxxxxxxxxx" OEM assembly number + __le16 OemAssyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F46 "xxxxxxxxxxxxxx" OEM assembly number __u8 ManufDateLength; // F62 USB string descriptor len __u8 ManufDateDescType; // F63 USB descriptor type (=STRING type) - __u16 ManufDate[6]; // F64 "MMDDYY" manufacturing date + __le16 ManufDate[6]; // F64 "MMDDYY" manufacturing date __u8 Reserved3[0x4D]; // F70 -- unused, set to 0 -- __u8 UartType; // FBD Uart Type __u8 IonPid; // FBE Product ID, == LSB of USB DevDesc.PID - // (Note: Edgeport/4s before 11/98 will have - // 00 here instead of 01) + // (Note: Edgeport/4s before 11/98 will have + // 00 here instead of 01) __u8 IonConfig; // FBF Config byte for ION manufacturing use // FBF end of structure, total len = 3C0h @@ -312,7 +479,7 @@ // both 00 and 01 values mean '654. #define MANUF_UART_EXAR_654_EARLY 0 // Exar 16C654 in Edgeport/4s before 11/98 #define MANUF_UART_EXAR_654 1 // Exar 16C654 -#define MANUF_UART_EXAR_2852 2 // Exar 16C2852 +#define MANUF_UART_EXAR_2852 2 // Exar 16C2852 // // Note: The CpuRev and BoardRev values do not conform to manufacturing @@ -334,25 +501,22 @@ #define MANUF_BOARD_REV_GENERATION_2 0x20 // Second generaiton edgeport - - // Values of bottom 5 bits of CpuRev & BoardRev for // Implementation 1 (ie, 251+Netchip-based) #define MANUF_CPU_REV_1 1 // C251TB Rev 1 (Need actual Intel rev here) #define MANUF_BOARD_REV_A 1 // First rev of 251+Netchip design - - #define MANUF_SERNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->SerialNumber) #define MANUF_ASSYNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->AssemblyNumber) #define MANUF_OEMASSYNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->OemAssyNumber) #define MANUF_MANUFDATE_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->ManufDate) -#define MANUF_ION_CONFIG_MASTER 0x80 // 1=Master mode, 0=Normal -#define MANUF_ION_CONFIG_DIAG 0x40 // 1=Run h/w diags, 0=norm -#define MANUF_ION_CONFIG_DIAG_NO_LOOP 0x20 // As above but no ext loopback test - +#define MANUF_ION_CONFIG_DIAG_NO_LOOP 0x20 // As below but no ext loopback test +#define MANUF_ION_CONFIG_DIAG 0x40 // 930 based device: 1=Run h/w diags, 0=norm + // TIUMP Device : 1=IONSERIAL needs to run Final Test +#define MANUF_ION_CONFIG_MASTER 0x80 // 930 based device: 1=Master mode, 0=Normal + // TIUMP Device : 1=First device on a multi TIUMP Device // // This structure describes parameters for the boot code, and @@ -368,19 +532,19 @@ __u8 DescVer; // C2 Desc version/format __u8 Reserved1; // C3 -- unused, set to 0 -- - __u16 BootCodeLength; // C4 Boot code goes from FF:0000 to FF:(len-1) + __le16 BootCodeLength; // C4 Boot code goes from FF:0000 to FF:(len-1) // (LE format) __u8 MajorVersion; // C6 Firmware version: xx. __u8 MinorVersion; // C7 yy. - __u16 BuildNumber; // C8 zzzz (LE format) + __le16 BuildNumber; // C8 zzzz (LE format) __u16 EnumRootDescTable; // CA Root of ROM-based descriptor table __u8 NumDescTypes; // CC Number of supported descriptor types __u8 Reserved4; // CD Fix Compiler Packing - __u16 Capabilities; // CE-CF Capabilities flags (LE format) + __le16 Capabilities; // CE-CF Capabilities flags (LE format) __u8 Reserved2[0x28]; // D0 -- unused, set to 0 -- __u8 UConfig0; // F8 930-defined CPU configuration byte 0 __u8 UConfig1; // F9 930-defined CPU configuration byte 1 @@ -398,23 +562,29 @@ #define BOOT_CAP_RESET_CMD 0x0001 // If set, boot correctly supports ION_RESET_DEVICE - /************************************************************************ T I U M P D E F I N I T I O N S ***********************************************************************/ +// Chip definitions in I2C +#define UMP5152 0x52 +#define UMP3410 0x10 + + //************************************************************************ // TI I2C Format Definitions //************************************************************************ -#define I2C_DESC_TYPE_INFO_BASIC 1 -#define I2C_DESC_TYPE_FIRMWARE_BASIC 2 -#define I2C_DESC_TYPE_DEVICE 3 -#define I2C_DESC_TYPE_CONFIG 4 -#define I2C_DESC_TYPE_STRING 5 -#define I2C_DESC_TYPE_FIRMWARE_BLANK 0xf2 +#define I2C_DESC_TYPE_INFO_BASIC 0x01 +#define I2C_DESC_TYPE_FIRMWARE_BASIC 0x02 +#define I2C_DESC_TYPE_DEVICE 0x03 +#define I2C_DESC_TYPE_CONFIG 0x04 +#define I2C_DESC_TYPE_STRING 0x05 +#define I2C_DESC_TYPE_FIRMWARE_AUTO 0x07 // for 3410 download +#define I2C_DESC_TYPE_CONFIG_KLUDGE 0x14 // for 3410 +#define I2C_DESC_TYPE_WATCHPORT_VERSION 0x15 // firmware version number for watchport +#define I2C_DESC_TYPE_WATCHPORT_CALIBRATION_DATA 0x16 // Watchport Calibration Data -#define I2C_DESC_TYPE_MAX 5 -// 3410 may define types 6, 7 for other firmware downloads +#define I2C_DESC_TYPE_FIRMWARE_BLANK 0xf2 // Special section defined by ION #define I2C_DESC_TYPE_ION 0 // Not defined by TI @@ -428,7 +598,9 @@ __u8 Data[0]; // Data starts here }__attribute__((packed)); -struct ti_i2c_firmware_rec +// for 5152 devices only (type 2 record) +// for 3410 the version is stored in the WATCHPORT_FIRMWARE_VERSION descriptor +struct ti_i2c_firmware_rec { __u8 Ver_Major; // Firmware Major version number __u8 Ver_Minor; // Firmware Minor version number @@ -436,6 +608,14 @@ }__attribute__((packed)); +struct watchport_firmware_version +{ +// Added 2 bytes for version number + __u8 Version_Major; // Download Version (for Watchport) + __u8 Version_Minor; +}__attribute__((packed)); + + // Structure of header of download image in fw_down.h struct ti_i2c_image_header { @@ -461,6 +641,15 @@ } __attribute__((packed)); +// CPU / Board Rev Definitions +#define TI_CPU_REV_5052 2 // 5052 based edgeports +#define TI_CPU_REV_3410 3 // 3410 based edgeports + +#define TI_BOARD_REV_TI_EP 0 // Basic ti based edgeport +#define TI_BOARD_REV_COMPACT 1 // Compact board +#define TI_BOARD_REV_WATCHPORT 2 // Watchport + + #define TI_GET_CPU_REVISION(x) (__u8)((((x)>>4)&0x0f)) #define TI_GET_BOARD_REVISION(x) (__u8)(((x)&0x0f)) @@ -469,20 +658,30 @@ #define TI_MAX_I2C_SIZE ( 16 * 1024 ) -/* TI USB 5052 definitions */ +#define TI_MANUF_VERSION_0 0 + +// IonConig2 flags +#define TI_CONFIG2_RS232 0x01 +#define TI_CONFIG2_RS422 0x02 +#define TI_CONFIG2_RS485 0x04 +#define TI_CONFIG2_SWITCHABLE 0x08 + +#define TI_CONFIG2_WATCHPORT 0x10 + + struct edge_ti_manuf_descriptor { __u8 IonConfig; // Config byte for ION manufacturing use __u8 IonConfig2; // Expansion - __u8 Version; // Verqsion + __u8 Version; // Version __u8 CpuRev_BoardRev; // CPU revision level (0xF0) and Board Rev Level (0x0F) __u8 NumPorts; // Number of ports for this UMP __u8 NumVirtualPorts; // Number of Virtual ports __u8 HubConfig1; // Used to configure the Hub __u8 HubConfig2; // Used to configure the Hub __u8 TotalPorts; // Total Number of Com Ports for the entire device (All UMPs) - __u8 Reserved; + __u8 Reserved; // Reserved }__attribute__((packed)); -#endif // if !defined() +#endif // if !defined(_USBVEND_H) diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c --- a/drivers/usb/serial/ipaq.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/serial/ipaq.c 2004-10-18 14:56:49 -07:00 @@ -127,6 +127,7 @@ { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E335_ID) }, { USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) }, + { USB_DEVICE(HTC_VENDOR_ID, HTC_HIMALAYA_ID) }, { USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) }, { USB_DEVICE(ASUS_VENDOR_ID, ASUS_A600_PRODUCT_ID) }, { USB_DEVICE(ASUS_VENDOR_ID, ASUS_A620_PRODUCT_ID) }, @@ -188,6 +189,7 @@ usb_set_serial_port_data(port, priv); priv->active = 0; priv->queue_len = 0; + priv->free_len = 0; INIT_LIST_HEAD(&priv->queue); INIT_LIST_HEAD(&priv->freelist); diff -Nru a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h --- a/drivers/usb/serial/ipaq.h 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/serial/ipaq.h 2004-10-18 14:55:54 -07:00 @@ -78,6 +78,7 @@ #define HTC_VENDOR_ID 0x0bb4 #define HTC_PRODUCT_ID 0x00ce +#define HTC_HIMALAYA_ID 0x0a02 #define NEC_VENDOR_ID 0x0409 #define NEC_PRODUCT_ID 0x00d5 diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c --- a/drivers/usb/serial/ir-usb.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/serial/ir-usb.c 2004-10-18 14:56:29 -07:00 @@ -449,6 +449,10 @@ */ tty = port->tty; + /* + * FIXME: must not do this in IRQ context, + * must honour TTY_DONT_FLIP + */ tty->ldisc.receive_buf( tty, data+1, diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c --- a/drivers/usb/serial/keyspan_pda.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/serial/keyspan_pda.c 2004-10-18 14:56:33 -07:00 @@ -186,13 +186,7 @@ wake_up_interruptible( &port->write_wait ); /* wake up line discipline */ - if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup ) - (tty->ldisc.write_wakeup)(tty); - - /* wake up other tty processes */ - wake_up_interruptible( &tty->write_wait ); - /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ + tty_wakeup(tty); } static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c --- a/drivers/usb/serial/mct_u232.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/usb/serial/mct_u232.c 2004-10-18 14:56:48 -07:00 @@ -579,11 +579,7 @@ if (write_blocking) { wake_up_interruptible(&port->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - + tty_wakeup(tty); } else { /* from generic_write_bulk_callback */ schedule_work(&port->work); diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c --- a/drivers/usb/serial/pl2303.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/serial/pl2303.c 2004-10-18 14:56:29 -07:00 @@ -659,7 +659,7 @@ state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__); + dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c 2004-10-18 14:57:20 -07:00 +++ b/drivers/usb/serial/usb-serial.c 2004-10-18 14:57:20 -07:00 @@ -421,6 +421,63 @@ return; } +static void destroy_serial(struct kref *kref) +{ + struct usb_serial *serial; + struct usb_serial_port *port; + int i; + + serial = to_usb_serial(kref); + + dbg ("%s - %s", __FUNCTION__, serial->type->name); + + serial->type->shutdown(serial); + + /* return the minor range that this device had */ + return_serial(serial); + + for (i = 0; i < serial->num_ports; ++i) + serial->port[i]->open_count = 0; + + /* the ports are cleaned up and released in port_release() */ + for (i = 0; i < serial->num_ports; ++i) + if (serial->port[i]->dev.parent != NULL) { + device_unregister(&serial->port[i]->dev); + serial->port[i] = NULL; + } + + /* If this is a "fake" port, we have to clean it up here, as it will + * not get cleaned up in port_release() as it was never registered with + * the driver core */ + if (serial->num_ports < serial->num_port_pointers) { + for (i = serial->num_ports; i < serial->num_port_pointers; ++i) { + port = serial->port[i]; + if (!port) + continue; + if (port->read_urb) { + usb_unlink_urb(port->read_urb); + usb_free_urb(port->read_urb); + } + if (port->write_urb) { + usb_unlink_urb(port->write_urb); + usb_free_urb(port->write_urb); + } + if (port->interrupt_in_urb) { + usb_unlink_urb(port->interrupt_in_urb); + usb_free_urb(port->interrupt_in_urb); + } + kfree(port->bulk_in_buffer); + kfree(port->bulk_out_buffer); + kfree(port->interrupt_in_buffer); + } + } + + usb_put_dev(serial->dev); + + /* free up any memory that we allocated */ + kfree (serial); +} + /***************************************************************************** * Driver tty interface functions *****************************************************************************/ @@ -465,7 +522,7 @@ if (retval) { port->open_count = 0; module_put(serial->type->owner); - kref_put(&serial->kref); + kref_put(&serial->kref, destroy_serial); } } bailout: @@ -496,7 +553,7 @@ } module_put(port->serial->type->owner); - kref_put(&port->serial->kref); + kref_put(&port->serial->kref, destroy_serial); } static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) @@ -654,13 +711,6 @@ ; } -static void serial_shutdown (struct usb_serial *serial) -{ - dbg ("%s", __FUNCTION__); - - serial->type->shutdown(serial); -} - static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { struct usb_serial *serial; @@ -694,7 +744,7 @@ begin += length; length = 0; } - kref_put(&serial->kref); + kref_put(&serial->kref, destroy_serial); } *eof = 1; done: @@ -755,68 +805,7 @@ if (!tty) return; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - dbg("%s - write wakeup call.", __FUNCTION__); - (tty->ldisc.write_wakeup)(tty); - } - - wake_up_interruptible(&tty->write_wait); -} - -static void destroy_serial(struct kref *kref) -{ - struct usb_serial *serial; - struct usb_serial_port *port; - int i; - - serial = to_usb_serial(kref); - - dbg ("%s - %s", __FUNCTION__, serial->type->name); - serial_shutdown (serial); - - /* return the minor range that this device had */ - return_serial(serial); - - for (i = 0; i < serial->num_ports; ++i) - serial->port[i]->open_count = 0; - - /* the ports are cleaned up and released in port_release() */ - for (i = 0; i < serial->num_ports; ++i) - if (serial->port[i]->dev.parent != NULL) { - device_unregister(&serial->port[i]->dev); - serial->port[i] = NULL; - } - - /* If this is a "fake" port, we have to clean it up here, as it will - * not get cleaned up in port_release() as it was never registered with - * the driver core */ - if (serial->num_ports < serial->num_port_pointers) { - for (i = serial->num_ports; i < serial->num_port_pointers; ++i) { - port = serial->port[i]; - if (!port) - continue; - if (port->read_urb) { - usb_unlink_urb(port->read_urb); - usb_free_urb(port->read_urb); - } - if (port->write_urb) { - usb_unlink_urb(port->write_urb); - usb_free_urb(port->write_urb); - } - if (port->interrupt_in_urb) { - usb_unlink_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); - } - kfree(port->bulk_in_buffer); - kfree(port->bulk_out_buffer); - kfree(port->interrupt_in_buffer); - } - } - - usb_put_dev(serial->dev); - - /* free up any memory that we allocated */ - kfree (serial); + tty_wakeup(tty); } static void port_release(struct device *dev) @@ -859,7 +848,7 @@ serial->interface = interface; serial->vendor = dev->descriptor.idVendor; serial->product = dev->descriptor.idProduct; - kref_init(&serial->kref, destroy_serial); + kref_init(&serial->kref); return serial; } @@ -1209,7 +1198,7 @@ if (serial) { /* let the last holder of this object * cause it to be cleaned up */ - kref_put(&serial->kref); + kref_put(&serial->kref, destroy_serial); } dev_info(dev, "device disconnected\n"); } diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c --- a/drivers/usb/serial/whiteheat.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/serial/whiteheat.c 2004-10-18 14:56:28 -07:00 @@ -668,8 +668,7 @@ if (port->tty->driver->flush_buffer) port->tty->driver->flush_buffer(port->tty); - if (port->tty->ldisc.flush_buffer) - port->tty->ldisc.flush_buffer(port->tty); + tty_ldisc_flush(port->tty); firm_report_tx_done(port); diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/storage/datafab.c 2004-10-18 14:57:04 -07:00 @@ -50,16 +50,19 @@ * in that routine. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "datafab.h" -#include -#include -#include - static int datafab_determine_lun(struct us_data *us, struct datafab_info *info); @@ -388,7 +391,7 @@ static int datafab_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, + struct scsi_cmnd * srb, int sense_6) { static unsigned char rw_err_page[12] = { @@ -483,7 +486,7 @@ if (sense_6) ptr[0] = i - 1; else - ((u16 *) ptr)[0] = cpu_to_be16(i - 2); + ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); usb_stor_set_xfer_buf(ptr, i, srb); return USB_STOR_TRANSPORT_GOOD; @@ -498,7 +501,7 @@ // Transport for the Datafab MDCFE-B // -int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) +int datafab_transport(struct scsi_cmnd * srb, struct us_data *us) { struct datafab_info *info; int rc; @@ -540,8 +543,8 @@ // build the reply // we need the last sector, not the number of sectors - ((u32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); - ((u32 *) ptr)[1] = cpu_to_be32(info->ssize); + ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); + ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); usb_stor_set_xfer_buf(ptr, 8, srb); return USB_STOR_TRANSPORT_GOOD; @@ -625,12 +628,12 @@ if (srb->cmnd[0] == MODE_SENSE) { US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n"); - return datafab_handle_mode_sense(us, srb, TRUE); + return datafab_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n"); - return datafab_handle_mode_sense(us, srb, FALSE); + return datafab_handle_mode_sense(us, srb, 0); } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { diff -Nru a/drivers/usb/storage/datafab.h b/drivers/usb/storage/datafab.h --- a/drivers/usb/storage/datafab.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/storage/datafab.h 2004-10-18 14:56:49 -07:00 @@ -24,7 +24,7 @@ #ifndef _USB_DATAFAB_MDCFE_B_H #define _USB_DATAFAB_MDCFE_B_H -extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int datafab_transport(struct scsi_cmnd *srb, struct us_data *us); struct datafab_info { unsigned long sectors; // total sector count diff -Nru a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c --- a/drivers/usb/storage/debug.c 2004-10-18 14:55:55 -07:00 +++ b/drivers/usb/storage/debug.c 2004-10-18 14:55:55 -07:00 @@ -44,9 +44,15 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include + #include "debug.h" +#include "scsi.h" + -void usb_stor_show_command(Scsi_Cmnd *srb) +void usb_stor_show_command(struct scsi_cmnd *srb) { char *what = NULL; int i; diff -Nru a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h --- a/drivers/usb/storage/debug.h 2004-10-18 14:57:19 -07:00 +++ b/drivers/usb/storage/debug.h 2004-10-18 14:57:19 -07:00 @@ -46,13 +46,13 @@ #include #include -#include -#include "usb.h" + +struct scsi_cmnd; #define USB_STORAGE "usb-storage: " #ifdef CONFIG_USB_STORAGE_DEBUG -void usb_stor_show_command(Scsi_Cmnd *srb); +void usb_stor_show_command(struct scsi_cmnd *srb); void usb_stor_show_sense( unsigned char key, unsigned char asc, unsigned char ascq ); #define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x ) diff -Nru a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c --- a/drivers/usb/storage/dpcm.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/storage/dpcm.c 2004-10-18 14:56:49 -07:00 @@ -30,6 +30,10 @@ */ #include +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" @@ -41,7 +45,7 @@ * Transport for the Microtech DPCM-USB * */ -int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us) +int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) { int ret; diff -Nru a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h --- a/drivers/usb/storage/dpcm.h 2004-10-18 14:56:27 -07:00 +++ b/drivers/usb/storage/dpcm.h 2004-10-18 14:56:27 -07:00 @@ -29,6 +29,6 @@ #ifndef _MICROTECH_DPCM_USB_H #define _MICROTECH_DPCM_USB_H -extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us); #endif diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c --- a/drivers/usb/storage/freecom.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/usb/storage/freecom.c 2004-10-18 14:57:04 -07:00 @@ -29,12 +29,16 @@ */ #include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "freecom.h" -#include "linux/hdreg.h" #ifdef CONFIG_USB_STORAGE_DEBUG static void pdump (void *, int); @@ -55,14 +59,14 @@ struct freecom_xfer_wrap { u8 Type; /* Command type. */ u8 Timeout; /* Timeout in seconds. */ - u32 Count; /* Number of bytes to transfer. */ + __le32 Count; /* Number of bytes to transfer. */ u8 Pad[58]; } __attribute__ ((packed)); struct freecom_ide_out { u8 Type; /* Type + IDE register. */ u8 Pad; - u16 Value; /* Value to write. */ + __le16 Value; /* Value to write. */ u8 Pad2[60]; }; @@ -74,7 +78,7 @@ struct freecom_status { u8 Status; u8 Reason; - u16 Count; + __le16 Count; u8 Pad[60]; }; @@ -105,7 +109,7 @@ #define FCM_STATUS_PACKET_LENGTH 4 static int -freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, +freecom_readdata (struct scsi_cmnd *srb, struct us_data *us, unsigned int ipipe, unsigned int opipe, int count) { struct freecom_xfer_wrap *fxfr = @@ -139,7 +143,7 @@ } static int -freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, +freecom_writedata (struct scsi_cmnd *srb, struct us_data *us, int unsigned ipipe, unsigned int opipe, int count) { struct freecom_xfer_wrap *fxfr = @@ -176,7 +180,7 @@ * Transport for the Freecom USB/IDE adaptor. * */ -int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) +int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) { struct freecom_cb_wrap *fcb; struct freecom_status *fst; @@ -302,7 +306,7 @@ * move in. */ switch (us->srb->sc_data_direction) { - case SCSI_DATA_READ: + case DMA_FROM_DEVICE: /* catch bogus "read 0 length" case */ if (!length) break; @@ -334,7 +338,7 @@ US_DEBUGP("Transfer happy\n"); break; - case SCSI_DATA_WRITE: + case DMA_TO_DEVICE: /* catch bogus "write 0 length" case */ if (!length) break; @@ -364,7 +368,7 @@ break; - case SCSI_DATA_NONE: + case DMA_NONE: /* Easy, do nothing. */ break; diff -Nru a/drivers/usb/storage/freecom.h b/drivers/usb/storage/freecom.h --- a/drivers/usb/storage/freecom.h 2004-10-18 14:56:21 -07:00 +++ b/drivers/usb/storage/freecom.h 2004-10-18 14:56:21 -07:00 @@ -29,7 +29,7 @@ #ifndef _FREECOM_USB_H #define _FREECOM_USB_H -extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int freecom_transport(struct scsi_cmnd *srb, struct us_data *us); extern int usb_stor_freecom_reset(struct us_data *us); extern int freecom_init (struct us_data *us); diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c 2004-10-18 14:56:31 -07:00 +++ b/drivers/usb/storage/isd200.c 2004-10-18 14:56:31 -07:00 @@ -44,6 +44,16 @@ /* Include files */ +#include +#include +#include +#include +#include + +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" @@ -51,11 +61,6 @@ #include "scsiglue.h" #include "isd200.h" -#include -#include -#include -#include -#include /* Timeout defines (in Seconds) */ @@ -290,8 +295,8 @@ */ struct read_capacity_data { - unsigned long LogicalBlockAddress; - unsigned long BytesPerBlock; + __be32 LogicalBlockAddress; + __be32 BytesPerBlock; }; /* @@ -349,7 +354,7 @@ * RETURNS: * void */ -static void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb) +static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; @@ -427,7 +432,7 @@ ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_STATUS | REG_ERROR; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; srb->request_buffer = pointer; srb->request_bufflen = value; break; @@ -439,7 +444,7 @@ ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_RESET: @@ -448,7 +453,7 @@ ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_REENABLE: @@ -457,7 +462,7 @@ ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_SOFT_RESET: @@ -466,14 +471,14 @@ ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; ata.write.CommandByte = WIN_SRST; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; srb->request_buffer = (void *) info->id; srb->request_bufflen = sizeof(struct hd_driveid); break; @@ -535,7 +540,7 @@ * the device and receive the response. */ static void isd200_invoke_transport( struct us_data *us, - Scsi_Cmnd *srb, + struct scsi_cmnd *srb, union ata_cdb *ataCdb ) { int need_auto_sense = 0; @@ -839,7 +844,7 @@ unsigned long endTime; struct isd200_info *info = (struct isd200_info *)us->extra; unsigned char *regs = info->RegsBuf; - int recheckAsMaster = FALSE; + int recheckAsMaster = 0; if ( detect ) endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ; @@ -847,7 +852,7 @@ endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ; /* loop until we detect !BSY or timeout */ - while(TRUE) { + while(1) { #ifdef CONFIG_USB_STORAGE_DEBUG char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ? "Master" : "Slave"; @@ -899,9 +904,9 @@ itself okay as a master also */ if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && - (recheckAsMaster == FALSE)) { + !recheckAsMaster) { US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n"); - recheckAsMaster = TRUE; + recheckAsMaster = 1; master_slave = ATA_ADDRESS_DEVHEAD_STD; } else { US_DEBUGP(" Identified ATAPI device\n"); @@ -948,15 +953,15 @@ if (retStatus == ISD200_GOOD) { int isslave; /* master or slave? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, FALSE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0); if (retStatus == ISD200_GOOD) - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, FALSE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0); if (retStatus == ISD200_GOOD) { retStatus = isd200_srst(us); if (retStatus == ISD200_GOOD) /* ata or atapi? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, TRUE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1); } isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; @@ -1011,7 +1016,8 @@ } else { /* ATA Command Identify successful */ int i; - __u16 *src, *dest; + __be16 *src; + __u16 *dest; ide_fix_driveid(id); US_DEBUGP(" Identify Data Structure:\n"); @@ -1063,17 +1069,17 @@ } /* Fill in vendor identification fields */ - src = (__u16*)id->model; + src = (__be16*)id->model; dest = (__u16*)info->InquiryData.VendorId; for (i=0;i<4;i++) dest[i] = be16_to_cpu(src[i]); - src = (__u16*)(id->model+8); + src = (__be16*)(id->model+8); dest = (__u16*)info->InquiryData.ProductId; for (i=0;i<8;i++) dest[i] = be16_to_cpu(src[i]); - src = (__u16*)id->fw_rev; + src = (__be16*)id->fw_rev; dest = (__u16*)info->InquiryData.ProductRevisionLevel; for (i=0;i<2;i++) dest[i] = be16_to_cpu(src[i]); @@ -1121,15 +1127,15 @@ * Translate SCSI commands to ATA commands. * * RETURNS: - * TRUE if the command needs to be sent to the transport layer - * FALSE otherwise + * 1 if the command needs to be sent to the transport layer + * 0 otherwise */ -static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, +static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, union ata_cdb * ataCdb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct hd_driveid *id = info->id; - int sendToTransport = TRUE; + int sendToTransport = 1; unsigned char sectnum, head; unsigned short cylinder; unsigned long lba; @@ -1147,7 +1153,7 @@ usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, sizeof(info->InquiryData), srb); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; break; case MODE_SENSE: @@ -1167,7 +1173,7 @@ } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1185,7 +1191,7 @@ } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1209,15 +1215,14 @@ usb_stor_set_xfer_buf((unsigned char *) &readCapacityData, sizeof(readCapacityData), srb); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; case READ_10: US_DEBUGP(" ATA OUT - SCSIOP_READ\n"); - lba = *(unsigned long *)&srb->cmnd[2]; - lba = cpu_to_be32(lba); + lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; if (id->capability & CAPABILITY_LBA) { @@ -1249,8 +1254,7 @@ case WRITE_10: US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n"); - lba = *(unsigned long *)&srb->cmnd[2]; - lba = cpu_to_be32(lba); + lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; if (id->capability & CAPABILITY_LBA) { @@ -1293,7 +1297,7 @@ } else { US_DEBUGP(" Not removeable media, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1319,14 +1323,14 @@ } else { US_DEBUGP(" Nothing to do, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; default: US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]); srb->result = DID_ERROR << 16; - sendToTransport = FALSE; + sendToTransport = 0; break; } @@ -1424,9 +1428,9 @@ * */ -void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us) +void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) { - int sendToTransport = TRUE; + int sendToTransport = 1; union ata_cdb ataCdb; /* Make sure driver was initialized */ diff -Nru a/drivers/usb/storage/isd200.h b/drivers/usb/storage/isd200.h --- a/drivers/usb/storage/isd200.h 2004-10-18 14:56:13 -07:00 +++ b/drivers/usb/storage/isd200.h 2004-10-18 14:56:13 -07:00 @@ -25,7 +25,7 @@ #ifndef _USB_ISD200_H #define _USB_ISD200_H -extern void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us); +extern void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us); extern int isd200_Initialization(struct us_data *us); #endif diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c --- a/drivers/usb/storage/jumpshot.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/storage/jumpshot.c 2004-10-18 14:55:54 -07:00 @@ -47,15 +47,19 @@ * in that routine. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "jumpshot.h" -#include -#include -#include static inline int jumpshot_bulk_read(struct us_data *us, unsigned char *data, @@ -319,7 +323,7 @@ } static int jumpshot_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, + struct scsi_cmnd * srb, int sense_6) { static unsigned char rw_err_page[12] = { @@ -409,7 +413,7 @@ if (sense_6) ptr[0] = i - 1; else - ((u16 *) ptr)[0] = cpu_to_be16(i - 2); + ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); usb_stor_set_xfer_buf(ptr, i, srb); return USB_STOR_TRANSPORT_GOOD; @@ -426,7 +430,7 @@ // Transport for the Lexar 'Jumpshot' // -int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) +int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us) { struct jumpshot_info *info; int rc; @@ -471,8 +475,8 @@ // build the reply // - ((u32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); - ((u32 *) ptr)[1] = cpu_to_be32(info->ssize); + ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); + ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); usb_stor_set_xfer_buf(ptr, 8, srb); return USB_STOR_TRANSPORT_GOOD; @@ -551,12 +555,12 @@ if (srb->cmnd[0] == MODE_SENSE) { US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n"); - return jumpshot_handle_mode_sense(us, srb, TRUE); + return jumpshot_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n"); - return jumpshot_handle_mode_sense(us, srb, FALSE); + return jumpshot_handle_mode_sense(us, srb, 0); } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { diff -Nru a/drivers/usb/storage/jumpshot.h b/drivers/usb/storage/jumpshot.h --- a/drivers/usb/storage/jumpshot.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/storage/jumpshot.h 2004-10-18 14:56:33 -07:00 @@ -24,7 +24,7 @@ #ifndef _USB_JUMPSHOT_H #define _USB_JUMPSHOT_H -extern int jumpshot_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us); struct jumpshot_info { unsigned long sectors; // total sector count diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c --- a/drivers/usb/storage/protocol.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/storage/protocol.c 2004-10-18 14:55:54 -07:00 @@ -45,6 +45,8 @@ */ #include +#include +#include #include "protocol.h" #include "usb.h" #include "debug.h" @@ -59,7 +61,7 @@ * Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us */ -static void fix_inquiry_data(Scsi_Cmnd *srb) +static void fix_inquiry_data(struct scsi_cmnd *srb) { unsigned char databuf[3]; unsigned int index, offset; @@ -91,10 +93,10 @@ * Fix-up the return data from a READ CAPACITY command. My Feiya reader * returns a value that is 1 too large. */ -static void fix_read_capacity(Scsi_Cmnd *srb) +static void fix_read_capacity(struct scsi_cmnd *srb) { unsigned int index, offset; - u32 c; + __be32 c; unsigned long capacity; /* verify that it's a READ CAPACITY command */ @@ -120,11 +122,11 @@ * Protocol routines ***********************************************************************/ -void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us) { /* Pad the ATAPI command with zeros * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ for (; srb->cmd_len<12; srb->cmd_len++) @@ -141,11 +143,11 @@ } } -void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us) { /* Pad the ATAPI command with zeros * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ @@ -166,12 +168,12 @@ } -void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us) { /* fix some commands -- this is a form of mode translation * UFI devices only accept 12 byte long commands * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ @@ -213,7 +215,8 @@ } } -void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, + struct us_data *us) { /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); @@ -241,7 +244,7 @@ * pick up from where this one left off. */ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, unsigned int *offset, enum xfer_buf_dir dir) { unsigned int cnt; @@ -327,7 +330,7 @@ /* Store the contents of buffer into srb's transfer buffer and set the * SCSI residue. */ void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb) + unsigned int buflen, struct scsi_cmnd *srb) { unsigned int index = 0, offset = 0; diff -Nru a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h --- a/drivers/usb/storage/protocol.h 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/storage/protocol.h 2004-10-18 14:56:29 -07:00 @@ -41,9 +41,8 @@ #ifndef _PROTOCOL_H_ #define _PROTOCOL_H_ -#include -#include "scsi.h" -#include "usb.h" +struct scsi_cmnd; +struct us_data; /* Sub Classes */ @@ -60,18 +59,19 @@ #define US_SC_DEVICE 0xff /* Use device's value */ /* Protocol handling routines */ -extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*); +extern void usb_stor_ATAPI_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_qic157_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*, + struct us_data*); -/* Scsi_Cmnd transfer buffer access utilities */ +/* struct scsi_cmnd transfer buffer access utilities */ enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF}; extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, unsigned int *offset, enum xfer_buf_dir dir); extern void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb); + unsigned int buflen, struct scsi_cmnd *srb); #endif diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/usb/storage/scsiglue.c 2004-10-18 14:56:32 -07:00 @@ -44,17 +44,23 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "scsiglue.h" -#include "usb.h" -#include "debug.h" -#include "transport.h" -#include "protocol.h" #include #include + +#include +#include #include +#include +#include #include +#include "scsiglue.h" +#include "usb.h" +#include "debug.h" +#include "transport.h" +#include "protocol.h" + /*********************************************************************** * Host functions ***********************************************************************/ @@ -92,17 +98,15 @@ * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - /* Devices using Genesys Logic chips cause a lot of trouble for - * high-speed transfers; they die unpredictably when given more - * than 64 KB of data at a time. If we detect such a device, - * reduce the maximum transfer size to 64 KB = 128 sectors. */ - -#define USB_VENDOR_ID_GENESYS 0x05e3 // Needs a standard location - + /* According to the technical support people at Genesys Logic, + * devices using their chips have problems transferring more than + * 32 KB at a time. In practice people have found that 64 KB + * works okay and that's what Windows does. But we'll be + * conservative; people can always use the sysfs interface to + * increase max_sectors. */ if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS && - us->pusb_dev->speed == USB_SPEED_HIGH && - sdev->request_queue->max_sectors > 128) - blk_queue_max_sectors(sdev->request_queue, 128); + sdev->request_queue->max_sectors > 64) + blk_queue_max_sectors(sdev->request_queue, 64); /* We can't put these settings in slave_alloc() because that gets * called before the device type is known. Consequently these @@ -146,7 +150,8 @@ /* queue a command */ /* This is always called with scsi_lock(srb->host) held */ -static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +static int queuecommand(struct scsi_cmnd *srb, + void (*done)(struct scsi_cmnd *)) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; @@ -176,7 +181,7 @@ /* Command abort */ /* This is always called with scsi_lock(srb->host) held */ -static int command_abort( Scsi_Cmnd *srb ) +static int command_abort(struct scsi_cmnd *srb ) { struct Scsi_Host *host = srb->device->host; struct us_data *us = (struct us_data *) host->hostdata[0]; @@ -223,7 +228,7 @@ /* This invokes the transport reset mechanism to reset the state of the * device */ /* This is always called with scsi_lock(srb->host) held */ -static int device_reset( Scsi_Cmnd *srb ) +static int device_reset(struct scsi_cmnd *srb) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; int result; @@ -258,7 +263,7 @@ /* It refuses to work if there's more than one interface in * the device, so that other users are not affected. */ /* This is always called with scsi_lock(srb->host) held */ -static int bus_reset( Scsi_Cmnd *srb ) +static int bus_reset(struct scsi_cmnd *srb) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; int result; @@ -444,10 +449,10 @@ * periodically someone should test to see which setting is more * optimal. */ - .use_clustering = TRUE, + .use_clustering = 1, /* emulated HBA */ - .emulated = TRUE, + .emulated = 1, /* we do our own delay after a device or bus reset */ .skip_settle_delay = 1, diff -Nru a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h --- a/drivers/usb/storage/scsiglue.h 2004-10-18 14:56:32 -07:00 +++ b/drivers/usb/storage/scsiglue.h 2004-10-18 14:56:32 -07:00 @@ -41,17 +41,15 @@ #ifndef _SCSIGLUE_H_ #define _SCSIGLUE_H_ -#include -#include "scsi.h" #include -#include "usb.h" + +struct us_data; +struct scsi_cmnd; extern void usb_stor_report_device_reset(struct us_data *us); extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_invalidCDB[18]; extern struct scsi_host_template usb_stor_host_template; -extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); -extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); #endif diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/storage/sddr09.c 2004-10-18 14:56:49 -07:00 @@ -41,16 +41,19 @@ * EF: compute checksum (?) */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "sddr09.h" -#include -#include -#include -#include #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) #define LSB_of(s) ((s)&0xFF) @@ -1401,7 +1404,7 @@ /* * Transport for the Sandisk SDDR-09 */ -int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) +int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) { static unsigned char sensekey = 0, sensecode = 0; static unsigned char havefakesense = 0; @@ -1486,11 +1489,11 @@ capacity = (info->lbact << info->blockshift) - 1; - ((u32 *) ptr)[0] = cpu_to_be32(capacity); + ((__be32 *) ptr)[0] = cpu_to_be32(capacity); // Report page size - ((u32 *) ptr)[1] = cpu_to_be32(info->pagesize); + ((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize); usb_stor_set_xfer_buf(ptr, 8, srb); return USB_STOR_TRANSPORT_GOOD; @@ -1507,7 +1510,7 @@ "mode page 0x%x\n", modepage); memcpy(ptr, mode_page_01, sizeof(mode_page_01)); - ((u16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); + ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0; usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); return USB_STOR_TRANSPORT_GOOD; @@ -1581,13 +1584,13 @@ if (srb->request_bufflen == 0) return USB_STOR_TRANSPORT_GOOD; - if (srb->sc_data_direction == SCSI_DATA_WRITE || - srb->sc_data_direction == SCSI_DATA_READ) { - unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE) + if (srb->sc_data_direction == DMA_TO_DEVICE || + srb->sc_data_direction == DMA_FROM_DEVICE) { + unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) ? us->send_bulk_pipe : us->recv_bulk_pipe; US_DEBUGP("SDDR09: %s %d bytes\n", - (srb->sc_data_direction == SCSI_DATA_WRITE) ? + (srb->sc_data_direction == DMA_TO_DEVICE) ? "sending" : "receiving", srb->request_bufflen); diff -Nru a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h --- a/drivers/usb/storage/sddr09.h 2004-10-18 14:56:17 -07:00 +++ b/drivers/usb/storage/sddr09.h 2004-10-18 14:56:17 -07:00 @@ -29,7 +29,7 @@ /* Sandisk SDDR-09 stuff */ -extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); struct sddr09_card_info { unsigned long capacity; /* Size of card in bytes */ diff -Nru a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c --- a/drivers/usb/storage/sddr55.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/storage/sddr55.c 2004-10-18 14:56:28 -07:00 @@ -24,15 +24,19 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "sddr55.h" -#include -#include -#include #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) #define LSB_of(s) ((s)&0xFF) @@ -74,7 +78,7 @@ sddr55_bulk_transport(struct us_data *us, int direction, unsigned char *data, unsigned int len) { struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - unsigned int pipe = (direction == SCSI_DATA_READ) ? + unsigned int pipe = (direction == DMA_FROM_DEVICE) ? us->recv_bulk_pipe : us->send_bulk_pipe; if (!len) @@ -99,7 +103,7 @@ command[5] = 0xB0; command[7] = 0x80; result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); US_DEBUGP("Result for send_command in status %d\n", result); @@ -110,7 +114,7 @@ } result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 4); + DMA_FROM_DEVICE, status, 4); /* expect to get short transfer if no card fitted */ if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) { @@ -139,7 +143,7 @@ /* now read status */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 2); + DMA_FROM_DEVICE, status, 2); if (result != USB_STOR_XFER_GOOD) { set_sense_info (4, 0, 0); /* hardware error */ @@ -215,7 +219,7 @@ /* send command */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); US_DEBUGP("Result for send_command in read_data %d\n", result); @@ -227,7 +231,7 @@ /* read data */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, buffer, len); + DMA_FROM_DEVICE, buffer, len); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; @@ -236,7 +240,7 @@ /* now read status */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 2); + DMA_FROM_DEVICE, status, 2); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; @@ -390,7 +394,7 @@ /* send command */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for send_command in write_data %d\n", @@ -404,7 +408,7 @@ /* send the data */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, buffer, len); + DMA_TO_DEVICE, buffer, len); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for send_data in write_data %d\n", @@ -417,7 +421,7 @@ } /* now read status */ - result = sddr55_bulk_transport(us, SCSI_DATA_READ, status, 6); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for get_status in write_data %d\n", @@ -483,7 +487,7 @@ memset(command, 0, 8); command[5] = 0xB0; command[7] = 0x84; - result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); + result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); US_DEBUGP("Result of send_control for device ID is %d\n", result); @@ -492,7 +496,7 @@ return USB_STOR_TRANSPORT_ERROR; result = sddr55_bulk_transport(us, - SCSI_DATA_READ, content, 4); + DMA_FROM_DEVICE, content, 4); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -502,7 +506,7 @@ if (content[0] != 0xff) { result = sddr55_bulk_transport(us, - SCSI_DATA_READ, content, 2); + DMA_FROM_DEVICE, content, 2); } return USB_STOR_TRANSPORT_GOOD; @@ -624,21 +628,21 @@ command[6] = numblocks * 2 / 256; command[7] = 0x8A; - result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); + result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); return -1; } - result = sddr55_bulk_transport(us, SCSI_DATA_READ, buffer, numblocks * 2); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, buffer, numblocks * 2); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); return -1; } - result = sddr55_bulk_transport(us, SCSI_DATA_READ, command, 2); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, command, 2); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); @@ -734,7 +738,7 @@ /* * Transport for the Sandisk SDDR-55 */ -int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) +int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) { int result; static unsigned char inquiry_response[8] = { @@ -834,8 +838,8 @@ capacity /= PAGESIZE; capacity--; - ((u32 *) ptr)[0] = cpu_to_be32(capacity); - ((u32 *) ptr)[1] = cpu_to_be32(PAGESIZE); + ((__be32 *) ptr)[0] = cpu_to_be32(capacity); + ((__be32 *) ptr)[1] = cpu_to_be32(PAGESIZE); usb_stor_set_xfer_buf(ptr, 8, srb); sddr55_read_map(us); diff -Nru a/drivers/usb/storage/sddr55.h b/drivers/usb/storage/sddr55.h --- a/drivers/usb/storage/sddr55.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/storage/sddr55.h 2004-10-18 14:56:49 -07:00 @@ -28,7 +28,7 @@ /* Sandisk SDDR-55 stuff */ -extern int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us); extern int sddr55_reset(struct us_data *us); #endif diff -Nru a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c --- a/drivers/usb/storage/shuttle_usbat.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/storage/shuttle_usbat.c 2004-10-18 14:55:54 -07:00 @@ -39,16 +39,20 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "shuttle_usbat.h" -#include -#include -#include - #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) @@ -275,7 +279,7 @@ int minutes) { int result; - unsigned int pipe = (direction == SCSI_DATA_READ) ? + unsigned int pipe = (direction == DMA_FROM_DEVICE) ? us->recv_bulk_pipe : us->send_bulk_pipe; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, @@ -315,9 +319,9 @@ } else cmdlen = 8; - command[cmdlen-8] = (direction==SCSI_DATA_WRITE ? 0x40 : 0xC0); + command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); command[cmdlen-7] = access | - (direction==SCSI_DATA_WRITE ? 0x05 : 0x04); + (direction==DMA_TO_DEVICE ? 0x05 : 0x04); command[cmdlen-6] = data_reg; command[cmdlen-5] = status_reg; command[cmdlen-4] = timeout; @@ -355,7 +359,7 @@ //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", - // direction == SCSI_DATA_WRITE ? "out" : "in", + // direction == DMA_TO_DEVICE ? "out" : "in", // len, use_sg); result = usb_stor_bulk_transfer_sg(us, @@ -388,7 +392,7 @@ * the bulk output pipe only the first time. */ - if (direction==SCSI_DATA_READ && i==0) { + if (direction==DMA_FROM_DEVICE && i==0) { if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0) return USB_STOR_TRANSPORT_ERROR; @@ -399,7 +403,7 @@ */ result = usbat_read(us, USBAT_ATA, - direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, + direction==DMA_TO_DEVICE ? 0x17 : 0x0E, status); if (result!=USB_STOR_XFER_GOOD) @@ -410,7 +414,7 @@ return USB_STOR_TRANSPORT_FAILED; US_DEBUGP("Redoing %s\n", - direction==SCSI_DATA_WRITE ? "write" : "read"); + direction==DMA_TO_DEVICE ? "write" : "read"); } else if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -420,7 +424,7 @@ } US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", - direction==SCSI_DATA_WRITE ? "Writing" : "Reading"); + direction==DMA_TO_DEVICE ? "Writing" : "Reading"); return USB_STOR_TRANSPORT_FAILED; } @@ -520,7 +524,7 @@ static int usbat_handle_read10(struct us_data *us, unsigned char *registers, unsigned char *data, - Scsi_Cmnd *srb) + struct scsi_cmnd *srb) { int result = USB_STOR_TRANSPORT_GOOD; unsigned char *buffer; @@ -537,7 +541,7 @@ result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, + DMA_FROM_DEVICE, srb->request_buffer, srb->request_bufflen, srb->use_sg, 1); @@ -606,7 +610,7 @@ result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, + DMA_FROM_DEVICE, buffer, len, 0, 1); @@ -803,7 +807,7 @@ /* * Transport for the HP 8200e */ -int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) +int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) { int result; unsigned char *status = us->iobuf; @@ -847,12 +851,12 @@ if (srb->cmnd[0] == TEST_UNIT_READY) transferred = 0; - if (srb->sc_data_direction == SCSI_DATA_WRITE) { + if (srb->sc_data_direction == DMA_TO_DEVICE) { result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_WRITE, + DMA_TO_DEVICE, srb->request_buffer, len, srb->use_sg, 10); @@ -900,7 +904,7 @@ // If there is response data to be read in // then do it here. - if (len != 0 && (srb->sc_data_direction == SCSI_DATA_READ)) { + if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { // How many bytes to read in? Check cylL register diff -Nru a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h --- a/drivers/usb/storage/shuttle_usbat.h 2004-10-18 14:55:54 -07:00 +++ b/drivers/usb/storage/shuttle_usbat.h 2004-10-18 14:55:54 -07:00 @@ -53,7 +53,7 @@ #define USBAT_UIO_ADPRST 0x01 // Reset SCM chip /* HP 8200e stuff */ -extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); extern int init_8200e(struct us_data *us); #endif diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/storage/transport.c 2004-10-18 14:56:28 -07:00 @@ -46,15 +46,20 @@ */ #include +#include +#include +#include + +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "scsiglue.h" #include "usb.h" #include "debug.h" -#include -#include -#include /*********************************************************************** * Data transfer routines @@ -260,9 +265,7 @@ USB_ENDPOINT_HALT, endp, NULL, 0, 3*HZ); - /* reset the toggles and endpoint flags */ - usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), - usb_pipeout(pipe)); + /* reset the endpoint toggle */ usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); @@ -522,7 +525,7 @@ * This is used by the protocol layers to actually send the message to * the device and receive the response. */ -void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; @@ -569,7 +572,7 @@ * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && - srb->sc_data_direction != SCSI_DATA_READ) { + srb->sc_data_direction != DMA_FROM_DEVICE) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } @@ -629,7 +632,7 @@ /* set the transfer direction */ old_sc_data_direction = srb->sc_data_direction; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; /* use the new buffer we have */ old_request_buffer = srb->request_buffer; @@ -749,7 +752,7 @@ * Control/Bulk/Interrupt transport */ -int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) { unsigned int transfer_length = srb->request_bufflen; unsigned int pipe = 0; @@ -778,7 +781,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (transfer_length) { - pipe = srb->sc_data_direction == SCSI_DATA_READ ? + pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, @@ -849,7 +852,7 @@ /* * Control/Bulk transport */ -int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) { unsigned int transfer_length = srb->request_bufflen; int result; @@ -877,7 +880,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, @@ -908,6 +911,7 @@ int result; /* issue the command */ + us->iobuf[0] = 0; result = usb_stor_control_msg(us, us->recv_ctrl_pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | @@ -918,7 +922,7 @@ result, us->iobuf[0]); /* if we have a successful request, return the result */ - if (result == 1) + if (result >= 0) return us->iobuf[0]; /* @@ -939,7 +943,7 @@ return -1; } -int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; @@ -952,7 +956,7 @@ /* set up the command wrapper */ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = cpu_to_le32(transfer_length); - bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; + bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0; bcb->Tag = srb->serial_number; bcb->Lun = srb->device->lun; if (us->flags & US_FL_SCM_MULT_TARG) @@ -977,8 +981,14 @@ /* DATA STAGE */ /* send/receive data payload, if there is any */ + + /* Genesys Logic interface chips need a 100us delay between the + * command phase and the data phase */ + if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS) + udelay(100); + if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h 2004-10-18 14:56:28 -07:00 +++ b/drivers/usb/storage/transport.h 2004-10-18 14:56:28 -07:00 @@ -44,7 +44,8 @@ #include #include #include "usb.h" -#include "scsi.h" + +struct scsi_cmnd; /* Protocols */ @@ -82,9 +83,9 @@ /* command block wrapper */ struct bulk_cb_wrap { - __u32 Signature; /* contains 'USBC' */ + __le32 Signature; /* contains 'USBC' */ __u32 Tag; /* unique per command id */ - __u32 DataTransferLength; /* size of data */ + __le32 DataTransferLength; /* size of data */ __u8 Flags; /* direction in bit 0 */ __u8 Lun; /* LUN normally 0 */ __u8 Length; /* of of the CDB */ @@ -98,9 +99,9 @@ /* command status wrapper */ struct bulk_cs_wrap { - __u32 Signature; /* should = 'USBS' */ + __le32 Signature; /* should = 'USBS' */ __u32 Tag; /* same as original command */ - __u32 Residue; /* amount not transferred */ + __le32 Residue; /* amount not transferred */ __u8 Status; /* see below */ __u8 Filler[18]; }; @@ -150,16 +151,16 @@ #define US_CBI_ADSC 0 -extern int usb_stor_CBI_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_CBI_transport(struct scsi_cmnd *, struct us_data*); -extern int usb_stor_CB_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*); extern int usb_stor_CB_reset(struct us_data*); -extern int usb_stor_Bulk_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*); extern int usb_stor_Bulk_max_lun(struct us_data*); extern int usb_stor_Bulk_reset(struct us_data*); -extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); +extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*); extern void usb_stor_stop_transport(struct us_data*); extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h 2004-10-18 14:56:49 -07:00 +++ b/drivers/usb/storage/unusual_devs.h 2004-10-18 14:56:49 -07:00 @@ -45,11 +45,6 @@ * */ -UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245, - "Mitsumi", - "CD-R/RW Drive", - US_SC_8020, US_PR_CBI, NULL, 0), - UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, "Mitsumi", "USB FDD", @@ -373,6 +368,15 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN), +/* Reported by Johann Cardon + * This entry is needed only because the device reports + * bInterfaceClass = 0xff (vendor-specific) + */ +UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999, + "Y-E Data", + "Silicon Media R/W", + US_SC_DEVICE, US_PR_DEVICE, NULL, 0), + /* Fabrizio Fellini */ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, "Fujifilm", @@ -384,11 +388,15 @@ "USB Hard Disk", US_SC_RBC, US_PR_CB, NULL, 0 ), -/* Submitted by Jol Bourquard */ +/* Submitted by Joel Bourquard + * Some versions of this device need the SubClass and Protocol overrides + * while others don't. + */ UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110, "In-System", "PyroGate External CD-ROM Enclosure (FCD-523)", - US_SC_SCSI, US_PR_BULK, NULL, 0 ), + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_NEED_OVERRIDE ), #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, @@ -482,6 +490,13 @@ US_FL_SINGLE_LUN ), #endif +/* Reported by Darsen Lu */ +UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001, + "SigmaTel", + "USBMSC Audio Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Submitted by Benny Sjostrand */ UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001, "Minolta", @@ -510,11 +525,13 @@ US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN ), +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk", "ImageMate SDDR-31", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_SER ), +#endif UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", @@ -685,7 +702,7 @@ "Trumpion", "t33520 USB Flash Card Controller", US_SC_DEVICE, US_PR_BULK, NULL, - US_FL_MODE_XLATE), + US_FL_NEED_OVERRIDE | US_FL_MODE_XLATE), /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/usb/storage/usb.c 2004-10-18 14:56:27 -07:00 @@ -50,6 +50,11 @@ #include #include #include + +#include +#include +#include + #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -133,7 +138,9 @@ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) }, { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) }, { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) }, +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, +#endif /* Terminating entry */ { } @@ -207,8 +214,10 @@ .useTransport = US_PR_BULK}, { .useProtocol = US_SC_8070, .useTransport = US_PR_BULK}, +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) { .useProtocol = US_SC_SCSI, .useTransport = US_PR_BULK}, +#endif /* Terminating entry */ { NULL } @@ -322,7 +331,7 @@ /* reject the command if the direction indicator * is UNKNOWN */ - if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) { + if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { US_DEBUGP("UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; } @@ -423,6 +432,13 @@ us->pusb_dev = interface_to_usbdev(intf); us->pusb_intf = intf; us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", + us->pusb_dev->descriptor.idVendor, + us->pusb_dev->descriptor.idProduct, + us->pusb_dev->descriptor.bcdDevice); + US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n", + intf->cur_altsetting->desc.bInterfaceSubClass, + intf->cur_altsetting->desc.bInterfaceProtocol); /* Store our private data in the interface */ usb_set_intfdata(intf, us); @@ -453,11 +469,6 @@ struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index]; struct usb_device_id *id = &storage_usb_ids[id_index]; - if (unusual_dev->vendorName) - US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName); - if (unusual_dev->productName) - US_DEBUGP("Product: %s\n", unusual_dev->productName); - /* Store the entries */ us->unusual_dev = unusual_dev; us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ? @@ -528,6 +539,8 @@ } if (strlen(us->serial) == 0) strcpy(us->serial, "None"); + + US_DEBUGP("Vendor: %s, Product: %s\n", us->vendor, us->product); } /* Get the transport settings */ @@ -715,8 +728,6 @@ ep_int = ep; } } - US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n", - ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0); if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); @@ -880,9 +891,6 @@ int result; US_DEBUGP("USB Mass Storage device detected\n"); - US_DEBUGP("altsetting is %d, id_index is %d\n", - intf->cur_altsetting->desc.bAlternateSetting, - id_index); /* Allocate the us_data structure and initialize the mutexes */ us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL); diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h 2004-10-18 14:56:33 -07:00 +++ b/drivers/usb/storage/usb.h 2004-10-18 14:56:33 -07:00 @@ -48,10 +48,9 @@ #include #include #include -#include "scsi.h" -#include struct us_data; +struct scsi_cmnd; /* * Unusual device list definitions @@ -102,9 +101,9 @@ #define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */ -typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*); typedef int (*trans_reset)(struct us_data*); -typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*); typedef void (*extra_data_destructor)(void *); /* extra data destructor */ /* we allocate one of these for every device that we remember */ @@ -144,7 +143,7 @@ /* SCSI interfaces */ struct Scsi_Host *host; /* our dummy host data */ - Scsi_Cmnd *srb; /* current srb */ + struct scsi_cmnd *srb; /* current srb */ /* thread information */ int pid; /* control thread */ @@ -179,5 +178,9 @@ * single queue element srb for write access */ #define scsi_unlock(host) spin_unlock_irq(host->host_lock) #define scsi_lock(host) spin_lock_irq(host->host_lock) + + +/* Vendor ID list for devices that require special handling */ +#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */ #endif diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/usb/usb-skeleton.c 2004-10-18 14:56:29 -07:00 @@ -1,42 +1,15 @@ /* - * USB Skeleton driver - 1.1 + * USB Skeleton driver - 2.0 * - * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. * - * - * This driver is to be used as a skeleton driver to be able to create a - * USB driver quickly. The design of it is based on the usb-serial and - * dc2xx drivers. - * - * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help - * in debugging this driver. - * - * - * History: - * - * 2003-05-06 - 1.1 - changes due to usb core changes with usb_register_dev() - * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and - * disconnect. Fix transfer amount in read(). Use - * macros instead of magic numbers in probe(). Change - * size variables to size_t. Show how to eliminate - * DMA bounce buffer. - * 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array. - * 2002_09_26 - 0.8 - changes due to USB core conversion to struct device - * driver. - * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do - * not have both a bulk in and bulk out endpoint. - * Thanks to Holger Waechtler for the fix. - * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect. - * Thanks to Pete Zaitcev for the fix. - * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux - * 2001_08_21 - 0.4 - more small bug fixes. - * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel - * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people - * 2001_05_01 - 0.1 - first version + * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c + * but has been rewritten to be easy to read and use, as no locks are now + * needed anymore. * */ @@ -46,31 +19,10 @@ #include #include #include -#include -#include +#include #include #include -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) - - -/* Version Information */ -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" -#define DRIVER_DESC "USB Skeleton Driver" - -/* Module parameters */ -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - /* Define these values to match your devices */ #define USB_SKEL_VENDOR_ID 0xfff0 @@ -79,11 +31,8 @@ /* table of devices that work with this driver */ static struct usb_device_id skel_table [] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, - /* "Gadget Zero" firmware runs under Linux */ - { USB_DEVICE(0x0525, 0xa4a0) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE (usb, skel_table); @@ -92,413 +41,195 @@ /* Structure to hold all of our device specific stuff */ struct usb_skel { - struct usb_device * udev; /* save off the usb device pointer */ + struct usb_device * udev; /* the usb device for this device */ struct usb_interface * interface; /* the interface for this device */ - unsigned char minor; /* the starting minor number for this device */ - unsigned char num_ports; /* the number of ports this device has */ - char num_interrupt_in; /* number of interrupt in endpoints we have */ - char num_bulk_in; /* number of bulk in endpoints we have */ - char num_bulk_out; /* number of bulk out endpoints we have */ - unsigned char * bulk_in_buffer; /* the buffer to receive data */ size_t bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ - - unsigned char * bulk_out_buffer; /* the buffer to send data */ - size_t bulk_out_size; /* the size of the send buffer */ - struct urb * write_urb; /* the urb used to send data */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ - atomic_t write_busy; /* true iff write urb is busy */ - struct completion write_finished; /* wait for the write to finish */ - - int open; /* if the port is open or not */ - int present; /* if the device is not disconnected */ - struct semaphore sem; /* locks this structure */ + struct kref kref; }; +#define to_skel_dev(d) container_of(d, struct usb_skel, kref) +static struct usb_driver skel_driver; -/* prevent races between open() and disconnect() */ -static DECLARE_MUTEX (disconnect_sem); - -/* local function prototypes */ -static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos); -static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos); -static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int skel_open (struct inode *inode, struct file *file); -static int skel_release (struct inode *inode, struct file *file); - -static int skel_probe (struct usb_interface *interface, const struct usb_device_id *id); -static void skel_disconnect (struct usb_interface *interface); - -static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs); - -/* - * File operations needed when we register this driver. - * This assumes that this driver NEEDS file operations, - * of course, which means that the driver is expected - * to have a node in the /dev directory. If the USB - * device were for a network interface then the driver - * would use "struct net_driver" instead, and a serial - * device would use "struct tty_driver". - */ -static struct file_operations skel_fops = { - /* - * The owner field is part of the module-locking - * mechanism. The idea is that the kernel knows - * which module to increment the use-counter of - * BEFORE it calls the device's open() function. - * This also means that the kernel can decrement - * the use-counter again before calling release() - * or should the open() function fail. - */ - .owner = THIS_MODULE, - - .read = skel_read, - .write = skel_write, - .ioctl = skel_ioctl, - .open = skel_open, - .release = skel_release, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with devfs and the driver core - */ -static struct usb_class_driver skel_class = { - .name = "usb/skel%d", - .fops = &skel_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, - .minor_base = USB_SKEL_MINOR_BASE, -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver skel_driver = { - .owner = THIS_MODULE, - .name = "skeleton", - .probe = skel_probe, - .disconnect = skel_disconnect, - .id_table = skel_table, -}; - - -/** - * usb_skel_debug_data - */ -static inline void usb_skel_debug_data (const char *function, int size, const unsigned char *data) -{ - int i; - - if (!debug) - return; - - printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", - function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -} - +static void skel_delete(struct kref *kref) +{ + struct usb_skel *dev = to_skel_dev(kref); -/** - * skel_delete - */ -static inline void skel_delete (struct usb_skel *dev) -{ + usb_put_dev(dev->udev); kfree (dev->bulk_in_buffer); - usb_buffer_free (dev->udev, dev->bulk_out_size, - dev->bulk_out_buffer, - dev->write_urb->transfer_dma); - usb_free_urb (dev->write_urb); kfree (dev); } - -/** - * skel_open - */ -static int skel_open (struct inode *inode, struct file *file) +static int skel_open(struct inode *inode, struct file *file) { - struct usb_skel *dev = NULL; + struct usb_skel *dev; struct usb_interface *interface; int subminor; int retval = 0; - dbg("%s", __FUNCTION__); - subminor = iminor(inode); - /* prevent disconnects */ - down (&disconnect_sem); - - interface = usb_find_interface (&skel_driver, subminor); + interface = usb_find_interface(&skel_driver, subminor); if (!interface) { err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); retval = -ENODEV; - goto exit_no_device; + goto exit; } dev = usb_get_intfdata(interface); if (!dev) { retval = -ENODEV; - goto exit_no_device; + goto exit; } - /* lock this device */ - down (&dev->sem); - - /* increment our usage count for the driver */ - ++dev->open; + /* increment our usage count for the device */ + kref_get(&dev->kref); /* save our object in the file's private structure */ file->private_data = dev; - /* unlock this device */ - up (&dev->sem); - -exit_no_device: - up (&disconnect_sem); +exit: return retval; } - -/** - * skel_release - */ -static int skel_release (struct inode *inode, struct file *file) +static int skel_release(struct inode *inode, struct file *file) { struct usb_skel *dev; - int retval = 0; dev = (struct usb_skel *)file->private_data; - if (dev == NULL) { - dbg ("%s - object is NULL", __FUNCTION__); + if (dev == NULL) return -ENODEV; - } - - dbg("%s - minor %d", __FUNCTION__, dev->minor); - - /* lock our device */ - down (&dev->sem); - - if (dev->open <= 0) { - dbg ("%s - device not opened", __FUNCTION__); - retval = -ENODEV; - goto exit_not_opened; - } - - /* wait for any bulk writes that might be going on to finish up */ - if (atomic_read (&dev->write_busy)) - wait_for_completion (&dev->write_finished); - - --dev->open; - if (!dev->present && !dev->open) { - /* the device was unplugged before the file was released */ - up (&dev->sem); - skel_delete (dev); - return 0; - } - -exit_not_opened: - up (&dev->sem); - - return retval; + /* decrement the count on our device */ + kref_put(&dev->kref, skel_delete); + return 0; } - -/** - * skel_read - */ -static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct usb_skel *dev; int retval = 0; dev = (struct usb_skel *)file->private_data; - - dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count); - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - up (&dev->sem); - return -ENODEV; - } - + /* do a blocking bulk read to get data from the device */ - retval = usb_bulk_msg (dev->udev, - usb_rcvbulkpipe (dev->udev, - dev->bulk_in_endpointAddr), - dev->bulk_in_buffer, - min (dev->bulk_in_size, count), - &count, HZ*10); + retval = usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), + dev->bulk_in_buffer, + min(dev->bulk_in_size, count), + &count, HZ*10); /* if the read was successful, copy the data to userspace */ if (!retval) { - if (copy_to_user (buffer, dev->bulk_in_buffer, count)) + if (copy_to_user(buffer, dev->bulk_in_buffer, count)) retval = -EFAULT; else retval = count; } - /* unlock the device */ - up (&dev->sem); return retval; } +static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_skel *dev; -/** - * skel_write - * - * A device driver has to decide how to report I/O errors back to the - * user. The safest course is to wait for the transfer to finish before - * returning so that any errors will be reported reliably. skel_read() - * works like this. But waiting for I/O is slow, so many drivers only - * check for errors during I/O initiation and do not report problems - * that occur during the actual transfer. That's what we will do here. - * - * A driver concerned with maximum I/O throughput would use double- - * buffering: Two urbs would be devoted to write transfers, so that - * one urb could always be active while the other was waiting for the - * user to send more data. - */ -static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos) + dev = (struct usb_skel *)urb->context; + + /* sync/async unlink faults aren't errors */ + if (urb->status && + !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) { + dbg("%s - nonzero write bulk status received: %d", + __FUNCTION__, urb->status); + } + + /* free up our allocated buffer */ + usb_buffer_free(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); +} + +static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) { struct usb_skel *dev; - ssize_t bytes_written = 0; int retval = 0; + struct urb *urb = NULL; + char *buf = NULL; dev = (struct usb_skel *)file->private_data; - dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count); - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - retval = -ENODEV; + /* verify that we actually have some data to write */ + if (count == 0) goto exit; + + /* create a urb, and a buffer for it, and copy the data to the urb */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + retval = -ENOMEM; + goto error; } - /* verify that we actually have some data to write */ - if (count == 0) { - dbg("%s - write request of 0 bytes", __FUNCTION__); - goto exit; + buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + goto error; } - /* wait for a previous write to finish up; we don't use a timeout - * and so a nonresponsive device can delay us indefinitely. - */ - if (atomic_read (&dev->write_busy)) - wait_for_completion (&dev->write_finished); - - /* we can only write as much as our buffer will hold */ - bytes_written = min (dev->bulk_out_size, count); - - /* copy the data from userspace into our transfer buffer; - * this is the only copy required. - */ - if (copy_from_user(dev->write_urb->transfer_buffer, buffer, - bytes_written)) { + if (copy_from_user(buf, user_buffer, count)) { retval = -EFAULT; - goto exit; + goto error; } - usb_skel_debug_data (__FUNCTION__, bytes_written, - dev->write_urb->transfer_buffer); - - /* this urb was already set up, except for this write size */ - dev->write_urb->transfer_buffer_length = bytes_written; + /* initialize the urb properly */ + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + buf, count, skel_write_bulk_callback, dev); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* send the data out the bulk port */ - /* a character device write uses GFP_KERNEL, - unless a spinlock is held */ - init_completion (&dev->write_finished); - atomic_set (&dev->write_busy, 1); - retval = usb_submit_urb(dev->write_urb, GFP_KERNEL); + retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - atomic_set (&dev->write_busy, 0); - err("%s - failed submitting write urb, error %d", - __FUNCTION__, retval); - } else { - retval = bytes_written; + err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); + goto error; } + /* release our reference to this urb, the USB core will eventually free it entirely */ + usb_free_urb(urb); + exit: - /* unlock the device */ - up (&dev->sem); + return count; +error: + usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); + usb_free_urb(urb); return retval; } +static struct file_operations skel_fops = { + .owner = THIS_MODULE, + .read = skel_read, + .write = skel_write, + .open = skel_open, + .release = skel_release, +}; -/** - * skel_ioctl - */ -static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usb_skel *dev; - - dev = (struct usb_skel *)file->private_data; - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - up (&dev->sem); - return -ENODEV; - } - - dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __FUNCTION__, - dev->minor, cmd, arg); - - /* fill in your device specific stuff here */ - - /* unlock the device */ - up (&dev->sem); - - /* return that we did not understand this ioctl call */ - return -ENOTTY; -} - - -/** - * skel_write_bulk_callback +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core */ -static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_skel *dev = (struct usb_skel *)urb->context; - - dbg("%s - minor %d", __FUNCTION__, dev->minor); - - /* sync/async unlink faults aren't errors */ - if (urb->status && !(urb->status == -ENOENT || - urb->status == -ECONNRESET)) { - dbg("%s - nonzero write bulk status received: %d", - __FUNCTION__, urb->status); - } - - /* notify anyone waiting that the write has finished */ - atomic_set (&dev->write_busy, 0); - complete (&dev->write_finished); -} - +static struct usb_class_driver skel_class = { + .name = "usb/skel%d", + .fops = &skel_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + .minor_base = USB_SKEL_MINOR_BASE, +}; -/** - * skel_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(interface); struct usb_skel *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; @@ -506,28 +237,21 @@ int i; int retval = -ENOMEM; - /* See if the device offered us matches what we can accept */ - if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || - (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) { - return -ENODEV; - } - /* allocate memory for our device state and initialize it */ - dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL); + dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - err ("Out of memory"); - return -ENOMEM; + err("Out of memory"); + goto error; } - memset (dev, 0x00, sizeof (*dev)); + memset(dev, 0x00, sizeof(*dev)); + kref_init(&dev->kref); - init_MUTEX (&dev->sem); - dev->udev = udev; + dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; /* set up the endpoint information */ - /* check out the endpoints */ /* use only the first bulk-in and bulk-out endpoints */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; @@ -539,9 +263,9 @@ buffer_size = endpoint->wMaxPacketSize; dev->bulk_in_size = buffer_size; dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); + err("Could not allocate bulk_in_buffer"); goto error; } } @@ -551,153 +275,85 @@ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk out endpoint */ - /* a probe() may sleep and has no restrictions on memory allocations */ - dev->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->write_urb) { - err("No free urbs available"); - goto error; - } dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; - - /* on some platforms using this kind of buffer alloc - * call eliminates a dma "bounce buffer". - * - * NOTE: you'd normally want i/o buffers that hold - * more than one packet, so that i/o delays between - * packets don't hurt throughput. - */ - buffer_size = endpoint->wMaxPacketSize; - dev->bulk_out_size = buffer_size; - dev->write_urb->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | - URB_ASYNC_UNLINK); - dev->bulk_out_buffer = usb_buffer_alloc (udev, - buffer_size, GFP_KERNEL, - &dev->write_urb->transfer_dma); - if (!dev->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); - goto error; - } - usb_fill_bulk_urb(dev->write_urb, udev, - usb_sndbulkpipe(udev, - endpoint->bEndpointAddress), - dev->bulk_out_buffer, buffer_size, - skel_write_bulk_callback, dev); } } if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Couldn't find both bulk-in and bulk-out endpoints"); + err("Could not find both bulk-in and bulk-out endpoints"); goto error; } - /* allow device read, write and ioctl */ - dev->present = 1; + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); /* we can register the device now, as it is ready */ - usb_set_intfdata (interface, dev); - retval = usb_register_dev (interface, &skel_class); + retval = usb_register_dev(interface, &skel_class); if (retval) { /* something prevented us from registering this driver */ - err ("Not able to get a minor for this device."); - usb_set_intfdata (interface, NULL); + err("Not able to get a minor for this device."); + usb_set_intfdata(interface, NULL); goto error; } - dev->minor = interface->minor; - /* let the user know what node this device is now attached to */ - info ("USB Skeleton device now attached to USBSkel-%d", dev->minor); + info("USB Skeleton device now attached to USBSkel-%d", interface->minor); return 0; error: - skel_delete (dev); + if (dev) + kref_put(&dev->kref, skel_delete); return retval; } - -/** - * skel_disconnect - * - * Called by the usb core when the device is removed from the system. - * - * This routine guarantees that the driver will not submit any more urbs - * by clearing dev->udev. It is also supposed to terminate any currently - * active urbs. Unfortunately, usb_bulk_msg(), used in skel_read(), does - * not provide any way to do this. But at least we can cancel an active - * write. - */ static void skel_disconnect(struct usb_interface *interface) { struct usb_skel *dev; - int minor; + int minor = interface->minor; - /* prevent races with open() */ - down (&disconnect_sem); + /* prevent skel_open() from racing skel_disconnect() */ + lock_kernel(); - dev = usb_get_intfdata (interface); - usb_set_intfdata (interface, NULL); - - down (&dev->sem); - - minor = dev->minor; + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); /* give back our minor */ - usb_deregister_dev (interface, &skel_class); + usb_deregister_dev(interface, &skel_class); - /* terminate an ongoing write */ - if (atomic_read (&dev->write_busy)) { - usb_unlink_urb (dev->write_urb); - wait_for_completion (&dev->write_finished); - } - - /* prevent device read, write and ioctl */ - dev->present = 0; - - up (&dev->sem); + unlock_kernel(); - /* if the device is opened, skel_release will clean this up */ - if (!dev->open) - skel_delete (dev); - - up (&disconnect_sem); + /* decrement our usage count */ + kref_put(&dev->kref, skel_delete); info("USB Skeleton #%d now disconnected", minor); } +static struct usb_driver skel_driver = { + .owner = THIS_MODULE, + .name = "skeleton", + .probe = skel_probe, + .disconnect = skel_disconnect, + .id_table = skel_table, +}; - -/** - * usb_skel_init - */ static int __init usb_skel_init(void) { int result; /* register this driver with the USB subsystem */ result = usb_register(&skel_driver); - if (result) { - err("usb_register failed. Error number %d", - result); - return result; - } + if (result) + err("usb_register failed. Error number %d", result); - info(DRIVER_DESC " " DRIVER_VERSION); - return 0; + return result; } - -/** - * usb_skel_exit - */ static void __exit usb_skel_exit(void) { /* deregister this driver with the USB subsystem */ usb_deregister(&skel_driver); } - module_init (usb_skel_init); module_exit (usb_skel_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/68328fb.c b/drivers/video/68328fb.c --- a/drivers/video/68328fb.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/video/68328fb.c 2004-10-18 14:56:48 -07:00 @@ -199,6 +199,15 @@ */ switch (var->bits_per_pixel) { case 1: + var->red.offset = 0; + var->red.length = 1; + var->green.offset = 0; + var->green.length = 1; + var->blue.offset = 0; + var->blue.length = 1; + var->transp.offset = 0; + var->transp.length = 0; + break; case 8: var->red.offset = 0; var->red.length = 8; @@ -430,6 +439,13 @@ int __init mc68x328fb_init(void) { +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("68328fb", &option)) + return -ENODEV; + mc68x328fb_setup(option); +#endif /* * initialize the default mode from the LCD controller registers */ @@ -452,8 +468,12 @@ get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel); fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ? MC68X328FB_MONO_VISUAL : FB_VISUAL_PSEUDOCOLOR; + if (fb_info.var.bits_per_pixel == 1) { + fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1; + fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0; + } fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; - fb_info.flags = FBINFO_FLAG_DEFAULT; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; fb_alloc_cmap(&fb_info.cmap, 256, 0); @@ -471,6 +491,8 @@ return 0; } +module_init(mc68x328fb_init); + #ifdef MODULE static void __exit mc68x328fb_cleanup(void) @@ -478,7 +500,6 @@ unregister_framebuffer(&fb_info); } -module_init(mc68x328fb_init); module_exit(mc68x328fb_cleanup); MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig --- a/drivers/video/Kconfig 2004-10-18 14:55:54 -07:00 +++ b/drivers/video/Kconfig 2004-10-18 14:55:54 -07:00 @@ -38,6 +38,17 @@ (e.g. an accelerated X server) and that are not frame buffer device-aware may cause unexpected results. If unsure, say N. +config FB_MODE_HELPERS + bool "Enable Video Mode Handling Helpers" + depends on FB + default y + ---help--- + This enables functions for handling video modes using the + Generalized Timing Formula and the EDID parser. A few drivers rely + on this feature such as the radeonfb, rivafb, and the i810fb. If + your driver does not take advantage of this feature, choosing Y will + just increase the kernel size by about 5K. + config FB_CIRRUS tristate "Cirrus Logic support" depends on FB && (ZORRO || PCI) @@ -68,6 +79,19 @@ help Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2). +config FB_ARMCLCD + tristate "ARM PrimeCell PL110 support" + depends on FB && ARM && ARM_AMBA + help + This framebuffer device driver is for the ARM PrimeCell PL110 + Colour LCD controller. ARM PrimeCells provide the building + blocks for System on a Chip devices. + + If you want to compile this as a module (=code which can be + inserted into and removed from the running kernel), say M + here and read . The module + will be called amba-clcd. + config FB_ACORN bool "Acorn VIDC support" depends on FB && ARM && ARCH_ACORN @@ -392,40 +416,21 @@ (). Please see the file . -config FB_E1355 +config FB_EPSON1355 bool "Epson 1355 framebuffer support" - depends on FB && SUPERH + depends on FB && (SUPERH || ARCH_CEIVA) help Build in support for the SED1355 Epson Research Embedded RAMDAC LCD/CRT Controller (since redesignated as the S1D13505) as a framebuffer. Product specs at . -config E1355_REG_BASE - hex "Register Base Address" - depends on FB_E1355 - default "a8000000" - help - Epson SED1355/S1D13505 LCD/CRT controller register base address. - See the manuals at - for - discussion. - -config E1355_FB_BASE - hex "Framebuffer Base Address" - depends on FB_E1355 - default "a8200000" - help - Epson SED1355/S1D13505 LCD/CRT controller memory base address. See - the manuals at - for - discussion. - config FB_RIVA tristate "nVidia Riva support" depends on FB && PCI select I2C_ALGOBIT if FB_RIVA_I2C select I2C if FB_RIVA_I2C + select FB_MODE_HELPERS help This driver supports graphics boards with the nVidia Riva/Geforce chips. @@ -457,7 +462,10 @@ config FB_I810 tristate "Intel 810/815 support (EXPERIMENTAL)" - depends on FB && AGP && AGP_INTEL && EXPERIMENTAL && PCI + depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 + select AGP + select AGP_INTEL + select FB_MODE_HELPERS help This driver supports the on-board graphics built in to the Intel 810 and 815 chipsets. Say Y if you have and plan to use such a board. @@ -661,6 +669,7 @@ depends on FB && PCI select I2C_ALGOBIT if FB_RADEON_I2C select I2C if FB_RADEON_I2C + select FB_MODE_HELPERS help Choose this option if you want to use an ATI Radeon graphics card as a framebuffer device. There are both PCI and AGP versions. You @@ -766,6 +775,7 @@ config FB_NEOMAGIC tristate "NeoMagic display support" depends on FB && PCI + select FB_MODE_HELPERS help This driver supports notebooks with NeoMagic PCI chips. Say Y if you have such a graphics card. diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile --- a/drivers/video/Makefile 2004-10-18 14:55:55 -07:00 +++ b/drivers/video/Makefile 2004-10-18 14:55:55 -07:00 @@ -13,80 +13,88 @@ obj-$(CONFIG_PPC) += macmodes.o endif -obj-$(CONFIG_FB_ACORN) += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +# Hardware specific drivers go first +obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_CYBER) += cyberfb.o +obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PM2) += pm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PM3) += pm3fb.o -obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_ATARI) += atafb.o -obj-$(CONFIG_FB_68328) += 68328fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o + +obj-$(CONFIG_FB_MATROX) += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o +obj-$(CONFIG_FB_ATY) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_ATY128) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_RADEON) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_SIS) += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_KYRO) += kyro/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o + +obj-$(CONFIG_FB_I810) += cfbcopyarea.o cfbfillrect.o cfbimgblt.o \ + vgastate.o obj-$(CONFIG_FB_RADEON_OLD) += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_NEOMAGIC) += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o vgastate.o -obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_VIRGE) += virgefb.o +obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o +ifneq ($(CONFIG_FB_3DFX_ACCEL),y) +obj-$(CONFIG_FB_3DFX) += cfbfillrect.o cfbcopyarea.o +endif obj-$(CONFIG_FB_CONTROL) += controlfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_CYBER) += cyberfb.o -obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_GBE) += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o -obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_HP300) += hpfb.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o cfbimgblt.o -obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o -obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_TRIDENT) += tridentfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o -obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ - cfbimgblt.o vgastate.o -obj-$(CONFIG_FB_VIRGE) += virgefb.o -obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_STI) += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o - -obj-$(CONFIG_FB_MATROX) += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o -obj-$(CONFIG_FB_SIS) += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_ATY) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_ATY128) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_RADEON) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_I810) += i810/ cfbfillrect.o cfbcopyarea.o \ - cfbimgblt.o vgastate.o - -obj-$(CONFIG_FB_SUN3) += sun3fb.o +obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ACORN) += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ATARI) += atafb.o +obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_HGA) += hgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_HP300) += hpfb.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_E1355) += epson1355fb.o +obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_KYRO) += kyro/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_68328) += 68328fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_GBE) += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PXA) += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o + +# Platform or fallback drivers go here +obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ + cfbimgblt.o vgastate.o +obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_PXA) += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o +# the test framebuffer is last +obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o diff -Nru a/drivers/video/acornfb.c b/drivers/video/acornfb.c --- a/drivers/video/acornfb.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/video/acornfb.c 2004-10-18 14:57:04 -07:00 @@ -1010,7 +1010,7 @@ first = 0; fb_info.fbops = &acornfb_ops; - fb_info.flags = FBINFO_FLAG_DEFAULT; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; fb_info.pseudo_palette = current_par.pseudo_palette; strcpy(fb_info.fix.id, "Acorn"); @@ -1291,6 +1291,11 @@ unsigned long size; u_int h_sync, v_sync; int rc, i; + char *option = NULL; + + if (fb_get_options("acornfb", &option)) + return -ENODEV; + acornfb_setup(option); acornfb_init_fbinfo(); @@ -1455,6 +1460,8 @@ return -EINVAL; return 0; } + +module_init(acornfb_init); MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver"); diff -Nru a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/amba-clcd.c 2004-10-18 14:57:24 -07:00 @@ -0,0 +1,515 @@ +/* + * linux/drivers/video/amba-clcd.c + * + * Copyright (C) 2001 ARM Limited, by David A Rusling + * Updated to 2.5, Deep Blue Solutions Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * ARM PrimeCell PL110 Color LCD Controller + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define to_clcd(info) container_of(info, struct clcd_fb, fb) + +/* This is limited to 16 characters when displayed by X startup */ +static const char *clcd_name = "CLCD FB"; + +/* + * Unfortunately, the enable/disable functions may be called either from + * process or IRQ context, and we _need_ to delay. This is _not_ good. + */ +static inline void clcdfb_sleep(unsigned int ms) +{ + if (in_atomic()) { + mdelay(ms); + } else { + msleep(ms); + } +} + +static inline void clcdfb_set_start(struct clcd_fb *fb) +{ + unsigned long ustart = fb->fb.fix.smem_start; + unsigned long lstart; + + ustart += fb->fb.var.yoffset * fb->fb.fix.line_length; + lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2; + + writel(ustart, fb->regs + CLCD_UBAS); + writel(lstart, fb->regs + CLCD_LBAS); +} + +static void clcdfb_disable(struct clcd_fb *fb) +{ + u32 val; + + if (fb->board->disable) + fb->board->disable(fb); + + val = readl(fb->regs + CLCD_CNTL); + if (val & CNTL_LCDPWR) { + val &= ~CNTL_LCDPWR; + writel(val, fb->regs + CLCD_CNTL); + + clcdfb_sleep(20); + } + if (val & CNTL_LCDEN) { + val &= ~CNTL_LCDEN; + writel(val, fb->regs + CLCD_CNTL); + } + + /* + * Disable CLCD clock source. + */ + clk_disable(fb->clk); +} + +static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) +{ + /* + * Enable the CLCD clock source. + */ + clk_enable(fb->clk); + + /* + * Bring up by first enabling.. + */ + cntl |= CNTL_LCDEN; + writel(cntl, fb->regs + CLCD_CNTL); + + clcdfb_sleep(20); + + /* + * and now apply power. + */ + cntl |= CNTL_LCDPWR; + writel(cntl, fb->regs + CLCD_CNTL); + + /* + * finally, enable the interface. + */ + if (fb->board->enable) + fb->board->enable(fb); +} + +static int +clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) +{ + int ret = 0; + + memset(&var->transp, 0, sizeof(var->transp)); + memset(&var->red, 0, sizeof(var->red)); + memset(&var->green, 0, sizeof(var->green)); + memset(&var->blue, 0, sizeof(var->blue)); + + switch (var->bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + var->red.length = 8; + var->red.offset = 0; + var->green.length = 8; + var->green.offset = 0; + var->blue.length = 8; + var->blue.offset = 0; + break; + case 16: + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + if (fb->panel->cntl & CNTL_BGR) { + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + } else { + var->red.offset = 0; + var->green.offset = 5; + var->blue.offset = 10; + } + break; + case 24: + if (fb->panel->cntl & CNTL_LCDTFT) { + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + + if (fb->panel->cntl & CNTL_BGR) { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + } else { + var->red.offset = 0; + var->green.offset = 8; + var->blue.offset = 16; + } + break; + } + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + int ret = -EINVAL; + + if (fb->board->check) + ret = fb->board->check(fb, var); + if (ret == 0) + ret = clcdfb_set_bitfields(fb, var); + + return ret; +} + +static int clcdfb_set_par(struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + struct clcd_regs regs; + + fb->fb.fix.line_length = fb->fb.var.xres_virtual * + fb->fb.var.bits_per_pixel / 8; + + if (fb->fb.var.bits_per_pixel <= 8) + fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + + fb->board->decode(fb, ®s); + + clcdfb_disable(fb); + + writel(regs.tim0, fb->regs + CLCD_TIM0); + writel(regs.tim1, fb->regs + CLCD_TIM1); + writel(regs.tim2, fb->regs + CLCD_TIM2); + writel(regs.tim3, fb->regs + CLCD_TIM3); + + clcdfb_set_start(fb); + + clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000); + + fb->clcd_cntl = regs.cntl; + + clcdfb_enable(fb, regs.cntl); + +#ifdef DEBUG + printk(KERN_INFO "CLCD: Registers set to\n" + KERN_INFO " %08x %08x %08x %08x\n" + KERN_INFO " %08x %08x %08x %08x\n", + readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1), + readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3), + readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS), + readl(fb->regs + CLCD_IENB), readl(fb->regs + CLCD_CNTL)); +#endif + + return 0; +} + +static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) +{ + unsigned int mask = (1 << bf->length) - 1; + + return (val >> (16 - bf->length) & mask) << bf->offset; +} + +/* + * Set a single color register. The values supplied have a 16 bit + * magnitude. Return != 0 for invalid regno. + */ +static int +clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + + if (regno < 16) + fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | + convert_bitfield(blue, &fb->fb.var.blue) | + convert_bitfield(green, &fb->fb.var.green) | + convert_bitfield(red, &fb->fb.var.red); + + if (fb->fb.var.bits_per_pixel == 8 && regno < 256) { + int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3); + u32 val, mask, newval; + + newval = (red >> 11) & 0x001f; + newval |= (green >> 6) & 0x03e0; + newval |= (blue >> 1) & 0x7c00; + + /* + * 3.2.11: if we're configured for big endian + * byte order, the palette entries are swapped. + */ + if (fb->clcd_cntl & CNTL_BEBO) + regno ^= 1; + + if (regno & 1) { + newval <<= 16; + mask = 0x0000ffff; + } else { + mask = 0xffff0000; + } + + val = readl(fb->regs + hw_reg) & mask; + writel(val | newval, fb->regs + hw_reg); + } + + return regno > 255; +} + +/* + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +static int clcdfb_blank(int blank_mode, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + + if (blank_mode != 0) { + clcdfb_disable(fb); + } else { + clcdfb_enable(fb, fb->clcd_cntl); + } + return 0; +} + +static struct fb_ops clcdfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = clcdfb_check_var, + .fb_set_par = clcdfb_set_par, + .fb_setcolreg = clcdfb_setcolreg, + .fb_blank = clcdfb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static int clcdfb_register(struct clcd_fb *fb) +{ + int ret; + + fb->clk = clk_get(&fb->dev->dev, "CLCDCLK"); + if (IS_ERR(fb->clk)) { + ret = PTR_ERR(fb->clk); + goto out; + } + + ret = clk_use(fb->clk); + if (ret) + goto free_clk; + + fb->fb.fix.mmio_start = fb->dev->res.start; + fb->fb.fix.mmio_len = SZ_4K; + + fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); + if (!fb->regs) { + printk(KERN_ERR "CLCD: unable to remap registers\n"); + ret = -ENOMEM; + goto unuse_clk; + } + + fb->fb.fbops = &clcdfb_ops; + fb->fb.flags = FBINFO_FLAG_DEFAULT; + fb->fb.pseudo_palette = fb->cmap; + + strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id)); + fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fb->fb.fix.type_aux = 0; + fb->fb.fix.xpanstep = 0; + fb->fb.fix.ypanstep = 0; + fb->fb.fix.ywrapstep = 0; + fb->fb.fix.accel = FB_ACCEL_NONE; + + fb->fb.var.xres = fb->panel->mode.xres; + fb->fb.var.yres = fb->panel->mode.yres; + fb->fb.var.xres_virtual = fb->panel->mode.xres; + fb->fb.var.yres_virtual = fb->panel->mode.yres; + fb->fb.var.bits_per_pixel = fb->panel->bpp; + fb->fb.var.grayscale = fb->panel->grayscale; + fb->fb.var.pixclock = fb->panel->mode.pixclock; + fb->fb.var.left_margin = fb->panel->mode.left_margin; + fb->fb.var.right_margin = fb->panel->mode.right_margin; + fb->fb.var.upper_margin = fb->panel->mode.upper_margin; + fb->fb.var.lower_margin = fb->panel->mode.lower_margin; + fb->fb.var.hsync_len = fb->panel->mode.hsync_len; + fb->fb.var.vsync_len = fb->panel->mode.vsync_len; + fb->fb.var.sync = fb->panel->mode.sync; + fb->fb.var.vmode = fb->panel->mode.vmode; + fb->fb.var.activate = FB_ACTIVATE_NOW; + fb->fb.var.nonstd = 0; + fb->fb.var.height = fb->panel->height; + fb->fb.var.width = fb->panel->width; + fb->fb.var.accel_flags = 0; + + fb->fb.monspecs.hfmin = 0; + fb->fb.monspecs.hfmax = 100000; + fb->fb.monspecs.vfmin = 0; + fb->fb.monspecs.vfmax = 400; + fb->fb.monspecs.dclkmin = 1000000; + fb->fb.monspecs.dclkmax = 100000000; + + /* + * Make sure that the bitfields are set appropriately. + */ + clcdfb_set_bitfields(fb, &fb->fb.var); + + /* + * Allocate colourmap. + */ + fb_alloc_cmap(&fb->fb.cmap, 256, 0); + + /* + * Ensure interrupts are disabled. + */ + writel(0, fb->regs + CLCD_IENB); + + fb_set_var(&fb->fb, &fb->fb.var); + + printk(KERN_INFO "CLCD: %s hardware, %s display\n", + fb->board->name, fb->panel->mode.name); + + ret = register_framebuffer(&fb->fb); + if (ret == 0) + goto out; + + printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); + + iounmap(fb->regs); + unuse_clk: + clk_unuse(fb->clk); + free_clk: + clk_put(fb->clk); + out: + return ret; +} + +static int clcdfb_probe(struct amba_device *dev, void *id) +{ + struct clcd_board *board = dev->dev.platform_data; + struct clcd_fb *fb; + int ret; + + if (!board) + return -EINVAL; + + ret = amba_request_regions(dev, NULL); + if (ret) { + printk(KERN_ERR "CLCD: unable to reserve regs region\n"); + goto out; + } + + fb = (struct clcd_fb *) kmalloc(sizeof(struct clcd_fb), GFP_KERNEL); + if (!fb) { + printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); + ret = -ENOMEM; + goto free_region; + } + memset(fb, 0, sizeof(struct clcd_fb)); + + fb->dev = dev; + fb->board = board; + + ret = fb->board->setup(fb); + if (ret) + goto free_fb; + + ret = clcdfb_register(fb); + if (ret == 0) { + amba_set_drvdata(dev, fb); + goto out; + } + + fb->board->remove(fb); + free_fb: + kfree(fb); + free_region: + amba_release_regions(dev); + out: + return ret; +} + +static int clcdfb_remove(struct amba_device *dev) +{ + struct clcd_fb *fb = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + clcdfb_disable(fb); + unregister_framebuffer(&fb->fb); + iounmap(fb->regs); + clk_unuse(fb->clk); + clk_put(fb->clk); + + fb->board->remove(fb); + + kfree(fb); + + amba_release_regions(dev); + + return 0; +} + +static struct amba_id clcdfb_id_table[] = { + { + .id = 0x00041110, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver clcd_driver = { + .drv = { + .name = "clcd-pl110", + }, + .probe = clcdfb_probe, + .remove = clcdfb_remove, + .id_table = clcdfb_id_table, +}; + +int __init amba_clcdfb_init(void) +{ + if (fb_get_options("ambafb", NULL)) + return -ENODEV; + + return amba_driver_register(&clcd_driver); +} + +module_init(amba_clcdfb_init); + +static void __exit amba_clcdfb_exit(void) +{ + amba_driver_unregister(&clcd_driver); +} + +module_exit(amba_clcdfb_exit); + +MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/amifb.c b/drivers/video/amifb.c --- a/drivers/video/amifb.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/video/amifb.c 2004-10-18 14:56:50 -07:00 @@ -1307,6 +1307,8 @@ info->fix.ywrapstep = 1; info->fix.xpanstep = 0; info->fix.ypanstep = 0; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | + FBINFO_READS_FAST; /* override SCROLL_REDRAW */ } else { info->fix.ywrapstep = 0; if (par->vmode & FB_VMODE_SMOOTH_XPAN) @@ -1314,6 +1316,7 @@ else info->fix.xpanstep = 16<fix.ypanstep = 1; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; } return 0; } @@ -2254,6 +2257,13 @@ u_long chipptr; u_int defmode; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("amifb", &option)) + return -ENODEV; + amifb_setup(option); +#endif if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) return -ENXIO; @@ -2382,7 +2392,7 @@ fb_info.fbops = &amifb_ops; fb_info.par = ¤tpar; - fb_info.flags = FBINFO_FLAG_DEFAULT; + fb_info.flags = FBINFO_DEFAULT; if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { @@ -3811,13 +3821,10 @@ } +module_init(amifb_init); + #ifdef MODULE MODULE_LICENSE("GPL"); - -int init_module(void) -{ - return amifb_init(); -} void cleanup_module(void) { diff -Nru a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c --- a/drivers/video/asiliantfb.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/video/asiliantfb.c 2004-10-18 14:57:03 -07:00 @@ -524,7 +524,7 @@ p->fix.smem_start = addr; p->var = asiliantfb_var; p->fbops = &asiliantfb_ops; - p->flags = FBINFO_FLAG_DEFAULT; + p->flags = FBINFO_DEFAULT; fb_alloc_cmap(&p->cmap, 256, 0); @@ -609,8 +609,13 @@ int __init asiliantfb_init(void) { + if (fb_get_options("asiliantfb", NULL)) + return -ENODEV; + return pci_module_init(&asiliantfb_driver); } + +module_init(asiliantfb_init); static void __exit asiliantfb_exit(void) { diff -Nru a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c --- a/drivers/video/aty/aty128fb.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/video/aty/aty128fb.c 2004-10-18 14:56:29 -07:00 @@ -2439,6 +2439,14 @@ int __init aty128fb_init(void) { +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("aty128fb", &option)) + return -ENODEV; + aty128fb_setup(option); +#endif + return pci_module_init(&aty128fb_driver); } @@ -2447,8 +2455,9 @@ pci_unregister_driver(&aty128fb_driver); } -#ifdef MODULE module_init(aty128fb_init); + +#ifdef MODULE module_exit(aty128fb_exit); MODULE_AUTHOR("(c)1999-2003 Brad Douglas "); diff -Nru a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c --- a/drivers/video/aty/atyfb_base.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/video/aty/atyfb_base.c 2004-10-18 14:56:48 -07:00 @@ -1902,7 +1902,7 @@ return 1; } -int __init atyfb_init(void) +int __init atyfb_do_init(void) { #if defined(CONFIG_PCI) unsigned long addr, res_start, res_size; @@ -1917,12 +1917,14 @@ char prop[128]; int node, len, j; u32 mem, chip_id; +#else + u16 tmp; +#endif +#ifdef __sparc__ /* Do not attach when we have a serial console. */ if (!con_is_present()) return -ENXIO; -#else - u16 tmp; #endif while ((pdev = @@ -2377,6 +2379,19 @@ return 0; } +int __init atyfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("atyfb", &option)) + return -ENODEV; + atyfb_setup(option); +#endif + return atyfb_do_init(); +} + + #ifndef MODULE int __init atyfb_setup(char *options) { @@ -2445,6 +2460,7 @@ } return 0; } +module_init(atyfb_init); #endif /* !MODULE */ #ifdef CONFIG_ATARI diff -Nru a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c --- a/drivers/video/aty/radeon_base.c 2004-10-18 14:56:28 -07:00 +++ b/drivers/video/aty/radeon_base.c 2004-10-18 14:56:28 -07:00 @@ -282,7 +282,7 @@ static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) { - void *rom; + void __iomem *rom; struct resource *r; u16 dptr; u8 rom_type; @@ -395,13 +395,13 @@ * if we end up having conflicts */ u32 segstart; - unsigned char *rom_base = NULL; + void __iomem *rom_base = NULL; for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { - rom_base = (char *)ioremap(segstart, 0x10000); + rom_base = ioremap(segstart, 0x10000); if (rom_base == NULL) return -ENOMEM; - if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) + if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa) break; iounmap(rom_base); rom_base = NULL; @@ -1702,68 +1702,6 @@ } - -static ssize_t radeonfb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - struct inode *inode = file->f_dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - struct radeonfb_info *rinfo = info->par; - - if (p >= rinfo->mapped_vram) - return 0; - if (count >= rinfo->mapped_vram) - count = rinfo->mapped_vram; - if (count + p > rinfo->mapped_vram) - count = rinfo->mapped_vram - p; - radeonfb_sync(info); - if (count) { - char *base_addr; - - base_addr = info->screen_base; - count -= copy_to_user(buf, base_addr+p, count); - if (!count) - return -EFAULT; - *ppos += count; - } - return count; -} - -static ssize_t radeonfb_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) -{ - unsigned long p = *ppos; - struct inode *inode = file->f_dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - struct radeonfb_info *rinfo = info->par; - int err; - - if (p > rinfo->mapped_vram) - return -ENOSPC; - if (count >= rinfo->mapped_vram) - count = rinfo->mapped_vram; - err = 0; - if (count + p > rinfo->mapped_vram) { - count = rinfo->mapped_vram - p; - err = -ENOSPC; - } - radeonfb_sync(info); - if (count) { - char *base_addr; - - base_addr = info->screen_base; - count -= copy_from_user(base_addr+p, buf, count); - *ppos += count; - err = -EFAULT; - } - if (count) - return count; - return err; -} - - static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, .fb_check_var = radeonfb_check_var, @@ -1776,8 +1714,6 @@ .fb_fillrect = radeonfb_fillrect, .fb_copyarea = radeonfb_copyarea, .fb_imageblit = radeonfb_imageblit, - .fb_read = radeonfb_read, - .fb_write = radeonfb_write, .fb_cursor = soft_cursor, }; @@ -1795,8 +1731,8 @@ | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; info->fbops = &radeonfb_ops; - info->screen_base = (char *)rinfo->fb_base; - + info->screen_base = rinfo->fb_base; + info->screen_size = rinfo->mapped_vram; /* Fill fix common fields */ strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id)); info->fix.smem_start = rinfo->fb_base_phys; @@ -1932,7 +1868,7 @@ #undef SET_MC_FB_FROM_APERTURE static void fixup_memory_mappings(struct radeonfb_info *rinfo) { - u32 save_crtc_gen_cntl, save_crtc2_gen_cntl; + u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0; u32 save_crtc_ext_cntl; u32 aper_base, aper_size; u32 agp_base; @@ -2069,19 +2005,22 @@ struct fb_info *info; struct radeonfb_info *rinfo; u32 tmp; + int ret; RTRACE("radeonfb_pci_register BEGIN\n"); /* Enable device in PCI config */ - if (pci_enable_device(pdev) != 0) { + ret = pci_enable_device(pdev); + if (ret < 0) { printk(KERN_ERR "radeonfb: Cannot enable PCI device\n"); - return -ENODEV; + goto err_out; } info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev); if (!info) { printk (KERN_ERR "radeonfb: could not allocate memory\n"); - return -ENODEV; + ret = -ENOMEM; + goto err_disable; } rinfo = info->par; rinfo->info = info; @@ -2106,23 +2045,19 @@ rinfo->mmio_base_phys = pci_resource_start (pdev, 2); /* request the mem regions */ - if (!request_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0), "radeonfb")) { - printk (KERN_ERR "radeonfb: cannot reserve FB region\n"); - goto free_rinfo; - } - - if (!request_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2), "radeonfb")) { - printk (KERN_ERR "radeonfb: cannot reserve MMIO region\n"); - goto release_fb; + ret = pci_request_regions(pdev, "radeonfb"); + if (ret < 0) { + printk( KERN_ERR "radeonfb: cannot reserve PCI regions." + " Someone already got them?\n"); + goto err_release_fb; } /* map the regions */ - rinfo->mmio_base = (unsigned long) ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE); + rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE); if (!rinfo->mmio_base) { - printk (KERN_ERR "radeonfb: cannot map MMIO\n"); - goto release_mmio; + printk(KERN_ERR "radeonfb: cannot map MMIO\n"); + ret = -EIO; + goto err_release_pci; } /* On PPC, the firmware sets up a memory mapping that tends @@ -2226,33 +2161,24 @@ RTRACE("radeonfb: probed %s %ldk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024)); - rinfo->mapped_vram = MAX_MAPPED_VRAM; - if (rinfo->video_ram < rinfo->mapped_vram) - rinfo->mapped_vram = rinfo->video_ram; - for (;;) { - rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys, - rinfo->mapped_vram); - if (rinfo->fb_base == 0 && rinfo->mapped_vram > MIN_MAPPED_VRAM) { - rinfo->mapped_vram /= 2; - continue; - } - memset_io(rinfo->fb_base, 0, rinfo->mapped_vram); - break; - } + rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram); + + do { + rinfo->fb_base = ioremap (rinfo->fb_base_phys, + rinfo->mapped_vram); + } while ( rinfo->fb_base == 0 && + ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) ); - if (!rinfo->fb_base) { + if (rinfo->fb_base) + memset_io(rinfo->fb_base, 0, rinfo->mapped_vram); + else { printk (KERN_ERR "radeonfb: cannot map FB\n"); - goto unmap_rom; + ret = -EIO; + goto err_unmap_rom; } RTRACE("radeonfb: mapped %ldk videoram\n", rinfo->mapped_vram/1024); - - /* Argh. Scary arch !!! */ -#ifdef CONFIG_PPC64 - rinfo->fb_base = IO_TOKEN_TO_ADDR(rinfo->fb_base); -#endif - /* * Check for required workaround for PLL accesses */ @@ -2330,9 +2256,10 @@ printk("radeonfb: Power Management enabled for Mobility chipsets\n"); } - if (register_framebuffer(info) < 0) { + ret = register_framebuffer(info); + if (ret < 0) { printk (KERN_ERR "radeonfb: could not register framebuffer\n"); - goto unmap_fb; + goto err_unmap_fb; } #ifdef CONFIG_MTRR @@ -2358,30 +2285,30 @@ RTRACE("radeonfb_pci_register END\n"); return 0; -unmap_fb: - iounmap ((void*)rinfo->fb_base); -unmap_rom: +err_unmap_fb: + iounmap(rinfo->fb_base); +err_unmap_rom: if (rinfo->mon1_EDID) kfree(rinfo->mon1_EDID); if (rinfo->mon2_EDID) kfree(rinfo->mon2_EDID); if (rinfo->mon1_modedb) fb_destroy_modedb(rinfo->mon1_modedb); + fb_dealloc_cmap(&info->cmap); #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); #endif if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); - iounmap ((void*)rinfo->mmio_base); -release_mmio: - release_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2)); -release_fb: - release_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0)); -free_rinfo: + iounmap(rinfo->mmio_base); +err_release_pci: + pci_release_regions(pdev); +err_release_fb: framebuffer_release(info); - return -ENODEV; +err_disable: + pci_disable_device(pdev); +err_out: + return ret; } @@ -2410,13 +2337,10 @@ unregister_framebuffer(info); - iounmap ((void*)rinfo->mmio_base); - iounmap ((void*)rinfo->fb_base); + iounmap(rinfo->mmio_base); + iounmap(rinfo->fb_base); - release_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2)); - release_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0)); + pci_release_regions(pdev); if (rinfo->mon1_EDID) kfree(rinfo->mon1_EDID); @@ -2427,7 +2351,9 @@ #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); #endif + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); + pci_disable_device(pdev); } @@ -2442,9 +2368,17 @@ #endif /* CONFIG_PM */ }; +int __init radeonfb_setup (char *options); int __init radeonfb_init (void) { +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("radeonfb", &option)) + return -ENODEV; + radeonfb_setup(option); +#endif return pci_module_init (&radeonfb_driver); } @@ -2489,9 +2423,9 @@ return 0; } +module_init(radeonfb_init); #ifdef MODULE -module_init(radeonfb_init); module_exit(radeonfb_exit); #endif diff -Nru a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c --- a/drivers/video/aty/radeon_monitor.c 2004-10-18 14:55:46 -07:00 +++ b/drivers/video/aty/radeon_monitor.c 2004-10-18 14:55:46 -07:00 @@ -55,7 +55,7 @@ u8 *pedid = NULL; u8 *pmt = NULL; u8 *tmp; - int i, mt; + int i, mt = MT_NONE; RTRACE("analyzing OF properties...\n"); pmt = (u8 *)get_property(dp, "display-type", NULL); @@ -72,7 +72,9 @@ else if (strcmp(pmt, "NONE")) { printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n", pmt); return MT_NONE; - } + } else + return MT_NONE; + for (i = 0; propnames[i] != NULL; ++i) { pedid = (u8 *)get_property(dp, propnames[i], NULL); if (pedid != NULL) @@ -645,15 +647,23 @@ rinfo->panel_info.fbk_divider = 0xad; rinfo->panel_info.use_bios_dividers = 1; } + /* Aluminium PowerBook 15" */ + if (machine_is_compatible("PowerBook5,4")) { + rinfo->panel_info.ref_divider = rinfo->pll.ref_div; + rinfo->panel_info.post_divider = 0x2; + rinfo->panel_info.fbk_divider = 0x8e; + rinfo->panel_info.use_bios_dividers = 1; + } /* Aluminium PowerBook 17" */ - if (machine_is_compatible("PowerBook5,3")) { + if (machine_is_compatible("PowerBook5,3") || + machine_is_compatible("PowerBook5,5")) { rinfo->panel_info.ref_divider = rinfo->pll.ref_div; rinfo->panel_info.post_divider = 0x4; rinfo->panel_info.fbk_divider = 0x80; rinfo->panel_info.use_bios_dividers = 1; } /* iBook G4 */ - if (machine_is_compatible("PowerBook6,3") | + if (machine_is_compatible("PowerBook6,3") || machine_is_compatible("PowerBook6,5")) { rinfo->panel_info.ref_divider = rinfo->pll.ref_div; rinfo->panel_info.post_divider = 0x6; diff -Nru a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h --- a/drivers/video/aty/radeonfb.h 2004-10-18 14:57:19 -07:00 +++ b/drivers/video/aty/radeonfb.h 2004-10-18 14:57:19 -07:00 @@ -262,14 +262,14 @@ unsigned long mmio_base_phys; unsigned long fb_base_phys; - unsigned long mmio_base; - unsigned long fb_base; + void __iomem *mmio_base; + void __iomem *fb_base; - unsigned long fb_local_base; + unsigned long fb_local_base; struct pci_dev *pdev; - u8 *bios_seg; + void __iomem *bios_seg; int fp_bios_start; u32 pseudo_palette[17]; diff -Nru a/drivers/video/bw2.c b/drivers/video/bw2.c --- a/drivers/video/bw2.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/video/bw2.c 2004-10-18 14:56:33 -07:00 @@ -323,7 +323,7 @@ resp = &res; all->info.var.xres = all->info.var.xres_virtual = 1152; all->info.var.yres = all->info.var.yres_virtual = 900; - all->info.bits_per_pixel = 1; + all->info.var.bits_per_pixel = 1; linebytes = 1152 / 8; } else #else @@ -337,6 +337,10 @@ all->info.var.xres); } #endif + all->info.var.red.length = all->info.var.green.length = + all->info.var.blue.length = all->info.var.bits_per_pixel; + all->info.var.red.offset = all->info.var.green.offset = + all->info.var.blue.offset = 0; all->par.regs = (struct bw2_regs *) sbus_ioremap(resp, BWTWO_REGISTER_OFFSET, @@ -347,7 +351,7 @@ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT; all->info.fbops = &bw2_ops; #if defined(CONFIG_SPARC32) if (sdev) @@ -382,6 +386,9 @@ struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("bw2fb", &option)) + return -ENODEV; + #ifdef CONFIG_SUN4 bw2_init_one(NULL); #endif @@ -412,8 +419,9 @@ return 0; } -#ifdef MODULE module_init(bw2_init); + +#ifdef MODULE module_exit(bw2_exit); #endif diff -Nru a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c --- a/drivers/video/cfbcopyarea.c 2004-10-18 14:57:03 -07:00 +++ b/drivers/video/cfbcopyarea.c 2004-10-18 14:57:03 -07:00 @@ -43,8 +43,9 @@ #define BYTES_PER_LONG 8 #endif -static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, unsigned long n) +static void bitcpy(unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, + unsigned long n) { unsigned long first, last; int shift = dst_idx-src_idx, left, right; @@ -185,8 +186,8 @@ } } -static void bitcpy_rev(unsigned long *dst, int dst_idx, - const unsigned long *src, int src_idx, unsigned long n) +static void bitcpy_rev(unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, unsigned long n) { unsigned long first, last; int shift = dst_idx-src_idx, left, right; @@ -344,7 +345,7 @@ int x2, y2, old_dx, old_dy, vxres, vyres; unsigned long next_line = p->fix.line_length; int dst_idx = 0, src_idx = 0, rev_copy = 0; - unsigned long *dst = NULL, *src = NULL; + unsigned long __iomem *dst = NULL, *src = NULL; if (p->state != FBINFO_STATE_RUNNING) return; @@ -394,7 +395,7 @@ rev_copy = 1; } - dst = src = (unsigned long *)((unsigned long)p->screen_base & + dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(BYTES_PER_LONG-1)); dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1); dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel; diff -Nru a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c --- a/drivers/video/cfbfillrect.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/video/cfbfillrect.c 2004-10-18 14:56:32 -07:00 @@ -119,7 +119,7 @@ * Unaligned 32-bit pattern fill using 32/64-bit memory accesses */ -void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +void bitfill32(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n) { unsigned long val = pat; unsigned long first, last; @@ -178,7 +178,7 @@ * used for the next 32/64-bit word */ -void bitfill(unsigned long *dst, int dst_idx, unsigned long pat, int left, +void bitfill(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left, int right, u32 n) { unsigned long first, last; @@ -228,7 +228,7 @@ } } -void bitfill32_rev(unsigned long *dst, int dst_idx, u32 pat, u32 n) +void bitfill32_rev(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n) { unsigned long val = pat, dat; unsigned long first, last; @@ -300,7 +300,7 @@ * used for the next 32/64-bit word */ -void bitfill_rev(unsigned long *dst, int dst_idx, unsigned long pat, int left, +void bitfill_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left, int right, u32 n) { unsigned long first, last, dat; @@ -364,7 +364,7 @@ u32 bpp = p->var.bits_per_pixel; unsigned long x2, y2, vxres, vyres; unsigned long height, width, fg; - unsigned long *dst; + unsigned long __iomem *dst; int dst_idx, left; if (p->state != FBINFO_STATE_RUNNING) @@ -397,7 +397,7 @@ else fg = rect->color; - dst = (unsigned long *)((unsigned long)p->screen_base & + dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(BYTES_PER_LONG-1)); dst_idx = ((unsigned long)p->screen_base & (BYTES_PER_LONG-1))*8; dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; @@ -407,7 +407,7 @@ p->fbops->fb_sync(p); if (!left) { u32 pat = pixel_to_pat32(p, fg); - void (*fill_op32)(unsigned long *dst, int dst_idx, u32 pat, + void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n) = NULL; switch (rect->rop) { @@ -429,7 +429,7 @@ unsigned long pat = pixel_to_pat(p, fg, (left-dst_idx) % bpp); int right = bpp-left; int r; - void (*fill_op)(unsigned long *dst, int dst_idx, + void (*fill_op)(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left, int right, u32 n) = NULL; diff -Nru a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c --- a/drivers/video/cfbimgblt.c 2004-10-18 14:56:32 -07:00 +++ b/drivers/video/cfbimgblt.c 2004-10-18 14:56:32 -07:00 @@ -87,21 +87,22 @@ #endif static inline void color_imageblit(const struct fb_image *image, - struct fb_info *p, u8 *dst1, + struct fb_info *p, u8 __iomem *dst1, u32 start_index, u32 pitch_index) { /* Draw the penguin */ - u32 *dst, *dst2, color = 0, val, shift; + u32 __iomem *dst, *dst2; + u32 color = 0, val, shift; int i, n, bpp = p->var.bits_per_pixel; u32 null_bits = 32 - bpp; u32 *palette = (u32 *) p->pseudo_palette; const u8 *src = image->data; - dst2 = (u32 *) dst1; + dst2 = (u32 __iomem *) dst1; for (i = image->height; i--; ) { n = image->width; - dst = (u32 *) dst1; + dst = (u32 __iomem *) dst1; shift = 0; val = 0; @@ -136,7 +137,7 @@ dst1 += p->fix.line_length; if (pitch_index) { dst2 += p->fix.line_length; - dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1)); + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); start_index += pitch_index; start_index &= 32 - 1; @@ -145,25 +146,26 @@ } static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, - u8 *dst1, u32 fgcolor, + u8 __iomem *dst1, u32 fgcolor, u32 bgcolor, u32 start_index, u32 pitch_index) { u32 shift, color = 0, bpp = p->var.bits_per_pixel; - u32 *dst, *dst2, val, pitch = p->fix.line_length; + u32 __iomem *dst, *dst2; + u32 val, pitch = p->fix.line_length; u32 null_bits = 32 - bpp; u32 spitch = (image->width+7)/8; const u8 *src = image->data, *s; u32 i, j, l; - dst2 = (u32 *) dst1; + dst2 = (u32 __iomem *) dst1; for (i = image->height; i--; ) { shift = val = 0; l = 8; j = image->width; - dst = (u32 *) dst1; + dst = (u32 __iomem *) dst1; s = src; /* write leading bits */ @@ -201,7 +203,7 @@ src += spitch; if (pitch_index) { dst2 += pitch; - dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1)); + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); start_index += pitch_index; start_index &= 32 - 1; } @@ -218,14 +220,14 @@ * beginning and end of a scanline is dword aligned */ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, - u8 *dst1, u32 fgcolor, + u8 __iomem *dst1, u32 fgcolor, u32 bgcolor) { u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; u32 ppw = 32/bpp, spitch = (image->width + 7)/8; u32 bit_mask, end_mask, eorx, shift; const char *s = image->data, *src; - u32 *dst; + u32 __iomem *dst; u32 *tab = NULL; int i, j, k; @@ -253,7 +255,7 @@ k = image->width/ppw; for (i = image->height; i--; ) { - dst = (u32 *) dst1, shift = 8; src = s; + dst = (u32 __iomem *) dst1, shift = 8; src = s; for (j = k; j--; ) { shift -= ppw; @@ -273,7 +275,7 @@ u32 width = image->width, height = image->height; u32 dx = image->dx, dy = image->dy; int x2, y2, vxres, vyres; - u8 *dst1; + u8 __iomem *dst1; if (p->state != FBINFO_STATE_RUNNING) return; @@ -325,7 +327,7 @@ else slow_imageblit(image, p, dst1, fgcolor, bgcolor, start_index, pitch_index); - } else if (image->depth <= bpp) + } else color_imageblit(image, p, dst1, start_index, pitch_index); } diff -Nru a/drivers/video/cg14.c b/drivers/video/cg14.c --- a/drivers/video/cg14.c 2004-10-18 14:57:04 -07:00 +++ b/drivers/video/cg14.c 2004-10-18 14:57:04 -07:00 @@ -550,7 +550,7 @@ all->par.mode = MDI_8_PIX; all->par.ramsize = (is_8mb ? 0x800000 : 0x400000); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; all->info.fbops = &cg14_ops; all->info.currcon = -1; all->info.par = &all->par; @@ -584,6 +584,9 @@ struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("cg14fb", NULL)) + return -ENODEV; + #ifdef CONFIG_SPARC32 { int root, node; @@ -626,8 +629,9 @@ return 0; } -#ifdef MODULE module_init(cg14_init); + +#ifdef MODULE module_exit(cg14_exit); #endif diff -Nru a/drivers/video/cg3.c b/drivers/video/cg3.c --- a/drivers/video/cg3.c 2004-10-18 14:56:33 -07:00 +++ b/drivers/video/cg3.c 2004-10-18 14:56:33 -07:00 @@ -398,7 +398,7 @@ sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET, sizeof(struct cg3_regs), "cg3 regs"); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT; all->info.fbops = &cg3_ops; #ifdef CONFIG_SPARC32 all->info.screen_base = (char *) @@ -444,6 +444,9 @@ struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("cg3fb", NULL)) + return -ENODEV; + for_all_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, "cgthree") || !strcmp(sdev->prom_name, "cgRDI")) @@ -473,8 +476,9 @@ return 0; } -#ifdef MODULE module_init(cg3_init); + +#ifdef MODULE module_exit(cg3_exit); #endif diff -Nru a/drivers/video/cg6.c b/drivers/video/cg6.c --- a/drivers/video/cg6.c 2004-10-18 14:56:27 -07:00 +++ b/drivers/video/cg6.c 2004-10-18 14:56:27 -07:00 @@ -712,7 +712,8 @@ sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET, sizeof(u32), "cgsix fhc"); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; all->info.fbops = &cg6_ops; #ifdef CONFIG_SPARC32 all->info.screen_base = (char *) @@ -759,6 +760,9 @@ struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("cg6fb", NULL)) + return -ENODEV; + for_all_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, "cgsix") || !strcmp(sdev->prom_name, "cgthree+")) @@ -788,8 +792,9 @@ return 0; } -#ifdef MODULE module_init(cg6_init); + +#ifdef MODULE module_exit(cg6_exit); #endif diff -Nru a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c --- a/drivers/video/chipsfb.c 2004-10-18 14:56:29 -07:00 +++ b/drivers/video/chipsfb.c 2004-10-18 14:56:29 -07:00 @@ -362,7 +362,7 @@ p->var = chipsfb_var; p->fbops = &chipsfb_ops; - p->flags = FBINFO_FLAG_DEFAULT; + p->flags = FBINFO_DEFAULT; fb_alloc_cmap(&p->cmap, 256, 0); @@ -462,8 +462,13 @@ int __init chips_init(void) { + if (fb_get_options("chipsfb", NULL)) + return -ENODEV; + return pci_module_init(&chipsfb_driver); } + +module_init(chips_init); static void __exit chipsfb_exit(void) { diff -Nru a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c --- a/drivers/video/cirrusfb.c 2004-10-18 14:56:50 -07:00 +++ b/drivers/video/cirrusfb.c 2004-10-18 14:56:50 -07:00 @@ -752,6 +752,12 @@ switch (var->bits_per_pixel) { case 1: + var->red.offset = 0; + var->red.length = 1; + var->green.offset = 0; + var->green.length = 1; + var->blue.offset = 0; + var->blue.length = 1; break; case 8: @@ -2600,6 +2606,14 @@ { int error = 0; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cirrusfb", &option)) + return -ENODEV; + cirrusfb_setup(option); +#endif + #ifdef CONFIG_ZORRO error |= zorro_module_init(&cirrusfb_zorro_driver); #endif @@ -2657,8 +2671,9 @@ #endif } -#ifdef MODULE module_init(cirrusfb_init); + +#ifdef MODULE module_exit(cirrusfb_exit); #endif diff -Nru a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c --- a/drivers/video/clps711xfb.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/video/clps711xfb.c 2004-10-18 14:56:17 -07:00 @@ -364,6 +364,9 @@ { int err = -ENOMEM; + if (fb_get_options("clps711xfb", NULL)) + return -ENODEV; + cfb = kmalloc(sizeof(*cfb), GFP_KERNEL); if (!cfb) goto out; @@ -372,7 +375,7 @@ strcpy(cfb->fix.id, "clps711x"); cfb->fbops = &clps7111fb_ops; - cfb->flags = FBINFO_FLAG_DEFAULT; + cfb->flags = FBINFO_DEFAULT; clps711x_guess_lcd_params(cfb); @@ -432,9 +435,7 @@ } } -#ifdef MODULE module_init(clps711xfb_init); -#endif module_exit(clps711xfb_exit); MODULE_AUTHOR("Russell King "); diff -Nru a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig --- a/drivers/video/console/Kconfig 2004-10-18 14:56:20 -07:00 +++ b/drivers/video/console/Kconfig 2004-10-18 14:56:20 -07:00 @@ -6,7 +6,7 @@ config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC default y help Saying Y here will allow you to use Linux in text mode through a @@ -43,7 +43,7 @@ about the Video mode selection support. If unsure, say N. config MDA_CONSOLE - depends on !M68K + depends on !M68K && ISA tristate "MDA text console (dual-headed) (EXPERIMENTAL)" ---help--- Say Y here if you have an old MDA or monochrome Hercules graphics @@ -67,7 +67,7 @@ # bool 'IODC console' CONFIG_IODC_CONSOLE config STI_CONSOLE tristate "STI text console" - depends on PARISC + depends on PARISC && FRAMEBUFFER_CONSOLE default y help The STI console is the builtin display/keyboard on HP-PARISC diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c --- a/drivers/video/console/fbcon.c 2004-10-18 14:56:48 -07:00 +++ b/drivers/video/console/fbcon.c 2004-10-18 14:56:48 -07:00 @@ -314,6 +314,28 @@ return 0; } +static int fbcon_takeover(void) +{ + int err, i; + + if (!num_registered_fb) + return -ENODEV; + + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = info_idx; + + err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + if (err) { + for (i = first_fb_vc; i <= last_fb_vc; i++) { + con2fb_map[i] = -1; + } + info_idx = -1; + } + + return err; +} + /** * set_con2fb_map - map console to frame buffer device * @unit: virtual console number to map @@ -322,7 +344,7 @@ * Maps a virtual console @unit to a frame buffer device * @newidx. */ -int set_con2fb_map(int unit, int newidx) +static int set_con2fb_map(int unit, int newidx) { struct vc_data *vc = vc_cons[unit].d; int oldidx = con2fb_map[unit]; @@ -338,8 +360,7 @@ if (!search_for_mapped_con()) { info_idx = newidx; - fb_console_init(); - return 0; + return fbcon_takeover(); } if (oldidx != -1) @@ -405,6 +426,87 @@ /* * Accelerated handlers. */ +static inline int get_color(struct vc_data *vc, struct fb_info *info, + u16 c, int is_fg) +{ + int depth = fb_get_color_depth(info); + int color = 0; + + if (depth != 1) + color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c) + : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c); + + switch (depth) { + case 1: + { + /* 0 or 1 */ + int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; + int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; + + color = (is_fg) ? fg : bg; + break; + } + case 2: + /* + * Scale down 16-colors to 4 colors. Default 4-color palette + * is grayscale. + */ + color /= 4; + break; + case 3: + /* + * Last 8 entries of default 16-color palette is a more intense + * version of the first 8 (i.e., same chrominance, different + * luminance). + */ + color &= 7; + break; + } + + return color; +} + +#define FBCON_ATTRIBUTE_UNDERLINE 1 +#define FBCON_ATTRIBUTE_REVERSE 2 +#define FBCON_ATTRIBUTE_BOLD 4 + +static inline int get_attribute(struct fb_info *info, u16 c) +{ + int attribute = 0; + + if (fb_get_color_depth(info) == 1) { + if (attr_underline(c)) + attribute |= FBCON_ATTRIBUTE_UNDERLINE; + if (attr_reverse(c)) + attribute |= FBCON_ATTRIBUTE_REVERSE; + if (attr_bold(c)) + attribute |= FBCON_ATTRIBUTE_BOLD; + } + + return attribute; +} + +static inline void update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + u8 c; + + offset = cellsize - (offset * width); + for (i = 0; i < cellsize; i++) { + c = src[i]; + if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset) + c = 0xff; + if (attribute & FBCON_ATTRIBUTE_BOLD) + c |= c >> 1; + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + dst[i] = c; + } +} + void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, int sx, int dy, int dx, int height, int width) { @@ -455,13 +557,19 @@ unsigned int shift_low = 0, mod = vc->vc_font.width % 8; unsigned int shift_high = 8, pitch, cnt, size, k; unsigned int idx = vc->vc_font.width >> 3; + unsigned int attribute = get_attribute(info, scr_readw(s)); struct fb_image image; - u8 *src, *dst; + u8 *src, *dst, *buf = NULL; + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + image.fg_color = get_color(vc, info, scr_readw(s), 1); + image.bg_color = get_color(vc, info, scr_readw(s), 0); - image.fg_color = attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, - scr_readw(s)); - image.bg_color = attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, - scr_readw(s)); image.dx = xx * vc->vc_font.width; image.dy = yy * vc->vc_font.height; image.height = vc->vc_font.height; @@ -491,6 +599,12 @@ while (k--) { src = vc->vc_font.data + (scr_readw(s++)& charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + move_unaligned(info, &info->pixmap, dst, pitch, src, idx, image.height, shift_high, shift_low, mod); @@ -503,6 +617,12 @@ while (k--) { src = vc->vc_font.data + (scr_readw(s++)& charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + move_aligned(info, &info->pixmap, dst, pitch, src, idx, image.height); dst += width; @@ -512,6 +632,9 @@ image.dx += cnt * vc->vc_font.width; count -= cnt; } + + if (buf) + kfree(buf); } void accel_clear_margins(struct vc_data *vc, struct fb_info *info, @@ -550,6 +673,47 @@ * Low Level Operations */ /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ +static int var_to_display(struct display *disp, + struct fb_var_screeninfo *var, + struct fb_info *info) +{ + disp->xres_virtual = var->xres_virtual; + disp->yres_virtual = var->yres_virtual; + disp->bits_per_pixel = var->bits_per_pixel; + disp->grayscale = var->grayscale; + disp->nonstd = var->nonstd; + disp->accel_flags = var->accel_flags; + disp->height = var->height; + disp->width = var->width; + disp->red = var->red; + disp->green = var->green; + disp->blue = var->blue; + disp->transp = var->transp; + disp->mode = fb_match_mode(var, &info->modelist); + if (disp->mode == NULL) + /* This should not happen */ + return -EINVAL; + return 0; +} + +static void display_to_var(struct fb_var_screeninfo *var, + struct display *disp) +{ + fb_videomode_to_var(var, disp->mode); + var->xres_virtual = disp->xres_virtual; + var->yres_virtual = disp->yres_virtual; + var->bits_per_pixel = disp->bits_per_pixel; + var->grayscale = disp->grayscale; + var->nonstd = disp->nonstd; + var->accel_flags = disp->accel_flags; + var->height = disp->height; + var->width = disp->width; + var->red = disp->red; + var->green = disp->green; + var->blue = disp->blue; + var->transp = disp->transp; +} + static const char *fbcon_startup(void) { const char *display_desc = "frame buffer device"; @@ -723,6 +887,9 @@ info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + if (var_to_display(p, &info->var, info)) + return; + /* If we are not the first console on this fb, copy the font from that console */ t = &fb_display[display_fg]; @@ -737,7 +904,7 @@ } if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); - vc->vc_can_do_color = info->var.bits_per_pixel != 1; + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { vc->vc_hi_font_mask = 0; @@ -780,9 +947,15 @@ if (logo) { /* Need to make room for the logo */ - int cnt; + int cnt, erase = vc->vc_video_erase_char; int step; + /* + * remove underline attribute from erase character + * if black and white framebuffer. + */ + if (fb_get_color_depth(info) == 1) + erase &= ~0x400; logo_height = fb_prepare_logo(info); logo_lines = (logo_height + vc->vc_font.height - 1) / vc->vc_font.height; @@ -796,8 +969,7 @@ save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL); if (save) { int i = cols < new_cols ? cols : new_cols; - scr_memsetw(save, vc->vc_video_erase_char, - logo_lines * new_cols * 2); + scr_memsetw(save, erase, logo_lines * new_cols * 2); r = q - step; for (cnt = 0; cnt < logo_lines; cnt++, r += i) scr_memcpyw(save + cnt * new_cols, r, 2 * i); @@ -817,7 +989,7 @@ } } scr_memsetw((unsigned short *) vc->vc_origin, - vc->vc_video_erase_char, + erase, vc->vc_size_row * logo_lines); if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) { @@ -926,55 +1098,6 @@ accel_clear(vc, info, real_y(p, sy), sx, height, width); } -static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) -{ - struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - unsigned int scan_align = info->pixmap.scan_align - 1; - unsigned int buf_align = info->pixmap.buf_align - 1; - unsigned int width = (vc->vc_font.width + 7) >> 3; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; - struct display *p = &fb_display[vc->vc_num]; - unsigned int size, pitch; - struct fb_image image; - u8 *src, *dst; - - if (!info->fbops->fb_blank && console_blanked) - return; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) - return; - - image.dx = xpos * vc->vc_font.width; - image.dy = real_y(p, ypos) * vc->vc_font.height; - image.width = vc->vc_font.width; - image.height = vc->vc_font.height; - image.fg_color = attr_fgcol(fgshift, c); - image.bg_color = attr_bgcol(bgshift, c); - image.depth = 1; - - src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width; - - pitch = width + scan_align; - pitch &= ~scan_align; - size = pitch * vc->vc_font.height; - size += buf_align; - size &= ~buf_align; - - dst = fb_get_buffer_offset(info, &info->pixmap, size); - image.data = dst; - - if (info->pixmap.outbuf) - fb_iomove_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height); - else - fb_sysmove_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height); - - info->fbops->fb_imageblit(info, &image); -} - static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos) { @@ -992,17 +1115,22 @@ accel_putcs(vc, info, s, count, real_y(p, ypos), xpos); } +static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) +{ + fbcon_putcs(vc, (const unsigned short *) &c, 1, ypos, xpos); +} + static void fbcon_cursor(struct vc_data *vc, int mode) { + struct fb_cursor cursor; struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; struct display *p = &fb_display[vc->vc_num]; int w = (vc->vc_font.width + 7) >> 3, c; - int y = real_y(p, vc->vc_y); - struct fb_cursor cursor; - + int y = real_y(p, vc->vc_y), fg, bg; + int attribute; + u8 *src; + if (mode & CM_SOFTBACK) { mode &= ~CM_SOFTBACK; if (softback_lines) { @@ -1015,8 +1143,22 @@ fbcon_set_origin(vc); c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; + if (info->cursor.data) + kfree(info->cursor.data); + info->cursor.data = dst; + update_attr(dst, src, attribute, vc); + src = dst; + } - cursor.image.data = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + cursor.image.data = src; cursor.set = FB_CUR_SETCUR; cursor.image.depth = 1; @@ -1031,11 +1173,13 @@ case CM_MOVE: case CM_DRAW: info->cursor.enable = 1; - - if (info->cursor.image.fg_color != attr_fgcol(fgshift, c) || - info->cursor.image.bg_color != attr_bgcol(bgshift, c)) { - cursor.image.fg_color = attr_fgcol(fgshift, c); - cursor.image.bg_color = attr_bgcol(bgshift, c); + fg = get_color(vc, info, c, 1); + bg = get_color(vc, info, c, 0); + + if (info->cursor.image.fg_color != fg || + info->cursor.image.bg_color != bg) { + cursor.image.fg_color = fg; + cursor.image.bg_color = bg; cursor.set |= FB_CUR_SETCMAP; } @@ -1058,17 +1202,19 @@ cursor.set |= FB_CUR_SETHOT; } - if ((cursor.set & FB_CUR_SETSIZE) || ((vc->vc_cursor_type & 0x0f) != p->cursor_shape) + if ((cursor.set & FB_CUR_SETSIZE) || + ((vc->vc_cursor_type & 0x0f) != p->cursor_shape) || info->cursor.mask == NULL) { char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); int cur_height, size, i = 0; + u8 msk = 0xff; - if (!mask) return; + if (!mask) + return; if (info->cursor.mask) kfree(info->cursor.mask); info->cursor.mask = mask; - p->cursor_shape = vc->vc_cursor_type & 0x0f; cursor.set |= FB_CUR_SETSHAPE; @@ -1095,10 +1241,10 @@ } size = (vc->vc_font.height - cur_height) * w; while (size--) - mask[i++] = 0; + mask[i++] = ~msk; size = cur_height * w; while (size--) - mask[i++] = 0xff; + mask[i++] = msk; } info->cursor.rop = ROP_XOR; info->fbops->fb_cursor(info, &cursor); @@ -1126,6 +1272,8 @@ int rows, cols, charcnt = 256; info->var.xoffset = info->var.yoffset = p->yscroll = 0; + if (var_to_display(p, &info->var, info)) + return; t = &fb_display[display_fg]; if (!vc->vc_font.data) { vc->vc_font.data = p->fontdata = t->fontdata; @@ -1139,7 +1287,7 @@ if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); - vc->vc_can_do_color = info->var.bits_per_pixel != 1; + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { vc->vc_hi_font_mask = 0; @@ -1813,7 +1961,7 @@ struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var = info->var; - int err; int x_diff, y_diff; + int x_diff, y_diff; int fw = vc->vc_font.width; int fh = vc->vc_font.height; @@ -1822,15 +1970,31 @@ x_diff = info->var.xres - var.xres; y_diff = info->var.yres - var.yres; if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { - char mode[40]; + struct fb_videomode *mode; DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); - snprintf(mode, 40, "%ix%i", var.xres, var.yres); - err = fb_find_mode(&var, info, mode, info->monspecs.modedb, - info->monspecs.modedb_len, NULL, - info->var.bits_per_pixel); - if (!err || width > var.xres/fw || height > var.yres/fh) + mode = fb_find_best_mode(&var, &info->modelist); + if (mode == NULL) return -EINVAL; + fb_videomode_to_var(&var, mode); + if (width > var.xres/fw || height > var.yres/fh) + return -EINVAL; + /* + * The following can probably have any value... Do we need to + * set all of them? + */ + var.bits_per_pixel = p->bits_per_pixel; + var.xres_virtual = p->xres_virtual; + var.yres_virtual = p->yres_virtual; + var.accel_flags = p->accel_flags; + var.width = p->width; + var.height = p->height; + var.red = p->red; + var.green = p->green; + var.blue = p->blue; + var.transp = p->transp; + var.nonstd = p->nonstd; + DPRINTK("resize now %ix%i\n", var.xres, var.yres); if (CON_IS_VISIBLE(vc)) { var.activate = FB_ACTIVATE_NOW | @@ -1838,6 +2002,7 @@ fb_set_var(info, &var); info->flags &= ~FBINFO_MISC_MODESWITCH; } + var_to_display(p, &info->var, info); } updatescrollmode(p, info, vc); return 0; @@ -1847,6 +2012,7 @@ { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var; int i; if (softback_top) { @@ -1872,8 +2038,6 @@ conp2->vc_top = 0; logo_shown = -1; } - if (info) - info->var.yoffset = p->yscroll = 0; /* * FIXME: If we have multiple fbdev's loaded, we need to @@ -1888,7 +2052,18 @@ registered_fb[i]->currcon = vc->vc_num; } - fbcon_resize(vc, vc->vc_cols, vc->vc_rows); + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + fb_videomode_to_var(&var, p->mode); + display_to_var(&var, p); + var.activate = FB_ACTIVATE_NOW; + + /* + * make sure we don't unnecessarily trip the memcmp() + * in fb_set_var() + */ + info->var.activate = var.activate; + info->var.yoffset = info->var.xoffset = p->yscroll = 0; + fb_set_var(info, &var); if (info->flags & FBINFO_MISC_MODESWITCH) { if (info->fbops->fb_set_par) @@ -1896,6 +2071,10 @@ info->flags &= ~FBINFO_MISC_MODESWITCH; } + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + updatescrollmode(p, info, vc); + switch (p->scrollmode) { case SCROLL_WRAP_MOVE: scrollback_phys_max = p->vrows - vc->vc_rows; @@ -2290,26 +2469,31 @@ static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - int i, j, k; + int i, j, k, depth; u8 val; - if (!vc->vc_can_do_color - || (!info->fbops->fb_blank && console_blanked)) + if (!info->fbops->fb_blank && console_blanked) return -EINVAL; - for (i = j = 0; i < 16; i++) { - k = table[i]; - val = vc->vc_palette[j++]; - palette_red[k] = (val << 8) | val; - val = vc->vc_palette[j++]; - palette_green[k] = (val << 8) | val; - val = vc->vc_palette[j++]; - palette_blue[k] = (val << 8) | val; - } - if (info->var.bits_per_pixel <= 4) - palette_cmap.len = 1 << info->var.bits_per_pixel; - else + depth = fb_get_color_depth(info); + if (depth > 3) { + for (i = j = 0; i < 16; i++) { + k = table[i]; + val = vc->vc_palette[j++]; + palette_red[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_green[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_blue[k] = (val << 8) | val; + } palette_cmap.len = 16; - palette_cmap.start = 0; + palette_cmap.start = 0; + /* + * If framebuffer is capable of less than 16 colors, + * use default palette of fbcon. + */ + } else + fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); + return fb_set_cmap(&palette_cmap, info); } @@ -2516,10 +2700,9 @@ p = &fb_display[vc->vc_num]; info->var.xoffset = info->var.yoffset = p->yscroll = 0; - vc->vc_can_do_color = info->var.bits_per_pixel != 1; - vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (CON_IS_VISIBLE(vc)) { + var_to_display(p, &info->var, info); cols = info->var.xres / vc->vc_font.width; rows = info->var.yres / vc->vc_font.height; vc_resize(vc->vc_num, cols, rows); @@ -2542,10 +2725,52 @@ } } +static int fbcon_mode_deleted(struct fb_info *info, + struct fb_videomode *mode) +{ + struct fb_info *fb_info; + struct display *p; + int i, j, found = 0; + + /* before deletion, ensure that mode is not in use */ + for (i = first_fb_vc; i <= last_fb_vc; i++) { + j = (int) con2fb_map[i]; + if (j == -1) + continue; + fb_info = registered_fb[j]; + if (fb_info != info) + continue; + p = &fb_display[i]; + if (!p || !p->mode) + continue; + if (fb_mode_is_equal(p->mode, mode)) { + found = 1; + break; + } + } + return found; +} + +static int fbcon_fb_registered(int idx) +{ + int ret = 0; + + if (info_idx == -1) { + info_idx = idx; + ret = fbcon_takeover(); + } + + return ret; +} + static int fbcon_event_notify(struct notifier_block *self, unsigned long action, void *data) { - struct fb_info *info = (struct fb_info *) data; + struct fb_event *event = (struct fb_event *) data; + struct fb_info *info = event->info; + struct fb_videomode *mode; + struct fb_con2fbmap *con2fb; + int ret = 0; switch(action) { case FB_EVENT_SUSPEND: @@ -2557,9 +2782,24 @@ case FB_EVENT_MODE_CHANGE: fbcon_modechanged(info); break; + case FB_EVENT_MODE_DELETE: + mode = (struct fb_videomode *) event->data; + ret = fbcon_mode_deleted(info, mode); + break; + case FB_EVENT_FB_REGISTERED: + ret = fbcon_fb_registered(info->node); + break; + case FB_EVENT_SET_CONSOLE_MAP: + con2fb = (struct fb_con2fbmap *) event->data; + ret = set_con2fb_map(con2fb->console - 1, con2fb->framebuffer); + break; + case FB_EVENT_GET_CONSOLE_MAP: + con2fb = (struct fb_con2fbmap *) event->data; + con2fb->framebuffer = con2fb_map[con2fb->console - 1]; + break; } - return 0; + return ret; } /* @@ -2595,60 +2835,43 @@ static struct notifier_block fbcon_event_notifier = { .notifier_call = fbcon_event_notify, }; -static int fbcon_event_notifier_registered; -/* can't be __init as it can be called by set_con2fb_map() later */ -int fb_console_init(void) +int __init fb_console_init(void) { - int err, i; + int i; + + acquire_console_sem(); + fb_register_client(&fbcon_event_notifier); + release_console_sem(); for (i = 0; i < MAX_NR_CONSOLES; i++) con2fb_map[i] = -1; - if (!num_registered_fb) - return -ENODEV; - - if (info_idx == -1) { + if (num_registered_fb) { for (i = 0; i < FB_MAX; i++) { if (registered_fb[i] != NULL) { info_idx = i; break; } } + fbcon_takeover(); } - for (i = first_fb_vc; i <= last_fb_vc; i++) - con2fb_map[i] = info_idx; - err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, - fbcon_is_default); - if (err) { - for (i = first_fb_vc; i <= last_fb_vc; i++) { - con2fb_map[i] = -1; - } - return err; - } - acquire_console_sem(); - if (!fbcon_event_notifier_registered) { - fb_register_client(&fbcon_event_notifier); - fbcon_event_notifier_registered = 1; - } - release_console_sem(); + return 0; } +module_init(fb_console_init); + #ifdef MODULE void __exit fb_console_exit(void) { acquire_console_sem(); - if (fbcon_event_notifier_registered) { - fb_unregister_client(&fbcon_event_notifier); - fbcon_event_notifier_registered = 0; - } + fb_unregister_client(&fbcon_event_notifier); release_console_sem(); give_up_console(&fb_con); } -module_init(fb_console_init); module_exit(fb_console_exit); #endif diff -Nru a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h --- a/drivers/video/console/fbcon.h 2004-10-18 14:56:48 -07:00 +++ b/drivers/video/console/fbcon.h 2004-10-18 14:56:48 -07:00 @@ -33,12 +33,21 @@ short yscroll; /* Hardware scrolling */ int vrows; /* number of virtual rows */ int cursor_shape; + u32 xres_virtual; + u32 yres_virtual; + u32 height; + u32 width; + u32 bits_per_pixel; + u32 grayscale; + u32 nonstd; + u32 accel_flags; + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + struct fb_videomode *mode; }; -/* drivers/video/console/fbcon.c */ -extern signed char con2fb_map[MAX_NR_CONSOLES]; -extern int set_con2fb_map(int unit, int newidx); - /* * Attribute Decoding */ @@ -56,8 +65,8 @@ /* Monochrome */ #define attr_bold(s) \ ((s) & 0x200) -#define attr_reverse(s, inverse) \ - (((s) & 0x800) ^ (inverse ? 0x800 : 0)) +#define attr_reverse(s) \ + ((s) & 0x800) #define attr_underline(s) \ ((s) & 0x400) #define attr_blink(s) \ diff -Nru a/drivers/video/controlfb.c b/drivers/video/controlfb.c --- a/drivers/video/controlfb.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/video/controlfb.c 2004-10-18 14:56:17 -07:00 @@ -556,6 +556,11 @@ int __init control_init(void) { struct device_node *dp; + char *option = NULL; + + if (fb_get_options("controlfb", &option)) + return -ENODEV; + control_setup(option); dp = find_devices("control"); if (dp != 0 && !control_of_init(dp)) @@ -564,6 +569,7 @@ return -ENXIO; } +module_init(control_init); /* Work out which banks of VRAM we have installed. */ /* danj: I guess the card just ignores writes to nonexistant VRAM... */ @@ -1010,7 +1016,7 @@ info->par = &p->par; info->fbops = &controlfb_ops; info->pseudo_palette = p->pseudo_palette; - info->flags = FBINFO_FLAG_DEFAULT; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; info->screen_base = (char *) p->frame_buffer + CTRLFB_OFF; fb_alloc_cmap(&info->cmap, 256, 0); diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c --- a/drivers/video/cyber2000fb.c 2004-10-18 14:56:17 -07:00 +++ b/drivers/video/cyber2000fb.c 2004-10-18 14:56:17 -07:00 @@ -1166,7 +1166,7 @@ .vmode = FB_VMODE_NONINTERLACED }; -static char igs_regs[] __devinitdata = { +static char igs_regs[] = { EXT_CRT_IRQ, 0, EXT_CRT_TEST, 0, EXT_SYNC_CTL, 0, @@ -1281,7 +1281,7 @@ cfb->fb.var.accel_flags = FB_ACCELF_TEXT; cfb->fb.fbops = &cyber2000fb_ops; - cfb->fb.flags = FBINFO_FLAG_DEFAULT; + cfb->fb.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; cfb->fb.pseudo_palette = (void *)(cfb + 1); fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0); @@ -1289,7 +1289,7 @@ return cfb; } -static void __devinit +static void cyberpro_free_fb_info(struct cfb_info *cfb) { if (cfb) { @@ -1712,11 +1712,21 @@ * I don't think we can use the "module_init" stuff here because * the fbcon stuff may not be initialised yet. Hence the #ifdef * around module_init. + * + * Tony: "module_init" is now required */ int __init cyber2000fb_init(void) { int ret = -1, err; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cyber2000fb", NULL)) + return -ENODEV; + cyber2000fb_setup(option); +#endif + #ifdef CONFIG_ARCH_SHARK err = cyberpro_vl_probe(); if (!err) { @@ -1738,9 +1748,7 @@ pci_unregister_driver(&cyberpro_driver); } -#ifdef MODULE module_init(cyber2000fb_init); -#endif module_exit(cyberpro_exit); MODULE_AUTHOR("Russell King"); diff -Nru a/drivers/video/dnfb.c b/drivers/video/dnfb.c --- a/drivers/video/dnfb.c 2004-10-18 14:56:49 -07:00 +++ b/drivers/video/dnfb.c 2004-10-18 14:56:49 -07:00 @@ -239,6 +239,9 @@ info->fbops = &dn_fb_ops; info->fix = dnfb_fix; info->var = dnfb_var; + info->var.red.length = 1; + info->var.red.offset = 0; + info->var.green = info->var.blue = info->var.red; info->screen_base = (u_char *) info->fix.smem_start; err = fb_alloc_cmap(&info->cmap, 2, 0); @@ -281,6 +284,9 @@ { int ret; + if (fb_get_options("dnfb", NULL)) + return -ENODEV; + ret = driver_register(&dnfb_driver); if (!ret) { @@ -290,5 +296,7 @@ } return ret; } + +module_init(dnfb_init); MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c --- a/drivers/video/epson1355fb.c 2004-10-18 14:55:54 -07:00 +++ b/drivers/video/epson1355fb.c 2004-10-18 14:55:54 -07:00 @@ -1,541 +1,771 @@ /* - * linux/drivers/video/epson1355fb.c - * -- Support for the Epson SED1355 LCD/CRT controller + * linux/drivers/video/epson1355fb.c -- Epson S1D13505 frame buffer for 2.5. * - * Copyright (C) 2000 Philipp Rumpf + * Epson Research S1D13505 Embedded RAMDAC LCD/CRT Controller + * (previously known as SED1355) * - * based on linux/drivers/video/skeletonfb.c, which was + * Cf. http://www.erd.epson.com/vdc/html/S1D13505.html + * + * + * Copyright (C) Hewlett-Packard Company. All rights reserved. + * + * Written by Christopher Hoover + * + * Adapted from: + * + * linux/drivers/video/skeletonfb.c + * Modified to new api Jan 2001 by James Simmons (jsimmons@infradead.org) * Created 28 Dec 1997 by Geert Uytterhoeven * + * linux/drivers/video/epson1355fb.c (2.4 driver) + * Copyright (C) 2000 Philipp Rumpf + * * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ -/* TODO (roughly in order of priority): - * 16 bpp support - * crt support - * hw cursor support - * SwivelView + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * + * Noteworthy Issues + * ----------------- + * + * This driver is complicated by the fact that this is a 16-bit chip + * and, on at least one platform (ceiva), we can only do 16-bit reads + * and writes to the framebuffer. We hide this from user space + * except in the case of mmap(). + * + * + * To Do + * ----- + * + * - Test 8-bit pseudocolor mode + * - Allow setting bpp, virtual resolution + * - Implement horizontal panning + * - (maybe) Implement hardware cursor */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include #include +#include #include -#include